diff options
Diffstat (limited to 'adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter')
38 files changed, 4985 insertions, 0 deletions
diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/pom.xml b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/pom.xml new file mode 100644 index 0000000000..560cd87bee --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/pom.xml @@ -0,0 +1,109 @@ +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <modelVersion>4.0.0</modelVersion> + <parent> + <groupId>org.onap.so.adapters</groupId> + <artifactId>etsi-sol003-lcm</artifactId> + <version>1.6.0-SNAPSHOT</version> + </parent> + <artifactId>etsi-sol003-lcm-adapter</artifactId> + <name>ETSI SOL003 Life Cycle Management Adapter</name> + + <build> + <plugins> + <plugin> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-surefire-plugin</artifactId> + <configuration> + <systemPropertyVariables> + <so.log.level>DEBUG</so.log.level> + </systemPropertyVariables> + <rerunFailingTestsCount>2</rerunFailingTestsCount> + <parallel>suites</parallel> + <useUnlimitedThreads>false</useUnlimitedThreads> + <threadCount>1</threadCount> + </configuration> + </plugin> + </plugins> + </build> + <dependencies> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-web</artifactId> + <exclusions> + <exclusion> + <groupId>com.fasterxml.jackson.core</groupId> + <artifactId>jackson-databind</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-security</artifactId> + <exclusions> + <exclusion> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-tomcat</artifactId> + </exclusion> + </exclusions> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-actuator</artifactId> + </dependency> + <dependency> + <groupId>org.springframework.boot</groupId> + <artifactId>spring-boot-starter-test</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.onap.so</groupId> + <artifactId>common</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.so.adapters</groupId> + <artifactId>etsi-sol003-adapter-common</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.so.adapters</groupId> + <artifactId>etsi-sol003-lcm-api</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.so.adapters</groupId> + <artifactId>etsi-sol003-lcm-ext-clients</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.core</groupId> + <artifactId>jersey-client</artifactId> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.core</groupId> + <artifactId>jersey-common</artifactId> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.inject</groupId> + <artifactId>jersey-hk2</artifactId> + </dependency> + <dependency> + <groupId>org.glassfish.jersey.media</groupId> + <artifactId>jersey-media-json-jackson</artifactId> + </dependency> + <dependency> + <groupId>org.yaml</groupId> + <artifactId>snakeyaml</artifactId> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + </dependencies> +</project>
\ No newline at end of file diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/LifeCycleManagementConstants.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/LifeCycleManagementConstants.java new file mode 100644 index 0000000000..ec82c17971 --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/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.etsi.sol003.adapter.lcm; + +/** + * 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/etsi/sol003/adapter/lcm/NvfmAdapterUtils.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/NvfmAdapterUtils.java new file mode 100644 index 0000000000..2132108ca2 --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/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.etsi.sol003.adapter.lcm; + +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/etsi/sol003/adapter/lcm/extclients/AbstractServiceProviderConfiguration.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/extclients/AbstractServiceProviderConfiguration.java new file mode 100644 index 0000000000..84dd549d61 --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/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.etsi.sol003.adapter.lcm.extclients; + +import java.util.Iterator; +import org.onap.etsi.sol003.adapter.lcm.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; +import com.google.gson.Gson; + +/** + * 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/etsi/sol003/adapter/lcm/extclients/SdcPackageProvider.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/extclients/SdcPackageProvider.java new file mode 100644 index 0000000000..907a15d3bc --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/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.etsi.sol003.adapter.lcm.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.etsi.sol003.adapter.lcm.NvfmAdapterUtils.abortOperation; +import static org.onap.so.adapters.etsi.sol003.adapter.lcm.NvfmAdapterUtils.child; +import static org.onap.so.adapters.etsi.sol003.adapter.lcm.NvfmAdapterUtils.childElement; +import static org.onap.so.adapters.etsi.sol003.adapter.lcm.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/etsi/sol003/adapter/lcm/extclients/aai/AaiClientProvider.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/extclients/aai/AaiClientProvider.java new file mode 100644 index 0000000000..f12ff4c89b --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/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.etsi.sol003.adapter.lcm.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/etsi/sol003/adapter/lcm/extclients/aai/AaiHelper.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/extclients/aai/AaiHelper.java new file mode 100644 index 0000000000..806193fc5f --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/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.etsi.sol003.adapter.lcm.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.etsi.sol003.adapter.lcm.v1.model.Tenant; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.lcn.model.LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.rest.exceptions.TenantNotFoundException; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.rest.exceptions.VnfmNotFoundException; +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/etsi/sol003/adapter/lcm/extclients/aai/AaiPropertiesImpl.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/extclients/aai/AaiPropertiesImpl.java new file mode 100644 index 0000000000..cc1af3d215 --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/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.etsi.sol003.adapter.lcm.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/etsi/sol003/adapter/lcm/extclients/aai/AaiServiceProvider.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/extclients/aai/AaiServiceProvider.java new file mode 100644 index 0000000000..68a8405c0a --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/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.etsi.sol003.adapter.lcm.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.etsi.sol003.adapter.lcm.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/etsi/sol003/adapter/lcm/extclients/aai/AaiServiceProviderImpl.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/extclients/aai/AaiServiceProviderImpl.java new file mode 100644 index 0000000000..140d0370e0 --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/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.etsi.sol003.adapter.lcm.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.etsi.sol003.adapter.lcm.v1.model.Tenant; +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.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/etsi/sol003/adapter/lcm/extclients/aai/OamIpAddressSource.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/extclients/aai/OamIpAddressSource.java new file mode 100644 index 0000000000..25bacce705 --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/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.etsi.sol003.adapter.lcm.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/etsi/sol003/adapter/lcm/extclients/vim/model/AccessInfo.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/extclients/vim/model/AccessInfo.java new file mode 100644 index 0000000000..b557acd892 --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/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.etsi.sol003.adapter.lcm.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/etsi/sol003/adapter/lcm/extclients/vim/model/InterfaceInfo.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/extclients/vim/model/InterfaceInfo.java new file mode 100644 index 0000000000..af11e35e80 --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/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.etsi.sol003.adapter.lcm.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/etsi/sol003/adapter/lcm/extclients/vim/model/VimCredentials.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/extclients/vim/model/VimCredentials.java new file mode 100644 index 0000000000..6927d38757 --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/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.etsi.sol003.adapter.lcm.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/etsi/sol003/adapter/lcm/extclients/vnfm/VnfmHelper.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/extclients/vnfm/VnfmHelper.java new file mode 100644 index 0000000000..e2f673b6c4 --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/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.etsi.sol003.adapter.lcm.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.etsi.sol003.adapter.lcm.v1.model.CreateVnfRequest; +import org.onap.etsi.sol003.adapter.lcm.v1.model.ExternalVirtualLink; +import org.onap.etsi.sol003.adapter.lcm.v1.model.Tenant; +import org.onap.so.adapters.etsi.sol003.adapter.common.VnfmAdapterUrlProvider; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.aai.AaiServiceProvider; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vim.model.AccessInfo; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vim.model.InterfaceInfo; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vim.model.VimCredentials; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InstantiateVnfRequest; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.LccnSubscriptionRequest; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.SubscriptionsAuthentication; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.SubscriptionsAuthentication.AuthTypeEnum; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.SubscriptionsAuthenticationParamsBasic; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.SubscriptionsAuthenticationParamsOauth2ClientCredentials; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.SubscriptionsFilter; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.SubscriptionsFilter.NotificationTypesEnum; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.SubscriptionsFilterVnfInstanceSubscriptionFilter; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.VnfInstancesvnfInstanceIdinstantiateExtVirtualLinks; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.VnfInstancesvnfInstanceIdinstantiateVimConnectionInfo; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.grant.model.InlineResponse201VimConnections; +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/etsi/sol003/adapter/lcm/extclients/vnfm/VnfmServiceProvider.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/extclients/vnfm/VnfmServiceProvider.java new file mode 100644 index 0000000000..d4ce8c8484 --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/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.etsi.sol003.adapter.lcm.extclients.vnfm; + +import org.onap.aai.domain.yang.EsrVnfm; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.CreateVnfRequest; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse200; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse2001; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse201; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InstantiateVnfRequest; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.LccnSubscriptionRequest; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.TerminateVnfRequest; +import com.google.common.base.Optional; + +/** + * 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/etsi/sol003/adapter/lcm/extclients/vnfm/VnfmServiceProviderConfiguration.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/extclients/vnfm/VnfmServiceProviderConfiguration.java new file mode 100644 index 0000000000..231d19a6aa --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/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.etsi.sol003.adapter.lcm.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.etsi.sol003.adapter.lcm.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/etsi/sol003/adapter/lcm/extclients/vnfm/VnfmServiceProviderImpl.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/extclients/vnfm/VnfmServiceProviderImpl.java new file mode 100644 index 0000000000..6adbde2eae --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/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.etsi.sol003.adapter.lcm.extclients.vnfm; + +import org.onap.aai.domain.yang.EsrVnfm; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.CreateVnfRequest; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse200; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse2001; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse201; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse201.InstantiationStateEnum; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InstantiateVnfRequest; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.LccnSubscriptionRequest; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.TerminateVnfRequest; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.jobmanagement.JobManager; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.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; +import com.google.common.base.Optional; + +@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/etsi/sol003/adapter/lcm/extclients/vnfm/VnfmUrlProvider.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/extclients/vnfm/VnfmUrlProvider.java new file mode 100644 index 0000000000..a88086ff00 --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/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.etsi.sol003.adapter.lcm.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.etsi.sol003.adapter.lcm.extclients.aai.AaiServiceProvider; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.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/etsi/sol003/adapter/lcm/jobmanagement/JobManager.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/jobmanagement/JobManager.java new file mode 100644 index 0000000000..84d1022424 --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/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.etsi.sol003.adapter.lcm.jobmanagement; + +import static org.slf4j.LoggerFactory.getLogger; +import java.util.Map; +import java.util.UUID; +import org.onap.etsi.sol003.adapter.lcm.v1.model.OperationEnum; +import org.onap.etsi.sol003.adapter.lcm.v1.model.OperationStateEnum; +import org.onap.etsi.sol003.adapter.lcm.v1.model.OperationStatusRetrievalStatusEnum; +import org.onap.etsi.sol003.adapter.lcm.v1.model.QueryJobResponse; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.aai.AaiServiceProvider; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.VnfmServiceProvider; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse200; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.rest.exceptions.JobNotFoundException; +import org.onap.so.rest.exceptions.HttpResouceNotFoundException; +import org.slf4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import com.google.common.base.Optional; +import com.google.common.collect.Maps; + +/** + * 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.etsi.sol003.adapter.lcm.v1.model.OperationStateEnum.PROCESSING; + case NOTIFICATION_PROCEESING_SUCCESSFUL: + return org.onap.etsi.sol003.adapter.lcm.v1.model.OperationStateEnum.COMPLETED; + case NOTIFICATION_PROCESSING_FAILED: + return org.onap.etsi.sol003.adapter.lcm.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/etsi/sol003/adapter/lcm/jobmanagement/VnfmOperation.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/jobmanagement/VnfmOperation.java new file mode 100644 index 0000000000..f28eeb9ebc --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/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.etsi.sol003.adapter.lcm.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/etsi/sol003/adapter/lcm/lifecycle/LifecycleManager.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/lifecycle/LifecycleManager.java new file mode 100644 index 0000000000..74c6571c3d --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/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.etsi.sol003.adapter.lcm.lifecycle; + +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.etsi.sol003.adapter.lcm.v1.model.CreateVnfRequest; +import org.onap.etsi.sol003.adapter.lcm.v1.model.CreateVnfResponse; +import org.onap.etsi.sol003.adapter.lcm.v1.model.DeleteVnfResponse; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.SdcPackageProvider; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.aai.AaiHelper; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.aai.AaiServiceProvider; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.aai.OamIpAddressSource; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.aai.OamIpAddressSource.OamIpAddressType; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.VnfmHelper; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.VnfmServiceProvider; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse201; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InstantiateVnfRequest; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.LccnSubscriptionRequest; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.TerminateVnfRequest; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.TerminateVnfRequest.TerminationTypeEnum; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.jobmanagement.JobManager; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.rest.exceptions.VnfNotFoundException; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.rest.exceptions.VnfmNotFoundException; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.rest.exceptions.VnfmRequestFailureException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import com.google.common.base.Optional; + +/** + * 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.etsi.sol003.adapter.lcm.extclients.vnfm.model.CreateVnfRequest vnfmRequest = + new org.onap.so.adapters.etsi.sol003.adapter.lcm.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/etsi/sol003/adapter/lcm/notificationhandling/NotificationHandler.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/notificationhandling/NotificationHandler.java new file mode 100644 index 0000000000..43a8c352ff --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/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.etsi.sol003.adapter.lcm.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.etsi.sol003.adapter.lcm.extclients.aai.AaiHelper; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.aai.AaiServiceProvider; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.aai.OamIpAddressSource; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.aai.OamIpAddressSource.OamIpAddressType; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.VnfmServiceProvider; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse201; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse201VimConnectionInfo; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.jobmanagement.JobManager; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.lcn.model.LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.lcn.model.LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs.ChangeTypeEnum; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.lcn.model.VnfLcmOperationOccurrenceNotification; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.lcn.model.VnfLcmOperationOccurrenceNotification.OperationStateEnum; +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/etsi/sol003/adapter/lcm/rest/Sol003GrantController.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/rest/Sol003GrantController.java new file mode 100644 index 0000000000..a9682964d8 --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/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.etsi.sol003.adapter.lcm.rest; + +import static org.onap.so.adapters.etsi.sol003.adapter.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.etsi.sol003.adapter.lcm.v1.model.Tenant; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.aai.AaiHelper; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.aai.AaiServiceProvider; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.VnfmHelper; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.grant.model.GrantRequest; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.grant.model.GrantsAddResources; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.grant.model.InlineResponse201; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.grant.model.InlineResponse201AddResources; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.grant.model.InlineResponse201VimConnections; +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/etsi/sol003/adapter/lcm/rest/Sol003LcnContoller.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/rest/Sol003LcnContoller.java new file mode 100644 index 0000000000..26ba1fffcf --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/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.etsi.sol003.adapter.lcm.rest; + +import static org.onap.so.adapters.etsi.sol003.adapter.common.CommonConstants.BASE_URL; +import static org.onap.so.adapters.etsi.sol003.adapter.lcm.LifeCycleManagementConstants.OPERATION_NOTIFICATION_ENDPOINT; +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.etsi.sol003.adapter.lcm.extclients.aai.AaiHelper; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.aai.AaiServiceProvider; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.VnfmServiceProvider; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.jobmanagement.JobManager; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.lcn.model.VnfIdentifierCreationNotification; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.lcn.model.VnfIdentifierDeletionNotification; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.lcn.model.VnfLcmOperationOccurrenceNotification; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.lcn.model.VnfLcmOperationOccurrenceNotification.OperationEnum; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.lcn.model.VnfLcmOperationOccurrenceNotification.OperationStateEnum; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.notificationhandling.NotificationHandler; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse201; +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/etsi/sol003/adapter/lcm/rest/VnfmAdapterController.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/rest/VnfmAdapterController.java new file mode 100644 index 0000000000..9b571af81e --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/rest/VnfmAdapterController.java @@ -0,0 +1,163 @@ +/*- + * ============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.etsi.sol003.adapter.lcm.rest; + +import static org.onap.so.adapters.etsi.sol003.adapter.common.CommonConstants.BASE_URL; +import javax.validation.Valid; +import javax.ws.rs.core.MediaType; +import org.onap.etsi.sol003.adapter.lcm.v1.model.CreateVnfRequest; +import org.onap.etsi.sol003.adapter.lcm.v1.model.CreateVnfResponse; +import org.onap.etsi.sol003.adapter.lcm.v1.model.DeleteVnfResponse; +import org.onap.etsi.sol003.adapter.lcm.v1.model.QueryJobResponse; +import org.onap.logging.ref.slf4j.ONAPLogConstants; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.jobmanagement.JobManager; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.lifecycle.LifecycleManager; +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/etsi/sol003/adapter/lcm/rest/exceptions/JobNotFoundException.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/rest/exceptions/JobNotFoundException.java new file mode 100644 index 0000000000..a5fac29ec7 --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/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.etsi.sol003.adapter.lcm.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/etsi/sol003/adapter/lcm/rest/exceptions/TenantNotFoundException.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/rest/exceptions/TenantNotFoundException.java new file mode 100644 index 0000000000..d120f7e81a --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/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.etsi.sol003.adapter.lcm.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/etsi/sol003/adapter/lcm/rest/exceptions/VnfNotFoundException.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/rest/exceptions/VnfNotFoundException.java new file mode 100644 index 0000000000..31ea91ae72 --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/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.etsi.sol003.adapter.lcm.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/etsi/sol003/adapter/lcm/rest/exceptions/VnfmNotFoundException.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/rest/exceptions/VnfmNotFoundException.java new file mode 100644 index 0000000000..d4107616c3 --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/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.etsi.sol003.adapter.lcm.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/etsi/sol003/adapter/lcm/rest/exceptions/VnfmRequestFailureException.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/rest/exceptions/VnfmRequestFailureException.java new file mode 100644 index 0000000000..c2add907fe --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/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.etsi.sol003.adapter.lcm.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); + } + +} diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/resources/META-INF/services/org.onap.so.client.RestProperties b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/resources/META-INF/services/org.onap.so.client.RestProperties new file mode 100644 index 0000000000..1d13643147 --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/main/resources/META-INF/services/org.onap.so.client.RestProperties @@ -0,0 +1 @@ +org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.aai.AaiPropertiesImpl
\ No newline at end of file diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/test/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/rest/HealthCheckTest.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/test/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/rest/HealthCheckTest.java new file mode 100644 index 0000000000..8b3c7f3ce7 --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/test/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/rest/HealthCheckTest.java @@ -0,0 +1,54 @@ +/*- + * ============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.etsi.sol003.adapter.lcm.rest; + +import static org.junit.Assert.assertEquals; +import java.net.URI; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = TestApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT) +@ActiveProfiles("test") +public class HealthCheckTest { + + @LocalServerPort + private int port; + + private final TestRestTemplate restTemplate = new TestRestTemplate("test", "test"); + + @Test + public void testHealthcheck() throws Exception { + final RequestEntity<Void> request = + RequestEntity.get(new URI("http://localhost:" + port + "/manage/health")).build(); + final ResponseEntity<Void> response = restTemplate.exchange(request, Void.class); + assertEquals(200, response.getStatusCode().value()); + } + +} diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/test/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/rest/Sol003GrantControllerTest.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/test/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/rest/Sol003GrantControllerTest.java new file mode 100644 index 0000000000..d15693ddfc --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/test/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/rest/Sol003GrantControllerTest.java @@ -0,0 +1,252 @@ +/*- + * ============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.etsi.sol003.adapter.lcm.rest; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.onap.so.client.RestTemplateConfig.CONFIGURABLE_REST_TEMPLATE; +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.hamcrest.MockitoHamcrest; +import org.onap.aai.domain.yang.EsrSystemInfo; +import org.onap.aai.domain.yang.EsrSystemInfoList; +import org.onap.aai.domain.yang.GenericVnf; +import org.onap.aai.domain.yang.GenericVnfs; +import org.onap.aai.domain.yang.Relationship; +import org.onap.aai.domain.yang.RelationshipData; +import org.onap.aai.domain.yang.RelationshipList; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.grant.model.GrantRequest; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.grant.model.GrantRequest.OperationEnum; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.grant.model.GrantsAddResources; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.grant.model.GrantsAddResources.TypeEnum; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.grant.model.GrantsLinks; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.grant.model.GrantsLinksVnfLcmOpOcc; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.grant.model.InlineResponse201; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.grant.model.InlineResponse201VimConnections; +import org.onap.so.client.aai.AAIResourcesClient; +import org.onap.so.client.aai.entities.uri.AAIResourceUri; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.web.client.RestTemplate; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = TestApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT) +@ActiveProfiles("test") +public class Sol003GrantControllerTest { + + private static final String CLOUD_OWNER = "myTestCloudOwner"; + private static final String REGION = "myTestRegion"; + private static final String TENANT_ID = "myTestTenantId"; + private static final String SEPARATOR = "_"; + private static final String vimConnectionId = CLOUD_OWNER + SEPARATOR + REGION; + + @LocalServerPort + private int port; + @Autowired + @Qualifier(CONFIGURABLE_REST_TEMPLATE) + private RestTemplate testRestTemplate; + + @MockBean + private AAIResourcesClient aaiResourcesClient; + + @Autowired + private Sol003GrantController controller; + + @Before + public void setUp() throws Exception { + setUpVimInMockAai(); + } + + @Test + public void grantRequest_ValidRequestInstantiate_GrantApproved() { + final GrantRequest grantRequest = createGrantRequest("INSTANTIATE"); + setUpGenericVnfWithVnfmRelationshipInMockAai("vnfmType", "vnfm1"); + final ResponseEntity<InlineResponse201> response = controller.grantsPost(grantRequest); + assertEquals(HttpStatus.CREATED, response.getStatusCode()); + assertEquals(1, response.getBody().getAddResources().size()); + assertNull(response.getBody().getRemoveResources()); + + assertEquals(vimConnectionId, response.getBody().getAddResources().get(0).getVimConnectionId()); + assertEquals("myTestVnfIdOnVnfm", response.getBody().getVnfInstanceId()); + assertEquals("123456", response.getBody().getVnfLcmOpOccId()); + + final InlineResponse201VimConnections vimConnections = response.getBody().getVimConnections().get(0); + assertEquals(vimConnectionId, vimConnections.getVimId()); + assertEquals("OPENSTACK", vimConnections.getVimType()); + assertNotNull(vimConnections.getAccessInfo()); + assertNotNull(vimConnections.getInterfaceInfo()); + assertEquals("INSTANTIATE", grantRequest.getOperation().toString()); + } + + @Test + public void getGrant_notSupported_returns501() { + final ResponseEntity<InlineResponse201> response2 = controller.grantsGrantIdGet("myTestGrantId"); + assertEquals(HttpStatus.NOT_IMPLEMENTED, response2.getStatusCode()); + } + + @Test + public void grantRequest_ValidRequestTerminate_GrantApproved() { + final GrantRequest grantRequest = createGrantRequest("TERMINATE"); + setUpGenericVnfWithVnfmRelationshipInMockAai("vnfmType", "vnfm1"); + final ResponseEntity<InlineResponse201> response = controller.grantsPost(grantRequest); + + assertEquals(HttpStatus.CREATED, response.getStatusCode()); + assertNull(response.getBody().getAddResources()); + assertEquals(1, response.getBody().getRemoveResources().size()); + assertEquals(vimConnectionId, response.getBody().getRemoveResources().get(0).getVimConnectionId()); + assertEquals("myTestVnfIdOnVnfm", response.getBody().getVnfInstanceId()); + assertEquals("123456", response.getBody().getVnfLcmOpOccId()); + + final InlineResponse201VimConnections vimConnections = response.getBody().getVimConnections().get(0); + assertEquals(vimConnectionId, vimConnections.getVimId()); + assertEquals("OPENSTACK", vimConnections.getVimType()); + assertNotNull(vimConnections.getAccessInfo()); + assertNotNull(vimConnections.getInterfaceInfo()); + assertEquals("TERMINATE", grantRequest.getOperation().toString()); + + } + + private GrantRequest createGrantRequest(final String operation) { + final GrantRequest grantRequest = new GrantRequest(); + grantRequest.setVnfInstanceId("myTestVnfIdOnVnfm"); + grantRequest.setVnfLcmOpOccId("123456"); + grantRequest.links(new GrantsLinks() + .vnfInstance(new GrantsLinksVnfLcmOpOcc().href("http://vnfm:8080/vnfs/myTestVnfIdOnVnfm"))); + if (operation == "INSTANTIATE") { + grantRequest.setOperation(OperationEnum.INSTANTIATE); + final GrantsAddResources resource = new GrantsAddResources(); + resource.setId("123"); + resource.setType(TypeEnum.COMPUTE); + grantRequest.addAddResourcesItem(resource); + } else if (operation == "TERMINATE") { + grantRequest.setOperation(OperationEnum.TERMINATE); + final GrantsAddResources resource = new GrantsAddResources(); + resource.setId("123"); + resource.setType(TypeEnum.COMPUTE); + grantRequest.addRemoveResourcesItem(resource); + } + + return grantRequest; + } + + private void setUpVimInMockAai() { + final EsrSystemInfo esrSystemInfo = new EsrSystemInfo(); + esrSystemInfo.setServiceUrl("http://myVim:8080"); + esrSystemInfo.setType("OPENSTACK"); + esrSystemInfo.setSystemType("VIM"); + esrSystemInfo.setCloudDomain("myDomain"); + esrSystemInfo.setUserName("myUser"); + esrSystemInfo.setPassword("myPassword"); + + final EsrSystemInfoList esrSystemInfoList = new EsrSystemInfoList(); + esrSystemInfoList.getEsrSystemInfo().add(esrSystemInfo); + + doReturn(Optional.of(esrSystemInfoList)).when(aaiResourcesClient).get(eq(EsrSystemInfoList.class), + MockitoHamcrest.argThat(new AaiResourceUriMatcher("/cloud-infrastructure/cloud-regions/cloud-region/" + + CLOUD_OWNER + "/" + REGION + "/esr-system-info-list"))); + } + + private GenericVnf createGenericVnf(final String type) { + final GenericVnf genericVnf = new GenericVnf(); + genericVnf.setVnfId("myTestVnfId"); + genericVnf.setNfType(type); + return genericVnf; + } + + private void setUpGenericVnfWithVnfmRelationshipInMockAai(final String type, final String vnfmId) { + final GenericVnf genericVnf = createGenericVnf(type); + + final Relationship relationshipToVnfm = new Relationship(); + relationshipToVnfm.setRelatedTo("tenant"); + final RelationshipData relationshipData1 = new RelationshipData(); + final RelationshipData relationshipData2 = new RelationshipData(); + final RelationshipData relationshipData3 = new RelationshipData(); + + relationshipData1.setRelationshipKey("cloud-region.cloud-owner"); + relationshipData1.setRelationshipValue(CLOUD_OWNER); + relationshipData2.setRelationshipKey("cloud-region.cloud-region-id"); + relationshipData2.setRelationshipValue(REGION); + relationshipData3.setRelationshipKey("tenant.tenant-id"); + relationshipData3.setRelationshipValue(TENANT_ID); + + relationshipToVnfm.getRelationshipData().add(relationshipData1); + relationshipToVnfm.getRelationshipData().add(relationshipData2); + relationshipToVnfm.getRelationshipData().add(relationshipData3); + + final RelationshipList relationshipList = new RelationshipList(); + relationshipList.getRelationship().add(relationshipToVnfm); + genericVnf.setRelationshipList(relationshipList); + + doReturn(Optional.of(genericVnf)).when(aaiResourcesClient).get(eq(GenericVnf.class), + MockitoHamcrest.argThat(new AaiResourceUriMatcher("/network/generic-vnfs/generic-vnf/myTestVnfId"))); + + final List<GenericVnf> listOfGenericVnfs = new ArrayList<>(); + listOfGenericVnfs.add(genericVnf); + final GenericVnfs genericVnfs = new GenericVnfs(); + genericVnfs.getGenericVnf().addAll(listOfGenericVnfs); + doReturn(Optional.of(genericVnfs)).when(aaiResourcesClient).get(eq(GenericVnfs.class), + MockitoHamcrest.argThat(new AaiResourceUriMatcher( + "/network/generic-vnfs?selflink=http%3A%2F%2Fvnfm%3A8080%2Fvnfs%2FmyTestVnfIdOnVnfm"))); + } + + private class AaiResourceUriMatcher extends BaseMatcher<AAIResourceUri> { + + final String uriAsString; + + public AaiResourceUriMatcher(final String uriAsString) { + this.uriAsString = uriAsString; + } + + @Override + public boolean matches(final Object item) { + if (item instanceof AAIResourceUri) { + if (uriAsString.endsWith("...")) { + return ((AAIResourceUri) item).build().toString() + .startsWith(uriAsString.substring(0, uriAsString.indexOf("..."))); + } + return ((AAIResourceUri) item).build().toString().equals(uriAsString); + } + return false; + } + + @Override + public void describeTo(final Description description) {} + + } + +} diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/test/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/rest/Sol003LcnControllerTest.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/test/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/rest/Sol003LcnControllerTest.java new file mode 100644 index 0000000000..ec35099469 --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/test/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/rest/Sol003LcnControllerTest.java @@ -0,0 +1,413 @@ +/*- + * ============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.etsi.sol003.adapter.lcm.rest; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.verifyZeroInteractions; +import static org.onap.so.client.RestTemplateConfig.CONFIGURABLE_REST_TEMPLATE; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import javax.inject.Inject; +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.hamcrest.MockitoHamcrest; +import org.onap.aai.domain.yang.EsrSystemInfoList; +import org.onap.aai.domain.yang.EsrVnfm; +import org.onap.aai.domain.yang.GenericVnf; +import org.onap.aai.domain.yang.GenericVnfs; +import org.onap.aai.domain.yang.Relationship; +import org.onap.aai.domain.yang.RelationshipData; +import org.onap.aai.domain.yang.RelationshipList; +import org.onap.aai.domain.yang.Vserver; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.aai.AaiHelper; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.aai.OamIpAddressSource; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.aai.OamIpAddressSource.OamIpAddressType; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vim.model.AccessInfo; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse201; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse201Links; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse201LinksSelf; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse201VimConnectionInfo; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.lcn.model.LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.lcn.model.LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs.ChangeTypeEnum; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.lcn.model.LcnVnfLcmOperationOccurrenceNotificationComputeResource; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.lcn.model.LcnVnfLcmOperationOccurrenceNotificationLinks; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.lcn.model.LcnVnfLcmOperationOccurrenceNotificationLinksVnfInstance; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.lcn.model.VnfIdentifierCreationNotification; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.lcn.model.VnfLcmOperationOccurrenceNotification; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.lcn.model.VnfLcmOperationOccurrenceNotification.OperationEnum; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.lcn.model.VnfLcmOperationOccurrenceNotification.OperationStateEnum; +import org.onap.so.client.aai.AAIResourcesClient; +import org.onap.so.client.aai.entities.uri.AAIResourceUri; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.client.MockRestServiceServer; +import org.springframework.web.client.RestTemplate; +import com.google.gson.Gson; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = TestApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT) +@ActiveProfiles("test") +public class Sol003LcnControllerTest { + + private static final String CLOUD_OWNER = "myTestCloudOwner"; + private static final String REGION = "myTestRegion"; + private static final String TENANT_ID = "myTestTenantId"; + + @LocalServerPort + private int port; + @Autowired + @Qualifier(CONFIGURABLE_REST_TEMPLATE) + private RestTemplate testRestTemplate; + private MockRestServiceServer mockRestServer; + + @MockBean + private AAIResourcesClient aaiResourcesClient; + + @Autowired + private Sol003LcnContoller controller; + private final Gson gson = new Gson(); + + @Inject + private AaiHelper aaiHelper; + + @Before + public void setUp() throws Exception { + mockRestServer = MockRestServiceServer.bindTo(testRestTemplate).build(); + } + + @Test + public void lcnNotification_IdentifierCreated_Returns204() throws URISyntaxException, InterruptedException { + final VnfIdentifierCreationNotification vnfIdentifierCreationNotification = + new VnfIdentifierCreationNotification(); + final ResponseEntity<Void> response = + controller.lcnVnfIdentifierCreationNotificationPost(vnfIdentifierCreationNotification); + assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode()); + } + + @Test + public void lcnNotification_IdentifierDeleted_Returns204() throws URISyntaxException, InterruptedException { + final VnfIdentifierCreationNotification vnfIdentifierCreationNotification = + new VnfIdentifierCreationNotification(); + final ResponseEntity<Void> response = + controller.lcnVnfIdentifierCreationNotificationPost(vnfIdentifierCreationNotification); + assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode()); + } + + @Test + public void lcnNotification_InstantiateStartingOrProcessing_NoAction() + throws URISyntaxException, InterruptedException { + final VnfLcmOperationOccurrenceNotification startingNotification = new VnfLcmOperationOccurrenceNotification(); + startingNotification.setOperation(OperationEnum.INSTANTIATE); + startingNotification.setOperationState(OperationStateEnum.STARTING); + + ResponseEntity<Void> response = controller.lcnVnfLcmOperationOccurrenceNotificationPost(startingNotification); + assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode()); + + verifyZeroInteractions(aaiResourcesClient); + + final VnfLcmOperationOccurrenceNotification processingNotification = + new VnfLcmOperationOccurrenceNotification(); + processingNotification.setOperation(OperationEnum.INSTANTIATE); + processingNotification.setOperationState(OperationStateEnum.STARTING); + + response = controller.lcnVnfLcmOperationOccurrenceNotificationPost(processingNotification); + assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode()); + + verifyZeroInteractions(aaiResourcesClient); + } + + @Test + public void lcnNotification_InstantiateCompleted_AaiUpdated() throws URISyntaxException, InterruptedException { + final VnfLcmOperationOccurrenceNotification vnfLcmOperationOccurrenceNotification = + createNotification(OperationEnum.INSTANTIATE); + addVnfcsToNotification(vnfLcmOperationOccurrenceNotification, ChangeTypeEnum.ADDED); + final InlineResponse201 vnfInstance = createVnfInstance(); + + mockRestServer.expect(requestTo(new URI("http://vnfm:8080/vnfs/myTestVnfIdOnVnfm"))) + .andRespond(withSuccess(gson.toJson(vnfInstance), MediaType.APPLICATION_JSON)); + + final GenericVnf genericVnf = createGenericVnf("vnfmType1"); + addRelationshipFromGenericVnfToVnfm(genericVnf, "vnfm1"); + final List<GenericVnf> listOfGenericVnfs = new ArrayList<>(); + listOfGenericVnfs.add(genericVnf); + final GenericVnfs genericVnfs = new GenericVnfs(); + genericVnfs.getGenericVnf().addAll(listOfGenericVnfs); + doReturn(Optional.of(genericVnfs)).when(aaiResourcesClient).get(eq(GenericVnfs.class), + MockitoHamcrest.argThat(new AaiResourceUriMatcher( + "/network/generic-vnfs?selflink=http%3A%2F%2Fvnfm%3A8080%2Fvnfs%2FmyTestVnfIdOnVnfm"))); + EsrVnfm vnfm = new EsrVnfm(); + vnfm.setVnfmId("vnfm1"); + final EsrSystemInfoList esrSystemInfoList = new EsrSystemInfoList(); + vnfm.setEsrSystemInfoList(esrSystemInfoList); + doReturn(Optional.of(vnfm)).when(aaiResourcesClient).get(eq(EsrVnfm.class), MockitoHamcrest + .argThat(new AaiResourceUriMatcher("/external-system/esr-vnfm-list/esr-vnfm/vnfm1?depth=1"))); + + final ResponseEntity<Void> response = + controller.lcnVnfLcmOperationOccurrenceNotificationPost(vnfLcmOperationOccurrenceNotification); + assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode()); + + final ArgumentCaptor<Object> bodyArgument1 = ArgumentCaptor.forClass(Object.class); + final ArgumentCaptor<AAIResourceUri> uriArgument1 = ArgumentCaptor.forClass(AAIResourceUri.class); + + verify(aaiResourcesClient, timeout(1000)).update(uriArgument1.capture(), bodyArgument1.capture()); + + assertEquals("/network/generic-vnfs/generic-vnf/myTestVnfId", + uriArgument1.getAllValues().get(0).build().toString()); + final GenericVnf updatedGenericVnf = (GenericVnf) bodyArgument1.getAllValues().get(0); + assertEquals("10.10.10.10", updatedGenericVnf.getIpv4OamAddress()); + assertEquals("Created", updatedGenericVnf.getOrchestrationStatus()); + + final ArgumentCaptor<Object> bodyArgument2 = ArgumentCaptor.forClass(Object.class); + final ArgumentCaptor<AAIResourceUri> uriArgument2 = ArgumentCaptor.forClass(AAIResourceUri.class); + verify(aaiResourcesClient, timeout(1000)).create(uriArgument2.capture(), bodyArgument2.capture()); + + assertEquals( + "/cloud-infrastructure/cloud-regions/cloud-region/" + CLOUD_OWNER + "/" + REGION + "/tenants/tenant/" + + TENANT_ID + "/vservers/vserver/myVnfc1", + uriArgument2.getAllValues().get(0).build().toString()); + + final Vserver vserver = (Vserver) bodyArgument2.getAllValues().get(0); + assertEquals("myVnfc1", vserver.getVserverId()); + + final ArgumentCaptor<AAIResourceUri> uriArgument1Connect = ArgumentCaptor.forClass(AAIResourceUri.class); + final ArgumentCaptor<AAIResourceUri> uriArgument2Connect = ArgumentCaptor.forClass(AAIResourceUri.class); + verify(aaiResourcesClient, timeout(1000)).connect(uriArgument1Connect.capture(), uriArgument2Connect.capture()); + assertEquals( + "/cloud-infrastructure/cloud-regions/cloud-region/" + CLOUD_OWNER + "/" + REGION + "/tenants/tenant/" + + TENANT_ID + "/vservers/vserver/myVnfc1", + uriArgument1Connect.getAllValues().get(0).build().toString()); + assertEquals("/network/generic-vnfs/generic-vnf/myTestVnfId", + uriArgument2Connect.getAllValues().get(0).build().toString()); + } + + @Test + public void lcnNotification_TerminateCompleted_AaiUpdated() throws URISyntaxException, InterruptedException { + final VnfLcmOperationOccurrenceNotification vnfLcmOperationOccurrenceNotification = + createNotification(OperationEnum.TERMINATE); + addVnfcsToNotification(vnfLcmOperationOccurrenceNotification, ChangeTypeEnum.REMOVED); + + final InlineResponse201 vnfInstance = createVnfInstance(); + + mockRestServer.expect(requestTo(new URI("http://vnfm:8080/vnfs/myTestVnfIdOnVnfm"))) + .andRespond(withSuccess(gson.toJson(vnfInstance), MediaType.APPLICATION_JSON)); + + mockRestServer.expect(requestTo(new URI("http://vnfm:8080/vnfs/myTestVnfIdOnVnfm"))) + .andRespond(withStatus(HttpStatus.NO_CONTENT).contentType(MediaType.APPLICATION_JSON)); + + final GenericVnf genericVnf = createGenericVnf("vnfmType1"); + addRelationshipFromGenericVnfToVnfm(genericVnf, "vnfm1"); + genericVnf.setSelflink("http://vnfm:8080/vnfs/myTestVnfIdOnVnfm"); + final List<GenericVnf> listOfGenericVnfs = new ArrayList<>(); + listOfGenericVnfs.add(genericVnf); + final GenericVnfs genericVnfs = new GenericVnfs(); + genericVnfs.getGenericVnf().addAll(listOfGenericVnfs); + addRelationshipFromGenericVnfToVserver(genericVnf, "myVnfc1"); + + doReturn(Optional.of(genericVnfs)).when(aaiResourcesClient).get(eq(GenericVnfs.class), + MockitoHamcrest.argThat(new AaiResourceUriMatcher( + "/network/generic-vnfs?selflink=http%3A%2F%2Fvnfm%3A8080%2Fvnfs%2FmyTestVnfIdOnVnfm"))); + EsrVnfm vnfm = new EsrVnfm(); + vnfm.setVnfmId("vnfm1"); + final EsrSystemInfoList esrSystemInfoList = new EsrSystemInfoList(); + vnfm.setEsrSystemInfoList(esrSystemInfoList); + doReturn(Optional.of(vnfm)).when(aaiResourcesClient).get(eq(EsrVnfm.class), MockitoHamcrest + .argThat(new AaiResourceUriMatcher("/external-system/esr-vnfm-list/esr-vnfm/vnfm1?depth=1"))); + + final ResponseEntity<Void> response = + controller.lcnVnfLcmOperationOccurrenceNotificationPost(vnfLcmOperationOccurrenceNotification); + assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode()); + + final ArgumentCaptor<GenericVnf> genericVnfArgument = ArgumentCaptor.forClass(GenericVnf.class); + final ArgumentCaptor<AAIResourceUri> updateUriArgument = ArgumentCaptor.forClass(AAIResourceUri.class); + verify(aaiResourcesClient, timeout(10000000)).update(updateUriArgument.capture(), genericVnfArgument.capture()); + assertEquals("/network/generic-vnfs/generic-vnf/myTestVnfId", updateUriArgument.getValue().build().toString()); + assertEquals("Assigned", genericVnfArgument.getValue().getOrchestrationStatus()); + + final ArgumentCaptor<AAIResourceUri> deleteUriArgument = ArgumentCaptor.forClass(AAIResourceUri.class); + + verify(aaiResourcesClient, timeout(10000000)).delete(deleteUriArgument.capture()); + + assertEquals( + "/cloud-infrastructure/cloud-regions/cloud-region/" + CLOUD_OWNER + "/" + REGION + "/tenants/tenant/" + + TENANT_ID + "/vservers/vserver/myVnfc1", + deleteUriArgument.getAllValues().get(0).build().toString()); + } + + private VnfLcmOperationOccurrenceNotification createNotification(final OperationEnum operation) { + final VnfLcmOperationOccurrenceNotification notification = new VnfLcmOperationOccurrenceNotification(); + notification.setOperation(operation); + notification.setOperationState(OperationStateEnum.COMPLETED); + + final LcnVnfLcmOperationOccurrenceNotificationLinksVnfInstance linkToVnfInstance = + new LcnVnfLcmOperationOccurrenceNotificationLinksVnfInstance() + .href("http://vnfm:8080/vnfs/myTestVnfIdOnVnfm"); + final LcnVnfLcmOperationOccurrenceNotificationLinks operationLinks = + new LcnVnfLcmOperationOccurrenceNotificationLinks().vnfInstance(linkToVnfInstance); + notification.setLinks(operationLinks); + + return notification; + } + + private void addVnfcsToNotification(final VnfLcmOperationOccurrenceNotification notification, + final ChangeTypeEnum changeType) { + final List<LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs> affectedVnfcs = new ArrayList<>();; + final LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs vnfc = + new LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs(); + vnfc.changeType(changeType); + final LcnVnfLcmOperationOccurrenceNotificationComputeResource computeResource = + new LcnVnfLcmOperationOccurrenceNotificationComputeResource(); + computeResource.setResourceId("myVnfc1"); + computeResource.setVimConnectionId(CLOUD_OWNER + "_" + REGION); + vnfc.setComputeResource(computeResource); + affectedVnfcs.add(vnfc); + notification.setAffectedVnfcs(affectedVnfcs); + } + + private InlineResponse201 createVnfInstance() { + final InlineResponse201 vnfInstance = new InlineResponse201(); + vnfInstance.setId("myTestVnfIdOnVnfm"); + final InlineResponse201LinksSelf selfLink = new InlineResponse201LinksSelf(); + selfLink.setHref("http://vnfm:8080/vnfs/myTestVnfIdOnVnfm"); + final InlineResponse201Links VnfInstancelinks = new InlineResponse201Links(); + VnfInstancelinks.setSelf(selfLink); + vnfInstance.setLinks(VnfInstancelinks); + + final Map<String, String> vnfConfigurableProperties = new HashMap<>(); + vnfConfigurableProperties.put("vnfIpAddress", "10.10.10.10"); + vnfInstance.setVnfConfigurableProperties(vnfConfigurableProperties); + + final List<InlineResponse201VimConnectionInfo> vimConnectionInfo = new ArrayList<>();; + final InlineResponse201VimConnectionInfo vimConnection = new InlineResponse201VimConnectionInfo(); + vimConnection.setVimId(CLOUD_OWNER + "_" + REGION); + vimConnection.setId(CLOUD_OWNER + "_" + REGION); + final AccessInfo accessInfo = new AccessInfo(); + accessInfo.setProjectId(TENANT_ID); + vimConnection.setAccessInfo(accessInfo); + vimConnectionInfo.add(vimConnection); + vnfInstance.setVimConnectionInfo(vimConnectionInfo); + + final OamIpAddressSource oamIpAddressSource = + new OamIpAddressSource(OamIpAddressType.CONFIGURABLE_PROPERTY, "vnfIpAddress"); + aaiHelper.setOamIpAddressSource("myTestVnfIdOnVnfm", oamIpAddressSource); + return vnfInstance; + } + + private GenericVnf createGenericVnf(final String type) { + final GenericVnf genericVnf = new GenericVnf(); + genericVnf.setVnfId("myTestVnfId"); + genericVnf.setNfType(type); + return genericVnf; + } + + private void addRelationshipFromGenericVnfToVnfm(final GenericVnf genericVnf, final String vnfmId) { + final Relationship relationshipToVnfm = new Relationship(); + relationshipToVnfm.setRelatedLink("/aai/v15/external-system/esr-vnfm-list/esr-vnfm/" + vnfmId); + relationshipToVnfm.setRelatedTo("esr-vnfm"); + final RelationshipData relationshipData = new RelationshipData(); + relationshipData.setRelationshipKey("esr-vnfm.vnfm-id"); + relationshipData.setRelationshipValue(vnfmId); + relationshipToVnfm.getRelationshipData().add(relationshipData); + + if (genericVnf.getRelationshipList() == null) { + final RelationshipList relationshipList = new RelationshipList(); + genericVnf.setRelationshipList(relationshipList); + } + genericVnf.getRelationshipList().getRelationship().add(relationshipToVnfm); + } + + private void addRelationshipFromGenericVnfToVserver(final GenericVnf genericVnf, final String vserverId) { + final Relationship relationshipToVserver = new Relationship(); + relationshipToVserver.setRelatedTo("vserver"); + final RelationshipData relationshipData1 = new RelationshipData(); + relationshipData1.setRelationshipKey("vserver.vserver-id"); + relationshipData1.setRelationshipValue(vserverId); + relationshipToVserver.getRelationshipData().add(relationshipData1); + final RelationshipData relationshipData2 = new RelationshipData(); + relationshipData2.setRelationshipKey("cloud-region.cloud-owner"); + relationshipData2.setRelationshipValue(CLOUD_OWNER); + relationshipToVserver.getRelationshipData().add(relationshipData2); + final RelationshipData relationshipData3 = new RelationshipData(); + relationshipData3.setRelationshipKey("cloud-region.cloud-region-id"); + relationshipData3.setRelationshipValue(REGION); + relationshipToVserver.getRelationshipData().add(relationshipData3); + final RelationshipData relationshipData4 = new RelationshipData(); + relationshipData4.setRelationshipKey("tenant.tenant-id"); + relationshipData4.setRelationshipValue(TENANT_ID); + relationshipToVserver.getRelationshipData().add(relationshipData4); + + if (genericVnf.getRelationshipList() == null) { + final RelationshipList relationshipList = new RelationshipList(); + genericVnf.setRelationshipList(relationshipList); + } + genericVnf.getRelationshipList().getRelationship().add(relationshipToVserver); + } + + private class AaiResourceUriMatcher extends BaseMatcher<AAIResourceUri> { + + final String uriAsString; + + public AaiResourceUriMatcher(final String uriAsString) { + this.uriAsString = uriAsString; + } + + @Override + public boolean matches(final Object item) { + if (item instanceof AAIResourceUri) { + if (uriAsString.endsWith("...")) { + return ((AAIResourceUri) item).build().toString() + .startsWith(uriAsString.substring(0, uriAsString.indexOf("..."))); + } + return ((AAIResourceUri) item).build().toString().equals(uriAsString); + } + return false; + } + + @Override + public void describeTo(final Description description) {} + + } + +} diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/test/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/rest/TestApplication.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/test/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/rest/TestApplication.java new file mode 100755 index 0000000000..9c2453db85 --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/test/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/rest/TestApplication.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.etsi.sol003.adapter.lcm.rest; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; +import org.springframework.cache.annotation.EnableCaching; + +@EnableCaching +@SpringBootApplication(scanBasePackages = {"org.onap.so"}) +@EnableAutoConfiguration(exclude = {JacksonAutoConfiguration.class}) +public class TestApplication { + + public static void main(final String[] args) { + new SpringApplication(TestApplication.class).run(args); + } + +} diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/test/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/rest/VnfmAdapterControllerTest.java b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/test/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/rest/VnfmAdapterControllerTest.java new file mode 100644 index 0000000000..4280e579be --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/test/java/org/onap/so/adapters/etsi/sol003/adapter/lcm/rest/VnfmAdapterControllerTest.java @@ -0,0 +1,561 @@ +/*- + * ============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.etsi.sol003.adapter.lcm.rest; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.verify; +import static org.onap.so.client.RestTemplateConfig.CONFIGURABLE_REST_TEMPLATE; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.content; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.requestTo; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withBadRequest; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; +import java.net.URI; +import java.util.Optional; +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.junit.Before; +import org.junit.Ignore; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.hamcrest.MockitoHamcrest; +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.RelationshipList; +import org.onap.etsi.sol003.adapter.lcm.v1.model.CreateVnfRequest; +import org.onap.etsi.sol003.adapter.lcm.v1.model.CreateVnfResponse; +import org.onap.etsi.sol003.adapter.lcm.v1.model.DeleteVnfResponse; +import org.onap.etsi.sol003.adapter.lcm.v1.model.OperationEnum; +import org.onap.etsi.sol003.adapter.lcm.v1.model.OperationStateEnum; +import org.onap.etsi.sol003.adapter.lcm.v1.model.QueryJobResponse; +import org.onap.etsi.sol003.adapter.lcm.v1.model.Tenant; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.SdcPackageProvider; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse200; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse2001; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse201; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse201.InstantiationStateEnum; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse201Links; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse201LinksSelf; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.lcn.JSON; +import org.onap.so.adapters.etsi.sol003.adapter.lcm.rest.exceptions.VnfmNotFoundException; +import org.onap.so.client.aai.AAIResourcesClient; +import org.onap.so.client.aai.AAIVersion; +import org.onap.so.client.aai.entities.uri.AAIResourceUri; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.RequestEntity; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.client.MockRestServiceServer; +import org.springframework.web.client.RestTemplate; +import org.threeten.bp.LocalDateTime; +import org.threeten.bp.OffsetDateTime; +import org.threeten.bp.ZoneOffset; +import com.google.gson.Gson; + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = TestApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT) +@ActiveProfiles("test") +public class VnfmAdapterControllerTest { + + private static final OffsetDateTime JAN_1_2019_12_00 = + OffsetDateTime.of(LocalDateTime.of(2019, 1, 1, 12, 0), ZoneOffset.UTC); + private static final OffsetDateTime JAN_1_2019_1_00 = + OffsetDateTime.of(LocalDateTime.of(2019, 1, 1, 1, 0), ZoneOffset.UTC); + private static final String CLOUD_OWNER = "myTestCloudOwner"; + private static final String REGION = "myTestRegion"; + private static final String TENANT_ID = "myTestTenantId"; + + @LocalServerPort + private int port; + @Autowired + @Qualifier(CONFIGURABLE_REST_TEMPLATE) + private RestTemplate testRestTemplate; + private MockRestServiceServer mockRestServer; + + @MockBean + AAIResourcesClient aaiResourcesClient; + + @MockBean + SdcPackageProvider sdcPackageProvider; + + @Autowired + VnfmAdapterController controller; + Gson gson = new JSON().getGson(); + + @Before + public void setUp() throws Exception { + mockRestServer = MockRestServiceServer.bindTo(testRestTemplate).build(); + } + + @Test + public void createVnf_ValidRequest_Returns202AndJobId() throws Exception { + final Tenant tenant = new Tenant().cloudOwner(CLOUD_OWNER).regionName(REGION).tenantId(TENANT_ID); + final CreateVnfRequest createVnfRequest = new CreateVnfRequest().name("myTestName").tenant(tenant); + + setUpGenericVnfInMockAai("vnfmType2"); + setUpVnfmsInMockAai(); + setUpVimInMockAai(); + + final String expectedsubscriptionRequest = + "{\"filter\":{\"vnfInstanceSubscriptionFilter\":{\"vnfInstanceIds\":[\"vnfId\"]},\"notificationTypes\":[\"VnfLcmOperationOccurrenceNotification\"]},\"callbackUri\":\"https://so-vnfm-adapter.onap:30406/so/vnfm-adapter/v1/lcn/VnfLcmOperationOccurrenceNotification\",\"authentication\":{\"authType\":[\"OAUTH2_CLIENT_CREDENTIALS\", \"BASIC\", \"TLS_CERT\"],\"paramsOauth2ClientCredentials\":{\"clientId\":\"vnfm\",\"clientPassword\":\"password1$\",\"tokenEndpoint\":\"https://so-vnfm-adapter.onap:30406/oauth/token\"},\"paramsBasic\":{\"userName\":\"vnfm\",\"password\":\"password1$\"}}}"; + final InlineResponse2001 subscriptionResponse = new InlineResponse2001(); + + final InlineResponse201 createResponse = createCreateResponse(); + mockRestServer.expect(requestTo("http://vnfm2:8080/vnf_instances")) + .andRespond(withSuccess(gson.toJson(createResponse), MediaType.APPLICATION_JSON)); + + mockRestServer.expect(requestTo("http://vnfm2:8080/subscriptions")) + .andExpect(content().json(expectedsubscriptionRequest)) + .andRespond(withSuccess(gson.toJson(subscriptionResponse), MediaType.APPLICATION_JSON)); + + mockRestServer.expect(requestTo("http://vnfm2:8080/vnf_instances/vnfId/instantiate")) + .andRespond(withStatus(HttpStatus.ACCEPTED).contentType(MediaType.APPLICATION_JSON) + .location(new URI("http://vnfm2:8080/vnf_lcm_op_occs/123456"))); + + final InlineResponse200 firstOperationQueryResponse = createOperationQueryResponse( + org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse200.OperationEnum.INSTANTIATE, + org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse200.OperationStateEnum.PROCESSING); + mockRestServer.expect(requestTo("http://vnfm2:8080/vnf_lcm_op_occs/123456")) + .andRespond(withSuccess(gson.toJson(firstOperationQueryResponse), MediaType.APPLICATION_JSON)); + + final InlineResponse200 secondOperationQueryReponse = createOperationQueryResponse( + org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse200.OperationEnum.INSTANTIATE, + org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse200.OperationStateEnum.COMPLETED); + mockRestServer.expect(requestTo("http://vnfm2:8080/vnf_lcm_op_occs/123456")) + .andRespond(withSuccess(gson.toJson(secondOperationQueryReponse), MediaType.APPLICATION_JSON)); + + // Invoke the create request + + final ResponseEntity<CreateVnfResponse> createVnfResponse = + controller.vnfCreate("myTestVnfId", createVnfRequest, "asadas", "so", "1213"); + assertEquals(HttpStatus.ACCEPTED, createVnfResponse.getStatusCode()); + assertNotNull(createVnfResponse.getBody().getJobId()); + + final ArgumentCaptor<GenericVnf> genericVnfArgument = ArgumentCaptor.forClass(GenericVnf.class); + final ArgumentCaptor<AAIResourceUri> uriArgument = ArgumentCaptor.forClass(AAIResourceUri.class); + + verify(aaiResourcesClient).update(uriArgument.capture(), genericVnfArgument.capture()); + + assertEquals("/network/generic-vnfs/generic-vnf/myTestVnfId", uriArgument.getValue().build().toString()); + + assertEquals("myTestVnfId", genericVnfArgument.getValue().getVnfId()); + + final ArgumentCaptor<AAIResourceUri> uriArgument1Connect = ArgumentCaptor.forClass(AAIResourceUri.class); + final ArgumentCaptor<AAIResourceUri> uriArgument2Connect = ArgumentCaptor.forClass(AAIResourceUri.class); + verify(aaiResourcesClient, timeout(1000)).connect(uriArgument1Connect.capture(), uriArgument2Connect.capture()); + assertEquals("/external-system/esr-vnfm-list/esr-vnfm/vnfm2", + uriArgument1Connect.getAllValues().get(0).build().toString()); + assertEquals("/network/generic-vnfs/generic-vnf/myTestVnfId", + uriArgument2Connect.getAllValues().get(0).build().toString()); + + // check the job status + + final ResponseEntity<QueryJobResponse> firstJobQueryResponse = + controller.jobQuery(createVnfResponse.getBody().getJobId(), "", "so", "1213"); + assertEquals(OperationEnum.INSTANTIATE, firstJobQueryResponse.getBody().getOperation()); + assertEquals(OperationStateEnum.PROCESSING, firstJobQueryResponse.getBody().getOperationState()); + assertEquals(JAN_1_2019_12_00, firstJobQueryResponse.getBody().getStartTime()); + assertEquals(JAN_1_2019_1_00, firstJobQueryResponse.getBody().getStateEnteredTime()); + + final ResponseEntity<QueryJobResponse> secondJobQueryResponse = + controller.jobQuery(createVnfResponse.getBody().getJobId(), "", "so", "1213"); + assertEquals(OperationEnum.INSTANTIATE, secondJobQueryResponse.getBody().getOperation()); + assertEquals(OperationStateEnum.COMPLETED, secondJobQueryResponse.getBody().getOperationState()); + assertEquals(JAN_1_2019_12_00, secondJobQueryResponse.getBody().getStartTime()); + assertEquals(JAN_1_2019_1_00, secondJobQueryResponse.getBody().getStateEnteredTime()); + } + + @Test(expected = IllegalArgumentException.class) + public void createVnf_VnfAlreadyExistsOnVnfm_ThrowsIllegalArgumentException() throws Exception { + final Tenant tenant = new Tenant().cloudOwner(CLOUD_OWNER).regionName(REGION).tenantId(TENANT_ID); + final CreateVnfRequest createVnfRequest = new CreateVnfRequest().name("myTestName").tenant(tenant); + + final GenericVnf genericVnf = setUpGenericVnfInMockAai("vnfmType1"); + addSelfLinkToGenericVnf(genericVnf); + addRelationshipFromGenericVnfToVnfm(genericVnf, "vnfm1"); + setUpVnfmsInMockAai(); + + final InlineResponse201 reponse = new InlineResponse201(); + mockRestServer.expect(requestTo(new URI("http://vnfm:8080/vnfs/myTestVnfIdOnVnfm"))) + .andRespond(withSuccess(gson.toJson(reponse), MediaType.APPLICATION_JSON)); + + controller.vnfCreate("myTestVnfId", createVnfRequest, "asadas", "so", "1213"); + } + + @Test(expected = VnfmNotFoundException.class) + public void createVnf_NoMatchingVnfmFound_ThrowsException() throws Exception { + final Tenant tenant = new Tenant().cloudOwner(CLOUD_OWNER).regionName(REGION).tenantId(TENANT_ID); + final CreateVnfRequest createVnfRequest = new CreateVnfRequest().name("myTestName").tenant(tenant); + + setUpGenericVnfInMockAai("anotherType"); + setUpVnfmsInMockAai(); + + controller.vnfCreate("myTestVnfId", createVnfRequest, "asadas", "so", "1213"); + } + + @Test + public void createVnf_VnfmAlreadyAssociatedWithVnf_Returns202AndJobId() throws Exception { + final Tenant tenant = new Tenant().cloudOwner(CLOUD_OWNER).regionName(REGION).tenantId(TENANT_ID); + final CreateVnfRequest createVnfRequest = new CreateVnfRequest().name("myTestName").tenant(tenant); + + final GenericVnf genericVnf = setUpGenericVnfInMockAai("vnfmType2"); + addRelationshipFromGenericVnfToVnfm(genericVnf, "vnfm2"); + setUpVnfmsInMockAai(); + setUpVimInMockAai(); + + final InlineResponse201 createResponse = createCreateResponse(); + mockRestServer.expect(requestTo("http://vnfm2:8080/vnf_instances")) + .andRespond(withSuccess(gson.toJson(createResponse), MediaType.APPLICATION_JSON)); + + mockRestServer.expect(requestTo("http://vnfm2:8080/subscriptions")).andRespond(withBadRequest()); + + mockRestServer.expect(requestTo("http://vnfm2:8080/vnf_instances/vnfId/instantiate")) + .andRespond(withStatus(HttpStatus.ACCEPTED).contentType(MediaType.APPLICATION_JSON) + .location(new URI("http://vnfm2:8080/vnf_lcm_op_occs/123456"))); + + final ResponseEntity<CreateVnfResponse> response = + controller.vnfCreate("myTestVnfId", createVnfRequest, "asadas", "so", "1213"); + assertEquals(HttpStatus.ACCEPTED, response.getStatusCode()); + assertNotNull(response.getBody().getJobId()); + } + + @Test + @Ignore + public void createVnf_UnauthorizedUser_Returns401() throws Exception { + final TestRestTemplate restTemplateWrongPassword = new TestRestTemplate("test", "wrongPassword"); + final Tenant tenant = new Tenant().cloudOwner(CLOUD_OWNER).regionName(REGION).tenantId(TENANT_ID); + final CreateVnfRequest createVnfRequest = new CreateVnfRequest().name("myTestName").tenant(tenant); + + final RequestEntity<CreateVnfRequest> request = + RequestEntity.post(new URI("http://localhost:" + port + "/so/vnfm-adapter/v1/vnfs/myVnfId")) + .accept(MediaType.APPLICATION_JSON).contentType(MediaType.APPLICATION_JSON) + .header("X-ONAP-RequestId", "myRequestId").header("X-ONAP-InvocationID", "myInvocationId") + .body(createVnfRequest); + final ResponseEntity<CreateVnfResponse> response = + restTemplateWrongPassword.exchange(request, CreateVnfResponse.class); + assertEquals(401, response.getStatusCode().value()); + } + + @Test + public void deleteVnf_ValidRequest_Returns202AndJobId() throws Exception { + final TestRestTemplate restTemplate = new TestRestTemplate("test", "test"); + + final GenericVnf genericVnf = setUpGenericVnfInMockAai("vnfmType1"); + addSelfLinkToGenericVnf(genericVnf); + addRelationshipFromGenericVnfToVnfm(genericVnf, "vnfm1"); + setUpVnfmsInMockAai(); + + mockRestServer.expect(requestTo("http://vnfm:8080/vnfs/myTestVnfIdOnVnfm/terminate")) + .andRespond(withStatus(HttpStatus.ACCEPTED).contentType(MediaType.APPLICATION_JSON) + .location(new URI("http://vnfm1:8080/vnf_lcm_op_occs/1234567"))); + + final InlineResponse200 firstOperationQueryResponse = createOperationQueryResponse( + org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse200.OperationEnum.TERMINATE, + org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse200.OperationStateEnum.PROCESSING); + mockRestServer.expect(requestTo("http://vnfm1:8080/vnf_lcm_op_occs/1234567")) + .andRespond(withSuccess(gson.toJson(firstOperationQueryResponse), MediaType.APPLICATION_JSON)); + + final InlineResponse200 secondOperationQueryReponse = createOperationQueryResponse( + org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse200.OperationEnum.TERMINATE, + org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse200.OperationStateEnum.COMPLETED); + mockRestServer.expect(requestTo("http://vnfm1:8080/vnf_lcm_op_occs/1234567")) + .andRespond(withSuccess(gson.toJson(secondOperationQueryReponse), MediaType.APPLICATION_JSON)); + + final RequestEntity<Void> request = RequestEntity + .delete(new URI("http://localhost:" + port + "/so/vnfm-adapter/v1/vnfs/myTestVnfId")) + .accept(MediaType.APPLICATION_JSON).header("X-ONAP-RequestId", "myRequestId") + .header("X-ONAP-InvocationID", "myInvocationId").header("Content-Type", "application/json").build(); + final ResponseEntity<DeleteVnfResponse> deleteVnfResponse = + restTemplate.exchange(request, DeleteVnfResponse.class); + assertEquals(202, deleteVnfResponse.getStatusCode().value()); + assertNotNull(deleteVnfResponse.getBody().getJobId()); + + final ResponseEntity<QueryJobResponse> firstJobQueryResponse = + controller.jobQuery(deleteVnfResponse.getBody().getJobId(), "", "so", "1213"); + assertEquals(OperationEnum.TERMINATE, firstJobQueryResponse.getBody().getOperation()); + assertEquals(OperationStateEnum.PROCESSING, firstJobQueryResponse.getBody().getOperationState()); + assertEquals(JAN_1_2019_12_00, firstJobQueryResponse.getBody().getStartTime()); + assertEquals(JAN_1_2019_1_00, firstJobQueryResponse.getBody().getStateEnteredTime()); + + final ResponseEntity<QueryJobResponse> secondJobQueryResponse = + controller.jobQuery(deleteVnfResponse.getBody().getJobId(), "", "so", "1213"); + assertEquals(OperationEnum.TERMINATE, secondJobQueryResponse.getBody().getOperation()); + assertEquals(OperationStateEnum.PROCESSING, secondJobQueryResponse.getBody().getOperationState()); + assertEquals(JAN_1_2019_12_00, secondJobQueryResponse.getBody().getStartTime()); + assertEquals(JAN_1_2019_1_00, secondJobQueryResponse.getBody().getStateEnteredTime()); + } + + @Test + public void deleteVnf_VnfAlreadyTerminated_Returns202AndJobId() throws Exception { + final TestRestTemplate restTemplate = new TestRestTemplate("test", "test"); + + final GenericVnf genericVnf = setUpGenericVnfInMockAai("vnfmType1"); + addSelfLinkToGenericVnf(genericVnf); + addRelationshipFromGenericVnfToVnfm(genericVnf, "vnfm1"); + setUpVnfmsInMockAai(); + + mockRestServer.expect(requestTo("http://vnfm:8080/vnfs/myTestVnfIdOnVnfm/terminate")) + .andRespond(withStatus(HttpStatus.CONFLICT).contentType(MediaType.APPLICATION_JSON)); + + final InlineResponse201 reponse = new InlineResponse201(); + reponse.setInstantiationState(InstantiationStateEnum.NOT_INSTANTIATED); + mockRestServer.expect(requestTo(new URI("http://vnfm:8080/vnfs/myTestVnfIdOnVnfm"))) + .andRespond(withSuccess(gson.toJson(reponse), MediaType.APPLICATION_JSON)); + + mockRestServer.expect(requestTo("http://vnfm:8080/vnfs/myTestVnfIdOnVnfm")) + .andRespond(withStatus(HttpStatus.NO_CONTENT).contentType(MediaType.APPLICATION_JSON)); + + final RequestEntity<Void> request = RequestEntity + .delete(new URI("http://localhost:" + port + "/so/vnfm-adapter/v1/vnfs/myTestVnfId")) + .accept(MediaType.APPLICATION_JSON).header("X-ONAP-RequestId", "myRequestId") + .header("X-ONAP-InvocationID", "myInvocationId").header("Content-Type", "application/json").build(); + final ResponseEntity<DeleteVnfResponse> deleteVnfResponse = + restTemplate.exchange(request, DeleteVnfResponse.class); + assertEquals(202, deleteVnfResponse.getStatusCode().value()); + assertNotNull(deleteVnfResponse.getBody().getJobId()); + + final ResponseEntity<QueryJobResponse> jobQueryResponse = + controller.jobQuery(deleteVnfResponse.getBody().getJobId(), "", "so", "1213"); + assertEquals(OperationStateEnum.COMPLETED, jobQueryResponse.getBody().getOperationState()); + } + + @Test + public void deleteVnf_GenericVnfNotFound_Returns404() throws Exception { + final TestRestTemplate restTemplate = new TestRestTemplate("test", "test"); + + final RequestEntity<Void> request = RequestEntity + .delete(new URI("http://localhost:" + port + "/so/vnfm-adapter/v1/vnfs/myNonExistingVnfId")) + .accept(MediaType.APPLICATION_JSON).header("X-ONAP-RequestId", "myRequestId") + .header("X-ONAP-InvocationID", "myInvocationId").header("Content-Type", "application/json").build(); + final ResponseEntity<DeleteVnfResponse> deleteVnfResponse = + restTemplate.exchange(request, DeleteVnfResponse.class); + assertEquals(404, deleteVnfResponse.getStatusCode().value()); + assertNull(deleteVnfResponse.getBody().getJobId()); + } + + @Test + public void deleteVnf_NoAssignedVnfm_Returns400() throws Exception { + final TestRestTemplate restTemplate = new TestRestTemplate("test", "test"); + + setUpGenericVnfInMockAai("vnfmType"); + + final RequestEntity<Void> request = RequestEntity + .delete(new URI("http://localhost:" + port + "/so/vnfm-adapter/v1/vnfs/myTestVnfId")) + .accept(MediaType.APPLICATION_JSON).header("X-ONAP-RequestId", "myRequestId") + .header("X-ONAP-InvocationID", "myInvocationId").header("Content-Type", "application/json").build(); + final ResponseEntity<DeleteVnfResponse> deleteVnfResponse = + restTemplate.exchange(request, DeleteVnfResponse.class); + assertEquals(400, deleteVnfResponse.getStatusCode().value()); + assertNull(deleteVnfResponse.getBody().getJobId()); + } + + @Test + public void deleteVnf_ErrorStatusCodeFromVnfm_Returns500() throws Exception { + final TestRestTemplate restTemplate = new TestRestTemplate("test", "test"); + + final GenericVnf genericVnf = setUpGenericVnfInMockAai("vnfmType1"); + addSelfLinkToGenericVnf(genericVnf); + addRelationshipFromGenericVnfToVnfm(genericVnf, "vnfm1"); + setUpVnfmsInMockAai(); + + mockRestServer.expect(requestTo("http://vnfm:8080/vnfs/myTestVnfIdOnVnfm/terminate")) + .andRespond(withStatus(HttpStatus.BAD_REQUEST).contentType(MediaType.APPLICATION_JSON)); + + final RequestEntity<Void> request = RequestEntity + .delete(new URI("http://localhost:" + port + "/so/vnfm-adapter/v1/vnfs/myTestVnfId")) + .accept(MediaType.APPLICATION_JSON).header("X-ONAP-RequestId", "myRequestId") + .header("X-ONAP-InvocationID", "myInvocationId").header("Content-Type", "application/json").build(); + final ResponseEntity<DeleteVnfResponse> deleteVnfResponse = + restTemplate.exchange(request, DeleteVnfResponse.class); + assertEquals(500, deleteVnfResponse.getStatusCode().value()); + assertNull(deleteVnfResponse.getBody().getJobId()); + + } + + private InlineResponse200 createOperationQueryResponse( + final org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse200.OperationEnum operation, + final org.onap.so.adapters.etsi.sol003.adapter.lcm.extclients.vnfm.model.InlineResponse200.OperationStateEnum operationState) { + final InlineResponse200 response = new InlineResponse200(); + response.setId("9876"); + response.setOperation(operation); + response.setOperationState(operationState); + response.setStartTime(JAN_1_2019_12_00); + response.setStateEnteredTime(JAN_1_2019_1_00); + response.setVnfInstanceId("myVnfInstanceId"); + return response; + } + + private GenericVnf createGenericVnf(final String type) { + final GenericVnf genericVnf = new GenericVnf(); + genericVnf.setVnfId("myTestVnfId"); + genericVnf.setNfType(type); + return genericVnf; + } + + private GenericVnf setUpGenericVnfInMockAai(final String type) { + final GenericVnf genericVnf = createGenericVnf(type); + + doReturn(Optional.of(genericVnf)).when(aaiResourcesClient).get(eq(GenericVnf.class), + MockitoHamcrest.argThat(new AaiResourceUriMatcher("/network/generic-vnfs/generic-vnf/myTestVnfId"))); + return genericVnf; + } + + private void addSelfLinkToGenericVnf(final GenericVnf vnf) { + vnf.setSelflink("http://vnfm:8080/vnfs/myTestVnfIdOnVnfm"); + } + + private void addRelationshipFromGenericVnfToVnfm(final GenericVnf genericVnf, final String vnfmId) { + final Relationship relationshipToVnfm = new Relationship(); + relationshipToVnfm + .setRelatedLink("/aai/" + AAIVersion.LATEST + "/external-system/esr-vnfm-list/esr-vnfm/" + vnfmId); + relationshipToVnfm.setRelatedTo("esr-vnfm"); + final RelationshipData relationshipData = new RelationshipData(); + relationshipData.setRelationshipKey("esr-vnfm.vnfm-id"); + relationshipData.setRelationshipValue(vnfmId); + relationshipToVnfm.getRelationshipData().add(relationshipData); + + final RelationshipList relationshipList = new RelationshipList(); + relationshipList.getRelationship().add(relationshipToVnfm); + genericVnf.setRelationshipList(relationshipList); + } + + private void setUpVnfmsInMockAai() { + final EsrSystemInfo esrSystemInfo1 = new EsrSystemInfo(); + esrSystemInfo1.setServiceUrl("http://vnfm1:8080"); + esrSystemInfo1.setType("vnfmType1"); + esrSystemInfo1.setSystemType("VNFM"); + final EsrSystemInfoList esrSystemInfoList1 = new EsrSystemInfoList(); + esrSystemInfoList1.getEsrSystemInfo().add(esrSystemInfo1); + + final EsrVnfm esrVnfm1 = new EsrVnfm(); + esrVnfm1.setVnfmId("vnfm1"); + esrVnfm1.setEsrSystemInfoList(esrSystemInfoList1); + esrVnfm1.setResourceVersion("1234"); + + final EsrSystemInfo esrSystemInfo2 = new EsrSystemInfo(); + esrSystemInfo2.setServiceUrl("http://vnfm2:8080"); + esrSystemInfo2.setType("vnfmType2"); + esrSystemInfo2.setSystemType("VNFM"); + final EsrSystemInfoList esrSystemInfoList2 = new EsrSystemInfoList(); + esrSystemInfoList2.getEsrSystemInfo().add(esrSystemInfo2); + + final EsrVnfm esrVnfm2 = new EsrVnfm(); + esrVnfm2.setVnfmId("vnfm2"); + esrVnfm2.setEsrSystemInfoList(esrSystemInfoList2); + esrVnfm2.setResourceVersion("1234"); + + final EsrVnfmList esrVnfmList = new EsrVnfmList(); + esrVnfmList.getEsrVnfm().add(esrVnfm1); + esrVnfmList.getEsrVnfm().add(esrVnfm2); + + doReturn(Optional.of(esrVnfm1)).when(aaiResourcesClient).get(eq(EsrVnfm.class), MockitoHamcrest + .argThat(new AaiResourceUriMatcher("/external-system/esr-vnfm-list/esr-vnfm/vnfm1?depth=1"))); + + doReturn(Optional.of(esrVnfm2)).when(aaiResourcesClient).get(eq(EsrVnfm.class), MockitoHamcrest + .argThat(new AaiResourceUriMatcher("/external-system/esr-vnfm-list/esr-vnfm/vnfm2?depth=1"))); + + doReturn(Optional.of(esrVnfmList)).when(aaiResourcesClient).get(eq(EsrVnfmList.class), + MockitoHamcrest.argThat(new AaiResourceUriMatcher("/external-system/esr-vnfm-list"))); + + doReturn(Optional.of(esrSystemInfoList1)).when(aaiResourcesClient).get(eq(EsrSystemInfoList.class), + MockitoHamcrest.argThat(new AaiResourceUriMatcher( + "/external-system/esr-vnfm-list/esr-vnfm/vnfm1/esr-system-info-list"))); + doReturn(Optional.of(esrSystemInfoList2)).when(aaiResourcesClient).get(eq(EsrSystemInfoList.class), + MockitoHamcrest.argThat(new AaiResourceUriMatcher( + "/external-system/esr-vnfm-list/esr-vnfm/vnfm2/esr-system-info-list"))); + } + + private void setUpVimInMockAai() { + final EsrSystemInfo esrSystemInfo = new EsrSystemInfo(); + esrSystemInfo.setServiceUrl("http://myVim:8080"); + esrSystemInfo.setType("openstack"); + esrSystemInfo.setSystemType("VIM"); + esrSystemInfo.setCloudDomain("myDomain"); + esrSystemInfo.setUserName("myUser"); + esrSystemInfo.setPassword("myPassword"); + + final EsrSystemInfoList esrSystemInfoList = new EsrSystemInfoList(); + esrSystemInfoList.getEsrSystemInfo().add(esrSystemInfo); + + doReturn(Optional.of(esrSystemInfoList)).when(aaiResourcesClient).get(eq(EsrSystemInfoList.class), + MockitoHamcrest.argThat(new AaiResourceUriMatcher("/cloud-infrastructure/cloud-regions/cloud-region/" + + CLOUD_OWNER + "/" + REGION + "/esr-system-info-list"))); + } + + private InlineResponse201 createCreateResponse() { + final InlineResponse201 createResponse = new InlineResponse201(); + createResponse.setVnfdId("myTestVnfd"); + final InlineResponse201Links links = new InlineResponse201Links(); + final InlineResponse201LinksSelf self = new InlineResponse201LinksSelf(); + self.setHref("http://vnfm2:8080/vnf_instances/vnfId"); + links.setSelf(self); + createResponse.setLinks(links); + createResponse.setId("vnfId"); + return createResponse; + } + + + private class AaiResourceUriMatcher extends BaseMatcher<AAIResourceUri> { + + final String uriAsString; + + public AaiResourceUriMatcher(final String uriAsString) { + this.uriAsString = uriAsString; + } + + @Override + public boolean matches(final Object item) { + if (item instanceof AAIResourceUri) { + if (uriAsString.endsWith("...")) { + return ((AAIResourceUri) item).build().toString() + .startsWith(uriAsString.substring(0, uriAsString.indexOf("..."))); + } + return ((AAIResourceUri) item).build().toString().equals(uriAsString); + } + return false; + } + + @Override + public void describeTo(final Description description) {} + + } + +} diff --git a/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/test/resources/application.yaml b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/test/resources/application.yaml new file mode 100644 index 0000000000..cdb6662191 --- /dev/null +++ b/adapters/etsi-sol003-adapter/etsi-sol003-lcm/etsi-sol003-lcm-adapter/src/test/resources/application.yaml @@ -0,0 +1,61 @@ +# Copyright © 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. +spring: + security: + usercredentials: + - username: test + password: '$2a$12$Zi3AuYcZoZO/gBQyUtST2.F5N6HqcTtaNci2Et.ufsQhski56srIu' + role: BPEL-Client + - username: vnfm + password: '$2a$10$Fh9ffgPw2vnmsghsRD3ZauBL1aKXebigbq3BB1RPWtE62UDILsjke' + role: BPEL-Client + main: + allow-bean-definition-overriding: true + +mso: + key: 07a7159d3bf51a0e53be7a8f89699be7 + +aai: + auth: 2A11B07DB6214A839394AA1EC5844695F5114FC407FF5422625FB00175A3DCB8A1FF745F22867EFA72D5369D599BBD88DA8BED4233CF5586 + endpoint: https://aai.onap:8443 + version: v15 + +sdc: + username: sdcUser + password: sdcPassword + key: adadadadad + endpoint: http://sdc.onap/1234A + + +vnfmadapter: + endpoint: https://so-vnfm-adapter.onap:30406 + + +#Actuator +management: + endpoints: + web: + base-path: /manage + exposure: + include: "*" + metrics: + se-global-registry: false + export: + prometheus: + enabled: true # Whether exporting of metrics to Prometheus is enabled. + step: 1m # Step size (i.e. reporting frequency) to use. + +etsi-catalog-manager: + vnfpkgm: + endpoint: http://msb-iag.onap:80/api/vnfpkgm/v1 |