diff options
Diffstat (limited to 'cps-ncmp-service/src/main/java')
8 files changed, 198 insertions, 73 deletions
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/PolicyExecutorException.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/PolicyExecutorException.java new file mode 100644 index 0000000000..333c12271b --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/exceptions/PolicyExecutorException.java @@ -0,0 +1,42 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2024 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.cps.ncmp.api.exceptions; + +import lombok.Getter; + +/** + * Exception to be used when policy execution fails or does not allow to proceed. + */ +@Getter +public class PolicyExecutorException extends NcmpException { + + private static final long serialVersionUID = 6659897770659834798L; + + /** + * Constructor to form exception for policy executor responses. + * + * @param message response message + * @param details response details + */ + public PolicyExecutorException(final String message, final String details) { + super(message, details); + } +} 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 1acd937a31..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 @@ -26,6 +26,7 @@ package org.onap.cps.ncmp.api.inventory; import static org.onap.cps.ncmp.impl.inventory.CmHandleQueryParametersValidator.validateCmHandleQueryParameters; +import java.util.ArrayList; import java.util.Collection; import java.util.Map; import lombok.RequiredArgsConstructor; @@ -44,6 +45,7 @@ import org.onap.cps.ncmp.impl.inventory.models.CmHandleQueryConditions; import org.onap.cps.ncmp.impl.inventory.models.InventoryQueryConditions; import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; import org.onap.cps.ncmp.impl.inventory.trustlevel.TrustLevelManager; +import org.onap.cps.ncmp.impl.models.RequiredDmiService; import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher; import org.onap.cps.ncmp.impl.utils.YangDataConverter; import org.onap.cps.spi.model.ModuleDefinition; @@ -143,9 +145,13 @@ public class NetworkCmProxyInventoryFacade { final CmHandleQueryServiceParameters cmHandleQueryServiceParameters = jsonObjectMapper.convertToValueType( cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class); validateCmHandleQueryParameters(cmHandleQueryServiceParameters, CmHandleQueryConditions.ALL_CONDITION_NAMES); - final Collection<NcmpServiceCmHandle> ncmpServiceCmHandles = + final Collection<YangModelCmHandle> yangModelCmHandles = parameterizedCmHandleQueryService.queryCmHandles(cmHandleQueryServiceParameters); - ncmpServiceCmHandles.forEach(this::applyCurrentTrustLevel); + final Collection<NcmpServiceCmHandle> ncmpServiceCmHandles = new ArrayList<>(yangModelCmHandles.size()); + for (final YangModelCmHandle yangModelCmHandle : yangModelCmHandles) { + final NcmpServiceCmHandle ncmpServiceCmHandle = toNcmpServiceCmHandleWithTrustLevel(yangModelCmHandle); + ncmpServiceCmHandles.add(ncmpServiceCmHandle); + } return ncmpServiceCmHandles; } @@ -180,19 +186,18 @@ public class NetworkCmProxyInventoryFacade { * @return cm handle details */ public NcmpServiceCmHandle getNcmpServiceCmHandle(final String cmHandleId) { - final NcmpServiceCmHandle ncmpServiceCmHandle = YangDataConverter.toNcmpServiceCmHandle( - inventoryPersistence.getYangModelCmHandle(cmHandleId)); - applyCurrentTrustLevel(ncmpServiceCmHandle); - return ncmpServiceCmHandle; + final YangModelCmHandle yangModelCmHandle = inventoryPersistence.getYangModelCmHandle(cmHandleId); + return toNcmpServiceCmHandleWithTrustLevel(yangModelCmHandle); } /** - * 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()); } @@ -208,10 +213,12 @@ public class NetworkCmProxyInventoryFacade { return inventoryPersistence.getYangModelCmHandle(cmHandleId).getCompositeState(); } - private void applyCurrentTrustLevel(final NcmpServiceCmHandle ncmpServiceCmHandle) { - ncmpServiceCmHandle.setCurrentTrustLevel(trustLevelManager - .getEffectiveTrustLevel(ncmpServiceCmHandle.getCmHandleId())); + private NcmpServiceCmHandle toNcmpServiceCmHandleWithTrustLevel(final YangModelCmHandle yangModelCmHandle) { + final NcmpServiceCmHandle ncmpServiceCmHandle = YangDataConverter.toNcmpServiceCmHandle(yangModelCmHandle); + final String dmiServiceName = yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA); + ncmpServiceCmHandle.setCurrentTrustLevel( + trustLevelManager.getEffectiveTrustLevel(dmiServiceName, ncmpServiceCmHandle.getCmHandleId())); + return ncmpServiceCmHandle; } - } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/DmiDataOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/DmiDataOperations.java index 6b813a6f69..301b8195e4 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/DmiDataOperations.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/DmiDataOperations.java @@ -139,8 +139,7 @@ public class DmiDataOperations { final String requestId, final String authorization) { - final Set<String> cmHandlesIds - = getDistinctCmHandleIds(dataOperationRequest); + final Set<String> cmHandlesIds = getDistinctCmHandleIds(dataOperationRequest); final Collection<YangModelCmHandle> yangModelCmHandles = inventoryPersistence.getYangModelCmHandles(cmHandlesIds); 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 8e7620ccea..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,12 +20,29 @@ 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; +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; +import org.onap.cps.ncmp.impl.utils.http.RestServiceUrlTemplateBuilder; +import org.onap.cps.ncmp.impl.utils.http.UrlTemplateParameters; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpHeaders; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; +import org.springframework.web.reactive.function.BodyInserters; +import org.springframework.web.reactive.function.client.WebClient; @Slf4j @Service @@ -41,7 +58,10 @@ public class PolicyExecutor { @Value("${ncmp.policy-executor.server.port:8080}") private String serverPort; - private static final String PAYLOAD_TYPE_PREFIX = "cm_"; + @Qualifier("policyExecutorWebClient") + private final WebClient policyExecutorWebClient; + + private final ObjectMapper objectMapper; /** * Use the Policy Executor to check permission for a cm write operation. @@ -58,17 +78,108 @@ public class PolicyExecutor { final String authorization, final String resourceIdentifier, final String changeRequestAsJson) { + log.trace("Policy Executor Enabled: {}", enabled); if (enabled) { - final String payloadType = PAYLOAD_TYPE_PREFIX + operationType.getOperationName(); - log.info("Policy Executor Enabled"); - log.info("Address : {}", serverAddress); - log.info("Port : {}", serverPort); - log.info("Authorization : {}", authorization); - log.info("Payload Type : {}", payloadType); - log.info("Target FDN : {}", yangModelCmHandle.getAlternateId()); - log.info("CM Handle Id : {}", yangModelCmHandle.getId()); - log.info("Resource Identifier : {}", resourceIdentifier); - log.info("Change Request (json) : {}", changeRequestAsJson); + final ResponseEntity<JsonNode> responseEntity = + getPolicyExecutorResponse(yangModelCmHandle, operationType, authorization, resourceIdentifier, + changeRequestAsJson); + + if (responseEntity == null) { + log.warn("No valid response from policy, ignored"); + return; + } + + if (responseEntity.getStatusCode().is2xxSuccessful()) { + if (responseEntity.getBody() == null) { + log.warn("No valid response body from policy, ignored"); + return; + } + processResponse(responseEntity.getBody()); + } else { + log.warn("Policy Executor invocation failed with status {}", + responseEntity.getStatusCode().value()); + throw new ServerNcmpException("Policy Executor invocation failed", "HTTP status code: " + + responseEntity.getStatusCode().value()); + } + } + } + + private Map<String, Object> getSingleRequestAsMap(final YangModelCmHandle yangModelCmHandle, + final OperationType operationType, + final String resourceIdentifier, + final String changeRequestAsJson) { + final Map<String, Object> data = new HashMap<>(4); + data.put("cmHandleId", yangModelCmHandle.getId()); + data.put("resourceIdentifier", resourceIdentifier); + data.put("targetIdentifier", yangModelCmHandle.getAlternateId()); + if (!OperationType.DELETE.equals(operationType)) { + 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); + request.put("schema", getAssociatedPolicyDataSchemaName(operationType)); + request.put("data", data); + return request; + } + + private static String getAssociatedPolicyDataSchemaName(final OperationType operationType) { + return "urn:cps:org.onap.cps.ncmp.policy-executor.ncmp-" + operationType.getOperationName() + "-schema:1.0.0"; + } + + private Object createBodyAsObject(final List<Object> requests) { + final Map<String, Object> bodyAsMap = new HashMap<>(2); + bodyAsMap.put("decisionType", "allow"); + bodyAsMap.put("requests", requests); + return bodyAsMap; } + + private ResponseEntity<JsonNode> getPolicyExecutorResponse(final YangModelCmHandle yangModelCmHandle, + final OperationType operationType, + final String authorization, + final String resourceIdentifier, + final String changeRequestAsJson) { + final String serviceBaseUrl = serverAddress + ":" + serverPort; + + final Map<String, Object> requestAsMap = getSingleRequestAsMap(yangModelCmHandle, + operationType, + resourceIdentifier, + changeRequestAsJson); + + final Object bodyAsObject = createBodyAsObject(Collections.singletonList(requestAsMap)); + + final UrlTemplateParameters urlTemplateParameters = RestServiceUrlTemplateBuilder.newInstance() + .fixedPathSegment("execute") + .createUrlTemplateParameters(serviceBaseUrl, ""); + + return policyExecutorWebClient.post() + .uri(urlTemplateParameters.urlTemplate(), urlTemplateParameters.urlVariables()) + .header(HttpHeaders.AUTHORIZATION, authorization) + .body(BodyInserters.fromValue(bodyAsObject)) + .retrieve() + .toEntity(JsonNode.class) + .block(); + } + + private static void processResponse(final JsonNode responseBody) { + final String decisionId = responseBody.path("decisionId").asText("unknown id"); + log.trace("Policy Executor Decision ID: {} ", decisionId); + final String decision = responseBody.path("decision").asText("unknown"); + if ("allow".equals(decision)) { + log.trace("Policy Executor allows the operation"); + } else { + log.warn("Policy Executor decision: {}", decision); + final String details = responseBody.path("message").asText(); + log.warn("Policy Executor message: {}", details); + final String message = "Policy Executor did not allow request. Decision #" + + decisionId + " : " + decision; + throw new PolicyExecutorException(message, details); + } + } + } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryService.java index e5848c0dfa..03ec30b73b 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryService.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryService.java @@ -22,7 +22,7 @@ package org.onap.cps.ncmp.impl.inventory; import java.util.Collection; import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryServiceParameters; -import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle; +import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; public interface ParameterizedCmHandleQueryService { /** @@ -51,22 +51,14 @@ public interface ParameterizedCmHandleQueryService { Collection<String> queryCmHandleIdsForInventory(CmHandleQueryServiceParameters cmHandleQueryServiceParameters); /** - * Query and return cm handle objects that match the given query parameters. + * Query and return yang model cm handle objects that match the given query parameters. * Supported query types: * public properties * modules * cps-path * * @param cmHandleQueryServiceParameters the cm handle query parameters - * @return collection of cm handles + * @return collection of yang model cm handles */ - Collection<NcmpServiceCmHandle> queryCmHandles(CmHandleQueryServiceParameters cmHandleQueryServiceParameters); - - /** - * Get all cm handle objects. - * Note: it is similar to all the queries above but simply no conditions and hence not 'parameterized' - * - * @return collection of cm handles - */ - Collection<NcmpServiceCmHandle> getAllCmHandles(); + Collection<YangModelCmHandle> queryCmHandles(CmHandleQueryServiceParameters cmHandleQueryServiceParameters); } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryServiceImpl.java index 34eeaccf8f..84229e2895 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryServiceImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryServiceImpl.java @@ -27,7 +27,6 @@ import static org.onap.cps.ncmp.impl.inventory.models.CmHandleQueryConditions.HA import static org.onap.cps.ncmp.impl.inventory.models.CmHandleQueryConditions.HAS_ALL_PROPERTIES; import static org.onap.cps.ncmp.impl.inventory.models.CmHandleQueryConditions.WITH_CPS_PATH; import static org.onap.cps.ncmp.impl.inventory.models.CmHandleQueryConditions.WITH_TRUST_LEVEL; -import static org.onap.cps.ncmp.impl.utils.YangDataConverter.toNcmpServiceCmHandle; import static org.onap.cps.spi.FetchDescendantsOption.DIRECT_CHILDREN_ONLY; import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS; @@ -40,10 +39,8 @@ import java.util.Map; import java.util.function.Function; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.onap.cps.cpspath.parser.PathParsingException; import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryServiceParameters; -import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle; import org.onap.cps.ncmp.impl.inventory.models.InventoryQueryConditions; import org.onap.cps.ncmp.impl.inventory.models.PropertyType; import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; @@ -54,7 +51,6 @@ import org.onap.cps.spi.model.DataNode; import org.springframework.stereotype.Service; @Service -@Slf4j @RequiredArgsConstructor public class ParameterizedCmHandleQueryServiceImpl implements ParameterizedCmHandleQueryService { @@ -83,22 +79,18 @@ public class ParameterizedCmHandleQueryServiceImpl implements ParameterizedCmHan } @Override - public Collection<NcmpServiceCmHandle> queryCmHandles( - final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) { - + public Collection<YangModelCmHandle> queryCmHandles( + final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) { if (cmHandleQueryServiceParameters.getCmHandleQueryParameters().isEmpty()) { return getAllCmHandles(); } - final Collection<String> cmHandleIds = queryCmHandleIds(cmHandleQueryServiceParameters); - - return getNcmpServiceCmHandles(cmHandleIds); + return inventoryPersistence.getYangModelCmHandles(cmHandleIds); } - @Override - public Collection<NcmpServiceCmHandle> getAllCmHandles() { + private Collection<YangModelCmHandle> getAllCmHandles() { final DataNode dataNode = inventoryPersistence.getDataNode(NCMP_DMI_REGISTRY_PARENT).iterator().next(); - return dataNode.getChildDataNodes().stream().map(this::createNcmpServiceCmHandle).collect(Collectors.toSet()); + return dataNode.getChildDataNodes().stream().map(YangDataConverter::toYangModelCmHandle).toList(); } private Collection<String> queryCmHandlesByDmiPlugin( @@ -226,22 +218,6 @@ public class ParameterizedCmHandleQueryServiceImpl implements ParameterizedCmHan return collectCmHandleIdsFromDataNodes(dataNode.getChildDataNodes()); } - private Collection<NcmpServiceCmHandle> getNcmpServiceCmHandles(final Collection<String> cmHandleIds) { - final Collection<YangModelCmHandle> yangModelcmHandles - = inventoryPersistence.getYangModelCmHandles(cmHandleIds); - - final Collection<NcmpServiceCmHandle> ncmpServiceCmHandles = new ArrayList<>(yangModelcmHandles.size()); - - yangModelcmHandles.forEach(yangModelcmHandle -> - ncmpServiceCmHandles.add(YangDataConverter.toNcmpServiceCmHandle(yangModelcmHandle)) - ); - return ncmpServiceCmHandles; - } - - private NcmpServiceCmHandle createNcmpServiceCmHandle(final DataNode dataNode) { - return toNcmpServiceCmHandle(YangDataConverter.toYangModelCmHandle(dataNode)); - } - private Collection<String> executeQueries(final CmHandleQueryServiceParameters cmHandleQueryServiceParameters, final Function<CmHandleQueryServiceParameters, Collection<String>>... queryFunctions) { diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManager.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManager.java index f468127dbc..33310b955e 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManager.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManager.java @@ -138,8 +138,8 @@ public class TrustLevelManager { * @param cmHandleId cm handle id * @return TrustLevel effective trust level */ - public TrustLevel getEffectiveTrustLevel(final String cmHandleId) { - final TrustLevel dmiTrustLevel = TrustLevel.COMPLETE; // TODO: CPS-2375 + public TrustLevel getEffectiveTrustLevel(final String dmiServiceName, final String cmHandleId) { + final TrustLevel dmiTrustLevel = trustLevelPerDmiPlugin.get(dmiServiceName); final TrustLevel cmHandleTrustLevel = trustLevelPerCmHandle.get(cmHandleId); return dmiTrustLevel.getEffectiveTrustLevel(cmHandleTrustLevel); } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/http/RestServiceUrlTemplateBuilder.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/http/RestServiceUrlTemplateBuilder.java index fafb09007d..c850ca94a0 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/http/RestServiceUrlTemplateBuilder.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/http/RestServiceUrlTemplateBuilder.java @@ -96,9 +96,7 @@ public class RestServiceUrlTemplateBuilder { * @return a UrlTemplateParameters instance containing the complete URL template and URL variables */ public UrlTemplateParameters createUrlTemplateParameters(final String serviceBaseUrl, final String basePath) { - this.uriComponentsBuilder.pathSegment(basePath) - .pathSegment(VERSION_SEGMENT); - + this.uriComponentsBuilder.pathSegment(basePath).pathSegment(VERSION_SEGMENT); final Map<String, String> urlTemplateVariables = new HashMap<>(); pathSegments.forEach((pathSegmentName, variablePathValue) -> { @@ -120,7 +118,7 @@ public class RestServiceUrlTemplateBuilder { } /** - * Constructs a URL for DMI health check based on the given base URL. + * Constructs a URL for a spring actuator health check based on the given base URL. * * @param serviceBaseUrl the base URL of the service, e.g., "http://dmi-service.com". * @return a {@link UrlTemplateParameters} instance containing the complete URL template and empty URL variables, |