From 55164b23839f187ae089fd08c34487dcfd165188 Mon Sep 17 00:00:00 2001 From: sourabh_sourabh Date: Tue, 26 Sep 2023 12:11:42 +0100 Subject: Expose REST endpoint to update YANG schema set using moduleSetTag - Added new schema to upgrade model into component. - Modified Ncmp rest input mapper to add upgradedCmHandles attributes. - Modified cm handle state mapper to add new lock reason. - Added new method to parse and upgrade Cm handles in DmiRegistration. - YANG data converter is modified to add "module-set-tag" atribute. - Cm handle new query method is added for cps path without appending ancestor. - Modified setCompositeStateForRetry to add lock reason. - New lock reason category is added. - Existing module sync service is modified to upgrade the model "syncAndCreateOrUpgradeSchemaSetAndAnchor". - Sync util method "getModuleSyncFailedCmHandles" to modified to add another lock reason "LOCKED_MISBEHAVING". - Added new attribute "UpgradedCmHandles" into DmiPluginRegistration and DmiPluginRegistrationResponse. - New attribute "moduleSetTag" is added into NcmpServiceCmHandle. - New model "UpgradedCmHandles" is added. - New method "updateSchemaSetWithExistingModules" is added into cps module service to update cm handle with exsting model. - Code coverage is reducced to 96 percentage that would be addressed and pushed into new patch. Issue-ID: CPS-1798 Signed-off-by: sourabh_sourabh Change-Id: I540acb404e38fc434de87a0d959bfde710a18b03 Signed-off-by: sourabh_sourabh --- .../NetworkCmProxyCmHandleQueryServiceImpl.java | 3 +- .../api/impl/NetworkCmProxyDataServiceImpl.java | 84 ++++++++++++++++++---- .../ncmp/api/impl/inventory/CmHandleQueries.java | 11 ++- .../api/impl/inventory/CmHandleQueriesImpl.java | 19 +++-- .../api/impl/inventory/CompositeStateUtils.java | 4 +- .../api/impl/inventory/LockReasonCategory.java | 5 +- .../api/impl/inventory/sync/ModuleSyncService.java | 80 +++++++++++++++++++-- .../api/impl/inventory/sync/ModuleSyncTasks.java | 13 ++-- .../impl/inventory/sync/ModuleSyncWatchdog.java | 2 +- .../ncmp/api/impl/inventory/sync/SyncUtils.java | 67 +++++++++-------- .../cps/ncmp/api/impl/utils/YangDataConverter.java | 10 ++- .../api/impl/yangmodels/YangModelCmHandle.java | 7 +- .../api/models/CmHandleRegistrationResponse.java | 13 ++-- .../cps/ncmp/api/models/DmiPluginRegistration.java | 2 + .../api/models/DmiPluginRegistrationResponse.java | 2 + .../cps/ncmp/api/models/NcmpServiceCmHandle.java | 4 ++ .../cps/ncmp/api/models/UpgradedCmHandles.java | 36 ++++++++++ 17 files changed, 288 insertions(+), 74 deletions(-) create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/models/UpgradedCmHandles.java (limited to 'cps-ncmp-service/src/main/java') 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 58732b207c..7475cdd4a3 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 d34e2a3141..692a9f2a94 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 getCmHandlePublicProperties(final String cmHandleId) { - final YangModelCmHandle yangModelCmHandle = - inventoryPersistence.getYangModelCmHandle(cmHandleId); + final YangModelCmHandle yangModelCmHandle = inventoryPersistence.getYangModelCmHandle(cmHandleId); final List yangModelPublicProperties = yangModelCmHandle.getPublicProperties(); final Map 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 parseAndCreateCmHandlesInDmiRegistrationAndSyncModules( + public List parseAndProcessCreatedCmHandlesInRegistration( final DmiPluginRegistration dmiPluginRegistration) { final Map 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 parseAndRemoveCmHandlesInDmiRegistration( + protected List parseAndProcessDeletedCmHandlesInRegistration( final List tobeRemovedCmHandles) { final List cmHandleRegistrationResponses = new ArrayList<>(tobeRemovedCmHandles.size()); final Collection yangModelCmHandles = - inventoryPersistence.getYangModelCmHandles(tobeRemovedCmHandles); + inventoryPersistence.getYangModelCmHandles(tobeRemovedCmHandles); updateCmHandleStateBatch(yangModelCmHandles, CmHandleState.DELETING); @@ -351,6 +360,42 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService return cmHandleRegistrationResponses; } + protected List parseAndProcessUpgradedCmHandlesInRegistration( + final DmiPluginRegistration dmiPluginRegistration) { + + final UpgradedCmHandles upgradedCmHandles = dmiPluginRegistration.getUpgradedCmHandles(); + final String moduleSetTag = dmiPluginRegistration.getUpgradedCmHandles().getModuleSetTag(); + final Map cmHandleStatePerCmHandle = + new HashMap<>(upgradedCmHandles.getCmHandles().size()); + final Collection 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 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 registerNewCmHandles(final Map cmHandleStatePerCmHandle) { - final List cmHandleIds = cmHandleStatePerCmHandle.keySet().stream().map(YangModelCmHandle::getId) - .toList(); + final List cmHandleIds = getCmHandleIds(cmHandleStatePerCmHandle); try { lcmEventsCmHandleStateHandler.updateCmHandleStateBatch(cmHandleStatePerCmHandle); return CmHandleRegistrationResponse.createSuccessResponses(cmHandleIds); @@ -418,6 +462,22 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService } } + private List upgradeCmHandles(final Map + cmHandleStatePerCmHandle) { + final List 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 getCmHandleIds(final Map 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 4776788c84..a5892afc3e 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 @@ -52,13 +52,22 @@ public interface CmHandleQueries { */ List 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 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 queryCmHandleDataNodesByCpsPath(String cpsPath, FetchDescendantsOption fetchDescendantsOption); + List 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 b3ade4f1cf..c4e3fd098d 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 queryCmHandlesByState(final CmHandleState cmHandleState) { - return queryCmHandleDataNodesByCpsPath("//state[@cm-handle-state=\"" + cmHandleState + "\"]", + return queryCmHandleAncestorsByCpsPath("//state[@cm-handle-state=\"" + cmHandleState + "\"]", INCLUDE_ALL_DESCENDANTS); } @Override - public List queryCmHandleDataNodesByCpsPath(final String cpsPath, - final FetchDescendantsOption fetchDescendantsOption) { + public List 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 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 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 dataNodes = queryCmHandleDataNodesByCpsPath(cpsPath, OMIT_DESCENDANTS); + final Collection 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 ef4b299e10..99cca8c0b3 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 8306619f20..e2b2c6b4ae 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 b2949c2781..8e17ab9166 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 existingCmHandleWithSameModuleSetTag + = getFirstReadyDataNodeWithModuleSetTag(moduleSetTag); + if (existingCmHandleWithSameModuleSetTag.isPresent()) { + upgradeUsingModuleSetTag(upgradedCmHandle, moduleSetTag); + } else { + syncAndCreateSchemaSetAndAnchor(upgradedCmHandle); + } + setCmHandleModuleSetTag(upgradedCmHandle, moduleSetTag); + } + + private void syncAndCreateSchemaSetAndAnchor(final YangModelCmHandle yangModelCmHandle) { final Collection allModuleReferencesFromCmHandle = dmiModelOperations.getModuleReferences(yangModelCmHandle); @@ -73,8 +106,8 @@ public class ModuleSyncService { final Map newModuleNameToContentMap, final Collection 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 getFirstReadyDataNodeWithModuleSetTag(final String moduleSetTag) { + final List 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> dmiRegistryProperties = new HashMap<>(1); + final Map 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 moduleReferencesFromExistingCmHandle = + cpsModuleService.getYangResourcesModuleReferences(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR); + final String upgradedSchemaSetAndAnchorName = upgradedCmHandle.getId(); + final Map 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 7306f71740..c19dbeb900 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 performModuleSync(final Collection cmHandlesAsDataNodes, final AtomicInteger batchCounter) { try { - final Map cmHandelStatePerCmHandle = new HashMap<>(); + final Map 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 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 6ba52ee16c..75781eb1b3 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 failedCmHandles = syncUtils.getModuleSyncFailedCmHandles(); + final List 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 c50bd42789..ab85c2127e 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 getModuleSyncFailedCmHandles() { - final List lockedCmHandlesAsDataNodeList = cmHandleQueries.queryCmHandleDataNodesByCpsPath( - "//lock-reason[@reason=\"MODULE_SYNC_FAILED\"]", + public List getCmHandlesThatFailedModelSyncOrUpgrade() { + final List 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 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 1b190759ee..b6a04d3677 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 52fc81f503..d148f371b5 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 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 5bab51bc27..e007491ce0 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 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 953b3c4e94..4615af61c1 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 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 8a3d26414a..ee034176e3 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 createdCmHandles = Collections.emptyList(); private List updatedCmHandles = Collections.emptyList(); private List removedCmHandles = Collections.emptyList(); + private List 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 c46a8c26d6..0b50346f81 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 0000000000..61cd99ac8f --- /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 cmHandles = Collections.emptyList(); + private String moduleSetTag; +} + -- cgit 1.2.3-korg