diff options
Diffstat (limited to 'adapters')
17 files changed, 532 insertions, 22 deletions
diff --git a/adapters/mso-catalog-db-adapter/src/test/java/org/onap/so/db/catalog/client/CatalogDbClientTest.java b/adapters/mso-catalog-db-adapter/src/test/java/org/onap/so/db/catalog/client/CatalogDbClientTest.java index 707a2a45af..739b4b62de 100644 --- a/adapters/mso-catalog-db-adapter/src/test/java/org/onap/so/db/catalog/client/CatalogDbClientTest.java +++ b/adapters/mso-catalog-db-adapter/src/test/java/org/onap/so/db/catalog/client/CatalogDbClientTest.java @@ -22,8 +22,8 @@ package org.onap.so.db.catalog.client; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; @@ -428,7 +428,7 @@ public class CatalogDbClientTest extends CatalogDbAdapterBaseTest { } @Test - public void testPostCloudSite() { + public void testCloudSiteClient() { CatalogDbClientPortChanger localClient = new CatalogDbClientPortChanger( "http://localhost:" + client.wiremockPort, msoAdaptersAuth, client.wiremockPort); CloudSite cloudSite = new CloudSite(); @@ -455,6 +455,19 @@ public class CatalogDbClientTest extends CatalogDbAdapterBaseTest { assertEquals("TESTCLLI", getCloudSite.getClli()); assertEquals("regionId", getCloudSite.getRegionId()); assertEquals("RANDOMID", getCloudSite.getIdentityServiceId()); + + getCloudSite.setClli("clli2"); + getCloudSite.setRegionId("region2"); + + CloudSite updatedCloudSite = this.client.updateCloudSite(getCloudSite); + assertNotNull(updatedCloudSite); + assertNotNull(updatedCloudSite.getIdentityService()); + assertEquals("clli2", updatedCloudSite.getClli()); + assertEquals("region2", updatedCloudSite.getRegionId()); + + this.client.deleteCloudSite(getCloudSite.getId()); + getCloudSite = this.client.getCloudSite("MTN6"); + assertNull(getCloudSite); } @Test diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/cloudregion/CloudException.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/cloudregion/CloudException.java new file mode 100644 index 0000000000..9cdf7e3b2a --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/cloudregion/CloudException.java @@ -0,0 +1,14 @@ +package org.onap.so.adapters.cloudregion; + +public class CloudException extends RuntimeException { + + /** + * + */ + private static final long serialVersionUID = -2631715095942372451L; + + public CloudException(String error, Exception e) { + super(error, e); + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/cloudregion/CloudRegionRestV1.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/cloudregion/CloudRegionRestV1.java new file mode 100644 index 0000000000..780480507b --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/cloudregion/CloudRegionRestV1.java @@ -0,0 +1,102 @@ +/*- + * ============LICENSE_START======================================================= + * OPENECOMP - SO + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * ================================================================================ + * Modifications Copyright (C) 2018 IBM. + * Modifications Copyright (c) 2019 Samsung + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ + +package org.onap.so.adapters.cloudregion; + + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import org.apache.http.HttpStatus; +import org.onap.so.db.catalog.beans.CloudSite; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; + + +@Path("/v1/cloud-region") +@Api(value = "/v1/cloud-region", description = "root of cloud region adapter") +@Component +public class CloudRegionRestV1 { + private static Logger logger = LoggerFactory.getLogger(CloudRegionRestV1.class); + + @Autowired + private CloudRestImpl cloudRestImpl; + + @POST + @Path("{cloud-region-id}/{cloud-owner}") + @Consumes({MediaType.APPLICATION_JSON}) + @Produces({MediaType.APPLICATION_JSON}) + @ApiOperation(value = "CreateCloudRegion", response = Response.class, + notes = "Create a cloud site in MSO and Region In AAI") + @ApiResponses({@ApiResponse(code = 201, message = "Cloud Region has been created"), + @ApiResponse(code = 500, message = "Create Cloud Region has failed")}) + public Response createCloudRegion( + @ApiParam(value = "cloud-region-id", required = true) @PathParam("cloud-region-id") String cloudRegionId, + @ApiParam(value = "cloud-owner", required = true) @PathParam("cloud-owner") String cloudOwner, + @ApiParam(value = "CloudSite", required = true) final CloudSite cloudSite) { + cloudRestImpl.createCloudRegion(cloudSite, cloudOwner); + return Response.status(HttpStatus.SC_CREATED).build(); + } + + @DELETE + @Path("{cloud-region-id}/{cloud-owner}") + @Consumes({MediaType.APPLICATION_JSON}) + @Produces({MediaType.APPLICATION_JSON}) + @ApiOperation(value = "CreateCloudRegion", response = Response.class, notes = "Delete an cloud Region in SO") + @ApiResponses({@ApiResponse(code = 204, message = "cloud Region has been deleted"), + @ApiResponse(code = 500, message = "Cloud Region delete has failed")}) + public Response deleteCloudRegion( + @ApiParam(value = "cloud-region-id", required = true) @PathParam("cloud-region-id") String cloudRegionId, + @ApiParam(value = "cloud-owner", required = true) @PathParam("cloud-owner") String cloudOwner) { + cloudRestImpl.deleteCloudRegion(cloudRegionId); + return Response.status(HttpStatus.SC_NO_CONTENT).build(); + } + + @PUT + @Path("{cloud-region-id}/{cloud-owner}") + @Consumes({MediaType.APPLICATION_JSON}) + @Produces({MediaType.APPLICATION_JSON}) + @ApiOperation(value = "CreateCloudRegion", response = Response.class, notes = "Update an existing Cloud Region") + @ApiResponses({@ApiResponse(code = 200, message = "Cloud Region has been updated"), + @ApiResponse(code = 500, message = "Update Cloud Region has failed examine entity object for details")}) + public Response updateCloudRegion( + @ApiParam(value = "cloud-region-id", required = true) @PathParam("cloud-region-id") String cloudRegionId, + @ApiParam(value = "cloud-owner", required = true) @PathParam("cloud-owner") String cloudOwner, + @ApiParam(value = "CloudSite", required = true) final CloudSite cloudSite) { + cloudRestImpl.updateCloudRegion(cloudSite, cloudOwner); + return Response.status(HttpStatus.SC_OK).build(); + } +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/cloudregion/CloudRestImpl.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/cloudregion/CloudRestImpl.java new file mode 100644 index 0000000000..4cde8655ae --- /dev/null +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/cloudregion/CloudRestImpl.java @@ -0,0 +1,97 @@ +package org.onap.so.adapters.cloudregion; + +import java.util.Optional; +import org.onap.aai.domain.yang.CloudRegion; +import org.onap.so.client.aai.AAIObjectType; +import org.onap.so.client.aai.AAIResourcesClient; +import org.onap.so.client.aai.entities.uri.AAIResourceUri; +import org.onap.so.client.aai.entities.uri.AAIUriFactory; +import org.onap.so.db.catalog.beans.CloudSite; +import org.onap.so.db.catalog.client.CatalogDbClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Component; + + +@Component +public class CloudRestImpl { + private static final Logger logger = LoggerFactory.getLogger(CloudRestImpl.class); + + private AAIResourcesClient aaiClient; + + @Autowired + private CatalogDbClient catalogDBClient; + + public void createCloudRegion(CloudSite cloudSite, String cloudOwner) throws CloudException { + createRegionInCatalogDb(cloudSite); + createCloudRegionInAAI(cloudSite, cloudOwner); + } + + public void updateCloudRegion(CloudSite cloudSite, String cloudOwner) throws CloudException { + updateRegionInCatalogDb(cloudSite); + } + + protected void updateRegionInCatalogDb(CloudSite cloudSite) { + try { + catalogDBClient.updateCloudSite(cloudSite); + } catch (Exception e) { + logger.error("Error updating cloud region in catalogdb", e); + throw new CloudException("Error updating cloud region in Catalog: " + e.getMessage(), e); + } + } + + public void deleteCloudRegion(String cloudRegionId) throws CloudException { + try { + catalogDBClient.deleteCloudSite(cloudRegionId); + } catch (Exception e) { + logger.error("Error deleting cloud region in catalogdb", e); + throw new CloudException("Error deleting cloud region in Catalog: " + e.getMessage(), e); + } + } + + protected void createCloudRegionInAAI(CloudSite cloudSite, String cloudOwner) { + try { + CloudRegion cloudRegion = mapCloudRegion(cloudSite, cloudOwner); + AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIObjectType.CLOUD_REGION, + cloudRegion.getCloudOwner(), cloudRegion.getCloudRegionId()); + getAaiClient().createIfNotExists(uri, Optional.of(cloudRegion)); + } catch (Exception e) { + logger.error("Error creating cloud region in AAI", e); + throw new CloudException("Error creating cloud region in AAI: " + e.getMessage(), e); + } + } + + protected void createRegionInCatalogDb(CloudSite cloudSite) throws CloudException { + try { + CloudSite existingCloudSite = catalogDBClient.getCloudSite(cloudSite.getRegionId()); + if (existingCloudSite == null) { + catalogDBClient.postCloudSite(cloudSite); + } + } catch (Exception e) { + logger.error("Error creating cloud site in Catalog Adapter: " + e.getMessage(), e); + throw new CloudException("Error creating cloud site in Catalog Adapter", e); + } + } + + protected CloudRegion mapCloudRegion(CloudSite cloudSite, String cloudOwner) { + CloudRegion region = new CloudRegion(); + region.setCloudOwner(cloudOwner); + region.setCloudRegionId(cloudSite.getRegionId()); + region.setCloudRegionVersion(cloudSite.getCloudVersion()); + region.setOwnerDefinedType("cLCP"); + region.setOrchestrationDisabled(false); + region.setComplexName("NA"); + region.setInMaint(false); + region.setCloudType("openstack"); + return region; + } + + protected AAIResourcesClient getAaiClient() { + if (aaiClient == null) + return new AAIResourcesClient(); + else + return aaiClient; + } + +} diff --git a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/CXFConfiguration.java b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/CXFConfiguration.java index 9fc5c979d8..9badd795eb 100644 --- a/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/CXFConfiguration.java +++ b/adapters/mso-openstack-adapters/src/main/java/org/onap/so/adapters/openstack/CXFConfiguration.java @@ -32,6 +32,7 @@ import org.apache.cxf.jaxrs.JAXRSServerFactoryBean; import org.apache.cxf.jaxrs.swagger.Swagger2Feature; import org.apache.cxf.jaxws.EndpointImpl; import org.apache.cxf.transport.servlet.CXFServlet; +import org.onap.so.adapters.cloudregion.CloudRegionRestV1; import org.onap.so.adapters.network.MsoNetworkAdapterAsyncImpl; import org.onap.so.adapters.network.MsoNetworkAdapterImpl; import org.onap.so.adapters.network.NetworkAdapterRest; @@ -47,10 +48,12 @@ import org.onap.so.adapters.vnf.VolumeAdapterRestV2; import org.onap.so.client.policy.JettisonStyleMapperProvider; import org.onap.so.logging.cxf.interceptor.SOAPLoggingInInterceptor; import org.onap.so.logging.cxf.interceptor.SOAPLoggingOutInterceptor; +import org.onap.so.logging.jaxrs.filter.SOAuditLogContainerFilter; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.web.servlet.ServletRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider; @@ -81,7 +84,14 @@ public class CXFConfiguration { @Autowired private MsoVnfCloudifyAdapterImpl vnfCloudifyAdapterImpl; @Autowired + private CloudRegionRestV1 cloudRegionRestV1; + @Autowired private JettisonStyleMapperProvider jettisonStyleObjectMapper; + @Autowired + private ObjectMapper mapper; + @Autowired + private SOAuditLogContainerFilter soAuditLogContainerFilter; + @Bean(name = Bus.DEFAULT_BUS_ID) public SpringBus springBus() { @@ -170,6 +180,7 @@ public class CXFConfiguration { return endpoint; } + // Uses Jettson Style marshalling semantics @Bean public Server rsServer() { JAXRSServerFactoryBean endpoint = new JAXRSServerFactoryBean(); @@ -178,7 +189,20 @@ public class CXFConfiguration { vnfAdapterRestV2, volumeAdapterRest, volumeAdapterRestV2)); endpoint.setAddress("/rest"); endpoint.setFeatures(Arrays.asList(createSwaggerFeature(), new LoggingFeature())); - endpoint.setProvider(new JacksonJsonProvider(jettisonStyleObjectMapper.getMapper())); + endpoint.setProviders(Arrays.asList(new JacksonJsonProvider(jettisonStyleObjectMapper.getMapper()), + soAuditLogContainerFilter)); + return endpoint.create(); + } + + // Uses normal Jackson marshalling semantics + @Bean + public Server rsServerApi() { + JAXRSServerFactoryBean endpoint = new JAXRSServerFactoryBean(); + endpoint.setBus(springBus()); + endpoint.setServiceBeans(Arrays.<Object>asList(cloudRegionRestV1)); + endpoint.setAddress("/api"); + endpoint.setFeatures(Arrays.asList(new LoggingFeature())); + endpoint.setProviders(Arrays.asList(new JacksonJsonProvider(mapper), soAuditLogContainerFilter)); return endpoint.create(); } diff --git a/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/cloudregion/CloudRegionRestImplTest.java b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/cloudregion/CloudRegionRestImplTest.java new file mode 100644 index 0000000000..9c62c286ac --- /dev/null +++ b/adapters/mso-openstack-adapters/src/test/java/org/onap/so/adapters/cloudregion/CloudRegionRestImplTest.java @@ -0,0 +1,96 @@ +package org.onap.so.adapters.cloudregion; + +import static com.shazam.shazamcrest.MatcherAssert.assertThat; +import static com.shazam.shazamcrest.matcher.Matchers.sameBeanAs; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import java.util.Optional; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.ArgumentCaptor; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.Spy; +import org.mockito.junit.MockitoJUnitRunner; +import org.onap.aai.domain.yang.CloudRegion; +import org.onap.so.client.aai.AAIObjectType; +import org.onap.so.client.aai.AAIResourcesClient; +import org.onap.so.client.aai.entities.uri.AAIResourceUri; +import org.onap.so.client.aai.entities.uri.AAIUriFactory; +import org.onap.so.db.catalog.beans.CloudSite; +import org.onap.so.db.catalog.client.CatalogDbClient; + + +@RunWith(MockitoJUnitRunner.class) +public class CloudRegionRestImplTest { + + @Spy + @InjectMocks + private CloudRestImpl cloudRestImpl; + + @Mock + private CatalogDbClient catalogDbClientMock; + + @Mock + private AAIResourcesClient aaiResClientMock; + + private CloudSite cloudSite = new CloudSite(); + + private CloudRegion testCloudRegion = new CloudRegion(); + + @Before + public void setup() { + cloudSite.setCloudVersion("1.0"); + cloudSite.setRegionId("region1"); + Mockito.doReturn(aaiResClientMock).when(cloudRestImpl).getAaiClient(); + testCloudRegion.setCloudOwner("bob"); + testCloudRegion.setCloudRegionId("region1"); + testCloudRegion.setCloudRegionVersion("1.0"); + testCloudRegion.setInMaint(false); + testCloudRegion.setOrchestrationDisabled(false); + testCloudRegion.setComplexName("NA"); + testCloudRegion.setCloudRegionVersion("1.0"); + testCloudRegion.setOwnerDefinedType("cLCP"); + testCloudRegion.setCloudType("openstack"); + } + + @Test + public void mapCloudRegionTest() { + CloudRegion mappedRegion = cloudRestImpl.mapCloudRegion(cloudSite, "bob"); + assertThat(mappedRegion, sameBeanAs(testCloudRegion)); + } + + @Test + public void createCloudRegionTest() { + when(catalogDbClientMock.getCloudSite("region1")).thenReturn(null); + when(catalogDbClientMock.postCloudSite(cloudSite)).thenReturn(cloudSite); + AAIResourceUri uri = AAIUriFactory.createResourceUri(AAIObjectType.CLOUD_REGION, "bob", "region1"); + cloudRestImpl.createCloudRegion(cloudSite, "bob"); + ArgumentCaptor<AAIResourceUri> actualURI = ArgumentCaptor.forClass(AAIResourceUri.class); + ArgumentCaptor<Optional<Object>> actualCloudRegion = ArgumentCaptor.forClass(Optional.class); + verify(catalogDbClientMock, times(1)).getCloudSite("region1"); + verify(catalogDbClientMock, times(1)).postCloudSite(cloudSite); + verify(aaiResClientMock, times(1)).createIfNotExists(Mockito.eq(uri), Mockito.any()); + verify(aaiResClientMock, times(1)).createIfNotExists(actualURI.capture(), actualCloudRegion.capture()); + assertThat((CloudRegion) actualCloudRegion.getValue().get(), sameBeanAs(testCloudRegion)); + } + + @Test + public void updateCloudRegionTest() { + when(catalogDbClientMock.updateCloudSite(cloudSite)).thenReturn(cloudSite); + cloudRestImpl.updateCloudRegion(cloudSite, "bob"); + verify(catalogDbClientMock, times(1)).updateCloudSite(cloudSite); + } + + @Test + public void deleteCloudRegionTest() { + doNothing().when(catalogDbClientMock).deleteCloudSite("region1"); + cloudRestImpl.deleteCloudRegion(cloudSite.getRegionId()); + verify(catalogDbClientMock, times(1)).deleteCloudSite("region1"); + } + +} diff --git a/adapters/mso-ve-vnfm-adapter/src/main/java/org/onap/so/adapters/vevnfm/controller/NotificationController.java b/adapters/mso-ve-vnfm-adapter/src/main/java/org/onap/so/adapters/vevnfm/controller/NotificationController.java index 2e5a00ad02..1882b4e183 100644 --- a/adapters/mso-ve-vnfm-adapter/src/main/java/org/onap/so/adapters/vevnfm/controller/NotificationController.java +++ b/adapters/mso-ve-vnfm-adapter/src/main/java/org/onap/so/adapters/vevnfm/controller/NotificationController.java @@ -20,9 +20,11 @@ package org.onap.so.adapters.vevnfm.controller; +import org.onap.so.adapters.vevnfm.service.DmaapService; import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.VnfLcmOperationOccurrenceNotification; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -33,9 +35,13 @@ public class NotificationController { private static final Logger logger = LoggerFactory.getLogger(NotificationController.class); + @Autowired + private DmaapService dmaapService; + @PostMapping("${notification.url}") public ResponseEntity receiveNotification(@RequestBody final VnfLcmOperationOccurrenceNotification notification) { logger.info("Notification received {}", notification); + dmaapService.send(notification); return ResponseEntity.ok().build(); } } diff --git a/adapters/mso-ve-vnfm-adapter/src/main/java/org/onap/so/adapters/vevnfm/service/DmaapService.java b/adapters/mso-ve-vnfm-adapter/src/main/java/org/onap/so/adapters/vevnfm/service/DmaapService.java new file mode 100644 index 0000000000..59397cead3 --- /dev/null +++ b/adapters/mso-ve-vnfm-adapter/src/main/java/org/onap/so/adapters/vevnfm/service/DmaapService.java @@ -0,0 +1,39 @@ +package org.onap.so.adapters.vevnfm.service; + +import org.onap.so.adapters.vnfmadapter.extclients.vnfm.lcn.model.VnfLcmOperationOccurrenceNotification; +import org.onap.so.rest.service.HttpRestServiceProvider; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Service; + +@Service +public class DmaapService { + + private static final Logger logger = LoggerFactory.getLogger(DmaapService.class); + + @Value("${dmaap.endpoint}") + private String endpoint; + + @Value("${dmaap.topic}") + private String topic; + + @Autowired + private HttpRestServiceProvider restProvider; + + public void send(final VnfLcmOperationOccurrenceNotification notification) { + final ResponseEntity<String> response = restProvider.postHttpRequest(notification, getUrl(), String.class); + + final HttpStatus statusCode = response.getStatusCode(); + final String body = response.getBody(); + + logger.info("The DMaaP replied with the code {} and the body {}", statusCode, body); + } + + private String getUrl() { + return endpoint + topic; + } +} diff --git a/adapters/mso-ve-vnfm-adapter/src/main/resources/application.yaml b/adapters/mso-ve-vnfm-adapter/src/main/resources/application.yaml index f3ad9615ec..35871c51ac 100644 --- a/adapters/mso-ve-vnfm-adapter/src/main/resources/application.yaml +++ b/adapters/mso-ve-vnfm-adapter/src/main/resources/application.yaml @@ -33,6 +33,10 @@ aai: vnfm: subscription: /vnflcm/v1/subscriptions +dmaap: + endpoint: http://message-router:30227 + topic: /events/unauthenticated.DCAE_CL_OUTPUT + spring: security: usercredentials: diff --git a/adapters/mso-ve-vnfm-adapter/src/test/java/org/onap/so/adapters/vevnfm/controller/NotificationControllerTest.java b/adapters/mso-ve-vnfm-adapter/src/test/java/org/onap/so/adapters/vevnfm/controller/NotificationControllerTest.java index 418c2e2201..57638a165a 100644 --- a/adapters/mso-ve-vnfm-adapter/src/test/java/org/onap/so/adapters/vevnfm/controller/NotificationControllerTest.java +++ b/adapters/mso-ve-vnfm-adapter/src/test/java/org/onap/so/adapters/vevnfm/controller/NotificationControllerTest.java @@ -21,6 +21,9 @@ package org.onap.so.adapters.vevnfm.controller; import static org.junit.Assert.assertEquals; +import static org.springframework.test.web.client.ExpectedCount.once; +import static org.springframework.test.web.client.match.MockRestRequestMatchers.anything; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -33,11 +36,13 @@ import org.springframework.http.MediaType; import org.springframework.mock.web.MockHttpServletResponse; import org.springframework.test.context.ActiveProfiles; import org.springframework.test.context.junit4.SpringRunner; +import org.springframework.test.web.client.MockRestServiceServer; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import org.springframework.test.web.servlet.setup.MockMvcBuilders; +import org.springframework.web.client.RestTemplate; import org.springframework.web.context.WebApplicationContext; @SpringBootTest @@ -54,11 +59,16 @@ public class NotificationControllerTest { @Autowired private WebApplicationContext webApplicationContext; + @Autowired + private RestTemplate restTemplate; + private MockMvc mvc; + private MockRestServiceServer mockRestServer; @Before public void init() { mvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build(); + mockRestServer = MockRestServiceServer.bindTo(restTemplate).build(); } @Test @@ -67,6 +77,8 @@ public class NotificationControllerTest { final MockHttpServletRequestBuilder request = MockMvcRequestBuilders.post(notificationUrl) .contentType(MediaType.APPLICATION_JSON).content(MINIMAL_JSON_CONTENT); + mockRestServer.expect(once(), anything()).andRespond(withSuccess()); + // when final MvcResult mvcResult = mvc.perform(request).andReturn(); @@ -74,5 +86,6 @@ public class NotificationControllerTest { final MockHttpServletResponse response = mvcResult.getResponse(); assertEquals(HttpStatus.OK.value(), response.getStatus()); assertEquals(ZERO, response.getContentLength()); + mockRestServer.verify(); } } diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/VnfmBasicWebSecurityConfigurerAdapter.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/VnfmBasicHttpSecurityConfigurer.java index a5404607b4..1e0a18a339 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/VnfmBasicWebSecurityConfigurerAdapter.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/VnfmBasicHttpSecurityConfigurer.java @@ -22,34 +22,41 @@ package org.onap.so.adapters.vnfmadapter; -import org.onap.so.security.SoBasicWebSecurityConfigurerAdapter; +import org.onap.so.security.HttpSecurityConfigurer; import org.onap.so.security.SoUserCredentialConfiguration; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; -import org.springframework.context.annotation.Configuration; +import org.springframework.context.annotation.Primary; import org.springframework.http.HttpMethod; import org.springframework.security.config.annotation.web.builders.HttpSecurity; -import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.stereotype.Component; +import org.springframework.util.StringUtils; /** * @author Waqas Ikram (waqas.ikram@est.tech) * @author Gareth Roper (gareth.roper@est.tech) * */ -@EnableWebSecurity -@Configuration -public class VnfmBasicWebSecurityConfigurerAdapter extends SoBasicWebSecurityConfigurerAdapter { +@Primary +@Component +public class VnfmBasicHttpSecurityConfigurer implements HttpSecurityConfigurer { + + @Autowired + private SoUserCredentialConfiguration soUserCredentialConfiguration; @Value("${server.ssl.client-auth:none}") private String clientAuth; - SoUserCredentialConfiguration soUserCredentialConfiguration; @Override - protected void configure(final HttpSecurity http) throws Exception { + public void configure(final HttpSecurity http) throws Exception { if (("need").equalsIgnoreCase(clientAuth)) { http.csrf().disable().authorizeRequests().anyRequest().permitAll(); } else { - super.configure(http); - http.authorizeRequests().antMatchers(HttpMethod.GET, "/etsi/subscription/notification").permitAll(); + http.csrf().disable().authorizeRequests().antMatchers("/manage/health", "/manage/info").permitAll() + .antMatchers(HttpMethod.GET, "/etsi/subscription/notification").permitAll().antMatchers("/**") + .hasAnyRole(StringUtils.collectionToDelimitedString(soUserCredentialConfiguration.getRoles(), ",")) + .and().httpBasic(); + } } } diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/etsicatalog/EtsiCatalogServiceProvider.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/etsicatalog/EtsiCatalogServiceProvider.java index 62b365745c..e0eed159c2 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/etsicatalog/EtsiCatalogServiceProvider.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/etsicatalog/EtsiCatalogServiceProvider.java @@ -23,7 +23,6 @@ package org.onap.so.adapters.vnfmadapter.extclients.etsicatalog; import java.util.Optional; import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.model.PkgmSubscription; import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.InlineResponse2001; -import org.springframework.http.ResponseEntity; /** * Provides methods for invoking REST calls to the ETSI Catalog Manager. @@ -74,11 +73,18 @@ public interface EtsiCatalogServiceProvider { Optional<byte[]> getVnfPackageArtifact(final String vnfPkgId, final String artifactPath); /** - * Post the SubscriptionRequest Object. + * POST the SubscriptionRequest Object. * - * @return The ResponseEntity containing the ETSI Catalog Manager's PkgmSubscription object. + * @return The ETSI Catalog Manager's PkgmSubscription object. */ Optional<PkgmSubscription> postSubscription( final org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.model.PkgmSubscriptionRequest etsiCatalogManagerSubscriptionRequest); + /** + * DELETE the SubscriptionRequest Object. + * + * @return A Boolean representing if the delete was successful or not. + */ + Boolean deleteSubscription(final String subscriptionId); + } diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/etsicatalog/EtsiCatalogServiceProviderImpl.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/etsicatalog/EtsiCatalogServiceProviderImpl.java index 1a48494e1a..573a798410 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/etsicatalog/EtsiCatalogServiceProviderImpl.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/extclients/etsicatalog/EtsiCatalogServiceProviderImpl.java @@ -21,11 +21,14 @@ package org.onap.so.adapters.vnfmadapter.extclients.etsicatalog; import java.util.Optional; -import javax.swing.text.html.Option; import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.model.PkgmSubscription; import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.model.VnfPkgInfo; import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.InlineResponse2001; -import org.onap.so.adapters.vnfmadapter.rest.exceptions.*; +import org.onap.so.adapters.vnfmadapter.rest.exceptions.EtsiCatalogManagerBadRequestException; +import org.onap.so.adapters.vnfmadapter.rest.exceptions.EtsiCatalogManagerRequestFailureException; +import org.onap.so.adapters.vnfmadapter.rest.exceptions.VnfPkgBadRequestException; +import org.onap.so.adapters.vnfmadapter.rest.exceptions.VnfPkgConflictException; +import org.onap.so.adapters.vnfmadapter.rest.exceptions.VnfPkgNotFoundException; import org.onap.so.rest.exceptions.HttpResouceNotFoundException; import org.onap.so.rest.exceptions.InvalidRestRequestException; import org.onap.so.rest.exceptions.RestProcessingException; @@ -190,7 +193,8 @@ public class EtsiCatalogServiceProviderImpl implements EtsiCatalogServiceProvide return Optional.empty(); } catch (final InvalidRestRequestException invalidRestRequestException) { logger.error("Caught InvalidRestRequestException", invalidRestRequestException); - throw new EtsiCatalogManagerBadRequestException("Bad Request Received on postSubscription call."); + throw new EtsiCatalogManagerBadRequestException( + "Bad Request Received on postSubscription call to ETSI Catalog Manager."); } catch (final RestProcessingException restProcessingException) { logger.error("Caught RestProcessingException with Status Code: {}", restProcessingException.getStatusCode(), restProcessingException); @@ -200,6 +204,28 @@ public class EtsiCatalogServiceProviderImpl implements EtsiCatalogServiceProvide } } + public Boolean deleteSubscription(final String subscriptionId) { + try { + final ResponseEntity<Void> responseEntity = httpServiceProvider + .deleteHttpRequest(etsiCatalogUrlProvider.getSubscriptionUrl() + "/" + subscriptionId, Void.class); + + if (responseEntity.getStatusCode() == HttpStatus.NO_CONTENT) { + logger.info("Subscription with ID: {} has been successfully deleted from the ETSI Catalog Manager", + subscriptionId); + return true; + } + logger.error("Unexpected Status Code Received on deleteSubscription: {}", responseEntity.getStatusCode()); + return false; + } catch (final InvalidRestRequestException invalidRestRequestException) { + logger.error("Caught InvalidRestRequestException on deleteSubscription call to ETSI Catalog Manager.", + invalidRestRequestException); + throw new EtsiCatalogManagerBadRequestException( + "Bad Request Received on deleteSubscription call to ETSI Catalog Manager."); + } + } + + + private Optional<byte[]> requestVnfElement(final String vnfPkgId, final String vnfRequestUrl, final String vnfRequestName) { try { diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/SubscriptionManager.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/SubscriptionManager.java index 30a16f70a8..bbf8b74952 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/SubscriptionManager.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/SubscriptionManager.java @@ -143,6 +143,15 @@ public class SubscriptionManager { return response; } + public boolean deleteSubscription(final String subscriptionId) { + if (getSubscription(subscriptionId).isPresent()) { + if (etsiCatalogServiceProvider.deleteSubscription(subscriptionId)) { + return packageManagementCacheServiceProvider.deleteSubscription(subscriptionId); + } + } + return false; + } + public URI getSubscriptionUri(final String subscriptionId) { return URI.create( vnfmAdapterEndpoint + Constants.PACKAGE_MANAGEMENT_BASE_URL + "/subscriptions/" + subscriptionId); diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/cache/PackageManagementCacheServiceProvider.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/cache/PackageManagementCacheServiceProvider.java index 6042513a50..437d20e593 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/cache/PackageManagementCacheServiceProvider.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/packagemanagement/subscriptionmanagement/cache/PackageManagementCacheServiceProvider.java @@ -60,7 +60,7 @@ public interface PackageManagementCacheServiceProvider { * Delete subscription from cache * * @param subscriptionId - * @return true if subscription exists and able to be removed, otherwise returns false + * @return Boolean */ boolean deleteSubscription(final String subscriptionId); diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/Sol003PackageManagementSubscriptionController.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/Sol003PackageManagementSubscriptionController.java index cbad564210..4be0838c08 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/Sol003PackageManagementSubscriptionController.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/main/java/org/onap/so/adapters/vnfmadapter/rest/Sol003PackageManagementSubscriptionController.java @@ -23,14 +23,13 @@ package org.onap.so.adapters.vnfmadapter.rest; import static org.onap.so.adapters.vnfmadapter.Constants.PACKAGE_MANAGEMENT_BASE_URL; import static org.slf4j.LoggerFactory.getLogger; import java.net.URI; -import java.net.URISyntaxException; import java.security.GeneralSecurityException; import java.util.List; import java.util.Optional; import javax.ws.rs.core.MediaType; +import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.model.ProblemDetails; import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.InlineResponse2002; import org.onap.so.adapters.vnfmadapter.extclients.vnfm.packagemanagement.model.PkgmSubscriptionRequest; -import org.onap.so.adapters.vnfmadapter.extclients.etsicatalog.model.ProblemDetails; import org.onap.so.adapters.vnfmadapter.packagemanagement.subscriptionmanagement.SubscriptionManager; import org.slf4j.Logger; import org.springframework.beans.factory.annotation.Autowired; @@ -38,6 +37,7 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Controller; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; @@ -140,6 +140,24 @@ public class Sol003PackageManagementSubscriptionController { } /** + * DELETE a specific subscription, by subscriptionId. Section Number: 10.4.8.3.5 + * + * @param subscriptionId The ID of the subscription that you wish to delete. + * @return Empty response if successful. Object: Void Response Code: 204 No Content + */ + @DeleteMapping(value = "/subscriptions/{subscriptionId}") + public ResponseEntity<?> deleteSubscription(@PathVariable("subscriptionId") final String subscriptionId) { + if (subscriptionManager.deleteSubscription(subscriptionId)) { + logger.debug("Successfully deleted subscription with id {}", subscriptionId); + return ResponseEntity.noContent().build(); + } + final String errorMessage = + "The requested subscription: " + subscriptionId + " was not found on call deleteSubscription"; + logger.error(errorMessage); + return ResponseEntity.status(HttpStatus.NOT_FOUND).body(new ProblemDetails().detail(errorMessage)); + } + + /** * Method to set the Location in the header with the URI parameter * * @param subscriptionUri diff --git a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/Sol003PackageManagementSubscriptionControllerTest.java b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/Sol003PackageManagementSubscriptionControllerTest.java index f90978e0d5..3d26c33679 100644 --- a/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/Sol003PackageManagementSubscriptionControllerTest.java +++ b/adapters/mso-vnfm-adapter/mso-vnfm-etsi-adapter/src/test/java/org/onap/so/adapters/vnfmadapter/rest/Sol003PackageManagementSubscriptionControllerTest.java @@ -68,6 +68,7 @@ import org.springframework.web.client.RestTemplate; import org.springframework.http.HttpMethod; import static org.springframework.test.web.client.match.MockRestRequestMatchers.method; import static org.hamcrest.Matchers.is; +import static org.springframework.test.web.client.response.MockRestResponseCreators.withStatus; import static org.springframework.test.web.client.response.MockRestResponseCreators.withSuccess; /** @@ -199,6 +200,41 @@ public class Sol003PackageManagementSubscriptionControllerTest { assertEquals(HttpStatus.OK, response.getStatusCode()); } + @Test + public void testSuccessDeleteSubscriptionWithSubscriptionId() throws GeneralSecurityException { + final PkgmSubscriptionRequest pkgmSubscriptionRequest = buildPkgmSubscriptionRequest(); + final PkgmSubscription pkgmSubscription = buildPkgmSubscription(); + final String subscriptionId = pkgmSubscription.getId(); + + mockRestServer.expect(requestTo(msbEndpoint)).andExpect(method(HttpMethod.POST)) + .andRespond(withSuccess(gson.toJson(pkgmSubscription), MediaType.APPLICATION_JSON)); + mockRestServer.expect(requestTo(msbEndpoint + "/" + subscriptionId)).andExpect(method(HttpMethod.DELETE)) + .andRespond(withStatus(HttpStatus.NO_CONTENT)); + + final ResponseEntity<InlineResponse2002> responsePost = + (ResponseEntity<InlineResponse2002>) sol003PackageManagementSubscriptionController + .postSubscriptionRequest(pkgmSubscriptionRequest); + + + final ResponseEntity responseDelete = + sol003PackageManagementSubscriptionController.deleteSubscription(subscriptionId); + + // Attempt to retrieve the subscription after delete + final ResponseEntity<InlineResponse2002> responseGetSubscription = + (ResponseEntity<InlineResponse2002>) sol003PackageManagementSubscriptionController + .getSubscription(subscriptionId); + + assertEquals(HttpStatus.NOT_FOUND, responseGetSubscription.getStatusCode()); + assertEquals(HttpStatus.NO_CONTENT, responseDelete.getStatusCode()); + } + + @Test + public void testFailDeleteSubscriptionWithInvalidSubscriptionId() throws URISyntaxException, InterruptedException { + final ResponseEntity<Void> responseDelete = (ResponseEntity<Void>) sol003PackageManagementSubscriptionController + .deleteSubscription("invalidSubscriptionId"); + assertEquals(HttpStatus.NOT_FOUND, responseDelete.getStatusCode()); + } + private PkgmSubscriptionRequest buildPkgmSubscriptionRequest() { final PkgmSubscriptionRequest pkgmSubscriptionRequest = new PkgmSubscriptionRequest(); final SubscriptionsFilter sub = buildSubscriptionsFilter(); |