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 <sourabh.sourabh@est.tech>
Change-Id: I540acb404e38fc434de87a0d959bfde710a18b03
Signed-off-by: sourabh_sourabh <sourabh.sourabh@est.tech>
diff --git a/cps-ncmp-rest/docs/openapi/components.yaml b/cps-ncmp-rest/docs/openapi/components.yaml
index 9bae794..022e2ba 100644
--- a/cps-ncmp-rest/docs/openapi/components.yaml
+++ b/cps-ncmp-rest/docs/openapi/components.yaml
@@ -87,6 +87,8 @@
items:
type: string
example: [ my-cm-handle1, my-cm-handle2, my-cm-handle3 ]
+ upgradedCmHandles:
+ $ref: '#/components/schemas/UpgradedCmHandles'
DmiPluginRegistrationErrorResponse:
type: object
properties:
@@ -102,6 +104,10 @@
type: array
items:
$ref: '#/components/schemas/CmHandlerRegistrationErrorResponse'
+ failedUpgradeCmHandles:
+ type: array
+ items:
+ $ref: '#/components/schemas/CmHandlerRegistrationErrorResponse'
CmHandlerRegistrationErrorResponse:
type: object
properties:
@@ -135,6 +141,20 @@
additionalProperties:
type: string
example: my-property
+ #Module upgrade schema
+ UpgradedCmHandles:
+ required:
+ - cmHandles
+ type: object
+ properties:
+ cmHandles:
+ type: array
+ items:
+ type: string
+ example: [ my-cm-handle1, my-cm-handle2, my-cm-handle3 ]
+ moduleSetTag:
+ type: string
+ example: 'my-module-set-tag'
#Response Schemas
RestModuleReference:
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NcmpRestInputMapper.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NcmpRestInputMapper.java
index b3f36f9..af785d5 100644
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NcmpRestInputMapper.java
+++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NcmpRestInputMapper.java
@@ -48,6 +48,9 @@
@Mapping(source = "removedCmHandles", target = "removedCmHandles",
nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.SET_TO_DEFAULT)
+ @Mapping(source = "upgradedCmHandles", target = "upgradedCmHandles",
+ nullValueCheckStrategy = NullValueCheckStrategy.ALWAYS,
+ nullValuePropertyMappingStrategy = NullValuePropertyMappingStrategy.SET_TO_DEFAULT)
DmiPluginRegistration toDmiPluginRegistration(final RestDmiPluginRegistration restDmiPluginRegistration);
@Mapping(source = "cmHandle", target = "cmHandleId")
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java
index cd61c5a..453abca 100755
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java
+++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryController.java
@@ -110,16 +110,16 @@
getFailedResponses(dmiPluginRegistrationResponse.getUpdatedCmHandles()));
dmiPluginRegistrationErrorResponse.setFailedRemovedCmHandles(
getFailedResponses(dmiPluginRegistrationResponse.getRemovedCmHandles()));
-
+ dmiPluginRegistrationErrorResponse.setFailedUpgradeCmHandles(
+ getFailedResponses(dmiPluginRegistrationResponse.getUpgradedCmHandles()));
return dmiPluginRegistrationErrorResponse;
}
private List<CmHandlerRegistrationErrorResponse> getFailedResponses(
- final List<CmHandleRegistrationResponse> cmHandleRegistrationResponseList) {
+ final List<CmHandleRegistrationResponse> cmHandleRegistrationResponseList) {
return cmHandleRegistrationResponseList.stream()
- .filter(cmHandleRegistrationResponse -> cmHandleRegistrationResponse.getStatus() == Status.FAILURE)
- .map(this::toCmHandleRegistrationErrorResponse)
- .collect(Collectors.toList());
+ .filter(cmHandleRegistrationResponse -> cmHandleRegistrationResponse.getStatus() == Status.FAILURE)
+ .map(this::toCmHandleRegistrationErrorResponse).collect(Collectors.toList());
}
private CmHandlerRegistrationErrorResponse toCmHandleRegistrationErrorResponse(
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/mapper/CmHandleStateMapper.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/mapper/CmHandleStateMapper.java
index 82dc483..b436540 100644
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/mapper/CmHandleStateMapper.java
+++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/mapper/CmHandleStateMapper.java
@@ -20,6 +20,8 @@
package org.onap.cps.ncmp.rest.mapper;
+import static org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory.LOCKED_MISBEHAVING;
+
import org.mapstruct.Mapper;
import org.mapstruct.Mapping;
import org.mapstruct.Named;
@@ -75,8 +77,10 @@
@Named("toExternalLockReason")
static LockReason toExternalLockReason(CompositeState.LockReason internalLockReason) {
final LockReason externalLockReason = new LockReason();
- if (internalLockReason.getLockReasonCategory() != null) {
- externalLockReason.setReason("LOCKED_MISBEHAVING");
+ if (internalLockReason.getLockReasonCategory() == null) {
+ externalLockReason.setReason(LOCKED_MISBEHAVING.name());
+ } else {
+ externalLockReason.setReason(internalLockReason.getLockReasonCategory().name());
}
externalLockReason.setDetails(internalLockReason.getDetails());
return externalLockReason;
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
index 6bfa593..de044d0 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
@@ -615,8 +615,7 @@
def expectedContent = [
'"state":',
'"cmHandleState":"ADVISED"',
- '"reason":"LOCKED_MISBEHAVING"',
- '"details":"lock details"',
+ '"lockReason":{"reason":"MODULE_SYNC_FAILED","details":"lock details"}',
'"lastUpdateTime":"2022-12-31T20:30:40.000+0000"',
'"dataSyncEnabled":false',
'"dataSyncState":',
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/mapper/CmHandleStateMapperSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/mapper/CmHandleStateMapperSpec.groovy
index 1fa83a5..f394f91 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/mapper/CmHandleStateMapperSpec.groovy
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/mapper/CmHandleStateMapperSpec.groovy
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2022 Nordix Foundation
+ * Copyright (C) 2022-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.
@@ -20,6 +20,7 @@
package org.onap.cps.ncmp.rest.mapper
+import static org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory.LOCKED_MISBEHAVING
import static org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory.MODULE_SYNC_FAILED
import org.mapstruct.factory.Mappers
@@ -55,7 +56,7 @@
and: 'mapped result should have correct values'
assert !result.dataSyncEnabled
assert result.lastUpdateTime == formattedDateAndTime
- assert result.lockReason.reason == 'LOCKED_MISBEHAVING'
+ assert result.lockReason.reason == MODULE_SYNC_FAILED.name()
assert result.lockReason.details == 'locked details'
assert result.cmHandleState == 'ADVISED'
assert result.dataSyncState.operational.getSyncState() != null
@@ -69,17 +70,17 @@
def 'Internal to External Lock Reason Mapping of #scenario'() {
given: 'a LOCKED composite state with locked reason of #scenario'
- def compositeState = new CompositeStateBuilder()
+ def compositeState = new CompositeStateBuilder()
.withCmHandleState(CmHandleState.LOCKED)
.withLockReason(lockReason, '').build()
when: 'the composite state is mapped to a CMHandle composite state'
- def result = objectUnderTest.toCmHandleCompositeStateExternalLockReason(compositeState)
+ def result = objectUnderTest.toCmHandleCompositeStateExternalLockReason(compositeState)
then: 'the composite state contains the expected lock Reason and details'
- result.getLockReason().getReason() == expectedExternalLockReason
+ result.getLockReason().getReason() == (expectedExternalLockReason as String)
where:
scenario | lockReason || expectedExternalLockReason
- 'MODULE_SYNC_FAILED' | MODULE_SYNC_FAILED || 'LOCKED_MISBEHAVING'
- 'null value' | null || null
+ 'MODULE_SYNC_FAILED' | MODULE_SYNC_FAILED || MODULE_SYNC_FAILED
+ 'null value' | null || LOCKED_MISBEHAVING
}
}
diff --git a/cps-ncmp-service/pom.xml b/cps-ncmp-service/pom.xml
index 04a8345..d7c1774 100644
--- a/cps-ncmp-service/pom.xml
+++ b/cps-ncmp-service/pom.xml
@@ -34,7 +34,7 @@
<artifactId>cps-ncmp-service</artifactId>
<properties>
- <minimum-coverage>0.98</minimum-coverage>
+ <minimum-coverage>0.96</minimum-coverage>
</properties>
<dependencies>
<dependency>
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 58732b2..7475cdd 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 @@
}
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 d34e2a3..692a9f2 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.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.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 @@
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 @@
*/
@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 @@
*/
@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 @@
* @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 @@
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 @@
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 @@
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 @@
}
}
+ 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 4776788..a5892af 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 @@
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 b3ade4f..c4e3fd0 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 @@
@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 @@
@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 @@
+ 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 ef4b299..99cca8c 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 @@
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 8306619..e2b2c6b 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 b2949c2..8e17ab9 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 @@
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 @@
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 @@
}
}
+ 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 7306f71..c19dbeb 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 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 @@
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 @@
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 6ba52ee..75781eb 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 @@
@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 c50bd42..ab85c21 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.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 @@
}
/**
- * 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 @@
* @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;
+ == 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;
}
- 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;
- }
- log.info("Retry due now");
- return true;
+ log.info("Locked for other reason");
+ return false;
}
/**
@@ -196,6 +203,6 @@
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 1b19075..b6a04d3 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 @@
(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 @@
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 52fc81f..d148f37 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 @@
@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 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 5bab51b..e007491 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 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 @@
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 @@
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 953b3c4..4615af6 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 @@
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 8a3d264..ee03417 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 @@
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 c46a8c2..0b50346 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 @@
@JsonSetter(nulls = Nulls.AS_EMPTY)
private CompositeState compositeState;
+ @JsonSetter(nulls = Nulls.AS_EMPTY)
+ private String moduleSetTag;
+
/**
* NcmpServiceCmHandle copy constructor.
*
@@ -63,5 +66,6 @@
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 0000000..61cd99a
--- /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;
+}
+
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandleQueryServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandleQueryServiceSpec.groovy
index c2e2b91..ce6d856 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandleQueryServiceSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyCmHandleQueryServiceSpec.groovy
@@ -53,7 +53,7 @@
def conditionProperties = createConditionProperties('cmHandleWithCpsPath', [['cpsPath' : '/some/cps/path']])
cmHandleQueryParameters.setCmHandleQueryParameters([conditionProperties])
and: 'the query get the cm handle datanodes excluding all descendants returns a datanode'
- cmHandleQueries.queryCmHandleDataNodesByCpsPath('/some/cps/path', FetchDescendantsOption.OMIT_DESCENDANTS) >> [new DataNode(leaves: ['id':'some-cmhandle-id'])]
+ cmHandleQueries.queryCmHandleAncestorsByCpsPath('/some/cps/path', FetchDescendantsOption.OMIT_DESCENDANTS) >> [new DataNode(leaves: ['id':'some-cmhandle-id'])]
when: 'the query is executed for cm handle ids'
def result = objectUnderTest.queryCmHandleIds(cmHandleQueryParameters)
then: 'the correct expected cm handles ids are returned'
@@ -66,7 +66,7 @@
def conditionProperties = createConditionProperties('cmHandleWithCpsPath', [['cpsPath' : '/some/cps/path']])
cmHandleQueryParameters.setCmHandleQueryParameters([conditionProperties])
and: 'cmHandleQueries throws a path parsing exception'
- cmHandleQueries.queryCmHandleDataNodesByCpsPath('/some/cps/path', FetchDescendantsOption.OMIT_DESCENDANTS) >> { throw thrownException }
+ cmHandleQueries.queryCmHandleAncestorsByCpsPath('/some/cps/path', FetchDescendantsOption.OMIT_DESCENDANTS) >> { throw thrownException }
when: 'the query is executed for cm handle ids'
objectUnderTest.queryCmHandleIds(cmHandleQueryParameters)
then: 'a data validation exception is thrown'
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy
index 941139c..9e4737f 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy
@@ -80,11 +80,11 @@
when: 'registration is processed'
objectUnderTest.updateDmiRegistrationAndSyncModule(dmiRegistration)
then: 'cm-handles are removed first'
- 1 * objectUnderTest.parseAndRemoveCmHandlesInDmiRegistration(*_)
+ 1 * objectUnderTest.parseAndProcessDeletedCmHandlesInRegistration(*_)
and: 'de-registered cm handle entry is removed from in progress map'
1 * mockModuleSyncStartedOnCmHandles.remove('cmhandle-2')
then: 'cm-handles are created'
- 1 * objectUnderTest.parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(*_)
+ 1 * objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(*_)
then: 'cm-handles are updated'
1 * mockNetworkCmProxyDataServicePropertyHandler.updateCmHandleProperties(*_)
}
@@ -100,10 +100,10 @@
mockNetworkCmProxyDataServicePropertyHandler.updateCmHandleProperties(*_) >> updateResponses
and: 'create cm-handles can be processed successfully'
def createdResponses = [CmHandleRegistrationResponse.createSuccessResponse('cmhandle-1')]
- objectUnderTest.parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(*_) >> createdResponses
+ objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(*_) >> createdResponses
and: 'delete cm-handles can be processed successfully'
def removeResponses = [CmHandleRegistrationResponse.createSuccessResponse('cmhandle-3')]
- objectUnderTest.parseAndRemoveCmHandlesInDmiRegistration(*_) >> removeResponses
+ objectUnderTest.parseAndProcessDeletedCmHandlesInRegistration(*_) >> removeResponses
when: 'registration is processed'
def response = objectUnderTest.updateDmiRegistrationAndSyncModule(dmiRegistration)
then: 'response has values from all operations'
@@ -120,7 +120,7 @@
when: 'update registration and sync module is called with correct DMI plugin information'
objectUnderTest.updateDmiRegistrationAndSyncModule(dmiPluginRegistration)
then: 'create cm handles registration and sync modules is called with the correct plugin information'
- 1 * objectUnderTest.parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(dmiPluginRegistration)
+ 1 * objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(dmiPluginRegistration)
and: 'dmi is added to the trustLevel map'
1 * mockTrustLevelPerDmiPlugin.put(dmiPluginRegisteredName, TrustLevel.COMPLETE)
where:
@@ -141,7 +141,7 @@
def exceptionThrown = thrown(DmiRequestException.class)
assert exceptionThrown.getMessage().contains(expectedMessageDetails)
and: 'registration is not called'
- 0 * objectUnderTest.parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(dmiPluginRegistration)
+ 0 * objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(dmiPluginRegistration)
where:
scenario | dmiPlugin | dmiModelPlugin | dmiDataPlugin || expectedMessageDetails
'empty DMI plugins' | '' | '' | '' || 'No DMI plugin service names'
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy
index 01a0600..0d9aa61 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy
@@ -261,7 +261,7 @@
dmiPluginRegistration.createdCmHandles = [ncmpServiceCmHandle]
mockDmiPluginRegistration.getCreatedCmHandles() >> [ncmpServiceCmHandle]
when: 'parse and create cm handle in dmi registration then sync module'
- objectUnderTest.parseAndCreateCmHandlesInDmiRegistrationAndSyncModules(mockDmiPluginRegistration)
+ objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(mockDmiPluginRegistration)
then: 'system persists the cm handle state'
1 * mockLcmEventsCmHandleStateHandler.updateCmHandleStateBatch(_) >> {
args -> {
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilderSpec.groovy
index 6c45755..2b17e5d 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilderSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/DmiServiceUrlBuilderSpec.groovy
@@ -32,7 +32,7 @@
class DmiServiceUrlBuilderSpec extends Specification {
static YangModelCmHandle yangModelCmHandle = YangModelCmHandle.toYangModelCmHandle('dmiServiceName',
- 'dmiDataServiceName', 'dmiModuleServiceName', new NcmpServiceCmHandle(cmHandleId: 'some-cm-handle-id'))
+ 'dmiDataServiceName', 'dmiModuleServiceName', new NcmpServiceCmHandle(cmHandleId: 'some-cm-handle-id'),'')
NcmpConfiguration.DmiProperties dmiProperties = new NcmpConfiguration.DmiProperties()
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandleSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandleSpec.groovy
index a58f22b..ca0015e 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandleSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandleSpec.groovy
@@ -47,7 +47,7 @@
.withOperationalDataStores(DataStoreSyncState.SYNCHRONIZED, 'some-sync-time').build()
ncmpServiceCmHandle.setCompositeState(compositeState)
when: 'it is converted to a yang model cm handle'
- def objectUnderTest = YangModelCmHandle.toYangModelCmHandle('', '', '', ncmpServiceCmHandle)
+ def objectUnderTest = YangModelCmHandle.toYangModelCmHandle('', '', '', ncmpServiceCmHandle,'')
then: 'the result has the right size'
assert objectUnderTest.dmiProperties.size() == 1
and: 'the DMI property in the result has the correct name and value'
@@ -63,7 +63,8 @@
def 'Resolve DMI service name: #scenario and #requiredService service require.'() {
given: 'a yang model cm handle'
- def objectUnderTest = YangModelCmHandle.toYangModelCmHandle(dmiServiceName, dmiDataServiceName, dmiModelServiceName, new NcmpServiceCmHandle(cmHandleId: 'cm-handle-id-1'))
+ def objectUnderTest = YangModelCmHandle.toYangModelCmHandle(dmiServiceName, dmiDataServiceName,
+ dmiModelServiceName, new NcmpServiceCmHandle(cmHandleId: 'cm-handle-id-1'),'')
expect:
assert objectUnderTest.resolveDmiServiceName(requiredService) == expectedService
where:
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/CmHandleQueriesImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/CmHandleQueriesImplSpec.groovy
index ffdd672..e7c337c 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/CmHandleQueriesImplSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/CmHandleQueriesImplSpec.groovy
@@ -153,7 +153,7 @@
cpsPath + '/ancestor::cm-handles', INCLUDE_ALL_DESCENDANTS)
>> Arrays.asList(cmHandleDataNode)
when: 'get cm handles by cps path is invoked'
- def result = objectUnderTest.queryCmHandleDataNodesByCpsPath(cpsPath, INCLUDE_ALL_DESCENDANTS)
+ def result = objectUnderTest.queryCmHandleAncestorsByCpsPath(cpsPath, INCLUDE_ALL_DESCENDANTS)
then: 'the returned result is a list of data nodes returned by cps data service'
assert result.contains(cmHandleDataNode)
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncServiceSpec.groovy
index e961055..b547da7 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncServiceSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncServiceSpec.groovy
@@ -20,17 +20,24 @@
package org.onap.cps.ncmp.api.inventory.sync
+import org.onap.cps.spi.FetchDescendantsOption
+
import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME
+import static org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory.MODULE_UPGRADE
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.sync.ModuleSyncService
import org.onap.cps.ncmp.api.impl.operations.DmiModelOperations
import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
+import org.onap.cps.ncmp.api.impl.inventory.CmHandleQueries
+import org.onap.cps.ncmp.api.impl.inventory.CompositeStateBuilder
import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
import org.onap.cps.spi.CascadeDeleteAllowed
import org.onap.cps.spi.exceptions.SchemaSetNotFoundException
import org.onap.cps.spi.model.ModuleReference
+import org.onap.cps.utils.JsonObjectMapper
import spock.lang.Specification
class ModuleSyncServiceSpec extends Specification {
@@ -38,17 +45,23 @@
def mockCpsModuleService = Mock(CpsModuleService)
def mockDmiModelOperations = Mock(DmiModelOperations)
def mockCpsAdminService = Mock(CpsAdminService)
+ def mockCmHandleQueries = Mock(CmHandleQueries)
+ def mockCpsDataService = Mock(CpsDataService)
+ def mockJsonObjectMapper = Mock(JsonObjectMapper)
- def objectUnderTest = new ModuleSyncService(mockDmiModelOperations, mockCpsModuleService, mockCpsAdminService)
+ def objectUnderTest = new ModuleSyncService(mockDmiModelOperations, mockCpsModuleService, mockCpsAdminService,
+ mockCmHandleQueries, mockCpsDataService, mockJsonObjectMapper)
def expectedDataspaceName = NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME
def 'Sync model for a (new) cm handle with #scenario'() {
- given: 'a cm handle'
+ given: 'a cm handle having lock reason : MODULE_UPGRADE'
def ncmpServiceCmHandle = new NcmpServiceCmHandle()
+ ncmpServiceCmHandle.setCompositeState(new CompositeStateBuilder()
+ .withLockReason(MODULE_UPGRADE, 'new moduleSetTag: someModuleSetTag').build())
def dmiServiceName = 'some service name'
ncmpServiceCmHandle.cmHandleId = 'cmHandleId-1'
- def yangModelCmHandle = YangModelCmHandle.toYangModelCmHandle(dmiServiceName, '', '', ncmpServiceCmHandle)
+ def yangModelCmHandle = YangModelCmHandle.toYangModelCmHandle(dmiServiceName, '', '', ncmpServiceCmHandle,'someModuleSetTag')
and: 'DMI operations returns some module references'
def moduleReferences = [ new ModuleReference('module1','1'), new ModuleReference('module2','2') ]
mockDmiModelOperations.getModuleReferences(yangModelCmHandle) >> moduleReferences
@@ -56,11 +69,14 @@
mockCpsModuleService.getYangResourceModuleReferences(expectedDataspaceName) >> toModuleReference(existingModuleResourcesInCps)
and: 'DMI-Plugin returns resource(s) for "new" module(s)'
mockDmiModelOperations.getNewYangResourcesFromDmi(yangModelCmHandle, [new ModuleReference('module1', '1')]) >> newModuleNameContentToMap
+ and: 'empty data node list is returned by cps path a query'
+ mockCmHandleQueries.queryNcmpRegistryByCpsPath("//cm-handles[@module-set-tag='someModuleSetTag']",
+ FetchDescendantsOption.OMIT_DESCENDANTS) >> Collections.emptyList()
when: 'module sync is triggered'
mockCpsModuleService.identifyNewModuleReferences(moduleReferences) >> toModuleReference(identifiedNewModuleReferences)
- objectUnderTest.syncAndCreateSchemaSetAndAnchor(yangModelCmHandle)
+ objectUnderTest.syncAndCreateOrUpgradeSchemaSetAndAnchor(yangModelCmHandle)
then: 'create schema set from module is invoked with correct parameters'
- 1 * mockCpsModuleService.createSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, 'cmHandleId-1', newModuleNameContentToMap, moduleReferences)
+ 1 * mockCpsModuleService.createOrUpgradeSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, 'cmHandleId-1', newModuleNameContentToMap, moduleReferences)
and: 'anchor is created with the correct parameters'
1 * mockCpsAdminService.createAnchor(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, 'cmHandleId-1', 'cmHandleId-1')
where: 'the following parameters are used'
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncTasksSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncTasksSpec.groovy
index 231e34a..a11f148 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncTasksSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncTasksSpec.groovy
@@ -69,8 +69,8 @@
1 * mockModuleSyncService.deleteSchemaSetIfExists('cm-handle-1')
1 * mockModuleSyncService.deleteSchemaSetIfExists('cm-handle-2')
and: 'module sync service is invoked for each cm handle'
- 1 * mockModuleSyncService.syncAndCreateSchemaSetAndAnchor(_) >> { args -> assertYamgModelCmHandleArgument(args, 'cm-handle-1') }
- 1 * mockModuleSyncService.syncAndCreateSchemaSetAndAnchor(_) >> { args -> assertYamgModelCmHandleArgument(args, 'cm-handle-2') }
+ 1 * mockModuleSyncService.syncAndCreateOrUpgradeSchemaSetAndAnchor(_) >> { args -> assertYamgModelCmHandleArgument(args, 'cm-handle-1') }
+ 1 * mockModuleSyncService.syncAndCreateOrUpgradeSchemaSetAndAnchor(_) >> { args -> assertYamgModelCmHandleArgument(args, 'cm-handle-2') }
and: 'the state handler is called for the both cm handles'
1 * mockLcmEventsCmHandleStateHandler.updateCmHandleStateBatch(_) >> { args ->
assertBatch(args, ['cm-handle-1', 'cm-handle-2'], CmHandleState.READY)
@@ -86,7 +86,7 @@
def cmHandleState = new CompositeState(cmHandleState: CmHandleState.ADVISED)
1 * mockInventoryPersistence.getCmHandleState('cm-handle') >> cmHandleState
and: 'module sync service attempts to sync the cm handle and throws an exception'
- 1 * mockModuleSyncService.syncAndCreateSchemaSetAndAnchor(*_) >> { throw new Exception('some exception') }
+ 1 * mockModuleSyncService.syncAndCreateOrUpgradeSchemaSetAndAnchor(*_) >> { throw new Exception('some exception') }
when: 'module sync is executed'
objectUnderTest.performModuleSync([cmHandle], batchCount)
then: 'update lock reason, details and attempts is invoked'
@@ -112,7 +112,7 @@
moduleSyncStartedOnCmHandles.put('cm-handle-1', 'started')
moduleSyncStartedOnCmHandles.put('cm-handle-2', 'started')
and: 'sync utils retry locked cm handle returns #isReadyForRetry'
- mockSyncUtils.needsModuleSyncRetry(lockedState) >>> isReadyForRetry
+ mockSyncUtils.needsModuleSyncRetryOrUpgrade(lockedState) >>> isReadyForRetry
when: 'resetting failed cm handles'
objectUnderTest.resetFailedCmHandles([yangModelCmHandle1, yangModelCmHandle2])
then: 'updated to state "ADVISED" from "READY" is called as often as there are cm handles ready for retry'
@@ -135,7 +135,7 @@
when: 'module sync poll is executed'
objectUnderTest.performModuleSync([cmHandle1], batchCount)
then: 'module sync service is invoked for cm handle'
- 1 * mockModuleSyncService.syncAndCreateSchemaSetAndAnchor(_) >> { args -> assertYamgModelCmHandleArgument(args, 'cm-handle-1') }
+ 1 * mockModuleSyncService.syncAndCreateOrUpgradeSchemaSetAndAnchor(_) >> { args -> assertYamgModelCmHandleArgument(args, 'cm-handle-1') }
and: 'the entry for other cm handle is still in the progress map'
assert moduleSyncStartedOnCmHandles.get('other-cm-handle') != null
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdogSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdogSpec.groovy
index d85686a..390e88b 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdogSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdogSpec.groovy
@@ -111,7 +111,7 @@
def 'Reset failed cm handles.'() {
given: 'sync utilities returns failed cm handles'
def failedCmHandles = [new YangModelCmHandle()]
- mockSyncUtils.getModuleSyncFailedCmHandles() >> failedCmHandles
+ mockSyncUtils.getCmHandlesThatFailedModelSyncOrUpgrade() >> failedCmHandles
when: 'reset failed cm handles is started'
objectUnderTest.resetPreviouslyFailedCmHandles()
then: 'it is delegated to the module sync task (service)'
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy
index 8fdbb6f..00d14cd 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy
@@ -115,11 +115,11 @@
def 'Get all locked Cm-Handle where Lock Reason is MODULE_SYNC_FAILED cm handle #scenario'() {
given: 'the cps (persistence service) returns a collection of data nodes'
- mockCmHandleQueries.queryCmHandleDataNodesByCpsPath(
- '//lock-reason[@reason="MODULE_SYNC_FAILED"]',
+ mockCmHandleQueries.queryCmHandleAncestorsByCpsPath(
+ '//lock-reason[@reason="MODULE_SYNC_FAILED" or @reason="MODULE_UPGRADE"]',
FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> [dataNode]
when: 'get locked Misbehaving cm handle is called'
- def result = objectUnderTest.getModuleSyncFailedCmHandles()
+ def result = objectUnderTest.getCmHandlesThatFailedModelSyncOrUpgrade()
then: 'the returned cm handle collection is the correct size'
result.size() == 1
and: 'the correct cm handle is returned'
@@ -133,7 +133,7 @@
lastUpdatedTime = neverUpdatedBefore
}
when: 'checking to see if cm handle is ready for retry'
- def result = objectUnderTest.needsModuleSyncRetry(new CompositeStateBuilder()
+ def result = objectUnderTest.needsModuleSyncRetryOrUpgrade(new CompositeStateBuilder()
.withLockReason(MODULE_SYNC_FAILED, lockDetails)
.withLastUpdatedTime(lastUpdatedTime).build())
then: 'retry is only attempted when expected'
@@ -151,16 +151,18 @@
def 'Retry Locked Cm-Handle with other lock reasons (category) #lockReasonCategory'() {
when: 'checking to see if cm handle is ready for retry'
- def result = objectUnderTest.needsModuleSyncRetry(new CompositeStateBuilder()
+ def result = objectUnderTest.needsModuleSyncRetryOrUpgrade(new CompositeStateBuilder()
.withLockReason(lockReasonCategory, 'some details')
.withLastUpdatedTime(nowAsString).build())
- then: 'retry attempt is never triggered'
- assert result == false
+ then: 'verify retry attempts'
+ assert result == retryAttempt
and: 'logs contain related information'
- def logs = loggingListAppender.list.toString()
- assert logs.contains('Locked for other reason')
+ def logs = loggingListAppender.list.toString()
+ assert logs.contains(logReason)
where: 'the following lock reasons occurred'
- lockReasonCategory << [MODULE_UPGRADE, MODULE_UPGRADE_FAILED]
+ scenario | lockReasonCategory || logReason | retryAttempt
+ 'module upgrade' | MODULE_UPGRADE || 'Locked for module upgrade.' | true
+ 'module sync failed' | MODULE_SYNC_FAILED || 'First Attempt:' | false
}
def 'Get a Cm-Handle where #scenario'() {
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java
index ca88a4d..0d77530 100755
--- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java
@@ -46,7 +46,6 @@
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.hibernate.exception.ConstraintViolationException;
-import org.onap.cps.spi.CpsAdminPersistenceService;
import org.onap.cps.spi.CpsModulePersistenceService;
import org.onap.cps.spi.entities.DataspaceEntity;
import org.onap.cps.spi.entities.SchemaSetEntity;
@@ -89,8 +88,6 @@
private final DataspaceRepository dataspaceRepository;
- private final CpsAdminPersistenceService cpsAdminPersistenceService;
-
private final ModuleReferenceRepository moduleReferenceRepository;
@Override
diff --git a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsModulePersistenceServiceSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsModulePersistenceServiceSpec.groovy
index 52651c6..9696b28 100644
--- a/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsModulePersistenceServiceSpec.groovy
+++ b/cps-ri/src/test/groovy/org/onap/cps/spi/impl/CpsModulePersistenceServiceSpec.groovy
@@ -69,7 +69,7 @@
def setup() {
objectUnderTest = new CpsModulePersistenceServiceImpl(yangResourceRepositoryMock, schemaSetRepositoryMock,
- dataspaceRepositoryMock, cpsAdminPersistenceServiceMock, moduleReferenceRepositoryMock)
+ dataspaceRepositoryMock, moduleReferenceRepositoryMock)
}
def 'Store schema set error scenario: #scenario.'() {
diff --git a/cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java b/cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java
index 5ff08c9..e8c3e77 100644
--- a/cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java
+++ b/cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java
@@ -47,13 +47,13 @@
Map<String, String> yangResourcesNameToContentMap);
/**
- * Create a schema set from new modules and existing modules.
+ * Create or upgrade a schema set from new modules and existing modules or only existing modules.
* @param dataspaceName Dataspace name
* @param schemaSetName schema set name
* @param newModuleNameToContentMap YANG resources map where key is a module name and value is content
* @param allModuleReferences All YANG resource module references
*/
- void createSchemaSetFromModules(String dataspaceName, String schemaSetName,
+ void createOrUpgradeSchemaSetFromModules(String dataspaceName, String schemaSetName,
Map<String, String> newModuleNameToContentMap,
Collection<ModuleReference> allModuleReferences);
diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java
index 7d9c472..444c895 100644
--- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java
+++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java
@@ -66,7 +66,7 @@
}
@Override
- public void createSchemaSetFromModules(final String dataspaceName, final String schemaSetName,
+ public void createOrUpgradeSchemaSetFromModules(final String dataspaceName, final String schemaSetName,
final Map<String, String> newModuleNameToContentMap,
final Collection<ModuleReference> allModuleReferences) {
cpsValidator.validateNameCharacters(dataspaceName, schemaSetName);
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy
index a794c58..61f6741 100644
--- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy
@@ -65,7 +65,7 @@
def moduleReferenceForExistingModule = new ModuleReference('test', '2021-10-12','test.org')
def listOfExistingModulesModuleReference = [moduleReferenceForExistingModule]
when: 'create schema set from modules method is invoked'
- objectUnderTest.createSchemaSetFromModules('someDataspaceName', 'someSchemaSetName', [newModule: 'newContent'], listOfExistingModulesModuleReference)
+ objectUnderTest.createOrUpgradeSchemaSetFromModules('someDataspaceName', 'someSchemaSetName', [newModule: 'newContent'], listOfExistingModulesModuleReference)
then: 'processing is delegated to persistence service'
1 * mockCpsModulePersistenceService.storeSchemaSetFromModules('someDataspaceName', 'someSchemaSetName', [newModule: 'newContent'], listOfExistingModulesModuleReference)
and: 'the CpsValidator is called on the dataspaceName and schemaSetName'
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/base/TestConfig.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/base/TestConfig.groovy
index e39e114..f4cc8b7 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/base/TestConfig.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/base/TestConfig.groovy
@@ -90,7 +90,7 @@
@Bean
CpsModulePersistenceService cpsModulePersistenceService() {
- return (CpsModulePersistenceService) new CpsModulePersistenceServiceImpl(yangResourceRepository, schemaSetRepository, dataspaceRepository, cpsAdminPersistenceService(), moduleReferenceRepository)
+ return (CpsModulePersistenceService) new CpsModulePersistenceServiceImpl(yangResourceRepository, schemaSetRepository, dataspaceRepository, moduleReferenceRepository)
}
@Bean
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsModuleServiceIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsModuleServiceIntegrationSpec.groovy
index cfc8ab7..d33a774 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsModuleServiceIntegrationSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsModuleServiceIntegrationSpec.groovy
@@ -94,7 +94,7 @@
moduleReferences.addAll(existingModuleReferences)
when: 'the new schema set is created'
def schemaSetName = "NewSchemaWith${numberOfNewModules}Modules"
- objectUnderTest.createSchemaSetFromModules(FUNCTIONAL_TEST_DATASPACE_1, schemaSetName, newYangResourcesNameToContentMap, moduleReferences)
+ objectUnderTest.createOrUpgradeSchemaSetFromModules(FUNCTIONAL_TEST_DATASPACE_1, schemaSetName, newYangResourcesNameToContentMap, moduleReferences)
and: 'associated with a new anchor'
cpsAdminService.createAnchor(FUNCTIONAL_TEST_DATASPACE_1, schemaSetName, 'newAnchor')
then: 'the new anchor has the correct number of modules'