X-Git-Url: https://gerrit.onap.org/r/gitweb?a=blobdiff_plain;f=cps-ncmp-service%2Fsrc%2Fmain%2Fjava%2Forg%2Fonap%2Fcps%2Fncmp%2Fapi%2Fimpl%2FNetworkCmProxyDataServiceImpl.java;h=08370ab890af9795a02ccd49bd0ee0759fce3910;hb=21171253eb47349832e1e1d4952a42051c19be05;hp=9e013145dae3b18b15553950c2d6f527cc089519;hpb=34a94b92edd0c359291445735eb3d7e974deea1f;p=cps.git diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java index 9e013145d..f8adde85f 100755 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java @@ -1,13 +1,17 @@ /* - * ============LICENSE_START======================================================= + * ============LICENSE_START======================================================= * Copyright (C) 2021 highstreet technologies GmbH - * Copyright (C) 2021 Nordix Foundation + * Modifications Copyright (C) 2021-2023 Nordix Foundation + * Modifications Copyright (C) 2021 Pantheon.tech + * Modifications Copyright (C) 2021-2022 Bell Canada + * Modifications Copyright (C) 2023 TechMahindra Ltd. * ================================================================================ * 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. @@ -20,45 +24,406 @@ package org.onap.cps.ncmp.api.impl; +import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_PARENT; +import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME; +import static org.onap.cps.ncmp.api.impl.utils.RestQueryParametersValidator.validateCmHandleQueryParameters; + +import com.google.common.collect.Lists; +import com.hazelcast.map.IMap; +import java.time.OffsetDateTime; +import java.util.ArrayList; import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.onap.cps.api.CpsDataService; -import org.onap.cps.api.CpsQueryService; +import org.onap.cps.ncmp.api.NetworkCmProxyCmHandleQueryService; import org.onap.cps.ncmp.api.NetworkCmProxyDataService; +import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler; +import org.onap.cps.ncmp.api.impl.inventory.CmHandleQueries; +import org.onap.cps.ncmp.api.impl.inventory.CmHandleState; +import org.onap.cps.ncmp.api.impl.inventory.CompositeState; +import org.onap.cps.ncmp.api.impl.inventory.CompositeStateUtils; +import org.onap.cps.ncmp.api.impl.inventory.DataStoreSyncState; +import org.onap.cps.ncmp.api.impl.inventory.InventoryPersistence; +import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations; +import org.onap.cps.ncmp.api.impl.operations.OperationType; +import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel; +import org.onap.cps.ncmp.api.impl.utils.CmHandleQueryConditions; +import org.onap.cps.ncmp.api.impl.utils.InventoryQueryConditions; +import org.onap.cps.ncmp.api.impl.utils.YangDataConverter; +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; +import org.onap.cps.ncmp.api.models.CmHandleQueryApiParameters; +import org.onap.cps.ncmp.api.models.CmHandleQueryServiceParameters; +import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse; +import org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.RegistrationError; +import org.onap.cps.ncmp.api.models.DataOperationRequest; +import org.onap.cps.ncmp.api.models.DmiPluginRegistration; +import org.onap.cps.ncmp.api.models.DmiPluginRegistrationResponse; +import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle; import org.onap.cps.spi.FetchDescendantsOption; -import org.onap.cps.spi.model.DataNode; -import org.springframework.beans.factory.annotation.Autowired; +import org.onap.cps.spi.exceptions.AlreadyDefinedException; +import org.onap.cps.spi.exceptions.CpsException; +import org.onap.cps.spi.exceptions.DataNodeNotFoundException; +import org.onap.cps.spi.exceptions.DataValidationException; +import org.onap.cps.spi.model.ModuleDefinition; +import org.onap.cps.spi.model.ModuleReference; +import org.onap.cps.utils.JsonObjectMapper; +import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Service; +@Slf4j @Service +@RequiredArgsConstructor public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService { - private static final String NF_PROXY_DATASPACE_NAME = "NFP-Operational"; + private static final int DELETE_BATCH_SIZE = 100; + private final JsonObjectMapper jsonObjectMapper; + private final DmiDataOperations dmiDataOperations; + private final NetworkCmProxyDataServicePropertyHandler networkCmProxyDataServicePropertyHandler; + private final InventoryPersistence inventoryPersistence; + private final CmHandleQueries cmHandleQueries; + private final NetworkCmProxyCmHandleQueryService networkCmProxyCmHandleQueryService; + private final LcmEventsCmHandleStateHandler lcmEventsCmHandleStateHandler; + private final CpsDataService cpsDataService; + private final IMap moduleSyncStartedOnCmHandles; + private final IMap trustLevelPerDmiPlugin; + + @Override + public DmiPluginRegistrationResponse updateDmiRegistrationAndSyncModule( + final DmiPluginRegistration dmiPluginRegistration) { + dmiPluginRegistration.validateDmiPluginRegistration(); + final DmiPluginRegistrationResponse dmiPluginRegistrationResponse = new DmiPluginRegistrationResponse(); + + if (!dmiPluginRegistration.getRemovedCmHandles().isEmpty()) { + dmiPluginRegistrationResponse.setRemovedCmHandles( + parseAndRemoveCmHandlesInDmiRegistration(dmiPluginRegistration.getRemovedCmHandles())); + } + + if (!dmiPluginRegistration.getCreatedCmHandles().isEmpty()) { + dmiPluginRegistrationResponse.setCreatedCmHandles( + parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(dmiPluginRegistration)); + } + if (!dmiPluginRegistration.getUpdatedCmHandles().isEmpty()) { + dmiPluginRegistrationResponse.setUpdatedCmHandles( + networkCmProxyDataServicePropertyHandler + .updateCmHandleProperties(dmiPluginRegistration.getUpdatedCmHandles())); + } + + setTrustLevelPerDmiPlugin(dmiPluginRegistration); + + return dmiPluginRegistrationResponse; + } + + @Override + public Object getResourceDataForCmHandle(final String datastoreName, + final String cmHandleId, + final String resourceIdentifier, + final String optionsParamInQuery, + final String topicParamInQuery, + final String requestId) { + final ResponseEntity responseEntity = dmiDataOperations.getResourceDataFromDmi(datastoreName, cmHandleId, + resourceIdentifier, + optionsParamInQuery, + topicParamInQuery, + requestId); + return responseEntity.getBody(); + } + + @Override + public Object getResourceDataForCmHandle(final String datastoreName, + final String cmHandleId, + final String resourceIdentifier, + final FetchDescendantsOption fetchDescendantsOption) { + return cpsDataService.getDataNodes(datastoreName, cmHandleId, resourceIdentifier, + fetchDescendantsOption).iterator().next(); + } + + @Override + public void executeDataOperationForCmHandles(final String topicParamInQuery, + final DataOperationRequest + dataOperationRequest, + final String requestId) { + dmiDataOperations.requestResourceDataFromDmi(topicParamInQuery, dataOperationRequest, requestId); + } + + @Override + public Object writeResourceDataPassThroughRunningForCmHandle(final String cmHandleId, + final String resourceIdentifier, + final OperationType operationType, + final String requestData, + final String dataType) { + return dmiDataOperations.writeResourceDataPassThroughRunningFromDmi(cmHandleId, resourceIdentifier, + operationType, requestData, dataType); + } + + @Override + public Collection getYangResourcesModuleReferences(final String cmHandleId) { + return inventoryPersistence.getYangResourcesModuleReferences(cmHandleId); + } - @Autowired - private CpsDataService cpsDataService; + @Override + public Collection getModuleDefinitionsByCmHandleId(final String cmHandleId) { + return inventoryPersistence.getModuleDefinitionsByCmHandleId(cmHandleId); + } + + /** + * Retrieve cm handles with details for the given query parameters. + * + * @param cmHandleQueryApiParameters cm handle query parameters + * @return cm handles with details + */ + @Override + public Collection executeCmHandleSearch( + final CmHandleQueryApiParameters cmHandleQueryApiParameters) { + final CmHandleQueryServiceParameters cmHandleQueryServiceParameters = jsonObjectMapper.convertToValueType( + cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class); + validateCmHandleQueryParameters(cmHandleQueryServiceParameters, CmHandleQueryConditions.ALL_CONDITION_NAMES); + return networkCmProxyCmHandleQueryService.queryCmHandles(cmHandleQueryServiceParameters); + } - @Autowired - private CpsQueryService cpsQueryService; + /** + * Retrieve cm handle ids for the given query parameters. + * + * @param cmHandleQueryApiParameters cm handle query parameters + * @return cm handle ids + */ + @Override + public Collection executeCmHandleIdSearch(final CmHandleQueryApiParameters cmHandleQueryApiParameters) { + final CmHandleQueryServiceParameters cmHandleQueryServiceParameters = jsonObjectMapper.convertToValueType( + cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class); + validateCmHandleQueryParameters(cmHandleQueryServiceParameters, CmHandleQueryConditions.ALL_CONDITION_NAMES); + return networkCmProxyCmHandleQueryService.queryCmHandleIds(cmHandleQueryServiceParameters); + } + /** + * Set the data sync enabled flag, along with the data sync state + * based on the data sync enabled boolean for the cm handle id provided. + * + * @param cmHandleId cm handle id + * @param dataSyncEnabled data sync enabled flag + */ @Override - public DataNode getDataNode(final String cmHandle, final String xpath, - final FetchDescendantsOption fetchDescendantsOption) { - return cpsDataService.getDataNode(NF_PROXY_DATASPACE_NAME, cmHandle, xpath, fetchDescendantsOption); + public void setDataSyncEnabled(final String cmHandleId, final boolean dataSyncEnabled) { + final CompositeState compositeState = inventoryPersistence + .getCmHandleState(cmHandleId); + if (compositeState.getDataSyncEnabled().equals(dataSyncEnabled)) { + log.info("Data-Sync Enabled flag is already: {} ", dataSyncEnabled); + } else if (compositeState.getCmHandleState() != CmHandleState.READY) { + throw new CpsException("State mismatch exception.", "Cm-Handle not in READY state. Cm handle state is: " + + compositeState.getCmHandleState()); + } else { + final DataStoreSyncState dataStoreSyncState = compositeState.getDataStores() + .getOperationalDataStore().getDataStoreSyncState(); + if (!dataSyncEnabled && dataStoreSyncState == DataStoreSyncState.SYNCHRONIZED) { + cpsDataService.deleteDataNode(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandleId, + "/netconf-state", OffsetDateTime.now()); + } + CompositeStateUtils.setDataSyncEnabledFlagWithDataSyncState(dataSyncEnabled, compositeState); + inventoryPersistence.saveCmHandleState(cmHandleId, + compositeState); + } } + /** + * Get all cm handle IDs by DMI plugin identifier. + * + * @param dmiPluginIdentifier DMI plugin identifier + * @return set of cm handle IDs + */ @Override - public Collection queryDataNodes(final String cmHandle, final String cpsPath, - final FetchDescendantsOption fetchDescendantsOption) { - return cpsQueryService.queryDataNodes(NF_PROXY_DATASPACE_NAME, cmHandle, cpsPath, fetchDescendantsOption); + public Collection getAllCmHandleIdsByDmiPluginIdentifier(final String dmiPluginIdentifier) { + return cmHandleQueries.getCmHandleIdsByDmiPluginIdentifier(dmiPluginIdentifier); } + /** + * Get all cm handle IDs by various properties. + * + * @param cmHandleQueryServiceParameters cm handle query parameters + * @return set of cm handle IDs + */ @Override - public void updateNodeLeaves(final String cmHandle, final String parentNodeXpath, final String jsonData) { - cpsDataService.updateNodeLeaves(NF_PROXY_DATASPACE_NAME, cmHandle, parentNodeXpath, jsonData); + public Collection executeCmHandleIdSearchForInventory( + final CmHandleQueryServiceParameters cmHandleQueryServiceParameters) { + validateCmHandleQueryParameters(cmHandleQueryServiceParameters, InventoryQueryConditions.ALL_CONDITION_NAMES); + return networkCmProxyCmHandleQueryService.queryCmHandleIdsForInventory(cmHandleQueryServiceParameters); } + /** + * Retrieve cm handle details for a given cm handle. + * + * @param cmHandleId cm handle identifier + * @return cm handle details + */ @Override - public void replaceNodeTree(final String cmHandle, final String parentNodeXpath, final String jsonData) { - cpsDataService.replaceNodeTree(NF_PROXY_DATASPACE_NAME, cmHandle, parentNodeXpath, jsonData); + public NcmpServiceCmHandle getNcmpServiceCmHandle(final String cmHandleId) { + return YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle( + inventoryPersistence.getYangModelCmHandle(cmHandleId)); } + + /** + * Get cm handle public properties for a given cm handle id. + * + * @param cmHandleId cm handle identifier + * @return cm handle public properties + */ + @Override + public Map getCmHandlePublicProperties(final String cmHandleId) { + final YangModelCmHandle yangModelCmHandle = + inventoryPersistence.getYangModelCmHandle(cmHandleId); + final List yangModelPublicProperties = yangModelCmHandle.getPublicProperties(); + final Map cmHandlePublicProperties = new HashMap<>(); + YangDataConverter.asPropertiesMap(yangModelPublicProperties, cmHandlePublicProperties); + return cmHandlePublicProperties; + } + + /** + * Get cm handle composite state for a given cm handle id. + * + * @param cmHandleId cm handle identifier + * @return cm handle state + */ + @Override + public CompositeState getCmHandleCompositeState(final String cmHandleId) { + return inventoryPersistence.getYangModelCmHandle(cmHandleId).getCompositeState(); + } + + /** + * THis method registers a cm handle and initiates modules sync. + * + * @param dmiPluginRegistration dmi plugin registration information. + * @return cm-handle registration response for create cm-handle requests. + */ + public List parseAndCreateCmHandlesInDmiRegistrationAndSyncModules( + final DmiPluginRegistration dmiPluginRegistration) { + final Map cmHandleStatePerCmHandle = new HashMap<>(); + dmiPluginRegistration.getCreatedCmHandles() + .forEach(cmHandle -> { + final YangModelCmHandle yangModelCmHandle = YangModelCmHandle.toYangModelCmHandle( + dmiPluginRegistration.getDmiPlugin(), + dmiPluginRegistration.getDmiDataPlugin(), + dmiPluginRegistration.getDmiModelPlugin(), + cmHandle); + cmHandleStatePerCmHandle.put(yangModelCmHandle, CmHandleState.ADVISED); + }); + return registerNewCmHandles(cmHandleStatePerCmHandle); + } + + protected List parseAndRemoveCmHandlesInDmiRegistration( + final List tobeRemovedCmHandles) { + final List cmHandleRegistrationResponses = + new ArrayList<>(tobeRemovedCmHandles.size()); + final Collection yangModelCmHandles = + inventoryPersistence.getYangModelCmHandles(tobeRemovedCmHandles); + + updateCmHandleStateBatch(yangModelCmHandles, CmHandleState.DELETING); + + final Set notDeletedCmHandles = new HashSet<>(); + for (final List tobeRemovedCmHandleBatch : Lists.partition(tobeRemovedCmHandles, DELETE_BATCH_SIZE)) { + try { + batchDeleteCmHandlesFromDbAndModuleSyncMap(tobeRemovedCmHandleBatch); + tobeRemovedCmHandleBatch.forEach(cmHandleId -> + cmHandleRegistrationResponses.add(CmHandleRegistrationResponse.createSuccessResponse(cmHandleId))); + + } catch (final RuntimeException batchException) { + log.error("Unable to de-register cm-handle batch, retrying on each cm handle"); + for (final String cmHandleId : tobeRemovedCmHandleBatch) { + final CmHandleRegistrationResponse cmHandleRegistrationResponse = + deleteCmHandleAndGetCmHandleRegistrationResponse(cmHandleId); + cmHandleRegistrationResponses.add(cmHandleRegistrationResponse); + if (cmHandleRegistrationResponse.getStatus() != CmHandleRegistrationResponse.Status.SUCCESS) { + notDeletedCmHandles.add(cmHandleId); + } + } + } + } + + yangModelCmHandles.removeIf(yangModelCmHandle -> notDeletedCmHandles.contains(yangModelCmHandle.getId())); + updateCmHandleStateBatch(yangModelCmHandles, CmHandleState.DELETED); + + return cmHandleRegistrationResponses; + } + + private CmHandleRegistrationResponse deleteCmHandleAndGetCmHandleRegistrationResponse(final String cmHandleId) { + try { + deleteCmHandleFromDbAndModuleSyncMap(cmHandleId); + return CmHandleRegistrationResponse.createSuccessResponse(cmHandleId); + } catch (final DataNodeNotFoundException dataNodeNotFoundException) { + log.error("Unable to find dataNode for cmHandleId : {} , caused by : {}", + cmHandleId, dataNodeNotFoundException.getMessage()); + return CmHandleRegistrationResponse.createFailureResponse(cmHandleId, + RegistrationError.CM_HANDLE_DOES_NOT_EXIST); + } catch (final DataValidationException dataValidationException) { + log.error("Unable to de-register cm-handle id: {}, caused by: {}", + cmHandleId, dataValidationException.getMessage()); + return CmHandleRegistrationResponse.createFailureResponse(cmHandleId, + RegistrationError.CM_HANDLE_INVALID_ID); + } catch (final Exception exception) { + log.error("Unable to de-register cm-handle id : {} , caused by : {}", cmHandleId, exception.getMessage()); + return CmHandleRegistrationResponse.createFailureResponse(cmHandleId, exception); + } + } + + private void updateCmHandleStateBatch(final Collection yangModelCmHandles, + final CmHandleState cmHandleState) { + final Map cmHandleStatePerCmHandle = new HashMap<>(yangModelCmHandles.size()); + yangModelCmHandles.forEach(yangModelCmHandle -> cmHandleStatePerCmHandle.put(yangModelCmHandle, cmHandleState)); + lcmEventsCmHandleStateHandler.updateCmHandleStateBatch(cmHandleStatePerCmHandle); + } + + private void deleteCmHandleFromDbAndModuleSyncMap(final String cmHandleId) { + inventoryPersistence.deleteSchemaSetWithCascade(cmHandleId); + inventoryPersistence.deleteDataNode(NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@id='" + cmHandleId + + "']"); + removeDeletedCmHandleFromModuleSyncMap(cmHandleId); + } + + private void batchDeleteCmHandlesFromDbAndModuleSyncMap(final Collection tobeRemovedCmHandles) { + inventoryPersistence.deleteSchemaSetsWithCascade(tobeRemovedCmHandles); + inventoryPersistence.deleteDataNodes(mapCmHandleIdsToXpaths(tobeRemovedCmHandles)); + tobeRemovedCmHandles.forEach(this::removeDeletedCmHandleFromModuleSyncMap); + } + + private Collection mapCmHandleIdsToXpaths(final Collection cmHandles) { + return cmHandles.stream() + .map(cmHandleId -> NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@id='" + cmHandleId + "']") + .collect(Collectors.toSet()); + } + + // CPS-1239 Robustness cleaning of in progress cache + private void removeDeletedCmHandleFromModuleSyncMap(final String deletedCmHandleId) { + if (moduleSyncStartedOnCmHandles.remove(deletedCmHandleId) != null) { + log.debug("{} removed from in progress map", deletedCmHandleId); + } + } + + private List registerNewCmHandles(final Map + cmHandleStatePerCmHandle) { + final List cmHandleIds = cmHandleStatePerCmHandle.keySet().stream().map(YangModelCmHandle::getId) + .collect(Collectors.toList()); + try { + lcmEventsCmHandleStateHandler.updateCmHandleStateBatch(cmHandleStatePerCmHandle); + return CmHandleRegistrationResponse.createSuccessResponses(cmHandleIds); + } catch (final AlreadyDefinedException alreadyDefinedException) { + return CmHandleRegistrationResponse.createFailureResponses( + alreadyDefinedException.getAlreadyDefinedObjectNames(), + RegistrationError.CM_HANDLE_ALREADY_EXIST); + } catch (final Exception exception) { + return CmHandleRegistrationResponse.createFailureResponses(cmHandleIds, exception); + } + } + + private void setTrustLevelPerDmiPlugin(final DmiPluginRegistration dmiPluginRegistration) { + if (DmiPluginRegistration.isNullEmptyOrBlank(dmiPluginRegistration.getDmiDataPlugin())) { + trustLevelPerDmiPlugin.put(dmiPluginRegistration.getDmiPlugin(), TrustLevel.COMPLETE); + } else { + trustLevelPerDmiPlugin.put(dmiPluginRegistration.getDmiDataPlugin(), TrustLevel.COMPLETE); + } + } + }