diff options
Diffstat (limited to 'adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src')
6 files changed, 604 insertions, 0 deletions
diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiHelper.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiHelper.java index 893df02019..bacbea141e 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiHelper.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/aai/AaiHelper.java @@ -30,6 +30,8 @@ import org.onap.aai.domain.yang.Relationship; import org.onap.aai.domain.yang.RelationshipData; import org.onap.aai.domain.yang.RelationshipList; import org.onap.aai.domain.yang.Tenant; +import org.onap.aai.domain.yang.Vserver; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs; import org.onap.so.adapters.vnfmadapter.rest.exceptions.VnfmNotFoundException; import org.onap.so.client.aai.AAIObjectType; import org.onap.so.client.aai.AAIVersion; @@ -172,4 +174,43 @@ public class AaiHelper { return false; } + /** + * Create a vserver. + * + * @param vnfc the VNFC to base the vserver on + * @return the vserver + */ + public Vserver createVserver(final LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs vnfc) { + final Vserver vserver = new Vserver(); + vserver.setVserverId(vnfc.getComputeResource().getResourceId()); + vserver.setVserverName(vnfc.getId()); + vserver.setProvStatus("active"); + vserver.setVserverSelflink("Not available"); + return vserver; + } + + /** + * Add a relationship to the given vserver to the given VNF. + * + * @param vnf the vserver + * @param vnfmId the ID of the VNF + */ + public void addRelationshipFromVserverVnfToGenericVnf(final Vserver vserver, final String vnfId) { + if (vserver.getRelationshipList() == null) { + vserver.setRelationshipList(new RelationshipList()); + } + final RelationshipList vserverRelationshiplist = vserver.getRelationshipList(); + vserverRelationshiplist.getRelationship().add(createRelationshipToGenericVnf(vnfId)); + } + + private Relationship createRelationshipToGenericVnf(final String vnfId) { + final Relationship relationship = new Relationship(); + relationship.setRelatedTo("generic-vnf"); + relationship.setRelationshipLabel("tosca.relationships.HostedOn"); + relationship.setRelatedLink("/aai/" + AAIVersion.LATEST + + AAIUriFactory.createResourceUri(AAIObjectType.GENERIC_VNF, vnfId).build().toString()); + relationship.getRelationshipData().add(createRelationshipData("generic-vnf.vnf-id", vnfId)); + return relationship; + } + } 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 d11da0c91b..a043bb85b6 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 @@ -20,11 +20,13 @@ package org.onap.so.adapters.vnfmadapter.extclients.aai; +import java.util.List; import org.onap.aai.domain.yang.EsrSystemInfoList; import org.onap.aai.domain.yang.EsrVnfm; import org.onap.aai.domain.yang.EsrVnfmList; import org.onap.aai.domain.yang.GenericVnf; import org.onap.aai.domain.yang.Tenant; +import org.onap.aai.domain.yang.Vserver; /** * Provides methods for invoking REST calls to AAI. @@ -40,6 +42,14 @@ public interface AaiServiceProvider { GenericVnf invokeGetGenericVnf(final String vnfId); /** + * Invoke a query for a generic VNF with the given selfLink + * + * @param selfLink the selfLink + * @return the matching generic vnfs + */ + List<GenericVnf> invokeQueryGenericVnf(final String selfLink); + + /** * Invoke a GET request for the VNFMs. * * @return the VNFMs @@ -70,6 +80,18 @@ public interface AaiServiceProvider { void invokePutGenericVnf(GenericVnf vnf); /** + * Invoke a PUT request for a vserver. + * + * @param cloudOwner the cloud owner + * @param cloudRegion the cloud region + * @param tenantId the ID of the tenant + * @param vserver the vserver + * @return + */ + void invokePutVserver(final String cloudOwner, final String cloudRegion, final String tenantId, + final Vserver vserver); + + /** * Invoke a 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 fa0dcf07f1..364a6415a8 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 @@ -20,11 +20,13 @@ package org.onap.so.adapters.vnfmadapter.extclients.aai; +import java.util.List; import org.onap.aai.domain.yang.EsrSystemInfoList; import org.onap.aai.domain.yang.EsrVnfm; import org.onap.aai.domain.yang.EsrVnfmList; import org.onap.aai.domain.yang.GenericVnf; import org.onap.aai.domain.yang.Tenant; +import org.onap.aai.domain.yang.Vserver; import org.onap.so.client.aai.AAIObjectType; import org.onap.so.client.aai.entities.uri.AAIUriFactory; import org.slf4j.Logger; @@ -54,6 +56,17 @@ public class AaiServiceProviderImpl implements AaiServiceProvider { } @Override + public List<GenericVnf> invokeQueryGenericVnf(final String selfLink) { + return aaiClientProvider.getAaiClient() + .get(List.class, + AAIUriFactory.createResourceUri(AAIObjectType.GENERIC_VNFS).queryParam("selflink", selfLink)) + .orElseGet(() -> { + logger.debug("No vnf found in AAI with selflink: {}", selfLink); + return null; + }); + } + + @Override public EsrVnfmList invokeGetVnfms() { return aaiClientProvider.getAaiClient() .get(EsrVnfmList.class, AAIUriFactory.createResourceUri(AAIObjectType.VNFM_LIST)).orElseGet(() -> { @@ -89,6 +102,13 @@ public class AaiServiceProviderImpl implements AaiServiceProvider { } @Override + public void invokePutVserver(final String cloudOwner, final String cloudRegion, final String tenant, + final Vserver vserver) { + aaiClientProvider.getAaiClient().update(AAIUriFactory.createResourceUri(AAIObjectType.VSERVER, cloudOwner, + cloudRegion, tenant, vserver.getVserverId()), vserver); + } + + @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/notificationhandling/NotificationHandler.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/notificationhandling/NotificationHandler.java new file mode 100644 index 0000000000..36b197dd06 --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/notificationhandling/NotificationHandler.java @@ -0,0 +1,159 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnfmadapter.notificationhandling; + +import static org.slf4j.LoggerFactory.getLogger; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.json.JSONException; +import org.json.JSONObject; +import org.onap.aai.domain.yang.GenericVnf; +import org.onap.aai.domain.yang.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.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.slf4j.Logger; + +/** + * Performs updates to AAI based on a received notification. The updates are executed in a separate + * thread so as the notification response to the VNFM is not delayed. + */ +public class NotificationHandler implements Runnable { + private static Logger logger = getLogger(NotificationHandler.class); + private final VnfLcmOperationOccurrenceNotification vnfLcmOperationOccurrenceNotification; + private final AaiHelper aaiHelper; + private final AaiServiceProvider aaiServiceProvider; + + + private final InlineResponse201 vnfInstance; + + public NotificationHandler(final VnfLcmOperationOccurrenceNotification vnfLcmOperationOccurrenceNotification, + final AaiHelper aaiHelper, final AaiServiceProvider aaiServiceProvider, + final InlineResponse201 vnfInstance) { + this.vnfLcmOperationOccurrenceNotification = vnfLcmOperationOccurrenceNotification; + this.aaiHelper = aaiHelper; + this.aaiServiceProvider = aaiServiceProvider; + this.vnfInstance = vnfInstance; + } + + @Override + 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); + break; + default: + } + } + } catch (final Exception exception) { + logger.error("Error encountered handling notification, AAI may not be updated correctly " + + vnfLcmOperationOccurrenceNotification, exception); + } + } + + private void handleVnfInstantiated(final GenericVnf genericVnf) { + final String ipAddress = getOamIpAddress(vnfInstance); + logger.debug("Updating " + genericVnf.getVnfId() + " with VNF OAM IP ADDRESS: " + ipAddress); + genericVnf.setIpv4OamAddress(ipAddress); + genericVnf.setOrchestrationStatus("Created"); + + aaiServiceProvider.invokePutGenericVnf(genericVnf); + + updateVservers(vnfLcmOperationOccurrenceNotification, genericVnf.getVnfId(), + vnfInstance.getVimConnectionInfo()); + + logger.debug("Finished handling notification for vnfm: " + vnfInstance.getId()); + } + + private String getOamIpAddress(final InlineResponse201 vnfInstance) { + try { + logger.debug("ConfigurableProperties: " + vnfInstance.getVnfConfigurableProperties()); + if (vnfInstance.getVnfConfigurableProperties() == null) { + logger.warn("No ConfigurableProperties, cannot set OAM IP Address"); + return null; + } + final JSONObject properties = new JSONObject((Map) vnfInstance.getVnfConfigurableProperties()); + return properties.get("vnfIpAddress").toString(); + } catch (final JSONException jsonException) { + logger.error("Error getting vnfIpAddress", jsonException); + return null; + } + } + + private void updateVservers(final VnfLcmOperationOccurrenceNotification notification, final String vnfId, + final List<InlineResponse201VimConnectionInfo> vnfInstancesVimConnectionInfo) { + final Map<String, InlineResponse201VimConnectionInfo> vimConnectionIdToVimConnectionInfo = new HashMap<>(); + for (final InlineResponse201VimConnectionInfo vimConnectionInfo : vnfInstancesVimConnectionInfo) { + vimConnectionIdToVimConnectionInfo.put(vimConnectionInfo.getId(), vimConnectionInfo); + } + + for (final LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs vnfc : notification.getAffectedVnfcs()) { + + 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: + case MODIFIED: + case TEMPORARY: + default: + } + } + } + + private InlineResponse201VimConnectionInfo getVimConnectionInfo( + final Map<String, InlineResponse201VimConnectionInfo> vimConnectionIdToVimConnectionInfo, + final LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs vnfc) { + final String vimConnectionId = vnfc.getComputeResource().getVimConnectionId(); + return vimConnectionIdToVimConnectionInfo.get(vimConnectionId); + } + + private String getCloudOwner(final InlineResponse201VimConnectionInfo vimConnectionInfo) { + final String vimId = vimConnectionInfo.getVimId(); + return vimId.substring(0, vimId.indexOf("_")); + } + + private String getCloudRegion(final InlineResponse201VimConnectionInfo vimConnectionInfo) { + final String vimId = vimConnectionInfo.getVimId(); + return vimId.substring(vimId.indexOf("_") + 1); + } + + private String getTenant(final InlineResponse201VimConnectionInfo vimConnectionInfo) { + final JSONObject vimConnectionJsonObject = new JSONObject(vimConnectionInfo); + return vimConnectionJsonObject.getJSONObject("accessInfo").get("projectId").toString(); + } + +} diff --git a/adapters/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 new file mode 100644 index 0000000000..60f3f51e52 --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/Sol003LcnContoller.java @@ -0,0 +1,107 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnfmadapter.rest; + +import static org.onap.so.adapters.vnfmadapter.Constants.BASE_URL; +import static org.slf4j.LoggerFactory.getLogger; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import javax.ws.rs.core.MediaType; +import org.onap.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.VnfIdentifierCreationNotification; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.VnfIdentifierDeletionNotification; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.VnfLcmOperationOccurrenceNotification; +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.notificationhandling.NotificationHandler; +import org.slf4j.Logger; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; + +/** + * Controller for handling notifications from the VNFM (Virtual Network Function Manager). + */ +@Controller +@RequestMapping(value = BASE_URL, produces = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}, + consumes = {MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML}) +public class Sol003LcnContoller { + private static Logger logger = getLogger(Sol003LcnContoller.class); + private static final String LOG_LCN_RECEIVED = "LCN received from VNFM: "; + private final AaiServiceProvider aaiServiceProvider; + private final AaiHelper aaiHelper; + private final VnfmServiceProvider vnfmServiceProvider; + private final ExecutorService executor = Executors.newCachedThreadPool(); + + @Autowired + Sol003LcnContoller(final AaiServiceProvider aaiServiceProvider, final AaiHelper aaiHelper, + final VnfmServiceProvider vnfmServiceProvider) { + this.aaiServiceProvider = aaiServiceProvider; + this.aaiHelper = aaiHelper; + this.vnfmServiceProvider = vnfmServiceProvider; + } + + @PostMapping(value = "/lcn/VnfIdentifierCreationNotification") + public ResponseEntity<Void> lcnVnfIdentifierCreationNotificationPost( + @RequestBody final VnfIdentifierCreationNotification vnfIdentifierCreationNotification) { + logger.info(LOG_LCN_RECEIVED + vnfIdentifierCreationNotification); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @PostMapping(value = "/lcn/VnfIdentifierDeletionNotification") + public ResponseEntity<Void> lcnVnfIdentifierDeletionNotificationPost( + @RequestBody final VnfIdentifierDeletionNotification vnfIdentifierDeletionNotification) { + logger.info(LOG_LCN_RECEIVED + vnfIdentifierDeletionNotification); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + @PostMapping(value = "/lcn/VnfLcmOperationOccurrenceNotification") + public ResponseEntity<Void> lcnVnfLcmOperationOccurrenceNotificationPost( + @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)) { + final InlineResponse201 vnfInstance = getVnfInstance(vnfLcmOperationOccurrenceNotification); + final NotificationHandler handler = new NotificationHandler(vnfLcmOperationOccurrenceNotification, + aaiHelper, aaiServiceProvider, vnfInstance); + executor.execute(handler); + } + + logger.info("Sending notification response"); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + private InlineResponse201 getVnfInstance( + final VnfLcmOperationOccurrenceNotification vnfLcmOperationOccurrenceNotification) { + return vnfmServiceProvider.getVnf(vnfLcmOperationOccurrenceNotification.getLinks().getVnfInstance().getHref()) + .get(); + } + +} 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 new file mode 100644 index 0000000000..b3fbcaa3b4 --- /dev/null +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/Sol003LcnControllerTest.java @@ -0,0 +1,255 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2019 Nordix Foundation. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * SPDX-License-Identifier: Apache-2.0 + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.vnfmadapter.rest; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.timeout; +import static org.mockito.Mockito.verify; +import static org.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.withSuccess; +import com.google.gson.Gson; +import java.net.URI; +import java.net.URISyntaxException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Optional; +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.hamcrest.MockitoHamcrest; +import org.onap.aai.domain.yang.GenericVnf; +import org.onap.aai.domain.yang.Relationship; +import org.onap.aai.domain.yang.Vserver; +import org.onap.so.adapters.vnfmadapter.VnfmAdapterApplication; +import org.onap.so.adapters.vnfmadapter.extclients.vim.model.AccessInfo; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs.ChangeTypeEnum; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.LcnVnfLcmOperationOccurrenceNotificationComputeResource; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.LcnVnfLcmOperationOccurrenceNotificationLinks; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.LcnVnfLcmOperationOccurrenceNotificationLinksVnfInstance; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.VnfIdentifierCreationNotification; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.VnfLcmOperationOccurrenceNotification; +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.extclients.vnfm.model.InlineResponse201Links; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse201LinksSelf; +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.model.InlineResponse201VimConnectionInfo; +import org.onap.so.client.aai.AAIResourcesClient; +import org.onap.so.client.aai.entities.uri.AAIResourceUri; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.boot.test.context.SpringBootTest.WebEnvironment; +import org.springframework.boot.test.mock.mockito.MockBean; +import org.springframework.boot.web.server.LocalServerPort; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.client.MockRestServiceServer; +import org.springframework.web.client.RestTemplate; + + +@RunWith(SpringRunner.class) +@SpringBootTest(classes = VnfmAdapterApplication.class, webEnvironment = WebEnvironment.RANDOM_PORT) +@ActiveProfiles("test") +public class Sol003LcnControllerTest { + + private static final String CLOUD_OWNER = "myTestCloudOwner"; + private static final String REGION = "myTestRegion"; + private static final String TENANT_ID = "myTestTenantId"; + + @LocalServerPort + private int port; + @Autowired + @Qualifier(CONFIGURABLE_REST_TEMPLATE) + private RestTemplate testRestTemplate; + private MockRestServiceServer mockRestServer; + + @MockBean + private AAIResourcesClient aaiResourcesClient; + + @Autowired + private Sol003LcnContoller controller; + private final Gson gson = new Gson(); + + @Before + public void setUp() throws Exception { + mockRestServer = MockRestServiceServer.bindTo(testRestTemplate).build(); + } + + @Test + public void lcnNotification_IdentifierCreated_Returns204() throws URISyntaxException, InterruptedException { + final VnfIdentifierCreationNotification vnfIdentifierCreationNotification = + new VnfIdentifierCreationNotification(); + final ResponseEntity<Void> response = + controller.lcnVnfIdentifierCreationNotificationPost(vnfIdentifierCreationNotification); + assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode()); + } + + @Test + public void lcnNotification_IdentifierDeleted_Returns204() throws URISyntaxException, InterruptedException { + final VnfIdentifierCreationNotification vnfIdentifierCreationNotification = + new VnfIdentifierCreationNotification(); + final ResponseEntity<Void> response = + controller.lcnVnfIdentifierCreationNotificationPost(vnfIdentifierCreationNotification); + assertEquals(HttpStatus.NO_CONTENT, response.getStatusCode()); + } + + @Test + public void lcnNotification_InstantiateCompleted_AaiUpdated() throws URISyntaxException, InterruptedException { + final VnfLcmOperationOccurrenceNotification vnfLcmOperationOccurrenceNotification = createNotification(); + final InlineResponse201 vnfInstance = createVnfInstance(); + + mockRestServer.expect(requestTo(new URI("http://vnfm:8080/vnfs/myTestVnfIdOnVnfm"))) + .andRespond(withSuccess(gson.toJson(vnfInstance), MediaType.APPLICATION_JSON)); + + final GenericVnf genericVnf = createGenericVnf("vnfmType1"); + 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<Object> bodyArgument = ArgumentCaptor.forClass(Object.class); + final ArgumentCaptor<AAIResourceUri> uriArgument = ArgumentCaptor.forClass(AAIResourceUri.class); + + verify(aaiResourcesClient, timeout(1000).times(2)).update(uriArgument.capture(), bodyArgument.capture()); + + assertEquals("/network/generic-vnfs/generic-vnf/myTestVnfId", + uriArgument.getAllValues().get(0).build().toString()); + final GenericVnf updatedGenericVnf = (GenericVnf) bodyArgument.getAllValues().get(0); + assertEquals("10.10.10.10", updatedGenericVnf.getIpv4OamAddress()); + assertEquals("Created", updatedGenericVnf.getOrchestrationStatus()); + + assertEquals( + "/cloud-infrastructure/cloud-regions/cloud-region/" + CLOUD_OWNER + "/" + REGION + "/tenants/tenant/" + + TENANT_ID + "/vservers/vserver/myVnfc1", + uriArgument.getAllValues().get(1).build().toString()); + + final Vserver vserver = (Vserver) bodyArgument.getAllValues().get(1); + assertEquals("myVnfc1", vserver.getVserverId()); + final Relationship relationship = vserver.getRelationshipList().getRelationship().get(0); + assertEquals("generic-vnf", relationship.getRelatedTo()); + assertEquals("tosca.relationships.HostedOn", relationship.getRelationshipLabel()); + assertEquals("/aai/v15/network/generic-vnfs/generic-vnf/myTestVnfId", relationship.getRelatedLink()); + assertEquals("generic-vnf.vnf-id", relationship.getRelationshipData().get(0).getRelationshipKey()); + assertEquals("myTestVnfId", relationship.getRelationshipData().get(0).getRelationshipValue()); + } + + private VnfLcmOperationOccurrenceNotification createNotification() { + final VnfLcmOperationOccurrenceNotification notification = new VnfLcmOperationOccurrenceNotification(); + notification.setOperation(OperationEnum.INSTANTIATE); + notification.setOperationState(OperationStateEnum.COMPLETED); + + final LcnVnfLcmOperationOccurrenceNotificationLinksVnfInstance linkToVnfInstance = + new LcnVnfLcmOperationOccurrenceNotificationLinksVnfInstance() + .href("http://vnfm:8080/vnfs/myTestVnfIdOnVnfm"); + final LcnVnfLcmOperationOccurrenceNotificationLinks operationLinks = + new LcnVnfLcmOperationOccurrenceNotificationLinks().vnfInstance(linkToVnfInstance); + notification.setLinks(operationLinks); + + final List<LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs> affectedVnfcs = new ArrayList<>();; + final LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs vnfc = + new LcnVnfLcmOperationOccurrenceNotificationAffectedVnfcs(); + vnfc.changeType(ChangeTypeEnum.ADDED); + final LcnVnfLcmOperationOccurrenceNotificationComputeResource computeResource = + new LcnVnfLcmOperationOccurrenceNotificationComputeResource(); + computeResource.setResourceId("myVnfc1"); + computeResource.setVimConnectionId(CLOUD_OWNER + "_" + REGION); + vnfc.setComputeResource(computeResource); + affectedVnfcs.add(vnfc); + notification.setAffectedVnfcs(affectedVnfcs); + return notification; + } + + private InlineResponse201 createVnfInstance() { + final InlineResponse201 vnfInstance = new InlineResponse201(); + final InlineResponse201LinksSelf selfLink = new InlineResponse201LinksSelf(); + selfLink.setHref("http://vnfm:8080/vnfs/myTestVnfIdOnVnfm"); + final InlineResponse201Links VnfInstancelinks = new InlineResponse201Links(); + VnfInstancelinks.setSelf(selfLink); + vnfInstance.setLinks(VnfInstancelinks); + + final Map<String, String> vnfConfigurableProperties = new HashMap<>(); + vnfConfigurableProperties.put("vnfIpAddress", "10.10.10.10"); + vnfInstance.setVnfConfigurableProperties(vnfConfigurableProperties); + + final List<InlineResponse201VimConnectionInfo> vimConnectionInfo = new ArrayList<>();; + final InlineResponse201VimConnectionInfo vimConnection = new InlineResponse201VimConnectionInfo(); + vimConnection.setVimId(CLOUD_OWNER + "_" + REGION); + vimConnection.setId(CLOUD_OWNER + "_" + REGION); + final AccessInfo accessInfo = new AccessInfo(); + accessInfo.setProjectId(TENANT_ID); + vimConnection.setAccessInfo(accessInfo); + vimConnectionInfo.add(vimConnection); + vnfInstance.setVimConnectionInfo(vimConnectionInfo); + return vnfInstance; + } + + private GenericVnf createGenericVnf(final String type) { + final GenericVnf genericVnf = new GenericVnf(); + genericVnf.setVnfId("myTestVnfId"); + genericVnf.setNfType(type); + return genericVnf; + } + + private class AaiResourceUriMatcher extends BaseMatcher<AAIResourceUri> { + + final String uriAsString; + + public AaiResourceUriMatcher(final String uriAsString) { + this.uriAsString = uriAsString; + } + + @Override + public boolean matches(final Object item) { + if (item instanceof AAIResourceUri) { + if (uriAsString.endsWith("...")) { + return ((AAIResourceUri) item).build().toString() + .startsWith(uriAsString.substring(0, uriAsString.indexOf("..."))); + } + return ((AAIResourceUri) item).build().toString().equals(uriAsString); + } + return false; + } + + @Override + public void describeTo(final Description description) {} + + } + + +} |