Helm artifacts added in CSAR package.
Validation added for the HELM artifacts when creating rApp with package.
Create rApp API added with specific error messages.
Issue-ID: NONRTRIC-975
Change-Id: I9ed99e460d440015f43057354faa8352695b31fa
Signed-off-by: aravind.est <aravindhan.a@est.tech>
/*-
* ============LICENSE_START======================================================================
- * Copyright (C) 2023 OpenInfra Foundation Europe. All rights reserved.
+ * Copyright (C) 2023-2024 OpenInfra Foundation Europe. All rights reserved.
* ===============================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
import static org.junit.jupiter.api.Assertions.assertEquals;
+import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.JsonArray;
import com.google.gson.JsonParser;
import com.oransc.rappmanager.models.csar.RappCsarConfigurationHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
-@SpringBootTest(classes = {RappCsarConfigurationHandler.class, DmeAcmInterceptor.class})
+@SpringBootTest(classes = {ObjectMapper.class, RappCsarConfigurationHandler.class, DmeAcmInterceptor.class})
class DmeAcmInterceptorTest {
@Autowired
/*-
* ============LICENSE_START======================================================================
* Copyright (C) 2023 Nordix Foundation. All rights reserved.
+ * Copyright (C) 2024 OpenInfra Foundation Europe. All rights reserved.
* ===============================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
package com.oransc.rappmanager.models.csar;
+import static com.google.common.base.Splitter.on;
+import static com.google.common.collect.Iterables.filter;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.gson.Gson;
+import com.oransc.rappmanager.models.exception.RappHandlerException;
import com.oransc.rappmanager.models.rapp.Rapp;
import com.oransc.rappmanager.models.rapp.RappResources;
import com.oransc.rappmanager.models.rappinstance.RappACMInstance;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.file.Path;
+import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.function.Predicate;
import java.util.stream.Collectors;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
+import lombok.RequiredArgsConstructor;
import org.apache.commons.compress.archivers.ArchiveEntry;
import org.apache.commons.compress.archivers.zip.ZipArchiveInputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
+import org.yaml.snakeyaml.Yaml;
@Service
+@RequiredArgsConstructor
public class RappCsarConfigurationHandler {
Logger logger = LoggerFactory.getLogger(RappCsarConfigurationHandler.class);
+
+ private final ObjectMapper objectMapper;
+ private static final String TOSCA_METADATA_LOCATION = "TOSCA-Metadata/TOSCA.meta";
+ private static final String ENTRY_DEFINITIONS_INDEX = "Entry-Definitions";
private static final String ACM_COMPOSITION_JSON_LOCATION = "Files/Acm/definition/compositions.json";
private static final String ACM_DEFINITION_LOCATION = "Files/Acm/definition";
private static final String ACM_INSTANCES_LOCATION = "Files/Acm/instances";
String originalFilename = multipartFile.getOriginalFilename();
if (originalFilename != null) {
return originalFilename.endsWith(".csar") && isFileExistsInCsar(multipartFile,
- ACM_COMPOSITION_JSON_LOCATION);
+ ACM_COMPOSITION_JSON_LOCATION) && isFileExistsInCsar(multipartFile, TOSCA_METADATA_LOCATION)
+ && containsValidArtifactDefinition(multipartFile);
}
return false;
}
return Boolean.TRUE;
}
}
- return Boolean.FALSE;
+ throw new RappHandlerException(HttpStatus.BAD_REQUEST, "rApp package missing a file " + fileLocation);
} catch (IOException e) {
logger.error("Unable to find the CSAR file", e);
- return Boolean.FALSE;
+ throw new RappHandlerException(HttpStatus.BAD_REQUEST, "rApp package missing a file " + fileLocation);
}
}
getRappPackageLocation(rapp.getPackageLocation(), rapp.getName(), rapp.getPackageName()).toUri());
}
+ ByteArrayOutputStream getFileFromCsar(MultipartFile multipartFile, String fileLocation) {
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ try (ZipArchiveInputStream zipArchiveInputStream = new ZipArchiveInputStream(multipartFile.getInputStream())) {
+ byteArrayOutputStream = getFileFromCsar(zipArchiveInputStream, fileLocation);
+ } catch (IOException e) {
+ logger.info("Unable to get file {} from the multipart CSAR file", fileLocation, e);
+ }
+ return byteArrayOutputStream;
+ }
+
ByteArrayOutputStream getFileFromCsar(File csarFile, String fileLocation) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
try (FileInputStream fileInputStream = new FileInputStream(csarFile);
ZipArchiveInputStream zipArchiveInputStream = new ZipArchiveInputStream(fileInputStream)) {
+ byteArrayOutputStream = getFileFromCsar(zipArchiveInputStream, fileLocation);
+ } catch (IOException e) {
+ logger.info("Unable to get file {} from the CSAR file", fileLocation, e);
+ }
+ return byteArrayOutputStream;
+ }
+
+ ByteArrayOutputStream getFileFromCsar(ZipArchiveInputStream zipArchiveInputStream, String fileLocation) {
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ try {
ArchiveEntry entry;
while ((entry = zipArchiveInputStream.getNextEntry()) != null) {
if (!entry.isDirectory() && entry.getName().equals(fileLocation)) {
}
}
} catch (IOException e) {
- logger.error("Unable to find the CSAR file", e);
+ logger.info("Unable to get file {} from the zip archive CSAR file", fileLocation, e);
}
return byteArrayOutputStream;
}
+ boolean containsValidArtifactDefinition(MultipartFile multipartFile) {
+ String asdLocation = getAsdDefinitionLocation(multipartFile);
+ if (asdLocation != null && !asdLocation.isEmpty() && isFileExistsInCsar(multipartFile, asdLocation)) {
+ try {
+ String asdContent = getFileFromCsar(multipartFile, asdLocation).toString();
+ String asdJsonContent = new Gson().toJsonTree(new Yaml().load(asdContent)).toString();
+ JsonNode jsonNode = objectMapper.readTree(asdJsonContent);
+ List<String> artifactFileList =
+ jsonNode.at("/topology_template/node_templates/applicationServiceDescriptor/artifacts")
+ .findValuesAsText("file");
+ return artifactFileList.stream()
+ .allMatch(artifactFile -> isFileExistsInCsar(multipartFile, artifactFile));
+ } catch (RappHandlerException e) {
+ throw e;
+ } catch (Exception e) {
+ logger.warn("Unable to validate artifact definition", e);
+ throw new RappHandlerException(HttpStatus.BAD_REQUEST, "ASD definition in rApp package is invalid.");
+ }
+ }
+ throw new RappHandlerException(HttpStatus.BAD_REQUEST, "ASD definition in rApp package is invalid.");
+ }
+
+ String getAsdDefinitionLocation(final MultipartFile multipartFile) {
+ String asdLocation = "";
+ final ByteArrayOutputStream fileContent = getFileFromCsar(multipartFile, TOSCA_METADATA_LOCATION);
+ if (fileContent != null) {
+ final String toscaMetadata = fileContent.toString();
+ if (!toscaMetadata.isEmpty()) {
+ final String entry =
+ filter(on("\n").split(toscaMetadata), line -> line.contains(ENTRY_DEFINITIONS_INDEX)).iterator()
+ .next();
+ asdLocation = entry.replace(ENTRY_DEFINITIONS_INDEX + ":", "").trim();
+ }
+ }
+ return asdLocation;
+ }
+
public String getSmeProviderDomainPayload(Rapp rapp, RappSMEInstance rappSMEInstance) {
return getPayload(rapp, getResourceUri(SME_PROVIDER_FUNCS_LOCATION, rappSMEInstance.getProviderFunction()));
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import com.fasterxml.jackson.databind.ObjectMapper;
import com.oransc.rappmanager.models.csar.RappCsarConfigurationHandler;
import com.oransc.rappmanager.models.rapp.Rapp;
import com.oransc.rappmanager.models.rapp.RappResources;
import org.springframework.test.context.ContextConfiguration;
@SpringBootTest
-@ContextConfiguration(classes = RappCsarConfigurationHandler.class)
+@ContextConfiguration(classes = {ObjectMapper.class, RappCsarConfigurationHandler.class})
class RappServiceEnablerTest {
@Autowired
/*-
* ============LICENSE_START======================================================================
* Copyright (C) 2023 Nordix Foundation. All rights reserved.
+ * Copyright (C) 2024 OpenInfra Foundation Europe. All rights reserved.
* ===============================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doCallRealMethod;
import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.oransc.rappmanager.models.exception.RappHandlerException;
import com.oransc.rappmanager.models.rapp.Rapp;
import com.oransc.rappmanager.models.rapp.RappResources;
import com.oransc.rappmanager.models.rappinstance.RappACMInstance;
import java.io.IOException;
import java.util.Set;
import java.util.UUID;
+import java.util.stream.Stream;
import org.apache.http.entity.ContentType;
import org.json.JSONException;
import org.json.JSONObject;
import org.junit.jupiter.api.Test;
-import org.springframework.beans.factory.annotation.Autowired;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.mock.mockito.SpyBean;
+import org.springframework.http.HttpStatus;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.web.multipart.MultipartFile;
@SpringBootTest
-@ContextConfiguration(classes = RappCsarConfigurationHandler.class)
+@ContextConfiguration(classes = {ObjectMapper.class, RappCsarConfigurationHandler.class})
class RappCsarConfigurationHandlerTest {
- @Autowired
+ @SpyBean
RappCsarConfigurationHandler rappCsarConfigurationHandler;
String validCsarFileLocation = "src/test/resources/";
assertEquals(Boolean.TRUE, rappCsarConfigurationHandler.isValidRappPackage(multipartFile));
}
- @Test
- void testCsarPackageValidationFailure() throws IOException {
- String rappCsarPath = validCsarFileLocation + File.separator + invalidRappFile;
+ @ParameterizedTest
+ @MethodSource("getInvalidCsarPackage")
+ void testCsarPackageValidationFailure(MultipartFile multipartFile) {
+ System.out.println(multipartFile.getOriginalFilename());
+ RappHandlerException exception = assertThrows(RappHandlerException.class,
+ () -> rappCsarConfigurationHandler.isValidRappPackage(multipartFile));
+ assertEquals(HttpStatus.BAD_REQUEST, exception.getStatusCode());
+ }
+
+
+ private static Stream<Arguments> getInvalidCsarPackage() throws IOException {
+ String validCsarFileLocation = "src/test/resources";
+ String rappCsarPath = validCsarFileLocation + File.separator + "invalid-rapp-package.csar";
MultipartFile multipartFile =
new MockMultipartFile(rappCsarPath, rappCsarPath, ContentType.MULTIPART_FORM_DATA.getMimeType(),
new FileInputStream(rappCsarPath));
- assertEquals(Boolean.FALSE, rappCsarConfigurationHandler.isValidRappPackage(multipartFile));
+ String rappCsarPathNoTosca = validCsarFileLocation + File.separator + "invalid-rapp-package-no-tosca.csar";
+ MultipartFile multipartFileNoTosca = new MockMultipartFile(rappCsarPathNoTosca, rappCsarPathNoTosca,
+ ContentType.MULTIPART_FORM_DATA.getMimeType(), new FileInputStream(rappCsarPathNoTosca));
+ String rappCsarPathNoAsdYaml = validCsarFileLocation + File.separator + "invalid-rapp-package-no-asd-yaml.csar";
+ MultipartFile multipartFileNoAsdYaml = new MockMultipartFile(rappCsarPathNoAsdYaml, rappCsarPathNoAsdYaml,
+ ContentType.MULTIPART_FORM_DATA.getMimeType(), new FileInputStream(rappCsarPathNoAsdYaml));
+ String rappCsarPathMissingArtifact =
+ validCsarFileLocation + File.separator + "invalid-rapp-package-missing-artifact.csar";
+ MultipartFile multipartFileMissingArtifact =
+ new MockMultipartFile(rappCsarPathMissingArtifact, rappCsarPathMissingArtifact,
+ ContentType.MULTIPART_FORM_DATA.getMimeType(),
+ new FileInputStream(rappCsarPathMissingArtifact));
+ String rappCsarPathNoComposition =
+ validCsarFileLocation + File.separator + "invalid-rapp-package-no-acm-composition.csar";
+ MultipartFile multipartFileNoComposition =
+ new MockMultipartFile(rappCsarPathNoComposition, rappCsarPathNoComposition,
+ ContentType.MULTIPART_FORM_DATA.getMimeType(), new FileInputStream(rappCsarPathNoComposition));
+ return Stream.of(Arguments.of(multipartFile), Arguments.of(multipartFileNoTosca),
+ Arguments.of(multipartFileNoAsdYaml), Arguments.of(multipartFileMissingArtifact),
+ Arguments.of(multipartFileNoComposition));
}
@Test
- void testCsarPackageValidationFailureWithoutOrginalName() throws IOException {
+ void testCsarPackageValidationFailureWithoutOrginalName() {
MultipartFile multipartFile = mock(MultipartFile.class);
assertEquals(Boolean.FALSE, rappCsarConfigurationHandler.isValidRappPackage(multipartFile));
}
@Test
void testInvalidCsarFileExist() {
MultipartFile multipartFile = mock(MultipartFile.class);
- assertEquals(Boolean.FALSE, rappCsarConfigurationHandler.isFileExistsInCsar(multipartFile, "INVALID_LOCATION"));
+ RappHandlerException exception = assertThrows(RappHandlerException.class,
+ () -> rappCsarConfigurationHandler.isFileExistsInCsar(multipartFile, "INVALID_LOCATION"));
+ assertEquals(HttpStatus.BAD_REQUEST, exception.getStatusCode());
+ }
+
+ @Test
+ void testCsarContainsValidAsdFile() throws IOException {
+ String rappCsarPath = validCsarFileLocation + File.separator + validRappFile;
+ MultipartFile multipartFile =
+ new MockMultipartFile(rappCsarPath, rappCsarPath, ContentType.MULTIPART_FORM_DATA.getMimeType(),
+ new FileInputStream(rappCsarPath));
+ assertTrue(rappCsarConfigurationHandler.containsValidArtifactDefinition(multipartFile));
+ }
+
+ @Test
+ void testCsarContainsValidAsdFileFailure() throws IOException {
+ String rappCsarPath = validCsarFileLocation + File.separator + invalidRappFile;
+ MultipartFile multipartFile =
+ new MockMultipartFile(rappCsarPath, rappCsarPath, ContentType.MULTIPART_FORM_DATA.getMimeType(),
+ new FileInputStream(rappCsarPath));
+ RappHandlerException exception = assertThrows(RappHandlerException.class,
+ () -> rappCsarConfigurationHandler.containsValidArtifactDefinition(multipartFile));
+ assertEquals(HttpStatus.BAD_REQUEST, exception.getStatusCode());
+ }
+
+ @Test
+ void testCsarNoAsdFailure() {
+ MultipartFile multipartFile = mock(MultipartFile.class);
+ RappHandlerException exception = assertThrows(RappHandlerException.class,
+ () -> rappCsarConfigurationHandler.containsValidArtifactDefinition(multipartFile));
+ assertEquals(HttpStatus.BAD_REQUEST, exception.getStatusCode());
+ }
+
+ @Test
+ void testCsarAsdContentInvalidFailure() throws IOException {
+ String rappCsarPath = validCsarFileLocation + File.separator + validRappFile;
+ MultipartFile multipartFile =
+ new MockMultipartFile(rappCsarPath, rappCsarPath, ContentType.MULTIPART_FORM_DATA.getMimeType(),
+ new FileInputStream(rappCsarPath));
+ String invalidJson = "{asasdasd";
+ ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ byteArrayOutputStream.write(invalidJson.getBytes(), 0, invalidJson.getBytes().length);
+ doCallRealMethod().doReturn(byteArrayOutputStream).when(rappCsarConfigurationHandler)
+ .getFileFromCsar(any(MultipartFile.class), any());
+ RappHandlerException exception = assertThrows(RappHandlerException.class,
+ () -> rappCsarConfigurationHandler.containsValidArtifactDefinition(multipartFile));
+ assertEquals(HttpStatus.BAD_REQUEST, exception.getStatusCode());
+ }
+
+ @Test
+ void testgetFileFromCsarFailure() throws IOException {
+ MultipartFile multipartFile = mock(MultipartFile.class);
+ when(multipartFile.getInputStream()).thenThrow(new IOException());
+ assertThat(rappCsarConfigurationHandler.getFileFromCsar(multipartFile, null).size()).isZero();
}
@Test
@Test
void testListInvalidResources() {
UUID rappId = UUID.randomUUID();
- Rapp rapp = Rapp.builder().rappId(rappId).name("").build();
+ Rapp rapp = Rapp.builder().rappId(rappId).name("").packageName("").packageLocation("").build();
RappResources rappResources = rappCsarConfigurationHandler.getRappResource(rapp);
assertThat(rappResources).isNotNull();
assertNull(rappResources.getAcm());
tosca_definitions_version: tosca_simple_yaml_1_2\r
\r
-description: First drop of free5gc and ueransim ASD\r
+description: rApp all\r
\r
imports:\r
- asd_types.yaml\r
node_templates:\r
applicationServiceDescriptor:\r
type: tosca.nodes.asd\r
- description: "Free5gc"\r
+ description: "rapp-all"\r
properties:\r
descriptor_id: 123e4567-e89b-12d3-a456-426614174000\r
descriptor_invariant_id: 123e4yyy-e89b-12d3-a456-426614174abc\r
descriptor_version: 1.0\r
schema_version: 2.0\r
- function_description: free5gc description\r
+ function_description: rApp description\r
provider: EST\r
- application_name: free5gc-app\r
- application_version: 2.3\r
- ext_cpds:\r
- - id: 1\r
- description: webpage-service\r
- virtual_link_requirement: endUser\r
- network_interface_realization_requirements:\r
- trunk_mode: false\r
- ipam: orchestrated\r
- interface_type: direct.userdriver\r
- interface_option:\r
- - virtio\r
- - memif\r
- interface_redundancy: actPassBond\r
- nic_options:\r
- - nic id1\r
- - nic id2\r
- input_param_mappings:\r
- loadbalancer_IP: 1.2.3.4\r
- external_IPs:\r
- - 5.6.7.8\r
- - 10.11.12.13\r
- nad_names:\r
- - nad name 1\r
- - nad name 2\r
- nad_namespace: myNamespace\r
- resource_mapping: my resource manifest\r
- - id: 2\r
- description: transactionAPI\r
- virtual_link_requirement: backhaul\r
- network_interface_realization_requirements:\r
- trunk_mode: true\r
- ipam: orchestrated\r
- interface_type: direct.userdriver\r
- interface_option:\r
- - virtio\r
- interface_redundancy: actPassBond\r
- nic_options:\r
- - nic id3\r
- - nic id4\r
- input_param_mappings:\r
- loadbalancer_IP: 192.168.1.0\r
- external_IPs:\r
- - 192.168.1.1\r
- - 192.168.1.2\r
- nad_names:\r
- - nad name 3\r
- - nad name 4\r
- nad_namespace: myNamespace2\r
- resource_mapping: my resource manifest\r
- enhanced_cluster_capabilities:\r
- min_kernel_version: 1.2.3\r
- required_kernel_modules:\r
- - ip6_tables\r
- - cryptd\r
- conflicting_kernel_modules:\r
- - nf_nat\r
- required_custom_resources:\r
- - kind: myKind\r
- api_version: myVersion\r
- - kind: mySecondKind\r
- api_version: mySecondVersion\r
- cluster_labels:\r
- - label 1\r
- - label 2\r
- required_plugin:\r
- - name: plugin1Name\r
- version: 1.2.3\r
- - name: plugin2Name\r
- version: 4.5.6\r
+ application_name: rapp-all\r
+ application_version: 1.0\r
artifacts:\r
- free5gc:\r
+ ransliceassurance:\r
type: tosca.artifacts.asd.deploymentItem\r
- file: "Artifacts/Deployment/HELM/free5gc-1.1.3.tgz"\r
+ file: "Artifacts/Deployment/HELM/ransliceassurance-1.0.0.tgz"\r
properties:\r
artifact_type: "helm_chart"\r
itemId: 1\r
- deployment_order: 1\r
- lifecycle_parameters:\r
- - ".Values.global.n2network.masterIf"\r
- - ".Values.global.n3network.masterIf"\r
- - ".Values.global.n4network.masterIf"\r
- - ".Values.global.n6network.masterIf"\r
- ueransim-free5gc:\r
+ oru-app:\r
type: tosca.artifacts.asd.deploymentItem\r
- file: "Artifacts/Deployment/HELM/ueransim-2.0.14.tgz"\r
+ file: "Artifacts/Deployment/HELM/orufhrecovery-1.0.0.tgz"\r
properties:\r
artifact_type: "helm_chart"\r
itemId: 2\r
- deployment_order: 2\r
- lifecycle_parameters:\r
- - ".Values.global.n2network.masterIf"\r
- - ".Values.global.n3network.masterIf"\r
tosca_definitions_version: tosca_simple_yaml_1_2
description: ASD types definitions version 0.1
-data_types:
-tosca.datatypes.asd.networkInterfaceRequirements:
- derived_from: tosca.datatypes.Root
- version: 0.1
- description: "Describes the datatype for network interface requirements"
- properties:
- trunk_mode:
- description: >
- Information about whether the CP instantiated from this Cp is
- in Trunk mode (802.1Q or other). When operating in "trunk mode",
- the Cp is capable of carrying traffic for several VLANs.
- Absence of this property implies that trunkMode is not configured
- for the Cp i.e. It is equivalent to boolean value "false".
- required: true
- type: boolean
- default: false
- ipam:
- description: >
- Identifies whether application expects IP address assignment to be
- managed by the cluster infrastructure (CNI IPAM plugin), or
- configured by orchestrator via for example helm input parameter,
- or if IP assignment is handled by the application itself.
- required: true
- type: string
- constraints:
- - valid_values: ["infraProvided", "orchestrated", "userManaged"]
- default: "infraProvided"
- interface_type:
- description: >
- Indicates what type of network interface the application expects.
- Kernel based virtual netdev based on CNIs such as ovs | bridge |
- macvlan | ipvlan, or PCIe dev directly visible in application
- namespace with kernel or userspace driver or bonded with the Bond
- CNI, or userspace-CNI based network interface
- (requires DPDK-OVS/VPP vSwitch).
- required: true
- type: string
- constraints:
- - valid_values: ["kernel.netdev", "direct.userdriver", "direct.kerneldriver", "direct.bond", "userspace"]
- default: "kernel.netdev"
- interface_option:
- description: >
- This attribute describes verified realization options for the
- network interface in question. Currently listed options
- (virtio and memif) are applicable for the interfaceType “userspace”.
- required: false
- type: list
- entry_schema:
- type: string
- constraints:
- - valid_values: ["virtio", "memif"]
- interface_redundancy:
- description: >
- Identifies switch-plane redundancy method the application uses,
- and that node infrastructure is required to comply with.
- "infraProvided", “left” and “right”: The container sees a
- single vNIC that a) the infrastructure bonds over both switchplanes
- or b) that is connected to the network via only left or
- right the switchplane.
- The other cases are for a mated pair of vnics connecting to
- same network, but where one vNIC connects
- via left switch plane and the other via right switch plane,
- and where the application manages the redundancy.
- "activePassiveBond": the application bonds with move of MAC address.
- "activeActiveBond“: bonded left/right links must be part of a multi-chassis LAG
- "activePassiveL3": application will move application IP address between the vNICs.
- "activeActiveL3": the application uses anycast/ECMP.
- required: true
- type: string
- constraints:
- - valid_values: ["infraProvided", "actPassBond", "actActBond", "actPassL3", "actActL3", "Left", "Right"]
- default: "infraProvided"
- nic_options:
- description: >
- Identifies for the direct.userdriver interface type, the physical
- nics the driver is verified to work with.
- Allowed values for nic types must be handled via a registry or be standardized.
- required: false
- type: list
- entry_schema:
- type: string
-
-tosca.datatypes.asd.paramMappings:
- version: 0.1
- derived_from: tosca.datatypes.Root
- description: "Describes the datatype for parameter mapping"
- properties:
- loadbalancer_IP:
- description: >
- When present, this attribute specifies the name of the deployment
- artifact input parameter through which the orchestrator can
- configure the loadbalancerIP parameter of the K8s service
- or ingress controller that the extCpdData represents.
- Note: The format of the Content strings is specific for each different
- orchestration templating technology used (Helm, Teraform, etc.).
- Currently only a format for use with Helm charts is suggested:
- "<helmchartname>:[<subchartname>.]^(0..N)[<parentparamname>.]^(0..N)<paramname>".
- Whether the optional parts of the format are present depends on how the
- parameter is declared in the helm chart. An example is:
- "chartName:subChart1.subChart2.subChart3.Parent1.Parent2.Parent3.LBIP".
- required: false
- type: string
- external_IPs:
- description: >
- When present, this attribute specifies the name of the deployment
- artifact input parameter through which the orchestrator can
- configure the extermalIPs parameter of the K8s service or ingress
- controller, or the pod network interface annotation, that the
- extCpdData represents.
- Note: The format of the Content strings is specific for each different
- orchestration templating technology used (Helm, Teraform, etc.).
- Currently only a format for use with Helm charts is suggested:
- "<helmchartname>:[<subchartname>.]^(0..N)[<parentparamname>.]^(0..N)<paramname>".
- Whether the optional parts of the format are present depends on how the
- parameter is declared in the helm chart. An example is:
- "chartName:subChart1.subChart2.subChart3.Parent1.Parent2.Parent3.extIP".
- required: false
- type: list
- entry_schema:
- type: string
- nad_names:
- description: >
- Specifies, for an extCpdData respesenting a secondary network interface,
- the name(s) of the deployment artifact input parameter(s) through which
- the orchestrator can provide the names of the network attachment
- definitions (NADs) the orchestrator has created as base for the network
- interface the extCpdData represents.
- Note 1: When the extCpdData represent a networkRedundant/mated-pair of
- sriov interfaces, there are references to 2 or 3 related NADs needed
- to be passed, while for other interface types only one NAD reference
- is needed to be passed.
- Note 2: The format of the Content strings is specific for each different
- orchestration templating technology used (Helm, Teraform, etc.).
- Currently only a format for use with Helm charts is suggested:
- "<helmchartname>:[<subchartname>.]^(0..N)[<parentparamname>.]^(0..N)<paramname>".
- Whether the optional parts of the format are present depends on how the
- parameter is declared in the helm chart. An example is:
- chartName:"subChart1.subChart2.subChart3.Parent1.Parent2.Parent3.nadName".
- Note 3: A direct attached (passthrough) network interface, such as an sriov
- interface, attaches to a network via only one of the two switch planes
- in the infrastructure.
- When using a direct attached network interface one therefore commonly in a
- pod uses a mated pair of sriov network attachments, where each interface
- attaches same network but via different switchplane.
- The application uses the mated pair of network interfaces as a single
- logical “swith-path-redundant” network interface – and this is represented
- by a single extCpdData.
- Also there is a case where a third “bond” attachment interface is used in
- the pod, bonding the two direct interfaces so that the application do not
- need to handle the redundancy issues – application just uses the bond interface.
- In this case, all three attachments are together making up a logical
- “switch-path-redundant” network interface represented by a single extCpdData.
- When three NADs are used in the extCpdData the NAD implementing the bond attachment
- interface is provided through the parameter indicated in the third place in
- the nadNames attribute.
- required: false
- type: list
- entry_schema:
- type: string
- nad_namespace:
- description: >
- Specifies, for an extCpdData respesenting a secondary network interface,
- the name of the deployment artifact input parameter through which the orchestrator
- can provide the namespace where the NetworkAttachmentDefinitions (NADs) are located.
- Attribute may be omitted if the namespace is same as the application
- namespace.
- Note: The format of the Content strings is specific for each different
- orchestration templating technology used (Helm, Teraform, etc.).
- Currently only a format for use with Helm charts is suggested:
- "<helmchartname>:[<subchartname>.]^(0..N)[<parentparamname>.]^(0..N)<paramname>".
- Whether the optional parts of the format are present depends on how the
- parameter is declared in the helm chart. An example is:
- "chartName:subChart1.subChart2.subChart3.Parent1.Parent2.Parent3.NameSpace".
- required: false
- type: string
-
-tosca.datatypes.asd.extCpdData:
- version: 0.1
- derived_from: tosca.datatypes.Root
- description: "Describes the datatype for external connection point definition data"
- properties:
- id:
- description: "The identifier of this extCpdData"
- required: true
- type: string
- description:
- description: >
- This property describes for a particular ExtCpd instance
- what service it exposes.
- required: true
- type: string
- virtual_link_requirement:
- description: >
- Refers in an abstract way to the network or multiple networks that
- the ExtCpd shall be exposed on (ex: OAM, EndUser, backhaul, LI, etc)
- required: true
- type: string
- network_interface_realization_requirements:
- description: >
- Details container implementation specific requirements on
- the NetworkAttachmentDefinition
- required: false
- type: tosca.datatypes.asd.networkInterfaceRequirements
- input_param_mappings:
- description: >
- Information on what helm chart input parameters that
- are required to be configured for this extCpd
- required: false
- type: tosca.datatypes.asd.paramMappings
- resource_mapping:
- description: >
- Kubernetes API resource name for the resource manifest for the service,
- ingress controller or pod
- required: false
- type: string
-
-tosca.datatypes.asd.enhancedClusterCapabilities:
- version: 0.1
- derived_from: tosca.datatypes.Root
- description: "Describes the datatype for parameter mapping"
- properties:
- min_kernel_version:
- description: >
- Describes the minimal required Kernel version, e.g. 4.15.0.
- Coded as displayed by linux command uname –r
- required: true
- type: string
- required_kernel_modules:
- description: >
- Required kernel modules are coded as listed by linux lsmod command,
- e.g. ip6_tables, cryptd, nf_nat etc.
- required: false
- type: list
- entry_schema:
- type: string
- conflicting_kernel_modules:
- description: >
- Kernel modules, which must not be present in the target environment.
- The kernel modules are coded as listed by linux lsmod command,
- e.g., ip6_tables, cryptd, nf_nat etc.
- Example: Linux kernel SCTP module, which would conflict with use of
- proprietary user space SCTP stack provided by the application.
- required: false
- type: list
- entry_schema:
- type: string
- required_custom_resources:
- description: >
- List the custom resource kinds required to be supported in the target
- environment. The list shall include those custom resource kinds which
- are not delivered with the application.
- required: false
- type: list
- entry_schema:
- type: tosca.datatypes.asd.customResourceRequirement
- cluster_labels:
- description: >
- This attribute allows to associate arbitrary labels to clusters.
- These can indicate special infrastructure capabilities (e.g., NW acceleration,
- GPU compute, etc.). The intent of these labels is to serve as a set of
- values that can help in application placement decisions.
- clusterLabels follow the Kubernetes label key-value-nomenclature
- (https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/).
- It is recommended that labels follow a standardized meaning e.g. for node
- features (https://kubernetes-sigs.github.io/node-feature-discovery/v0.9/get-started/features.html#table-of-contents).
- Example:
- ClusterLabels
- - feature.node.kubernetes.io/cpu-cpuid.AESNI: true
- required: false
- type: list
- entry_schema:
- type: string
- required_plugin:
- description: a list of the name of the required K8s plugin
- required: false
- type: list
- entry_schema:
- type: tosca.datatypes.asd.requiredPlugin
-
-tosca.datatypes.asd.customResourceRequirement:
- version: 0.1
- derived_from: tosca.datatypes.Root
- description: >
- kind: "Redis", apiVersion: "kubedb.com/v1alpha1"
- properties:
- kind:
- description: "the name of the custom resource requirement"
- type: string
- required: true
- api_version:
- description: "the api version of the custom resource requirement"
- type: string
- required: true
-
-tosca.datatypes.asd.requiredPlugin:
- version: 0.1
- derived_from: tosca.datatypes.Root
- description: "the required K8s plugin"
- properties:
- name:
- description: "the name of the required K8s plugin"
- type: string
- required: true
- version:
- description: "the version of the required K8s plugin"
- type: string
- required: true
-
node_types:
tosca.nodes.asd:
derived_from: tosca.nodes.Root
type: string
required: true
description: Identifies the version of the application service described by this ASD.
- ext_cpds:
- type: list
- required: false
- entry_schema:
- type: tosca.datatypes.asd.extCpdData
- description: >
- Describes the externally exposed connection points of the application
- service described by this ASD
- enhanced_cluster_capabilities:
- type: tosca.datatypes.asd.enhancedClusterCapabilities
- required: false
- description: >
- A list of expected capabilities of the target Kubernetes cluster to aid
- placement of the application service on a suitable cluster.
- tosca.nodes.asdInNsd:
- derived_from: tosca.nodes.nfv.VNF
- description: "The generic ASD node types for NS requirements. Optional properties are not list here."
- version: 0.1
- properties:
- descriptor_id:
- type: string # UUID
- description: Identifier of an ASD. It is in UUID format as specified in RFC 4122
- required: true
- descriptor_version:
- type: string
- description: Identifies the version of the ASD.
- required: true
- default: ""
- provider:
- type: string
- description: Identifies the provider of the ASD
- required: true
- default: ""
- product_name:
- type: string
- description: Please use the application_name property
- required: true
- default: ""
- software_version:
- type: string
- description: Please use the application_version property
- required: true
- default: ""
- flavour_id:
- type: string
- required: true
- constraints: [ equal: "simple" ]
- default: "simple"
- flavour_description:
- type: string
- required: true
- default: ""
- vnfm_info:
- type: list
- required: true
- entry_schema:
- type: list
- requirements:
- - virtual_link:
- capability: tosca.capabilities.nfv.VirtualLinkable
- relationship: tosca.relationships.nfv.VirtualLinkableTo
- occurrences: [ 0,0 ]
- - virtual_links:
- capability: tosca.capabilities.nfv.VirtualLinkable
- relationship: tosca.relationships.nfv.VirtualLinkableTo
- occurrences: [ 0,UNBOUNDED ]
+
artifact_types:
tosca.artifacts.asd.deploymentItem:
version: 0.1
derived_from: tosca.artifacts.Root
description: "Describes the artifact type of asd deployment item"
- file: "URI or path of the artifact"
+ file: "Relative path of the artifact in the package"
properties:
item_id:
description: "The identifier of this asd deployment item"
required: true
type: string
constraints:
- - valid_values: ["helm_chart", "helmfile", "crd", "terraform" ]
- deployment_order:
- description: >
- Specifies the deployment stage that the DeploymentArtifact belongs to.
- A lower value specifies that the DeploymentArtifact belongs to an earlier
- deployment stage. When this value is omitted, the deployment order
- will be decided by the orchestrator.
- required: false
- type: integer
- lifecycle_parameters:
- description: "list of parameters that can be overridden at deployment time "
- required: false
- type: list
- entry_schema:
- type: string
+ - valid_values: ["helm_chart"]
entry_definition_type: asd\r
\r
Source: asd.mf\r
+Source: Artifacts/Deployment/HELM/orufhrecovery-1.0.0.tgz\r
+Source: Artifacts/Deployment/HELM/ransliceassurance-1.0.0.tgz\r
Source: Definitions/asd.yaml\r
Source: Definitions/asd_types.yaml\r
Source: Files/Guides/user_guide.txt\r