summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--adapters/mso-openstack-adapters/pom.xml52
-rw-r--r--adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterImpl.java94
-rw-r--r--adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/HeatBridgeApi.java128
-rw-r--r--adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/HeatBridgeException.java29
-rw-r--r--adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/HeatBridgeImpl.java365
-rw-r--r--adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/constants/HeatBridgeConstants.java76
-rw-r--r--adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/factory/MsoCloudClientFactory.java41
-rw-r--r--adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/factory/MsoCloudClientFactoryImpl.java77
-rw-r--r--adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/helpers/AaiHelper.java275
-rw-r--r--adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/api/OpenstackAccess.java120
-rw-r--r--adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/api/OpenstackClient.java69
-rw-r--r--adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/api/OpenstackClientException.java29
-rw-r--r--adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/api/OpenstackClientImpl.java69
-rw-r--r--adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/api/OpenstackV2ClientImpl.java37
-rw-r--r--adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/api/OpenstackV3ClientImpl.java37
-rw-r--r--adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/factory/OpenstackClientFactory.java27
-rw-r--r--adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/factory/OpenstackClientFactoryImpl.java74
-rw-r--r--adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/utils/HeatBridgeUtils.java61
-rw-r--r--adapters/mso-openstack-adapters/src/test/java/org/onap/so/heatbridge/HeatBridgeImplTest.java375
-rw-r--r--adapters/mso-openstack-adapters/src/test/resources/stack-resources.json441
-rw-r--r--adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/VnfmAdapterController.java35
-rw-r--r--adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/VnfmAdapterControllerTest.java12
-rw-r--r--bpmn/MSOCommonBPMN/src/test/java/org/onap/so/bpmn/servicedecomposition/tasks/BBInputSetupTest.java22
-rw-r--r--bpmn/so-bpmn-building-blocks/src/main/resources/subprocess/BuildingBlock/EtsiVnfInstantiateBB.bpmn40
-rw-r--r--bpmn/so-bpmn-building-blocks/src/main/resources/subprocess/BuildingBlock/ExecuteBuildingBlock.bpmn3
-rw-r--r--bpmn/so-bpmn-tasks/pom.xml6
-rw-r--r--bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/Constants.java5
-rw-r--r--bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/InputParameterRetrieverTask.java74
-rw-r--r--bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/VnfmAdapterCreateVnfTask.java12
-rw-r--r--bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/utils/InputParameter.java81
-rw-r--r--bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/utils/InputParametersProvider.java31
-rw-r--r--bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/utils/InputParametersProviderImpl.java161
-rw-r--r--bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/utils/NullInputParameter.java37
-rw-r--r--bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/utils/VnfParameter.java91
-rw-r--r--bpmn/so-bpmn-tasks/src/test/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/InputParameterRetrieverTaskTest.java125
-rw-r--r--bpmn/so-bpmn-tasks/src/test/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/VnfmAdapterCreateVnfTaskTest.java6
-rw-r--r--bpmn/so-bpmn-tasks/src/test/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/utils/InputParametersProviderImplTest.java181
-rw-r--r--bpmn/so-bpmn-tasks/src/test/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/utils/VnfParameterTest.java38
-rw-r--r--bpmn/so-bpmn-tasks/src/test/resources/__files/SDNCClientPrelaodDataResponse.json127
-rw-r--r--bpmn/so-bpmn-tasks/src/test/resources/__files/SDNCClientPrelaodDataResponseWithInvalidAdditionalAndExtVmData.json47
-rw-r--r--bpmn/so-bpmn-tasks/src/test/resources/__files/SDNCClientPrelaodDataResponseWithInvalidData.json39
-rw-r--r--bpmn/so-bpmn-tasks/src/test/resources/__files/SDNCClientPrelaodDataResponseWithInvalidVnfParamsTag.json34
-rw-r--r--common/src/main/java/org/onap/so/client/aai/AAIObjectType.java5
43 files changed, 3648 insertions, 40 deletions
diff --git a/adapters/mso-openstack-adapters/pom.xml b/adapters/mso-openstack-adapters/pom.xml
index cb35e90860..73f50ed908 100644
--- a/adapters/mso-openstack-adapters/pom.xml
+++ b/adapters/mso-openstack-adapters/pom.xml
@@ -10,11 +10,13 @@
<packaging>jar</packaging>
<name>mso-openstack-adapters</name>
<description>Consolidate openstack adapters into one Spring Boot project</description>
-
+ <properties>
+ <openfeign.version>10.1.0</openfeign.version>
+ </properties>
<build>
<finalName>${project.artifactId}-${project.version}</finalName>
-
- <plugins>
+
+ <plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
@@ -211,12 +213,44 @@
<artifactId>janino</artifactId>
<version>2.5.15</version>
</dependency>
-
- <!-- end added for spring boot support -->
-
-
-
- <!-- added for unit testing -->
+
+ <!-- end added for spring boot support -->
+
+ <dependency>
+ <groupId>org.pacesys</groupId>
+ <artifactId>openstack4j-core</artifactId>
+ <version>3.1.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.pacesys.openstack4j.connectors</groupId>
+ <artifactId>openstack4j-httpclient</artifactId>
+ <version>3.1.0</version>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-collections</groupId>
+ <artifactId>commons-collections</artifactId>
+ <version>3.2.1</version>
+ </dependency>
+
+ <dependency>
+ <groupId>com.typesafe</groupId>
+ <artifactId>config</artifactId>
+ <version>1.3.2</version>
+ </dependency>
+ <dependency>
+ <groupId>com.google.code.findbugs</groupId>
+ <artifactId>jsr305</artifactId>
+ <version>1.3.9</version>
+ </dependency>
+
+ <dependency>
+ <groupId>commons-validator</groupId>
+ <artifactId>commons-validator</artifactId>
+ <version>1.4.0</version>
+ </dependency>
+
+ <!-- added for unit testing -->
<dependency>
<groupId>org.onap.so.adapters</groupId>
<artifactId>mso-adapter-utils</artifactId>
diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterImpl.java
index 3913d7f758..949027f7c1 100644
--- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterImpl.java
+++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfAdapterImpl.java
@@ -37,10 +37,22 @@ import java.util.concurrent.TimeUnit;
import javax.jws.WebService;
import javax.xml.ws.Holder;
+import org.apache.commons.collections.CollectionUtils;
+import org.onap.so.adapters.valet.GenericValetResponse;
+import org.onap.so.adapters.valet.ValetClient;
+import org.onap.so.adapters.valet.beans.HeatRequest;
+import org.onap.so.adapters.valet.beans.ValetConfirmResponse;
+import org.onap.so.adapters.valet.beans.ValetCreateResponse;
+import org.onap.so.adapters.valet.beans.ValetDeleteResponse;
+import org.onap.so.adapters.valet.beans.ValetRollbackResponse;
+import org.onap.so.adapters.valet.beans.ValetStatus;
+import org.onap.so.adapters.valet.beans.ValetUpdateResponse;
import org.onap.so.adapters.vnf.exceptions.VnfAlreadyExists;
import org.onap.so.adapters.vnf.exceptions.VnfException;
import org.onap.so.adapters.vnf.exceptions.VnfNotFound;
+import org.onap.so.client.aai.AAIResourcesClient;
import org.onap.so.cloud.CloudConfig;
+import org.onap.so.db.catalog.beans.CloudIdentity;
import org.onap.so.db.catalog.beans.CloudSite;
import org.onap.so.db.catalog.beans.HeatEnvironment;
import org.onap.so.db.catalog.beans.HeatFiles;
@@ -54,27 +66,26 @@ import org.onap.so.db.catalog.data.repository.VnfResourceRepository;
import org.onap.so.db.catalog.utils.MavenLikeVersioning;
import org.onap.so.entity.MsoRequest;
import org.onap.so.logger.ErrorCode;
+import org.onap.so.heatbridge.HeatBridgeApi;
+import org.onap.so.heatbridge.HeatBridgeImpl;
+import org.onap.so.heatbridge.openstack.api.OpenstackClient;
import org.onap.so.logger.MessageEnum;
import org.onap.so.openstack.beans.HeatStatus;
import org.onap.so.openstack.beans.StackInfo;
import org.onap.so.openstack.beans.VnfRollback;
import org.onap.so.openstack.beans.VnfStatus;
+import org.onap.so.openstack.exceptions.MsoCloudSiteNotFound;
import org.onap.so.openstack.exceptions.MsoException;
import org.onap.so.openstack.exceptions.MsoExceptionCategory;
import org.onap.so.openstack.exceptions.MsoHeatNotFoundException;
import org.onap.so.openstack.utils.MsoHeatEnvironmentEntry;
import org.onap.so.openstack.utils.MsoHeatUtils;
import org.onap.so.openstack.utils.MsoHeatUtilsWithUpdate;
-import org.onap.so.adapters.valet.ValetClient;
-import org.onap.so.adapters.valet.beans.HeatRequest;
-import org.onap.so.adapters.valet.beans.ValetConfirmResponse;
-import org.onap.so.adapters.valet.beans.ValetCreateResponse;
-import org.onap.so.adapters.valet.beans.ValetDeleteResponse;
-import org.onap.so.adapters.valet.beans.ValetRollbackResponse;
-import org.onap.so.adapters.valet.beans.ValetStatus;
-import org.onap.so.adapters.valet.beans.ValetUpdateResponse;
-import org.onap.so.adapters.valet.GenericValetResponse;
+import org.openstack4j.model.compute.Flavor;
+import org.openstack4j.model.compute.Image;
+import org.openstack4j.model.compute.Server;
+import org.openstack4j.model.heat.Resource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
@@ -509,6 +520,67 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter {
}
}
+ private void heatbridge(StackInfo heatStack, String cloudSiteId, String tenantId, String genericVnfName,
+ String vfModuleId) {
+ try {
+ CloudSite cloudSite = cloudConfig.getCloudSite(cloudSiteId).orElseThrow(
+ () -> new MsoCloudSiteNotFound(cloudSiteId));
+ CloudIdentity cloudIdentity = cloudSite.getIdentityService();
+ String heatStackId = heatStack.getCanonicalName().split("/")[1];
+
+ String cloudOwner = "CloudOwner";//cloud owner needs to come from bpmn-adapter
+ List<String> oobMgtNetNames = new ArrayList<>();
+
+ HeatBridgeApi heatBridgeClient = new HeatBridgeImpl(new AAIResourcesClient(), cloudIdentity,
+ cloudOwner, cloudSiteId, tenantId);
+
+ OpenstackClient openstackClient = heatBridgeClient.authenticate();
+ List<Resource> stackResources = heatBridgeClient.queryNestedHeatStackResources(heatStackId);
+
+ List<Server> osServers = heatBridgeClient.getAllOpenstackServers(stackResources);
+
+ List<Image> osImages = heatBridgeClient.extractOpenstackImagesFromServers(osServers);
+
+ List<Flavor> osFlavors = heatBridgeClient.extractOpenstackFlavorsFromServers(osServers);
+
+ logger.debug("Successfully queried heat stack{} for resources.", heatStackId);
+ //os images
+ if (osImages != null && !osImages.isEmpty()) {
+ heatBridgeClient.buildAddImagesToAaiAction(osImages);
+ logger.debug("Successfully built AAI actions to add images.");
+ } else {
+ logger.debug("No images to update to AAI.");
+ }
+ //flavors
+ if (osFlavors != null && !osFlavors.isEmpty()) {
+ heatBridgeClient.buildAddFlavorsToAaiAction(osFlavors);
+ logger.debug("Successfully built AAI actions to add flavors.");
+ } else {
+ logger.debug("No flavors to update to AAI.");
+ }
+
+ //compute resources
+ heatBridgeClient.buildAddVserversToAaiAction(genericVnfName, vfModuleId, osServers);
+ logger.debug("Successfully queried compute resources and built AAI vserver actions.");
+
+ //neutron resources
+ List<String> oobMgtNetIds = new ArrayList<>();
+
+ //if no network-id list is provided, however network-name list is
+ if (!CollectionUtils.isEmpty(oobMgtNetNames)) {
+ oobMgtNetIds = heatBridgeClient.extractNetworkIds(oobMgtNetNames);
+ }
+ heatBridgeClient.buildAddVserverLInterfacesToAaiAction(stackResources, oobMgtNetIds);
+ logger.debug(
+ "Successfully queried neutron resources and built AAI actions to add l-interfaces to vservers.");
+
+ //Update AAI
+ heatBridgeClient.submitToAai();
+ } catch (Exception ex) {
+ logger.debug("Heatbrige failed for stackId: " + heatStack.getCanonicalName(), ex);
+ }
+ }
+
private String convertNode(final JsonNode node) {
try {
final Object obj = JSON_MAPPER.treeToValue(node, Object.class);
@@ -1271,7 +1343,9 @@ public class MsoVnfAdapterImpl implements MsoVnfAdapter {
logger.error("Exception encountered while sending Confirm to Valet ", e);
}
}
- logger.debug("VF Module {} successfully created", vfModuleName);
+ logger.debug ("VF Module {} successfully created", vfModuleName);
+ //call heatbridge
+ heatbridge(heatStack, cloudSiteId, tenantId, genericVnfName, vfModuleId);
return;
} catch (Exception e) {
logger.debug("unhandled exception in create VF",e);
diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/HeatBridgeApi.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/HeatBridgeApi.java
new file mode 100644
index 0000000000..6b06761474
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/HeatBridgeApi.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2018 Bell Canada. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onap.so.heatbridge;
+
+import java.util.List;
+import org.onap.so.heatbridge.openstack.api.OpenstackClient;
+import org.openstack4j.model.compute.Flavor;
+import org.openstack4j.model.compute.Image;
+import org.openstack4j.model.compute.Server;
+import org.openstack4j.model.heat.Resource;
+
+/**
+ * Defines the contract to extract Heat Stack Resources from Openstack and inventory it to AAI.
+ * This API is used only to "create" objects in AAI.
+ */
+public interface HeatBridgeApi {
+
+ /**
+ * Authenticate with Openstack Keystone. The auth information is read from SO cloud configuration file.
+ *
+ * @return Openstack client object with keystone token
+ * @throws HeatBridgeException upon failure to authenticate with keystone
+ */
+ OpenstackClient authenticate() throws HeatBridgeException;
+
+ /**
+ * Query all the stack based resources from Openstack Heat service
+ *
+ * @param heatStackId Heat stack UUID
+ * @return A list of stack based resources
+ */
+ List<Resource> queryNestedHeatStackResources(String heatStackId);
+
+ /**
+ * Get a filtered list of resource IDs by resource type
+ *
+ * @param stackResources A list of stack based resources
+ * @param resourceType Resource type to filter by
+ * @return A list of stack resources matching the specified resource-type
+ */
+ List<String> extractStackResourceIdsByResourceType(List<Resource> stackResources, String resourceType);
+
+ /**
+ * Get network IDs for a given list of network names.
+ * It is assumed that there is a one to one mapping between the name and ID.
+ * @param networkNameList List of network names
+ * @return List of matching network IDs
+ */
+ List<String> extractNetworkIds(List<String> networkNameList);
+
+ /**
+ * Query the Openstack server objects from the list of stack resources
+ *
+ * @param stackResources A list of stack based resources
+ * @return A list of Openstack Server objects
+ */
+ List<Server> getAllOpenstackServers(List<Resource> stackResources);
+
+ /**
+ * Extract Openstack Image objects from a a list of Server objects
+ *
+ * @param servers A list of Openstack Server objects
+ * @return A list of Openstack Image objects
+ */
+ List<Image> extractOpenstackImagesFromServers(List<Server> servers);
+
+ /**
+ * Extract Openstack Flavor objects from a a list of Server objects
+ *
+ * @param servers A list of Openstack Server objects
+ * @return A list of Openstack Flavor objects
+ */
+ List<Flavor> extractOpenstackFlavorsFromServers(List<Server> servers);
+
+ /**
+ * Query and build AAI actions for Openstack Image resources to AAI's image objects
+ *
+ * @param images List of Openstack Image objects
+ * @throws HeatBridgeException when failing to add images to AAI
+ */
+ void buildAddImagesToAaiAction(List<Image> images) throws HeatBridgeException;
+
+ /**
+ * Query and build AAI actions for Openstack Flavor resources to AAI's flavor objects
+ *
+ * @param flavors List of Openstack Flavor objects
+ * @throws HeatBridgeException when failing to add flavors to AAI
+ */
+ void buildAddFlavorsToAaiAction(List<Flavor> flavors) throws HeatBridgeException;
+
+ /**
+ * Query and build AAI actions for Openstack Compute resources to AAI's vserver objects
+ *
+ * @param genericVnfId AAI generic-vnf-id
+ * @param vfModuleId AAI vf-module-id
+ * @param servers Openstack Server list
+ */
+ void buildAddVserversToAaiAction(String genericVnfId, String vfModuleId, List<Server> servers);
+
+ /**
+ * Query and build AAI actions for Openstack Neutron resources associated with a Compute resource to AAI's
+ * l-interface objects
+ *
+ * @param stackResources Openstack Heat stack resource list
+ * @param oobMgtNetIds List of OOB network IDs list
+ */
+ void buildAddVserverLInterfacesToAaiAction(List<Resource> stackResources, List<String> oobMgtNetIds);
+
+ /**
+ * Execute AAI restful API to update the Openstack resources
+ *
+ * @throws HeatBridgeException when failing to add openstack resource PoJos to AAI
+ */
+ void submitToAai() throws HeatBridgeException;
+}
diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/HeatBridgeException.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/HeatBridgeException.java
new file mode 100644
index 0000000000..f993d71e4c
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/HeatBridgeException.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2018 Bell Canada. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onap.so.heatbridge;
+
+public class HeatBridgeException extends Exception {
+
+ private static final long serialVersionUID = -1472047930391718894L;
+
+ public HeatBridgeException(final String message) {
+ super(message);
+ }
+
+ public HeatBridgeException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/HeatBridgeImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/HeatBridgeImpl.java
new file mode 100644
index 0000000000..90ceeb7d1c
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/HeatBridgeImpl.java
@@ -0,0 +1,365 @@
+/*
+ * Copyright (C) 2018 Bell Canada. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onap.so.heatbridge;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.function.Function;
+import java.util.function.Predicate;
+import java.util.stream.Collectors;
+
+import javax.annotation.Nonnull;
+import javax.ws.rs.WebApplicationException;
+
+import org.apache.commons.collections.CollectionUtils;
+import org.apache.commons.validator.routines.InetAddressValidator;
+import org.onap.aai.domain.yang.Flavor;
+import org.onap.aai.domain.yang.Image;
+import org.onap.aai.domain.yang.L3InterfaceIpv4AddressList;
+import org.onap.aai.domain.yang.LInterface;
+import org.onap.aai.domain.yang.PInterface;
+import org.onap.aai.domain.yang.SriovPf;
+import org.onap.aai.domain.yang.SriovPfs;
+import org.onap.aai.domain.yang.SriovVf;
+import org.onap.aai.domain.yang.SriovVfs;
+import org.onap.aai.domain.yang.Vlan;
+import org.onap.aai.domain.yang.Vlans;
+import org.onap.aai.domain.yang.Vserver;
+import org.onap.so.client.aai.AAIObjectType;
+import org.onap.so.client.aai.AAIResourcesClient;
+import org.onap.so.client.aai.AAISingleTransactionClient;
+import org.onap.so.client.aai.entities.uri.AAIResourceUri;
+import org.onap.so.client.aai.entities.uri.AAIUriFactory;
+import org.onap.so.client.graphinventory.entities.uri.Depth;
+import org.onap.so.client.graphinventory.exceptions.BulkProcessFailed;
+import org.onap.so.db.catalog.beans.CloudIdentity;
+import org.onap.so.heatbridge.constants.HeatBridgeConstants;
+import org.onap.so.heatbridge.factory.MsoCloudClientFactoryImpl;
+import org.onap.so.heatbridge.helpers.AaiHelper;
+import org.onap.so.heatbridge.openstack.api.OpenstackClient;
+import org.onap.so.heatbridge.openstack.factory.OpenstackClientFactoryImpl;
+import org.onap.so.heatbridge.utils.HeatBridgeUtils;
+import org.onap.so.logger.MessageEnum;
+import org.onap.so.logger.ErrorCode;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.openstack4j.model.compute.Server;
+import org.openstack4j.model.heat.Resource;
+import org.openstack4j.model.network.IP;
+import org.openstack4j.model.network.Network;
+import org.openstack4j.model.network.NetworkType;
+import org.openstack4j.model.network.Port;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableMap;
+
+/**
+ * This class provides an implementation of {@link HeatBridgeApi}
+ */
+public class HeatBridgeImpl implements HeatBridgeApi {
+
+ private static final Logger logger = LoggerFactory.getLogger(HeatBridgeImpl.class);
+ private static final String ERR_MSG_NULL_OS_CLIENT = "Initialization error: Null openstack client. Authenticate with Keystone first.";
+ private static final String OOB_MGT_NETWORK_IDENTIFIER = "Management";
+ private OpenstackClient osClient;
+ private AAIResourcesClient resourcesClient;
+ private AAISingleTransactionClient transaction;
+ private String cloudOwner;
+ private String cloudRegionId;
+ private String tenantId;
+ private AaiHelper aaiHelper = new AaiHelper();
+ private CloudIdentity cloudIdentity;
+
+
+ public HeatBridgeImpl(AAIResourcesClient resourcesClient, final CloudIdentity cloudIdentity,
+ @Nonnull final String cloudOwner, @Nonnull final String cloudRegionId, @Nonnull final String tenantId) {
+ Objects.requireNonNull(cloudOwner, "Null cloud-owner value!");
+ Objects.requireNonNull(cloudRegionId, "Null cloud-region identifier!");
+ Objects.requireNonNull(tenantId, "Null tenant identifier!");
+ Objects.requireNonNull(tenantId, "Null AAI actions list!");
+
+ this.cloudIdentity = cloudIdentity;
+ this.cloudOwner = cloudOwner;
+ this.cloudRegionId = cloudRegionId;
+ this.tenantId = tenantId;
+ this.resourcesClient = resourcesClient;
+ this.transaction = resourcesClient.beginSingleTransaction();
+ }
+
+ @Override
+ public OpenstackClient authenticate() throws HeatBridgeException {
+ this.osClient = new MsoCloudClientFactoryImpl(new OpenstackClientFactoryImpl())
+ .getOpenstackClient(cloudIdentity.getIdentityUrl(), cloudIdentity.getMsoId(), cloudIdentity.getMsoPass(), cloudRegionId, tenantId);
+ logger.debug("Successfully authenticated with keystone for tenant: " + tenantId + " and cloud "
+ + "region: " + cloudRegionId);
+ return osClient;
+ }
+
+ @Override
+ public List<Resource> queryNestedHeatStackResources(final String heatStackId) {
+ Objects.requireNonNull(osClient, ERR_MSG_NULL_OS_CLIENT);
+ Preconditions.checkState(!Strings.isNullOrEmpty(heatStackId), "Invalid heatStackId!");
+ List<Resource> stackBasedResources = osClient
+ .getStackBasedResources(heatStackId, HeatBridgeConstants.OS_DEFAULT_HEAT_NESTING);
+ logger.debug(stackBasedResources.size() + " heat stack resources are extracted for stack: " + heatStackId);
+ return stackBasedResources;
+ }
+
+ @Override
+ public List<String> extractStackResourceIdsByResourceType(final List<Resource> stackResources,
+ final String resourceType) {
+ return stackResources.stream()
+ .filter(stackResource -> stackResource.getType().equals(resourceType))
+ .map(Resource::getPhysicalResourceId)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public List<String> extractNetworkIds(final List<String> networkNameList) {
+ Objects.requireNonNull(osClient, ERR_MSG_NULL_OS_CLIENT);
+ return networkNameList.stream()
+ .map(netName -> osClient.listNetworksByFilter(ImmutableMap.of(HeatBridgeConstants.OS_NAME_KEY, netName)))
+ .filter(nets -> nets != null && nets.size() == 1) //extract network-id only if network-name is unique
+ .map(nets -> nets.get(0).getId())
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public List<Server> getAllOpenstackServers(final List<Resource> stackResources) {
+ Objects.requireNonNull(osClient, ERR_MSG_NULL_OS_CLIENT);
+
+ // Filter Openstack Compute resources
+ List<String> serverIds = extractStackResourceIdsByResourceType(stackResources,
+ HeatBridgeConstants.OS_SERVER_RESOURCE_TYPE);
+ return serverIds.stream().map(serverId -> osClient.getServerById(serverId)).collect(Collectors.toList());
+ }
+
+ @Override
+ public List<org.openstack4j.model.compute.Image> extractOpenstackImagesFromServers(final List<Server> servers) {
+ Objects.requireNonNull(osClient, ERR_MSG_NULL_OS_CLIENT);
+ return servers.stream().map(Server::getImage)
+ .filter(distinctByProperty(org.openstack4j.model.compute.Image::getId)).collect(Collectors.toList());
+ }
+
+ @Override
+ public List<org.openstack4j.model.compute.Flavor> extractOpenstackFlavorsFromServers(final List<Server> servers) {
+ Objects.requireNonNull(osClient, ERR_MSG_NULL_OS_CLIENT);
+ return servers.stream().map(Server::getFlavor)
+ .filter(distinctByProperty(org.openstack4j.model.compute.Flavor::getId)).collect(Collectors.toList());
+ }
+
+ @Override
+ public void buildAddImagesToAaiAction(final List<org.openstack4j.model.compute.Image> images)
+ throws HeatBridgeException {
+ for (org.openstack4j.model.compute.Image image : images) {
+ Image aaiImage = aaiHelper.buildImage(image);
+ try {
+ AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIObjectType.IMAGE, cloudOwner, cloudRegionId, aaiImage.getImageId());
+ if (!resourcesClient.exists(uri)) {
+ transaction.create(uri, aaiImage);
+ logger.debug("Queuing AAI command to add image: " + aaiImage.getImageId());
+ } else {
+ logger.debug("Nothing to add since image: " + aaiImage.getImageId() + "already exists in AAI.");
+ }
+ } catch (WebApplicationException e) {
+ throw new HeatBridgeException("Failed to update image to AAI: " + aaiImage.getImageId() + ". Error"
+ + " cause: " + e, e);
+ }
+ }
+ }
+
+ @Override
+ public void buildAddFlavorsToAaiAction(final List<org.openstack4j.model.compute.Flavor> flavors)
+ throws HeatBridgeException {
+ for (org.openstack4j.model.compute.Flavor flavor : flavors) {
+ Flavor aaiFlavor = aaiHelper.buildFlavor(flavor);
+ try {
+ AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIObjectType.FLAVOR, cloudOwner, cloudRegionId, aaiFlavor.getFlavorId());
+ if (!resourcesClient.exists(uri)) {
+ transaction.create(uri, aaiFlavor);
+ logger.debug("Queuing AAI command to add flavor: " + aaiFlavor.getFlavorId());
+ } else {
+ logger.debug("Nothing to add since flavor: " + aaiFlavor.getFlavorId() + "already exists in AAI.");
+ }
+ } catch (WebApplicationException e) {
+ throw new HeatBridgeException("Failed to update flavor to AAI: " + aaiFlavor.getFlavorId() + ". Error"
+ + " cause: " + e, e);
+ }
+ }
+ }
+
+ @Override
+ public void buildAddVserversToAaiAction(final String genericVnfId, final String vfModuleId,
+ final List<Server> servers) {
+ servers.forEach(server -> {
+ Vserver vserver = aaiHelper.buildVserver(server.getId(), server);
+
+ // Build vserver relationships to: image, flavor, pserver, vf-module
+ vserver.setRelationshipList(aaiHelper.getVserverRelationshipList(cloudOwner, cloudRegionId, genericVnfId,
+ vfModuleId, server));
+ transaction.create(AAIUriFactory.createResourceUri(AAIObjectType.VSERVER, cloudOwner, cloudRegionId, tenantId, vserver.getVserverId()), vserver);
+ });
+ }
+
+ @Override
+ public void buildAddVserverLInterfacesToAaiAction(final List<Resource> stackResources,
+ final List<String> oobMgtNetIds) {
+ Objects.requireNonNull(osClient, ERR_MSG_NULL_OS_CLIENT);
+ List<String> portIds = extractStackResourceIdsByResourceType(stackResources,
+ HeatBridgeConstants.OS_PORT_RESOURCE_TYPE);
+ for (String portId : portIds) {
+ Port port = osClient.getPortById(portId);
+ LInterface lIf = new LInterface();
+ lIf.setInterfaceId(port.getId());
+ lIf.setInterfaceName(port.getName());
+ lIf.setMacaddr(port.getMacAddress());
+ if (oobMgtNetIds != null && oobMgtNetIds.contains(port.getNetworkId())) {
+ lIf.setInterfaceRole(OOB_MGT_NETWORK_IDENTIFIER);
+ } else {
+ lIf.setInterfaceRole(port.getvNicType());
+ }
+
+ updateLInterfaceIps(port, lIf);
+ updateLInterfaceVlan(port, lIf);
+
+ // Update l-interface to the vserver
+ transaction.create(AAIUriFactory.createResourceUri(
+ AAIObjectType.L_INTERFACE, cloudOwner, cloudRegionId, tenantId, port.getDeviceId(), lIf.getInterfaceName()), lIf);
+ }
+ }
+
+ private void updateLInterfaceVlan(final Port port, final LInterface lIf) {
+ Vlan vlan = new Vlan();
+ Network network = osClient.getNetworkById(port.getNetworkId());
+ lIf.setNetworkName(network.getName());
+ if (network.getNetworkType().equals(NetworkType.VLAN)) {
+ vlan.setVlanInterface(network.getProviderSegID());
+ Vlans vlans = new Vlans();
+ List<Vlan> vlanList = vlans.getVlan();
+ vlanList.add(vlan);
+ lIf.setVlans(vlans);
+ }
+ // Build sriov-vf to the l-interface
+ if (port.getvNicType().equalsIgnoreCase(HeatBridgeConstants.OS_SRIOV_PORT_TYPE)) {
+ SriovVfs sriovVfs = new SriovVfs();
+ // JAXB does not generate setters for list, however getter ensures its creation.
+ // Thus, all list manipulations must be made on live list.
+ List<SriovVf> sriovVfList = sriovVfs.getSriovVf();
+ SriovVf sriovVf = new SriovVf();
+ sriovVf.setPciId(port.getProfile().get(HeatBridgeConstants.OS_PCI_SLOT_KEY).toString());
+ sriovVf.setNeutronNetworkId(port.getNetworkId());
+ if (port.getVifDetails() != null) {
+ sriovVf.setVfVlanFilter((String) port.getVifDetails().get(HeatBridgeConstants.OS_VLAN_NETWORK_KEY));
+ }
+ sriovVfList.add(sriovVf);
+
+ lIf.setSriovVfs(sriovVfs);
+
+ // For the given port create sriov-pf for host pserver/p-interface if absent
+ updateSriovPfToPserver(port, lIf);
+ }
+ }
+
+ /**
+ * Needs to be corrected according to the specification that is in draft
+ * If pserver/p-interface does not have a SRIOV-PF object matching the PCI-ID of the Openstack port object, then
+ * create it in AAI.
+ * Openstack SRIOV Port object has pci-id (to match sriov-pf on pserver/p-interface), physical-network ID (that
+ * matches the p-interface name).
+ *
+ * @param port Openstack port object
+ * @param lIf AAI l-interface object
+ */
+ private void updateSriovPfToPserver(final Port port, final LInterface lIf) {
+ if (port.getProfile() == null || Strings
+ .isNullOrEmpty(port.getProfile().get(HeatBridgeConstants.OS_PHYSICAL_NETWORK_KEY).toString())) {
+ logger.debug("The SRIOV port:" + port.getName() + " is missing physical-network-id, cannot update "
+ + "sriov-pf object for host pserver: " + port.getHostId());
+ return;
+ }
+ Optional<String> matchingPifName = HeatBridgeUtils
+ .getMatchingPserverPifName(port.getProfile().get(HeatBridgeConstants.OS_PHYSICAL_NETWORK_KEY).toString());
+ if (matchingPifName.isPresent()) {
+ // Update l-interface description
+ String pserverHostName = port.getHostId();
+ lIf.setInterfaceDescription(
+ "Attached to SR-IOV port: " + pserverHostName + "::" + matchingPifName.get());
+ try {
+ Optional<PInterface> matchingPIf = resourcesClient.get(PInterface.class,
+ AAIUriFactory.createResourceUri(AAIObjectType.P_INTERFACE, pserverHostName, matchingPifName.get()).depth(Depth.ONE));
+ if (matchingPIf.isPresent()) {
+ SriovPfs pIfSriovPfs = matchingPIf.get().getSriovPfs();
+ if (pIfSriovPfs == null) {
+ pIfSriovPfs = new SriovPfs();
+ }
+ // Extract PCI-ID from OS port object
+ String pfPciId = port.getProfile().get(HeatBridgeConstants.OS_PCI_SLOT_KEY).toString();
+
+ List<SriovPf> existingSriovPfs = pIfSriovPfs.getSriovPf();
+ if (CollectionUtils.isEmpty(existingSriovPfs) || existingSriovPfs.stream()
+ .noneMatch(existingSriovPf -> existingSriovPf.getPfPciId().equals(pfPciId))) {
+ // Add sriov-pf object with PCI-ID to AAI
+ SriovPf sriovPf = new SriovPf();
+ sriovPf.setPfPciId(pfPciId);
+ logger.debug("Queuing AAI command to update sriov-pf object to pserver: " + pserverHostName + "/" +
+ matchingPifName.get());
+ transaction.create(AAIUriFactory.createResourceUri(
+ AAIObjectType.SRIOV_PF, pserverHostName, matchingPifName.get(), sriovPf.getPfPciId()), sriovPf);
+ }
+ }
+ } catch (WebApplicationException e) {
+ // Silently log that we failed to update the Pserver p-interface with PCI-ID
+ logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.GENERAL_EXCEPTION, pserverHostName, matchingPifName.get(), cloudOwner,
+ tenantId, "OpenStack", "Heatbridge", ErrorCode.DataError.getValue(), "Exception - Failed to add sriov-pf object to pserver", e);
+ }
+ }
+ }
+
+ private void updateLInterfaceIps(final Port port, final LInterface lIf) {
+ List<L3InterfaceIpv4AddressList> lInterfaceIps = lIf.getL3InterfaceIpv4AddressList();
+ for (IP ip : port.getFixedIps()) {
+ String ipAddress = ip.getIpAddress();
+ if (InetAddressValidator.getInstance().isValidInet4Address(ipAddress)) {
+ L3InterfaceIpv4AddressList lInterfaceIp = new L3InterfaceIpv4AddressList();
+ lInterfaceIp.setL3InterfaceIpv4Address(ipAddress);
+ lInterfaceIp.setNeutronNetworkId(port.getNetworkId());
+ lInterfaceIp.setNeutronSubnetId(ip.getSubnetId());
+ lInterfaceIp.setL3InterfaceIpv4PrefixLength(32L);
+ lInterfaceIps.add(lInterfaceIp);
+ }
+ }
+ }
+
+ @Override
+ public void submitToAai() throws HeatBridgeException {
+ try {
+ transaction.execute();
+ } catch (BulkProcessFailed e) {
+ String msg = "Failed to commit transaction";
+ logger.debug(msg + " with error: " + e);
+ throw new HeatBridgeException(msg, e);
+ }
+ }
+
+ private <T> Predicate<T> distinctByProperty(Function<? super T, Object> keyExtractor) {
+ Map<Object, Boolean> map = new ConcurrentHashMap<>();
+ return t -> map.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
+ }
+}
diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/constants/HeatBridgeConstants.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/constants/HeatBridgeConstants.java
new file mode 100644
index 0000000000..1f302341ad
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/constants/HeatBridgeConstants.java
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2018 Bell Canada. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onap.so.heatbridge.constants;
+
+public class HeatBridgeConstants {
+
+ private HeatBridgeConstants() {
+ throw new IllegalStateException("Trying to instantiate a constants class.");
+ }
+
+ /**
+ * Openstack related constants
+ */
+ public static final Integer OS_DEFAULT_HEAT_NESTING = 5;
+ public static final String OS_SERVER_RESOURCE_TYPE = "OS::Nova::Server";
+ public static final String OS_PORT_RESOURCE_TYPE = "OS::Neutron::Port";
+ public static final String OS_SRIOV_PORT_TYPE = "direct";
+ public static final String OS_PCI_SLOT_KEY = "pci_slot";
+ public static final String OS_PHYSICAL_NETWORK_KEY = "physical_network";
+ public static final String OS_VLAN_NETWORK_KEY = "vlan";
+ public static final String OS_UNKNOWN_KEY = "unknown";
+ public static final String OS_RESOURCES_SELF_LINK_KEY = "self";
+ public static final String OS_DEFAULT_DOMAIN_NAME = "default";
+ public static final String OS_KEYSTONE_V2_KEY = "v2.0";
+ public static final String OS_KEYSTONE_V3_KEY = "v3";
+ public static final String OS_NAME_KEY = "name";
+
+ /**
+ * AAI related constants
+ */
+ public static final String AAI_GENERIC_VNF = "generic-vnf";
+ public static final String AAI_GENERIC_VNF_ID = "generic-vnf.vnf-id";
+ public static final String AAI_PSERVER = "pserver";
+ public static final String AAI_VSERVER = "vserver";
+ public static final String AAI_PSERVER_HOSTNAME = "pserver.hostname";
+ public static final String AAI_VF_MODULE = "vf-module";
+ public static final String AAI_VF_MODULE_ID = "vf-module.vf-module-id";
+ public static final String AAI_IMAGE = "image";
+ public static final String AAI_IMAGE_ID = "image.image-id";
+ public static final String AAI_CLOUD_OWNER = "cloud-region.cloud-owner";
+ public static final String AAI_CLOUD_REGION_ID = "cloud-region.cloud-region-id";
+ public static final String AAI_FLAVOR = "flavor";
+ public static final String AAI_FLAVOR_ID = "flavor.flavor-id";
+ public static final String AAI_RESOURCE_DEPTH_ALL = "all";
+ public static final String AAI_SRIOV_PF = "sriov-pf";
+ public static final String AAI_P_INTERFACE_NAME = "p-interface.interface-name";
+ public static final String AAI_SRIOV_PF_PCI_ID = "sriov-pf.pf-pci-id";
+
+ /**
+ * Keys for internal usage
+ */
+ public static final String KEY_FLAVORS = "flavors";
+ public static final String KEY_IMAGES = "images";
+ public static final String KEY_VSERVERS = "vservers";
+ public static final String KEY_SRIOV_PFS = "pserverSriovPfs";
+ public static final String KEY_GLOBAL_SUBSCRIBER_ID = "globalSubscriberId";
+ public static final String KEY_SERVICE_TYPE = "subscriptionServiceType";
+ public static final String KEY_SERVICE_INSTANCE_ID = "serviceInstanceId";
+ public static final String KEY_VNF_INSTANCE_ID = "genericVnfId";
+ public static final String KEY_MSO_REQUEST_ID = "msoRequestId";
+ public static final String KEY_SO_WORKFLOW_EXCEPTION = "WorkflowException";
+ public static final String KEY_PROCESS_STATUS_MSG = "processStatusMsg";
+}
diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/factory/MsoCloudClientFactory.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/factory/MsoCloudClientFactory.java
new file mode 100644
index 0000000000..100b50e502
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/factory/MsoCloudClientFactory.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2018 Bell Canada. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onap.so.heatbridge.factory;
+
+import org.onap.so.heatbridge.HeatBridgeException;
+import org.onap.so.heatbridge.openstack.api.OpenstackClient;
+
+/**
+ * Defines contract to load the cloud configuration from SO, authenticate with keystone for a given cloud-region and
+ * tenant.
+ */
+public interface MsoCloudClientFactory {
+
+ /**
+ * Get the Openstack Client for keystone version specified in cloud configuration.
+ *
+ * @param url openstack url
+ * @param msoId openstack user for mso
+ * @param msoPass openstack password for mso user
+ * @param cloudRegionId cloud-region identifier
+ * @param tenantId tenant identifier
+ * @return Openstack Client for the keystone version requested
+ * @throws HeatBridgeException if any errors when reading cloud configuration or getting openstack client
+ */
+
+
+ OpenstackClient getOpenstackClient(String url, String msoId, String msoPass, String cloudRegionId, String tenantId) throws HeatBridgeException;
+}
diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/factory/MsoCloudClientFactoryImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/factory/MsoCloudClientFactoryImpl.java
new file mode 100644
index 0000000000..b70b32a4d6
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/factory/MsoCloudClientFactoryImpl.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2018 Bell Canada. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onap.so.heatbridge.factory;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.Objects;
+import javax.annotation.Nonnull;
+import org.onap.so.heatbridge.HeatBridgeException;
+import org.onap.so.heatbridge.constants.HeatBridgeConstants;
+import org.onap.so.heatbridge.openstack.api.OpenstackAccess;
+import org.onap.so.heatbridge.openstack.api.OpenstackAccess.OpenstackAccessBuilder;
+import org.onap.so.heatbridge.openstack.api.OpenstackClient;
+import org.onap.so.heatbridge.openstack.api.OpenstackClientException;
+import org.onap.so.heatbridge.openstack.factory.OpenstackClientFactory;
+import org.onap.so.utils.CryptoUtils;
+
+/**
+ * This class implements {@link MsoCloudClientFactory}
+ * It loads the cloud configuration from SO and uses it to authenticate with keystone.
+ * As a result of authentication with keystone, it returns the Openstack client with the auth token so that
+ * subsequent API calls to Openstack can be made.
+ */
+public class MsoCloudClientFactoryImpl implements MsoCloudClientFactory {
+
+ private OpenstackClientFactory openstackClientFactory;
+
+ public MsoCloudClientFactoryImpl(@Nonnull OpenstackClientFactory openstackClientFactory) {
+ Objects.requireNonNull(openstackClientFactory, "Null OpenstackClientFactory object");
+ this.openstackClientFactory = openstackClientFactory;
+ }
+ @Override
+ public OpenstackClient getOpenstackClient(@Nonnull String url, @Nonnull String msoId, @Nonnull String msoPass, @Nonnull String cloudRegionId, @Nonnull String tenantId) throws
+ HeatBridgeException {
+ Objects.requireNonNull(url, "Null openstack url!");
+ Objects.requireNonNull(msoId, "Null openstack user id!");
+ Objects.requireNonNull(msoPass, "Null openstack password!");
+ Objects.requireNonNull(cloudRegionId, "Null cloud-region ID!");
+ Objects.requireNonNull(tenantId, "Null tenant ID!");
+ try {
+ final OpenstackAccess osAccess = new OpenstackAccessBuilder()
+ .setBaseUrl(url) // keystone URL
+ .setUser(msoId) // keystone username
+ .setPassword(CryptoUtils.decryptCloudConfigPassword(msoPass)) // keystone decrypted password
+ .setRegion(cloudRegionId) // openstack region
+ .setDomainName(HeatBridgeConstants.OS_DEFAULT_DOMAIN_NAME) // hardcode to "default"
+ .setTenantId(tenantId) // tenantId
+ .build();
+
+ // Identify the Keystone version
+ String version = new URL(url).getPath().replace("/", "");
+ if (version.equals(HeatBridgeConstants.OS_KEYSTONE_V2_KEY)) {
+ return openstackClientFactory.createOpenstackV2Client(osAccess);
+ } else if (version.equals(HeatBridgeConstants.OS_KEYSTONE_V3_KEY)) {
+ return openstackClientFactory.createOpenstackV3Client(osAccess);
+ }
+ throw new OpenstackClientException("Unsupported keystone version!");
+ } catch (MalformedURLException e) {
+ throw new HeatBridgeException("Malformed Keystone Endpoint in SO configuration.", e);
+ } catch (OpenstackClientException osClientEx) {
+ throw new HeatBridgeException("Client error when authenticating with the Openstack V3.", osClientEx);
+ }
+ }
+}
diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/helpers/AaiHelper.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/helpers/AaiHelper.java
new file mode 100644
index 0000000000..a0f1f0798f
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/helpers/AaiHelper.java
@@ -0,0 +1,275 @@
+/*
+ * Copyright (C) 2018 Bell Canada.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onap.so.heatbridge.helpers;
+
+import com.google.common.base.Preconditions;
+import com.google.common.collect.ImmutableMap;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import org.apache.commons.collections.CollectionUtils;
+import org.onap.aai.domain.yang.Flavor;
+import org.onap.aai.domain.yang.Image;
+import org.onap.aai.domain.yang.Relationship;
+import org.onap.aai.domain.yang.RelationshipData;
+import org.onap.aai.domain.yang.RelationshipList;
+import org.onap.aai.domain.yang.SriovVf;
+import org.onap.aai.domain.yang.Vserver;
+import org.onap.so.heatbridge.constants.HeatBridgeConstants;
+import org.openstack4j.model.compute.Server;
+
+/**
+ * This class provides wrapper methods to manage creation of AAI objects and extracting objects from AAI and
+ * transforming into required objects.
+ */
+public class AaiHelper {
+
+ /**
+ * Build vserver relationship object to entities: pserver, vf-module, image, flavor
+ *
+ * @param cloudOwner AAI cloudOwner value
+ * @param cloudRegionId AAI cloud-region identifier
+ * @param genericVnfId AAI generic-vnf identifier
+ * @param vfModuleId AAI vf-module identifier
+ * @param server Openstack Server object
+ */
+ public RelationshipList getVserverRelationshipList(final String cloudOwner, final String cloudRegionId, final String
+ genericVnfId, final String vfModuleId, final Server server) {
+ RelationshipList relationshipList = new RelationshipList();
+ List<Relationship> relationships = relationshipList.getRelationship();
+
+ // vserver to pserver relationship
+ Relationship pserverRelationship = buildRelationship(HeatBridgeConstants.AAI_PSERVER,
+ ImmutableMap.<String, String>builder()
+ .put(HeatBridgeConstants.AAI_PSERVER_HOSTNAME, server.getHypervisorHostname())
+ .build());
+ relationships.add(pserverRelationship);
+
+ // vserver to vf-module relationship
+ Relationship vfModuleRelationship = buildRelationship(HeatBridgeConstants.AAI_VF_MODULE,
+ ImmutableMap.<String, String>builder()
+ .put(HeatBridgeConstants.AAI_GENERIC_VNF_ID, genericVnfId)
+ .put(HeatBridgeConstants.AAI_VF_MODULE_ID, vfModuleId)
+ .build());
+ relationships.add(vfModuleRelationship);
+
+ // vserver to image relationship
+ Relationship imageRel = buildRelationship(HeatBridgeConstants.AAI_IMAGE,
+ ImmutableMap.<String, String>builder()
+ .put(HeatBridgeConstants.AAI_CLOUD_OWNER, cloudOwner)
+ .put(HeatBridgeConstants.AAI_CLOUD_REGION_ID, cloudRegionId)
+ .put(HeatBridgeConstants.AAI_IMAGE_ID, server.getImage().getId())
+ .build());
+ relationships.add(imageRel);
+
+ // vserver to flavor relationship
+ Relationship flavorRel = buildRelationship(HeatBridgeConstants.AAI_FLAVOR,
+ ImmutableMap.<String, String>builder()
+ .put(HeatBridgeConstants.AAI_CLOUD_OWNER, cloudOwner)
+ .put(HeatBridgeConstants.AAI_CLOUD_REGION_ID, cloudRegionId)
+ .put(HeatBridgeConstants.AAI_FLAVOR_ID, server.getFlavor().getId())
+ .build());
+ relationships.add(flavorRel);
+ return relationshipList;
+ }
+
+ public RelationshipList getLInterfaceRelationshipList(final String pserverName, final String pIfName,
+ final String pfPciId) {
+ RelationshipList relationshipList = new RelationshipList();
+ List<Relationship> relationships = relationshipList.getRelationship();
+
+ // sriov-vf to sriov-pf relationship
+ Relationship sriovPfRelationship = buildRelationship(HeatBridgeConstants.AAI_SRIOV_PF,
+ ImmutableMap.<String, String>builder()
+ .put(HeatBridgeConstants.AAI_PSERVER_HOSTNAME, pserverName)
+ .put(HeatBridgeConstants.AAI_P_INTERFACE_NAME, pIfName)
+ .put(HeatBridgeConstants.AAI_SRIOV_PF_PCI_ID, pfPciId)
+ .build());
+ relationships.add(sriovPfRelationship);
+
+ return relationshipList;
+ }
+
+ /**
+ * Transform Openstack Server object to AAI Vserver object
+ *
+ * @param serverId Openstack server identifier
+ * @param server Openstack server object
+ * @return AAI Vserver object
+ */
+ public Vserver buildVserver(final String serverId, final Server server) {
+ Vserver vserver = new Vserver();
+ vserver.setInMaint(false);
+ vserver.setIsClosedLoopDisabled(false);
+ vserver.setVserverId(serverId);
+ vserver.setVserverName(server.getName());
+ vserver.setVserverName2(server.getName());
+ vserver.setProvStatus(server.getStatus().value());
+ server.getLinks().stream().filter(link -> link.getRel().equals(HeatBridgeConstants.OS_RESOURCES_SELF_LINK_KEY))
+ .findFirst().ifPresent(link -> vserver.setVserverSelflink(link.getHref()));
+ return vserver;
+ }
+
+ /**
+ * Transform Openstack Image object to AAI Image object
+ *
+ * @param image Openstack Image object
+ * @return AAI Image object
+ */
+ public Image buildImage(final org.openstack4j.model.compute.Image image) {
+ Image aaiImage = new Image();
+ aaiImage.setImageId(image.getId());
+ aaiImage.setImageName(image.getName());
+ aaiImage.setImageOsDistro(HeatBridgeConstants.OS_UNKNOWN_KEY);
+ aaiImage.setImageOsVersion(HeatBridgeConstants.OS_UNKNOWN_KEY);
+ image.getLinks().stream().filter(link -> link.getRel().equals(HeatBridgeConstants.OS_RESOURCES_SELF_LINK_KEY))
+ .findFirst().ifPresent(link -> aaiImage.setImageSelflink(link.getHref()));
+ return aaiImage;
+ }
+
+ /**
+ * Transform Openstack Flavor object to AAI Flavor object
+ *
+ * @param flavor Openstack Flavor object
+ * @return AAI Flavor object
+ */
+ public Flavor buildFlavor(final org.openstack4j.model.compute.Flavor flavor) {
+ Flavor aaiFlavor = new Flavor();
+ aaiFlavor.setFlavorId(flavor.getId());
+ aaiFlavor.setFlavorName(flavor.getName());
+ flavor.getLinks().stream().filter(link -> link.getRel().equals(HeatBridgeConstants.OS_RESOURCES_SELF_LINK_KEY))
+ .findFirst().ifPresent(link -> aaiFlavor.setFlavorSelflink(link.getHref()));
+ return aaiFlavor;
+ }
+
+ /**
+ * Extract a list of flavors URI associated with the list of vservers
+ *
+ * @param vservers List of vserver AAI objects
+ * @return a list of related flavor related-links
+ */
+ public List<String> getFlavorsUriFromVserver(final List<Vserver> vservers) {
+ List<String> flavorUris = new ArrayList<>();
+ vservers.forEach(vserver -> flavorUris.addAll(
+ filterRelatedLinksByRelatedToProperty(vserver.getRelationshipList(), HeatBridgeConstants.AAI_FLAVOR)));
+ return flavorUris;
+ }
+
+ /**
+ * Extract a list of images URI associated with the list of vservers
+ *
+ * @param vservers List of vserver AAI objects
+ * @return a list of related image related-links
+ */
+ public List<String> getImagesUriFromVserver(final List<Vserver> vservers) {
+ List<String> imageUris = new ArrayList<>();
+ vservers.forEach(vserver -> imageUris.addAll(
+ filterRelatedLinksByRelatedToProperty(vserver.getRelationshipList(), HeatBridgeConstants.AAI_IMAGE)));
+ return imageUris;
+ }
+
+ /**
+ * From the list vserver objects build a map of compute hosts's name and the PCI IDs linked to it.
+ *
+ * @param vservers List of vserver AAI objects
+ * @return a map of compute names to the PCI ids associated with the compute
+ */
+ public Map<String, List<String>> getPserverToPciIdMap(final List<Vserver> vservers) {
+ Map<String, List<String>> pserverToPciIdMap = new HashMap<>();
+ for(Vserver vserver : vservers) {
+ if(vserver.getLInterfaces() != null) {
+ List<String> pciIds = vserver.getLInterfaces().getLInterface()
+ .stream()
+ .filter(lInterface -> lInterface.getSriovVfs() != null
+ && CollectionUtils.isNotEmpty(lInterface.getSriovVfs().getSriovVf()))
+ .flatMap(lInterface -> lInterface.getSriovVfs().getSriovVf().stream())
+ .map(SriovVf::getPciId)
+ .collect(Collectors.toList());
+ if (CollectionUtils.isNotEmpty(pciIds)) {
+ List<String> matchingPservers = extractRelationshipDataValue(vserver.getRelationshipList(),
+ HeatBridgeConstants.AAI_PSERVER, HeatBridgeConstants.AAI_PSERVER_HOSTNAME);
+ Preconditions.checkState(matchingPservers != null && matchingPservers.size() == 1,
+ "Invalid pserver relationships for vserver: " + vserver.getVserverName());
+ pserverToPciIdMap.put(matchingPservers.get(0), pciIds);
+ }
+ }
+ }
+ return pserverToPciIdMap;
+ }
+
+ /**
+ * Extract from relationship-list object all the relationship-value that match the related-to and
+ * relationship-key fields.
+ *
+ * @param relationshipListObj AAI relationship-list object
+ * @param relatedToProperty related-to value
+ * @param relationshipKey relationship-key value
+ * @return relationship-value matching the key requested for the relationship object of type related-to property
+ */
+ private List<String> extractRelationshipDataValue(final RelationshipList relationshipListObj,
+ final String relatedToProperty, final String relationshipKey) {
+ if (relationshipListObj != null && relationshipListObj.getRelationship() != null) {
+ return relationshipListObj.getRelationship().stream()
+ .filter(relationship -> relationship.getRelatedTo().equals(relatedToProperty))
+ .map(Relationship::getRelationshipData)
+ .flatMap(Collection::stream)
+ .filter(data -> data.getRelationshipKey() != null && relationshipKey.equals(data.getRelationshipKey()))
+ .map(RelationshipData::getRelationshipValue)
+ .collect(Collectors.toList());
+ }
+ return new ArrayList<>();
+ }
+
+ /**
+ * Extract and filter the related-links to all objects that match the type specified by the filter property
+ *
+ * @param relationshipListObj AAI object representing relationship object
+ * @param relatedToProperty Value identifying the type of AAI object for related-to field
+ * @return a list of related-links filtered by the specified related-to property
+ */
+ private List<String> filterRelatedLinksByRelatedToProperty(final RelationshipList relationshipListObj,
+ final String relatedToProperty) {
+ if (relationshipListObj != null && relationshipListObj.getRelationship() != null) {
+ return relationshipListObj.getRelationship().stream()
+ .filter(relationship -> relationship.getRelatedTo().equals(relatedToProperty))
+ .map(Relationship::getRelatedLink)
+ .collect(Collectors.toList());
+ }
+ return new ArrayList<>();
+ }
+
+ /**
+ * Build the relationship object
+ *
+ * @param relatedTo Related to entity value
+ * @param relationshipKeyValues Key value pairs of relationship data
+ * @return AAI Relationship object
+ */
+ private Relationship buildRelationship(final String relatedTo, final Map<String, String> relationshipKeyValues) {
+ Relationship relationship = new Relationship();
+ relationship.setRelatedTo(relatedTo);
+ relationshipKeyValues.keySet().forEach(k -> {
+ RelationshipData relationshipData = new RelationshipData();
+ relationshipData.setRelationshipKey(k);
+ relationshipData.setRelationshipValue(relationshipKeyValues.get(k));
+ relationship.getRelationshipData().add(relationshipData);
+ });
+ return relationship;
+ }
+}
diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/api/OpenstackAccess.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/api/OpenstackAccess.java
new file mode 100644
index 0000000000..fd5dabc784
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/api/OpenstackAccess.java
@@ -0,0 +1,120 @@
+/*-
+ * Copyright (C) 2018 Bell Canada. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onap.so.heatbridge.openstack.api;
+
+import org.openstack4j.model.common.Identifier;
+
+/**
+ * Object handling OpenStack API access information.
+ */
+public class OpenstackAccess {
+ private final String baseUrl;
+ private final String tenantId;
+ private final String user;
+ private final String password;
+ private final String region;
+ private String domainName;
+ private String projectName;
+
+ public OpenstackAccess(OpenstackAccessBuilder builder) {
+ this.baseUrl = builder.baseUrl;
+ this.tenantId = builder.tenantId;
+ this.user = builder.user;
+ this.password = builder.password;
+ this.region = builder.region;
+ this.domainName = builder.domainName;
+ this.projectName = builder.projectName;
+ }
+
+ public String getUrl() {
+ return baseUrl;
+ }
+
+ public String getTenantId() {
+ return tenantId;
+ }
+
+ public String getUser() {
+ return user;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public String getRegion() {
+ return region;
+ }
+
+ public Identifier getDomainNameIdentifier() {
+ return Identifier.byName(domainName);
+ }
+
+ public String getProjectName() {
+ return projectName;
+ }
+
+ public static class OpenstackAccessBuilder {
+
+ private String baseUrl;
+ private String tenantId;
+ private String user;
+ private String password;
+ private String region;
+ private String domainName;
+ private String projectName;
+
+ public OpenstackAccessBuilder setBaseUrl(final String baseUrl) {
+ this.baseUrl = baseUrl;
+ return this;
+ }
+
+ public OpenstackAccessBuilder setTenantId(final String tenantId) {
+ this.tenantId = tenantId;
+ return this;
+ }
+
+ public OpenstackAccessBuilder setUser(final String user) {
+ this.user = user;
+ return this;
+ }
+
+ public OpenstackAccessBuilder setPassword(final String password) {
+ this.password = password;
+ return this;
+ }
+
+ public OpenstackAccessBuilder setRegion(final String region) {
+ this.region = region;
+ return this;
+ }
+
+ public OpenstackAccessBuilder setDomainName(final String domainName) {
+ this.domainName = domainName;
+ return this;
+ }
+
+ public OpenstackAccessBuilder setProjectName(final String projectName) {
+ this.projectName = projectName;
+ return this;
+ }
+
+ public OpenstackAccess build() {
+ return new OpenstackAccess(this);
+ }
+ }
+}
diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/api/OpenstackClient.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/api/OpenstackClient.java
new file mode 100644
index 0000000000..143e33581d
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/api/OpenstackClient.java
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (C) 2018 Bell Canada. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onap.so.heatbridge.openstack.api;
+
+import java.util.List;
+import java.util.Map;
+import org.openstack4j.model.compute.Server;
+import org.openstack4j.model.heat.Resource;
+import org.openstack4j.model.network.Network;
+import org.openstack4j.model.network.Port;
+
+public interface OpenstackClient {
+
+ /**
+ * Get a server object by server ID
+ * @param serverId Unique server-name (simple name) or server-id (UUID)
+ * @return Server object
+ */
+ Server getServerById(String serverId);
+
+ /**
+ * Get a port object by port ID
+ * @param portId Unique UUID of the port.
+ * @return Port object.
+ */
+ Port getPortById(String portId);
+
+ /**
+ * Returns a list of all ports we have the right to see
+ * @return List of all Openstack ports
+ */
+ List<Port> getAllPorts();
+
+ /**
+ * Returns a list of all the resources for the stack
+ * @param stackId Stack name or unique UUID
+ * @param nestingDepth The recursion level for which resources will be listed.
+ * @return List of Openstack Stack resources
+ */
+ List<Resource> getStackBasedResources(String stackId, int nestingDepth);
+
+ /**
+ * Get a network instance by network ID
+ * @param networkId Unique UUID of the network.
+ * @return Network object.
+ */
+ Network getNetworkById(String networkId);
+
+ /**
+ * List networks by filtering parameters
+ * @param filterParams key-value pairs for filtering params
+ * @return List of filtered Network objects
+ */
+ List<Network> listNetworksByFilter(Map<String, String> filterParams);
+}
diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/api/OpenstackClientException.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/api/OpenstackClientException.java
new file mode 100644
index 0000000000..a062ca826d
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/api/OpenstackClientException.java
@@ -0,0 +1,29 @@
+/*-
+ * Copyright (C) 2018 Bell Canada. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onap.so.heatbridge.openstack.api;
+
+public class OpenstackClientException extends Exception {
+ private static final long serialVersionUID = -5514207977226960180L;
+
+ public OpenstackClientException(final String message) {
+ super(message);
+ }
+
+ public OpenstackClientException(final String message, final Throwable cause) {
+ super(message, cause);
+ }
+}
diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/api/OpenstackClientImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/api/OpenstackClientImpl.java
new file mode 100644
index 0000000000..ebd4753323
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/api/OpenstackClientImpl.java
@@ -0,0 +1,69 @@
+/*-
+ * Copyright (C) 2018 Bell Canada. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onap.so.heatbridge.openstack.api;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.stream.Collectors;
+import org.openstack4j.api.OSClient;
+import org.openstack4j.model.compute.Server;
+import org.openstack4j.model.heat.Resource;
+import org.openstack4j.model.network.Network;
+import org.openstack4j.model.network.Port;
+
+abstract class OpenstackClientImpl implements OpenstackClient {
+ @Override
+ public Server getServerById(String serverId) {
+ return getClient().compute().servers().get(serverId);
+ }
+
+ @Override
+ public Port getPortById(String portId) {
+ return getClient().networking().port().get(portId);
+ }
+
+ @Override
+ public List<Port> getAllPorts() { return (List<Port>)getClient().networking().port().list(); }
+
+ @Override
+ public List<Resource> getStackBasedResources(String stackId, int nestingDepth) {
+ return getClient().heat()
+ .resources()
+ .list(stackId, nestingDepth)
+ .stream()
+ .filter(Objects::nonNull)
+ .collect(Collectors.toList());
+ }
+
+ @Override
+ public Network getNetworkById(String networkId) {
+ return getClient().networking().network().get(networkId);
+ }
+
+ @Override
+ public List<Network> listNetworksByFilter(Map<String, String> filterParams) {
+ return (List<Network>) getClient().networking().network().list(filterParams);
+ }
+
+ /**
+ * Retrieves the specific client to utilize.
+ * @return The specific client to utilize
+ */
+ protected abstract OSClient getClient();
+
+}
diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/api/OpenstackV2ClientImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/api/OpenstackV2ClientImpl.java
new file mode 100644
index 0000000000..760be72b3f
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/api/OpenstackV2ClientImpl.java
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (C) 2018 Bell Canada. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onap.so.heatbridge.openstack.api;
+
+import org.openstack4j.api.OSClient;
+import org.openstack4j.api.OSClient.OSClientV2;
+
+public class OpenstackV2ClientImpl extends OpenstackClientImpl {
+
+ private OSClientV2 client;
+
+ public OpenstackV2ClientImpl(OSClientV2 client) {
+ this.client = client;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected OSClient getClient() {
+ return client;
+ }
+
+}
diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/api/OpenstackV3ClientImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/api/OpenstackV3ClientImpl.java
new file mode 100644
index 0000000000..dddd82ce6a
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/api/OpenstackV3ClientImpl.java
@@ -0,0 +1,37 @@
+/*-
+ * Copyright (C) 2018 Bell Canada. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onap.so.heatbridge.openstack.api;
+
+import org.openstack4j.api.OSClient;
+import org.openstack4j.api.OSClient.OSClientV3;
+
+public class OpenstackV3ClientImpl extends OpenstackClientImpl {
+
+ private OSClientV3 client;
+
+ public OpenstackV3ClientImpl(OSClientV3 client) {
+ this.client = client;
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ protected OSClient getClient() {
+ return client;
+ }
+
+}
diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/factory/OpenstackClientFactory.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/factory/OpenstackClientFactory.java
new file mode 100644
index 0000000000..5019eec09b
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/factory/OpenstackClientFactory.java
@@ -0,0 +1,27 @@
+/*-
+ * Copyright (C) 2018 Bell Canada. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onap.so.heatbridge.openstack.factory;
+
+import org.onap.so.heatbridge.openstack.api.OpenstackAccess;
+import org.onap.so.heatbridge.openstack.api.OpenstackClient;
+import org.onap.so.heatbridge.openstack.api.OpenstackClientException;
+
+public interface OpenstackClientFactory {
+
+ OpenstackClient createOpenstackV3Client(OpenstackAccess osAccess) throws OpenstackClientException;
+
+ OpenstackClient createOpenstackV2Client(OpenstackAccess osAccess) throws OpenstackClientException;
+}
diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/factory/OpenstackClientFactoryImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/factory/OpenstackClientFactoryImpl.java
new file mode 100644
index 0000000000..72b3795053
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/openstack/factory/OpenstackClientFactoryImpl.java
@@ -0,0 +1,74 @@
+/*-
+ * Copyright (C) 2018 Bell Canada. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onap.so.heatbridge.openstack.factory;
+
+import com.google.common.base.Preconditions;
+import org.onap.so.heatbridge.openstack.api.OpenstackAccess;
+import org.onap.so.heatbridge.openstack.api.OpenstackClient;
+import org.onap.so.heatbridge.openstack.api.OpenstackClientException;
+import org.onap.so.heatbridge.openstack.api.OpenstackV2ClientImpl;
+import org.onap.so.heatbridge.openstack.api.OpenstackV3ClientImpl;
+import org.openstack4j.api.OSClient.OSClientV2;
+import org.openstack4j.api.OSClient.OSClientV3;
+import org.openstack4j.api.exceptions.AuthenticationException;
+import org.openstack4j.openstack.OSFactory;
+
+public class OpenstackClientFactoryImpl implements OpenstackClientFactory {
+
+ @Override
+ public OpenstackClient createOpenstackV3Client(OpenstackAccess osAccess) throws OpenstackClientException {
+ Preconditions.checkNotNull(osAccess.getUrl(), "Keystone-v3 Auth: endpoint not set.");
+ Preconditions.checkNotNull(osAccess.getUser(), "Keystone-v3 Auth: username not set.");
+ Preconditions.checkNotNull(osAccess.getPassword(), "Keystone-v3 Auth: password not set.");
+ Preconditions.checkNotNull(osAccess.getDomainNameIdentifier(), "Keystone-v3 Auth: domain not set.");
+ Preconditions.checkNotNull(osAccess.getRegion(), "Keystone-v3 Auth: region not set.");
+
+ OSClientV3 client;
+ try {
+ client = OSFactory.builderV3()
+ .endpoint(osAccess.getUrl())
+ .credentials(osAccess.getUser(), osAccess.getPassword(), osAccess.getDomainNameIdentifier())
+ .authenticate()
+ .useRegion(osAccess.getRegion());
+ return new OpenstackV3ClientImpl(client);
+ } catch (AuthenticationException exception) {
+ throw new OpenstackClientException("Failed to authenticate with Keystone-v3: " + osAccess.getUrl(), exception);
+ }
+ }
+
+ @Override
+ public OpenstackClient createOpenstackV2Client(OpenstackAccess osAccess) throws OpenstackClientException {
+ Preconditions.checkNotNull(osAccess.getUrl(), "Keystone-v2 Auth: endpoint not set.");
+ Preconditions.checkNotNull(osAccess.getUser(), "Keystone-v2 Auth: username not set.");
+ Preconditions.checkNotNull(osAccess.getPassword(), "Keystone-v2 Auth: password not set.");
+ Preconditions.checkNotNull(osAccess.getTenantId(), "Keystone-v2 Auth: domain not set.");
+ Preconditions.checkNotNull(osAccess.getRegion(), "Keystone-v2 Auth: region not set.");
+
+ OSClientV2 client;
+ try {
+ client = OSFactory.builderV2()
+ .endpoint(osAccess.getUrl())
+ .credentials(osAccess.getUser(), osAccess.getPassword())
+ .tenantId(osAccess.getTenantId())
+ .authenticate()
+ .useRegion(osAccess.getRegion());
+ return new OpenstackV2ClientImpl(client);
+ } catch (AuthenticationException exception) {
+ throw new OpenstackClientException("Failed to authenticate with Keystone-v2.0: " + osAccess.getUrl(),
+ exception);
+ }
+ }
+}
diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/utils/HeatBridgeUtils.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/utils/HeatBridgeUtils.java
new file mode 100644
index 0000000000..7daa8c2c71
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/heatbridge/utils/HeatBridgeUtils.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2018 Bell Canada. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.onap.so.heatbridge.utils;
+
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+import java.util.Optional;
+import javax.annotation.Nonnull;
+
+public class HeatBridgeUtils {
+
+ private HeatBridgeUtils() {
+ throw new IllegalStateException("Trying to instantiate a utility class.");
+ }
+
+ /**
+ * IaaS naming convention for compute/p-interface to openstack/physical-network name mapping
+ */
+ private static final String OS_SIDE_SHARED_SRIOV_PREFIX = "shared-";
+ private static final String OS_SIDE_DEDICATED_SRIOV_PREFIX = "dedicated-";
+ private static final String COMPUTE_SIDE_SHARED_SRIOV_PREFIX = "sriov-s-";
+ private static final String COMPUTE_SIDE_DEDICATED_SRIOV_PREFIX = "sriov-d-";
+
+ public static Optional<String> getMatchingPserverPifName(@Nonnull final String physicalNetworkName) {
+ Preconditions.checkState(!Strings.isNullOrEmpty(physicalNetworkName), "Physical network name is null or "
+ + "empty!");
+ if (physicalNetworkName.contains(OS_SIDE_DEDICATED_SRIOV_PREFIX)) {
+ return Optional
+ .of(physicalNetworkName.replace(OS_SIDE_DEDICATED_SRIOV_PREFIX, COMPUTE_SIDE_DEDICATED_SRIOV_PREFIX));
+ } else if (physicalNetworkName.contains(OS_SIDE_SHARED_SRIOV_PREFIX)) {
+ return Optional
+ .of(physicalNetworkName.replace(OS_SIDE_SHARED_SRIOV_PREFIX, COMPUTE_SIDE_SHARED_SRIOV_PREFIX));
+ }
+ return Optional.empty();
+ }
+
+ public static Optional<String> getMatchingPhysicalNetworkName(final String pserverPinterfaceName) {
+ if (pserverPinterfaceName.contains(COMPUTE_SIDE_DEDICATED_SRIOV_PREFIX)) {
+ return Optional
+ .of(pserverPinterfaceName.replace(COMPUTE_SIDE_DEDICATED_SRIOV_PREFIX, OS_SIDE_DEDICATED_SRIOV_PREFIX));
+ } else if (pserverPinterfaceName.contains(COMPUTE_SIDE_SHARED_SRIOV_PREFIX)) {
+ return Optional
+ .of(pserverPinterfaceName.replace(COMPUTE_SIDE_SHARED_SRIOV_PREFIX, OS_SIDE_SHARED_SRIOV_PREFIX));
+ }
+ return Optional.empty();
+ }
+}
diff --git a/adapters/mso-openstack-adapters/src/test/java/org/onap/so/heatbridge/HeatBridgeImplTest.java b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/heatbridge/HeatBridgeImplTest.java
new file mode 100644
index 0000000000..3c777e17cb
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/heatbridge/HeatBridgeImplTest.java
@@ -0,0 +1,375 @@
+/*
+ * Copyright (C) 2018 Bell Canada. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.onap.so.heatbridge;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.Charset;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+import org.apache.commons.io.FileUtils;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.onap.aai.domain.yang.LInterface;
+import org.onap.aai.domain.yang.PInterface;
+import org.onap.aai.domain.yang.SriovPf;
+import org.onap.aai.domain.yang.Vserver;
+import org.onap.so.client.aai.AAIObjectType;
+import org.onap.so.client.aai.AAIResourcesClient;
+import org.onap.so.client.aai.AAISingleTransactionClient;
+import org.onap.so.client.aai.entities.uri.AAIResourceUri;
+import org.onap.so.client.aai.entities.uri.AAIUriFactory;
+import org.onap.so.client.graphinventory.exceptions.BulkProcessFailed;
+import org.onap.so.db.catalog.beans.CloudIdentity;
+import org.onap.so.heatbridge.constants.HeatBridgeConstants;
+import org.onap.so.heatbridge.openstack.api.OpenstackClient;
+import org.onap.so.heatbridge.openstack.api.OpenstackClientException;
+import org.openstack4j.model.compute.Flavor;
+import org.openstack4j.model.compute.Image;
+import org.openstack4j.model.compute.Server;
+import org.openstack4j.model.compute.Server.Status;
+import org.openstack4j.model.heat.Resource;
+import org.openstack4j.model.network.Network;
+import org.openstack4j.model.network.NetworkType;
+import org.openstack4j.model.network.Port;
+import org.openstack4j.openstack.heat.domain.HeatResource;
+import org.openstack4j.openstack.heat.domain.HeatResource.Resources;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.google.common.collect.ImmutableMap;
+
+
+@RunWith(MockitoJUnitRunner.class)
+public class HeatBridgeImplTest {
+
+ private static final String CLOUD_OWNER = "CloudOwner";
+ private static final String REGION_ID = "RegionOne";
+ private static final String TENANT_ID = "7320ec4a5b9d4589ba7c4412ccfd290f";
+ private static final ObjectMapper MAPPER = new ObjectMapper();
+
+ @Mock
+ private OpenstackClient osClient;
+
+ private CloudIdentity cloudIdentity = new CloudIdentity();
+
+ @Mock
+ private AAIResourcesClient resourcesClient;
+ @Mock
+ private AAISingleTransactionClient transaction;
+
+ private HeatBridgeImpl heatbridge;
+
+ @Before
+ public void setUp() throws HeatBridgeException, OpenstackClientException, BulkProcessFailed {
+
+ when(resourcesClient.beginSingleTransaction()).thenReturn(transaction);
+ heatbridge = new HeatBridgeImpl(resourcesClient, cloudIdentity, CLOUD_OWNER, REGION_ID, TENANT_ID);
+ }
+
+ @Ignore
+ @Test
+ public void testQueryNestedHeatStackResources() throws HeatBridgeException {
+ // Arrange
+ String heatStackId = "1234567";
+ List<Resource> expectedResourceList = (List<Resource>) extractTestStackResources();
+ when(osClient.getStackBasedResources(heatStackId, HeatBridgeConstants.OS_DEFAULT_HEAT_NESTING))
+ .thenReturn(expectedResourceList);
+
+ // Act
+ List<Resource> resourceList = heatbridge.queryNestedHeatStackResources(heatStackId);
+
+ // Assert
+ verify(osClient).getStackBasedResources(heatStackId, HeatBridgeConstants.OS_DEFAULT_HEAT_NESTING);
+ assertEquals(resourceList, expectedResourceList);
+ }
+
+ @Test
+ public void testExtractStackResourceIdsByResourceType() throws HeatBridgeException {
+ // Arrange
+ List<Resource> expectedResourceList = (List<Resource>) extractTestStackResources();
+ List<String> expectedServerIds = Arrays.asList("43c2159b-2c04-46ac-bda5-594110cae2d3",
+ "7cff109a-b2b7-4933-97b4-ec44a8365568");
+
+ // Act
+ List<String> serverIds = heatbridge
+ .extractStackResourceIdsByResourceType(expectedResourceList, HeatBridgeConstants.OS_SERVER_RESOURCE_TYPE);
+
+ // Assert
+ assertEquals(expectedServerIds, serverIds);
+ }
+
+ @Ignore
+ @Test
+ public void testGetAllOpenstackServers() {
+ // Arrange
+ List<Resource> stackResources = (List<Resource>) extractTestStackResources();
+
+ Server server1 = mock(Server.class);
+ Server server2 = mock(Server.class);
+ List<Server> expectedServers = Arrays.asList(server1, server2);
+
+ when(osClient.getServerById("43c2159b-2c04-46ac-bda5-594110cae2d3")).thenReturn(server1);
+ when(osClient.getServerById("7cff109a-b2b7-4933-97b4-ec44a8365568")).thenReturn(server2);
+
+ // Act
+ List<Server> servers = heatbridge.getAllOpenstackServers(stackResources);
+
+ // Assert
+ assertEquals(expectedServers, servers);
+ }
+
+ @Ignore
+ @Test
+ public void testExtractOpenstackImagesFromServers() {
+ // Arrange
+ Server server1 = mock(Server.class);
+ Server server2 = mock(Server.class);
+ List<Server> servers = Arrays.asList(server1, server2);
+
+ Image image1 = mock(Image.class);
+ Image image2 = mock(Image.class);
+ when(image1.getId()).thenReturn("1");
+ when(image2.getId()).thenReturn("1");
+ List<Image> expectedDistinctImages = Collections.singletonList(image1);
+
+ when(server1.getImage()).thenReturn(image1);
+ when(server2.getImage()).thenReturn(image2);
+
+ // Act
+ List<Image> images = heatbridge.extractOpenstackImagesFromServers(servers);
+
+ // Assert
+ assertEquals(expectedDistinctImages, images);
+ }
+
+ @Ignore
+ @Test
+ public void testExtractOpenstackFlavorsFromServers() {
+ // Arrange
+ Server server1 = mock(Server.class);
+ Server server2 = mock(Server.class);
+ List<Server> servers = Arrays.asList(server1, server2);
+
+ Flavor flavor1 = mock(Flavor.class);
+ Flavor flavor2 = mock(Flavor.class);
+ when(flavor1.getId()).thenReturn("1");
+ when(flavor2.getId()).thenReturn("2");
+ List<Flavor> expectedFlavors = Arrays.asList(flavor1, flavor2);
+
+ when(server1.getFlavor()).thenReturn(flavor1);
+ when(server2.getFlavor()).thenReturn(flavor2);
+
+ // Act
+ List<Flavor> flavors = heatbridge.extractOpenstackFlavorsFromServers(servers);
+
+ // Assert
+ assertEquals(expectedFlavors, flavors);
+ }
+
+ @Test
+ public void testUpdateVserversToAai() throws HeatBridgeException {
+ // Arrange
+ Server server1 = mock(Server.class);
+
+ when(server1.getId()).thenReturn("test-server1-id");
+ when(server1.getHypervisorHostname()).thenReturn("test-hypervisor");
+ when(server1.getName()).thenReturn("test-server1-name");
+ when(server1.getStatus()).thenReturn(Status.ACTIVE);
+ when(server1.getLinks()).thenReturn(new ArrayList<>());
+
+ Server server2 = mock(Server.class);
+ when(server2.getId()).thenReturn("test-server2-id");
+ when(server2.getHypervisorHostname()).thenReturn("test-hypervisor");
+ when(server2.getName()).thenReturn("test-server2-name");
+ when(server2.getStatus()).thenReturn(Status.ACTIVE);
+ when(server2.getLinks()).thenReturn(new ArrayList<>());
+
+ List<Server> servers = Arrays.asList(server1, server2);
+
+ Image image = mock(Image.class);
+ when(server1.getImage()).thenReturn(image);
+ when(server2.getImage()).thenReturn(image);
+ when(image.getId()).thenReturn("test-image-id");
+
+ Flavor flavor = mock(Flavor.class);
+ when(server1.getFlavor()).thenReturn(flavor);
+ when(server2.getFlavor()).thenReturn(flavor);
+ when(flavor.getId()).thenReturn("test-flavor-id");
+
+
+ // Act
+ heatbridge.buildAddVserversToAaiAction("test-genericVnf-id", "test-vfModule-id", servers);
+
+ // Assert
+ ArgumentCaptor<AAIResourceUri> captor = ArgumentCaptor.forClass(AAIResourceUri.class);
+ verify(transaction, times(2)).create(captor.capture(), any(Vserver.class));
+
+ List<AAIResourceUri> uris = captor.getAllValues();
+ assertEquals(AAIUriFactory.createResourceUri(
+ AAIObjectType.VSERVER, CLOUD_OWNER, REGION_ID, TENANT_ID, server1.getId()), uris.get(0));
+ assertEquals(AAIUriFactory.createResourceUri(
+ AAIObjectType.VSERVER, CLOUD_OWNER, REGION_ID, TENANT_ID, server2.getId()), uris.get(1));
+
+ }
+
+ @Test
+ public void testUpdateImagesToAai() throws HeatBridgeException {
+ // Arrange
+ Image image1 = mock(Image.class);
+ when(image1.getId()).thenReturn("test-image1-id");
+ when(image1.getName()).thenReturn("test-image1-name");
+ when(image1.getLinks()).thenReturn(new ArrayList<>());
+
+ Image image2 = mock(Image.class);
+ when(image2.getId()).thenReturn("test-image2-id");
+ when(image2.getName()).thenReturn("test-image2-name");
+ when(image2.getLinks()).thenReturn(new ArrayList<>());
+
+ List<Image> images = Arrays.asList(image1, image2);
+
+ // Act #1
+ heatbridge.buildAddImagesToAaiAction(images);
+
+ // Assert #1
+ verify(transaction, times(2)).create(any(AAIResourceUri.class), any(org.onap.aai.domain.yang.Image.class));
+
+ // Act #2
+ heatbridge.buildAddImagesToAaiAction(images);
+
+ // Assert #2
+ verify(transaction, times(4)).create(any(AAIResourceUri.class), any(org.onap.aai.domain.yang.Image.class));
+ }
+
+ @Test
+ public void testUpdateFlavorsToAai() throws HeatBridgeException {
+ // Arrange
+ Flavor flavor1 = mock(Flavor.class);
+ when(flavor1.getId()).thenReturn("test-flavor1-id");
+ when(flavor1.getName()).thenReturn("test-flavor1-name");
+ when(flavor1.getLinks()).thenReturn(new ArrayList<>());
+
+ Flavor flavor2 = mock(Flavor.class);
+ when(flavor2.getId()).thenReturn("test-flavor2-id");
+ when(flavor2.getName()).thenReturn("test-flavor2-name");
+ when(flavor2.getLinks()).thenReturn(new ArrayList<>());
+
+ List<Flavor> flavors = Arrays.asList(flavor1, flavor2);
+
+ // Act #1
+ heatbridge.buildAddFlavorsToAaiAction(flavors);
+
+ // Assert #1
+ verify(transaction, times(2)).create(any(AAIResourceUri.class), any(org.onap.aai.domain.yang.Flavor.class));
+
+ // Act #2
+ heatbridge.buildAddFlavorsToAaiAction(flavors);
+
+ // Assert #2
+ verify(transaction, times(4)).create(any(AAIResourceUri.class), any(org.onap.aai.domain.yang.Flavor.class));
+ }
+
+ @Ignore
+ @Test
+ public void testUpdateVserverLInterfacesToAai() throws HeatBridgeException {
+ // Arrange
+ List<Resource> stackResources = (List<Resource>) extractTestStackResources();
+ Port port = mock(Port.class);
+ when(port.getId()).thenReturn("test-port-id");
+ when(port.getName()).thenReturn("test-port-name");
+ when(port.getvNicType()).thenReturn(HeatBridgeConstants.OS_SRIOV_PORT_TYPE);
+ when(port.getMacAddress()).thenReturn("78:4f:43:68:e2:78");
+ when(port.getNetworkId()).thenReturn("890a203a-23gg-56jh-df67-731656a8f13a");
+ when(port.getDeviceId()).thenReturn("test-device-id");
+ when(port.getVifDetails())
+ .thenReturn(ImmutableMap.of(HeatBridgeConstants.OS_VLAN_NETWORK_KEY, "2345"));
+ String pfPciId = "0000:08:00.0";
+ when(port.getProfile()).thenReturn(ImmutableMap.of(HeatBridgeConstants.OS_PCI_SLOT_KEY, pfPciId,
+ HeatBridgeConstants.OS_PHYSICAL_NETWORK_KEY, "physical_network_id"));
+
+ Network network = mock(Network.class);
+ when(network.getId()).thenReturn("test-network-id");
+ when(network.getNetworkType()).thenReturn(NetworkType.VLAN);
+ when(network.getProviderSegID()).thenReturn("2345");
+
+ when(osClient.getPortById("212a203a-9764-4f42-84ea-731536a8f13a")).thenReturn(port);
+ when(osClient.getPortById("387e3904-8948-43d1-8635-b6c2042b54da")).thenReturn(port);
+ when(osClient.getPortById("70a09dfd-f1c5-4bc8-bd8f-dc539b8d662a")).thenReturn(port);
+ when(osClient.getPortById("12f88b4d-c8a4-4fbd-bcb4-7e36af02430b")).thenReturn(port);
+ when(osClient.getPortById("c54b9f45-b413-4937-bbe4-3c8a5689cfc9")).thenReturn(port);
+ when(osClient.getNetworkById(anyString())).thenReturn(network);
+
+ SriovPf sriovPf = new SriovPf();
+ sriovPf.setPfPciId(pfPciId);
+ PInterface pIf = mock(PInterface.class);
+ when(pIf.getInterfaceName()).thenReturn("test-port-id");
+ when(resourcesClient.get(eq(PInterface.class), any(AAIResourceUri.class))).thenReturn(Optional.of(pIf));
+
+ // Act
+ heatbridge.buildAddVserverLInterfacesToAaiAction(stackResources, Arrays.asList("1", "2"));
+
+ // Assert
+ verify(transaction, times(5)).create(any(AAIResourceUri.class), any(LInterface.class));
+ verify(osClient, times(5)).getPortById(anyString());
+ verify(osClient, times(5)).getNetworkById(anyString());
+ }
+
+ private List<? extends Resource> extractTestStackResources() {
+ List<HeatResource> stackResources = null;
+ try {
+ stackResources = MAPPER.readValue(readTestResourceFile("stack-resources.json"), Resources.class)
+ .getList();
+ assertNotNull(stackResources);
+ assertFalse(stackResources.isEmpty());
+ } catch (IOException e) {
+ Assert.fail("Failed to extract test stack resources.");
+ }
+ return stackResources;
+ }
+
+ private String readTestResourceFile(String filePath) {
+ String content = null;
+ String pathname = Objects.requireNonNull(getClass().getClassLoader().getResource(filePath)).getFile();
+ File file = new File(pathname);
+ try {
+ content = Objects.requireNonNull(FileUtils.readFileToString(file, Charset.defaultCharset()));
+ } catch (IOException e) {
+ Assert.fail(String.format("Failed to read test resource file (%s)", filePath));
+ }
+ return content;
+ }
+}
diff --git a/adapters/mso-openstack-adapters/src/test/resources/stack-resources.json b/adapters/mso-openstack-adapters/src/test/resources/stack-resources.json
new file mode 100644
index 0000000000..6b63895a33
--- /dev/null
+++ b/adapters/mso-openstack-adapters/src/test/resources/stack-resources.json
@@ -0,0 +1,441 @@
+{
+ "resources": [
+ {
+ "resource_name": "ge_000",
+ "links": [
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule/d1431cdc-9b29-44fc-98d0-9b3dc1ac246d/resources/ge_000",
+ "rel": "self"
+ },
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule/d1431cdc-9b29-44fc-98d0-9b3dc1ac246d",
+ "rel": "stack"
+ },
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-ge_000-t66dxpwq6nb5/deee54a3-08ac-477b-9c09-c798edb40be1",
+ "rel": "nested"
+ }
+ ],
+ "logical_resource_id": "ge_000",
+ "resource_status_reason": "state changed",
+ "updated_time": "2018-04-09T21:09:52Z",
+ "required_by": [
+ "vfw_instance"
+ ],
+ "resource_status": "CREATE_COMPLETE",
+ "physical_resource_id": "deee54a3-08ac-477b-9c09-c798edb40be1",
+ "resource_type": "port.yaml"
+ },
+ {
+ "resource_name": "vfw_instance",
+ "links": [
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule/d1431cdc-9b29-44fc-98d0-9b3dc1ac246d/resources/vfw_instance",
+ "rel": "self"
+ },
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule/d1431cdc-9b29-44fc-98d0-9b3dc1ac246d",
+ "rel": "stack"
+ },
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam/54f93b9e-5138-4f3f-bfe0-ee06e1f0877b",
+ "rel": "nested"
+ }
+ ],
+ "logical_resource_id": "vfw_instance",
+ "resource_status_reason": "state changed",
+ "updated_time": "2018-04-09T21:09:52Z",
+ "required_by": [],
+ "resource_status": "CREATE_COMPLETE",
+ "physical_resource_id": "54f93b9e-5138-4f3f-bfe0-ee06e1f0877b",
+ "resource_type": "vfw.yaml"
+ },
+ {
+ "resource_name": "port",
+ "links": [
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-ge_000-t66dxpwq6nb5/deee54a3-08ac-477b-9c09-c798edb40be1/resources/port",
+ "rel": "self"
+ },
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-ge_000-t66dxpwq6nb5/deee54a3-08ac-477b-9c09-c798edb40be1",
+ "rel": "stack"
+ }
+ ],
+ "logical_resource_id": "port",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2018-04-09T21:09:52Z",
+ "required_by": [],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "212a203a-9764-4f42-84ea-731536a8f13a",
+ "resource_type": "OS::Neutron::Port"
+ },
+ {
+ "resource_name": "pfe0",
+ "links": [
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam/54f93b9e-5138-4f3f-bfe0-ee06e1f0877b/resources/pfe0",
+ "rel": "self"
+ },
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam/54f93b9e-5138-4f3f-bfe0-ee06e1f0877b",
+ "rel": "stack"
+ },
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam-pfe0-kvqmgn7jmiti/1325e04b-e836-4a13-bb2e-f34923d97ad7",
+ "rel": "nested"
+ }
+ ],
+ "logical_resource_id": "pfe0",
+ "resource_status_reason": "state changed",
+ "updated_time": "2018-04-09T21:09:54Z",
+ "required_by": [
+ "re0"
+ ],
+ "resource_status": "CREATE_COMPLETE",
+ "physical_resource_id": "1325e04b-e836-4a13-bb2e-f34923d97ad7",
+ "resource_type": "fpc.yaml"
+ },
+ {
+ "resource_name": "fpc_internal_port",
+ "links": [
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam/54f93b9e-5138-4f3f-bfe0-ee06e1f0877b/resources/fpc_internal_port",
+ "rel": "self"
+ },
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam/54f93b9e-5138-4f3f-bfe0-ee06e1f0877b",
+ "rel": "stack"
+ },
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam-fpc_internal_port-gbnyc4w7mb5b/4e920f39-9784-417e-9331-d75e2e37cc51",
+ "rel": "nested"
+ }
+ ],
+ "logical_resource_id": "fpc_internal_port",
+ "resource_status_reason": "state changed",
+ "updated_time": "2018-04-09T21:09:54Z",
+ "required_by": [
+ "pfe0"
+ ],
+ "resource_status": "CREATE_COMPLETE",
+ "physical_resource_id": "4e920f39-9784-417e-9331-d75e2e37cc51",
+ "resource_type": "re_pfe_port.yaml"
+ },
+ {
+ "resource_name": "re-fpc-affinity-grp",
+ "links": [
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam/54f93b9e-5138-4f3f-bfe0-ee06e1f0877b/resources/re-fpc-affinity-grp",
+ "rel": "self"
+ },
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam/54f93b9e-5138-4f3f-bfe0-ee06e1f0877b",
+ "rel": "stack"
+ }
+ ],
+ "logical_resource_id": "re-fpc-affinity-grp",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2018-04-09T21:09:54Z",
+ "required_by": [
+ "pfe0",
+ "re0"
+ ],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "3aa37238-f8ff-4c96-b56a-8903bae28a60",
+ "resource_type": "OS::Nova::ServerGroup"
+ },
+ {
+ "resource_name": "re0",
+ "links": [
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam/54f93b9e-5138-4f3f-bfe0-ee06e1f0877b/resources/re0",
+ "rel": "self"
+ },
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam/54f93b9e-5138-4f3f-bfe0-ee06e1f0877b",
+ "rel": "stack"
+ },
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam-re0-73oifso3xntc/0915e27e-428d-4d2c-a67b-abbce18081b2",
+ "rel": "nested"
+ }
+ ],
+ "logical_resource_id": "re0",
+ "resource_status_reason": "state changed",
+ "updated_time": "2018-04-09T21:09:54Z",
+ "required_by": [],
+ "resource_status": "CREATE_COMPLETE",
+ "physical_resource_id": "0915e27e-428d-4d2c-a67b-abbce18081b2",
+ "resource_type": "re.yaml"
+ },
+ {
+ "resource_name": "re_external_port",
+ "links": [
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam/54f93b9e-5138-4f3f-bfe0-ee06e1f0877b/resources/re_external_port",
+ "rel": "self"
+ },
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam/54f93b9e-5138-4f3f-bfe0-ee06e1f0877b",
+ "rel": "stack"
+ },
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam-re_external_port-3okiee3zocr7/f58c65e3-a72e-4b2d-a295-cb40324d6b4c",
+ "rel": "nested"
+ }
+ ],
+ "logical_resource_id": "re_external_port",
+ "resource_status_reason": "state changed",
+ "updated_time": "2018-04-09T21:09:54Z",
+ "required_by": [
+ "re0"
+ ],
+ "resource_status": "CREATE_COMPLETE",
+ "physical_resource_id": "f58c65e3-a72e-4b2d-a295-cb40324d6b4c",
+ "resource_type": "port.yaml"
+ },
+ {
+ "resource_name": "fpc_external_port",
+ "links": [
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam/54f93b9e-5138-4f3f-bfe0-ee06e1f0877b/resources/fpc_external_port",
+ "rel": "self"
+ },
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam/54f93b9e-5138-4f3f-bfe0-ee06e1f0877b",
+ "rel": "stack"
+ },
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam-fpc_external_port-5vumcqp7hkbn/979e47c9-c15a-428e-ad73-af922029ee37",
+ "rel": "nested"
+ }
+ ],
+ "logical_resource_id": "fpc_external_port",
+ "resource_status_reason": "state changed",
+ "updated_time": "2018-04-09T21:09:54Z",
+ "required_by": [
+ "pfe0",
+ "re0"
+ ],
+ "resource_status": "CREATE_COMPLETE",
+ "physical_resource_id": "979e47c9-c15a-428e-ad73-af922029ee37",
+ "resource_type": "port.yaml"
+ },
+ {
+ "resource_name": "re_internal_port",
+ "links": [
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam/54f93b9e-5138-4f3f-bfe0-ee06e1f0877b/resources/re_internal_port",
+ "rel": "self"
+ },
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam/54f93b9e-5138-4f3f-bfe0-ee06e1f0877b",
+ "rel": "stack"
+ },
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam-re_internal_port-u4txbvemndci/0aebfd9d-ad97-43b1-a67b-b2b5340738d2",
+ "rel": "nested"
+ }
+ ],
+ "logical_resource_id": "re_internal_port",
+ "resource_status_reason": "state changed",
+ "updated_time": "2018-04-09T21:09:54Z",
+ "required_by": [
+ "re0"
+ ],
+ "resource_status": "CREATE_COMPLETE",
+ "physical_resource_id": "0aebfd9d-ad97-43b1-a67b-b2b5340738d2",
+ "resource_type": "re_pfe_port.yaml"
+ },
+ {
+ "resource_name": "re_pfe_network",
+ "links": [
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam/54f93b9e-5138-4f3f-bfe0-ee06e1f0877b/resources/re_pfe_network",
+ "rel": "self"
+ },
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam/54f93b9e-5138-4f3f-bfe0-ee06e1f0877b",
+ "rel": "stack"
+ },
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam-re_pfe_network-2wmjvgzrhtvs/290fc2fd-cd1d-47d0-90eb-2ece7c009b29",
+ "rel": "nested"
+ }
+ ],
+ "logical_resource_id": "re_pfe_network",
+ "resource_status_reason": "state changed",
+ "updated_time": "2018-04-09T21:09:54Z",
+ "required_by": [
+ "fpc_internal_port",
+ "re_internal_port"
+ ],
+ "resource_status": "CREATE_COMPLETE",
+ "physical_resource_id": "290fc2fd-cd1d-47d0-90eb-2ece7c009b29",
+ "resource_type": "bridge_int.yaml"
+ },
+ {
+ "resource_name": "fpc",
+ "links": [
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam-pfe0-kvqmgn7jmiti/1325e04b-e836-4a13-bb2e-f34923d97ad7/resources/fpc",
+ "rel": "self"
+ },
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam-pfe0-kvqmgn7jmiti/1325e04b-e836-4a13-bb2e-f34923d97ad7",
+ "rel": "stack"
+ }
+ ],
+ "logical_resource_id": "fpc",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2018-04-09T21:09:58Z",
+ "required_by": [],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "43c2159b-2c04-46ac-bda5-594110cae2d3",
+ "resource_type": "OS::Nova::Server"
+ },
+ {
+ "resource_name": "port",
+ "links": [
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam-fpc_internal_port-gbnyc4w7mb5b/4e920f39-9784-417e-9331-d75e2e37cc51/resources/port",
+ "rel": "self"
+ },
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam-fpc_internal_port-gbnyc4w7mb5b/4e920f39-9784-417e-9331-d75e2e37cc51",
+ "rel": "stack"
+ }
+ ],
+ "logical_resource_id": "port",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2018-04-09T21:09:56Z",
+ "required_by": [],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "387e3904-8948-43d1-8635-b6c2042b54da",
+ "resource_type": "OS::Neutron::Port"
+ },
+ {
+ "resource_name": "re",
+ "links": [
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam-re0-73oifso3xntc/0915e27e-428d-4d2c-a67b-abbce18081b2/resources/re",
+ "rel": "self"
+ },
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam-re0-73oifso3xntc/0915e27e-428d-4d2c-a67b-abbce18081b2",
+ "rel": "stack"
+ }
+ ],
+ "logical_resource_id": "re",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2018-04-09T21:10:36Z",
+ "required_by": [],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "7cff109a-b2b7-4933-97b4-ec44a8365568",
+ "resource_type": "OS::Nova::Server"
+ },
+ {
+ "resource_name": "port",
+ "links": [
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam-re_external_port-3okiee3zocr7/f58c65e3-a72e-4b2d-a295-cb40324d6b4c/resources/port",
+ "rel": "self"
+ },
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam-re_external_port-3okiee3zocr7/f58c65e3-a72e-4b2d-a295-cb40324d6b4c",
+ "rel": "stack"
+ }
+ ],
+ "logical_resource_id": "port",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2018-04-09T21:09:55Z",
+ "required_by": [],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "70a09dfd-f1c5-4bc8-bd8f-dc539b8d662a",
+ "resource_type": "OS::Neutron::Port"
+ },
+ {
+ "resource_name": "port",
+ "links": [
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam-fpc_external_port-5vumcqp7hkbn/979e47c9-c15a-428e-ad73-af922029ee37/resources/port",
+ "rel": "self"
+ },
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam-fpc_external_port-5vumcqp7hkbn/979e47c9-c15a-428e-ad73-af922029ee37",
+ "rel": "stack"
+ }
+ ],
+ "logical_resource_id": "port",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2018-04-09T21:09:55Z",
+ "required_by": [],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "12f88b4d-c8a4-4fbd-bcb4-7e36af02430b",
+ "resource_type": "OS::Neutron::Port"
+ },
+ {
+ "resource_name": "port",
+ "links": [
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam-re_internal_port-u4txbvemndci/0aebfd9d-ad97-43b1-a67b-b2b5340738d2/resources/port",
+ "rel": "self"
+ },
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam-re_internal_port-u4txbvemndci/0aebfd9d-ad97-43b1-a67b-b2b5340738d2",
+ "rel": "stack"
+ }
+ ],
+ "logical_resource_id": "port",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2018-04-09T21:09:56Z",
+ "required_by": [],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "c54b9f45-b413-4937-bbe4-3c8a5689cfc9",
+ "resource_type": "OS::Neutron::Port"
+ },
+ {
+ "resource_name": "bridge_network_subnet",
+ "links": [
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam-re_pfe_network-2wmjvgzrhtvs/290fc2fd-cd1d-47d0-90eb-2ece7c009b29/resources/bridge_network_subnet",
+ "rel": "self"
+ },
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam-re_pfe_network-2wmjvgzrhtvs/290fc2fd-cd1d-47d0-90eb-2ece7c009b29",
+ "rel": "stack"
+ }
+ ],
+ "logical_resource_id": "bridge_network_subnet",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2018-04-09T21:09:55Z",
+ "required_by": [],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "5ffd8c02-6913-4b67-adba-74e78c2bbe40",
+ "resource_type": "OS::Neutron::Subnet"
+ },
+ {
+ "resource_name": "bridge_network",
+ "links": [
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam-re_pfe_network-2wmjvgzrhtvs/290fc2fd-cd1d-47d0-90eb-2ece7c009b29/resources/bridge_network",
+ "rel": "self"
+ },
+ {
+ "href": "http://10.10.10.10:8004/v1/7320ec4a5b9d4589ba7c4412ccfd290f/stacks/ClosedLoop_vFW_VfModule-vfw_instance-tw3i5ile2nam-re_pfe_network-2wmjvgzrhtvs/290fc2fd-cd1d-47d0-90eb-2ece7c009b29",
+ "rel": "stack"
+ }
+ ],
+ "logical_resource_id": "bridge_network",
+ "resource_status": "CREATE_COMPLETE",
+ "updated_time": "2018-04-09T21:09:55Z",
+ "required_by": [
+ "bridge_network_subnet"
+ ],
+ "resource_status_reason": "state changed",
+ "physical_resource_id": "5ad95036-8daf-4379-a59c-865f35976cd4",
+ "resource_type": "OS::Neutron::Net"
+ }
+ ]
+}
diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/VnfmAdapterController.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/VnfmAdapterController.java
index 77a3f21dca..b14ead0c4f 100644
--- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/VnfmAdapterController.java
+++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/VnfmAdapterController.java
@@ -27,12 +27,14 @@ import javax.ws.rs.core.MediaType;
import org.onap.logging.ref.slf4j.ONAPLogConstants;
import org.onap.vnfmadapter.v1.model.CreateVnfRequest;
import org.onap.vnfmadapter.v1.model.CreateVnfResponse;
+import org.onap.vnfmadapter.v1.model.DeleteVnfResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
@@ -58,15 +60,15 @@ public class VnfmAdapterController {
required = true) @Valid @RequestBody final CreateVnfRequest createVnfRequest,
@ApiParam(
value = "Used to track REST requests for logging purposes. Identifies a single top level invocation of ONAP",
- required = true) @RequestHeader(value = ONAPLogConstants.Headers.REQUEST_ID,
+ required = false) @RequestHeader(value = ONAPLogConstants.Headers.REQUEST_ID,
required = false) final String requestId,
@ApiParam(
value = "Used to track REST requests for logging purposes. Identifies the client application user agent or user invoking the API",
- required = true) @RequestHeader(value = ONAPLogConstants.Headers.PARTNER_NAME,
+ required = false) @RequestHeader(value = ONAPLogConstants.Headers.PARTNER_NAME,
required = false) final String partnerName,
@ApiParam(
value = "Used to track REST requests for logging purposes. Identifies a single invocation of a single component",
- required = true) @RequestHeader(value = ONAPLogConstants.Headers.INVOCATION_ID,
+ required = false) @RequestHeader(value = ONAPLogConstants.Headers.INVOCATION_ID,
required = false) final String invocationId) {
setLoggingMDCs(requestId, partnerName, invocationId);
@@ -79,6 +81,33 @@ public class VnfmAdapterController {
return new ResponseEntity<>(response, HttpStatus.ACCEPTED);
}
+ @DeleteMapping(value = "/vnfs/{vnfId}")
+ public ResponseEntity<DeleteVnfResponse> vnfDelete(
+ @ApiParam(value = "The identifier of the VNF. This must be the vnf-id of an existing generic-vnf in AAI.",
+ required = true) @PathVariable("vnfId") final String vnfId,
+ @ApiParam(
+ value = "Used to track REST requests for logging purposes. Identifies a single top level invocation of ONAP",
+ required = false) @RequestHeader(value = ONAPLogConstants.Headers.REQUEST_ID,
+ required = false) final String requestId,
+ @ApiParam(
+ value = "Used to track REST requests for logging purposes. Identifies the client application user agent or user invoking the API",
+ required = false) @RequestHeader(value = ONAPLogConstants.Headers.PARTNER_NAME,
+ required = false) final String partnerName,
+ @ApiParam(
+ value = "Used to track REST requests for logging purposes. Identifies a single invocation of a single component",
+ required = false) @RequestHeader(value = ONAPLogConstants.Headers.INVOCATION_ID,
+ required = false) final String invocationId) {
+
+ setLoggingMDCs(requestId, partnerName, invocationId);
+
+ logger.info("REST request vnfDelete for VNF: {}", vnfId);
+
+ final DeleteVnfResponse response = new DeleteVnfResponse();
+ response.setJobId(UUID.randomUUID().toString());
+ clearLoggingMDCs();
+ return new ResponseEntity<>(response, HttpStatus.ACCEPTED);
+ }
+
private void setLoggingMDCs(final String requestId, final String partnerName, final String invocationId) {
MDC.put(ONAPLogConstants.MDCs.REQUEST_ID, requestId);
MDC.put(ONAPLogConstants.MDCs.PARTNER_NAME, partnerName);
diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/VnfmAdapterControllerTest.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/VnfmAdapterControllerTest.java
index 842b3b56be..071a330e8b 100644
--- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/VnfmAdapterControllerTest.java
+++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/VnfmAdapterControllerTest.java
@@ -28,6 +28,7 @@ import org.junit.runner.RunWith;
import org.onap.so.adapters.vnfmadapter.VnfmAdapterApplication;
import org.onap.vnfmadapter.v1.model.CreateVnfRequest;
import org.onap.vnfmadapter.v1.model.CreateVnfResponse;
+import org.onap.vnfmadapter.v1.model.DeleteVnfResponse;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
@@ -75,4 +76,15 @@ public class VnfmAdapterControllerTest {
assertEquals(401, response.getStatusCode().value());
}
+ @Test
+ public void deleteVnf_ValidRequest_Returns202AndJobId() throws Exception {
+ final RequestEntity<Void> request = RequestEntity
+ .delete(new URI("http://localhost:" + port + "/so/vnfm-adapter/v1/vnfs/myVnfId"))
+ .accept(MediaType.APPLICATION_JSON).header("X-ONAP-RequestId", "myRequestId")
+ .header("X-ONAP-InvocationID", "myInvocationId").header("Content-Type", "application/json").build();
+ final ResponseEntity<DeleteVnfResponse> response = restTemplate.exchange(request, DeleteVnfResponse.class);
+ assertEquals(202, response.getStatusCode().value());
+ assertNotNull(response.getBody().getJobId());
+ }
+
}
diff --git a/bpmn/MSOCommonBPMN/src/test/java/org/onap/so/bpmn/servicedecomposition/tasks/BBInputSetupTest.java b/bpmn/MSOCommonBPMN/src/test/java/org/onap/so/bpmn/servicedecomposition/tasks/BBInputSetupTest.java
index df9f2259a1..eb26bf34ee 100644
--- a/bpmn/MSOCommonBPMN/src/test/java/org/onap/so/bpmn/servicedecomposition/tasks/BBInputSetupTest.java
+++ b/bpmn/MSOCommonBPMN/src/test/java/org/onap/so/bpmn/servicedecomposition/tasks/BBInputSetupTest.java
@@ -4,6 +4,8 @@
* ================================================================================
* Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
* ================================================================================
+ * Modifications Copyright (c) 2019 Samsung
+ * ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
@@ -43,6 +45,7 @@ import java.util.Map;
import java.util.Optional;
import org.camunda.bpm.engine.delegate.DelegateExecution;
+import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -2712,5 +2715,24 @@ public class BBInputSetupTest {
assertEquals("Lookup Key Map populated with VfModule Id", vfModuleId, lookupKeyMap.get(ResourceKey.VF_MODULE_ID));
assertEquals("Lookup Key Map populated with VolumeGroup Id", volumeGroupId, lookupKeyMap.get(ResourceKey.VOLUME_GROUP_ID));
}
+
+ @Test
+ public void testGettingVnfcToConfiguration() throws Exception {
+
+ String vnfcName = "vnfcName";
+ org.onap.aai.domain.yang.Configuration expectedAAI = new org.onap.aai.domain.yang.Configuration();
+ AAIResourceUri aaiResourceUri = AAIUriFactory.createResourceUri(AAIObjectType.VNFC, vnfcName);
+ AAIResultWrapper configurationWrapper =
+ new AAIResultWrapper(new AAICommonObjectMapperProvider().getMapper().writeValueAsString(expectedAAI));
+
+ doReturn(new AAIResultWrapper(null)).when(SPY_bbInputSetupUtils).getAAIResourceDepthOne(aaiResourceUri);
+ Vnfc vnfc = SPY_bbInputSetup.getVnfcToConfiguration(vnfcName);
+ Assert.assertNull(vnfc);
+
+ doReturn(configurationWrapper).when(SPY_bbInputSetupUtils).getAAIResourceDepthOne(aaiResourceUri);
+ vnfc = SPY_bbInputSetup.getVnfcToConfiguration(vnfcName);
+ Assert.assertNotNull(vnfc);
+ }
+
}
diff --git a/bpmn/so-bpmn-building-blocks/src/main/resources/subprocess/BuildingBlock/EtsiVnfInstantiateBB.bpmn b/bpmn/so-bpmn-building-blocks/src/main/resources/subprocess/BuildingBlock/EtsiVnfInstantiateBB.bpmn
index 9b98620f78..9437d02b69 100644
--- a/bpmn/so-bpmn-building-blocks/src/main/resources/subprocess/BuildingBlock/EtsiVnfInstantiateBB.bpmn
+++ b/bpmn/so-bpmn-building-blocks/src/main/resources/subprocess/BuildingBlock/EtsiVnfInstantiateBB.bpmn
@@ -2,48 +2,60 @@
<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" id="Definitions_0x13ohc" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="2.0.3">
<bpmn:process id="EtsiVnfInstantiateBB" name="&#10;EtsiVnfInstantiateBB" isExecutable="true">
<bpmn:serviceTask id="ServiceTask_02e82t2" name="Create &#10;CreateVnfRequest&#10;" camunda:expression="${VnfmAdapterCreateVnfTask.buildCreateVnfRequest(InjectExecution.execute(execution, execution.getVariable(&#34;gBuildingBlockExecution&#34;)))}">
- <bpmn:incoming>SequenceFlow_016sgof</bpmn:incoming>
+ <bpmn:incoming>SequenceFlow_18fsqzd</bpmn:incoming>
<bpmn:outgoing>SequenceFlow_0f0vsnv</bpmn:outgoing>
</bpmn:serviceTask>
<bpmn:startEvent id="StartEvent_0ru3x55">
<bpmn:outgoing>SequenceFlow_016sgof</bpmn:outgoing>
</bpmn:startEvent>
- <bpmn:sequenceFlow id="SequenceFlow_016sgof" sourceRef="StartEvent_0ru3x55" targetRef="ServiceTask_02e82t2" />
+ <bpmn:sequenceFlow id="SequenceFlow_016sgof" sourceRef="StartEvent_0ru3x55" targetRef="ServiceTask_1jf7hlc" />
<bpmn:endEvent id="EndEvent_001k15i">
- <bpmn:incoming>SequenceFlow_0cik89t</bpmn:incoming>
+ <bpmn:incoming>SequenceFlow_0hp0ka1</bpmn:incoming>
</bpmn:endEvent>
<bpmn:sequenceFlow id="SequenceFlow_0f0vsnv" sourceRef="ServiceTask_02e82t2" targetRef="ServiceTask_06ao4xu" />
<bpmn:serviceTask id="ServiceTask_06ao4xu" name="&#10;Invoke VNFM Adaptor&#10;" camunda:asyncAfter="true" camunda:expression="${VnfmAdapterCreateVnfTask.invokeVnfmAdapter(InjectExecution.execute(execution, execution.getVariable(&#34;gBuildingBlockExecution&#34;)))}">
<bpmn:incoming>SequenceFlow_0f0vsnv</bpmn:incoming>
- <bpmn:outgoing>SequenceFlow_0cik89t</bpmn:outgoing>
+ <bpmn:outgoing>SequenceFlow_0hp0ka1</bpmn:outgoing>
+ </bpmn:serviceTask>
+ <bpmn:serviceTask id="ServiceTask_1jf7hlc" name="&#10;Retrieve Input Parameters&#10;" camunda:asyncAfter="true" camunda:expression="${InputParameterRetrieverTask.getInputParameters(InjectExecution.execute(execution, execution.getVariable(&#34;gBuildingBlockExecution&#34;)))}">
+ <bpmn:incoming>SequenceFlow_016sgof</bpmn:incoming>
+ <bpmn:outgoing>SequenceFlow_18fsqzd</bpmn:outgoing>
</bpmn:serviceTask>
- <bpmn:sequenceFlow id="SequenceFlow_0cik89t" sourceRef="ServiceTask_06ao4xu" targetRef="EndEvent_001k15i" />
+ <bpmn:sequenceFlow id="SequenceFlow_18fsqzd" sourceRef="ServiceTask_1jf7hlc" targetRef="ServiceTask_02e82t2" />
+ <bpmn:sequenceFlow id="SequenceFlow_0hp0ka1" sourceRef="ServiceTask_06ao4xu" targetRef="EndEvent_001k15i" />
</bpmn:process>
<bpmndi:BPMNDiagram id="BPMNDiagram_1">
<bpmndi:BPMNPlane id="BPMNPlane_1" bpmnElement="EtsiVnfInstantiateBB">
<bpmndi:BPMNShape id="ServiceTask_02e82t1_di" bpmnElement="ServiceTask_02e82t2">
- <dc:Bounds x="353" y="227" width="100" height="80" />
+ <dc:Bounds x="480" y="227" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="StartEvent_0ru3x55_di" bpmnElement="StartEvent_0ru3x55">
<dc:Bounds x="232" y="249" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="SequenceFlow_016sgof_di" bpmnElement="SequenceFlow_016sgof">
<di:waypoint x="268" y="267" />
- <di:waypoint x="353" y="267" />
+ <di:waypoint x="332" y="267" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="EndEvent_001k15i_di" bpmnElement="EndEvent_001k15i">
- <dc:Bounds x="703" y="249" width="36" height="36" />
+ <dc:Bounds x="783" y="249" width="36" height="36" />
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge id="SequenceFlow_0f0vsnv_di" bpmnElement="SequenceFlow_0f0vsnv">
- <di:waypoint x="453" y="267" />
- <di:waypoint x="522" y="267" />
+ <di:waypoint x="580" y="267" />
+ <di:waypoint x="629" y="267" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="ServiceTask_06ao4xu_di" bpmnElement="ServiceTask_06ao4xu">
- <dc:Bounds x="522" y="227" width="100" height="80" />
+ <dc:Bounds x="629" y="227" width="100" height="80" />
</bpmndi:BPMNShape>
- <bpmndi:BPMNEdge id="SequenceFlow_0cik89t_di" bpmnElement="SequenceFlow_0cik89t">
- <di:waypoint x="622" y="267" />
- <di:waypoint x="703" y="267" />
+ <bpmndi:BPMNShape id="ServiceTask_1jf7hlc_di" bpmnElement="ServiceTask_1jf7hlc">
+ <dc:Bounds x="332" y="227" width="100" height="80" />
+ </bpmndi:BPMNShape>
+ <bpmndi:BPMNEdge id="SequenceFlow_18fsqzd_di" bpmnElement="SequenceFlow_18fsqzd">
+ <di:waypoint x="432" y="267" />
+ <di:waypoint x="480" y="267" />
+ </bpmndi:BPMNEdge>
+ <bpmndi:BPMNEdge id="SequenceFlow_0hp0ka1_di" bpmnElement="SequenceFlow_0hp0ka1">
+ <di:waypoint x="729" y="267" />
+ <di:waypoint x="783" y="267" />
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
diff --git a/bpmn/so-bpmn-building-blocks/src/main/resources/subprocess/BuildingBlock/ExecuteBuildingBlock.bpmn b/bpmn/so-bpmn-building-blocks/src/main/resources/subprocess/BuildingBlock/ExecuteBuildingBlock.bpmn
index 5189f8b48a..83363d48ba 100644
--- a/bpmn/so-bpmn-building-blocks/src/main/resources/subprocess/BuildingBlock/ExecuteBuildingBlock.bpmn
+++ b/bpmn/so-bpmn-building-blocks/src/main/resources/subprocess/BuildingBlock/ExecuteBuildingBlock.bpmn
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8"?>
-<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="1.8.2">
+<bpmn:definitions xmlns:bpmn="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:camunda="http://camunda.org/schema/1.0/bpmn" id="Definitions_1" targetNamespace="http://bpmn.io/schema/bpmn" exporter="Camunda Modeler" exporterVersion="1.7.2">
<bpmn:process id="ExecuteBuildingBlock" name="ExecuteBuildingBlock" isExecutable="true">
<bpmn:startEvent id="Start_ExecuteBuildingBlock" name="start">
<bpmn:outgoing>SequenceFlow_0rq4c5r</bpmn:outgoing>
@@ -9,6 +9,7 @@
<camunda:in source="gBuildingBlockExecution" target="gBuildingBlockExecution" />
<camunda:out source="WorkflowException" target="WorkflowException" />
<camunda:in source="mso-request-id" target="mso-request-id" />
+ <camunda:out source="WorkflowExceptionErrorMessage" target="WorkflowExceptionErrorMessage" />
</bpmn:extensionElements>
<bpmn:incoming>SequenceFlow_19wuics</bpmn:incoming>
<bpmn:outgoing>SequenceFlow_01h9qmz</bpmn:outgoing>
diff --git a/bpmn/so-bpmn-tasks/pom.xml b/bpmn/so-bpmn-tasks/pom.xml
index ce1cdd5068..8adffb29b5 100644
--- a/bpmn/so-bpmn-tasks/pom.xml
+++ b/bpmn/so-bpmn-tasks/pom.xml
@@ -156,5 +156,11 @@
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
+ <dependency>
+ <groupId>nl.jqno.equalsverifier</groupId>
+ <artifactId>equalsverifier</artifactId>
+ <version>2.5.1</version>
+ <scope>test</scope>
+ </dependency>
</dependencies>
</project>
diff --git a/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/Constants.java b/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/Constants.java
index d03173d0ac..667ac133af 100644
--- a/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/Constants.java
+++ b/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/Constants.java
@@ -27,6 +27,8 @@ public class Constants {
public static final String CREATE_VNF_REQUEST_PARAM_NAME = "createVnfRequest";
public static final String CREATE_VNF_RESPONSE_PARAM_NAME = "createVnfResponse";
+
+ public static final String INPUT_PARAMETER = "inputParameter";
public static final String DOT = ".";
public static final String UNDERSCORE = "_";
@@ -34,6 +36,9 @@ public class Constants {
public static final String VNFM_ADAPTER_DEFAULT_URL = "http://so-vnfm-adapter.onap:9092/so/vnfm-adapter/v1/";
public static final String VNFM_ADAPTER_DEFAULT_AUTH = "Basic dm5mbTpwYXNzd29yZDEk";
+
+ public static final String FORWARD_SLASH = "/";
+ public static final String PRELOAD_VNFS_URL = "/restconf/config/VNF-API:preload-vnfs/vnf-preload-list/";
private Constants() {}
diff --git a/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/InputParameterRetrieverTask.java b/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/InputParameterRetrieverTask.java
new file mode 100644
index 0000000000..ebb9d521c3
--- /dev/null
+++ b/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/InputParameterRetrieverTask.java
@@ -0,0 +1,74 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Ericsson. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks;
+
+import static org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.Constants.INPUT_PARAMETER;
+import static org.onap.so.bpmn.servicedecomposition.entities.ResourceKey.GENERIC_VNF_ID;
+
+import org.onap.so.bpmn.common.BuildingBlockExecution;
+import org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.utils.InputParameter;
+import org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.utils.InputParametersProvider;
+import org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.utils.NullInputParameter;
+import org.onap.so.bpmn.servicedecomposition.bbobjects.GenericVnf;
+import org.onap.so.bpmn.servicedecomposition.tasks.ExtractPojosForBB;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * This class retrieve input parameters
+ *
+ * @author waqas.ikram@est.tech
+ */
+@Component
+public class InputParameterRetrieverTask {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(InputParameterRetrieverTask.class);
+
+ private final InputParametersProvider inputParametersProvider;
+
+ private final ExtractPojosForBB extractPojosForBB;
+
+ @Autowired
+ public InputParameterRetrieverTask(final InputParametersProvider inputParametersProvider,
+ final ExtractPojosForBB extractPojosForBB) {
+ this.inputParametersProvider = inputParametersProvider;
+ this.extractPojosForBB = extractPojosForBB;
+ }
+
+ public void getInputParameters(final BuildingBlockExecution execution) {
+ try {
+ LOGGER.debug("Executing getInputParameters ...");
+
+ final GenericVnf vnf = extractPojosForBB.extractByKey(execution, GENERIC_VNF_ID);
+ final InputParameter inputParameter = inputParametersProvider.getInputParameter(vnf);
+
+ LOGGER.debug("inputParameter: {}", inputParameter);
+ execution.setVariable(INPUT_PARAMETER, inputParameter);
+
+ LOGGER.debug("Finished executing getInputParameters ...");
+ } catch (final Exception exception) {
+ LOGGER.error("Unable to invoke create and instantiation request", exception);
+ execution.setVariable(INPUT_PARAMETER, NullInputParameter.NULL_INSTANCE);
+ }
+ }
+
+}
diff --git a/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/VnfmAdapterCreateVnfTask.java b/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/VnfmAdapterCreateVnfTask.java
index 23ddb6f3f7..4e15474e46 100644
--- a/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/VnfmAdapterCreateVnfTask.java
+++ b/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/VnfmAdapterCreateVnfTask.java
@@ -23,11 +23,14 @@ package org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks;
import static org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.Constants.CREATE_VNF_REQUEST_PARAM_NAME;
import static org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.Constants.CREATE_VNF_RESPONSE_PARAM_NAME;
import static org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.Constants.DOT;
+import static org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.Constants.INPUT_PARAMETER;
import static org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.Constants.SPACE;
import static org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.Constants.UNDERSCORE;
import static org.onap.so.bpmn.servicedecomposition.entities.ResourceKey.GENERIC_VNF_ID;
import org.onap.so.bpmn.common.BuildingBlockExecution;
+import org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.utils.InputParameter;
+import org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.utils.NullInputParameter;
import org.onap.so.bpmn.servicedecomposition.bbobjects.CloudRegion;
import org.onap.so.bpmn.servicedecomposition.bbobjects.GenericVnf;
import org.onap.so.bpmn.servicedecomposition.entities.GeneralBuildingBlock;
@@ -83,10 +86,14 @@ public class VnfmAdapterCreateVnfTask {
final GenericVnf vnf = extractPojosForBB.extractByKey(execution, GENERIC_VNF_ID);
final ModelInfoGenericVnf modelInfoGenericVnf = vnf.getModelInfoGenericVnf();
+ final InputParameter inputParameter = getInputParameter(execution);
+
final CreateVnfRequest createVnfRequest = new CreateVnfRequest();
createVnfRequest.setName(getName(vnf.getVnfName(), modelInfoGenericVnf.getModelInstanceName()));
createVnfRequest.setTenant(getTenant(cloudRegion));
+ createVnfRequest.setAdditionalParams(inputParameter.getAdditionalParams());
+ createVnfRequest.setExternalVirtualLinks(inputParameter.getExtVirtualLinks());
LOGGER.info("CreateVnfRequest : {}", createVnfRequest);
@@ -99,6 +106,11 @@ public class VnfmAdapterCreateVnfTask {
}
}
+ private InputParameter getInputParameter(final BuildingBlockExecution execution) {
+ final InputParameter inputParameter = execution.getVariable(INPUT_PARAMETER);
+ return inputParameter != null ? inputParameter : NullInputParameter.NULL_INSTANCE;
+ }
+
/**
* Invoke VNFM adapter to create and instantiate VNF
*
diff --git a/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/utils/InputParameter.java b/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/utils/InputParameter.java
new file mode 100644
index 0000000000..5ade3240a0
--- /dev/null
+++ b/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/utils/InputParameter.java
@@ -0,0 +1,81 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Ericsson. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.utils;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.onap.vnfmadapter.v1.model.ExternalVirtualLink;
+
+/**
+ * Wrapper class for instance parameters which are based on SOL003
+ *
+ * @author waqas.ikram@est.tech
+ */
+public class InputParameter implements Serializable {
+
+ private static final long serialVersionUID = 42034634585595304L;
+
+ private Map<String, String> additionalParams = new HashMap<>();
+
+ private List<ExternalVirtualLink> extVirtualLinks = new ArrayList<>();
+
+ public InputParameter(final Map<String, String> additionalParams, final List<ExternalVirtualLink> extVirtualLinks) {
+ this.additionalParams = additionalParams;
+ this.extVirtualLinks = extVirtualLinks;
+ }
+
+ /**
+ * @return the additionalParams
+ */
+ public Map<String, String> getAdditionalParams() {
+ return additionalParams;
+ }
+
+ /**
+ * @return the extVirtualLinks
+ */
+ public List<ExternalVirtualLink> getExtVirtualLinks() {
+ return extVirtualLinks;
+ }
+
+ /**
+ * @param additionalParams the additionalParams to set
+ */
+ public void setAdditionalParams(final Map<String, String> additionalParams) {
+ this.additionalParams = additionalParams;
+ }
+
+ /**
+ * @param extVirtualLinks the extVirtualLinks to set
+ */
+ public void setExtVirtualLinks(final List<ExternalVirtualLink> extVirtualLinks) {
+ this.extVirtualLinks = extVirtualLinks;
+ }
+
+ @Override
+ public String toString() {
+ return "InputParameter [additionalParams=" + additionalParams + ", extVirtualLinks=" + extVirtualLinks + "]";
+ }
+
+}
diff --git a/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/utils/InputParametersProvider.java b/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/utils/InputParametersProvider.java
new file mode 100644
index 0000000000..55203fb7cc
--- /dev/null
+++ b/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/utils/InputParametersProvider.java
@@ -0,0 +1,31 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Ericsson. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.utils;
+
+import org.onap.so.bpmn.servicedecomposition.bbobjects.GenericVnf;
+
+/**
+ * @author waqas.ikram@est.tech
+ */
+public interface InputParametersProvider {
+
+ InputParameter getInputParameter(final GenericVnf genericVnf);
+
+}
diff --git a/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/utils/InputParametersProviderImpl.java b/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/utils/InputParametersProviderImpl.java
new file mode 100644
index 0000000000..6027e78d8b
--- /dev/null
+++ b/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/utils/InputParametersProviderImpl.java
@@ -0,0 +1,161 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Ericsson. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.utils;
+
+import static org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.Constants.FORWARD_SLASH;
+import static org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.Constants.PRELOAD_VNFS_URL;
+
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+import org.onap.so.bpmn.servicedecomposition.bbobjects.GenericVnf;
+import org.onap.so.bpmn.servicedecomposition.modelinfo.ModelInfoGenericVnf;
+import org.onap.so.client.sdnc.SDNCClient;
+import org.onap.vnfmadapter.v1.model.ExternalVirtualLink;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.fasterxml.jackson.core.JsonParseException;
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.jayway.jsonpath.JsonPath;
+
+import net.minidev.json.JSONArray;
+
+/**
+ * This class retrieve pre-load data from SDNC using <br/>
+ * <b>GET</b> /config/VNF-API:preload-vnfs/vnf-preload-list/{vnf-name}/{vnf-type}
+ *
+ * @author waqas.ikram@est.tech
+ */
+@Service
+public class InputParametersProviderImpl implements InputParametersProvider {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(InputParametersProviderImpl.class);
+
+ private static final String EXT_VIRTUAL_LINKS = "extVirtualLinks";
+ private static final String ADDITIONAL_PARAMS = "additionalParams";
+ private static final String VNF_PARAMETERS_PATH = "$..vnf-parameters";
+
+ private final SDNCClient sdncClient;
+
+ @Autowired
+ public InputParametersProviderImpl(final SDNCClient sdncClient) {
+ this.sdncClient = sdncClient;
+ }
+
+ @Override
+ public InputParameter getInputParameter(final GenericVnf genericVnf) {
+ final String vnfName = genericVnf.getVnfName();
+ final String vnfType = getVnfType(genericVnf);
+ final String url = getPreloadVnfsUrl(vnfName, vnfType);
+
+ try {
+ LOGGER.debug("Will query sdnc for input parameters using url: {}", url);
+ final String jsonResponse = sdncClient.get(url);
+
+ final JSONArray vnfParametersArray = JsonPath.read(jsonResponse, VNF_PARAMETERS_PATH);
+ if (vnfParametersArray != null) {
+ for (int index = 0; index < vnfParametersArray.size(); index++) {
+ final Object vnfParametersObject = vnfParametersArray.get(index);
+ if (vnfParametersObject instanceof JSONArray) {
+ final JSONArray vnfParameters = (JSONArray) vnfParametersObject;
+ final Map<String, String> vnfParametersMap = getVnfParameterMap(vnfParameters);
+ return new InputParameter(getAdditionalParameters(vnfParametersMap),
+ getExtVirtualLinks(vnfParametersMap));
+ }
+ }
+ }
+ } catch (final Exception exception) {
+ LOGGER.error("Unable to retrieve/parse input parameters using URL: {} ", url, exception);
+ }
+ LOGGER.warn("No input parameters found ...");
+ return NullInputParameter.NULL_INSTANCE;
+
+ }
+
+ private List<ExternalVirtualLink> getExtVirtualLinks(final Map<String, String> vnfParametersMap)
+ throws JsonParseException, IOException {
+ try {
+ final String extVirtualLinksString = vnfParametersMap.get(EXT_VIRTUAL_LINKS);
+
+ if (extVirtualLinksString != null && !extVirtualLinksString.isEmpty()) {
+ final ObjectMapper mapper = new ObjectMapper();
+ final TypeReference<List<ExternalVirtualLink>> extVirtualLinksStringTypeRef =
+ new TypeReference<List<ExternalVirtualLink>>() {};
+
+ return mapper.readValue(extVirtualLinksString, extVirtualLinksStringTypeRef);
+ }
+ } catch (final Exception exception) {
+ LOGGER.error("Unable to parse {} ", EXT_VIRTUAL_LINKS, exception);
+ }
+ return Collections.emptyList();
+ }
+
+ private Map<String, String> getAdditionalParameters(final Map<String, String> vnfParametersMap)
+ throws JsonParseException, IOException {
+ try {
+ final String additionalParamsString = vnfParametersMap.get(ADDITIONAL_PARAMS);
+ if (additionalParamsString != null && !additionalParamsString.isEmpty()) {
+ final ObjectMapper mapper = new ObjectMapper();
+ final TypeReference<Map<String, String>> typeRef = new TypeReference<Map<String, String>>() {};
+ return mapper.readValue(additionalParamsString, typeRef);
+ }
+ } catch (final Exception exception) {
+ LOGGER.error("Unable to parse {} ", ADDITIONAL_PARAMS, exception);
+ }
+ return Collections.emptyMap();
+ }
+
+ private Map<String, String> getVnfParameterMap(final JSONArray array) {
+ try {
+ if (array != null) {
+ final ObjectMapper mapper = new ObjectMapper();
+ final VnfParameter[] readValue = mapper.readValue(array.toJSONString(), VnfParameter[].class);
+ LOGGER.debug("Vnf parameters: {}", Arrays.asList(readValue));
+ return Arrays.asList(readValue).stream()
+ .filter(vnfParam -> vnfParam.getName() != null && vnfParam.getValue() != null)
+ .collect(Collectors.toMap(VnfParameter::getName, VnfParameter::getValue));
+ }
+ } catch (final IOException exception) {
+ LOGGER.error("Unable to parse vnf parameters : {}", array, exception);
+ }
+ return Collections.emptyMap();
+ }
+
+ private String getPreloadVnfsUrl(final String vnfName, final String vnfType) {
+ return PRELOAD_VNFS_URL + vnfName + FORWARD_SLASH + vnfType;
+ }
+
+ private String getVnfType(final GenericVnf genericVnf) {
+ final ModelInfoGenericVnf modelInfoGenericVnf = genericVnf.getModelInfoGenericVnf();
+ if (modelInfoGenericVnf != null && modelInfoGenericVnf.getModelName() != null) {
+ return modelInfoGenericVnf.getModelName();
+ }
+ return genericVnf.getVnfType();
+ }
+
+}
diff --git a/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/utils/NullInputParameter.java b/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/utils/NullInputParameter.java
new file mode 100644
index 0000000000..fb877ac55d
--- /dev/null
+++ b/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/utils/NullInputParameter.java
@@ -0,0 +1,37 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Ericsson. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.utils;
+
+import java.util.Collections;
+
+/**
+ * @author waqas.ikram@est.tech
+ */
+public class NullInputParameter extends InputParameter {
+
+ private static final long serialVersionUID = -7261286746726871696L;
+
+ public static final NullInputParameter NULL_INSTANCE = new NullInputParameter();
+
+ private NullInputParameter() {
+ super(Collections.emptyMap(), Collections.emptyList());
+ }
+
+}
diff --git a/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/utils/VnfParameter.java b/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/utils/VnfParameter.java
new file mode 100644
index 0000000000..11e93e733d
--- /dev/null
+++ b/bpmn/so-bpmn-tasks/src/main/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/utils/VnfParameter.java
@@ -0,0 +1,91 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Ericsson. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.utils;
+
+import java.util.Objects;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+/**
+ * This is used to deserialize vnf-parameters from vnf-preload-list/{vnf-name}/{vnf-type} response
+ *
+ * @author waqas.ikram@est.tech
+ */
+public class VnfParameter {
+
+ @JsonProperty("vnf-parameter-name")
+ private String name;
+
+ @JsonProperty("vnf-parameter-value")
+ private String value;
+
+ /**
+ * @return the name
+ */
+ public String getName() {
+ return name;
+ }
+
+ /**
+ * @param name the name to set
+ */
+ public void setName(final String name) {
+ this.name = name;
+ }
+
+ /**
+ * @return the value
+ */
+ public String getValue() {
+ return value;
+ }
+
+ /**
+ * @param value the value to set
+ */
+ public void setValue(final String value) {
+ this.value = value;
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + ((name == null) ? 0 : name.hashCode());
+ result = prime * result + ((value == null) ? 0 : value.hashCode());
+ return Objects.hash(name, value);
+ }
+
+ @Override
+ public boolean equals(final Object obj) {
+ if (obj instanceof VnfParameter) {
+ VnfParameter other = (VnfParameter) obj;
+ return Objects.equals(name, other.name) && Objects.equals(value, other.value);
+ }
+
+ return false;
+ }
+
+ @Override
+ public String toString() {
+ return "VnfParameter [name=" + name + ", value=" + value + "]";
+ }
+
+}
diff --git a/bpmn/so-bpmn-tasks/src/test/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/InputParameterRetrieverTaskTest.java b/bpmn/so-bpmn-tasks/src/test/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/InputParameterRetrieverTaskTest.java
new file mode 100644
index 0000000000..803b58b4b8
--- /dev/null
+++ b/bpmn/so-bpmn-tasks/src/test/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/InputParameterRetrieverTaskTest.java
@@ -0,0 +1,125 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Ericsson. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.when;
+
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Test;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.onap.so.bpmn.BaseTaskTest;
+import org.onap.so.bpmn.common.BuildingBlockExecution;
+import org.onap.so.bpmn.common.exceptions.RequiredExecutionVariableExeception;
+import org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.utils.InputParameter;
+import org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.utils.InputParametersProvider;
+import org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.utils.NullInputParameter;
+import org.onap.so.bpmn.servicedecomposition.bbobjects.GenericVnf;
+import org.onap.so.bpmn.servicedecomposition.entities.GeneralBuildingBlock;
+import org.onap.so.bpmn.servicedecomposition.entities.ResourceKey;
+import org.onap.so.client.exception.BBObjectNotFoundException;
+
+/**
+ * @author waqas.ikram@est.tech
+ */
+public class InputParameterRetrieverTaskTest extends BaseTaskTest {
+
+ private final BuildingBlockExecution stubbedxecution = new StubbedBuildingBlockExecution();
+
+ @Mock
+ private InputParametersProvider inputParametersProvider;
+
+ @Test
+ public void testGGetInputParameters_inputParameterStoredInExecutionContext() throws BBObjectNotFoundException {
+ final InputParameterRetrieverTask objUnderTest =
+ new InputParameterRetrieverTask(inputParametersProvider, extractPojosForBB);
+
+ final InputParameter inputParameter = new InputParameter(Collections.emptyMap(), Collections.emptyList());
+ when(inputParametersProvider.getInputParameter(Mockito.any(GenericVnf.class))).thenReturn(inputParameter);
+ when(extractPojosForBB.extractByKey(any(), eq(ResourceKey.GENERIC_VNF_ID))).thenReturn(new GenericVnf());
+ objUnderTest.getInputParameters(stubbedxecution);
+
+ final Object actual = stubbedxecution.getVariable(Constants.INPUT_PARAMETER);
+ assertNotNull(actual);
+ assertTrue(actual instanceof InputParameter);
+ }
+
+ @Test
+ public void testGGetInputParameters_ThrowExecption_NullInputParameterStoredInExecutionContext()
+ throws BBObjectNotFoundException {
+ final InputParameterRetrieverTask objUnderTest =
+ new InputParameterRetrieverTask(inputParametersProvider, extractPojosForBB);
+
+ when(inputParametersProvider.getInputParameter(Mockito.any(GenericVnf.class)))
+ .thenThrow(RuntimeException.class);
+ when(extractPojosForBB.extractByKey(any(), eq(ResourceKey.GENERIC_VNF_ID))).thenReturn(new GenericVnf());
+ objUnderTest.getInputParameters(stubbedxecution);
+
+ final Object actual = stubbedxecution.getVariable(Constants.INPUT_PARAMETER);
+ assertNotNull(actual);
+ assertTrue(actual instanceof NullInputParameter);
+ }
+
+
+ private class StubbedBuildingBlockExecution implements BuildingBlockExecution {
+
+ private final Map<String, Serializable> execution = new HashMap<>();
+
+ @Override
+ public GeneralBuildingBlock getGeneralBuildingBlock() {
+ return null;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public <T> T getVariable(final String key) {
+ return (T) execution.get(key);
+ }
+
+ @Override
+ public <T> T getRequiredVariable(final String key) throws RequiredExecutionVariableExeception {
+ return null;
+ }
+
+ @Override
+ public void setVariable(final String key, final Serializable value) {
+ execution.put(key, value);
+ }
+
+ @Override
+ public Map<ResourceKey, String> getLookupMap() {
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public String getFlowToBeCalled() {
+ return null;
+ }
+
+ }
+}
diff --git a/bpmn/so-bpmn-tasks/src/test/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/VnfmAdapterCreateVnfTaskTest.java b/bpmn/so-bpmn-tasks/src/test/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/VnfmAdapterCreateVnfTaskTest.java
index ddfc08e08f..20abe6ece1 100644
--- a/bpmn/so-bpmn-tasks/src/test/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/VnfmAdapterCreateVnfTaskTest.java
+++ b/bpmn/so-bpmn-tasks/src/test/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/VnfmAdapterCreateVnfTaskTest.java
@@ -29,6 +29,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.Constants.CREATE_VNF_REQUEST_PARAM_NAME;
import static org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.Constants.CREATE_VNF_RESPONSE_PARAM_NAME;
+import static org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.Constants.INPUT_PARAMETER;
import java.io.Serializable;
import java.util.Collections;
@@ -41,8 +42,7 @@ import org.mockito.Mock;
import org.onap.so.bpmn.BaseTaskTest;
import org.onap.so.bpmn.common.BuildingBlockExecution;
import org.onap.so.bpmn.common.exceptions.RequiredExecutionVariableExeception;
-import org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.VnfmAdapterCreateVnfTask;
-import org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.VnfmAdapterServiceProvider;
+import org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.utils.InputParameter;
import org.onap.so.bpmn.servicedecomposition.bbobjects.CloudRegion;
import org.onap.so.bpmn.servicedecomposition.bbobjects.GenericVnf;
import org.onap.so.bpmn.servicedecomposition.entities.GeneralBuildingBlock;
@@ -83,6 +83,8 @@ public class VnfmAdapterCreateVnfTaskTest extends BaseTaskTest {
public void testBuildCreateVnfRequest_withValidValues_storesRequestInExecution() throws Exception {
final VnfmAdapterCreateVnfTask objUnderTest = getEtsiVnfInstantiateTask();
+ stubbedxecution.setVariable(INPUT_PARAMETER,
+ new InputParameter(Collections.emptyMap(), Collections.emptyList()));
when(extractPojosForBB.extractByKey(any(), eq(ResourceKey.GENERIC_VNF_ID))).thenReturn(getGenericVnf());
objUnderTest.buildCreateVnfRequest(stubbedxecution);
diff --git a/bpmn/so-bpmn-tasks/src/test/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/utils/InputParametersProviderImplTest.java b/bpmn/so-bpmn-tasks/src/test/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/utils/InputParametersProviderImplTest.java
new file mode 100644
index 0000000000..d21942d08f
--- /dev/null
+++ b/bpmn/so-bpmn-tasks/src/test/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/utils/InputParametersProviderImplTest.java
@@ -0,0 +1,181 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Ericsson. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.utils;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.Mockito.when;
+import static org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.Constants.FORWARD_SLASH;
+import static org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.Constants.PRELOAD_VNFS_URL;
+import static org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.TestConstants.DUMMY_GENERIC_VND_ID;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.List;
+import java.util.Map;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.junit.MockitoJUnitRunner;
+import org.onap.so.bpmn.servicedecomposition.bbobjects.GenericVnf;
+import org.onap.so.bpmn.servicedecomposition.modelinfo.ModelInfoGenericVnf;
+import org.onap.so.client.exception.BadResponseException;
+import org.onap.so.client.exception.MapperException;
+import org.onap.so.client.sdnc.SDNCClient;
+import org.onap.vnfmadapter.v1.model.ExternalVirtualLink;
+
+/**
+ * @author waqas.ikram@est.tech
+ */
+@RunWith(MockitoJUnitRunner.class)
+public class InputParametersProviderImplTest {
+
+ private static final String BASE_DIR = "src/test/resources/__files/";
+
+ private static final Path PRE_LOAD_SDNC_RESPONSE = Paths.get(BASE_DIR + "SDNCClientPrelaodDataResponse.json");
+
+ private static final Path INVALID_PRE_LOAD_SDNC_RESPONSE =
+ Paths.get(BASE_DIR + "SDNCClientPrelaodDataResponseWithInvalidData.json");
+
+ private static final Path INVALID_ADDITIONAL_AND_EXT_VM_DATA =
+ Paths.get(BASE_DIR + "SDNCClientPrelaodDataResponseWithInvalidAdditionalAndExtVmData.json");
+
+
+ private static final Path INVALID_VNF_PARAMS =
+ Paths.get(BASE_DIR + "SDNCClientPrelaodDataResponseWithInvalidVnfParamsTag.json");
+
+
+ private static final String MODEL_NAME = "MODEL_NAME";
+
+ private static final String GENERIC_VNF_NAME = "GENERIC_VNF_NAME";
+
+ private static final String URL = PRELOAD_VNFS_URL + GENERIC_VNF_NAME + FORWARD_SLASH + MODEL_NAME;
+
+ private static final String GENERIC_VNF_TYPE = MODEL_NAME;
+
+ @Mock
+ private SDNCClient mockedSdncClient;
+
+ @Test
+ public void testGetInputParameter_ValidResponseFromSdnc_NotEmptyInputParameter() throws Exception {
+ assertValues(getGenericVnf());
+ }
+
+ @Test
+ public void testGetInputParameter_ValidResponseFromSdncAndVnfType_NotEmptyInputParameter() throws Exception {
+ assertValues(getGenericVnf(GENERIC_VNF_TYPE));
+ }
+
+ @Test
+ public void testGetInputParameter_ValidResponseFromSdncInvalidData_EmptyInputParameter() throws Exception {
+ when(mockedSdncClient.get(Mockito.eq(URL))).thenReturn(getReponseAsString(INVALID_PRE_LOAD_SDNC_RESPONSE));
+ final InputParametersProvider objUnderTest = new InputParametersProviderImpl(mockedSdncClient);
+ final InputParameter actual = objUnderTest.getInputParameter(getGenericVnf());
+ assertNotNull(actual);
+ assertTrue(actual.getAdditionalParams().isEmpty());
+ assertTrue(actual.getExtVirtualLinks().isEmpty());
+ }
+
+ @Test
+ public void testGetInputParameter_ExceptionThrownFromSdnc_EmptyInputParameter() throws Exception {
+ when(mockedSdncClient.get(Mockito.eq(URL))).thenThrow(RuntimeException.class);
+ final InputParametersProvider objUnderTest = new InputParametersProviderImpl(mockedSdncClient);
+ final InputParameter actual = objUnderTest.getInputParameter(getGenericVnf());
+ assertNotNull(actual);
+ assertTrue(actual instanceof NullInputParameter);
+ assertTrue(actual.getAdditionalParams().isEmpty());
+ assertTrue(actual.getExtVirtualLinks().isEmpty());
+ }
+
+ @Test
+ public void testGetInputParameter_InvalidResponseData_EmptyInputParameter() throws Exception {
+ when(mockedSdncClient.get(Mockito.eq(URL))).thenReturn(getReponseAsString(INVALID_ADDITIONAL_AND_EXT_VM_DATA));
+ final InputParametersProvider objUnderTest = new InputParametersProviderImpl(mockedSdncClient);
+ final InputParameter actual = objUnderTest.getInputParameter(getGenericVnf());
+ assertNotNull(actual);
+ assertTrue(actual.getAdditionalParams().isEmpty());
+ assertTrue(actual.getExtVirtualLinks().isEmpty());
+ }
+
+ @Test
+ public void testGetInputParameter_EmptyResponseData_EmptyInputParameter() throws Exception {
+ when(mockedSdncClient.get(Mockito.eq(URL))).thenReturn("");
+ final InputParametersProvider objUnderTest = new InputParametersProviderImpl(mockedSdncClient);
+ final InputParameter actual = objUnderTest.getInputParameter(getGenericVnf());
+ assertNotNull(actual);
+ assertTrue(actual instanceof NullInputParameter);
+ assertTrue(actual.getAdditionalParams().isEmpty());
+ assertTrue(actual.getExtVirtualLinks().isEmpty());
+ }
+
+ @Test
+ public void testGetInputParameter_InvalidVnfParamsResponseData_EmptyInputParameter() throws Exception {
+ when(mockedSdncClient.get(Mockito.eq(URL))).thenReturn(getReponseAsString(INVALID_VNF_PARAMS));
+ final InputParametersProvider objUnderTest = new InputParametersProviderImpl(mockedSdncClient);
+ final InputParameter actual = objUnderTest.getInputParameter(getGenericVnf());
+ assertNotNull(actual);
+ assertTrue(actual.getAdditionalParams().isEmpty());
+ assertTrue(actual.getExtVirtualLinks().isEmpty());
+ }
+
+ private void assertValues(final GenericVnf genericVnf) throws MapperException, BadResponseException, IOException {
+ when(mockedSdncClient.get(Mockito.eq(URL))).thenReturn(getReponseAsString(PRE_LOAD_SDNC_RESPONSE));
+ final InputParametersProvider objUnderTest = new InputParametersProviderImpl(mockedSdncClient);
+ final InputParameter actual = objUnderTest.getInputParameter(genericVnf);
+ assertNotNull(actual);
+
+ final Map<String, String> actualAdditionalParams = actual.getAdditionalParams();
+ assertEquals(3, actualAdditionalParams.size());
+
+ final String actualInstanceType = actualAdditionalParams.get("instance_type");
+ assertEquals("m1.small", actualInstanceType);
+
+ final List<ExternalVirtualLink> actualExtVirtualLinks = actual.getExtVirtualLinks();
+ assertEquals(1, actualExtVirtualLinks.size());
+
+ final ExternalVirtualLink actualExternalVirtualLink = actualExtVirtualLinks.get(0);
+ assertEquals("ac1ed33d-8dc1-4800-8ce8-309b99c38eec", actualExternalVirtualLink.getId());
+ }
+
+ private String getReponseAsString(final Path filePath) throws IOException {
+ return new String(Files.readAllBytes(filePath));
+ }
+
+ private GenericVnf getGenericVnf() {
+ final GenericVnf genericVnf = getGenericVnf(GENERIC_VNF_TYPE);
+ final ModelInfoGenericVnf modelInfoGenericVnf = new ModelInfoGenericVnf();
+ modelInfoGenericVnf.setModelName(MODEL_NAME);
+ genericVnf.setModelInfoGenericVnf(modelInfoGenericVnf);
+ return genericVnf;
+ }
+
+ private GenericVnf getGenericVnf(final String vnfType) {
+ final GenericVnf genericVnf = new GenericVnf();
+ genericVnf.setVnfId(DUMMY_GENERIC_VND_ID);
+ genericVnf.setVnfName(GENERIC_VNF_NAME);
+ genericVnf.setVnfType(vnfType);
+ return genericVnf;
+ }
+}
diff --git a/bpmn/so-bpmn-tasks/src/test/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/utils/VnfParameterTest.java b/bpmn/so-bpmn-tasks/src/test/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/utils/VnfParameterTest.java
new file mode 100644
index 0000000000..46018b8f39
--- /dev/null
+++ b/bpmn/so-bpmn-tasks/src/test/java/org/onap/so/bpmn/infrastructure/adapter/vnfm/tasks/utils/VnfParameterTest.java
@@ -0,0 +1,38 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Ericsson. 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.so.bpmn.infrastructure.adapter.vnfm.tasks.utils;
+
+import org.junit.Test;
+
+import nl.jqno.equalsverifier.EqualsVerifier;
+import nl.jqno.equalsverifier.Warning;
+
+/**
+ * @author waqas.ikram@est.tech
+ *
+ */
+public class VnfParameterTest {
+ @Test
+ public void testVnfParameter_equalAndHasCode() throws ClassNotFoundException {
+ EqualsVerifier.forClass(VnfParameter.class).suppress(Warning.STRICT_INHERITANCE, Warning.NONFINAL_FIELDS)
+ .verify();
+ }
+
+}
diff --git a/bpmn/so-bpmn-tasks/src/test/resources/__files/SDNCClientPrelaodDataResponse.json b/bpmn/so-bpmn-tasks/src/test/resources/__files/SDNCClientPrelaodDataResponse.json
new file mode 100644
index 0000000000..0de25616e3
--- /dev/null
+++ b/bpmn/so-bpmn-tasks/src/test/resources/__files/SDNCClientPrelaodDataResponse.json
@@ -0,0 +1,127 @@
+{
+ "vnf-preload-list": [
+ {
+ "vnf-name": "GENERIC_VNF_NAME",
+ "vnf-type": "SIMPLE",
+ "preload-data":
+ {
+ "network-topology-information":
+ {
+ },
+ "vnf-topology-information":
+ {
+ "vnf-topology-identifier":
+ {
+ "service-type": "vCPE",
+ "vnf-type": "SIMPLE",
+ "vnf-name": "GENERIC_VNF_NAME",
+ "generic-vnf-name": "GENERIC_VNF_NAME",
+ "generic-vnf-type": "SIMPLE"
+ },
+ "vnf-parameters": [
+ {
+ "vnf-parameter-name": "extra_console",
+ "vnf-parameter-value": "ttyS1"
+ },
+ {
+ "vnf-parameter-name": "vnfUsername",
+ "vnf-parameter-value": "vnf_user"
+ },
+ {
+ "vnf-parameter-name": "additionalParams",
+ "vnf-parameter-value": "{\"image_id\": \"DUMMYVNF\",\"instance_type\": \"m1.small\",\"ftp_address\": \"ftp://0.0.0.0:2100/\"}"
+ },
+ {
+ "vnf-parameter-name": "fsb_admin_gateway_ip_1",
+ "vnf-parameter-value": "0.0.0.0"
+ },
+ {
+ "vnf-parameter-name": "availability_zone_1"
+ },
+ {
+ "vnf-parameter-name": "fsb_admin_gateway_ip_2"
+ },
+ {
+ "vnf-parameter-name": "fsb_admin_prefix_length",
+ "vnf-parameter-value": "28"
+ },
+ {
+ "vnf-parameter-name": "ONAPMME_OMCN_vLC_P4_prefix_length",
+ "vnf-parameter-value": "28"
+ },
+ {
+ "vnf-parameter-name": "gpbs",
+ "vnf-parameter-value": "2"
+ },
+ {
+ "vnf-parameter-name": "fsb_admin_ip_2",
+ "vnf-parameter-value": "192.0.0.1"
+ },
+ {
+ "vnf-parameter-name": "internal_mtu",
+ "vnf-parameter-value": "1500"
+ },
+ {
+ "vnf-parameter-name": "storage_drbd_sync_rate",
+ "vnf-parameter-value": "0"
+ },
+ {
+ "vnf-parameter-name": "ONAPMME_MEDIA_vLC_P3_net_id",
+ "vnf-parameter-value": "ONAPMME_MEDIA_vLC_P3"
+ },
+ {
+ "vnf-parameter-name": "extVirtualLinks",
+ "vnf-parameter-value": "[{\"id\":\"ac1ed33d-8dc1-4800-8ce8-309b99c38eec\",\"tenant\":{\"cloudOwner\":\"CloudOwner\",\"regionName\":\"RegionOne\",\"tenantId\":\"80c26954-2536-4bca-9e20-10f8a2c9c2ad\"},\"resourceId\":\"8ef8cd54-75fd-4372-a6dd-2e05ea8fbd9b\",\"extCps\":[{\"cpdId\":\"f449292f-2f0f-4656-baa3-a18d86bac80f\",\"cpConfig\":[{\"cpInstanceId\":\"07876709-b66f-465c-99a7-0f4d026197f2\",\"linkPortId\":null,\"cpProtocolData\":null}]}],\"extLinkPorts\":null}]"
+ },
+ {
+ "vnf-parameter-name": "vnfIpAddress",
+ "vnf-parameter-value": "127.0.0.0"
+ },
+ {
+ "vnf-parameter-name": "node_type",
+ "vnf-parameter-value": "sgsnl"
+ },
+ {
+ "vnf-parameter-name": "ONAPMME_SIG_vLC_P2_net_id",
+ "vnf-parameter-value": "ONAPMME_SIG_vLC_P2"
+ },
+ {
+ "vnf-parameter-name": "updateOss",
+ "vnf-parameter-value": "false"
+ },
+ {
+ "vnf-parameter-name": "tmo",
+ "vnf-parameter-value": "0"
+ },
+ {
+ "vnf-parameter-name": "ss7",
+ "vnf-parameter-value": "Not_Applicable"
+ },
+ {
+ "vnf-parameter-name": "ONAPMME_OMCN_vLC_P4_net_id",
+ "vnf-parameter-value": "ONAPMME_OMCN_vLC_P4"
+ },
+ {
+ "vnf-parameter-name": "key_name"
+ },
+ {
+ "vnf-parameter-name": "fsb_admin_dns_server_ip_2"
+ },
+ {
+ "vnf-parameter-name": "time_zone",
+ "vnf-parameter-value": "GMT"
+ },
+ {
+ "vnf-parameter-name": "enableRollback",
+ "vnf-parameter-value": "false"
+ }
+ ]
+ },
+ "oper-status":
+ {
+ "order-status": "PendingAssignment"
+ }
+ }
+ }
+ ]
+}
diff --git a/bpmn/so-bpmn-tasks/src/test/resources/__files/SDNCClientPrelaodDataResponseWithInvalidAdditionalAndExtVmData.json b/bpmn/so-bpmn-tasks/src/test/resources/__files/SDNCClientPrelaodDataResponseWithInvalidAdditionalAndExtVmData.json
new file mode 100644
index 0000000000..c2cf2b2f28
--- /dev/null
+++ b/bpmn/so-bpmn-tasks/src/test/resources/__files/SDNCClientPrelaodDataResponseWithInvalidAdditionalAndExtVmData.json
@@ -0,0 +1,47 @@
+{
+ "vnf-preload-list": [
+ {
+ "vnf-name": "GENERIC_VNF_NAME",
+ "vnf-type": "SIMPLE",
+ "preload-data":
+ {
+ "network-topology-information":
+ {
+ },
+ "vnf-topology-information":
+ {
+ "vnf-topology-identifier":
+ {
+ "service-type": "vCPE",
+ "vnf-type": "SIMPLE",
+ "vnf-name": "GENERIC_VNF_NAME",
+ "generic-vnf-name": "GENERIC_VNF_NAME",
+ "generic-vnf-type": "SIMPLE"
+ },
+ "vnf-parameters": [
+ {
+ "vnf-parameter-name": "extra_console",
+ "vnf-parameter-value": "ttyS1"
+ },
+ {
+ "vnf-parameter-name": "vnfUsername",
+ "vnf-parameter-value": "vnf_user"
+ },
+ {
+ "vnf-parameter-name": "additionalParams",
+ "vnf-parameter-value": "[\"abc\"]"
+ },
+ {
+ "vnf-parameter-name": "extVirtualLinks",
+ "vnf-parameter-value": "{\"def\":\"123\"}"
+ }
+ ]
+ },
+ "oper-status":
+ {
+ "order-status": "PendingAssignment"
+ }
+ }
+ }
+ ]
+}
diff --git a/bpmn/so-bpmn-tasks/src/test/resources/__files/SDNCClientPrelaodDataResponseWithInvalidData.json b/bpmn/so-bpmn-tasks/src/test/resources/__files/SDNCClientPrelaodDataResponseWithInvalidData.json
new file mode 100644
index 0000000000..552adb9125
--- /dev/null
+++ b/bpmn/so-bpmn-tasks/src/test/resources/__files/SDNCClientPrelaodDataResponseWithInvalidData.json
@@ -0,0 +1,39 @@
+{
+ "vnf-preload-list": [
+ {
+ "vnf-name": "GENERIC_VNF_NAME",
+ "vnf-type": "SIMPLE",
+ "preload-data":
+ {
+ "network-topology-information":
+ {
+ },
+ "vnf-topology-information":
+ {
+ "vnf-topology-identifier":
+ {
+ "service-type": "vCPE",
+ "vnf-type": "SIMPLE",
+ "vnf-name": "GENERIC_VNF_NAME",
+ "generic-vnf-name": "GENERIC_VNF_NAME",
+ "generic-vnf-type": "SIMPLE"
+ },
+ "vnf-parameters": [
+ {
+ "vnf-parameter-name": "extra_console",
+ "vnf-parameter-value": "ttyS1"
+ },
+ {
+ "vnf-parameter-name": "vnfUsername",
+ "vnf-parameter-value": "vnf_user"
+ }
+ ]
+ },
+ "oper-status":
+ {
+ "order-status": "PendingAssignment"
+ }
+ }
+ }
+ ]
+}
diff --git a/bpmn/so-bpmn-tasks/src/test/resources/__files/SDNCClientPrelaodDataResponseWithInvalidVnfParamsTag.json b/bpmn/so-bpmn-tasks/src/test/resources/__files/SDNCClientPrelaodDataResponseWithInvalidVnfParamsTag.json
new file mode 100644
index 0000000000..e19ad1c9d3
--- /dev/null
+++ b/bpmn/so-bpmn-tasks/src/test/resources/__files/SDNCClientPrelaodDataResponseWithInvalidVnfParamsTag.json
@@ -0,0 +1,34 @@
+{
+ "vnf-preload-list": [
+ {
+ "vnf-name": "GENERIC_VNF_NAME",
+ "vnf-type": "SIMPLE",
+ "preload-data":
+ {
+ "network-topology-information":
+ {
+ },
+ "vnf-topology-information":
+ {
+ "vnf-topology-identifier":
+ {
+ "service-type": "vCPE",
+ "vnf-type": "SIMPLE",
+ "vnf-name": "GENERIC_VNF_NAME",
+ "generic-vnf-name": "GENERIC_VNF_NAME",
+ "generic-vnf-type": "SIMPLE"
+ },
+ "vnf-parameters": [
+ {
+ "hello": "world"
+ }
+ ]
+ },
+ "oper-status":
+ {
+ "order-status": "PendingAssignment"
+ }
+ }
+ }
+ ]
+}
diff --git a/common/src/main/java/org/onap/so/client/aai/AAIObjectType.java b/common/src/main/java/org/onap/so/client/aai/AAIObjectType.java
index 21e36cde6c..34d560210c 100644
--- a/common/src/main/java/org/onap/so/client/aai/AAIObjectType.java
+++ b/common/src/main/java/org/onap/so/client/aai/AAIObjectType.java
@@ -21,7 +21,6 @@
package org.onap.so.client.aai;
import java.io.Serializable;
-import java.lang.reflect.Field;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
@@ -39,7 +38,9 @@ import org.onap.aai.domain.yang.Connector;
import org.onap.aai.domain.yang.Customer;
import org.onap.aai.domain.yang.Device;
import org.onap.aai.domain.yang.ExtAaiNetwork;
+import org.onap.aai.domain.yang.Flavor;
import org.onap.aai.domain.yang.GenericVnf;
+import org.onap.aai.domain.yang.Image;
import org.onap.aai.domain.yang.InstanceGroup;
import org.onap.aai.domain.yang.L3Network;
import org.onap.aai.domain.yang.LInterface;
@@ -134,6 +135,8 @@ public class AAIObjectType implements GraphInventoryObjectType, Serializable {
public static final AAIObjectType EXT_AAI_NETWORK = new AAIObjectType(AAINamespaceConstants.NETWORK, ExtAaiNetwork.class);
public static final AAIObjectType AGGREGATE_ROUTE = new AAIObjectType(AAINamespaceConstants.NETWORK, AggregateRoute.class);
public static final AAIObjectType L_INTERFACE = new AAIObjectType(AAIObjectType.VSERVER.uriTemplate(), LInterface.class);
+ public static final AAIObjectType IMAGE = new AAIObjectType(AAIObjectType.CLOUD_REGION.uriTemplate(), Image.class);
+ public static final AAIObjectType FLAVOR = new AAIObjectType(AAIObjectType.CLOUD_REGION.uriTemplate(), Flavor.class);
public static final AAIObjectType UNKNOWN = new AAIObjectType("", "", "unknown");
public static final AAIObjectType DSL = new AAIObjectType("/dsl", "", "dsl");