diff options
9 files changed, 78 insertions, 40 deletions
diff --git a/cps-ncmp-rest/docs/openapi/components.yaml b/cps-ncmp-rest/docs/openapi/components.yaml index a9311d0861..112dddf61c 100644 --- a/cps-ncmp-rest/docs/openapi/components.yaml +++ b/cps-ncmp-rest/docs/openapi/components.yaml @@ -505,6 +505,14 @@ components: schema: type: string example: my-cm-handle + cmHandleReferenceInPath: + name: cm-handle + in: path + description: The identifier (cmHandle or alternate) for a network function, network element, subnetwork or any other cm object by managed Network CM Proxy + required: true + schema: + type: string + example: my-cm-handle-reference moduleNameInQuery: name: module-name in: query diff --git a/cps-ncmp-rest/docs/openapi/ncmp.yml b/cps-ncmp-rest/docs/openapi/ncmp.yml index 6972463e3c..9a6c076f03 100755 --- a/cps-ncmp-rest/docs/openapi/ncmp.yml +++ b/cps-ncmp-rest/docs/openapi/ncmp.yml @@ -27,7 +27,7 @@ resourceDataForCmHandle: operationId: getResourceDataForCmHandle parameters: - $ref: 'components.yaml#/components/parameters/datastoreName' - - $ref: 'components.yaml#/components/parameters/cmHandleInPath' + - $ref: 'components.yaml#/components/parameters/cmHandleReferenceInPath' - $ref: 'components.yaml#/components/parameters/resourceIdentifierInQuery' - $ref: 'components.yaml#/components/parameters/optionsParamInQuery' - $ref: 'components.yaml#/components/parameters/topicParamInQuery' @@ -60,7 +60,7 @@ resourceDataForCmHandle: operationId: createResourceDataRunningForCmHandle parameters: - $ref: 'components.yaml#/components/parameters/datastoreName' - - $ref: 'components.yaml#/components/parameters/cmHandleInPath' + - $ref: 'components.yaml#/components/parameters/cmHandleReferenceInPath' - $ref: 'components.yaml#/components/parameters/resourceIdentifierInQuery' - $ref: 'components.yaml#/components/parameters/contentParamInHeader' - $ref: 'components.yaml#/components/parameters/authorizationParamInHeader' @@ -99,7 +99,7 @@ resourceDataForCmHandle: operationId: updateResourceDataRunningForCmHandle parameters: - $ref: 'components.yaml#/components/parameters/datastoreName' - - $ref: 'components.yaml#/components/parameters/cmHandleInPath' + - $ref: 'components.yaml#/components/parameters/cmHandleReferenceInPath' - $ref: 'components.yaml#/components/parameters/resourceIdentifierInQuery' - $ref: 'components.yaml#/components/parameters/contentParamInHeader' - $ref: 'components.yaml#/components/parameters/authorizationParamInHeader' @@ -138,7 +138,7 @@ resourceDataForCmHandle: operationId: patchResourceDataRunningForCmHandle parameters: - $ref: 'components.yaml#/components/parameters/datastoreName' - - $ref: 'components.yaml#/components/parameters/cmHandleInPath' + - $ref: 'components.yaml#/components/parameters/cmHandleReferenceInPath' - $ref: 'components.yaml#/components/parameters/resourceIdentifierInQuery' - $ref: 'components.yaml#/components/parameters/contentParamInHeader' - $ref: 'components.yaml#/components/parameters/authorizationParamInHeader' @@ -171,7 +171,7 @@ resourceDataForCmHandle: operationId: deleteResourceDataRunningForCmHandle parameters: - $ref: 'components.yaml#/components/parameters/datastoreName' - - $ref: 'components.yaml#/components/parameters/cmHandleInPath' + - $ref: 'components.yaml#/components/parameters/cmHandleReferenceInPath' - $ref: 'components.yaml#/components/parameters/resourceIdentifierInQuery' - $ref: 'components.yaml#/components/parameters/contentParamInHeader' - $ref: 'components.yaml#/components/parameters/authorizationParamInHeader' @@ -377,7 +377,7 @@ getCmHandlePropertiesById: summary: Get CM handle properties operationId: getCmHandlePublicPropertiesByCmHandleId parameters: - - $ref: 'components.yaml#/components/parameters/cmHandleInPath' + - $ref: 'components.yaml#/components/parameters/cmHandleReferenceInPath' responses: 200: description: OK @@ -400,7 +400,7 @@ getCmHandleStateById: summary: Get CM handle state operationId: getCmHandleStateByCmHandleId parameters: - - $ref: 'components.yaml#/components/parameters/cmHandleInPath' + - $ref: 'components.yaml#/components/parameters/cmHandleReferenceInPath' responses: 200: description: OK diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java index 6a2e9a1541..ca2907b8d6 100755 --- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java +++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java @@ -148,7 +148,7 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { * Patch resource data. * * @param datastoreName name of the datastore (currently only supports "ncmp-datastore:passthrough-running") - * @param cmHandleReference cm handle or alternate identifier + * @param cmHandleReference cm handle or alternate identifier * @param resourceIdentifier resource identifier * @param requestBody the request body * @param contentType content type of body @@ -177,7 +177,7 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { * Create resource data for given cm-handle. * * @param datastoreName name of the datastore (currently only supports "ncmp-datastore:passthrough-running") - * @param cmHandleReference cm handle or alternate identifier + * @param cmHandleReference cm handle or alternate identifier * @param resourceIdentifier resource identifier * @param requestBody the request body * @param contentType content type of body @@ -202,7 +202,7 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { * Update resource data for given cm-handle. * * @param datastoreName name of the datastore (currently only supports "ncmp-datastore:passthrough-running") - * @param cmHandleReference cm handle or alternate identifier + * @param cmHandleReference cm handle or alternate identifier * @param resourceIdentifier resource identifier * @param requestBody the request body * @param contentType content type of the body @@ -228,7 +228,7 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { * Delete resource data for a given cm-handle. * * @param datastoreName name of the datastore (currently only supports "ncmp-datastore:passthrough-running") - * @param cmHandleReference cm handle or alternate identifier + * @param cmHandleReference cm handle or alternate identifier * @param resourceIdentifier resource identifier * @param contentType content type of the body * @param authorization contents of Authorization header, or null if not present @@ -298,16 +298,16 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { } /** - * Get Cm Handle Properties by Cm Handle Id. + * Get Cm Handle Properties by Cm Handle or alternate Identifier. * - * @param cmHandleId cm-handle identifier + * @param cmHandleReference cm-handle or alternate identifier * @return cm handle properties */ @Override public ResponseEntity<RestOutputCmHandlePublicProperties> getCmHandlePublicPropertiesByCmHandleId( - final String cmHandleId) { + final String cmHandleReference) { final CmHandlePublicProperties cmHandlePublicProperties = new CmHandlePublicProperties(); - cmHandlePublicProperties.add(networkCmProxyInventoryFacade.getCmHandlePublicProperties(cmHandleId)); + cmHandlePublicProperties.add(networkCmProxyInventoryFacade.getCmHandlePublicProperties(cmHandleReference)); final RestOutputCmHandlePublicProperties restOutputCmHandlePublicProperties = new RestOutputCmHandlePublicProperties(); restOutputCmHandlePublicProperties.setPublicCmHandleProperties(cmHandlePublicProperties); diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy index 92b47c6c8b..80e74caf75 100644 --- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy +++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy @@ -308,13 +308,13 @@ class NetworkCmProxyControllerSpec extends Specification { assert !response.contentAsString.contains("some DMI property") } - def 'Get Cm Handle public properties by Cm Handle id.'() { + def 'Get Cm Handle public properties by Cm Handle Reference.'() { given: 'a cm handle properties endpoint' - def cmHandlePropertiesEndpoint = "$ncmpBasePathV1/ch/some-cm-handle/properties" + def cmHandlePropertiesEndpoint = "$ncmpBasePathV1/ch/some-cm-handle-reference/properties" and: 'some cm handle public properties' def publicProperties = ['public prop': 'some public property'] and: 'the service method is invoked with the cm handle id returning the cm handle public properties' - 1 * mockNetworkCmProxyInventoryFacade.getCmHandlePublicProperties('some-cm-handle') >> publicProperties + 1 * mockNetworkCmProxyInventoryFacade.getCmHandlePublicProperties('some-cm-handle-reference') >> publicProperties when: 'the cm handle properties api is invoked' def response = mvc.perform(get(cmHandlePropertiesEndpoint)).andReturn().response then: 'the correct response is returned' diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/NetworkCmProxyInventoryFacade.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/NetworkCmProxyInventoryFacade.java index e678159d9f..785eb8f022 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/NetworkCmProxyInventoryFacade.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/NetworkCmProxyInventoryFacade.java @@ -191,12 +191,13 @@ public class NetworkCmProxyInventoryFacade { } /** - * Get cm handle public properties for a given cm handle id. + * Get cm handle public properties for a given cm handle or alternate id. * - * @param cmHandleId cm handle identifier + * @param cmHandleReference cm handle or alternate identifier * @return cm handle public properties */ - public Map<String, String> getCmHandlePublicProperties(final String cmHandleId) { + public Map<String, String> getCmHandlePublicProperties(final String cmHandleReference) { + final String cmHandleId = alternateIdMatcher.getCmHandleId(cmHandleReference); final YangModelCmHandle yangModelCmHandle = inventoryPersistence.getYangModelCmHandle(cmHandleId); return YangDataConverter.toPropertiesMap(yangModelCmHandle.getPublicProperties()); } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutor.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutor.java index 89b48f3755..b3aa848394 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutor.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutor.java @@ -20,7 +20,9 @@ package org.onap.cps.ncmp.impl.data.policyexecutor; +import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -28,6 +30,7 @@ import java.util.Map; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.onap.cps.ncmp.api.data.models.OperationType; +import org.onap.cps.ncmp.api.exceptions.NcmpException; import org.onap.cps.ncmp.api.exceptions.PolicyExecutorException; import org.onap.cps.ncmp.api.exceptions.ServerNcmpException; import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; @@ -58,6 +61,8 @@ public class PolicyExecutor { @Qualifier("policyExecutorWebClient") private final WebClient policyExecutorWebClient; + private final ObjectMapper objectMapper; + /** * Use the Policy Executor to check permission for a cm write operation. * Wil throw an exception when the operation is not permitted (work in progress) @@ -108,7 +113,13 @@ public class PolicyExecutor { data.put("resourceIdentifier", resourceIdentifier); data.put("targetIdentifier", yangModelCmHandle.getAlternateId()); if (!OperationType.DELETE.equals(operationType)) { - data.put("cmChangeRequest", changeRequestAsJson); + try { + final Object changeRequestAsObject = objectMapper.readValue(changeRequestAsJson, Object.class); + data.put("cmChangeRequest", changeRequestAsObject); + } catch (final JsonProcessingException e) { + throw new NcmpException("Cannot convert Change Request data to Object", + "Invalid Json: " + changeRequestAsJson); + } } final Map<String, Object> request = new HashMap<>(2); diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/PolicyExecutorConfigurationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorConfigurationSpec.groovy index c086eab810..c859bb0a09 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/PolicyExecutorConfigurationSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorConfigurationSpec.groovy @@ -18,10 +18,10 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.impl.data +package org.onap.cps.ncmp.impl.data.policyexecutor +import com.fasterxml.jackson.databind.ObjectMapper import org.onap.cps.ncmp.config.PolicyExecutorHttpClientConfig -import org.onap.cps.ncmp.impl.data.policyexecutor.PolicyExecutor import org.onap.cps.ncmp.impl.policyexecutor.PolicyExecutorWebClientConfiguration import org.onap.cps.ncmp.utils.WebClientBuilderTestConfig import org.springframework.beans.factory.annotation.Autowired @@ -30,7 +30,7 @@ import org.springframework.test.context.ContextConfiguration import spock.lang.Specification @SpringBootTest -@ContextConfiguration(classes = [PolicyExecutor, PolicyExecutorWebClientConfiguration, PolicyExecutorHttpClientConfig, WebClientBuilderTestConfig ]) +@ContextConfiguration(classes = [ObjectMapper, PolicyExecutor, PolicyExecutorWebClientConfiguration, PolicyExecutorHttpClientConfig, WebClientBuilderTestConfig ]) class PolicyExecutorConfigurationSpec extends Specification { @Autowired diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/PolicyExecutorSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorSpec.groovy index a5776676dc..63a915ab64 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/PolicyExecutorSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorSpec.groovy @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.ncmp.impl.data +package org.onap.cps.ncmp.impl.data.policyexecutor import ch.qos.logback.classic.Level import ch.qos.logback.classic.Logger @@ -26,9 +26,9 @@ import ch.qos.logback.classic.spi.ILoggingEvent import ch.qos.logback.core.read.ListAppender import com.fasterxml.jackson.databind.JsonNode import com.fasterxml.jackson.databind.ObjectMapper +import org.onap.cps.ncmp.api.exceptions.NcmpException import org.onap.cps.ncmp.api.exceptions.PolicyExecutorException import org.onap.cps.ncmp.api.exceptions.ServerNcmpException -import org.onap.cps.ncmp.impl.data.policyexecutor.PolicyExecutor import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle import org.slf4j.LoggerFactory import org.springframework.http.HttpStatus @@ -47,12 +47,13 @@ class PolicyExecutorSpec extends Specification { def mockWebClient = Mock(WebClient) def mockRequestBodyUriSpec = Mock(WebClient.RequestBodyUriSpec) def mockResponseSpec = Mock(WebClient.ResponseSpec) + def spiedObjectMapper = Spy(ObjectMapper) - PolicyExecutor objectUnderTest = new PolicyExecutor(mockWebClient) + PolicyExecutor objectUnderTest = new PolicyExecutor(mockWebClient, spiedObjectMapper) def logAppender = Spy(ListAppender<ILoggingEvent>) - ObjectMapper objectMapper = new ObjectMapper() + def someValidJson = '{"Hello":"World"}' def setup() { setupLogger() @@ -72,7 +73,7 @@ class PolicyExecutorSpec extends Specification { given: 'allow response' mockResponse([decision:'allow'], HttpStatus.OK) when: 'permission is checked for an operation' - objectUnderTest.checkPermission(new YangModelCmHandle(), operationType, 'my credentials','my resource','my change') + objectUnderTest.checkPermission(new YangModelCmHandle(), operationType, 'my credentials','my resource',someValidJson) then: 'system logs the operation is allowed' assert getLogEntry(2) == 'Policy Executor allows the operation' and: 'no exception occurs' @@ -85,7 +86,7 @@ class PolicyExecutorSpec extends Specification { given: 'other response' mockResponse([decision:'other', decisionId:123, message:'I dont like Mondays' ], HttpStatus.OK) when: 'permission is checked for an operation' - objectUnderTest.checkPermission(new YangModelCmHandle(), PATCH, 'my credentials','my resource','my change') + objectUnderTest.checkPermission(new YangModelCmHandle(), PATCH, 'my credentials','my resource',someValidJson) then: 'Policy Executor exception is thrown' def thrownException = thrown(PolicyExecutorException) assert thrownException.message == 'Policy Executor did not allow request. Decision #123 : other' @@ -96,7 +97,7 @@ class PolicyExecutorSpec extends Specification { given: 'other response' mockResponse([], HttpStatus.I_AM_A_TEAPOT) when: 'permission is checked for an operation' - objectUnderTest.checkPermission(new YangModelCmHandle(), PATCH, 'my credentials','my resource','my change') + objectUnderTest.checkPermission(new YangModelCmHandle(), PATCH, 'my credentials','my resource',someValidJson) then: 'Server Ncmp exception is thrown' def thrownException = thrown(ServerNcmpException) assert thrownException.message == 'Policy Executor invocation failed' @@ -107,7 +108,7 @@ class PolicyExecutorSpec extends Specification { given: 'invalid response from Policy executor' mockResponseSpec.toEntity(*_) >> invalidResponse when: 'permission is checked for an operation' - objectUnderTest.checkPermission(new YangModelCmHandle(), CREATE, 'my credentials','my resource','my change') + objectUnderTest.checkPermission(new YangModelCmHandle(), CREATE, 'my credentials','my resource',someValidJson) then: 'system logs the expected message' assert getLogEntry(1) == expectedMessage where: 'following invalid responses are received' @@ -116,17 +117,26 @@ class PolicyExecutorSpec extends Specification { Mono.just(new ResponseEntity<>(null, HttpStatus.OK)) || 'No valid response body from policy, ignored' } + def 'Permission check with an invalid change request json.'() { + when: 'permission is checked for an invalid change request' + objectUnderTest.checkPermission(new YangModelCmHandle(), CREATE, 'my credentials', 'my resource', 'invalid json string') + then: 'an ncmp exception thrown' + def ncmpException = thrown(NcmpException) + ncmpException.message == 'Cannot convert Change Request data to Object' + ncmpException.details.contains('invalid json string') + } + def 'Permission check feature disabled.'() { given: 'feature is disabled' objectUnderTest.enabled = false when: 'permission is checked for an operation' - objectUnderTest.checkPermission(new YangModelCmHandle(), PATCH, 'my credentials','my resource','my change') + objectUnderTest.checkPermission(new YangModelCmHandle(), PATCH, 'my credentials','my resource',someValidJson) then: 'system logs that the feature not enabled' assert getLogEntry(0) == 'Policy Executor Enabled: false' } def mockResponse(mockResponseAsMap, httpStatus) { - JsonNode jsonNode = objectMapper.readTree(objectMapper.writeValueAsString(mockResponseAsMap)) + JsonNode jsonNode = spiedObjectMapper.readTree(spiedObjectMapper.writeValueAsString(mockResponseAsMap)) def mono = Mono.just(new ResponseEntity<>(jsonNode, httpStatus)) mockResponseSpec.toEntity(*_) >> mono } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/NetworkCmProxyInventoryFacadeSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/NetworkCmProxyInventoryFacadeSpec.groovy index b243a74cd9..9d51fff05a 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/NetworkCmProxyInventoryFacadeSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/NetworkCmProxyInventoryFacadeSpec.groovy @@ -134,17 +134,25 @@ class NetworkCmProxyInventoryFacadeSpec extends Specification { assert result.currentTrustLevel == TrustLevel.COMPLETE } - def 'Get cm handle public properties'() { + def 'Get cm handle public properties using #scenario'() { given: 'a yang modelled cm handle' def dmiProperties = [new YangModelCmHandle.Property('prop', 'some DMI property')] def publicProperties = [new YangModelCmHandle.Property('public prop', 'some public prop')] - def yangModelCmHandle = new YangModelCmHandle(id:'some-cm-handle', dmiServiceName: 'some service name', dmiProperties: dmiProperties, publicProperties: publicProperties) + def cmHandleId = 'some-cm-handle' + def alternateId = 'some-alternate-id' + def yangModelCmHandle = new YangModelCmHandle(id:cmHandleId, alternateId: alternateId, dmiServiceName: 'some service name', dmiProperties: dmiProperties, publicProperties: publicProperties) + and: 'we have corresponding cm handle for the cm handle reference' + 1 * mockAlternateIdMatcher.getCmHandleId(cmHandleRef) >> cmHandleId and: 'the system returns this yang modelled cm handle' - 1 * mockInventoryPersistence.getYangModelCmHandle('some-cm-handle') >> yangModelCmHandle - when: 'getting cm handle public properties for a given cm handle id from ncmp service' - def result = objectUnderTest.getCmHandlePublicProperties('some-cm-handle') + 1 * mockInventoryPersistence.getYangModelCmHandle(cmHandleId) >> yangModelCmHandle + when: 'getting cm handle public properties for a given cm handle reference from ncmp service' + def result = objectUnderTest.getCmHandlePublicProperties(cmHandleRef) then: 'the result returns the correct data' assert result == [ 'public prop' : 'some public prop' ] + where: 'following cm handle reference is used' + scenario | cmHandleRef + 'Cm Handle Reference as cm handle-id' | 'some-cm-handle' + 'Cm Handle Reference as alternate-id' | 'some-alternate-id' } def 'Get cm handle composite state using #scenario'() { |