aboutsummaryrefslogtreecommitdiffstats
path: root/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap
diff options
context:
space:
mode:
Diffstat (limited to 'adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap')
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/LifeCycleManagementConstants.java33
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/NvfmAdapterUtils.java64
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/AbstractServiceProviderConfiguration.java49
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/SdcPackageProvider.java195
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiClientProvider.java34
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiHelper.java217
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiPropertiesImpl.java68
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiServiceProvider.java148
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiServiceProviderImpl.java158
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/OamIpAddressSource.java57
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vim/model/AccessInfo.java107
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vim/model/InterfaceInfo.java74
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vim/model/VimCredentials.java85
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmHelper.java228
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProvider.java104
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProviderConfiguration.java154
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProviderImpl.java194
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmUrlProvider.java95
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/jobmanagement/JobManager.java174
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/jobmanagement/VnfmOperation.java122
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/lifecycle/LifecycleManager.java265
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/notificationhandling/NotificationHandler.java276
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/oauth/AuthorizationServerConfig.java55
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/oauth/OAuth2AccessTokenAdapter.java51
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/oauth/OAuth2ResourceServer.java52
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/Sol003GrantController.java114
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/Sol003LcnContoller.java131
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/VnfmAdapterController.java164
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/JobNotFoundException.java38
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/TenantNotFoundException.java35
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/VnfNotFoundException.java38
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/VnfmNotFoundException.java38
-rw-r--r--adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/VnfmRequestFailureException.java38
33 files changed, 3655 insertions, 0 deletions
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/LifeCycleManagementConstants.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/LifeCycleManagementConstants.java
new file mode 100644
index 0000000000..c812863901
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/LifeCycleManagementConstants.java
@@ -0,0 +1,33 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter;
+
+/**
+ * ETSI SOL003 Life Cycle Management Adapter constants
+ *
+ * @author Waqas Ikram (waqas.ikram@est.tech)
+ */
+public class LifeCycleManagementConstants {
+
+ public static final String OPERATION_NOTIFICATION_ENDPOINT = "/lcn/VnfLcmOperationOccurrenceNotification";
+
+ private LifeCycleManagementConstants() {}
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/NvfmAdapterUtils.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/NvfmAdapterUtils.java
new file mode 100644
index 0000000000..db34cbf3f2
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/NvfmAdapterUtils.java
@@ -0,0 +1,64 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter;
+
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import org.slf4j.Logger;
+import java.util.ArrayList;
+import java.util.Collection;
+import static org.slf4j.LoggerFactory.getLogger;
+
+public class NvfmAdapterUtils {
+ private static Logger logger = getLogger(NvfmAdapterUtils.class);
+
+ public static JsonObject child(JsonObject parent, String name) {
+ return childElement(parent, name).getAsJsonObject();
+ }
+
+ public static JsonElement childElement(JsonObject parent, String name) {
+ JsonElement child = parent.get(name);
+ if (child == null) {
+ throw abortOperation("Missing child " + name);
+ }
+ return child;
+ }
+
+ public static Collection<JsonObject> children(JsonObject parent) {
+ ArrayList<JsonObject> childElements = new ArrayList<>();
+ for (String childKey : parent.keySet()) {
+ if (parent.get(childKey).isJsonObject()) {
+ childElements.add(parent.get(childKey).getAsJsonObject());
+ }
+ }
+ return childElements;
+ }
+
+ public static RuntimeException abortOperation(String msg, Exception e) {
+ logger.error(msg, e);
+ return new RuntimeException(msg, e);
+ }
+
+ public static RuntimeException abortOperation(String msg) {
+ logger.error(msg);
+ return new RuntimeException(msg);
+ }
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/AbstractServiceProviderConfiguration.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/AbstractServiceProviderConfiguration.java
new file mode 100644
index 0000000000..8f6d853997
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/AbstractServiceProviderConfiguration.java
@@ -0,0 +1,49 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.extclients;
+
+import com.google.gson.Gson;
+import java.util.Iterator;
+import org.onap.vnfmadapter.v1.JSON;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.converter.json.GsonHttpMessageConverter;
+import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * A base class that can be extended by classes for configuring HttpRestServiceProvider classes. Provides common methods
+ * that will be useful to some such classes.
+ *
+ * @author gareth.roper@est.tech
+ */
+public abstract class AbstractServiceProviderConfiguration {
+
+ public void setGsonMessageConverter(final RestTemplate restTemplate) {
+ final Iterator<HttpMessageConverter<?>> iterator = restTemplate.getMessageConverters().iterator();
+ while (iterator.hasNext()) {
+ if (iterator.next() instanceof MappingJackson2HttpMessageConverter) {
+ iterator.remove();
+ }
+ }
+ final Gson gson = new JSON().getGson();
+ restTemplate.getMessageConverters().add(new GsonHttpMessageConverter(gson));
+ }
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/SdcPackageProvider.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/SdcPackageProvider.java
new file mode 100644
index 0000000000..735e1f9d42
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/SdcPackageProvider.java
@@ -0,0 +1,195 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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
+ *
+ * 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.adapters.vnfmadapter.extclients;
+
+import static com.google.common.base.Splitter.on;
+import static com.google.common.collect.Iterables.filter;
+import static com.google.common.io.ByteStreams.toByteArray;
+import static java.lang.String.format;
+import static org.apache.http.HttpHeaders.ACCEPT;
+import static org.apache.http.HttpHeaders.AUTHORIZATION;
+import static org.onap.so.adapters.vnfmadapter.NvfmAdapterUtils.abortOperation;
+import static org.onap.so.adapters.vnfmadapter.NvfmAdapterUtils.child;
+import static org.onap.so.adapters.vnfmadapter.NvfmAdapterUtils.childElement;
+import static org.onap.so.adapters.vnfmadapter.NvfmAdapterUtils.children;
+import static org.slf4j.LoggerFactory.getLogger;
+import static org.springframework.http.MediaType.APPLICATION_OCTET_STREAM_VALUE;
+import com.google.common.io.ByteStreams;
+import com.google.gson.Gson;
+import com.google.gson.JsonObject;
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.NoSuchElementException;
+import java.util.Set;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import javax.net.ssl.SSLContext;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.http.HttpEntity;
+import org.apache.http.client.methods.CloseableHttpResponse;
+import org.apache.http.client.methods.HttpGet;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.HttpClients;
+import org.onap.so.utils.CryptoUtils;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import org.yaml.snakeyaml.Yaml;
+
+@Component
+public class SdcPackageProvider {
+ private static final String GET_PACKAGE_URL = "%s/sdc/v1/catalog/resources/%s/toscaModel";
+ @Value("${sdc.toscametapath:TOSCA-Metadata/TOSCA.meta}")
+ private List<String> toscaMetaPaths;
+ private static final String TOSCA_VNFD_KEY = "Entry-Definitions";
+ private static Logger logger = getLogger(SdcPackageProvider.class);
+
+ @Value("${sdc.username}")
+ private String sdcUsername;
+ @Value("${sdc.password}")
+ private String sdcPassword;
+ @Value("${sdc.key}")
+ private String sdcKey;
+ @Value("${sdc.endpoint}")
+ private String baseUrl;
+
+ public String getVnfdId(final String csarId) {
+ return getVnfNodeProperty(csarId, "descriptor_id");
+ }
+
+ private String getVnfNodeProperty(final String csarId, final String propertyName) {
+ logger.debug("Getting " + propertyName + " from " + csarId);
+ final byte[] onapPackage = getPackage(csarId);
+
+ try {
+ final String vnfdLocation = getVnfdLocation(new ByteArrayInputStream(onapPackage));
+ final String onapVnfdContent = getFileInZip(new ByteArrayInputStream(onapPackage), vnfdLocation).toString();
+ logger.debug("VNFD CONTENTS: " + onapVnfdContent);
+ final JsonObject root = new Gson().toJsonTree(new Yaml().load(onapVnfdContent)).getAsJsonObject();
+
+ final JsonObject topologyTemplates = child(root, "topology_template");
+ final JsonObject nodeTemplates = child(topologyTemplates, "node_templates");
+ for (final JsonObject child : children(nodeTemplates)) {
+ final String type = childElement(child, "type").getAsString();
+ String propertyValue = null;
+ if ("tosca.nodes.nfv.VNF".equals(type)) {
+ final JsonObject properties = child(child, "properties");
+ logger.debug("properties: " + properties.toString());
+
+ propertyValue = properties.get(propertyName).getAsJsonPrimitive().getAsString();
+ }
+ if (propertyValue == null) {
+ propertyValue = getValueFromNodeTypeDefinition(root, type, propertyName);
+ }
+ return propertyValue;
+ }
+
+ } catch (final Exception e) {
+ throw new IllegalArgumentException("Unable to extract " + propertyName + " from ONAP package", e);
+ }
+ throw new IllegalArgumentException("Unable to extract " + propertyName + " from ONAP package");
+ }
+
+ private String getValueFromNodeTypeDefinition(final JsonObject root, final String nodeTypeName,
+ final String propertyName) {
+ final JsonObject nodeTypes = child(root, "node_types");
+ final JsonObject nodeType = child(nodeTypes, nodeTypeName);
+
+ if ("tosca.nodes.nfv.VNF".equals(childElement(nodeType, "derived_from").getAsString())) {
+ final JsonObject properties = child(nodeType, "properties");
+ logger.debug("properties: " + properties.toString());
+ final JsonObject property = child(properties, propertyName);
+ logger.debug("property: " + property.toString());
+ logger.debug("property default: " + childElement(property, "default").toString());
+ return childElement(property, "default").getAsJsonPrimitive().getAsString();
+ }
+ return null;
+ }
+
+ private byte[] getPackage(final String csarId) {
+ final String SERVICE_NAME = "vnfm-adapter";
+ try (CloseableHttpClient client = HttpClients.custom().setSSLContext(SSLContext.getDefault()).build()) {
+ final HttpGet httpget = new HttpGet(format(GET_PACKAGE_URL, baseUrl, csarId));
+ httpget.setHeader(ACCEPT, APPLICATION_OCTET_STREAM_VALUE);
+ httpget.setHeader("X-ECOMP-InstanceID", SERVICE_NAME);
+ httpget.setHeader("X-FromAppId", SERVICE_NAME);
+ final String auth = sdcUsername + ":" + CryptoUtils.decrypt(sdcPassword, sdcKey);
+ final byte[] encodedAuth = Base64.encodeBase64(auth.getBytes(StandardCharsets.ISO_8859_1));
+ final String authHeader = "Basic " + new String(encodedAuth);
+ httpget.setHeader(AUTHORIZATION, authHeader);
+ logger.debug("Fetching from SDC: " + httpget);
+ final CloseableHttpResponse response = client.execute(httpget);
+ final HttpEntity entity = response.getEntity();
+ final InputStream is = entity.getContent();
+ return toByteArray(is);
+ } catch (final Exception e) {
+ throw abortOperation("Unable to download " + csarId + " package from SDC", e);
+ }
+ }
+
+ private String getVnfdLocation(final InputStream stream) throws IOException {
+ final Iterator<String> pathIterator = toscaMetaPaths.iterator();
+ while (pathIterator.hasNext()) {
+ final String toscaMetadata = new String(getFileInZip(stream, pathIterator.next()).toByteArray());
+ if (!toscaMetadata.isEmpty()) {
+ final String toscaVnfdLine =
+ filter(on("\n").split(toscaMetadata), line -> line.contains(TOSCA_VNFD_KEY)).iterator().next();
+ return toscaVnfdLine.replace(TOSCA_VNFD_KEY + ":", "").trim();
+ }
+ }
+ throw abortOperation("Unable to find valid Tosca Path");
+ }
+
+ private static ByteArrayOutputStream getFileInZip(final InputStream zip, final String path) throws IOException {
+ final ZipInputStream zipInputStream = new ZipInputStream(zip);
+ final ByteArrayOutputStream fileContent = getFileInZip(zipInputStream, path);
+ zipInputStream.close();
+ return fileContent;
+ }
+
+ private static ByteArrayOutputStream getFileInZip(final ZipInputStream zipInputStream, final String path)
+ throws IOException {
+ ZipEntry zipEntry;
+ final Set<String> items = new HashSet<>();
+ while ((zipEntry = zipInputStream.getNextEntry()) != null) {
+ items.add(zipEntry.getName());
+ if (zipEntry.getName().matches(path)) {
+ final ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
+ ByteStreams.copy(zipInputStream, byteArrayOutputStream);
+ return byteArrayOutputStream;
+ }
+ }
+ logger.error("Unable to find the {} in archive found: {}", path, items);
+ throw new NoSuchElementException("Unable to find the " + path + " in archive found: " + items);
+ }
+
+ public String getFlavourId(final String csarId) {
+ return getVnfNodeProperty(csarId, "flavour_id");
+ }
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiClientProvider.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiClientProvider.java
new file mode 100644
index 0000000000..674314d9da
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiClientProvider.java
@@ -0,0 +1,34 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.extclients.aai;
+
+import org.onap.so.client.aai.AAIResourcesClient;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class AaiClientProvider {
+
+ @Bean
+ public AAIResourcesClient getAaiClient() {
+ return new AAIResourcesClient();
+ }
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiHelper.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiHelper.java
new file mode 100644
index 0000000000..6a7bc6b94b
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiHelper.java
@@ -0,0 +1,217 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.extclients.aai;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import org.onap.aai.domain.yang.EsrSystemInfo;
+import org.onap.aai.domain.yang.EsrSystemInfoList;
+import org.onap.aai.domain.yang.EsrVnfm;
+import org.onap.aai.domain.yang.EsrVnfmList;
+import org.onap.aai.domain.yang.GenericVnf;
+import org.onap.aai.domain.yang.Relationship;
+import org.onap.aai.domain.yang.RelationshipData;
+import org.onap.aai.domain.yang.Vserver;
+import org.onap.so.adapters.vnfmadapter.lcn.model.LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs;
+import org.onap.so.adapters.vnfmadapter.rest.exceptions.TenantNotFoundException;
+import org.onap.so.adapters.vnfmadapter.rest.exceptions.VnfmNotFoundException;
+import org.onap.vnfmadapter.v1.model.Tenant;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * Provides helper methods for interactions with AAI.
+ */
+@Service
+public class AaiHelper {
+
+ private static final Logger logger = LoggerFactory.getLogger(AaiHelper.class);
+ private final AaiServiceProvider aaiServiceProvider;
+ private final Map<String, OamIpAddressSource> mapOfVnfIdToOamIpAddressHolder = new HashMap<>();
+
+ @Autowired
+ public AaiHelper(final AaiServiceProvider aaiServiceProvider) {
+ this.aaiServiceProvider = aaiServiceProvider;
+ }
+
+ /**
+ * Get the VNFM assigned for use for the given generic VNF.
+ *
+ * @param vnf the generic VNF
+ * @return the VNFM to use, or <code>null</code> if no VNFM has been assigned yet
+ */
+ public EsrVnfm getAssignedVnfm(final GenericVnf vnf) {
+ final String vnfmId = getIdOfAssignedVnfm(vnf);
+ return vnfmId == null ? null : aaiServiceProvider.invokeGetVnfm(vnfmId);
+ }
+
+ /**
+ * Get the ID of the VNFM assigned for use for the given generic VNF.
+ *
+ * @param vnf the generic VNF
+ * @return the ID of the VNFM to use, or <code>null</code> if no VNFM has been assigned yet
+ */
+ public String getIdOfAssignedVnfm(final GenericVnf vnf) {
+ final Relationship relationship = getRelationship(vnf, "esr-vnfm");
+ return getRelationshipData(relationship, "esr-vnfm.vnfm-id");
+ }
+
+ /**
+ * Get the tenant assigned for use for the given generic VNF.
+ *
+ * @param vnf the generic VNF
+ * @return the tenant to use, or <code>null</code> if no tenant has been assigned yet
+ */
+ public Tenant getAssignedTenant(final GenericVnf vnf) {
+ final Relationship relationship = getRelationship(vnf, "tenant");
+ final String cloudOwner = getRelationshipData(relationship, "cloud-region.cloud-owner");
+ final String cloudRegion = getRelationshipData(relationship, "cloud-region.cloud-region-id");
+ final String tenantId = getRelationshipData(relationship, "tenant.tenant-id");
+ if (cloudOwner == null || cloudRegion == null || tenantId == null) {
+ throw new TenantNotFoundException("No matching Tenant found in AAI. VNFID: " + vnf.getVnfId());
+ } else {
+ return new Tenant().cloudOwner(cloudOwner).regionName(cloudRegion).tenantId(tenantId);
+ }
+ }
+
+ private Relationship getRelationship(final GenericVnf vnf, final String relationshipRelatedToValue) {
+ for (final Relationship relationship : vnf.getRelationshipList() == null ? Collections.<Relationship>emptyList()
+ : vnf.getRelationshipList().getRelationship()) {
+ if (relationship.getRelatedTo().equals(relationshipRelatedToValue)) {
+ return relationship;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Get the value of the relationship data with the given key in the given relationship.
+ *
+ * @param relationship the relationship
+ * @param relationshipDataKey the key for the relationship data
+ * @return the value of the relationship data for the given key
+ */
+ public String getRelationshipData(final Relationship relationship, final String relationshipDataKey) {
+ if (relationship != null) {
+ for (final RelationshipData relationshipData : relationship.getRelationshipData()) {
+ if (relationshipData.getRelationshipKey().equals(relationshipDataKey)) {
+ return relationshipData.getRelationshipValue();
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Delete from the given VNF the relationship matching the given criteria.
+ *
+ * @param vnf the VNF
+ * @param relationshipRelatedToValue the related-to value for the relationship
+ * @param dataKey the relationship data key to match on
+ * @param dataValue the value the relationship data with the given key must match
+ * @return the deleted relationship or <code>null</code> if none found matching the given criteria
+ */
+ public Relationship deleteRelationshipWithDataValue(final GenericVnf vnf, final String relationshipRelatedToValue,
+ final String dataKey, final String dataValue) {
+ final Iterator<Relationship> relationships =
+ vnf.getRelationshipList() == null ? Collections.<Relationship>emptyList().iterator()
+ : vnf.getRelationshipList().getRelationship().iterator();
+
+ while (relationships.hasNext()) {
+ final Relationship relationship = relationships.next();
+ if (relationship.getRelatedTo().equals(relationshipRelatedToValue)
+ && dataValue.equals(getRelationshipData(relationship, dataKey))) {
+ relationships.remove();
+ return relationship;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Select a VNFM to use for the given generic VNF. Should only be used when no VNFM has already been assigned to the
+ * VNF.
+ *
+ * @param vnf the generic VNF
+ * @return the VNFM to use
+ */
+ public EsrVnfm selectVnfm(final GenericVnf vnf) {
+ final EsrVnfmList vnfmsInEsr = aaiServiceProvider.invokeGetVnfms();
+
+ if (vnfmsInEsr == null) {
+ throw new VnfmNotFoundException("No VNFMs found in AAI ESR");
+ }
+ logger.debug("VNFMs in ESR: " + vnfmsInEsr);
+
+ for (final EsrVnfm vnfm : vnfmsInEsr.getEsrVnfm()) {
+ final EsrSystemInfoList systemInfolist =
+ aaiServiceProvider.invokeGetVnfmEsrSystemInfoList(vnfm.getVnfmId());
+ vnfm.setEsrSystemInfoList(systemInfolist);
+ if (vnfmHasMatchingEsrSystemInfoType(vnfm, vnf.getNfType())) {
+ return vnfm;
+ }
+ }
+ throw new VnfmNotFoundException("No matching VNFM found in AAI ESR");
+ }
+
+ private boolean vnfmHasMatchingEsrSystemInfoType(final EsrVnfm vnfm, final String type) {
+ logger.debug("Checking VNFM ID: " + vnfm + ": " + vnfm.getVnfmId());
+
+ final EsrSystemInfoList systemInfolist = vnfm.getEsrSystemInfoList();
+ if (systemInfolist != null) {
+ for (final EsrSystemInfo esrSystemInfo : systemInfolist.getEsrSystemInfo()) {
+ if (esrSystemInfo.getType().equals(type)) {
+ logger.debug("Matched VNFM ID: " + vnfm + ", based on type");
+ return true;
+ }
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Create a vserver.
+ *
+ * @param vnfc the VNFC to base the vserver on
+ * @return the vserver
+ */
+ public Vserver createVserver(final LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs vnfc) {
+ final Vserver vserver = new Vserver();
+ vserver.setVserverId(vnfc.getComputeResource().getResourceId());
+ vserver.setVserverName(vnfc.getId());
+ vserver.setProvStatus("active");
+ vserver.setVserverSelflink("Not available");
+ return vserver;
+ }
+
+ public void setOamIpAddressSource(final String vnfId, final OamIpAddressSource oamIpAddressSource) {
+ mapOfVnfIdToOamIpAddressHolder.put(vnfId, oamIpAddressSource);
+ }
+
+ public OamIpAddressSource getOamIpAddressSource(final String vnfId) {
+ return mapOfVnfIdToOamIpAddressHolder.get(vnfId);
+ }
+
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiPropertiesImpl.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiPropertiesImpl.java
new file mode 100644
index 0000000000..cfaad3fd04
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiPropertiesImpl.java
@@ -0,0 +1,68 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.extclients.aai;
+
+import org.onap.so.client.aai.AAIProperties;
+import org.onap.so.client.aai.AAIVersion;
+import org.onap.so.spring.SpringContextHelper;
+import org.springframework.context.ApplicationContext;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+public class AaiPropertiesImpl implements AAIProperties {
+
+ private final String endpoint;
+ private final String encryptedBasicAuth;
+ private final String encrytptionKey;
+
+ public AaiPropertiesImpl() {
+
+ final ApplicationContext context = SpringContextHelper.getAppContext();
+ this.endpoint = context.getEnvironment().getProperty("aai.endpoint");
+ this.encryptedBasicAuth = context.getEnvironment().getProperty("aai.auth");
+ this.encrytptionKey = context.getEnvironment().getProperty("mso.key");
+ }
+
+ @Override
+ public URL getEndpoint() throws MalformedURLException {
+ return new URL(endpoint);
+ }
+
+ @Override
+ public String getSystemName() {
+ return "MSO";
+ }
+
+ @Override
+ public AAIVersion getDefaultVersion() {
+ return AAIVersion.LATEST;
+ }
+
+ @Override
+ public String getAuth() {
+ return encryptedBasicAuth;
+ }
+
+ @Override
+ public String getKey() {
+ return encrytptionKey;
+ }
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiServiceProvider.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiServiceProvider.java
new file mode 100644
index 0000000000..d19190d88e
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiServiceProvider.java
@@ -0,0 +1,148 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.extclients.aai;
+
+import org.onap.aai.domain.yang.EsrSystemInfoList;
+import org.onap.aai.domain.yang.EsrVnfm;
+import org.onap.aai.domain.yang.EsrVnfmList;
+import org.onap.aai.domain.yang.GenericVnf;
+import org.onap.aai.domain.yang.GenericVnfs;
+import org.onap.aai.domain.yang.Vserver;
+import org.onap.vnfmadapter.v1.model.Tenant;
+
+/**
+ * Provides methods for invoking REST calls to AAI.
+ */
+public interface AaiServiceProvider {
+
+ /**
+ * Invoke a get request for a generic VNF.
+ *
+ * @param vnfId the VNF id
+ * @return the generic VNF
+ */
+ GenericVnf invokeGetGenericVnf(final String vnfId);
+
+ /**
+ * Invoke a query for a generic VNF with the given selfLink
+ *
+ * @param selfLink the selfLink
+ * @return the matching generic vnfs
+ */
+ GenericVnfs invokeQueryGenericVnf(final String selfLink);
+
+ /**
+ * Invoke a GET request for the VNFMs.
+ *
+ * @return the VNFMs
+ */
+ EsrVnfmList invokeGetVnfms();
+
+ /**
+ * Invoke a GET request for the esr system info list for a VNFM.
+ *
+ * @return the esr system info list for the VNFM
+ */
+ EsrSystemInfoList invokeGetVnfmEsrSystemInfoList(final String vnfmId);
+
+ /**
+ * Invoke a GET request for the a VNFM.
+ *
+ * @param vnfmId the ID of the VNFM
+ * @return the VNFM
+ */
+ EsrVnfm invokeGetVnfm(final String vnfmId);
+
+ /**
+ * Invoke a PATCH request for a generic vnf.
+ *
+ * @param vnf the generic vnf
+ * @return
+ */
+ void invokePatchGenericVnf(GenericVnf vnf);
+
+ /**
+ * Invoke a PUT request for a relationship from a generic vnf to a VNFM.
+ *
+ * @param vnf the generic vnf
+ * @param vnfmId the ID of the VNFM
+ * @return
+ */
+ void invokePutGenericVnfToVnfmRelationship(GenericVnf vnf, final String vnfmId);
+
+
+ /**
+ * Invoke a PUT request for a vserver.
+ *
+ * @param cloudOwner the cloud owner
+ * @param cloudRegion the cloud region
+ * @param tenantId the ID of the tenant
+ * @param vserver the vserver
+ * @return
+ */
+ void invokePutVserver(final String cloudOwner, final String cloudRegion, final String tenantId,
+ final Vserver vserver);
+
+ /**
+ * Invoke a PUT request for a relationship from a vserver to a generic vnf.
+ *
+ * @param cloudOwner the cloud owner
+ * @param cloudRegion the cloud region the vserver is deployed on
+ * @param tenantId the ID of the tenant the vserver is deployed on
+ * @param vserver the vserver
+ * @param vnfId the ID of the generic vnf
+ * @return
+ */
+ void invokePutVserverToVnfRelationship(final String cloudOwner, final String cloudRegion, final String tenantId,
+ final Vserver vserver, final String vnfId);
+
+ /**
+ * Invoke a DELETE request for a vserver.
+ *
+ * @param cloudOwner the cloud owner
+ * @param cloudRegion the cloud region
+ * @param tenantId the ID of the tenant
+ * @param vserverId the ID of the vserver
+ * @return
+ */
+ void invokeDeleteVserver(final String cloudOwner, final String cloudRegion, final String tenantId,
+ final String vserverId);
+
+ /**
+ * Invoke a GET request for the a tenant.
+ *
+ * @param cloudOwner the cloud owner
+ * @param cloudRegion the cloud region
+ * @param tenantId the ID of the tenant
+ * @return the tenant
+ */
+ Tenant invokeGetTenant(final String cloudOwner, final String cloudRegion, final String tenantId);
+
+ /**
+ * Invoke a GET request for the esr system info list for a cloud region.
+ *
+ * @param cloudOwner the cloud owner
+ * @param cloudRegion the cloud region
+ * @return the esr system info list for the VNFM
+ */
+ EsrSystemInfoList invokeGetCloudRegionEsrSystemInfoList(final String cloudOwner, final String cloudRegion);
+
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiServiceProviderImpl.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiServiceProviderImpl.java
new file mode 100644
index 0000000000..6dc6020834
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiServiceProviderImpl.java
@@ -0,0 +1,158 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.extclients.aai;
+
+import org.onap.aai.domain.yang.EsrSystemInfoList;
+import org.onap.aai.domain.yang.EsrVnfm;
+import org.onap.aai.domain.yang.EsrVnfmList;
+import org.onap.aai.domain.yang.GenericVnf;
+import org.onap.aai.domain.yang.GenericVnfs;
+import org.onap.aai.domain.yang.Vserver;
+import org.onap.so.client.aai.AAIObjectType;
+import org.onap.so.client.aai.entities.uri.AAIUriFactory;
+import org.onap.so.client.graphinventory.entities.uri.Depth;
+import org.onap.vnfmadapter.v1.model.Tenant;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Service
+public class AaiServiceProviderImpl implements AaiServiceProvider {
+
+ private static final Logger logger = LoggerFactory.getLogger(AaiServiceProviderImpl.class);
+ private final AaiClientProvider aaiClientProvider;
+
+ @Autowired
+ public AaiServiceProviderImpl(final AaiClientProvider aaiClientProvider) {
+ this.aaiClientProvider = aaiClientProvider;
+ }
+
+ @Override
+ public GenericVnf invokeGetGenericVnf(final String vnfId) {
+ return aaiClientProvider.getAaiClient()
+ .get(GenericVnf.class, AAIUriFactory.createResourceUri(AAIObjectType.GENERIC_VNF, vnfId))
+ .orElseGet(() -> {
+ logger.debug("No vnf found in AAI with ID: {}", vnfId);
+ return null;
+ });
+ }
+
+ @Override
+ public GenericVnfs invokeQueryGenericVnf(final String selfLink) {
+ return aaiClientProvider.getAaiClient()
+ .get(GenericVnfs.class,
+ AAIUriFactory.createResourceUri(AAIObjectType.GENERIC_VNFS).queryParam("selflink", selfLink))
+ .orElseGet(() -> {
+ logger.debug("No vnf found in AAI with selflink: {}", selfLink);
+ return null;
+ });
+ }
+
+ @Override
+ public EsrVnfmList invokeGetVnfms() {
+ return aaiClientProvider.getAaiClient()
+ .get(EsrVnfmList.class, AAIUriFactory.createResourceUri(AAIObjectType.VNFM_LIST)).orElseGet(() -> {
+ logger.debug("No VNFMs in AAI");
+ return null;
+ });
+ }
+
+ @Override
+ public EsrVnfm invokeGetVnfm(final String vnfmId) {
+ return aaiClientProvider.getAaiClient()
+ .get(EsrVnfm.class, AAIUriFactory.createResourceUri(AAIObjectType.VNFM, vnfmId).depth(Depth.ONE))
+ .orElseGet(() -> {
+ logger.debug("VNFM not found in AAI");
+ return null;
+ });
+ }
+
+ @Override
+ public EsrSystemInfoList invokeGetVnfmEsrSystemInfoList(final String vnfmId) {
+ return aaiClientProvider.getAaiClient()
+ .get(EsrSystemInfoList.class,
+ AAIUriFactory.createResourceUri(AAIObjectType.VNFM_ESR_SYSTEM_INFO_LIST, vnfmId))
+ .orElseGet(() -> {
+ logger.debug("VNFM ESR system info list not found in AAI");
+ return null;
+ });
+ }
+
+ @Override
+ public void invokePatchGenericVnf(final GenericVnf vnf) {
+ aaiClientProvider.getAaiClient()
+ .update(AAIUriFactory.createResourceUri(AAIObjectType.GENERIC_VNF, vnf.getVnfId()), vnf);
+ }
+
+ @Override
+ public void invokePutGenericVnfToVnfmRelationship(final GenericVnf vnf, final String vnfmId) {
+ aaiClientProvider.getAaiClient().connect(AAIUriFactory.createResourceUri(AAIObjectType.VNFM, vnfmId),
+ AAIUriFactory.createResourceUri(AAIObjectType.GENERIC_VNF, vnf.getVnfId()));
+ }
+
+ @Override
+ public void invokePutVserver(final String cloudOwner, final String cloudRegion, final String tenant,
+ final Vserver vserver) {
+ aaiClientProvider.getAaiClient().create(AAIUriFactory.createResourceUri(AAIObjectType.VSERVER, cloudOwner,
+ cloudRegion, tenant, vserver.getVserverId()), vserver);
+ }
+
+ @Override
+ public void invokePutVserverToVnfRelationship(final String cloudOwner, final String cloudRegion,
+ final String tenant, final Vserver vserver, final String vnfId) {
+ aaiClientProvider.getAaiClient()
+ .connect(
+ AAIUriFactory.createResourceUri(AAIObjectType.VSERVER, cloudOwner, cloudRegion, tenant,
+ vserver.getVserverId()),
+ AAIUriFactory.createResourceUri(AAIObjectType.GENERIC_VNF, vnfId));
+ }
+
+ @Override
+ public void invokeDeleteVserver(final String cloudOwner, final String cloudRegion, final String tenant,
+ final String vserverId) {
+ aaiClientProvider.getAaiClient().delete(
+ AAIUriFactory.createResourceUri(AAIObjectType.VSERVER, cloudOwner, cloudRegion, tenant, vserverId));
+ }
+
+ @Override
+ public Tenant invokeGetTenant(final String cloudOwner, final String cloudRegion, final String tenantId) {
+ return aaiClientProvider.getAaiClient()
+ .get(Tenant.class,
+ AAIUriFactory.createResourceUri(AAIObjectType.TENANT, cloudOwner, cloudRegion, tenantId))
+ .orElseGet(() -> {
+ logger.debug("Tenant not found in AAI");
+ return null;
+ });
+ }
+
+ @Override
+ public EsrSystemInfoList invokeGetCloudRegionEsrSystemInfoList(final String cloudOwner, final String cloudRegion) {
+ return aaiClientProvider
+ .getAaiClient().get(EsrSystemInfoList.class, AAIUriFactory
+ .createResourceUri(AAIObjectType.CLOUD_ESR_SYSTEM_INFO_LIST, cloudOwner, cloudRegion))
+ .orElseGet(() -> {
+ logger.debug("Cloud esr system info list not found in AAI");
+ return null;
+ });
+ }
+
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/OamIpAddressSource.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/OamIpAddressSource.java
new file mode 100644
index 0000000000..311c4de8bd
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/OamIpAddressSource.java
@@ -0,0 +1,57 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.extclients.aai;
+
+/**
+ * Represents the source of the value to use as the AAI OAM IP address of a VNF
+ */
+public class OamIpAddressSource {
+
+ private final OamIpAddressType type;
+ private final String value;
+
+ public OamIpAddressSource(final OamIpAddressType type, final String value) {
+ this.type = type;
+ this.value = value;
+ }
+
+ public OamIpAddressType getType() {
+ return type;
+ }
+
+ public String getValue() {
+ return value;
+ }
+
+ public enum OamIpAddressType {
+ /**
+ * The value passed in {@link OamIpAddress#OamIpAddress(OamIpAddressType, String)} is to be used directly as the
+ * OAM IP address
+ */
+ LITERAL,
+ /**
+ * The OAM IP address is to be retrieved from the vnfConfigurableProperties returned from the VNFM using the
+ * value passed in {@link OamIpAddress#OamIpAddress(OamIpAddressType, String)} as the name of a property
+ */
+ CONFIGURABLE_PROPERTY
+ }
+
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vim/model/AccessInfo.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vim/model/AccessInfo.java
new file mode 100644
index 0000000000..9ab7618ee3
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vim/model/AccessInfo.java
@@ -0,0 +1,107 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.extclients.vim.model;
+
+import java.util.Objects;
+
+public class AccessInfo {
+
+ protected String projectId;
+ protected String projectName;
+ protected String domainName;
+ protected VimCredentials credentials;
+
+ public String getProjectId() {
+ return projectId;
+ }
+
+ public void setProjectId(final String value) {
+ projectId = value;
+ }
+
+ public String getProjectName() {
+ return projectName;
+ }
+
+ public void setProjectName(final String value) {
+ projectName = value;
+ }
+
+ public String getDomainName() {
+ return domainName;
+ }
+
+ public void setDomainName(final String value) {
+ domainName = value;
+ }
+
+ public VimCredentials getCredentials() {
+ return credentials;
+ }
+
+ public void setCredentials(final VimCredentials value) {
+ credentials = value;
+ }
+
+ @Override
+ public boolean equals(final java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final AccessInfo accessInfo = (AccessInfo) o;
+ return Objects.equals(this.projectId, accessInfo.projectId)
+ && Objects.equals(this.projectName, accessInfo.projectName)
+ && Objects.equals(this.domainName, accessInfo.domainName)
+ && Objects.equals(this.credentials, accessInfo.credentials);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(projectId, projectName, domainName, credentials);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("class AccessInfo {\n");
+
+ sb.append(" projectId: ").append(toIndentedString(projectId)).append("\n");
+ sb.append(" projectName: ").append(toIndentedString(projectName)).append("\n");
+ sb.append(" domainName: ").append(toIndentedString(domainName)).append("\n");
+ sb.append(" credentials: ").append(toIndentedString(credentials)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces (except the first line).
+ */
+ private String toIndentedString(final java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vim/model/InterfaceInfo.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vim/model/InterfaceInfo.java
new file mode 100644
index 0000000000..ae28ea589c
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vim/model/InterfaceInfo.java
@@ -0,0 +1,74 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.extclients.vim.model;
+
+import java.util.Objects;
+
+public class InterfaceInfo {
+
+ protected String identityEndPoint;
+
+ public String getIdentityEndPoint() {
+ return identityEndPoint;
+ }
+
+ public void setIdentityEndPoint(final String value) {
+ identityEndPoint = value;
+ }
+
+ @Override
+ public boolean equals(final java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final InterfaceInfo interfaceInfo = (InterfaceInfo) o;
+ return Objects.equals(this.identityEndPoint, interfaceInfo.identityEndPoint);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(identityEndPoint);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("class InterfaceInfo {\n");
+
+ sb.append(" identityEndPoint: ").append(toIndentedString(identityEndPoint)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces (except the first line).
+ */
+ private String toIndentedString(final java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vim/model/VimCredentials.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vim/model/VimCredentials.java
new file mode 100644
index 0000000000..63b00b4ef2
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vim/model/VimCredentials.java
@@ -0,0 +1,85 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.extclients.vim.model;
+
+import java.util.Objects;
+
+public class VimCredentials {
+
+ protected String username;
+
+ protected String password;
+
+ public String getUsername() {
+ return username;
+ }
+
+ public void setUsername(final String value) {
+ username = value;
+ }
+
+ public String getPassword() {
+ return password;
+ }
+
+ public void setPassword(final String password) {
+ this.password = password;
+ }
+
+ @Override
+ public boolean equals(final java.lang.Object o) {
+ if (this == o) {
+ return true;
+ }
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+ final VimCredentials vimCredentials = (VimCredentials) o;
+ return Objects.equals(this.username, vimCredentials.username)
+ && Objects.equals(this.password, vimCredentials.password);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(username, password);
+ }
+
+ @Override
+ public String toString() {
+ final StringBuilder sb = new StringBuilder();
+ sb.append("class AccessInfo {\n");
+
+ sb.append(" username: ").append(toIndentedString(username)).append("\n");
+ sb.append(" password: ").append(toIndentedString(password)).append("\n");
+ sb.append("}");
+ return sb.toString();
+ }
+
+ /**
+ * Convert the given object to string with each line indented by 4 spaces (except the first line).
+ */
+ private String toIndentedString(final java.lang.Object o) {
+ if (o == null) {
+ return "null";
+ }
+ return o.toString().replace("\n", "\n ");
+ }
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmHelper.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmHelper.java
new file mode 100644
index 0000000000..e9f8f2f5e4
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmHelper.java
@@ -0,0 +1,228 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.extclients.vnfm;
+
+import java.security.GeneralSecurityException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import org.apache.commons.lang3.tuple.ImmutablePair;
+import org.onap.aai.domain.yang.EsrSystemInfo;
+import org.onap.so.adapters.vnfmadapter.common.VnfmAdapterUrlProvider;
+import org.onap.so.adapters.vnfmadapter.extclients.aai.AaiServiceProvider;
+import org.onap.so.adapters.vnfmadapter.extclients.vim.model.AccessInfo;
+import org.onap.so.adapters.vnfmadapter.extclients.vim.model.InterfaceInfo;
+import org.onap.so.adapters.vnfmadapter.extclients.vim.model.VimCredentials;
+import org.onap.so.adapters.vnfmadapter.grant.model.InlineResponse201VimConnections;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InstantiateVnfRequest;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.LccnSubscriptionRequest;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.SubscriptionsAuthentication;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.SubscriptionsAuthentication.AuthTypeEnum;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.SubscriptionsAuthenticationParamsBasic;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.SubscriptionsAuthenticationParamsOauth2ClientCredentials;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.SubscriptionsFilter;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.SubscriptionsFilter.NotificationTypesEnum;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.SubscriptionsFilterVnfInstanceSubscriptionFilter;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.VnfInstancesvnfInstanceIdinstantiateExtVirtualLinks;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.VnfInstancesvnfInstanceIdinstantiateVimConnectionInfo;
+import org.onap.vnfmadapter.v1.model.CreateVnfRequest;
+import org.onap.vnfmadapter.v1.model.ExternalVirtualLink;
+import org.onap.vnfmadapter.v1.model.Tenant;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.google.common.reflect.TypeToken;
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+
+/**
+ * Provides helper methods for interactions with VNFM.
+ */
+@Service
+public class VnfmHelper {
+
+ private static final Logger logger = LoggerFactory.getLogger(VnfmHelper.class);
+ private static final String SEPARATOR = "_";
+ private final AaiServiceProvider aaiServiceProvider;
+ private final VnfmAdapterUrlProvider vnfmAdapterUrlProvider;
+
+ @Autowired
+ public VnfmHelper(final AaiServiceProvider aaiServiceProvider,
+ final VnfmAdapterUrlProvider vnfmAdapterUrlProvider) {
+ this.aaiServiceProvider = aaiServiceProvider;
+ this.vnfmAdapterUrlProvider = vnfmAdapterUrlProvider;
+ }
+
+ /**
+ * Create an {@link InstantiateVnfRequest} to send in an instantiation request to a VNFM.
+ *
+ * @param tenant the tenant the request is to be fulfilled on
+ * @param createVnfRequest the request received by the VNFM adapter
+ */
+ public InstantiateVnfRequest createInstantiateRequest(final Tenant tenant, final CreateVnfRequest createVnfRequest,
+ final String flavourId) {
+ final InstantiateVnfRequest instantiateVnfRequest = new InstantiateVnfRequest();
+ instantiateVnfRequest.setFlavourId(flavourId);
+ instantiateVnfRequest.setVimConnectionInfo(getVimConnectionInfos(tenant));
+ instantiateVnfRequest
+ .setAdditionalParams(getAdditionalParametersAsJsonObject(createVnfRequest.getAdditionalParams()));
+ instantiateVnfRequest.setExtVirtualLinks(getExternalVirtualLinks(createVnfRequest.getExternalVirtualLinks()));
+ createVnfRequest.getExternalVirtualLinks();
+ return instantiateVnfRequest;
+ }
+
+ private List<VnfInstancesvnfInstanceIdinstantiateVimConnectionInfo> getVimConnectionInfos(final Tenant tenant) {
+ final List<VnfInstancesvnfInstanceIdinstantiateVimConnectionInfo> connectionInfos = new ArrayList<>();
+ connectionInfos.add(getVimConnectionInfo(tenant));
+ return connectionInfos;
+ }
+
+ private VnfInstancesvnfInstanceIdinstantiateVimConnectionInfo getVimConnectionInfo(final Tenant tenant) {
+ final EsrSystemInfo esrSystemInfo =
+ aaiServiceProvider.invokeGetCloudRegionEsrSystemInfoList(tenant.getCloudOwner(), tenant.getRegionName())
+ .getEsrSystemInfo().iterator().next();
+
+ final VnfInstancesvnfInstanceIdinstantiateVimConnectionInfo vnfInstancesVimConnectionInfo =
+ new VnfInstancesvnfInstanceIdinstantiateVimConnectionInfo();
+ final String vimId = createVimId(tenant.getCloudOwner(), tenant.getRegionName());
+ vnfInstancesVimConnectionInfo.setId(vimId);
+ vnfInstancesVimConnectionInfo.setVimId(vimId);
+ vnfInstancesVimConnectionInfo.setVimType(esrSystemInfo.getType());
+ vnfInstancesVimConnectionInfo.setInterfaceInfo(getInterfaceInfo(esrSystemInfo.getServiceUrl()));
+ vnfInstancesVimConnectionInfo.setAccessInfo(getAccessInfo(esrSystemInfo, tenant.getTenantId()));
+ return vnfInstancesVimConnectionInfo;
+ }
+
+ private InterfaceInfo getInterfaceInfo(final String url) {
+ final InterfaceInfo interfaceInfo = new InterfaceInfo();
+ interfaceInfo.setIdentityEndPoint(url);
+ return interfaceInfo;
+ }
+
+ private AccessInfo getAccessInfo(final EsrSystemInfo esrSystemInfo, final String tenantId) {
+ final AccessInfo accessInfo = new AccessInfo();
+ accessInfo.setProjectId(tenantId);
+ accessInfo.setDomainName(esrSystemInfo.getCloudDomain());
+
+ final VimCredentials vimCredentials = new VimCredentials();
+ vimCredentials.setUsername(esrSystemInfo.getUserName());
+ vimCredentials.setPassword(esrSystemInfo.getPassword());
+ accessInfo.setCredentials(vimCredentials);
+ return accessInfo;
+ }
+
+ private String createVimId(final String cloudOwner, final String cloudRegion) {
+ return cloudOwner + SEPARATOR + cloudRegion;
+ }
+
+ private JsonObject getAdditionalParametersAsJsonObject(final Map<String, String> additionalParameters) {
+ final JsonObject additionalParametersJsonObject = new JsonObject();
+ if (additionalParameters != null) {
+ for (final Map.Entry<String, JsonElement> item : new Gson().toJsonTree(additionalParameters)
+ .getAsJsonObject().entrySet()) {
+ additionalParametersJsonObject.add(item.getKey(), item.getValue());
+ }
+ } else {
+ logger.warn("No additional parameters were specified for the operation");
+ }
+ return additionalParametersJsonObject;
+ }
+
+ private List<VnfInstancesvnfInstanceIdinstantiateExtVirtualLinks> getExternalVirtualLinks(
+ final List<ExternalVirtualLink> extVirtualLinks) {
+ if (extVirtualLinks != null) {
+ final String extVirtualLinksJsonObject =
+ new Gson().toJson(extVirtualLinks, new TypeToken<List<ExternalVirtualLink>>() {}.getType());
+ return new Gson().fromJson(extVirtualLinksJsonObject,
+ new TypeToken<List<VnfInstancesvnfInstanceIdinstantiateExtVirtualLinks>>() {}.getType());
+ }
+ return null;
+ }
+
+ /**
+ * Create a {@link LccnSubscriptionRequest} to send in an notification subscription request to a VNFM.
+ *
+ * @param the ID of the VNF notifications are required for
+ * @return the request
+ * @throws GeneralSecurityException
+ */
+ public LccnSubscriptionRequest createNotificationSubscriptionRequest(final String vnfId)
+ throws GeneralSecurityException {
+ final LccnSubscriptionRequest lccnSubscriptionRequest = new LccnSubscriptionRequest();
+ lccnSubscriptionRequest.setAuthentication(getSubscriptionsAuthentication());
+ lccnSubscriptionRequest.setCallbackUri(vnfmAdapterUrlProvider.getVnfLcmOperationOccurrenceNotificationUrl());
+ final SubscriptionsFilter filter = new SubscriptionsFilter();
+ filter.addNotificationTypesItem(NotificationTypesEnum.VNFLCMOPERATIONOCCURRENCENOTIFICATION);
+ final SubscriptionsFilterVnfInstanceSubscriptionFilter vnfInstanceSubscriptionFilter =
+ new SubscriptionsFilterVnfInstanceSubscriptionFilter();
+ vnfInstanceSubscriptionFilter.addVnfInstanceIdsItem(vnfId);
+ filter.setVnfInstanceSubscriptionFilter(vnfInstanceSubscriptionFilter);
+ lccnSubscriptionRequest.setFilter(filter);
+ return lccnSubscriptionRequest;
+ }
+
+ private SubscriptionsAuthentication getSubscriptionsAuthentication() throws GeneralSecurityException {
+ final SubscriptionsAuthentication authentication = new SubscriptionsAuthentication();
+
+ final ImmutablePair<String, String> decrypedAuth = vnfmAdapterUrlProvider.getDecryptAuth();
+
+ final SubscriptionsAuthenticationParamsOauth2ClientCredentials oauthParams =
+ new SubscriptionsAuthenticationParamsOauth2ClientCredentials();
+ oauthParams.setTokenEndpoint(vnfmAdapterUrlProvider.getOauthTokenUrl());
+ oauthParams.clientId(decrypedAuth.getLeft());
+ oauthParams.setClientPassword(decrypedAuth.getRight());
+ authentication.addAuthTypeItem(AuthTypeEnum.OAUTH2_CLIENT_CREDENTIALS);
+ authentication.paramsOauth2ClientCredentials(oauthParams);
+
+ final SubscriptionsAuthenticationParamsBasic basicAuthParams = new SubscriptionsAuthenticationParamsBasic();
+ basicAuthParams.setUserName(decrypedAuth.getLeft());
+ basicAuthParams.setPassword(decrypedAuth.getRight());
+ authentication.addAuthTypeItem(AuthTypeEnum.BASIC);
+ authentication.paramsBasic(basicAuthParams);
+
+ authentication.addAuthTypeItem(AuthTypeEnum.TLS_CERT);
+ return authentication;
+ }
+
+ /**
+ * Get the VIM connections for a tenant
+ *
+ * @param tenant the tenant
+ * @return the VIM connections
+ */
+ public InlineResponse201VimConnections getVimConnections(final Tenant tenant) {
+ final EsrSystemInfo esrSystemInfo =
+ aaiServiceProvider.invokeGetCloudRegionEsrSystemInfoList(tenant.getCloudOwner(), tenant.getRegionName())
+ .getEsrSystemInfo().iterator().next();
+
+ final InlineResponse201VimConnections vimConnection = new InlineResponse201VimConnections();
+ vimConnection.setId(createVimId(tenant.getCloudOwner(), tenant.getRegionName()));
+ vimConnection.setVimId(vimConnection.getId());
+ vimConnection.setVimType(esrSystemInfo.getType());
+ vimConnection.setInterfaceInfo(getInterfaceInfo(esrSystemInfo.getServiceUrl()));
+ vimConnection.setAccessInfo(getAccessInfo(esrSystemInfo, tenant.getTenantId()));
+ return vimConnection;
+ }
+
+
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProvider.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProvider.java
new file mode 100644
index 0000000000..cb8c7c4e56
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProvider.java
@@ -0,0 +1,104 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.extclients.vnfm;
+
+import com.google.common.base.Optional;
+import org.onap.aai.domain.yang.EsrVnfm;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.CreateVnfRequest;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse200;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse2001;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse201;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InstantiateVnfRequest;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.LccnSubscriptionRequest;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.TerminateVnfRequest;
+
+/**
+ * Provides methods for invoking REST calls to a VNFM.
+ */
+public interface VnfmServiceProvider {
+
+ /**
+ * Invoke a get request for a VNF.
+ *
+ * @param vnfm the VNFM in AAI
+ * @param vnfSelfLink the link to the VNF in the VNFM
+ * @return the VNF from the VNFM
+ */
+ Optional<InlineResponse201> getVnf(final EsrVnfm vnfm, final String vnfSelfLink);
+
+ /**
+ * Invoke an instantiate request for a VNF.
+ *
+ * @param vnfm the VNFM in AAI
+ * @param vnfSelfLink the link to he VNF on the VNFM
+ * @param instantiateVnfRequest the instantiate request
+ * @return the operation ID of the instantiation operation
+ */
+ String instantiateVnf(final EsrVnfm vnfm, final String vnfSelfLink,
+ final InstantiateVnfRequest instantiateVnfRequest);
+
+ /**
+ * Invoke a notification subscription request to a VNFM.
+ *
+ * @param vnfm the VNFM in AAI
+ * @param subscriptionRequest
+ * @return the response to the subscription request
+ */
+ InlineResponse2001 subscribeForNotifications(final EsrVnfm vnfm, final LccnSubscriptionRequest subscriptionRequest);
+
+ /**
+ * Invoke a terminate request for a VNF.
+ *
+ * @param vnfm the VNFM in AAI
+ * @param vnfSelfLink the link to he VNF on the VNFM
+ * @param terminateVnfRequest the terminate request
+ * @return the operation ID of the termination operation
+ */
+ String terminateVnf(final EsrVnfm vnfm, final String vnfSelfLink, final TerminateVnfRequest terminateVnfRequest);
+
+ /**
+ * Invoke a delete request for a VNF.
+ *
+ * @param vnfm the VNFM in AAI
+ * @param vnfSelfLink the link to he VNF on the VNFM
+ * @return the operation ID of the instantiation operation
+ */
+ void deleteVnf(final EsrVnfm vnfm, final String vnfSelfLink);
+
+ /**
+ * Invoke a get request for a VNFM operation.
+ *
+ * @param vnfm the VNFM in AAI
+ * @param operationId the id of the operation on the VNFM
+ * @return the operation from the VNFM
+ */
+ Optional<InlineResponse200> getOperation(final EsrVnfm vnfm, final String operationId);
+
+ /**
+ * Invoke a create request to a VNFM
+ *
+ * @param vnfm the VNFM in AAI
+ * @param createVnfRequest the parameters for creating a VNF
+ * @return the newly created VNF
+ */
+ Optional<InlineResponse201> createVnf(final EsrVnfm vnfm, final CreateVnfRequest createVnfRequest);
+
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProviderConfiguration.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProviderConfiguration.java
new file mode 100644
index 0000000000..eaaa8d8544
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProviderConfiguration.java
@@ -0,0 +1,154 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.extclients.vnfm;
+
+import static org.onap.so.client.RestTemplateConfig.CONFIGURABLE_REST_TEMPLATE;
+import java.io.IOException;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+import java.security.cert.CertificateException;
+import java.util.Map;
+import java.util.UUID;
+import java.util.concurrent.ConcurrentHashMap;
+import javax.net.ssl.SSLContext;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.client.HttpClient;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.impl.client.HttpClients;
+import org.apache.http.ssl.SSLContextBuilder;
+import org.onap.aai.domain.yang.EsrSystemInfo;
+import org.onap.aai.domain.yang.EsrVnfm;
+import org.onap.so.adapters.vnfmadapter.extclients.AbstractServiceProviderConfiguration;
+import org.onap.so.configuration.rest.BasicHttpHeadersProvider;
+import org.onap.so.rest.service.HttpRestServiceProvider;
+import org.onap.so.rest.service.HttpRestServiceProviderImpl;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.Resource;
+import org.springframework.http.client.BufferingClientHttpRequestFactory;
+import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
+import org.springframework.security.oauth2.client.OAuth2RestTemplate;
+import org.springframework.security.oauth2.client.token.grant.client.ClientCredentialsResourceDetails;
+import org.springframework.web.client.RestTemplate;
+
+/**
+ * Configures the HttpRestServiceProvider for REST call to a VNFM.
+ */
+@Configuration
+public class VnfmServiceProviderConfiguration extends AbstractServiceProviderConfiguration {
+
+ private static final Logger logger = LoggerFactory.getLogger(VnfmServiceProviderConfiguration.class);
+ private Map<String, HttpRestServiceProvider> mapOfVnfmIdToHttpRestServiceProvider = new ConcurrentHashMap<>();
+
+ @Value("${http.client.ssl.trust-store:#{null}}")
+ private Resource trustStore;
+ @Value("${http.client.ssl.trust-store-password:#{null}}")
+ private String trustStorePassword;
+
+ @Value("${server.ssl.key-store:#{null}}")
+ private Resource keyStoreResource;
+ @Value("${server.ssl.key--store-password:#{null}}")
+ private String keyStorePassword;
+
+ /**
+ * This property is only intended to be temporary until the AAI schema is updated to support setting the endpoint
+ */
+ @Value("${vnfmadapter.temp.vnfm.oauth.endpoint:#{null}}")
+ private String oauthEndpoint;
+
+ @Qualifier(CONFIGURABLE_REST_TEMPLATE)
+ @Autowired()
+ private RestTemplate defaultRestTemplate;
+
+ public HttpRestServiceProvider getHttpRestServiceProvider(final EsrVnfm vnfm) {
+ if (!mapOfVnfmIdToHttpRestServiceProvider.containsKey(vnfm.getVnfmId())) {
+ mapOfVnfmIdToHttpRestServiceProvider.put(vnfm.getVnfmId(), createHttpRestServiceProvider(vnfm));
+ }
+ return mapOfVnfmIdToHttpRestServiceProvider.get(vnfm.getVnfmId());
+ }
+
+ private HttpRestServiceProvider createHttpRestServiceProvider(final EsrVnfm vnfm) {
+ final RestTemplate restTemplate = createRestTemplate(vnfm);
+ setGsonMessageConverter(restTemplate);
+ if (trustStore != null) {
+ setTrustStore(restTemplate);
+ }
+ return new HttpRestServiceProviderImpl(restTemplate, new BasicHttpHeadersProvider().getHttpHeaders());
+ }
+
+ private RestTemplate createRestTemplate(final EsrVnfm vnfm) {
+ if (vnfm != null) {
+ for (final EsrSystemInfo esrSystemInfo : vnfm.getEsrSystemInfoList().getEsrSystemInfo()) {
+ if (!StringUtils.isEmpty(esrSystemInfo.getUserName())
+ && !StringUtils.isEmpty(esrSystemInfo.getPassword())) {
+ return createOAuth2RestTemplate(esrSystemInfo);
+ }
+ }
+ }
+ return defaultRestTemplate;
+ }
+
+ private OAuth2RestTemplate createOAuth2RestTemplate(final EsrSystemInfo esrSystemInfo) {
+ logger.debug("Getting OAuth2RestTemplate ...");
+ final ClientCredentialsResourceDetails resourceDetails = new ClientCredentialsResourceDetails();
+ resourceDetails.setId(UUID.randomUUID().toString());
+ resourceDetails.setClientId(esrSystemInfo.getUserName());
+ resourceDetails.setClientSecret(esrSystemInfo.getPassword());
+ resourceDetails.setAccessTokenUri(
+ oauthEndpoint == null ? esrSystemInfo.getServiceUrl().replace("vnflcm/v1", "oauth/token")
+ : oauthEndpoint);
+ resourceDetails.setGrantType("client_credentials");
+ return new OAuth2RestTemplate(resourceDetails);
+ }
+
+ private void setTrustStore(final RestTemplate restTemplate) {
+ SSLContext sslContext;
+ try {
+ if (keyStoreResource != null) {
+ KeyStore keystore = KeyStore.getInstance("pkcs12");
+ keystore.load(keyStoreResource.getInputStream(), keyStorePassword.toCharArray());
+ sslContext =
+ new SSLContextBuilder().loadTrustMaterial(trustStore.getURL(), trustStorePassword.toCharArray())
+ .loadKeyMaterial(keystore, keyStorePassword.toCharArray()).build();
+ } else {
+ sslContext = new SSLContextBuilder()
+ .loadTrustMaterial(trustStore.getURL(), trustStorePassword.toCharArray()).build();
+ }
+ logger.info("Setting truststore: {}", trustStore.getURL());
+ final SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext);
+ final HttpClient httpClient = HttpClients.custom().setSSLSocketFactory(socketFactory).build();
+ final HttpComponentsClientHttpRequestFactory factory =
+ new HttpComponentsClientHttpRequestFactory(httpClient);
+ restTemplate.setRequestFactory(new BufferingClientHttpRequestFactory(factory));
+ } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException | CertificateException
+ | IOException | UnrecoverableKeyException exception) {
+ logger.error("Error reading truststore, TLS connection to VNFM will fail.", exception);
+ }
+ }
+
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProviderImpl.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProviderImpl.java
new file mode 100644
index 0000000000..d898de3ad0
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProviderImpl.java
@@ -0,0 +1,194 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.extclients.vnfm;
+
+import com.google.common.base.Optional;
+import org.onap.aai.domain.yang.EsrVnfm;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.CreateVnfRequest;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse200;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse2001;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse201;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse201.InstantiationStateEnum;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InstantiateVnfRequest;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.LccnSubscriptionRequest;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.TerminateVnfRequest;
+import org.onap.so.adapters.vnfmadapter.jobmanagement.JobManager;
+import org.onap.so.adapters.vnfmadapter.rest.exceptions.VnfmRequestFailureException;
+import org.onap.so.rest.exceptions.RestProcessingException;
+import org.onap.so.rest.service.HttpRestServiceProvider;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Service;
+
+@Service
+public class VnfmServiceProviderImpl implements VnfmServiceProvider {
+ private static final Logger logger = LoggerFactory.getLogger(VnfmServiceProviderImpl.class);
+
+ private final VnfmServiceProviderConfiguration vnfmServiceProviderConfiguration;
+ private final VnfmUrlProvider urlProvider;
+
+ @Autowired
+ public VnfmServiceProviderImpl(final VnfmUrlProvider urlProvider,
+ VnfmServiceProviderConfiguration vnfmServiceProviderConfiguration) {
+ this.vnfmServiceProviderConfiguration = vnfmServiceProviderConfiguration;
+ this.urlProvider = urlProvider;
+ }
+
+ @Override
+ public Optional<InlineResponse201> getVnf(final EsrVnfm vnfm, final String vnfSelfLink) {
+ return getHttpServiceProvider(vnfm).get(vnfSelfLink, InlineResponse201.class);
+ }
+
+ @Override
+ public String instantiateVnf(final EsrVnfm vnfm, final String vnfSelfLink,
+ final InstantiateVnfRequest instantiateVnfRequest) {
+ logger.debug("Sending instantiate request " + instantiateVnfRequest + " to : " + vnfSelfLink);
+
+ ResponseEntity<Void> response = null;
+ try {
+ response = getHttpServiceProvider(vnfm).postHttpRequest(instantiateVnfRequest, vnfSelfLink + "/instantiate",
+ Void.class);
+ } catch (final Exception exception) {
+ final String errorMessage =
+ "Instantiate request to " + vnfSelfLink + " resulted in exception" + instantiateVnfRequest;
+ logger.error(errorMessage, exception);
+ throw new VnfmRequestFailureException(errorMessage, exception);
+ }
+ if (response.getStatusCode() != HttpStatus.ACCEPTED) {
+ final String errorMessage = "Instantiate request to " + vnfSelfLink + " returned status code: "
+ + response.getStatusCode() + ", request: " + instantiateVnfRequest;
+ logger.error(errorMessage);
+ throw new VnfmRequestFailureException(errorMessage);
+ }
+ final String locationHeader = response.getHeaders().get("Location").iterator().next();
+ return locationHeader.substring(locationHeader.lastIndexOf("/") + 1);
+ }
+
+ @Override
+ public InlineResponse2001 subscribeForNotifications(final EsrVnfm vnfm,
+ final LccnSubscriptionRequest subscriptionRequest) {
+ logger.info("Subscribing for notifications {}", subscriptionRequest);
+ final String url = urlProvider.getSubscriptionsUrl(vnfm.getVnfmId());
+ ResponseEntity<InlineResponse2001> response = null;
+ try {
+ response = getHttpServiceProvider(vnfm).postHttpRequest(subscriptionRequest, url, InlineResponse2001.class);
+ logger.info("Subscribing for notifications response {}", response);
+ } catch (final Exception exception) {
+ final String errorMessage =
+ "Subscription to VNFM " + vnfm.getVnfmId() + " resulted in exception" + subscriptionRequest;
+ logger.error(errorMessage, exception);
+ throw new VnfmRequestFailureException(errorMessage, exception);
+ }
+ if (response.getStatusCode() != HttpStatus.CREATED) {
+ final String errorMessage = "Subscription to VNFM " + vnfm.getVnfmId() + " returned status code: "
+ + response.getStatusCode() + ", request: " + subscriptionRequest;
+ logger.error(errorMessage);
+ throw new VnfmRequestFailureException(errorMessage);
+ }
+ return response.getBody();
+ }
+
+ @Override
+ public String terminateVnf(final EsrVnfm vnfm, final String vnfSelfLink,
+ final TerminateVnfRequest terminateVnfRequest) {
+ logger.debug("Sending terminate request " + terminateVnfRequest + " to : " + vnfSelfLink);
+
+ ResponseEntity<Void> response = null;
+ try {
+ response = getHttpServiceProvider(vnfm).postHttpRequest(terminateVnfRequest, vnfSelfLink + "/terminate",
+ Void.class);
+ } catch (final RestProcessingException restProcessingException) {
+ if (restProcessingException.getStatusCode() == HttpStatus.CONFLICT.value()) {
+ InlineResponse201 vnf = getVnf(vnfm, vnfSelfLink).get();
+ if (vnf.getInstantiationState().equals(InstantiationStateEnum.NOT_INSTANTIATED)) {
+ return JobManager.ALREADY_COMPLETED_OPERATION_ID;
+ } else {
+ final String errorMessage =
+ "Terminate request to " + vnfSelfLink + " resulted in exception" + terminateVnfRequest;
+ logger.error(errorMessage, restProcessingException);
+ throw new VnfmRequestFailureException(errorMessage, restProcessingException);
+ }
+ }
+ } catch (final Exception exception) {
+ final String errorMessage =
+ "Terminate request to " + vnfSelfLink + " resulted in exception" + terminateVnfRequest;
+ logger.error(errorMessage, exception);
+ throw new VnfmRequestFailureException(errorMessage, exception);
+ }
+ checkIfResponseIsAcceptable(response, vnfSelfLink, terminateVnfRequest);
+ final String locationHeader = response.getHeaders().get("Location").iterator().next();
+ return locationHeader.substring(locationHeader.lastIndexOf("/") + 1);
+ }
+
+ @Override
+ public void deleteVnf(final EsrVnfm vnfm, final String vnfSelfLink) {
+ logger.debug("Sending delete request to : " + vnfSelfLink);
+ final ResponseEntity<Void> response = getHttpServiceProvider(vnfm).deleteHttpRequest(vnfSelfLink, Void.class);
+ if (response.getStatusCode() != HttpStatus.NO_CONTENT) {
+ throw new VnfmRequestFailureException(
+ "Delete request to " + vnfSelfLink + " return status code: " + response.getStatusCode());
+ }
+ }
+
+ @Override
+ public Optional<InlineResponse200> getOperation(final EsrVnfm vnfm, final String operationId) {
+ final String url = urlProvider.getOperationUrl(vnfm.getVnfmId(), operationId);
+ return getHttpServiceProvider(vnfm).get(url, InlineResponse200.class);
+ }
+
+ @Override
+ public Optional<InlineResponse201> createVnf(final EsrVnfm vnfm, final CreateVnfRequest createVnfRequest) {
+ final String url = urlProvider.getCreationUrl(vnfm.getVnfmId());
+ logger.debug("Sending create request {} to : {}", createVnfRequest, url);
+ try {
+ return getHttpServiceProvider(vnfm).post(createVnfRequest, url, InlineResponse201.class);
+ } catch (final Exception exception) {
+ final String errorMessage =
+ "Create request to vnfm:" + vnfm.getVnfmId() + " resulted in exception" + createVnfRequest;
+ logger.error(errorMessage, exception);
+ throw new VnfmRequestFailureException(errorMessage, exception);
+ }
+ }
+
+ private void checkIfResponseIsAcceptable(ResponseEntity<Void> response, String vnfSelfLink,
+ TerminateVnfRequest terminateVnfRequest) {
+ if (response == null) {
+ final String errorMessage =
+ "Terminate request to " + vnfSelfLink + ", response is null, " + "request: " + terminateVnfRequest;
+ logger.error(errorMessage);
+ throw new VnfmRequestFailureException(errorMessage);
+ }
+ if (response.getStatusCode() != HttpStatus.ACCEPTED) {
+ final String errorMessage = "Terminate request to " + vnfSelfLink + ", returned status code: "
+ + response.getStatusCode() + ", request: " + terminateVnfRequest;
+ logger.error(errorMessage);
+ throw new VnfmRequestFailureException(errorMessage);
+ }
+ }
+
+ private HttpRestServiceProvider getHttpServiceProvider(final EsrVnfm vnfm) {
+ return vnfmServiceProviderConfiguration.getHttpRestServiceProvider(vnfm);
+ }
+
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmUrlProvider.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmUrlProvider.java
new file mode 100644
index 0000000000..9c760b44b1
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmUrlProvider.java
@@ -0,0 +1,95 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.extclients.vnfm;
+
+import static org.slf4j.LoggerFactory.getLogger;
+import java.net.URI;
+import org.onap.aai.domain.yang.EsrSystemInfo;
+import org.onap.aai.domain.yang.EsrSystemInfoList;
+import org.onap.so.adapters.vnfmadapter.extclients.aai.AaiServiceProvider;
+import org.onap.so.adapters.vnfmadapter.rest.exceptions.VnfmNotFoundException;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.web.util.UriComponentsBuilder;
+
+/**
+ * Provides URLs for REST calls to a VNFM.
+ */
+@Service
+public class VnfmUrlProvider {
+
+ private static Logger logger = getLogger(VnfmUrlProvider.class);
+ private final AaiServiceProvider aaiServiceProvider;
+
+ @Autowired
+ public VnfmUrlProvider(final AaiServiceProvider aaiServiceProvider) {
+ this.aaiServiceProvider = aaiServiceProvider;
+ }
+
+ /**
+ * Get the URL for an operation on a VNFM.
+ *
+ * @param vnfmId The ID of the VNFM
+ * @return the URL of the operation
+ */
+ public String getOperationUrl(final String vnfmId, final String operationId) {
+ final String url = UriComponentsBuilder.fromUri(getBaseUri(vnfmId)).pathSegment("vnf_lcm_op_occs")
+ .pathSegment(operationId).build().toString();
+ logger.debug("getOperationUrl:" + url);
+
+ return url;
+ }
+
+ /**
+ * Get the URL for the subscriptions on a VNFM.
+ *
+ * @param vnfmId The ID of the VNFM
+ * @return the URL of the subscriptions
+ */
+ public String getSubscriptionsUrl(final String vnfmId) {
+ final String url =
+ UriComponentsBuilder.fromUri(getBaseUri(vnfmId)).pathSegment("subscriptions").build().toString();
+ logger.debug("getSubscriptionUrl:" + url);
+
+ return url;
+ }
+
+ public String getCreationUrl(final String vnfmId) {
+ final String url =
+ UriComponentsBuilder.fromUri(getBaseUri(vnfmId)).pathSegment("vnf_instances").build().toString();
+ logger.debug("getCreationUrl:" + url);
+
+ return url;
+ }
+
+ private URI getBaseUri(final String vnfmId) {
+ final EsrSystemInfoList vnfmEsrSystemInfoList = aaiServiceProvider.invokeGetVnfmEsrSystemInfoList(vnfmId);
+
+ if (vnfmEsrSystemInfoList != null) {
+ for (final EsrSystemInfo esrSystemInfo : vnfmEsrSystemInfoList.getEsrSystemInfo()) {
+ return UriComponentsBuilder.fromHttpUrl(esrSystemInfo.getServiceUrl()).build().toUri();
+ }
+ }
+
+ throw new VnfmNotFoundException("VNFM, or Service URL for VNFM, not found for VNFM " + vnfmId);
+ }
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/jobmanagement/JobManager.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/jobmanagement/JobManager.java
new file mode 100644
index 0000000000..3de94ebe05
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/jobmanagement/JobManager.java
@@ -0,0 +1,174 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.jobmanagement;
+
+import static org.slf4j.LoggerFactory.getLogger;
+import com.google.common.base.Optional;
+import com.google.common.collect.Maps;
+import java.util.Map;
+import java.util.UUID;
+import org.onap.so.adapters.vnfmadapter.extclients.aai.AaiServiceProvider;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.VnfmServiceProvider;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse200;
+import org.onap.so.adapters.vnfmadapter.rest.exceptions.JobNotFoundException;
+import org.onap.so.rest.exceptions.HttpResouceNotFoundException;
+import org.onap.vnfmadapter.v1.model.OperationEnum;
+import org.onap.vnfmadapter.v1.model.OperationStateEnum;
+import org.onap.vnfmadapter.v1.model.OperationStatusRetrievalStatusEnum;
+import org.onap.vnfmadapter.v1.model.QueryJobResponse;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * Manages jobs enabling the status of jobs to be queried. A job is associated with an operation on a VNFM.
+ */
+@Component
+public class JobManager {
+ public static final String ALREADY_COMPLETED_OPERATION_ID = "alreadyCompleted";
+ private static final String SEPARATOR = "_";
+ private static Logger logger = getLogger(JobManager.class);
+ private final Map<String, VnfmOperation> mapOfJobIdToVnfmOperation = Maps.newConcurrentMap();
+ private final VnfmServiceProvider vnfmServiceProvider;
+ private final AaiServiceProvider aaiServiceProvider;
+
+ @Autowired
+ JobManager(final VnfmServiceProvider vnfmServiceProvider, final AaiServiceProvider aaiServiceProvider) {
+ this.vnfmServiceProvider = vnfmServiceProvider;
+ this.aaiServiceProvider = aaiServiceProvider;
+ }
+
+ /**
+ * Create a job associated with an operation on a VNFM.
+ *
+ * @param vnfmId the VNFM the operation relates to
+ * @param operationId the ID of the associated VNFM operation
+ * @param waitForNotificationForSuccess if set to <code>true</code> the {@link QueryJobResponse#getOperationState()}
+ * shall not return {@link org.onap.vnfmadapter.v1.model.OperationStateEnum#COMPLETED} unless a required
+ * notification has been processed
+ * @return the ID of the job. Can be used to query the job using {@link #getVnfmOperation(String)}
+ */
+ public String createJob(final String vnfmId, final String operationId,
+ final boolean waitForNotificationForSuccess) {
+ final String jobId = vnfmId + SEPARATOR + UUID.randomUUID().toString();
+ final VnfmOperation vnfmOperation = new VnfmOperation(vnfmId, operationId, waitForNotificationForSuccess);
+ mapOfJobIdToVnfmOperation.put(jobId, vnfmOperation);
+ return jobId;
+ }
+
+ /**
+ * Get the operation, associated with the given job ID, from the VNFM.
+ *
+ * @param jobId the job ID
+ * @return the associated operation from the VNFM, or <code>null</code> of no operation is associated with the given
+ * job ID
+ */
+ public QueryJobResponse getVnfmOperation(final String jobId) {
+ final VnfmOperation vnfmOperation = mapOfJobIdToVnfmOperation.get(jobId);
+ final QueryJobResponse response = new QueryJobResponse();
+
+ if (vnfmOperation == null) {
+ throw new JobNotFoundException("No job found with ID: " + jobId);
+ }
+
+ if (vnfmOperation.getOperationId().equals(ALREADY_COMPLETED_OPERATION_ID)) {
+ response.setOperationStatusRetrievalStatus(OperationStatusRetrievalStatusEnum.STATUS_FOUND);
+ return response.operationState(OperationStateEnum.COMPLETED);
+ }
+
+ if (vnfmOperation.isVnfDeleted()) {
+ response.setOperationStatusRetrievalStatus(OperationStatusRetrievalStatusEnum.STATUS_FOUND);
+ return response.operationState(getOperationState(vnfmOperation, null));
+ }
+
+ try {
+ final Optional<InlineResponse200> operationOptional = vnfmServiceProvider.getOperation(
+ aaiServiceProvider.invokeGetVnfm(vnfmOperation.getVnfmId()), vnfmOperation.getOperationId());
+
+ if (!operationOptional.isPresent()) {
+ return response.operationStatusRetrievalStatus(OperationStatusRetrievalStatusEnum.OPERATION_NOT_FOUND);
+ }
+ final InlineResponse200 operation = operationOptional.get();
+
+ logger.debug("Job Id: {} operationId: {} operation details: {} ", jobId, operation.getId(), operation);
+
+ if (operation.getOperationState() == null) {
+ return response.operationStatusRetrievalStatus(OperationStatusRetrievalStatusEnum.WAITING_FOR_STATUS);
+ }
+
+ response.setOperationStatusRetrievalStatus(OperationStatusRetrievalStatusEnum.STATUS_FOUND);
+ response.setId(operation.getId());
+ response.setOperation(OperationEnum.fromValue(operation.getOperation().getValue()));
+ response.setOperationState(getOperationState(vnfmOperation, operation));
+ response.setStartTime(operation.getStartTime());
+ response.setStateEnteredTime(operation.getStateEnteredTime());
+ response.setVnfInstanceId(operation.getVnfInstanceId());
+
+ return response;
+ } catch (final HttpResouceNotFoundException exception) {
+ logger.error("Exception encountered trying to get operation status for operation id "
+ + vnfmOperation.getOperationId(), exception);
+ return response.operationStatusRetrievalStatus(OperationStatusRetrievalStatusEnum.WAITING_FOR_STATUS);
+ }
+ }
+
+ private OperationStateEnum getOperationState(final VnfmOperation vnfmOperation,
+ final InlineResponse200 operationResponse) {
+ switch (vnfmOperation.getNotificationStatus()) {
+ case NOTIFICATION_PROCESSING_PENDING:
+ return org.onap.vnfmadapter.v1.model.OperationStateEnum.PROCESSING;
+ case NOTIFICATION_PROCEESING_SUCCESSFUL:
+ return org.onap.vnfmadapter.v1.model.OperationStateEnum.COMPLETED;
+ case NOTIFICATION_PROCESSING_FAILED:
+ return org.onap.vnfmadapter.v1.model.OperationStateEnum.FAILED;
+ default:
+ if (operationResponse == null || operationResponse.getOperationState() == null)
+ return null;
+ return OperationStateEnum.fromValue(operationResponse.getOperationState().getValue());
+ }
+ }
+
+ public void notificationProcessedForOperation(final String operationId,
+ final boolean notificationProcessingWasSuccessful) {
+ logger.debug("Notification processed for operation ID {} success?: {}", operationId,
+ notificationProcessingWasSuccessful);
+ final java.util.Optional<VnfmOperation> relatedOperation = mapOfJobIdToVnfmOperation.values().stream()
+ .filter(operation -> operation.getOperationId().equals(operationId)).findFirst();
+ if (relatedOperation.isPresent()) {
+ relatedOperation.get().setNotificationProcessed(notificationProcessingWasSuccessful);
+ } else {
+ logger.debug("No operation found for operation ID {} ", operationId);
+
+ }
+ }
+
+ public void vnfDeleted(final String operationId) {
+ logger.debug("VNF deleyed for operation ID {}", operationId);
+ final java.util.Optional<VnfmOperation> relatedOperation = mapOfJobIdToVnfmOperation.values().stream()
+ .filter(operation -> operation.getOperationId().equals(operationId)).findFirst();
+ if (relatedOperation.isPresent()) {
+ relatedOperation.get().setVnfDeleted();
+ } else {
+ logger.debug("No operation found for operation ID {} ", operationId);
+ }
+ }
+
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/jobmanagement/VnfmOperation.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/jobmanagement/VnfmOperation.java
new file mode 100644
index 0000000000..3bfe48af12
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/jobmanagement/VnfmOperation.java
@@ -0,0 +1,122 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.jobmanagement;
+
+/**
+ * Represents an operation on a VNFM.
+ */
+public class VnfmOperation {
+
+ private final String vnfmId;
+ private final String operationId;
+ private NotificationStatus notificationStatus;
+ private boolean vnfDeleted;
+
+ public VnfmOperation(final String vnfmId, final String operationId, final boolean waitForNotificationForSuccess) {
+ this.vnfmId = vnfmId;
+ this.operationId = operationId;
+ this.notificationStatus = waitForNotificationForSuccess ? NotificationStatus.NOTIFICATION_PROCESSING_PENDING
+ : NotificationStatus.NOTIFICATION_PROCESSING_NOT_REQUIRED;
+ }
+
+ /**
+ * Get the ID of the operation on the VNFM.
+ *
+ * @return the ID of the operation on the VNFM
+ */
+ public String getOperationId() {
+ return operationId;
+ }
+
+ /**
+ * Get the ID of the VNFM the operation is carried out by.
+ *
+ * @return the ID of the VNFM
+ */
+ public String getVnfmId() {
+ return vnfmId;
+ }
+
+ /**
+ * Set the required notification has been processed for the operation.
+ *
+ * @param notificationProcessingWasSuccessful <code>true</code> if the notification processing was successful,
+ * <code>false<code> otherwise
+ */
+ public void setNotificationProcessed(final boolean notificationProcessingWasSuccessful) {
+ this.notificationStatus =
+ notificationProcessingWasSuccessful ? NotificationStatus.NOTIFICATION_PROCEESING_SUCCESSFUL
+ : NotificationStatus.NOTIFICATION_PROCESSING_FAILED;
+ }
+
+ /**
+ * Get the notification status for the operation.
+ *
+ * @return the notification status
+ */
+ public NotificationStatus getNotificationStatus() {
+ return notificationStatus;
+ }
+
+ /**
+ * Set the VNF has been deleted from the VNFM.
+ */
+ public void setVnfDeleted() {
+ this.vnfDeleted = true;
+ }
+
+ /**
+ * Check if the VNF has been deleted from the VNFM
+ *
+ * @return <code>true</code> of the VNF has been deleted from the VNFM, <code>false</code> otherwise
+ */
+ public boolean isVnfDeleted() {
+ return vnfDeleted;
+ }
+
+
+ public enum NotificationStatus {
+ /**
+ * No notification handling is required to determine the status of the operation
+ */
+ NOTIFICATION_PROCESSING_NOT_REQUIRED,
+ /**
+ * A notification must be processed before the notification can be considered to be completed
+ */
+ NOTIFICATION_PROCESSING_PENDING,
+ /**
+ * A notification has been successfully handled for the operation
+ */
+ NOTIFICATION_PROCEESING_SUCCESSFUL,
+ /**
+ * An error occurred processing a notification for the operation
+ */
+ NOTIFICATION_PROCESSING_FAILED;
+ }
+
+ @Override
+ public String toString() {
+ return "VnfmOperation [vnfmId=" + vnfmId + ", operationId=" + operationId + ", notificationStatus="
+ + notificationStatus + "]";
+ }
+
+
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/lifecycle/LifecycleManager.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/lifecycle/LifecycleManager.java
new file mode 100644
index 0000000000..a885721b76
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/lifecycle/LifecycleManager.java
@@ -0,0 +1,265 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.lifecycle;
+
+import com.google.common.base.Optional;
+import java.util.Map;
+import org.onap.aai.domain.yang.EsrVnfm;
+import org.onap.aai.domain.yang.GenericVnf;
+import org.onap.aai.domain.yang.Relationship;
+import org.onap.so.adapters.vnfmadapter.extclients.SdcPackageProvider;
+import org.onap.so.adapters.vnfmadapter.extclients.aai.AaiHelper;
+import org.onap.so.adapters.vnfmadapter.extclients.aai.AaiServiceProvider;
+import org.onap.so.adapters.vnfmadapter.extclients.aai.OamIpAddressSource;
+import org.onap.so.adapters.vnfmadapter.extclients.aai.OamIpAddressSource.OamIpAddressType;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.VnfmHelper;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.VnfmServiceProvider;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse201;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InstantiateVnfRequest;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.LccnSubscriptionRequest;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.TerminateVnfRequest;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.TerminateVnfRequest.TerminationTypeEnum;
+import org.onap.so.adapters.vnfmadapter.jobmanagement.JobManager;
+import org.onap.so.adapters.vnfmadapter.rest.exceptions.VnfNotFoundException;
+import org.onap.so.adapters.vnfmadapter.rest.exceptions.VnfmNotFoundException;
+import org.onap.so.adapters.vnfmadapter.rest.exceptions.VnfmRequestFailureException;
+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.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+/**
+ * Manages lifecycle operations towards the VNFMs.
+ */
+@Component
+public class LifecycleManager {
+ private static final Logger logger = LoggerFactory.getLogger(LifecycleManager.class);
+ private final AaiServiceProvider aaiServiceProvider;
+ private final VnfmServiceProvider vnfmServiceProvider;
+ private final AaiHelper aaiHelper;
+ private final VnfmHelper vnfmHelper;
+ private final JobManager jobManager;
+ private final SdcPackageProvider packageProvider;
+
+ @Autowired
+ LifecycleManager(final AaiServiceProvider aaiServiceProvider, final AaiHelper aaiHelper,
+ final VnfmHelper vnfmHelper, final VnfmServiceProvider vnfmServiceProvider, final JobManager jobManager,
+ final SdcPackageProvider packageProvider) {
+ this.aaiServiceProvider = aaiServiceProvider;
+ this.vnfmServiceProvider = vnfmServiceProvider;
+ this.aaiHelper = aaiHelper;
+ this.vnfmHelper = vnfmHelper;
+ this.jobManager = jobManager;
+ this.packageProvider = packageProvider;
+ }
+
+ /**
+ * Create a VNF on a VNFM.
+ *
+ * @param vnfIdInAai the ID of the VNF in AAI
+ * @param request the create request
+ * @return the response to the request
+ */
+ public CreateVnfResponse createVnf(final String vnfIdInAai, final CreateVnfRequest request) {
+ GenericVnf genericVnf = getGenericVnfFromAai(vnfIdInAai);
+ EsrVnfm vnfm = aaiHelper.getAssignedVnfm(genericVnf);
+ checkIfVnfAlreadyExistsInVnfm(vnfm, genericVnf);
+
+ if (vnfm == null) {
+ vnfm = aaiHelper.selectVnfm(genericVnf);
+ aaiServiceProvider.invokePutGenericVnfToVnfmRelationship(genericVnf, vnfm.getVnfmId());
+ }
+ final InlineResponse201 vnfmResponse = sendCreateRequestToVnfm(request, genericVnf, vnfIdInAai, vnfm);
+
+ logger.info("Create response: {}", vnfmResponse);
+
+ genericVnf.setSelflink(getSelfLink(vnfmResponse, vnfm));
+
+ GenericVnf genericVnfPatch = new GenericVnf();
+ genericVnfPatch.setVnfId(genericVnf.getVnfId());
+ genericVnfPatch.setSelflink(genericVnf.getSelflink());
+ aaiServiceProvider.invokePatchGenericVnf(genericVnfPatch);
+
+ final String vnfIdInVnfm = vnfmResponse.getId();
+
+ final OamIpAddressSource oamIpAddressSource = extractOamIpAddressSource(request);
+ aaiHelper.setOamIpAddressSource(vnfIdInVnfm, oamIpAddressSource);
+
+ createNotificationSubscription(vnfm, vnfIdInVnfm);
+ final String operationId = sendInstantiateRequestToVnfm(vnfm, genericVnf, request);
+
+ final String jobId = jobManager.createJob(vnfm.getVnfmId(), operationId, false);
+ final CreateVnfResponse response = new CreateVnfResponse();
+ response.setJobId(jobId);
+ return response;
+ }
+
+ private String getSelfLink(final InlineResponse201 vnfmResponse, final EsrVnfm vnfm) {
+ if (vnfmResponse.getLinks() != null && vnfmResponse.getLinks().getSelf() != null
+ && vnfmResponse.getLinks().getSelf().getHref() != null) {
+ return vnfmResponse.getLinks().getSelf().getHref();
+ }
+ return vnfm.getEsrSystemInfoList().getEsrSystemInfo().iterator().next().getServiceUrl() + "/vnf_instances/"
+ + vnfmResponse.getId();
+ }
+
+ private OamIpAddressSource extractOamIpAddressSource(final CreateVnfRequest request) {
+ final Map<String, String> additionalParams = request.getAdditionalParams();
+ try {
+ final String sourceType = additionalParams.remove("oamIpAddressSourceType");
+ final String sourceValue = additionalParams.remove("oamIpAddressSourceValue");
+ final OamIpAddressType oamIpAddressType = OamIpAddressType.valueOf(sourceType.toUpperCase());
+ return new OamIpAddressSource(oamIpAddressType, sourceValue);
+ } catch (final NullPointerException | IllegalArgumentException exception) {
+ logger.debug("Additional Params not set for OAM IP address source", exception);
+ return null;
+ }
+ }
+
+ private void checkIfVnfAlreadyExistsInVnfm(final EsrVnfm vnfm, final GenericVnf genericVnf) {
+ if (genericVnf.getSelflink() != null && !genericVnf.getSelflink().isEmpty() && vnfm != null) {
+ Optional<InlineResponse201> response = Optional.absent();
+ try {
+ response = vnfmServiceProvider.getVnf(vnfm, genericVnf.getSelflink());
+ } catch (final Exception exception) {
+ logger.debug("Ignoring invalid self link in generic vnf", exception);
+ }
+ if (response.isPresent()) {
+ throw new IllegalArgumentException("VNF " + genericVnf.getVnfId()
+ + " is already defined on the VNFM, self link: " + genericVnf.getSelflink());
+ }
+ }
+ }
+
+ private InlineResponse201 sendCreateRequestToVnfm(final CreateVnfRequest aaiRequest, final GenericVnf genericVnf,
+ final String vnfIdInAai, final EsrVnfm vnfm) {
+ logger.debug("Sending a create request to SVNFM " + aaiRequest);
+ final org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.CreateVnfRequest vnfmRequest =
+ new org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.CreateVnfRequest();
+
+ final String vnfdId = packageProvider.getVnfdId(genericVnf.getModelVersionId());
+ vnfmRequest.setVnfdId(vnfdId);
+ vnfmRequest.setVnfInstanceName(aaiRequest.getName().replaceAll(" ", "_"));
+ vnfmRequest.setVnfInstanceDescription(vnfIdInAai);
+
+ final Optional<InlineResponse201> optionalResponse = vnfmServiceProvider.createVnf(vnfm, vnfmRequest);
+
+ try {
+ return optionalResponse.get();
+ } catch (final Exception exception) {
+ final String errorMessage = "Unable to return response from VNFM";
+ logger.error(errorMessage, exception);
+ throw new VnfmRequestFailureException(errorMessage, exception);
+ }
+ }
+
+ private void createNotificationSubscription(final EsrVnfm vnfm, final String vnfId) {
+ try {
+ final LccnSubscriptionRequest subscriptionRequest = vnfmHelper.createNotificationSubscriptionRequest(vnfId);
+ vnfmServiceProvider.subscribeForNotifications(vnfm, subscriptionRequest);
+ } catch (final Exception exception) {
+ logger.warn("Subscription for notifications to VNFM: " + vnfm.getVnfmId() + " for VNF " + vnfId
+ + " failed. AAI will not be updated unless the VNFM is configured by other means to send notifications relating to this VNF",
+ exception);
+ }
+ }
+
+ private String sendInstantiateRequestToVnfm(final EsrVnfm vnfm, final GenericVnf genericVnf,
+ final CreateVnfRequest createVnfRequest) {
+
+ final InstantiateVnfRequest instantiateVnfRequest =
+ vnfmHelper.createInstantiateRequest(createVnfRequest.getTenant(), createVnfRequest,
+ packageProvider.getFlavourId(genericVnf.getModelVersionId()));
+ final String jobId = vnfmServiceProvider.instantiateVnf(vnfm, genericVnf.getSelflink(), instantiateVnfRequest);
+
+ logger.info("Instantiate VNF request successfully sent to " + genericVnf.getSelflink());
+ return jobId;
+ }
+
+ /**
+ * Delete a VNF on a VNFM.
+ *
+ * @param vnfIdInAai the ID of the VNF in AAI
+ * @return the response to the request
+ */
+ public DeleteVnfResponse deleteVnf(final String vnfIdInAai) {
+ final GenericVnf genericVnf = getGenericVnfFromAai(vnfIdInAai);
+ final EsrVnfm vnfm = getAssignedVnfm(genericVnf);
+
+ final String operationId = sendTerminateRequestToVnfm(vnfm, genericVnf);
+
+ if (operationId.equals(JobManager.ALREADY_COMPLETED_OPERATION_ID)) {
+ sendDeleteRequestToVnfm(genericVnf);
+ }
+ final String jobId = jobManager.createJob(vnfm.getVnfmId(), operationId, true);
+
+ return new DeleteVnfResponse().jobId(jobId);
+ }
+
+ private String sendTerminateRequestToVnfm(final EsrVnfm vnfm, final GenericVnf genericVnf) {
+ final TerminateVnfRequest terminateVnfRequest = new TerminateVnfRequest();
+ terminateVnfRequest.setTerminationType(TerminationTypeEnum.FORCEFUL);
+ return vnfmServiceProvider.terminateVnf(vnfm, genericVnf.getSelflink(), terminateVnfRequest);
+ }
+
+ private GenericVnf getGenericVnfFromAai(final String vnfIdInAai) {
+ final GenericVnf genericVnf = aaiServiceProvider.invokeGetGenericVnf(vnfIdInAai);
+ if (genericVnf == null) {
+ throw new VnfNotFoundException("VNF not found in AAI: " + vnfIdInAai);
+ }
+ logger.debug("Retrieved generic VNF from AAI: " + genericVnf);
+ return genericVnf;
+ }
+
+ private EsrVnfm getAssignedVnfm(final GenericVnf genericVnf) {
+ final EsrVnfm vnfm = aaiHelper.getAssignedVnfm(genericVnf);
+ if (vnfm == null) {
+ throw new VnfmNotFoundException("No VNFM found in AAI for VNF " + genericVnf.getVnfId());
+ }
+ return vnfm;
+ }
+
+ private void sendDeleteRequestToVnfm(final GenericVnf genericVnf) {
+
+ vnfmServiceProvider.deleteVnf(aaiHelper.getAssignedVnfm(genericVnf), genericVnf.getSelflink());
+
+ final GenericVnf genericVnfPatch = new GenericVnf();
+ genericVnfPatch.setVnfId(genericVnf.getVnfId());
+ genericVnfPatch.setOrchestrationStatus("Assigned");
+ genericVnfPatch.setSelflink("");
+ aaiServiceProvider.invokePatchGenericVnf(genericVnfPatch);
+
+ for (final Relationship relationship : genericVnf.getRelationshipList().getRelationship()) {
+ if (relationship.getRelatedTo().equals("vserver")) {
+ aaiServiceProvider.invokeDeleteVserver(
+ aaiHelper.getRelationshipData(relationship, "cloud-region.cloud-owner"),
+ aaiHelper.getRelationshipData(relationship, "cloud-region.cloud-region-id"),
+ aaiHelper.getRelationshipData(relationship, "tenant.tenant-id"),
+ aaiHelper.getRelationshipData(relationship, "vserver.vserver-id"));
+ }
+ }
+
+
+ }
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/notificationhandling/NotificationHandler.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/notificationhandling/NotificationHandler.java
new file mode 100644
index 0000000000..09722d4e32
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/notificationhandling/NotificationHandler.java
@@ -0,0 +1,276 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.notificationhandling;
+
+import static org.slf4j.LoggerFactory.getLogger;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import org.json.JSONException;
+import org.json.JSONObject;
+import org.onap.aai.domain.yang.GenericVnf;
+import org.onap.aai.domain.yang.Relationship;
+import org.onap.aai.domain.yang.Vserver;
+import org.onap.so.adapters.vnfmadapter.extclients.aai.AaiHelper;
+import org.onap.so.adapters.vnfmadapter.extclients.aai.AaiServiceProvider;
+import org.onap.so.adapters.vnfmadapter.extclients.aai.OamIpAddressSource;
+import org.onap.so.adapters.vnfmadapter.extclients.aai.OamIpAddressSource.OamIpAddressType;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.VnfmServiceProvider;
+import org.onap.so.adapters.vnfmadapter.lcn.model.LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs;
+import org.onap.so.adapters.vnfmadapter.lcn.model.LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs.ChangeTypeEnum;
+import org.onap.so.adapters.vnfmadapter.lcn.model.VnfLcmOperationOccurrenceNotification;
+import org.onap.so.adapters.vnfmadapter.lcn.model.VnfLcmOperationOccurrenceNotification.OperationStateEnum;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse201;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse201VimConnectionInfo;
+import org.onap.so.adapters.vnfmadapter.jobmanagement.JobManager;
+import org.slf4j.Logger;
+
+/**
+ * Performs updates to AAI based on a received notification. The updates are executed in a separate thread so as the
+ * notification response to the VNFM is not delayed.
+ */
+public class NotificationHandler implements Runnable {
+ private static Logger logger = getLogger(NotificationHandler.class);
+ private final VnfLcmOperationOccurrenceNotification vnfLcmOperationOccurrenceNotification;
+ private final AaiHelper aaiHelper;
+ private final AaiServiceProvider aaiServiceProvider;
+ private final VnfmServiceProvider vnfmServiceProvider;
+ private final JobManager jobManager;
+ private final InlineResponse201 vnfInstance;
+
+ public NotificationHandler(final VnfLcmOperationOccurrenceNotification vnfLcmOperationOccurrenceNotification,
+ final AaiHelper aaiHelper, final AaiServiceProvider aaiServiceProvider,
+ final VnfmServiceProvider vnfmServiceProvider, final JobManager jobManager,
+ final InlineResponse201 vnfInstance) {
+ this.vnfLcmOperationOccurrenceNotification = vnfLcmOperationOccurrenceNotification;
+ this.aaiHelper = aaiHelper;
+ this.aaiServiceProvider = aaiServiceProvider;
+ this.vnfmServiceProvider = vnfmServiceProvider;
+ this.jobManager = jobManager;
+ this.vnfInstance = vnfInstance;
+ }
+
+ @Override
+ public void run() {
+ try {
+ if (vnfLcmOperationOccurrenceNotification.getOperationState().equals(OperationStateEnum.COMPLETED)) {
+ switch (vnfLcmOperationOccurrenceNotification.getOperation()) {
+ case INSTANTIATE:
+ handleVnfInstantiate();
+ break;
+ case TERMINATE:
+ handleVnfTerminate();
+ break;
+ default:
+ }
+ }
+ } catch (final Exception exception) {
+ logger.error("Error encountered handling notification, AAI may not be updated correctly "
+ + vnfLcmOperationOccurrenceNotification, exception);
+ }
+ }
+
+ private void handleVnfInstantiate() {
+ if (vnfLcmOperationOccurrenceNotification.getOperationState().equals(OperationStateEnum.COMPLETED)) {
+ handleVnfInstantiateCompleted();
+ }
+ }
+
+ private void handleVnfInstantiateCompleted() {
+ final GenericVnf genericVnf = aaiServiceProvider
+ .invokeQueryGenericVnf(vnfInstance.getLinks().getSelf().getHref()).getGenericVnf().get(0);
+
+ final GenericVnf genericVnfPatch = new GenericVnf();
+ genericVnfPatch.setVnfId(genericVnf.getVnfId());
+ setOamIpAddress(genericVnfPatch, vnfInstance);
+ genericVnfPatch.setOrchestrationStatus("Created");
+ aaiServiceProvider.invokePatchGenericVnf(genericVnfPatch);
+
+ addVservers(vnfLcmOperationOccurrenceNotification, genericVnf.getVnfId(), vnfInstance.getVimConnectionInfo());
+
+ logger.debug("Finished handling notification for vnfm: " + vnfInstance.getId());
+ }
+
+ private void setOamIpAddress(final GenericVnf genericVnf, final InlineResponse201 vnfInstance) {
+ final OamIpAddressSource oamIpAddressSource = aaiHelper.getOamIpAddressSource(vnfInstance.getId());
+ if (oamIpAddressSource == null) {
+ logger.warn("No source indicated for OAM IP address, no value will be set in AAI");
+ return;
+ }
+ if (oamIpAddressSource.getType().equals(OamIpAddressType.LITERAL)) {
+ genericVnf.setIpv4OamAddress(oamIpAddressSource.getValue());
+ } else {
+ try {
+ logger.debug("ConfigurableProperties: " + vnfInstance.getVnfConfigurableProperties());
+ if (vnfInstance.getVnfConfigurableProperties() == null) {
+ logger.warn("No ConfigurableProperties, cannot set OAM IP Address");
+ }
+ final JSONObject properties = new JSONObject((Map) vnfInstance.getVnfConfigurableProperties());
+ genericVnf.setIpv4OamAddress(properties.get(oamIpAddressSource.getValue()).toString());
+ } catch (final JSONException jsonException) {
+ logger.error("Error getting vnfIpAddress", jsonException);
+ }
+ }
+ }
+
+ private void handleVnfTerminate() {
+ switch (vnfLcmOperationOccurrenceNotification.getOperationState()) {
+ case COMPLETED:
+ handleVnfTerminateCompleted();
+ break;
+ case FAILED:
+ case ROLLING_BACK:
+ handleVnfTerminateFailed();
+ break;
+ default:
+ }
+ }
+
+ private void handleVnfTerminateFailed() {
+ try {
+ final GenericVnf genericVnf = aaiServiceProvider
+ .invokeQueryGenericVnf(vnfInstance.getLinks().getSelf().getHref()).getGenericVnf().get(0);
+ deleteVserversFromAai(vnfLcmOperationOccurrenceNotification, genericVnf);
+ } finally {
+ jobManager.notificationProcessedForOperation(vnfLcmOperationOccurrenceNotification.getVnfLcmOpOccId(),
+ false);
+ }
+ }
+
+ private void handleVnfTerminateCompleted() {
+ GenericVnf genericVnf = null;
+ boolean vServersDeletedFromAai = false;
+ boolean identifierDeletedFromVnfm = false;
+ boolean genericVnfUpdated = false;
+ try {
+ genericVnf = aaiServiceProvider.invokeQueryGenericVnf(vnfInstance.getLinks().getSelf().getHref())
+ .getGenericVnf().get(0);
+ vServersDeletedFromAai = deleteVserversFromAai(vnfLcmOperationOccurrenceNotification, genericVnf);
+ identifierDeletedFromVnfm = deleteVnfIdentifierOnVnfm(genericVnf);
+ genericVnfUpdated = patchVnfInAai(genericVnf.getVnfId(), "Assigned", identifierDeletedFromVnfm ? "" : null);
+ } finally {
+ jobManager.notificationProcessedForOperation(vnfLcmOperationOccurrenceNotification.getVnfLcmOpOccId(),
+ vServersDeletedFromAai && identifierDeletedFromVnfm && genericVnfUpdated);
+ jobManager.vnfDeleted(vnfLcmOperationOccurrenceNotification.getVnfLcmOpOccId());
+ }
+ }
+
+ private void addVservers(final VnfLcmOperationOccurrenceNotification notification, final String vnfId,
+ final List<InlineResponse201VimConnectionInfo> vnfInstancesVimConnectionInfo) {
+ final Map<String, InlineResponse201VimConnectionInfo> vimConnectionIdToVimConnectionInfo = new HashMap<>();
+ for (final InlineResponse201VimConnectionInfo vimConnectionInfo : vnfInstancesVimConnectionInfo) {
+ vimConnectionIdToVimConnectionInfo.put(vimConnectionInfo.getId(), vimConnectionInfo);
+ }
+
+ for (final LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs vnfc : notification.getAffectedVnfcs()) {
+ final InlineResponse201VimConnectionInfo vimConnectionInfo =
+ getVimConnectionInfo(vimConnectionIdToVimConnectionInfo, vnfc);
+ if (ChangeTypeEnum.ADDED.equals(vnfc.getChangeType())) {
+ final Vserver vserver = aaiHelper.createVserver(vnfc);
+ aaiServiceProvider.invokePutVserver(getCloudOwner(vimConnectionInfo), getCloudRegion(vimConnectionInfo),
+ getTenant(vimConnectionInfo), vserver);
+
+ aaiServiceProvider.invokePutVserverToVnfRelationship(getCloudOwner(vimConnectionInfo),
+ getCloudRegion(vimConnectionInfo), getTenant(vimConnectionInfo), vserver, vnfId);
+ }
+ }
+ }
+
+ private boolean deleteVserversFromAai(final VnfLcmOperationOccurrenceNotification notification,
+ final GenericVnf vnf) {
+ try {
+ for (final LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs vnfc : notification.getAffectedVnfcs()) {
+ if (ChangeTypeEnum.REMOVED.equals(vnfc.getChangeType())) {
+
+ final Relationship relationshipToVserver = aaiHelper.deleteRelationshipWithDataValue(vnf, "vserver",
+ "vserver.vserver-id", vnfc.getComputeResource().getResourceId());
+
+ aaiServiceProvider.invokeDeleteVserver(
+ aaiHelper.getRelationshipData(relationshipToVserver, "cloud-region.cloud-owner"),
+ aaiHelper.getRelationshipData(relationshipToVserver, "cloud-region.cloud-region-id"),
+ aaiHelper.getRelationshipData(relationshipToVserver, "tenant.tenant-id"),
+ vnfc.getComputeResource().getResourceId());
+ }
+ }
+ return true;
+ } catch (final Exception exception) {
+ logger.error(
+ "Error encountered deleting vservers based on received notification, AAI may not be updated correctly "
+ + vnfLcmOperationOccurrenceNotification,
+ exception);
+ return false;
+ }
+ }
+
+ private boolean deleteVnfIdentifierOnVnfm(GenericVnf genericVnf) {
+ try {
+ vnfmServiceProvider.deleteVnf(aaiHelper.getAssignedVnfm(genericVnf), genericVnf.getSelflink());
+ return true;
+ } catch (Exception exception) {
+ logger.error("Exception deleting the identifier " + genericVnf.getSelflink()
+ + " from the VNFM. The VNF has been terminated successfully but the identifier will remain on the VNFM.",
+ exception);
+ return false;
+ }
+ }
+
+ private boolean patchVnfInAai(final String vnfId, final String orchestrationStatus, final String selfLink) {
+ try {
+ final GenericVnf genericVnfPatch = new GenericVnf();
+ genericVnfPatch.setVnfId(vnfId);
+ genericVnfPatch.setOrchestrationStatus(orchestrationStatus);
+ if (selfLink != null) {
+ genericVnfPatch.setSelflink(selfLink);
+ }
+ aaiServiceProvider.invokePatchGenericVnf(genericVnfPatch);
+ return true;
+ } catch (final Exception exception) {
+ logger.error(
+ "Error encountered setting orchestration status and/or self link based on received notification, AAI may not be updated correctly "
+ + vnfLcmOperationOccurrenceNotification,
+ exception);
+ return false;
+ }
+ }
+
+ private InlineResponse201VimConnectionInfo getVimConnectionInfo(
+ final Map<String, InlineResponse201VimConnectionInfo> vimConnectionIdToVimConnectionInfo,
+ final LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs vnfc) {
+ final String vimConnectionId = vnfc.getComputeResource().getVimConnectionId();
+ return vimConnectionIdToVimConnectionInfo.get(vimConnectionId);
+ }
+
+ private String getCloudOwner(final InlineResponse201VimConnectionInfo vimConnectionInfo) {
+ final String vimId = vimConnectionInfo.getVimId();
+ return vimId.substring(0, vimId.indexOf("_"));
+ }
+
+ private String getCloudRegion(final InlineResponse201VimConnectionInfo vimConnectionInfo) {
+ final String vimId = vimConnectionInfo.getVimId();
+ return vimId.substring(vimId.indexOf("_") + 1);
+ }
+
+ private String getTenant(final InlineResponse201VimConnectionInfo vimConnectionInfo) {
+ final JSONObject vimConnectionJsonObject = new JSONObject(vimConnectionInfo);
+ return vimConnectionJsonObject.getJSONObject("accessInfo").get("projectId").toString();
+ }
+
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/oauth/AuthorizationServerConfig.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/oauth/AuthorizationServerConfig.java
new file mode 100644
index 0000000000..7f71b2e9d6
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/oauth/AuthorizationServerConfig.java
@@ -0,0 +1,55 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.oauth;
+
+import org.onap.so.utils.CryptoUtils;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
+import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
+import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
+
+@Configuration
+@EnableAuthorizationServer
+/**
+ * Configures the authorization server for oauth token based authentication.
+ */
+public class AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
+
+ private static final int ONE_DAY = 60 * 60 * 24;
+
+ @Value("${vnfmadapter.auth:E39823AAB2739CC654C4E92B52C05BC34149342D0A46451B00CA508C8EDC62242CE4E9DA9445D3C01A3F13}")
+ private String vnfmAdapterAuth;
+
+ @Value("${mso.key}")
+ private String msoEncryptionKey;
+
+ @Override
+ public void configure(final ClientDetailsServiceConfigurer clients) throws Exception {
+ final String[] decrypedAuth = CryptoUtils.decrypt(vnfmAdapterAuth, msoEncryptionKey).split(":");
+ BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
+ clients.inMemory().withClient(decrypedAuth[0]).secret(passwordEncoder.encode(decrypedAuth[1]))
+ .authorizedGrantTypes("client_credentials").scopes("write").accessTokenValiditySeconds(ONE_DAY)
+ .refreshTokenValiditySeconds(ONE_DAY);
+ }
+
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/oauth/OAuth2AccessTokenAdapter.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/oauth/OAuth2AccessTokenAdapter.java
new file mode 100644
index 0000000000..2f51406e23
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/oauth/OAuth2AccessTokenAdapter.java
@@ -0,0 +1,51 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.oauth;
+
+import com.google.gson.JsonArray;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonObject;
+import com.google.gson.JsonSerializationContext;
+import com.google.gson.JsonSerializer;
+import java.lang.reflect.Type;
+import org.springframework.security.oauth2.common.OAuth2AccessToken;
+
+public class OAuth2AccessTokenAdapter implements JsonSerializer<OAuth2AccessToken> {
+
+ @Override
+ public JsonElement serialize(final OAuth2AccessToken src, final Type typeOfSrc,
+ final JsonSerializationContext context) {
+ final JsonObject obj = new JsonObject();
+ obj.addProperty(OAuth2AccessToken.ACCESS_TOKEN, src.getValue());
+ obj.addProperty(OAuth2AccessToken.TOKEN_TYPE, src.getTokenType());
+ if (src.getRefreshToken() != null) {
+ obj.addProperty(OAuth2AccessToken.REFRESH_TOKEN, src.getRefreshToken().getValue());
+ }
+ obj.addProperty(OAuth2AccessToken.EXPIRES_IN, src.getExpiresIn());
+ final JsonArray scopeObj = new JsonArray();
+ for (final String scope : src.getScope()) {
+ scopeObj.add(scope);
+ }
+ obj.add(OAuth2AccessToken.SCOPE, scopeObj);
+
+ return obj;
+ }
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/oauth/OAuth2ResourceServer.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/oauth/OAuth2ResourceServer.java
new file mode 100644
index 0000000000..23533e90df
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/oauth/OAuth2ResourceServer.java
@@ -0,0 +1,52 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.oauth;
+
+import static org.onap.so.adapters.vnfmadapter.common.CommonConstants.BASE_URL;
+import javax.servlet.http.HttpServletRequest;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
+import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
+import org.springframework.security.web.util.matcher.RequestMatcher;
+
+@Configuration
+@EnableResourceServer
+/**
+ * Enforces oauth token based authentication when a token is provided in the request.
+ */
+public class OAuth2ResourceServer extends ResourceServerConfigurerAdapter {
+
+ @Override
+ public void configure(final HttpSecurity http) throws Exception {
+ http.requestMatcher(new OAuth2ResourceServerRequestMatcher()).authorizeRequests()
+ .antMatchers(BASE_URL + "/grants/**", BASE_URL + "/lcn/**").authenticated();
+ }
+
+ private static class OAuth2ResourceServerRequestMatcher implements RequestMatcher {
+ @Override
+ public boolean matches(HttpServletRequest request) {
+ String auth = request.getHeader("Authorization");
+ String uri = request.getRequestURI();
+ return (auth != null && auth.startsWith("Bearer") && (uri.contains("/grants") || uri.contains("/lcn/")));
+ }
+ }
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/Sol003GrantController.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/Sol003GrantController.java
new file mode 100644
index 0000000000..a485b1d18a
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/Sol003GrantController.java
@@ -0,0 +1,114 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.rest;
+
+import static org.onap.so.adapters.vnfmadapter.common.CommonConstants.BASE_URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.UUID;
+import javax.ws.rs.core.MediaType;
+import org.onap.so.adapters.vnfmadapter.extclients.aai.AaiHelper;
+import org.onap.so.adapters.vnfmadapter.extclients.aai.AaiServiceProvider;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.VnfmHelper;
+import org.onap.so.adapters.vnfmadapter.grant.model.GrantRequest;
+import org.onap.so.adapters.vnfmadapter.grant.model.GrantsAddResources;
+import org.onap.so.adapters.vnfmadapter.grant.model.InlineResponse201;
+import org.onap.so.adapters.vnfmadapter.grant.model.InlineResponse201AddResources;
+import org.onap.so.adapters.vnfmadapter.grant.model.InlineResponse201VimConnections;
+import org.onap.vnfmadapter.v1.model.Tenant;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+@Controller
+@RequestMapping(value = BASE_URL, produces = MediaType.APPLICATION_JSON, consumes = MediaType.APPLICATION_JSON)
+public class Sol003GrantController {
+
+ private static final Logger logger = LoggerFactory.getLogger(Sol003GrantController.class);
+ public final AaiServiceProvider aaiServiceProvider;
+ public final AaiHelper aaiHelper;
+ public final VnfmHelper vnfmHelper;
+
+ @Autowired
+ public Sol003GrantController(final AaiServiceProvider aaiServiceProvider, final AaiHelper aaiHelper,
+ final VnfmHelper vnfmHelper) {
+ this.aaiServiceProvider = aaiServiceProvider;
+ this.aaiHelper = aaiHelper;
+ this.vnfmHelper = vnfmHelper;
+ }
+
+ @GetMapping(value = "/grants/{grantId}")
+ public ResponseEntity<InlineResponse201> grantsGrantIdGet(@PathVariable("grantId") final String grantId) {
+ logger.info("Get grant received from VNFM, grant id: " + grantId);
+ return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
+ }
+
+ @PostMapping(value = "/grants")
+ public ResponseEntity<InlineResponse201> grantsPost(@RequestBody final GrantRequest grantRequest) {
+ logger.info("Grant request received from VNFM: " + grantRequest);
+
+ final InlineResponse201 grantResponse = createGrantResponse(grantRequest);
+ logger.info("Grant request returning to VNFM: " + grantResponse);
+ return new ResponseEntity<>(grantResponse, HttpStatus.CREATED);
+ }
+
+ private InlineResponse201 createGrantResponse(final GrantRequest grantRequest) {
+ final InlineResponse201 grantResponse = new InlineResponse201();
+ grantResponse.setId(UUID.randomUUID().toString());
+ grantResponse.setVnfInstanceId(grantRequest.getVnfInstanceId());
+ grantResponse.setVnfLcmOpOccId(grantRequest.getVnfLcmOpOccId());
+ final String vnfSelfLink = grantRequest.getLinks().getVnfInstance().getHref();
+ final Tenant tenant = aaiHelper
+ .getAssignedTenant(aaiServiceProvider.invokeQueryGenericVnf(vnfSelfLink).getGenericVnf().get(0));
+
+ String vimConnectionId = "";
+ final InlineResponse201VimConnections vimConnection = vnfmHelper.getVimConnections(tenant);
+ grantResponse.addVimConnectionsItem(vimConnection);
+ vimConnectionId = vimConnection.getId();
+
+ if (grantRequest.getOperation().equals(GrantRequest.OperationEnum.INSTANTIATE)) {
+ grantResponse.addResources(getResources(grantRequest.getAddResources(), vimConnectionId));
+ } else if (grantRequest.getOperation().equals(GrantRequest.OperationEnum.TERMINATE)) {
+ grantResponse.removeResources(getResources(grantRequest.getRemoveResources(), vimConnectionId));
+ }
+ return grantResponse;
+ }
+
+ private List<InlineResponse201AddResources> getResources(final List<GrantsAddResources> requestResources,
+ final String vimId) {
+ final List<InlineResponse201AddResources> resources = new ArrayList<>();
+ for (final GrantsAddResources requestResource : requestResources) {
+ final InlineResponse201AddResources responseResource = new InlineResponse201AddResources();
+ responseResource.setResourceDefinitionId(requestResource.getId());
+ responseResource.setVimConnectionId(vimId);
+ resources.add(responseResource);
+ }
+ return resources;
+ }
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/Sol003LcnContoller.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/Sol003LcnContoller.java
new file mode 100644
index 0000000000..49bad20fb8
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/Sol003LcnContoller.java
@@ -0,0 +1,131 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.rest;
+
+import static org.onap.so.adapters.vnfmadapter.LifeCycleManagementConstants.OPERATION_NOTIFICATION_ENDPOINT;
+import static org.onap.so.adapters.vnfmadapter.common.CommonConstants.BASE_URL;
+import static org.slf4j.LoggerFactory.getLogger;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import javax.ws.rs.core.MediaType;
+import org.onap.aai.domain.yang.EsrVnfm;
+import org.onap.aai.domain.yang.GenericVnf;
+import org.onap.so.adapters.vnfmadapter.extclients.aai.AaiHelper;
+import org.onap.so.adapters.vnfmadapter.extclients.aai.AaiServiceProvider;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.VnfmServiceProvider;
+import org.onap.so.adapters.vnfmadapter.lcn.model.VnfIdentifierCreationNotification;
+import org.onap.so.adapters.vnfmadapter.lcn.model.VnfIdentifierDeletionNotification;
+import org.onap.so.adapters.vnfmadapter.lcn.model.VnfLcmOperationOccurrenceNotification;
+import org.onap.so.adapters.vnfmadapter.lcn.model.VnfLcmOperationOccurrenceNotification.OperationEnum;
+import org.onap.so.adapters.vnfmadapter.lcn.model.VnfLcmOperationOccurrenceNotification.OperationStateEnum;
+import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse201;
+import org.onap.so.adapters.vnfmadapter.jobmanagement.JobManager;
+import org.onap.so.adapters.vnfmadapter.notificationhandling.NotificationHandler;
+import org.slf4j.Logger;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+/**
+ * Controller for handling notifications from the VNFM (Virtual Network Function Manager).
+ */
+@Controller
+@RequestMapping(value = BASE_URL, produces = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML},
+ consumes = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+public class Sol003LcnContoller {
+ private static Logger logger = getLogger(Sol003LcnContoller.class);
+ private static final String LOG_LCN_RECEIVED = "LCN received from VNFM: ";
+ private final AaiServiceProvider aaiServiceProvider;
+ private final AaiHelper aaiHelper;
+ private final VnfmServiceProvider vnfmServiceProvider;
+ private final JobManager jobManager;
+ private final ExecutorService executor = Executors.newCachedThreadPool();
+
+ @Autowired
+ Sol003LcnContoller(final AaiServiceProvider aaiServiceProvider, final AaiHelper aaiHelper,
+ final VnfmServiceProvider vnfmServiceProvider, final JobManager jobManager) {
+ this.aaiServiceProvider = aaiServiceProvider;
+ this.aaiHelper = aaiHelper;
+ this.vnfmServiceProvider = vnfmServiceProvider;
+ this.jobManager = jobManager;
+ }
+
+ @PostMapping(value = "/lcn/VnfIdentifierCreationNotification")
+ public ResponseEntity<Void> lcnVnfIdentifierCreationNotificationPost(
+ @RequestBody final VnfIdentifierCreationNotification vnfIdentifierCreationNotification) {
+ logger.info(LOG_LCN_RECEIVED + vnfIdentifierCreationNotification);
+ return new ResponseEntity<>(HttpStatus.NO_CONTENT);
+ }
+
+ @PostMapping(value = "/lcn/VnfIdentifierDeletionNotification")
+ public ResponseEntity<Void> lcnVnfIdentifierDeletionNotificationPost(
+ @RequestBody final VnfIdentifierDeletionNotification vnfIdentifierDeletionNotification) {
+ logger.info(LOG_LCN_RECEIVED + vnfIdentifierDeletionNotification);
+ return new ResponseEntity<>(HttpStatus.NO_CONTENT);
+ }
+
+ @PostMapping(value = OPERATION_NOTIFICATION_ENDPOINT)
+ public ResponseEntity<Void> lcnVnfLcmOperationOccurrenceNotificationPost(
+ @RequestBody final VnfLcmOperationOccurrenceNotification vnfLcmOperationOccurrenceNotification) {
+ logger.info(LOG_LCN_RECEIVED + vnfLcmOperationOccurrenceNotification);
+
+ if (isANotificationOfInterest(vnfLcmOperationOccurrenceNotification)) {
+ final InlineResponse201 vnfInstance = getVnfInstance(vnfLcmOperationOccurrenceNotification);
+ final NotificationHandler handler = new NotificationHandler(vnfLcmOperationOccurrenceNotification,
+ aaiHelper, aaiServiceProvider, vnfmServiceProvider, jobManager, vnfInstance);
+ executor.execute(handler);
+ }
+
+ logger.info("Sending notification response");
+ return new ResponseEntity<>(HttpStatus.NO_CONTENT);
+ }
+
+ private boolean isANotificationOfInterest(final VnfLcmOperationOccurrenceNotification notification) {
+ return isInstanitiateCompleted(notification) || isTerminateTerminalState(notification);
+ }
+
+ private boolean isInstanitiateCompleted(final VnfLcmOperationOccurrenceNotification notification) {
+ return notification.getOperation().equals(OperationEnum.INSTANTIATE)
+ && notification.getOperationState().equals(OperationStateEnum.COMPLETED);
+ }
+
+ private boolean isTerminateTerminalState(final VnfLcmOperationOccurrenceNotification notification) {
+ return notification.getOperation().equals(OperationEnum.TERMINATE)
+ && (notification.getOperationState().equals(OperationStateEnum.COMPLETED)
+ || notification.getOperationState().equals(OperationStateEnum.FAILED)
+ || notification.getOperationState().equals(OperationStateEnum.ROLLED_BACK));
+ }
+
+ private InlineResponse201 getVnfInstance(
+ final VnfLcmOperationOccurrenceNotification vnfLcmOperationOccurrenceNotification) {
+ GenericVnf vnfInAai = aaiServiceProvider
+ .invokeQueryGenericVnf(vnfLcmOperationOccurrenceNotification.getLinks().getVnfInstance().getHref())
+ .getGenericVnf().get(0);
+ EsrVnfm vnfm = aaiHelper.getAssignedVnfm(vnfInAai);
+ return vnfmServiceProvider
+ .getVnf(vnfm, vnfLcmOperationOccurrenceNotification.getLinks().getVnfInstance().getHref()).get();
+ }
+
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/VnfmAdapterController.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/VnfmAdapterController.java
new file mode 100644
index 0000000000..33ee88108d
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/VnfmAdapterController.java
@@ -0,0 +1,164 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.rest;
+
+import static org.onap.so.adapters.vnfmadapter.common.CommonConstants.BASE_URL;
+import javax.validation.Valid;
+import javax.ws.rs.core.MediaType;
+import org.onap.logging.ref.slf4j.ONAPLogConstants;
+import org.onap.so.adapters.vnfmadapter.common.CommonConstants;
+import org.onap.so.adapters.vnfmadapter.jobmanagement.JobManager;
+import org.onap.so.adapters.vnfmadapter.lifecycle.LifecycleManager;
+import org.onap.vnfmadapter.v1.model.CreateVnfRequest;
+import org.onap.vnfmadapter.v1.model.CreateVnfResponse;
+import org.onap.vnfmadapter.v1.model.DeleteVnfResponse;
+import org.onap.vnfmadapter.v1.model.QueryJobResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.slf4j.MDC;
+import org.springframework.beans.factory.annotation.Autowired;
+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.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestHeader;
+import org.springframework.web.bind.annotation.RequestMapping;
+import io.swagger.annotations.ApiParam;
+
+/**
+ * Controller for handling requests to the VNFM (Virtual Network Function Manager) adapter REST API.
+ */
+@Controller
+@RequestMapping(value = BASE_URL, produces = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML},
+ consumes = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
+public class VnfmAdapterController {
+
+ private static final Logger logger = LoggerFactory.getLogger(VnfmAdapterController.class);
+ private final LifecycleManager lifecycleManager;
+ private final JobManager jobManager;
+
+ @Autowired
+ VnfmAdapterController(final LifecycleManager lifecycleManager, final JobManager jobManager) {
+ this.lifecycleManager = lifecycleManager;
+ this.jobManager = jobManager;
+ }
+
+ @PostMapping(value = "/vnfs/{vnfId}")
+ public ResponseEntity<CreateVnfResponse> vnfCreate(
+ @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 = "VNF creation parameters",
+ 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 = 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 vnfCreate with body: {}", createVnfRequest);
+
+ try {
+ final CreateVnfResponse createVnfResponse = lifecycleManager.createVnf(vnfId, createVnfRequest);
+ return new ResponseEntity<>(createVnfResponse, HttpStatus.ACCEPTED);
+ } finally {
+ clearLoggingMDCs();
+ }
+ }
+
+ @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);
+
+ try {
+ final DeleteVnfResponse response = lifecycleManager.deleteVnf(vnfId);
+ return new ResponseEntity<>(response, HttpStatus.ACCEPTED);
+ } finally {
+ clearLoggingMDCs();
+ }
+ }
+
+ @GetMapping(value = "/jobs/{jobId}")
+ public ResponseEntity<QueryJobResponse> jobQuery(
+ @ApiParam(value = "The identifier of the Job.", required = true) @PathVariable("jobId") final String jobId,
+ @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);
+
+ try {
+ final QueryJobResponse response = jobManager.getVnfmOperation(jobId);
+ return new ResponseEntity<>(response, HttpStatus.OK);
+ } finally {
+ clearLoggingMDCs();
+ }
+ }
+
+ 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);
+ MDC.put(ONAPLogConstants.MDCs.INVOCATION_ID, invocationId);
+ }
+
+ private void clearLoggingMDCs() {
+ MDC.clear();
+ }
+
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/JobNotFoundException.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/JobNotFoundException.java
new file mode 100644
index 0000000000..bc7c569231
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/JobNotFoundException.java
@@ -0,0 +1,38 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.rest.exceptions;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
+/**
+ * Exception for job not found.
+ */
+@ResponseStatus(HttpStatus.NOT_FOUND)
+public class JobNotFoundException extends RuntimeException {
+
+ private static final long serialVersionUID = 6398018034431666933L;
+
+ public JobNotFoundException(final String message) {
+ super(message);
+ }
+
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/TenantNotFoundException.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/TenantNotFoundException.java
new file mode 100644
index 0000000000..215e68adcf
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/TenantNotFoundException.java
@@ -0,0 +1,35 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.rest.exceptions;
+
+/**
+ * Exception for Tenant not found.
+ */
+
+public class TenantNotFoundException extends RuntimeException {
+
+ private static final long serialVersionUID = 6398018034431666933L;
+
+ public TenantNotFoundException(final String message) {
+ super(message);
+ }
+
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/VnfNotFoundException.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/VnfNotFoundException.java
new file mode 100644
index 0000000000..9b73293020
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/VnfNotFoundException.java
@@ -0,0 +1,38 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.rest.exceptions;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
+/**
+ * Exception for VNF not found.
+ */
+@ResponseStatus(HttpStatus.NOT_FOUND)
+public class VnfNotFoundException extends RuntimeException {
+
+ private static final long serialVersionUID = 6398018034431666933L;
+
+ public VnfNotFoundException(final String message) {
+ super(message);
+ }
+
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/VnfmNotFoundException.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/VnfmNotFoundException.java
new file mode 100644
index 0000000000..4e494c14c6
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/VnfmNotFoundException.java
@@ -0,0 +1,38 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.rest.exceptions;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
+/**
+ * Exception for VNFM not found.
+ */
+@ResponseStatus(HttpStatus.BAD_REQUEST)
+public class VnfmNotFoundException extends RuntimeException {
+
+ private static final long serialVersionUID = 6398018034431666933L;
+
+ public VnfmNotFoundException(final String message) {
+ super(message);
+ }
+
+}
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/VnfmRequestFailureException.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/VnfmRequestFailureException.java
new file mode 100644
index 0000000000..9f50a2cee1
--- /dev/null
+++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/exceptions/VnfmRequestFailureException.java
@@ -0,0 +1,38 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * 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.adapters.vnfmadapter.rest.exceptions;
+
+/**
+ * Exception indicating a request to a VNFM failed.
+ */
+public class VnfmRequestFailureException extends RuntimeException {
+
+ private static final long serialVersionUID = 6398018034431666933L;
+
+ public VnfmRequestFailureException(final String message) {
+ super(message);
+ }
+
+ public VnfmRequestFailureException(final String message, final Throwable throwable) {
+ super(message, throwable);
+ }
+
+}