diff options
Diffstat (limited to 'cps-ncmp-service/src/main/java/org/onap/cps')
17 files changed, 288 insertions, 74 deletions
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandleQueryServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandleQueryServiceImpl.java index 58732b207..7475cdd4a 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandleQueryServiceImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandleQueryServiceImpl.java @@ -157,7 +157,8 @@ public class NetworkCmProxyCmHandleQueryServiceImpl implements NetworkCmProxyCmH } try { cpsPathQueryResult = collectCmHandleIdsFromDataNodes( - cmHandleQueries.queryCmHandleDataNodesByCpsPath(cpsPathCondition.get("cpsPath"), OMIT_DESCENDANTS)); + cmHandleQueries.queryCmHandleAncestorsByCpsPath( + cpsPathCondition.get("cpsPath"), OMIT_DESCENDANTS)); } catch (final PathParsingException pathParsingException) { throw new DataValidationException(pathParsingException.getMessage(), pathParsingException.getDetails(), pathParsingException); 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 d34e2a314..692a9f2a9 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 @@ -25,14 +25,17 @@ package org.onap.cps.ncmp.api.impl; import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLES_NOT_FOUND; +import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLES_NOT_READY; import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_ALREADY_EXIST; import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_INVALID_ID; +import static org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory.MODULE_UPGRADE; 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.text.MessageFormat; import java.time.OffsetDateTime; import java.util.ArrayList; import java.util.Collection; @@ -51,6 +54,7 @@ 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.CompositeStateBuilder; 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; @@ -68,6 +72,7 @@ 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.ncmp.api.models.UpgradedCmHandles; import org.onap.cps.spi.FetchDescendantsOption; import org.onap.cps.spi.exceptions.AlreadyDefinedException; import org.onap.cps.spi.exceptions.CpsException; @@ -104,18 +109,23 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService if (!dmiPluginRegistration.getRemovedCmHandles().isEmpty()) { dmiPluginRegistrationResponse.setRemovedCmHandles( - parseAndRemoveCmHandlesInDmiRegistration(dmiPluginRegistration.getRemovedCmHandles())); + parseAndProcessDeletedCmHandlesInRegistration(dmiPluginRegistration.getRemovedCmHandles())); } if (!dmiPluginRegistration.getCreatedCmHandles().isEmpty()) { dmiPluginRegistrationResponse.setCreatedCmHandles( - parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(dmiPluginRegistration)); + parseAndProcessCreatedCmHandlesInRegistration(dmiPluginRegistration)); } if (!dmiPluginRegistration.getUpdatedCmHandles().isEmpty()) { dmiPluginRegistrationResponse.setUpdatedCmHandles( networkCmProxyDataServicePropertyHandler .updateCmHandleProperties(dmiPluginRegistration.getUpdatedCmHandles())); } + if (dmiPluginRegistration.getUpgradedCmHandles() != null + && !dmiPluginRegistration.getUpgradedCmHandles().getCmHandles().isEmpty()) { + dmiPluginRegistrationResponse.setUpgradedCmHandles( + parseAndProcessUpgradedCmHandlesInRegistration(dmiPluginRegistration)); + } setTrustLevelPerDmiPlugin(dmiPluginRegistration); @@ -212,8 +222,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService */ @Override public void setDataSyncEnabled(final String cmHandleId, final boolean dataSyncEnabled) { - final CompositeState compositeState = inventoryPersistence - .getCmHandleState(cmHandleId); + 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) { @@ -276,8 +285,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService */ @Override public Map<String, String> getCmHandlePublicProperties(final String cmHandleId) { - final YangModelCmHandle yangModelCmHandle = - inventoryPersistence.getYangModelCmHandle(cmHandleId); + final YangModelCmHandle yangModelCmHandle = inventoryPersistence.getYangModelCmHandle(cmHandleId); final List<YangModelCmHandle.Property> yangModelPublicProperties = yangModelCmHandle.getPublicProperties(); final Map<String, String> cmHandlePublicProperties = new HashMap<>(); YangDataConverter.asPropertiesMap(yangModelPublicProperties, cmHandlePublicProperties); @@ -301,7 +309,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService * @param dmiPluginRegistration dmi plugin registration information. * @return cm-handle registration response for create cm-handle requests. */ - public List<CmHandleRegistrationResponse> parseAndCreateCmHandlesInDmiRegistrationAndSyncModules( + public List<CmHandleRegistrationResponse> parseAndProcessCreatedCmHandlesInRegistration( final DmiPluginRegistration dmiPluginRegistration) { final Map<YangModelCmHandle, CmHandleState> cmHandleStatePerCmHandle = new HashMap<>(); dmiPluginRegistration.getCreatedCmHandles() @@ -310,18 +318,19 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService dmiPluginRegistration.getDmiPlugin(), dmiPluginRegistration.getDmiDataPlugin(), dmiPluginRegistration.getDmiModelPlugin(), - cmHandle); + cmHandle, + cmHandle.getModuleSetTag()); cmHandleStatePerCmHandle.put(yangModelCmHandle, CmHandleState.ADVISED); }); return registerNewCmHandles(cmHandleStatePerCmHandle); } - protected List<CmHandleRegistrationResponse> parseAndRemoveCmHandlesInDmiRegistration( + protected List<CmHandleRegistrationResponse> parseAndProcessDeletedCmHandlesInRegistration( final List<String> tobeRemovedCmHandles) { final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses = new ArrayList<>(tobeRemovedCmHandles.size()); final Collection<YangModelCmHandle> yangModelCmHandles = - inventoryPersistence.getYangModelCmHandles(tobeRemovedCmHandles); + inventoryPersistence.getYangModelCmHandles(tobeRemovedCmHandles); updateCmHandleStateBatch(yangModelCmHandles, CmHandleState.DELETING); @@ -351,6 +360,42 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService return cmHandleRegistrationResponses; } + protected List<CmHandleRegistrationResponse> parseAndProcessUpgradedCmHandlesInRegistration( + final DmiPluginRegistration dmiPluginRegistration) { + + final UpgradedCmHandles upgradedCmHandles = dmiPluginRegistration.getUpgradedCmHandles(); + final String moduleSetTag = dmiPluginRegistration.getUpgradedCmHandles().getModuleSetTag(); + final Map<YangModelCmHandle, CmHandleState> cmHandleStatePerCmHandle = + new HashMap<>(upgradedCmHandles.getCmHandles().size()); + final Collection<String> notReadyCmHandles = new ArrayList<>(upgradedCmHandles.getCmHandles().size()); + final NcmpServiceCmHandle ncmpServiceCmHandle = new NcmpServiceCmHandle(); + final String formattedModuleSetTag = MessageFormat.format("new moduleSetTag: {0}", moduleSetTag); + + upgradedCmHandles.getCmHandles().forEach(cmHandleId -> { + if (cmHandleQueries.cmHandleHasState(cmHandleId, CmHandleState.READY)) { + ncmpServiceCmHandle.setCmHandleId(cmHandleId); + ncmpServiceCmHandle.setCompositeState(new CompositeStateBuilder() + .withCmHandleState(CmHandleState.READY) + .withLockReason(MODULE_UPGRADE, formattedModuleSetTag).build()); + final YangModelCmHandle yangModelCmHandle = YangModelCmHandle.toYangModelCmHandle( + dmiPluginRegistration.getDmiPlugin(), + dmiPluginRegistration.getDmiDataPlugin(), + dmiPluginRegistration.getDmiModelPlugin(), + ncmpServiceCmHandle, + moduleSetTag); + cmHandleStatePerCmHandle.put(yangModelCmHandle, CmHandleState.LOCKED); + } else { + notReadyCmHandles.add(cmHandleId); + } + }); + + final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses + = upgradeCmHandles(cmHandleStatePerCmHandle); + cmHandleRegistrationResponses.addAll(CmHandleRegistrationResponse.createFailureResponses(notReadyCmHandles, + CM_HANDLES_NOT_READY)); + return cmHandleRegistrationResponses; + } + private CmHandleRegistrationResponse deleteCmHandleAndGetCmHandleRegistrationResponse(final String cmHandleId) { try { deleteCmHandleFromDbAndModuleSyncMap(cmHandleId); @@ -404,8 +449,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService private List<CmHandleRegistrationResponse> registerNewCmHandles(final Map<YangModelCmHandle, CmHandleState> cmHandleStatePerCmHandle) { - final List<String> cmHandleIds = cmHandleStatePerCmHandle.keySet().stream().map(YangModelCmHandle::getId) - .toList(); + final List<String> cmHandleIds = getCmHandleIds(cmHandleStatePerCmHandle); try { lcmEventsCmHandleStateHandler.updateCmHandleStateBatch(cmHandleStatePerCmHandle); return CmHandleRegistrationResponse.createSuccessResponses(cmHandleIds); @@ -418,6 +462,22 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService } } + private List<CmHandleRegistrationResponse> upgradeCmHandles(final Map<YangModelCmHandle, CmHandleState> + cmHandleStatePerCmHandle) { + final List<String> cmHandleIds = getCmHandleIds(cmHandleStatePerCmHandle); + log.info("Moving cm handles : {} into locked (for upgrade) state.", cmHandleIds); + try { + lcmEventsCmHandleStateHandler.updateCmHandleStateBatch(cmHandleStatePerCmHandle); + return CmHandleRegistrationResponse.createSuccessResponses(cmHandleIds); + } catch (final Exception exception) { + return CmHandleRegistrationResponse.createFailureResponses(cmHandleIds, exception); + } + } + + private static List<String> getCmHandleIds(final Map<YangModelCmHandle, CmHandleState> cmHandleStatePerCmHandle) { + return cmHandleStatePerCmHandle.keySet().stream().map(YangModelCmHandle::getId).toList(); + } + private void setTrustLevelPerDmiPlugin(final DmiPluginRegistration dmiPluginRegistration) { if (DmiPluginRegistration.isNullEmptyOrBlank(dmiPluginRegistration.getDmiDataPlugin())) { trustLevelPerDmiPlugin.put(dmiPluginRegistration.getDmiPlugin(), TrustLevel.COMPLETE); diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueries.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueries.java index 4776788c8..a5892afc3 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueries.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueries.java @@ -53,12 +53,21 @@ public interface CmHandleQueries { List<DataNode> queryCmHandlesByState(CmHandleState cmHandleState); /** + * Method to return data nodes with ancestor representing the cm handles. + * + * @param cpsPath cps path for which the cmHandle is requested + * @return a list of data nodes representing the cm handles. + */ + List<DataNode> queryCmHandleAncestorsByCpsPath(String cpsPath, + FetchDescendantsOption fetchDescendantsOption); + + /** * Method to return data nodes representing the cm handles. * * @param cpsPath cps path for which the cmHandle is requested * @return a list of data nodes representing the cm handles. */ - List<DataNode> queryCmHandleDataNodesByCpsPath(String cpsPath, FetchDescendantsOption fetchDescendantsOption); + List<DataNode> queryNcmpRegistryByCpsPath(String cpsPath, FetchDescendantsOption fetchDescendantsOption); /** * Method to check the state of a cm handle with given id. diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueriesImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueriesImpl.java index b3ade4f1c..c4e3fd098 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueriesImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CmHandleQueriesImpl.java @@ -61,15 +61,21 @@ public class CmHandleQueriesImpl implements CmHandleQueries { @Override public List<DataNode> queryCmHandlesByState(final CmHandleState cmHandleState) { - return queryCmHandleDataNodesByCpsPath("//state[@cm-handle-state=\"" + cmHandleState + "\"]", + return queryCmHandleAncestorsByCpsPath("//state[@cm-handle-state=\"" + cmHandleState + "\"]", INCLUDE_ALL_DESCENDANTS); } @Override - public List<DataNode> queryCmHandleDataNodesByCpsPath(final String cpsPath, - final FetchDescendantsOption fetchDescendantsOption) { + public List<DataNode> queryNcmpRegistryByCpsPath(final String cpsPath, + final FetchDescendantsOption fetchDescendantsOption) { return cpsDataPersistenceService.queryDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, - cpsPath + ANCESTOR_CM_HANDLES, fetchDescendantsOption); + cpsPath, fetchDescendantsOption); + } + + @Override + public List<DataNode> queryCmHandleAncestorsByCpsPath(final String cpsPath, + final FetchDescendantsOption fetchDescendantsOption) { + return queryNcmpRegistryByCpsPath(cpsPath + ANCESTOR_CM_HANDLES, fetchDescendantsOption); } @Override @@ -81,7 +87,7 @@ public class CmHandleQueriesImpl implements CmHandleQueries { @Override public List<DataNode> queryCmHandlesByOperationalSyncState(final DataStoreSyncState dataStoreSyncState) { - return queryCmHandleDataNodesByCpsPath("//state/datastores" + "/operational[@sync-state=\"" + return queryCmHandleAncestorsByCpsPath("//state/datastores" + "/operational[@sync-state=\"" + dataStoreSyncState + "\"]", FetchDescendantsOption.OMIT_DESCENDANTS); } @@ -114,7 +120,8 @@ public class CmHandleQueriesImpl implements CmHandleQueries { + publicPropertyQueryPair.getKey() + "\" and @value=\"" + publicPropertyQueryPair.getValue() + "\"]"; - final Collection<DataNode> dataNodes = queryCmHandleDataNodesByCpsPath(cpsPath, OMIT_DESCENDANTS); + final Collection<DataNode> dataNodes = queryCmHandleAncestorsByCpsPath(cpsPath, + OMIT_DESCENDANTS); if (cmHandleIds == null) { cmHandleIds = collectCmHandleIdsFromDataNodes(dataNodes); } else { diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CompositeStateUtils.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CompositeStateUtils.java index ef4b299e1..99cca8c0b 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CompositeStateUtils.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/CompositeStateUtils.java @@ -100,7 +100,9 @@ public class CompositeStateUtils { compositeState.setLastUpdateTimeNow(); final String oldLockReasonDetails = compositeState.getLockReason().getDetails(); final CompositeState.LockReason lockReason = - CompositeState.LockReason.builder().details(oldLockReasonDetails).build(); + CompositeState.LockReason.builder() + .lockReasonCategory(compositeState.getLockReason().getLockReasonCategory()) + .details(oldLockReasonDetails).build(); compositeState.setLockReason(lockReason); }; } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/LockReasonCategory.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/LockReasonCategory.java index 8306619f2..e2b2c6b4a 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/LockReasonCategory.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/LockReasonCategory.java @@ -21,5 +21,8 @@ package org.onap.cps.ncmp.api.impl.inventory; public enum LockReasonCategory { - MODULE_SYNC_FAILED, MODULE_UPGRADE, MODULE_UPGRADE_FAILED + MODULE_SYNC_FAILED, + MODULE_UPGRADE, + MODULE_UPGRADE_FAILED, + LOCKED_MISBEHAVING } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncService.java index b2949c278..8e17ab916 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncService.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncService.java @@ -20,20 +20,38 @@ package org.onap.cps.ncmp.api.impl.inventory.sync; +import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME; +import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR; +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 java.time.OffsetDateTime; +import java.util.Arrays; import java.util.Collection; import java.util.Collections; +import java.util.HashMap; +import java.util.List; import java.util.Map; +import java.util.Optional; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; import org.onap.cps.api.CpsAdminService; +import org.onap.cps.api.CpsDataService; import org.onap.cps.api.CpsModuleService; +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.LockReasonCategory; import org.onap.cps.ncmp.api.impl.operations.DmiModelOperations; +import org.onap.cps.ncmp.api.impl.utils.YangDataConverter; import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; import org.onap.cps.spi.CascadeDeleteAllowed; +import org.onap.cps.spi.FetchDescendantsOption; import org.onap.cps.spi.exceptions.SchemaSetNotFoundException; +import org.onap.cps.spi.model.DataNode; import org.onap.cps.spi.model.ModuleReference; +import org.onap.cps.utils.JsonObjectMapper; import org.springframework.stereotype.Service; @Slf4j @@ -43,16 +61,31 @@ public class ModuleSyncService { private final DmiModelOperations dmiModelOperations; private final CpsModuleService cpsModuleService; - private final CpsAdminService cpsAdminService; + private final CmHandleQueries cmHandleQueries; + private final CpsDataService cpsDataService; + private final JsonObjectMapper jsonObjectMapper; /** * This method registers a cm handle and initiates modules sync. * - * @param yangModelCmHandle the yang model of cm handle. + * @param upgradedCmHandle the yang model of cm handle. */ - public void syncAndCreateSchemaSetAndAnchor(final YangModelCmHandle yangModelCmHandle) { + public void syncAndCreateOrUpgradeSchemaSetAndAnchor(final YangModelCmHandle upgradedCmHandle) { + + final String moduleSetTag = extractModuleSetTag(upgradedCmHandle.getCompositeState()); + final Optional<DataNode> existingCmHandleWithSameModuleSetTag + = getFirstReadyDataNodeWithModuleSetTag(moduleSetTag); + if (existingCmHandleWithSameModuleSetTag.isPresent()) { + upgradeUsingModuleSetTag(upgradedCmHandle, moduleSetTag); + } else { + syncAndCreateSchemaSetAndAnchor(upgradedCmHandle); + } + setCmHandleModuleSetTag(upgradedCmHandle, moduleSetTag); + } + + private void syncAndCreateSchemaSetAndAnchor(final YangModelCmHandle yangModelCmHandle) { final Collection<ModuleReference> allModuleReferencesFromCmHandle = dmiModelOperations.getModuleReferences(yangModelCmHandle); @@ -73,8 +106,8 @@ public class ModuleSyncService { final Map<String, String> newModuleNameToContentMap, final Collection<ModuleReference> allModuleReferencesFromCmHandle) { final String schemaSetAndAnchorName = yangModelCmHandle.getId(); - cpsModuleService.createSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, schemaSetAndAnchorName, - newModuleNameToContentMap, allModuleReferencesFromCmHandle); + cpsModuleService.createOrUpgradeSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, + schemaSetAndAnchorName, newModuleNameToContentMap, allModuleReferencesFromCmHandle); cpsAdminService.createAnchor(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, schemaSetAndAnchorName, schemaSetAndAnchorName); } @@ -94,4 +127,41 @@ public class ModuleSyncService { } } + private Optional<DataNode> getFirstReadyDataNodeWithModuleSetTag(final String moduleSetTag) { + final List<DataNode> dataNodes = StringUtils.isNotBlank(moduleSetTag) ? cmHandleQueries + .queryNcmpRegistryByCpsPath("//cm-handles[@module-set-tag='" + moduleSetTag + "']", + FetchDescendantsOption.OMIT_DESCENDANTS) : Collections.emptyList(); + return dataNodes.stream().filter(dataNode -> { + final String cmHandleId = YangDataConverter.extractCmHandleIdFromXpath(dataNode.getXpath()); + return cmHandleQueries.cmHandleHasState(cmHandleId, CmHandleState.READY); + }).findFirst(); + } + + private void setCmHandleModuleSetTag(final YangModelCmHandle upgradedCmHandle, final String moduleSetTag) { + final Map<String, Map<String, String>> dmiRegistryProperties = new HashMap<>(1); + final Map<String, String> cmHandleProperties = new HashMap<>(2); + cmHandleProperties.put("id", upgradedCmHandle.getId()); + cmHandleProperties.put("module-set-tag", moduleSetTag); + dmiRegistryProperties.put("cm-handles", cmHandleProperties); + cpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, NCMP_DMI_REGISTRY_PARENT, + jsonObjectMapper.asJsonString(dmiRegistryProperties), OffsetDateTime.now()); + } + + private void upgradeUsingModuleSetTag(final YangModelCmHandle upgradedCmHandle, final String moduleSetTag) { + log.info("Found cm handle having module set tag: {}", moduleSetTag); + final Collection<ModuleReference> moduleReferencesFromExistingCmHandle = + cpsModuleService.getYangResourcesModuleReferences(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR); + final String upgradedSchemaSetAndAnchorName = upgradedCmHandle.getId(); + final Map<String, String> noNewModules = Collections.emptyMap(); + cpsModuleService.createOrUpgradeSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, + upgradedSchemaSetAndAnchorName, noNewModules, moduleReferencesFromExistingCmHandle); + } + + private static String extractModuleSetTag(final CompositeState compositeState) { + return compositeState.getLockReason() != null && compositeState.getLockReason().getLockReasonCategory() + == LockReasonCategory.MODULE_UPGRADE + ? Arrays.stream(compositeState.getLockReason().getDetails().split(":")).toList().get(1).trim() + : StringUtils.EMPTY; + } + } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncTasks.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncTasks.java index 7306f7174..c19dbeb90 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncTasks.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncTasks.java @@ -60,7 +60,8 @@ public class ModuleSyncTasks { public CompletableFuture<Void> performModuleSync(final Collection<DataNode> cmHandlesAsDataNodes, final AtomicInteger batchCounter) { try { - final Map<YangModelCmHandle, CmHandleState> cmHandelStatePerCmHandle = new HashMap<>(); + final Map<YangModelCmHandle, CmHandleState> cmHandelStatePerCmHandle + = new HashMap<>(cmHandlesAsDataNodes.size()); for (final DataNode cmHandleAsDataNode : cmHandlesAsDataNodes) { final String cmHandleId = String.valueOf(cmHandleAsDataNode.getLeaves().get("id")); final YangModelCmHandle yangModelCmHandle = @@ -68,16 +69,18 @@ public class ModuleSyncTasks { final CompositeState compositeState = inventoryPersistence.getCmHandleState(cmHandleId); try { moduleSyncService.deleteSchemaSetIfExists(cmHandleId); - moduleSyncService.syncAndCreateSchemaSetAndAnchor(yangModelCmHandle); + moduleSyncService.syncAndCreateOrUpgradeSchemaSetAndAnchor(yangModelCmHandle); + yangModelCmHandle.getCompositeState().setLockReason(null); cmHandelStatePerCmHandle.put(yangModelCmHandle, CmHandleState.READY); } catch (final Exception e) { - log.warn("Processing of {} module sync failed due to reason {}.", cmHandleId, e.getMessage()); + log.warn("Processing of {} module sync failed due to reason {}.", + cmHandleId, e.getMessage()); syncUtils.updateLockReasonDetailsAndAttempts(compositeState, LockReasonCategory.MODULE_SYNC_FAILED, e.getMessage()); setCmHandleStateLocked(yangModelCmHandle, compositeState.getLockReason()); cmHandelStatePerCmHandle.put(yangModelCmHandle, CmHandleState.LOCKED); } - log.info("{} is now in {} state", cmHandleId, compositeState.getCmHandleState().name()); + log.info("{} is now in {} state", cmHandleId, cmHandelStatePerCmHandle.get(yangModelCmHandle).name()); } lcmEventsCmHandleStateHandler.updateCmHandleStateBatch(cmHandelStatePerCmHandle); } finally { @@ -96,7 +99,7 @@ public class ModuleSyncTasks { final Map<YangModelCmHandle, CmHandleState> cmHandleStatePerCmHandle = new HashMap<>(failedCmHandles.size()); for (final YangModelCmHandle failedCmHandle : failedCmHandles) { final CompositeState compositeState = failedCmHandle.getCompositeState(); - final boolean isReadyForRetry = syncUtils.needsModuleSyncRetry(compositeState); + final boolean isReadyForRetry = syncUtils.needsModuleSyncRetryOrUpgrade(compositeState); log.info("Retry for cmHandleId : {} is {}", failedCmHandle.getId(), isReadyForRetry); if (isReadyForRetry) { final String resetCmHandleId = failedCmHandle.getId(); diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncWatchdog.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncWatchdog.java index 6ba52ee16..75781eb1b 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncWatchdog.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncWatchdog.java @@ -90,7 +90,7 @@ public class ModuleSyncWatchdog { @Scheduled(fixedDelayString = "${ncmp.timers.locked-modules-sync.sleep-time-ms:300000}") public void resetPreviouslyFailedCmHandles() { log.info("Processing module sync retry-watchdog waking up."); - final List<YangModelCmHandle> failedCmHandles = syncUtils.getModuleSyncFailedCmHandles(); + final List<YangModelCmHandle> failedCmHandles = syncUtils.getCmHandlesThatFailedModelSyncOrUpgrade(); log.info("Retrying {} cmHandles", failedCmHandles.size()); moduleSyncTasks.resetFailedCmHandles(failedCmHandles); } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/SyncUtils.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/SyncUtils.java index c50bd4278..ab85c2127 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/SyncUtils.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/SyncUtils.java @@ -35,7 +35,6 @@ import java.util.Map; import java.util.UUID; import java.util.regex.Matcher; import java.util.regex.Pattern; -import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.onap.cps.ncmp.api.impl.inventory.CmHandleQueries; @@ -100,13 +99,14 @@ public class SyncUtils { } /** - * Query data nodes for cm handles with an "LOCKED" cm handle state with reason MODULE_SYNC_FAILED". + * Query data nodes for cm handles with an "LOCKED" cm handle state with reason. * * @return a random LOCKED yang model cm handle, return null if not found */ - public List<YangModelCmHandle> getModuleSyncFailedCmHandles() { - final List<DataNode> lockedCmHandlesAsDataNodeList = cmHandleQueries.queryCmHandleDataNodesByCpsPath( - "//lock-reason[@reason=\"MODULE_SYNC_FAILED\"]", + public List<YangModelCmHandle> getCmHandlesThatFailedModelSyncOrUpgrade() { + final List<DataNode> lockedCmHandlesAsDataNodeList + = cmHandleQueries.queryCmHandleAncestorsByCpsPath( + "//lock-reason[@reason=\"MODULE_SYNC_FAILED\" or @reason=\"MODULE_UPGRADE\"]", FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS); return convertCmHandlesDataNodesToYangModelCmHandles(lockedCmHandlesAsDataNodeList); } @@ -139,32 +139,39 @@ public class SyncUtils { * @param compositeState the composite state currently in the locked state * @return if the retry mechanism should be attempted */ - public boolean needsModuleSyncRetry(final CompositeState compositeState) { - final OffsetDateTime time = - OffsetDateTime.parse(compositeState.getLastUpdateTime(), - DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ")); - final Matcher matcher = retryAttemptPattern.matcher(compositeState.getLockReason().getDetails()); + public boolean needsModuleSyncRetryOrUpgrade(final CompositeState compositeState) { + final OffsetDateTime time = OffsetDateTime.parse(compositeState.getLastUpdateTime(), + DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ")); + final CompositeState.LockReason lockReason = compositeState.getLockReason(); + final boolean failedDuringModuleSync = LockReasonCategory.MODULE_SYNC_FAILED - == compositeState.getLockReason().getLockReasonCategory(); - if (!failedDuringModuleSync) { - log.info("Locked for other reason"); - return false; - } - final int timeInMinutesUntilNextAttempt; - if (matcher.find()) { - timeInMinutesUntilNextAttempt = (int) Math.pow(2, Integer.parseInt(matcher.group(1))); - } else { - timeInMinutesUntilNextAttempt = 1; - log.info("First Attempt: no current attempts found."); - } - final int timeSinceLastAttempt = (int) Duration.between(time, OffsetDateTime.now()).toMinutes(); - if (timeInMinutesUntilNextAttempt >= timeSinceLastAttempt) { - log.info("Time until next attempt is {} minutes: ", - timeInMinutesUntilNextAttempt - timeSinceLastAttempt); - return false; + == lockReason.getLockReasonCategory(); + final boolean moduleUpgrade = LockReasonCategory.MODULE_UPGRADE + == lockReason.getLockReasonCategory(); + + if (failedDuringModuleSync) { + final int timeInMinutesUntilNextAttempt; + final Matcher matcher = retryAttemptPattern.matcher(lockReason.getDetails()); + if (matcher.find()) { + timeInMinutesUntilNextAttempt = (int) Math.pow(2, Integer.parseInt(matcher.group(1))); + } else { + timeInMinutesUntilNextAttempt = 1; + log.info("First Attempt: no current attempts found."); + } + final int timeSinceLastAttempt = (int) Duration.between(time, OffsetDateTime.now()).toMinutes(); + if (timeInMinutesUntilNextAttempt >= timeSinceLastAttempt) { + log.info("Time until next attempt is {} minutes: ", + timeInMinutesUntilNextAttempt - timeSinceLastAttempt); + return false; + } + log.info("Retry due now"); + return true; + } else if (moduleUpgrade) { + log.info("Locked for module upgrade."); + return true; } - log.info("Retry due now"); - return true; + log.info("Locked for other reason"); + return false; } /** @@ -196,6 +203,6 @@ public class SyncUtils { final List<DataNode> cmHandlesAsDataNodeList) { return cmHandlesAsDataNodeList.stream() .map(cmHandle -> YangDataConverter.convertCmHandleToYangModel(cmHandle, - cmHandle.getLeaves().get("id").toString())).collect(Collectors.toList()); + cmHandle.getLeaves().get("id").toString())).toList(); } } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/YangDataConverter.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/YangDataConverter.java index 1b190759e..b6a04d367 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/YangDataConverter.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/YangDataConverter.java @@ -86,7 +86,8 @@ public class YangDataConverter { (String) cmHandleDataNode.getLeaves().get("dmi-service-name"), (String) cmHandleDataNode.getLeaves().get("dmi-data-service-name"), (String) cmHandleDataNode.getLeaves().get("dmi-model-service-name"), - ncmpServiceCmHandle + ncmpServiceCmHandle, + (String) cmHandleDataNode.getLeaves().get("module-set-tag") ); } @@ -105,7 +106,12 @@ public class YangDataConverter { return yangModelCmHandles; } - private static String extractCmHandleIdFromXpath(final String xpath) { + /** + * This method extract cm handle id from xpath of data node. + * @param xpath for data node of the cm handle + * @return cm handle Id + */ + public static String extractCmHandleIdFromXpath(final String xpath) { final Matcher matcher = cmHandleIdInXpathPattern.matcher(xpath); matcher.find(); return matcher.group(1); diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandle.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandle.java index 52fc81f50..d148f371b 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandle.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandle.java @@ -64,6 +64,9 @@ public class YangModelCmHandle { @JsonProperty("dmi-model-service-name") private String dmiModelServiceName; + @JsonProperty("module-set-tag") + private String moduleSetTag; + @JsonProperty("additional-properties") private List<Property> dmiProperties; @@ -102,12 +105,14 @@ public class YangModelCmHandle { public static YangModelCmHandle toYangModelCmHandle(final String dmiServiceName, final String dmiDataServiceName, final String dmiModelServiceName, - final NcmpServiceCmHandle ncmpServiceCmHandle) { + final NcmpServiceCmHandle ncmpServiceCmHandle, + final String moduleSetTag) { final YangModelCmHandle yangModelCmHandle = new YangModelCmHandle(); yangModelCmHandle.setId(ncmpServiceCmHandle.getCmHandleId()); yangModelCmHandle.setDmiServiceName(dmiServiceName); yangModelCmHandle.setDmiDataServiceName(dmiDataServiceName); yangModelCmHandle.setDmiModelServiceName(dmiModelServiceName); + yangModelCmHandle.setModuleSetTag(moduleSetTag); yangModelCmHandle.setDmiProperties(asYangModelCmHandleProperties(ncmpServiceCmHandle.getDmiProperties())); yangModelCmHandle.setPublicProperties(asYangModelCmHandleProperties( ncmpServiceCmHandle.getPublicProperties())); diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleRegistrationResponse.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleRegistrationResponse.java index 5bab51bc2..e007491ce 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleRegistrationResponse.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/CmHandleRegistrationResponse.java @@ -26,12 +26,11 @@ import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.regex.Matcher; -import java.util.regex.Pattern; import lombok.Builder; import lombok.Data; import lombok.extern.slf4j.Slf4j; import org.onap.cps.ncmp.api.NcmpResponseStatus; +import org.onap.cps.ncmp.api.impl.utils.YangDataConverter; @Data @Builder @@ -43,8 +42,6 @@ public class CmHandleRegistrationResponse { private NcmpResponseStatus ncmpResponseStatus; private String errorText; - private static final Pattern cmHandleIdInXpathPattern = Pattern.compile("\\[@id='(.*?)']"); - /** * Creates a failure response based on exception. * @@ -88,11 +85,11 @@ public class CmHandleRegistrationResponse { final NcmpResponseStatus ncmpResponseStatus) { final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses = new ArrayList<>(failedXpaths.size()); for (final String xpath : failedXpaths) { - final Matcher matcher = cmHandleIdInXpathPattern.matcher(xpath); - if (matcher.find()) { + try { + final String cmHandleId = YangDataConverter.extractCmHandleIdFromXpath(xpath); cmHandleRegistrationResponses.add( - CmHandleRegistrationResponse.createFailureResponse(matcher.group(1), ncmpResponseStatus)); - } else { + CmHandleRegistrationResponse.createFailureResponse(cmHandleId, ncmpResponseStatus)); + } catch (IllegalArgumentException | IllegalStateException e) { log.warn("Unexpected xpath {}", xpath); } } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DmiPluginRegistration.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DmiPluginRegistration.java index 953b3c4e9..4615af61c 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DmiPluginRegistration.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DmiPluginRegistration.java @@ -50,6 +50,8 @@ public class DmiPluginRegistration { private List<String> removedCmHandles = Collections.emptyList(); + private UpgradedCmHandles upgradedCmHandles; + /** * Validates plugin service names. * @throws NcmpException if validation fails. diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DmiPluginRegistrationResponse.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DmiPluginRegistrationResponse.java index 8a3d26414..ee034176e 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DmiPluginRegistrationResponse.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/DmiPluginRegistrationResponse.java @@ -1,6 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2022 Bell Canada + * Modifications Copyright (C) 2023 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -31,4 +32,5 @@ public class DmiPluginRegistrationResponse { private List<CmHandleRegistrationResponse> createdCmHandles = Collections.emptyList(); private List<CmHandleRegistrationResponse> updatedCmHandles = Collections.emptyList(); private List<CmHandleRegistrationResponse> removedCmHandles = Collections.emptyList(); + private List<CmHandleRegistrationResponse> upgradedCmHandles = Collections.emptyList(); }
\ No newline at end of file diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/NcmpServiceCmHandle.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/NcmpServiceCmHandle.java index c46a8c26d..0b50346f8 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/NcmpServiceCmHandle.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/NcmpServiceCmHandle.java @@ -52,6 +52,9 @@ public class NcmpServiceCmHandle { @JsonSetter(nulls = Nulls.AS_EMPTY) private CompositeState compositeState; + @JsonSetter(nulls = Nulls.AS_EMPTY) + private String moduleSetTag; + /** * NcmpServiceCmHandle copy constructor. * @@ -63,5 +66,6 @@ public class NcmpServiceCmHandle { this.publicProperties = new LinkedHashMap<>(ncmpServiceCmHandle.getPublicProperties()); this.compositeState = ncmpServiceCmHandle.getCompositeState() != null ? new CompositeState( ncmpServiceCmHandle.getCompositeState()) : null; + this.moduleSetTag = ncmpServiceCmHandle.getModuleSetTag(); } } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/UpgradedCmHandles.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/UpgradedCmHandles.java new file mode 100644 index 000000000..61cd99ac8 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/UpgradedCmHandles.java @@ -0,0 +1,36 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 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.models; + +import com.fasterxml.jackson.annotation.JsonInclude; +import java.util.Collections; +import java.util.List; +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +@JsonInclude(JsonInclude.Include.NON_EMPTY) +public class UpgradedCmHandles { + private List<String> cmHandles = Collections.emptyList(); + private String moduleSetTag; +} + |