diff options
14 files changed, 1208 insertions, 2 deletions
diff --git a/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/pom.xml b/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/pom.xml index 03f6f8c..73b5f0b 100644 --- a/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/pom.xml +++ b/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-bpmn-flows/pom.xml @@ -33,12 +33,12 @@ <dependencies> <dependency> - <groupId>org.onap.so.etsi.nfvo</groupId> + <groupId>org.onap.so.so-etsi-nfvo.ns.lcm</groupId> <artifactId>so-etsi-nfvo-ns-lcm-api</artifactId> <version>${project.version}</version> </dependency> <dependency> - <groupId>org.onap.so.etsi.nfvo</groupId> + <groupId>org.onap.so.so-etsi-nfvo.ns.lcm</groupId> <artifactId>so-etsi-nfvo-ns-lcm-database-service</artifactId> <version>${project.version}</version> </dependency> diff --git a/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/pom.xml b/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/pom.xml index 0571cab..2886298 100644 --- a/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/pom.xml +++ b/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/pom.xml @@ -8,4 +8,66 @@ </parent> <artifactId>so-etsi-nfvo-ns-lcm-service</artifactId> <name>SO ETSI NFVO NS LCM Service</name> + + <dependencies> + <dependency> + <groupId>org.onap.so.so-etsi-nfvo.ns.lcm</groupId> + <artifactId>so-etsi-nfvo-ns-lcm-api</artifactId> + <version>${project.version}</version> + </dependency> + <dependency> + <groupId>org.onap.so.so-etsi-nfvo.ns.lcm</groupId> + <artifactId>so-etsi-nfvo-ns-lcm-bpmn-flows</artifactId> + <version>${project.version}</version> + </dependency> + <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>${so-core-version}</version> + </dependency> + <dependency> + <groupId>com.h2database</groupId> + <artifactId>h2</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <scope>test</scope> + </dependency> + <dependency> + <groupId>com.h2database</groupId> + <artifactId>h2</artifactId> + <scope>test</scope> + </dependency> + </dependencies> </project>
\ No newline at end of file diff --git a/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/Constants.java b/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/Constants.java new file mode 100644 index 0000000..d330df3 --- /dev/null +++ b/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/Constants.java @@ -0,0 +1,39 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 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.etsi.nfvo.ns.lcm; + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +public class Constants { + + public static final String SERVICE_NAME = "so-etsi-nfvo-ns-lcm"; + public static final String SERVICE_VERSION = "v1"; + public static final String BASE_URL = "/so/" + SERVICE_NAME + "/" + SERVICE_VERSION + "/api"; + public static final String NS_LIFE_CYCLE_MANAGEMENT_BASE_URL = BASE_URL + "/nslcm/v1"; + + public static final String HTTP_GLOBAL_CUSTOMER_ID_HTTP_HEADER_PARM_NAME = "HTTP_GLOBALCUSTOMERID"; + public static final String HTTP_SERVICETYPE_HEADER_PARM_NAME = "HTTP_SERVICETYPE"; + public static final String HTTP_SERVICETYPE_HEADER_DEFAULT_VALUE = "NetworkService"; + + private Constants() {} + +} diff --git a/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/EtsiSoNsLcmManagerUrlProvider.java b/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/EtsiSoNsLcmManagerUrlProvider.java new file mode 100644 index 0000000..80ec604 --- /dev/null +++ b/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/EtsiSoNsLcmManagerUrlProvider.java @@ -0,0 +1,53 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 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.etsi.nfvo.ns.lcm; + +import java.net.URI; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.context.annotation.Configuration; + + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +@Configuration +public class EtsiSoNsLcmManagerUrlProvider { + + private final String etsiNsLcmManagerEndpoint; + + @Autowired + public EtsiSoNsLcmManagerUrlProvider( + @Value("${so-etsi-nfvo-ns-lcm.endpoint:http://so-etsi-nfvo-ns-lcm.onap:9095}") final String etsiNsLcmManagerEndpoint) { + this.etsiNsLcmManagerEndpoint = etsiNsLcmManagerEndpoint; + } + + public URI getCreatedNsResourceUri(final String nsInstanceId) { + return URI.create(etsiNsLcmManagerEndpoint + Constants.NS_LIFE_CYCLE_MANAGEMENT_BASE_URL + "/ns_instances/" + + nsInstanceId); + } + + public URI getNsLcmOpOccUri(final String nsLcmOpOccId) { + return URI.create(etsiNsLcmManagerEndpoint + Constants.NS_LIFE_CYCLE_MANAGEMENT_BASE_URL + "/ns_lcm_op_occs/" + + nsLcmOpOccId); + } + +} diff --git a/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/GsonSerializerConfiguration.java b/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/GsonSerializerConfiguration.java new file mode 100644 index 0000000..2e11ada --- /dev/null +++ b/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/GsonSerializerConfiguration.java @@ -0,0 +1,42 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 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.etsi.nfvo.ns.lcm; + +import java.time.LocalDateTime; +import org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.utils.LocalDateTimeTypeAdapter; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import com.google.gson.GsonBuilder; + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +@Configuration +public class GsonSerializerConfiguration { + + @Bean + public GsonBuilder gsonBuilder() { + return new GsonBuilder().registerTypeAdapter(LocalDateTime.class, new LocalDateTimeTypeAdapter()); + } + +} + + diff --git a/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/lifecycle/NsLcmOperationOccurrenceManager.java b/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/lifecycle/NsLcmOperationOccurrenceManager.java new file mode 100644 index 0000000..8a5cee6 --- /dev/null +++ b/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/lifecycle/NsLcmOperationOccurrenceManager.java @@ -0,0 +1,122 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 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.etsi.nfvo.ns.lcm.lifecycle; + +import static org.slf4j.LoggerFactory.getLogger; +import org.onap.so.etsi.nfvo.ns.lcm.EtsiSoNsLcmManagerUrlProvider; +import org.onap.so.etsi.nfvo.ns.lcm.database.beans.NsLcmOpOcc; +import org.onap.so.etsi.nfvo.ns.lcm.database.service.DatabaseServiceProvider; +import org.onap.so.etsi.nfvo.ns.lcm.model.NsInstancesNsInstanceLinksSelf; +import org.onap.so.etsi.nfvo.ns.lcm.model.NsLcmOpOccsNsLcmOpOcc; +import org.onap.so.etsi.nfvo.ns.lcm.model.NsLcmOpOccsNsLcmOpOccLinks; +import org.slf4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import java.util.Optional; + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + * @author Andrew Lamb (andrew.a.lamb@est.tech) + * + */ +@Service +public class NsLcmOperationOccurrenceManager { + + private static final Logger logger = getLogger(NsLcmOperationOccurrenceManager.class); + + private final DatabaseServiceProvider databaseServiceProvider; + private final EtsiSoNsLcmManagerUrlProvider etsiSoNsLcmManagerUrlProvider; + + @Autowired + public NsLcmOperationOccurrenceManager(final DatabaseServiceProvider databaseServiceProvider, + final EtsiSoNsLcmManagerUrlProvider etsiSoNsLcmManagerUrlProvider) { + this.databaseServiceProvider = databaseServiceProvider; + this.etsiSoNsLcmManagerUrlProvider = etsiSoNsLcmManagerUrlProvider; + } + + public Optional<NsLcmOpOccsNsLcmOpOcc> getNsLcmOperationOccurrence(final String nsLcmOpOccId) { + logger.info("Getting NS LCM Operation Occurrence Operation for id: {}", nsLcmOpOccId); + final Optional<NsLcmOpOcc> optionalNsLcmOpOcc = databaseServiceProvider.getNsLcmOpOcc(nsLcmOpOccId); + + if (optionalNsLcmOpOcc.isEmpty()) { + logger.info("No NS LCM Operation Occurrence found for id: {}", nsLcmOpOccId); + return Optional.empty(); + } + + logger.info("Found NS LCM Operation Occurrence for id: {}", nsLcmOpOccId); + final NsLcmOpOcc nsLcmOpOcc = optionalNsLcmOpOcc.get(); + final NsLcmOpOccsNsLcmOpOcc nsLcmOpOccsNsLcmOpOcc = convertToNsLcmOpOccsNsLcmOpOcc(nsLcmOpOcc); + return Optional.of(nsLcmOpOccsNsLcmOpOcc); + } + + private NsLcmOpOccsNsLcmOpOcc convertToNsLcmOpOccsNsLcmOpOcc(final NsLcmOpOcc nsLcmOpOcc) { + logger.info("Converting Database NsLcmOpOcc to API NsLcmOpOcc... "); + final NsLcmOpOccsNsLcmOpOcc nsLcmOpOccsNsLcmOpOcc = + new NsLcmOpOccsNsLcmOpOcc().id(nsLcmOpOcc.getId()).statusEnteredTime(nsLcmOpOcc.getStateEnteredTime()) + .startTime(nsLcmOpOcc.getStartTime()).isAutomaticInvocation(nsLcmOpOcc.getIsAutoInvocation()) + .isCancelPending(nsLcmOpOcc.getIsCancelPending()); + + if (nsLcmOpOcc.getNfvoNsInst() != null) { + nsLcmOpOccsNsLcmOpOcc.setNsInstanceId(nsLcmOpOcc.getNfvoNsInst().getNsInstId()); + } + + if (nsLcmOpOcc.getOperationState() != null) { + nsLcmOpOccsNsLcmOpOcc.setOperationState( + NsLcmOpOccsNsLcmOpOcc.OperationStateEnum.fromValue(nsLcmOpOcc.getOperationState().toString())); + } + + if (nsLcmOpOcc.getOperation() != null) { + nsLcmOpOccsNsLcmOpOcc.setLcmOperationType( + NsLcmOpOccsNsLcmOpOcc.LcmOperationTypeEnum.fromValue(nsLcmOpOcc.getOperation().toString())); + } + + if (nsLcmOpOcc.getOperationParams() != null) { + nsLcmOpOccsNsLcmOpOcc.setOperationParams(nsLcmOpOcc.getOperationParams()); + } + + if (nsLcmOpOcc.getCancelMode() != null) { + nsLcmOpOccsNsLcmOpOcc.setCancelMode( + NsLcmOpOccsNsLcmOpOcc.CancelModeEnum.fromValue(nsLcmOpOcc.getCancelMode().toString())); + } + + nsLcmOpOccsNsLcmOpOcc.setLinks(generateLinks(nsLcmOpOcc)); + + logger.info("Database NsLcmOpOcc converted to API NsLcmOpOcc successfully... {}", nsLcmOpOccsNsLcmOpOcc); + return nsLcmOpOccsNsLcmOpOcc; + } + + private NsLcmOpOccsNsLcmOpOccLinks generateLinks(final NsLcmOpOcc nsLcmOpOcc) { + logger.info("Generating links..."); + final String nsLcmOpOccId = nsLcmOpOcc.getId(); + final NsInstancesNsInstanceLinksSelf linksSelfNsLcmOpOcc = new NsInstancesNsInstanceLinksSelf() + .href(etsiSoNsLcmManagerUrlProvider.getNsLcmOpOccUri(nsLcmOpOccId).toString()); + final NsLcmOpOccsNsLcmOpOccLinks links = new NsLcmOpOccsNsLcmOpOccLinks().self(linksSelfNsLcmOpOcc); + + if (nsLcmOpOcc.getNfvoNsInst() != null) { + final String nsInstId = nsLcmOpOcc.getNfvoNsInst().getNsInstId(); + final NsInstancesNsInstanceLinksSelf linksSelfNsInst = new NsInstancesNsInstanceLinksSelf() + .href(etsiSoNsLcmManagerUrlProvider.getCreatedNsResourceUri(nsInstId).toString()); + links.setNsInstance(linksSelfNsInst); + } + + return links; + } + +} diff --git a/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/lifecycle/NsLifeCycleManager.java b/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/lifecycle/NsLifeCycleManager.java new file mode 100644 index 0000000..ae9f55e --- /dev/null +++ b/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/lifecycle/NsLifeCycleManager.java @@ -0,0 +1,90 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 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.etsi.nfvo.ns.lcm.lifecycle; + +import static org.slf4j.LoggerFactory.getLogger; +import java.net.URI; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.onap.so.etsi.nfvo.ns.lcm.EtsiSoNsLcmManagerUrlProvider; +import org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.service.JobExecutorService; +import org.onap.so.etsi.nfvo.ns.lcm.model.CreateNsRequest; +import org.onap.so.etsi.nfvo.ns.lcm.model.InstantiateNsRequest; +import org.onap.so.etsi.nfvo.ns.lcm.model.NsInstancesNsInstance; +import org.onap.so.etsi.nfvo.ns.lcm.model.TerminateNsRequest; +import org.slf4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +@Service +public class NsLifeCycleManager { + private static final Logger logger = getLogger(NsLifeCycleManager.class); + + private final JobExecutorService jobExecutorService; + + @Value("${etsi-so-ns-workflow-engine.requesttimeout.create.timeoutInSeconds:300}") + private int timeOutInSeconds; + + private final EtsiSoNsLcmManagerUrlProvider etsiSoNsLcmManagerUrlProvider; + + @Autowired + public NsLifeCycleManager(final JobExecutorService jobExecutorService, + final EtsiSoNsLcmManagerUrlProvider etsiSoNsLcmManagerUrlProvider) { + this.jobExecutorService = jobExecutorService; + this.etsiSoNsLcmManagerUrlProvider = etsiSoNsLcmManagerUrlProvider; + } + + public ImmutablePair<URI, NsInstancesNsInstance> createNs(final CreateNsRequest createNsRequest, + final String globalCustomerId, final String serviceType) { + logger.info("Will execute Create Ns for CreateNsRequest: {}, globalCustomerId: {} and serviceType: {}", + createNsRequest, globalCustomerId, serviceType); + final NsInstancesNsInstance nsInstanceResponse = + jobExecutorService.runCreateNsJob(createNsRequest, globalCustomerId, serviceType); + + return ImmutablePair.of(etsiSoNsLcmManagerUrlProvider.getCreatedNsResourceUri(nsInstanceResponse.getId()), + nsInstanceResponse); + } + + public URI instantiateNs(final String nsInstanceId, final InstantiateNsRequest instantiateNsRequest) { + logger.info("Will execute Instantiate Ns for InstantiateNsRequest: {} and nsInstanceId: {}", + instantiateNsRequest, nsInstanceId); + final String nsLcmOpOccId = jobExecutorService.runInstantiateNsJob(nsInstanceId, instantiateNsRequest); + + return etsiSoNsLcmManagerUrlProvider.getNsLcmOpOccUri(nsLcmOpOccId); + + } + + public URI terminateNs(final String nsInstanceId, final TerminateNsRequest terminateNsRequest) { + logger.info("Will execute Terminate Ns for TerminateNsRequest: {} and nsInstanceId: {}", terminateNsRequest, + nsInstanceId); + final String nsLcmOpOccId = jobExecutorService.runTerminateNsJob(nsInstanceId, terminateNsRequest); + + return etsiSoNsLcmManagerUrlProvider.getNsLcmOpOccUri(nsLcmOpOccId); + } + + public void deleteNs(final String nsInstanceId) { + logger.info("Will execute Delete Ns for nsInstanceId: {}", nsInstanceId); + jobExecutorService.runDeleteNsJob(nsInstanceId); + } +} diff --git a/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/rest/NsLcmOperationOccurrencesController.java b/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/rest/NsLcmOperationOccurrencesController.java new file mode 100644 index 0000000..207f0ff --- /dev/null +++ b/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/rest/NsLcmOperationOccurrencesController.java @@ -0,0 +1,85 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 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.etsi.nfvo.ns.lcm.rest; + +import static org.onap.so.etsi.nfvo.ns.lcm.Constants.NS_LIFE_CYCLE_MANAGEMENT_BASE_URL; +import static org.slf4j.LoggerFactory.getLogger; +import javax.ws.rs.core.MediaType; +import org.onap.so.etsi.nfvo.ns.lcm.lifecycle.NsLcmOperationOccurrenceManager; +import org.onap.so.etsi.nfvo.ns.lcm.model.InlineResponse400; +import org.onap.so.etsi.nfvo.ns.lcm.model.NsLcmOpOccsNsLcmOpOcc; +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.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import java.util.Optional; + +/** + * Controller for handling NS lifecycle management operation occurrence requests see clause 6.4.9 and 6.4.10 in + * https://www.etsi.org/deliver/etsi_gs/NFV-SOL/001_099/005/02.07.01_60/gs_NFV-SOL005v020701p.pdf + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * @author Andrew Lamb (andrew.a.lamb@est.tech) + * + */ +@Controller +@RequestMapping(value = NS_LIFE_CYCLE_MANAGEMENT_BASE_URL) +public class NsLcmOperationOccurrencesController { + private static final Logger logger = getLogger(NsLcmOperationOccurrencesController.class); + + private final NsLcmOperationOccurrenceManager nsLcmOperationOccurrenceManager; + + @Autowired + public NsLcmOperationOccurrencesController(final NsLcmOperationOccurrenceManager nsLcmOperationOccurrenceManager) { + this.nsLcmOperationOccurrenceManager = nsLcmOperationOccurrenceManager; + } + + /** + * The GET method to retrieve status information about a NS lifecycle management operation occurrence by reading an + * individual "NS LCM operation occurrence" resource. + * + * @param nsLcmOpOccId Identifier of a NS lifecycle management operation occurrence + * @return "200 OK" with {@link NsLcmOpOccsNsLcmOpOcc NsLcmOpOcc} Information about a NS LCM operation occurrence + * was queried successfully. The response body shall contain status information about a NS lifecycle + * management operation occurrence (see clause 6.5.2.3). + */ + @GetMapping(value = "/ns_lcm_op_occs/{nsLcmOpOccId}", + produces = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public ResponseEntity<?> getOperationStatus(@PathVariable("nsLcmOpOccId") final String nsLcmOpOccId) { + logger.info("Received request to retrieve operation status for nsLcmOpOccId: {}", nsLcmOpOccId); + final Optional<NsLcmOpOccsNsLcmOpOcc> optionalNsLcmOpOccs = + nsLcmOperationOccurrenceManager.getNsLcmOperationOccurrence(nsLcmOpOccId); + + if (optionalNsLcmOpOccs.isPresent()) { + final NsLcmOpOccsNsLcmOpOcc nsLcmOpOcc = optionalNsLcmOpOccs.get(); + logger.info("Sending back NsLcmOpOcc: {}", nsLcmOpOcc); + return ResponseEntity.ok().body(nsLcmOpOcc); + } + + final String errorMessage = "Unable to retrieve operation occurrence status for nsLcmOpOccId: " + nsLcmOpOccId; + logger.error(errorMessage); + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new InlineResponse400().detail(errorMessage)); + } + +} diff --git a/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/rest/NsLifecycleManagementController.java b/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/rest/NsLifecycleManagementController.java new file mode 100644 index 0000000..4d6f92c --- /dev/null +++ b/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/rest/NsLifecycleManagementController.java @@ -0,0 +1,156 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 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.etsi.nfvo.ns.lcm.rest; + +import static org.onap.so.etsi.nfvo.ns.lcm.Constants.HTTP_GLOBAL_CUSTOMER_ID_HTTP_HEADER_PARM_NAME; +import static org.onap.so.etsi.nfvo.ns.lcm.Constants.HTTP_SERVICETYPE_HEADER_DEFAULT_VALUE; +import static org.onap.so.etsi.nfvo.ns.lcm.Constants.HTTP_SERVICETYPE_HEADER_PARM_NAME; +import static org.onap.so.etsi.nfvo.ns.lcm.Constants.NS_LIFE_CYCLE_MANAGEMENT_BASE_URL; +import static org.slf4j.LoggerFactory.getLogger; +import java.net.URI; +import javax.ws.rs.core.MediaType; +import org.apache.commons.lang3.tuple.ImmutablePair; +import org.onap.so.etsi.nfvo.ns.lcm.lifecycle.NsLifeCycleManager; +import org.onap.so.etsi.nfvo.ns.lcm.model.Body; +import org.onap.so.etsi.nfvo.ns.lcm.model.CreateNsRequest; +import org.onap.so.etsi.nfvo.ns.lcm.model.InstantiateNsRequest; +import org.onap.so.etsi.nfvo.ns.lcm.model.NsInstancesNsInstance; +import org.onap.so.etsi.nfvo.ns.lcm.model.TerminateNsRequest; +import org.slf4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; + +/** + * Controller for handling the NS Lifecycle Management. For further information please read: + * https://www.etsi.org/deliver/etsi_gs/NFV-SOL/001_099/005/02.07.01_60/gs_NFV-SOL005v020701p.pdf Use the section number + * above each endpoint to find the corresponding section in the above document. + * + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +@Controller +@RequestMapping(value = NS_LIFE_CYCLE_MANAGEMENT_BASE_URL) +public class NsLifecycleManagementController { + private static final Logger logger = getLogger(NsLifecycleManagementController.class); + + private final NsLifeCycleManager nsLifeCycleManager; + + @Autowired + public NsLifecycleManagementController(final NsLifeCycleManager nsLifeCycleManager) { + this.nsLifeCycleManager = nsLifeCycleManager; + } + + /** + * The POST method creates new {@link Body new NS instance resource} request. See Section Number: 6.3.1 for more + * detail + * + * @param globalCustomerId The global customer ID + * @param serviceType The service type + * @param createNsRequest create network service request (see clause 6.5.2.9) + * @return "201 Created" response containing a representation of the NS instance resource + * {@link NsInstancesNsInstance} just created by the NFVO, and provides the URI of the newly-created + * resource in the "Location:" HTTP header + */ + @PostMapping(value = "/ns_instances", produces = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}, + consumes = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public ResponseEntity<NsInstancesNsInstance> createNs( + @RequestHeader(value = HTTP_GLOBAL_CUSTOMER_ID_HTTP_HEADER_PARM_NAME, + required = true) final String globalCustomerId, + @RequestHeader(value = HTTP_SERVICETYPE_HEADER_PARM_NAME, required = false, + defaultValue = HTTP_SERVICETYPE_HEADER_DEFAULT_VALUE) final String serviceType, + @RequestBody final CreateNsRequest createNsRequest) { + logger.info("Received Create NS Request: {}\n with globalCustomerId: {}\n serviceType: {}\n", createNsRequest, + globalCustomerId, serviceType); + + final ImmutablePair<URI, NsInstancesNsInstance> nsInstance = + nsLifeCycleManager.createNs(createNsRequest, globalCustomerId, serviceType); + + final URI resourceUri = nsInstance.getLeft(); + final NsInstancesNsInstance createdNsresponse = nsInstance.getRight(); + + logger.info("NS resource created successfully. Resource location: {}, response: {}", resourceUri, + createdNsresponse); + + return ResponseEntity.created(resourceUri).body(createdNsresponse); + } + + /** + * The DELETE method delete NS instance + * + * @param nsInstanceId Identifier of the NS instance to be deleted. + * @return "202 Accepted" response with an empty entity body + */ + @DeleteMapping(value = "/ns_instances/{nsInstanceId}", + produces = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public ResponseEntity<Void> deleteNs(@PathVariable("nsInstanceId") final String nsInstanceId) { + logger.debug("Received delete NS request for nsInstanceId: {}", nsInstanceId); + nsLifeCycleManager.deleteNs(nsInstanceId); + logger.info("Successfully deleted NS for nsInstanceId: {}", nsInstanceId); + return ResponseEntity.noContent().build(); + } + + /** + * The POST method instantiate NS instance + * + * @param nsInstanceId Identifier of the NS instance to be instantiated. + * @param instantiateNsRequest Instantiate network service request (see clause 6.5.2.11) + * @return "202 Accepted" response with an empty entity body and a "Location" HTTP header that points to the new "NS + * Lifecycle Operation Occurrence" resource + */ + @PostMapping(value = "/ns_instances/{nsInstanceId}/instantiate", + produces = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}, + consumes = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public ResponseEntity<Void> instantiateNs(@PathVariable("nsInstanceId") final String nsInstanceId, + @RequestBody final InstantiateNsRequest instantiateNsRequest) { + logger.debug("Received instantiate NS request: {}\n with nsInstanceId: {}", instantiateNsRequest, nsInstanceId); + final URI resourceUri = nsLifeCycleManager.instantiateNs(nsInstanceId, instantiateNsRequest); + logger.info("{} Ns Instantiation started successfully. Resource Operation Occurrence uri: {}", nsInstanceId, + resourceUri); + return ResponseEntity.accepted().location(resourceUri).build(); + } + + /** + * The POST method terminate NS instance + * + * @param nsInstanceId Identifier of the NS instance to be terminated. + * @param terminateNsRequest The terminate NS request parameters (see clause 6.5.2.15) + * @return "202 Accepted" response with an empty entity body and a "Location" HTTP header that points to the new "NS + * Lifecycle Operation Occurrence" resource + */ + @PostMapping(value = "/ns_instances/{nsInstanceId}/terminate", + produces = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}, + consumes = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) + public ResponseEntity<Void> terminateNs(@PathVariable("nsInstanceId") final String nsInstanceId, + @RequestBody(required = false) final TerminateNsRequest terminateNsRequest) { + logger.debug("Received terminate NS request: {}\n with nsInstanceId: {}", terminateNsRequest, nsInstanceId); + final URI resourceUri = nsLifeCycleManager.terminateNs(nsInstanceId, terminateNsRequest); + logger.info("{} Ns Terminate started successfully. Resource Operation Occurrence uri: {}", nsInstanceId, + resourceUri); + return ResponseEntity.accepted().location(resourceUri).build(); + } + +} diff --git a/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/rest/exceptions/NsLcmControllerExceptionHandler.java b/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/rest/exceptions/NsLcmControllerExceptionHandler.java new file mode 100644 index 0000000..3db04fc --- /dev/null +++ b/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/main/java/org/onap/so/etsi/nfvo/ns/lcm/rest/exceptions/NsLcmControllerExceptionHandler.java @@ -0,0 +1,58 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 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.etsi.nfvo.ns.lcm.rest.exceptions; + +import org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.exceptions.NsRequestProcessingException; +import org.onap.so.etsi.nfvo.ns.lcm.model.InlineResponse400; +import org.onap.so.etsi.nfvo.ns.lcm.rest.NsLifecycleManagementController; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.ControllerAdvice; +import org.springframework.web.bind.annotation.ExceptionHandler; + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +@ControllerAdvice(assignableTypes = NsLifecycleManagementController.class) +public class NsLcmControllerExceptionHandler { + + @ExceptionHandler(NsRequestProcessingException.class) + public ResponseEntity<InlineResponse400> handleNsRequestProcessingException( + final NsRequestProcessingException nsRequestProcessingException) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR) + .body(getInlineResponse400(nsRequestProcessingException)); + } + + @ExceptionHandler(Exception.class) + public ResponseEntity<InlineResponse400> handleNsRequestProcessingException(final Exception exception) { + return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body(new InlineResponse400() + .status(HttpStatus.INTERNAL_SERVER_ERROR.value()).detail(exception.getMessage())); + } + + private InlineResponse400 getInlineResponse400(final NsRequestProcessingException nsRequestProcessingException) { + if (nsRequestProcessingException.getProblemDetails() != null) { + return nsRequestProcessingException.getProblemDetails(); + } + return new InlineResponse400().status(HttpStatus.INTERNAL_SERVER_ERROR.value()) + .detail(nsRequestProcessingException.getMessage()); + } + +} diff --git a/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/test/java/org/onap/so/etsi/nfvo/ns/lcm/TestApplication.java b/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/test/java/org/onap/so/etsi/nfvo/ns/lcm/TestApplication.java new file mode 100644 index 0000000..d6f4a83 --- /dev/null +++ b/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/test/java/org/onap/so/etsi/nfvo/ns/lcm/TestApplication.java @@ -0,0 +1,37 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 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.etsi.nfvo.ns.lcm; + +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.EnableAutoConfiguration; +import org.springframework.boot.autoconfigure.SpringBootApplication; +import org.springframework.boot.autoconfigure.jackson.JacksonAutoConfiguration; + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +@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/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/test/java/org/onap/so/etsi/nfvo/ns/lcm/rest/NsLcmOperationOccurrencesControllerTest.java b/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/test/java/org/onap/so/etsi/nfvo/ns/lcm/rest/NsLcmOperationOccurrencesControllerTest.java new file mode 100644 index 0000000..c586256 --- /dev/null +++ b/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/test/java/org/onap/so/etsi/nfvo/ns/lcm/rest/NsLcmOperationOccurrencesControllerTest.java @@ -0,0 +1,133 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 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.etsi.nfvo.ns.lcm.rest; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import java.time.LocalDateTime; +import java.util.Optional; +import java.util.UUID; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.onap.so.etsi.nfvo.ns.lcm.Constants; +import org.onap.so.etsi.nfvo.ns.lcm.TestApplication; +import org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.GsonProvider; +import org.onap.so.etsi.nfvo.ns.lcm.database.beans.NfvoNsInst; +import org.onap.so.etsi.nfvo.ns.lcm.database.beans.NsLcmOpOcc; +import org.onap.so.etsi.nfvo.ns.lcm.database.beans.NsLcmOpType; +import org.onap.so.etsi.nfvo.ns.lcm.database.beans.OperationStateEnum; +import org.onap.so.etsi.nfvo.ns.lcm.database.beans.State; +import org.onap.so.etsi.nfvo.ns.lcm.database.service.DatabaseServiceProvider; +import org.onap.so.etsi.nfvo.ns.lcm.model.InlineResponse400; +import org.onap.so.etsi.nfvo.ns.lcm.model.NsLcmOpOccsNsLcmOpOcc; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.json.GsonHttpMessageConverter; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; +import com.google.gson.Gson; + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + * @author Andrew Lamb (andrew.a.lamb@est.tech) + * + */ + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = TestApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ActiveProfiles("test") +public class NsLcmOperationOccurrencesControllerTest { + + private static final String NS_LCM_OP_OCCS = "/ns_lcm_op_occs/"; + + @LocalServerPort + private int port; + + @Autowired + private DatabaseServiceProvider databaseServiceProvider; + + @Autowired + private GsonProvider gsonProvider; + + private TestRestTemplate testRestTemplate; + + @Before + public void setUp() { + final Gson gson = gsonProvider.getGson(); + testRestTemplate = new TestRestTemplate( + new RestTemplateBuilder().additionalMessageConverters(new GsonHttpMessageConverter(gson))); + } + + @Test + public void testGetOperationStatus_validNsLcmOpOccId_returnsNsLcmOpOcc() { + final String nsLcmOpOccId = addDummyNsLcmOpOccToDatabase(); + final String baseUrl = getNsLcmBaseUrl() + NS_LCM_OP_OCCS + nsLcmOpOccId; + final HttpEntity<?> request = new HttpEntity<>(new HttpHeaders()); + final ResponseEntity<NsLcmOpOccsNsLcmOpOcc> responseEntity = + testRestTemplate.exchange(baseUrl, HttpMethod.GET, request, NsLcmOpOccsNsLcmOpOcc.class); + assertEquals(HttpStatus.OK, responseEntity.getStatusCode()); + assertTrue(responseEntity.hasBody()); + assertNotNull(responseEntity.getBody()); + } + + @Test + public void testGetOperationStatus_nsLcmOpOccIdNotFound_returnsInlineResponse400() { + final String nsLcmOpOccId = UUID.randomUUID().toString(); + final Optional<NsLcmOpOcc> optionalNsLcmOpOcc = databaseServiceProvider.getNsLcmOpOcc(nsLcmOpOccId); + assertTrue(optionalNsLcmOpOcc.isEmpty()); + final String baseUrl = getNsLcmBaseUrl() + NS_LCM_OP_OCCS + nsLcmOpOccId; + final HttpEntity<?> request = new HttpEntity<>(new HttpHeaders()); + final ResponseEntity<InlineResponse400> responseEntity = + testRestTemplate.exchange(baseUrl, HttpMethod.GET, request, InlineResponse400.class); + assertEquals(HttpStatus.NOT_FOUND, responseEntity.getStatusCode()); + assertTrue(responseEntity.hasBody()); + assertNotNull(responseEntity.getBody()); + } + + private String addDummyNsLcmOpOccToDatabase() { + final LocalDateTime currentDateTime = LocalDateTime.now(); + + final NfvoNsInst nsInst = new NfvoNsInst().name("name").nsdId("id").status(State.NOT_INSTANTIATED) + .nsdInvariantId("id").statusUpdatedTime(currentDateTime); + databaseServiceProvider.saveNfvoNsInst(nsInst); + + final NsLcmOpOcc nsLcmOpOcc = new NsLcmOpOcc().nfvoNsInst(nsInst).operationState(OperationStateEnum.PROCESSING) + .isCancelPending(false).isAutoInvocation(false).operation(NsLcmOpType.INSTANTIATE) + .startTime(currentDateTime).stateEnteredTime(currentDateTime).operationParams(""); + databaseServiceProvider.addNSLcmOpOcc(nsLcmOpOcc); + + return nsLcmOpOcc.getId(); + } + + private String getNsLcmBaseUrl() { + return "http://localhost:" + port + Constants.NS_LIFE_CYCLE_MANAGEMENT_BASE_URL; + } +} + diff --git a/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/test/java/org/onap/so/etsi/nfvo/ns/lcm/rest/NsLifecycleManagementControllerTest.java b/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/test/java/org/onap/so/etsi/nfvo/ns/lcm/rest/NsLifecycleManagementControllerTest.java new file mode 100644 index 0000000..585b0e1 --- /dev/null +++ b/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/test/java/org/onap/so/etsi/nfvo/ns/lcm/rest/NsLifecycleManagementControllerTest.java @@ -0,0 +1,288 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 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.etsi.nfvo.ns.lcm.rest; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.when; +import java.net.URISyntaxException; +import java.util.List; +import java.util.UUID; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.onap.so.etsi.nfvo.ns.lcm.Constants; +import org.onap.so.etsi.nfvo.ns.lcm.TestApplication; +import org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.GsonProvider; +import org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.exceptions.NsRequestProcessingException; +import org.onap.so.etsi.nfvo.ns.lcm.bpmn.flows.service.JobExecutorService; +import org.onap.so.etsi.nfvo.ns.lcm.model.CreateNsRequest; +import org.onap.so.etsi.nfvo.ns.lcm.model.InlineResponse400; +import org.onap.so.etsi.nfvo.ns.lcm.model.InstantiateNsRequest; +import org.onap.so.etsi.nfvo.ns.lcm.model.NsInstancesNsInstance; +import org.onap.so.etsi.nfvo.ns.lcm.model.TerminateNsRequest; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.test.web.client.TestRestTemplate; +import org.springframework.boot.web.client.RestTemplateBuilder; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.http.converter.json.GsonHttpMessageConverter; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; +import com.google.gson.Gson; + +/** + * @author Waqas Ikram (waqas.ikram@est.tech) + * + */ +@RunWith(SpringRunner.class) +@SpringBootTest(classes = TestApplication.class, webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@ActiveProfiles("test") +public class NsLifecycleManagementControllerTest { + private static final String EXPECTED_BASE_URL = + "http://so-etsi-nfvo-ns-lcm.onap:9095/so/so-etsi-nfvo-ns-lcm/v1/api/nslcm/v1"; + private static final String RANDOM_NS_LCM_OP_OCC_ID = UUID.randomUUID().toString(); + private static final String RANDOM_NS_INST_ID = UUID.randomUUID().toString(); + private static final String SERVICE_TYPE = "NetworkService"; + private static final String GLOBAL_CUSTOMER_ID = UUID.randomUUID().toString(); + private static final String EXPECTED_CREATE_REQ_LOCATION_URL = + EXPECTED_BASE_URL + "/ns_instances/" + RANDOM_NS_INST_ID; + private static final String EXPECTED_NS_LCM_OP_OCC_REQ_LOCATION_URL = + EXPECTED_BASE_URL + "/ns_lcm_op_occs/" + RANDOM_NS_LCM_OP_OCC_ID; + + @LocalServerPort + private int port; + + private TestRestTemplate testRestTemplate; + + @Autowired + private GsonProvider gsonProvider; + + @MockBean + private JobExecutorService mockedJobExecutorService; + + @Before + public void setUp() { + final Gson gson = gsonProvider.getGson(); + testRestTemplate = new TestRestTemplate( + new RestTemplateBuilder().additionalMessageConverters(new GsonHttpMessageConverter(gson))); + } + + @Test + public void testCreateNs_ValidCreateNsRequest() throws URISyntaxException { + + final CreateNsRequest createNsRequest = getCreateNsRequest(); + + when(mockedJobExecutorService.runCreateNsJob(eq(createNsRequest), eq(GLOBAL_CUSTOMER_ID), eq(SERVICE_TYPE))) + .thenReturn(new NsInstancesNsInstance().id(RANDOM_NS_INST_ID)); + + final String baseUrl = getNsLcmBaseUrl() + "/ns_instances"; + final HttpHeaders headers = new HttpHeaders(); + headers.add(Constants.HTTP_GLOBAL_CUSTOMER_ID_HTTP_HEADER_PARM_NAME, GLOBAL_CUSTOMER_ID); + final HttpEntity<?> request = new HttpEntity<>(createNsRequest, headers); + final ResponseEntity<NsInstancesNsInstance> responseEntity = + testRestTemplate.exchange(baseUrl, HttpMethod.POST, request, NsInstancesNsInstance.class); + assertEquals(HttpStatus.CREATED, responseEntity.getStatusCode()); + assertTrue(responseEntity.hasBody()); + assertNotNull(responseEntity.getBody()); + + final HttpHeaders httpHeaders = responseEntity.getHeaders(); + assertTrue(httpHeaders.containsKey(HttpHeaders.LOCATION)); + final List<String> actual = httpHeaders.get(HttpHeaders.LOCATION); + assertEquals(1, actual.size()); + assertEquals(EXPECTED_CREATE_REQ_LOCATION_URL, actual.get(0)); + } + + @Test + public void testCreateNs_createNsRequest_nsRequestProcessingExceptionThrown_returnInlineResponse400() + throws URISyntaxException { + + final CreateNsRequest createNsRequest = getCreateNsRequest(); + + final String message = "Unable to process request"; + when(mockedJobExecutorService.runCreateNsJob(eq(createNsRequest), eq(GLOBAL_CUSTOMER_ID), eq(SERVICE_TYPE))) + .thenThrow(new NsRequestProcessingException(message, new InlineResponse400().detail(message))); + + final String baseUrl = getNsLcmBaseUrl() + "/ns_instances"; + final HttpHeaders headers = new HttpHeaders(); + headers.add(Constants.HTTP_GLOBAL_CUSTOMER_ID_HTTP_HEADER_PARM_NAME, GLOBAL_CUSTOMER_ID); + final HttpEntity<?> request = new HttpEntity<>(createNsRequest, headers); + final ResponseEntity<InlineResponse400> responseEntity = + testRestTemplate.exchange(baseUrl, HttpMethod.POST, request, InlineResponse400.class); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); + assertTrue(responseEntity.hasBody()); + assertNotNull(responseEntity.getBody()); + + final InlineResponse400 body = responseEntity.getBody(); + assertEquals(message, body.getDetail()); + + } + + @Test + public void testCreateNs_createNsRequest_exceptionThrown_returnInlineResponse400() throws URISyntaxException { + + final CreateNsRequest createNsRequest = getCreateNsRequest(); + + final String message = "Unable to process request"; + when(mockedJobExecutorService.runCreateNsJob(eq(createNsRequest), eq(GLOBAL_CUSTOMER_ID), eq(SERVICE_TYPE))) + .thenThrow(new RuntimeException(message)); + + final String baseUrl = getNsLcmBaseUrl() + "/ns_instances"; + final HttpHeaders headers = new HttpHeaders(); + headers.add(Constants.HTTP_GLOBAL_CUSTOMER_ID_HTTP_HEADER_PARM_NAME, GLOBAL_CUSTOMER_ID); + final HttpEntity<?> request = new HttpEntity<>(createNsRequest, headers); + final ResponseEntity<InlineResponse400> responseEntity = + testRestTemplate.exchange(baseUrl, HttpMethod.POST, request, InlineResponse400.class); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); + assertTrue(responseEntity.hasBody()); + assertNotNull(responseEntity.getBody()); + + final InlineResponse400 body = responseEntity.getBody(); + assertEquals(message, body.getDetail()); + + } + + @Test + public void testDeleteNs_SuccessfulCase() { + final String nsInstId = UUID.randomUUID().toString(); + doNothing().when(mockedJobExecutorService).runDeleteNsJob(eq(nsInstId)); + + final String baseUrl = getNsLcmBaseUrl() + "/ns_instances/" + nsInstId; + final ResponseEntity<Void> responseEntity = + testRestTemplate.exchange(baseUrl, HttpMethod.DELETE, null, Void.class); + assertEquals(HttpStatus.NO_CONTENT, responseEntity.getStatusCode()); + } + + @Test + public void testDeleteNs_nsRequestProcessingExceptionThrown_returnInlineResponse400() { + final String nsInstId = UUID.randomUUID().toString(); + final String message = "Unable to process request"; + doThrow(new NsRequestProcessingException(message, new InlineResponse400().detail(message))) + .when(mockedJobExecutorService).runDeleteNsJob(eq(nsInstId)); + + final String baseUrl = getNsLcmBaseUrl() + "/ns_instances/" + nsInstId; + final ResponseEntity<InlineResponse400> responseEntity = + testRestTemplate.exchange(baseUrl, HttpMethod.DELETE, null, InlineResponse400.class); + + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); + assertTrue(responseEntity.hasBody()); + assertNotNull(responseEntity.getBody()); + } + + @Test + public void testInstantiateNs_ValidInstantiateNsRequest() { + + final InstantiateNsRequest instantiateNsRequest = getInstantiateNsRequest(); + when(mockedJobExecutorService.runInstantiateNsJob(eq(RANDOM_NS_INST_ID), eq(instantiateNsRequest))) + .thenReturn(RANDOM_NS_LCM_OP_OCC_ID); + + final String baseUrl = getNsLcmBaseUrl() + "/ns_instances/" + RANDOM_NS_INST_ID + "/instantiate"; + final HttpEntity<?> request = new HttpEntity<>(instantiateNsRequest); + final ResponseEntity<Void> responseEntity = + testRestTemplate.exchange(baseUrl, HttpMethod.POST, request, Void.class); + assertEquals(HttpStatus.ACCEPTED, responseEntity.getStatusCode()); + + final HttpHeaders httpHeaders = responseEntity.getHeaders(); + assertTrue(httpHeaders.containsKey(HttpHeaders.LOCATION)); + final List<String> actual = httpHeaders.get(HttpHeaders.LOCATION); + assertEquals(1, actual.size()); + assertEquals(EXPECTED_NS_LCM_OP_OCC_REQ_LOCATION_URL, actual.get(0)); + } + + @Test + public void testInstantiateNs_instantiateNsRequest_nsRequestProcessingExceptionThrown_returnInlineResponse400() { + final String message = "Unable to process request"; + final InstantiateNsRequest instantiateNsRequest = getInstantiateNsRequest(); + when(mockedJobExecutorService.runInstantiateNsJob(eq(RANDOM_NS_INST_ID), eq(instantiateNsRequest))) + .thenThrow(new NsRequestProcessingException(message, new InlineResponse400().detail(message))); + + final String baseUrl = getNsLcmBaseUrl() + "/ns_instances/" + RANDOM_NS_INST_ID + "/instantiate"; + final HttpEntity<?> request = new HttpEntity<>(instantiateNsRequest); + final ResponseEntity<InlineResponse400> responseEntity = + testRestTemplate.exchange(baseUrl, HttpMethod.POST, request, InlineResponse400.class); + + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); + assertTrue(responseEntity.hasBody()); + assertNotNull(responseEntity.getBody()); + } + + @Test + public void testTerminateNs_ValidTerminateNsRequest_Success() { + final TerminateNsRequest terminateNsRequest = getTerminateNsRequest(); + when(mockedJobExecutorService.runTerminateNsJob(eq(RANDOM_NS_INST_ID), eq(terminateNsRequest))) + .thenReturn(RANDOM_NS_LCM_OP_OCC_ID); + + final String baseUrl = getNsLcmBaseUrl() + "/ns_instances/" + RANDOM_NS_INST_ID + "/terminate"; + final HttpEntity<?> request = new HttpEntity<>(terminateNsRequest); + final ResponseEntity<Void> responseEntity = + testRestTemplate.exchange(baseUrl, HttpMethod.POST, request, Void.class); + assertEquals(HttpStatus.ACCEPTED, responseEntity.getStatusCode()); + + final HttpHeaders httpHeaders = responseEntity.getHeaders(); + assertTrue(httpHeaders.containsKey(HttpHeaders.LOCATION)); + final List<String> actual = httpHeaders.get(HttpHeaders.LOCATION); + assertEquals(1, actual.size()); + assertEquals(EXPECTED_NS_LCM_OP_OCC_REQ_LOCATION_URL, actual.get(0)); + } + + @Test + public void testTerminateNs_ValidTerminateNsRequest_nsRequestProcessingExceptionThrown_returnInlineResponse400() { + final String errorMessage = "ERROR MESSAGE"; + final TerminateNsRequest terminateNsRequest = getTerminateNsRequest(); + when(mockedJobExecutorService.runTerminateNsJob(eq(RANDOM_NS_INST_ID), eq(terminateNsRequest))) + .thenThrow(new NsRequestProcessingException(errorMessage)); + + final String baseUrl = getNsLcmBaseUrl() + "/ns_instances/" + RANDOM_NS_INST_ID + "/terminate"; + final HttpEntity<?> request = new HttpEntity<>(terminateNsRequest); + final ResponseEntity<InlineResponse400> responseEntity = + testRestTemplate.exchange(baseUrl, HttpMethod.POST, request, InlineResponse400.class); + assertEquals(HttpStatus.INTERNAL_SERVER_ERROR, responseEntity.getStatusCode()); + assertTrue(responseEntity.hasBody()); + assertNotNull(responseEntity.getBody()); + } + + private TerminateNsRequest getTerminateNsRequest() { + // Only support for the immediate Terminate request; i.e., terminateTime field is empty (not set) + return new TerminateNsRequest(); + } + + private InstantiateNsRequest getInstantiateNsRequest() { + return new InstantiateNsRequest().nsFlavourId("FLAVOUR_ID"); + } + + private CreateNsRequest getCreateNsRequest() { + return new CreateNsRequest().nsdId(RANDOM_NS_INST_ID); + } + + private String getNsLcmBaseUrl() { + return "http://localhost:" + port + Constants.NS_LIFE_CYCLE_MANAGEMENT_BASE_URL; + } +} + diff --git a/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/test/resources/application.yaml b/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/test/resources/application.yaml new file mode 100644 index 0000000..6f2b4d2 --- /dev/null +++ b/so-etsi-nfvo-ns-lcm/so-etsi-nfvo-ns-lcm-service/src/test/resources/application.yaml @@ -0,0 +1,41 @@ +# Copyright © 2020 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: + main: + allow-bean-definition-overriding: true + flyway: + baseline-on-migrate: false + datasource: + hikari: + camunda: + jdbcUrl: jdbc:h2:mem:example-simple;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE + driver-class-name: org.h2.Driver + pool-name: ns-lcm-bpmn-pool + registerMbeans: true + nfvo: + jdbcUrl: jdbc:h2:mem:NFVO;DB_CLOSE_DELAY=-1;DB_CLOSE_ON_EXIT=FALSE;INIT=CREATE SCHEMA IF NOT EXISTS NFVO; + driver-class-name: org.h2.Driver + pool-name: ns-lcm-nfvo-pool + registerMbeans: true + jpa: + generate-ddl: true + hibernate: + ddl-auto: create +logging: + level: + org.reflections.Reflections: ERROR + +etsi-catalog-manager: + base: + endpoint: http://modeling-etsicatalog.onap:8806/api |