diff options
11 files changed, 365 insertions, 98 deletions
diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfPluginAdapterImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfPluginAdapterImpl.java index 584c934843..82b194a973 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfPluginAdapterImpl.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/vnf/MsoVnfPluginAdapterImpl.java @@ -705,18 +705,16 @@ public class MsoVnfPluginAdapterImpl implements MsoVnfAdapter { throw new VnfException("Exception during create VF " + e.getMessage()); } - // Perform a version check against cloudSite + // Perform a version check against cloudSite // Obtain the cloud site information where we will create the VF Module - Boolean usingMulticloud = false; Optional<CloudSite> cloudSiteOp = cloudConfig.getCloudSite (cloudSiteId); if (!cloudSiteOp.isPresent()) { // If cloudSiteId is not present in the catalog DB, then default to multicloud - usingMulticloud = true; + logger.debug("{} is not present in cloud_site catalog DB, defaulting to Multicloud plugin adapter", cloudSiteId); } else { CloudSite cloudSite = cloudSiteOp.get(); MavenLikeVersioning aicV = new MavenLikeVersioning(); aicV.setVersion(cloudSite.getCloudVersion()); - usingMulticloud = getUsingMulticloud(cloudSite); String vnfMin = vnfResource.getAicVersionMin(); String vnfMax = vnfResource.getAicVersionMax(); @@ -743,24 +741,20 @@ public class MsoVnfPluginAdapterImpl implements MsoVnfAdapter { // Use the VduPlugin. VduPlugin vduPlugin = getVduPlugin(cloudSiteId, cloudOwner); - // First, look up to see if the VF already exists, unless using multicloud adapter - long subStartTime1 = System.currentTimeMillis (); - if (!usingMulticloud) { - try { - vduInstance = vduPlugin.queryVdu (cloudInfo, vfModuleName); - } - catch (VduException me) { - // Failed to query the VDU due to a plugin exception. - String error = "Create VF Module: Query " + vfModuleName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me ; - logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, - cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(), - "Exception - queryVdu", me); - logger.debug(error); - // Convert to a generic VnfException - me.addContext ("CreateVFModule"); - throw new VnfException (me); - } + try { + vduInstance = vduPlugin.queryVdu (cloudInfo, vfModuleName); + } + catch (VduException me) { + // Failed to query the VDU due to a plugin exception. + String error = "Create VF Module: Query " + vfModuleName + " in " + cloudOwner + "/" + cloudSiteId + "/" + tenantId + ": " + me ; + logger.error("{} {} {} {} {} {} {} {} {}", MessageEnum.RA_QUERY_VNF_ERR.toString(), vfModuleName, + cloudOwner, cloudSiteId, tenantId, "VDU", "queryVdu", ErrorCode.DataError.getValue(), + "Exception - queryVdu", me); + logger.debug(error); + // Convert to a generic VnfException + me.addContext ("CreateVFModule"); + throw new VnfException (me); } // More precise handling/messaging if the Module already exists @@ -838,7 +832,7 @@ public class MsoVnfPluginAdapterImpl implements MsoVnfAdapter { Map<String, Object> volumeGroupOutputs = null; // If a Volume Group was provided, query its outputs for inclusion in Module input parameters - if (!usingMulticloud && volumeGroupId != null) { + if (volumeGroupId != null) { long subStartTime2 = System.currentTimeMillis (); VduInstance volumeVdu = null; try { @@ -887,8 +881,7 @@ public class MsoVnfPluginAdapterImpl implements MsoVnfAdapter { logger.debug("WARNING: Add-on Module request - no Base Module ID provided"); } - // Need to verify if multicloud needs to have the vaseVfModuleId passed to it. Ignoring this for now. - if (!usingMulticloud && baseVfModuleId != null) { + if (baseVfModuleId != null) { long subStartTime2 = System.currentTimeMillis (); VduInstance baseVdu = null; try { @@ -942,15 +935,15 @@ public class MsoVnfPluginAdapterImpl implements MsoVnfAdapter { } if (heatTemplate == null) { - String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType=" - + requestType; - logger.error("{} {} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Template ID", vfModuleType, - "VNF", ErrorCode.DataError.getValue(), error); - logger.debug(error); - throw new VnfException(error, MsoExceptionCategory.INTERNAL); - } else { - logger.debug("Got HEAT Template from DB: " + heatTemplate.getHeatTemplate()); - } + String error = "UpdateVF: No Heat Template ID defined in catalog database for " + vfModuleType + ", reqType=" + + requestType; + logger.error("{} {} {} {} {} {}", MessageEnum.RA_VNF_UNKNOWN_PARAM.toString(), "Heat Template ID", vfModuleType, + "VNF", ErrorCode.DataError.getValue(), error); + logger.debug(error); + throw new VnfException(error, MsoExceptionCategory.INTERNAL); + } else { + logger.debug("Got HEAT Template from DB: " + heatTemplate.getHeatTemplate()); + } if (heatEnvironment == null) { String error = "Update VNF: undefined Heat Environment. VF=" + vfModuleType; @@ -1011,12 +1004,10 @@ public class MsoVnfPluginAdapterImpl implements MsoVnfAdapter { if (!extraInputs.isEmpty()) { // Add multicloud inputs - boolean multicloudInputs = false; for (String key : MsoMulticloudUtils.MULTICLOUD_INPUTS) { if (extraInputs.contains(key)) { goldenInputs.put(key, inputs.get(key)); extraInputs.remove(key); - multicloudInputs = true; if (extraInputs.isEmpty()) { break; } @@ -1275,12 +1266,4 @@ public class MsoVnfPluginAdapterImpl implements MsoVnfAdapter { // Default if no cloudSite record exists - return multicloud plugin return multicloudUtils; } - - private Boolean getUsingMulticloud (CloudSite cloudSite) { - if (cloudSite.getOrchestrator().equalsIgnoreCase("MULTICLOUD")) { - return true; - } else { - return false; - } - } } diff --git a/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/vnf/MsoVnfMulticloudAdapterImplTest.java b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/vnf/MsoVnfMulticloudAdapterImplTest.java index f3ad4e6d7d..507251bb80 100644 --- a/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/vnf/MsoVnfMulticloudAdapterImplTest.java +++ b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/vnf/MsoVnfMulticloudAdapterImplTest.java @@ -25,6 +25,9 @@ import static com.github.tomakehurst.wiremock.client.WireMock.delete; import static com.github.tomakehurst.wiremock.client.WireMock.get; import static com.github.tomakehurst.wiremock.client.WireMock.post; import static com.github.tomakehurst.wiremock.client.WireMock.urlPathEqualTo; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.util.HashMap; import java.util.Map; @@ -36,8 +39,12 @@ import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; +import org.onap.so.adapters.vdu.VduModelInfo; +import org.onap.so.adapters.vnf.exceptions.VnfException; import org.onap.so.cloud.CloudConfig; import org.onap.so.entity.MsoRequest; +import org.onap.so.openstack.beans.StackInfo; +import org.onap.so.openstack.exceptions.MsoException; import org.springframework.beans.factory.annotation.Autowired; public class MsoVnfMulticloudAdapterImplTest extends BaseRestTestUtils{ @@ -50,6 +57,20 @@ public class MsoVnfMulticloudAdapterImplTest extends BaseRestTestUtils{ @Autowired private CloudConfig cloudConfig; + private static final String CREATE_STACK_RESPONSE = "{\"template_type\": \"TEST-template\", \"workload_id\": " + + "\"workload-id\", \"template_response\": {\"stack\": {\"id\": \"TEST-stack\", \"links\": []}}}"; + private static final String UPDATE_STACK_RESPONSE = "{\"template_type\": \"heat\", \"workload_id\": " + + "\"workload-id\"}"; + private static final String GET_CREATE_STACK_RESPONSE = "{\"template_type\": \"heat\", \"workload_id\": " + + "\"workload-id\", \"workload_status\": \"CREATE_COMPLETE\"}"; + private static final String GET_UPDATE_STACK_RESPONSE = "{\"template_type\": \"heat\", \"workload_id\": " + + "\"workload-id\", \"workload_status\": \"UPDATE_COMPLETE\"}"; + + private static final String MULTICLOUD_CREATE_PATH = "/api/multicloud/v1/CloudOwner/MTN13/infra_workload"; + private static final String MULTICLOUD_UPDATE_PATH = "/api/multicloud/v1/CloudOwner/MTN13/infra_workload/workload-id"; + private static final String MULTICLOUD_GET_PATH_BY_NAME = "/api/multicloud/v1/CloudOwner/MTN13/infra_workload/vfname"; + private static final String MULTICLOUD_GET_PATH_BY_ID = "/api/multicloud/v1/CloudOwner/MTN13/infra_workload/workload-id"; + @Before public void before() throws Exception { super.orchestrator = "multicloud"; @@ -59,10 +80,11 @@ public class MsoVnfMulticloudAdapterImplTest extends BaseRestTestUtils{ @Test public void createVfModule() throws Exception { - + Map<String, Object> stackInputs = new HashMap<>(); stackInputs.put("oof_directives", "{}"); stackInputs.put("sdnc_directives", "{}"); + stackInputs.put("user_directives", "{}"); stackInputs.put("generic_vnf_id", "genVNFID"); stackInputs.put("vf_module_id", "vfMODULEID"); @@ -70,23 +92,73 @@ public class MsoVnfMulticloudAdapterImplTest extends BaseRestTestUtils{ msoRequest.setRequestId("12345"); msoRequest.setServiceInstanceId("12345"); - wireMockServer.stubFor(get(urlPathEqualTo("/api/multicloud/v1/CloudOwner/MTN13/infra_workload/vfname")).willReturn(aResponse() - //.withHeader() + wireMockServer.stubFor(get(urlPathEqualTo(MULTICLOUD_GET_PATH_BY_NAME)) + .willReturn(aResponse() + .withHeader("Content-Type", "application/json") .withStatus(HttpStatus.SC_NOT_FOUND))); - wireMockServer.stubFor(get(urlPathEqualTo("/api/multicloud/v1/CloudOwner/MTN13/infra_workload/workload-id")).willReturn(aResponse() - //.withHeader() - .withBodyFile("MulticloudResponse_Stack.json") + wireMockServer.stubFor(get(urlPathEqualTo(MULTICLOUD_GET_PATH_BY_ID)) + .inScenario("CREATE").whenScenarioStateIs("CREATING") + .willReturn(aResponse() + .withHeader("Content-Type", "application/json") + .withBody(GET_CREATE_STACK_RESPONSE) .withStatus(HttpStatus.SC_OK))); - wireMockServer.stubFor(get(urlPathEqualTo("/api/multicloud/v1/CloudOwner/MTN13/infra_workload/vfname/outputs")).willReturn(aResponse() - .withStatus(HttpStatus.SC_NOT_FOUND))); + wireMockServer.stubFor(get(urlPathEqualTo(MULTICLOUD_GET_PATH_BY_ID)) + .inScenario("CREATE").whenScenarioStateIs("UPDATING") + .willReturn(aResponse() + .withHeader("Content-Type", "application/json") + .withBody(GET_UPDATE_STACK_RESPONSE) + .withStatus(HttpStatus.SC_OK))); - wireMockServer.stubFor(post(urlPathEqualTo("/api/multicloud/v1/CloudOwner/MTN13/infra_workload")).willReturn(aResponse() + wireMockServer.stubFor(post(urlPathEqualTo(MULTICLOUD_CREATE_PATH)).inScenario("CREATE") + .willReturn(aResponse() + .withHeader("Content-Type", "application/json") .withBodyFile("MulticloudResponse_Stack_Create.json") - .withStatus(HttpStatus.SC_CREATED))); + .withStatus(HttpStatus.SC_CREATED)) + .willSetStateTo("CREATING")); + + wireMockServer.stubFor(post(urlPathEqualTo(MULTICLOUD_UPDATE_PATH)).inScenario("CREATE") + .willReturn(aResponse() + .withHeader("Content-Type", "application/json") + .withBody(UPDATE_STACK_RESPONSE) + .withStatus(HttpStatus.SC_ACCEPTED)) + .willSetStateTo("UPDATING")); + + try { + instance.createVfModule("MTN13", "CloudOwner", "123", "vf", "v1", "genericVnfId", "vfname", "vfModuleId", "create", null, "234", "9b339a61-69ca-465f-86b8-1c72c582b8e8", stackInputs, true, true, true, msoRequest, new Holder<>(), new Holder<>(), new Holder<>()); + } catch (VnfException e) { + fail("createVfModule success expected, failed with exception: " + e.toString()); + } + wireMockServer.resetScenarios(); + } + + @Test + public void createVfModuleAlreadyExists() throws Exception { + + Map<String, Object> stackInputs = new HashMap<>(); + stackInputs.put("oof_directives", "{}"); + stackInputs.put("sdnc_directives", "{}"); + stackInputs.put("user_directives", "{}"); + stackInputs.put("generic_vnf_id", "genVNFID"); + stackInputs.put("vf_module_id", "vfMODULEID"); + + MsoRequest msoRequest = new MsoRequest(); + msoRequest.setRequestId("12345"); + msoRequest.setServiceInstanceId("12345"); + + wireMockServer.stubFor(get(urlPathEqualTo("/api/multicloud/v1/CloudOwner/MTN13/infra_workload/vfname")).willReturn(aResponse() + //.withHeader() + .withBodyFile("MulticloudResponse_Stack.json") + .withStatus(HttpStatus.SC_OK))); - instance.createVfModule("MTN13", "CloudOwner", "123", "vf", "v1", "genericVnfId", "vfname", "vfModuleId", "create", null, "234", "9b339a61-69ca-465f-86b8-1c72c582b8e8", stackInputs, true, true, true, msoRequest, new Holder<>(), new Holder<>(), new Holder<>()); + try { + instance.createVfModule("MTN13", "CloudOwner", "123", "vf", "v1", "genericVnfId", "vfname", "vfModuleId", "create", null, "234", "9b339a61-69ca-465f-86b8-1c72c582b8e8", stackInputs, true, true, true, msoRequest, new Holder<>(), new Holder<>(), new Holder<>()); + } catch (VnfException e) { + assertTrue(e.toString().contains("Resource vfname already exists in owner/cloud/tenant CloudOwner/MTN13/123 with ID vfname/vfname")); + return; + } + fail("VnfAlreadyExists Exception expected!"); } @Test diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiServiceProvider.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiServiceProvider.java index a043bb85b6..b3767a3b62 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiServiceProvider.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiServiceProvider.java @@ -92,6 +92,18 @@ public interface AaiServiceProvider { final Vserver vserver); /** + * 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 vserver 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 diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiServiceProviderImpl.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiServiceProviderImpl.java index 364a6415a8..6c3d7c2ca6 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiServiceProviderImpl.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiServiceProviderImpl.java @@ -109,6 +109,13 @@ public class AaiServiceProviderImpl implements AaiServiceProvider { } @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, diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProvider.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProvider.java index 8af6889ae2..320715dd33 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProvider.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProvider.java @@ -58,6 +58,14 @@ public interface VnfmServiceProvider { String terminateVnf(final String vnfSelfLink, final TerminateVnfRequest terminateVnfRequest); /** + * Invoke a delete request for a VNF. + * + * @param vnfSelfLink the link to he VNF on the VNFM + * @return the operation ID of the instantiation operation + */ + void deleteVnf(final String vnfSelfLink); + + /** * Invoke a get request for a VNFM operation. * * @param vnfmId the id of the VNFM in AAI diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProviderImpl.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProviderImpl.java index d447befa45..246444fa8c 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProviderImpl.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/vnfm/VnfmServiceProviderImpl.java @@ -104,6 +104,17 @@ public class VnfmServiceProviderImpl implements VnfmServiceProvider { } @Override + public void deleteVnf(final String vnfSelfLink) { + logger.debug("Sending delete request to : " + vnfSelfLink); + final ResponseEntity<Void> response = httpServiceProvider.deleteHttpRequest(vnfSelfLink, Void.class); + if (response.getStatusCode() != HttpStatus.OK) { + throw new VnfmRequestFailureException( + "Delete request to " + vnfSelfLink + " return status code: " + response.getStatusCode()); + } + } + + + @Override public Optional<InlineResponse200> getOperation(final String vnfmId, final String operationId) { final String url = urlProvider.getOperationUrl(vnfmId, operationId); return httpServiceProvider.get(url, InlineResponse200.class); diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/jobmanagement/JobManager.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/jobmanagement/JobManager.java index 97a945cf1d..89356c1b67 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/jobmanagement/JobManager.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/jobmanagement/JobManager.java @@ -110,11 +110,27 @@ public class JobManager { final InlineResponse200 operationResponse) { final OperationStateEnum operationState = OperationStateEnum.fromValue(operationResponse.getOperationState().getValue()); - if (operationState == OperationStateEnum.COMPLETED && vnfmOperation.isWaitForNotificationForSuccess() - && !vnfmOperation.isNotificationProcessed()) { - return org.onap.vnfmadapter.v1.model.OperationStateEnum.PROCESSING; + switch (vnfmOperation.getNotificationStatus()) { + case NOTIFICATION_PROCESSING_NOT_REQUIRED: + default: + return operationState; + case NOTIFICATION_PROCESSING_PENDING: + return org.onap.vnfmadapter.v1.model.OperationStateEnum.PROCESSING; + case NOTIFICATION_PROCEESING_SUCCESSFUL: + return operationState; + case NOTIFICATION_PROCESSING_FAILED: + return org.onap.vnfmadapter.v1.model.OperationStateEnum.FAILED; } - return operationState; + } + + public void notificationProcessedForOperation(final String operationId, + final boolean notificationProcessingWasSuccessful) { + final java.util.Optional<VnfmOperation> relatedOperation = mapOfJobIdToVnfmOperation.values().stream() + .filter(operation -> operation.getOperationId().equals(operationId)).findFirst(); + if (relatedOperation.isPresent()) { + relatedOperation.get().setNotificationProcessed(notificationProcessingWasSuccessful); + } + logger.debug("No operation found for operation ID " + operationId); } } diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/jobmanagement/VnfmOperation.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/jobmanagement/VnfmOperation.java index 916c9e4011..e0ad327bd3 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/jobmanagement/VnfmOperation.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/jobmanagement/VnfmOperation.java @@ -27,13 +27,13 @@ public class VnfmOperation { private final String vnfmId; private final String operationId; - private boolean waitForNotificationForSuccess = false; - private boolean isNotificationProcessed = false; + private NotificationStatus notificationStatus; public VnfmOperation(final String vnfmId, final String operationId, final boolean waitForNotificationForSuccess) { this.vnfmId = vnfmId; this.operationId = operationId; - this.waitForNotificationForSuccess = waitForNotificationForSuccess; + this.notificationStatus = waitForNotificationForSuccess ? NotificationStatus.NOTIFICATION_PROCESSING_PENDING + : NotificationStatus.NOTIFICATION_PROCESSING_NOT_REQUIRED; } /** @@ -55,31 +55,43 @@ public class VnfmOperation { } /** - * Check if a notification should be processed before the operation is considered successfully - * completed. + * Set the required notification has been processed for the operation. * - * @return <code>true></code> if a notification must be processed before the operation is considered - * successfully completed, <code>false</code> otherwise + * @param notificationProcessingWasSuccessful <code>true</code> if the notification processing was + * successful, <code>false<code> otherwise */ - public boolean isWaitForNotificationForSuccess() { - return waitForNotificationForSuccess; + public void setNotificationProcessed(final boolean notificationProcessingWasSuccessful) { + this.notificationStatus = + notificationProcessingWasSuccessful ? NotificationStatus.NOTIFICATION_PROCEESING_SUCCESSFUL + : NotificationStatus.NOTIFICATION_PROCESSING_FAILED; } /** - * Set the required notification has been processed for the operation. + * Get the notification status for the operation. + * + * @return the notification status */ - public void setNotificationProcessed() { - this.isNotificationProcessed = true; + public NotificationStatus getNotificationStatus() { + return notificationStatus; } - /** - * Check if the required notification has been processed. - * - * @return <code>true</code> of the required notification has been processed, <code>false</code> - * otherwise - */ - public boolean isNotificationProcessed() { - return isNotificationProcessed; + 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; } } diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/notificationhandling/NotificationHandler.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/notificationhandling/NotificationHandler.java index 36b197dd06..b82ed86beb 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/notificationhandling/NotificationHandler.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/notificationhandling/NotificationHandler.java @@ -30,11 +30,13 @@ import org.onap.aai.domain.yang.GenericVnf; import org.onap.aai.domain.yang.Vserver; import org.onap.so.adapters.vnfmadapter.extclients.aai.AaiHelper; import org.onap.so.adapters.vnfmadapter.extclients.aai.AaiServiceProvider; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.VnfmServiceProvider; import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs; import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.VnfLcmOperationOccurrenceNotification; import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.VnfLcmOperationOccurrenceNotification.OperationStateEnum; import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse201; import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse201VimConnectionInfo; +import org.onap.so.adapters.vnfmadapter.jobmanagement.JobManager; import org.slf4j.Logger; /** @@ -46,16 +48,19 @@ public class NotificationHandler implements Runnable { 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; } @@ -63,12 +68,12 @@ public class NotificationHandler implements Runnable { public void run() { try { if (vnfLcmOperationOccurrenceNotification.getOperationState().equals(OperationStateEnum.COMPLETED)) { - final GenericVnf genericVnf = - aaiServiceProvider.invokeQueryGenericVnf(vnfInstance.getLinks().getSelf().getHref()).get(0); - switch (vnfLcmOperationOccurrenceNotification.getOperation()) { case INSTANTIATE: - handleVnfInstantiated(genericVnf); + handleVnfInstantiate(); + break; + case TERMINATE: + handleVnfTerminate(); break; default: } @@ -79,7 +84,15 @@ public class NotificationHandler implements Runnable { } } - private void handleVnfInstantiated(final GenericVnf genericVnf) { + private void handleVnfInstantiate() { + if (vnfLcmOperationOccurrenceNotification.getOperationState().equals(OperationStateEnum.COMPLETED)) { + handleVnfInstantiateCompleted(); + } + } + + private void handleVnfInstantiateCompleted() { + final GenericVnf genericVnf = + aaiServiceProvider.invokeQueryGenericVnf(vnfInstance.getLinks().getSelf().getHref()).get(0); final String ipAddress = getOamIpAddress(vnfInstance); logger.debug("Updating " + genericVnf.getVnfId() + " with VNF OAM IP ADDRESS: " + ipAddress); genericVnf.setIpv4OamAddress(ipAddress); @@ -108,6 +121,45 @@ public class NotificationHandler implements Runnable { } } + private void handleVnfTerminate() { + switch (vnfLcmOperationOccurrenceNotification.getOperationState()) { + case COMPLETED: + handleVnfTerminateCompleted(); + break; + case FAILED: + case ROLLING_BACK: + handleVnfTerminateFailed(); + break; + default: + } + } + + private void handleVnfTerminateFailed() { + final GenericVnf genericVnf = + aaiServiceProvider.invokeQueryGenericVnf(vnfInstance.getLinks().getSelf().getHref()).get(0); + updateVservers(vnfLcmOperationOccurrenceNotification, genericVnf.getVnfId(), + vnfInstance.getVimConnectionInfo()); + jobManager.notificationProcessedForOperation(vnfLcmOperationOccurrenceNotification.getId(), false); + } + + private void handleVnfTerminateCompleted() { + final GenericVnf genericVnf = + aaiServiceProvider.invokeQueryGenericVnf(vnfInstance.getLinks().getSelf().getHref()).get(0); + updateVservers(vnfLcmOperationOccurrenceNotification, genericVnf.getVnfId(), + vnfInstance.getVimConnectionInfo()); + + boolean deleteSuccessful = false; + try { + vnfmServiceProvider.deleteVnf(genericVnf.getSelflink()); + deleteSuccessful = true; + } finally { + jobManager.notificationProcessedForOperation(vnfLcmOperationOccurrenceNotification.getId(), + deleteSuccessful); + genericVnf.setOrchestrationStatus("Assigned"); + aaiServiceProvider.invokePutGenericVnf(genericVnf); + } + } + private void updateVservers(final VnfLcmOperationOccurrenceNotification notification, final String vnfId, final List<InlineResponse201VimConnectionInfo> vnfInstancesVimConnectionInfo) { final Map<String, InlineResponse201VimConnectionInfo> vimConnectionIdToVimConnectionInfo = new HashMap<>(); @@ -116,17 +168,21 @@ public class NotificationHandler implements Runnable { } for (final LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs vnfc : notification.getAffectedVnfcs()) { - + final InlineResponse201VimConnectionInfo vimConnectionInfo = + getVimConnectionInfo(vimConnectionIdToVimConnectionInfo, vnfc); switch (vnfc.getChangeType()) { case ADDED: final Vserver vserver = aaiHelper.createVserver(vnfc); aaiHelper.addRelationshipFromVserverVnfToGenericVnf(vserver, vnfId); - final InlineResponse201VimConnectionInfo vimConnectionInfo = - getVimConnectionInfo(vimConnectionIdToVimConnectionInfo, vnfc); + aaiServiceProvider.invokePutVserver(getCloudOwner(vimConnectionInfo), getCloudRegion(vimConnectionInfo), getTenant(vimConnectionInfo), vserver); break; case REMOVED: + aaiServiceProvider.invokeDeleteVserver(getCloudOwner(vimConnectionInfo), + getCloudRegion(vimConnectionInfo), getTenant(vimConnectionInfo), + vnfc.getComputeResource().getResourceId()); + break; case MODIFIED: case TEMPORARY: default: diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/Sol003LcnContoller.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/Sol003LcnContoller.java index 60f3f51e52..f0958cbe7d 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/Sol003LcnContoller.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/Sol003LcnContoller.java @@ -34,6 +34,7 @@ import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.VnfLcmOperatio import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.VnfLcmOperationOccurrenceNotification.OperationEnum; import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.VnfLcmOperationOccurrenceNotification.OperationStateEnum; import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse201; +import org.onap.so.adapters.vnfmadapter.jobmanagement.JobManager; import org.onap.so.adapters.vnfmadapter.notificationhandling.NotificationHandler; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; @@ -56,14 +57,16 @@ public class Sol003LcnContoller { 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 VnfmServiceProvider vnfmServiceProvider, final JobManager jobManager) { this.aaiServiceProvider = aaiServiceProvider; this.aaiHelper = aaiHelper; this.vnfmServiceProvider = vnfmServiceProvider; + this.jobManager = jobManager; } @PostMapping(value = "/lcn/VnfIdentifierCreationNotification") @@ -85,12 +88,10 @@ public class Sol003LcnContoller { @RequestBody final VnfLcmOperationOccurrenceNotification vnfLcmOperationOccurrenceNotification) { logger.info(LOG_LCN_RECEIVED + vnfLcmOperationOccurrenceNotification); - final OperationEnum operation = vnfLcmOperationOccurrenceNotification.getOperation(); - if ((operation.equals(OperationEnum.INSTANTIATE)) - && vnfLcmOperationOccurrenceNotification.getOperationState().equals(OperationStateEnum.COMPLETED)) { + if (isANotificationOfInterest(vnfLcmOperationOccurrenceNotification)) { final InlineResponse201 vnfInstance = getVnfInstance(vnfLcmOperationOccurrenceNotification); final NotificationHandler handler = new NotificationHandler(vnfLcmOperationOccurrenceNotification, - aaiHelper, aaiServiceProvider, vnfInstance); + aaiHelper, aaiServiceProvider, vnfmServiceProvider, jobManager, vnfInstance); executor.execute(handler); } @@ -98,6 +99,22 @@ public class Sol003LcnContoller { 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) { return vnfmServiceProvider.getVnf(vnfLcmOperationOccurrenceNotification.getLinks().getVnfInstance().getHref()) diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/Sol003LcnControllerTest.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/Sol003LcnControllerTest.java index b3fbcaa3b4..a8455f85db 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/Sol003LcnControllerTest.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/Sol003LcnControllerTest.java @@ -25,8 +25,10 @@ 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 com.google.gson.Gson; import java.net.URI; @@ -125,8 +127,33 @@ public class Sol003LcnControllerTest { } @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(); + final VnfLcmOperationOccurrenceNotification vnfLcmOperationOccurrenceNotification = + createNotification(OperationEnum.INSTANTIATE); + addVnfcsToNotification(vnfLcmOperationOccurrenceNotification, ChangeTypeEnum.ADDED); final InlineResponse201 vnfInstance = createVnfInstance(); mockRestServer.expect(requestTo(new URI("http://vnfm:8080/vnfs/myTestVnfIdOnVnfm"))) @@ -169,9 +196,51 @@ public class Sol003LcnControllerTest { assertEquals("myTestVnfId", relationship.getRelationshipData().get(0).getRelationshipValue()); } - private VnfLcmOperationOccurrenceNotification createNotification() { + @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.OK).contentType(MediaType.APPLICATION_JSON)); + + final GenericVnf genericVnf = createGenericVnf("vnfmType1"); + genericVnf.setSelflink("http://vnfm:8080/vnfs/myTestVnfIdOnVnfm"); + final List<GenericVnf> genericVnfs = new ArrayList<>(); + genericVnfs.add(genericVnf); + doReturn(Optional.of(genericVnfs)).when(aaiResourcesClient).get(eq(List.class), + MockitoHamcrest.argThat(new AaiResourceUriMatcher( + "/network/generic-vnfs?selflink=http%3A%2F%2Fvnfm%3A8080%2Fvnfs%2FmyTestVnfIdOnVnfm"))); + + 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(OperationEnum.INSTANTIATE); + notification.setOperation(operation); notification.setOperationState(OperationStateEnum.COMPLETED); final LcnVnfLcmOperationOccurrenceNotificationLinksVnfInstance linkToVnfInstance = @@ -181,10 +250,15 @@ public class Sol003LcnControllerTest { 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(ChangeTypeEnum.ADDED); + vnfc.changeType(changeType); final LcnVnfLcmOperationOccurrenceNotificationComputeResource computeResource = new LcnVnfLcmOperationOccurrenceNotificationComputeResource(); computeResource.setResourceId("myVnfc1"); @@ -192,7 +266,6 @@ public class Sol003LcnControllerTest { vnfc.setComputeResource(computeResource); affectedVnfcs.add(vnfc); notification.setAffectedVnfcs(affectedVnfcs); - return notification; } private InlineResponse201 createVnfInstance() { |