diff options
85 files changed, 727 insertions, 821 deletions
diff --git a/cps-application/pom.xml b/cps-application/pom.xml index 5ac2202e85..1a46b5fa8a 100644 --- a/cps-application/pom.xml +++ b/cps-application/pom.xml @@ -78,6 +78,10 @@ <artifactId>micrometer-tracing-bridge-otel</artifactId> </dependency> <dependency> + <groupId>io.github.mweirauch</groupId> + <artifactId>micrometer-jvm-extras</artifactId> + </dependency> + <dependency> <groupId>com.fasterxml.jackson.dataformat</groupId> <artifactId>jackson-dataformat-xml</artifactId> </dependency> diff --git a/cps-application/src/main/java/org/onap/cps/Application.java b/cps-application/src/main/java/org/onap/cps/Application.java index 053139fcc8..62103bf368 100644 --- a/cps-application/src/main/java/org/onap/cps/Application.java +++ b/cps-application/src/main/java/org/onap/cps/Application.java @@ -22,9 +22,7 @@ package org.onap.cps; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
-import org.springframework.retry.annotation.EnableRetry;
-@EnableRetry
@SpringBootApplication
public class Application {
public static void main(final String[] args) {
diff --git a/cps-application/src/main/java/org/onap/cps/config/MicroMeterConfig.java b/cps-application/src/main/java/org/onap/cps/config/MicroMeterConfig.java index de981164f5..b85f391b8e 100644 --- a/cps-application/src/main/java/org/onap/cps/config/MicroMeterConfig.java +++ b/cps-application/src/main/java/org/onap/cps/config/MicroMeterConfig.java @@ -21,10 +21,14 @@ package org.onap.cps.config; import com.hazelcast.map.IMap; +import io.github.mweirauch.micrometer.jvm.extras.ProcessMemoryMetrics; +import io.github.mweirauch.micrometer.jvm.extras.ProcessThreadMetrics; import io.micrometer.core.aop.TimedAspect; import io.micrometer.core.instrument.Gauge; import io.micrometer.core.instrument.MeterRegistry; +import io.micrometer.core.instrument.binder.MeterBinder; import lombok.RequiredArgsConstructor; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -41,6 +45,18 @@ public class MicroMeterConfig { return new TimedAspect(meterRegistry); } + @Bean + @ConditionalOnProperty("cps.monitoring.micrometer-jvm-extras") + public MeterBinder processMemoryMetrics() { + return new ProcessMemoryMetrics(); + } + + @Bean + @ConditionalOnProperty("cps.monitoring.micrometer-jvm-extras") + public MeterBinder processThreadMetrics() { + return new ProcessThreadMetrics(); + } + /** * Register gauge metric for cm handles with state 'advised'. * @@ -52,7 +68,7 @@ public class MicroMeterConfig { return Gauge.builder(CM_HANDLE_STATE_GAUGE, cmHandlesByState, value -> cmHandlesByState.get("advisedCmHandlesCount")) .tag(STATE_TAG, "ADVISED") - .description("Current number of cmhandles in advised state") + .description("Current number of cm handles in advised state") .register(meterRegistry); } @@ -67,7 +83,7 @@ public class MicroMeterConfig { return Gauge.builder(CM_HANDLE_STATE_GAUGE, cmHandlesByState, value -> cmHandlesByState.get("readyCmHandlesCount")) .tag(STATE_TAG, "READY") - .description("Current number of cmhandles in ready state") + .description("Current number of cm handles in ready state") .register(meterRegistry); } @@ -82,7 +98,7 @@ public class MicroMeterConfig { return Gauge.builder(CM_HANDLE_STATE_GAUGE, cmHandlesByState, value -> cmHandlesByState.get("lockedCmHandlesCount")) .tag(STATE_TAG, "LOCKED") - .description("Current number of cmhandles in locked state") + .description("Current number of cm handles in locked state") .register(meterRegistry); } @@ -97,7 +113,22 @@ public class MicroMeterConfig { return Gauge.builder(CM_HANDLE_STATE_GAUGE, cmHandlesByState, value -> cmHandlesByState.get("deletingCmHandlesCount")) .tag(STATE_TAG, "DELETING") - .description("Current number of cmhandles in deleting state") + .description("Current number of cm handles in deleting state") + .register(meterRegistry); + } + + /** + * Register gauge metric for cm handles with state 'deleted'. + * + * @param meterRegistry meter registry + * @return cm handle state gauge + */ + @Bean + public Gauge deletedCmHandles(final MeterRegistry meterRegistry) { + return Gauge.builder(CM_HANDLE_STATE_GAUGE, cmHandlesByState, + value -> cmHandlesByState.get("deletedCmHandlesCount")) + .tag(STATE_TAG, "DELETED") + .description("Number of cm handles that have been deleted since the application started") .register(meterRegistry); } diff --git a/cps-application/src/main/resources/application.yml b/cps-application/src/main/resources/application.yml index 0b5d59ecc9..6b9c694cf2 100644 --- a/cps-application/src/main/resources/application.yml +++ b/cps-application/src/main/resources/application.yml @@ -152,6 +152,8 @@ security: password: ${CPS_PASSWORD:cpsr0cks!} cps: + monitoring: + micrometer-jvm-extras: false tracing: sampler: jaeger_remote: diff --git a/cps-application/src/test/groovy/org/onap/cps/config/MicroMeterConfigSpec.groovy b/cps-application/src/test/groovy/org/onap/cps/config/MicroMeterConfigSpec.groovy index da3afc6f2c..b9302ccd72 100644 --- a/cps-application/src/test/groovy/org/onap/cps/config/MicroMeterConfigSpec.groovy +++ b/cps-application/src/test/groovy/org/onap/cps/config/MicroMeterConfigSpec.groovy @@ -31,10 +31,17 @@ class MicroMeterConfigSpec extends Specification { def simpleMeterRegistry = new SimpleMeterRegistry() def 'Creating a timed aspect.'() { - expect: ' a timed aspect can be created' + expect: 'a timed aspect can be created' assert objectUnderTest.timedAspect(simpleMeterRegistry) != null } + def 'Creating JVM process metrics.'() { + expect: 'process memory metrics can be created' + assert objectUnderTest.processMemoryMetrics() != null + and: 'process thread metrics can be created' + assert objectUnderTest.processThreadMetrics() != null + } + def 'Creating gauges for cm handle states.'() { given: 'cache returns value for each state' cmHandlesByState.get(_) >> 1 @@ -43,10 +50,10 @@ class MicroMeterConfigSpec extends Specification { objectUnderTest.readyCmHandles(simpleMeterRegistry) objectUnderTest.lockedCmHandles(simpleMeterRegistry) objectUnderTest.deletingCmHandles(simpleMeterRegistry) + objectUnderTest.deletedCmHandles(simpleMeterRegistry) then: 'each state has the correct value when queried' - def states = ["ADVISED", "READY", "LOCKED", "DELETING"] - states.each { state -> - def gaugeValue = simpleMeterRegistry.get("cmHandlesByState").tag("state",state).gauge().value() + ['ADVISED', 'READY', 'LOCKED', 'DELETING', 'DELETED'].each { state -> + def gaugeValue = simpleMeterRegistry.get('cmHandlesByState').tag('state',state).gauge().value() assert gaugeValue == 1 } } diff --git a/cps-application/src/test/java/org/onap/cps/architecture/ArchitectureTestBase.java b/cps-application/src/test/java/org/onap/cps/architecture/ArchitectureTestBase.java index 1d39060024..c1d65758c7 100644 --- a/cps-application/src/test/java/org/onap/cps/architecture/ArchitectureTestBase.java +++ b/cps-application/src/test/java/org/onap/cps/architecture/ArchitectureTestBase.java @@ -36,6 +36,7 @@ public class ArchitectureTestBase { "lombok..", "org.apache..", "org.mapstruct..", + "org.opendaylight..", "org.slf4j..", "org.springframework..", "reactor.." diff --git a/cps-dependencies/pom.xml b/cps-dependencies/pom.xml index 5783ef7fcd..62fa154611 100644 --- a/cps-dependencies/pom.xml +++ b/cps-dependencies/pom.xml @@ -146,7 +146,7 @@ <dependency> <groupId>com.hazelcast</groupId> <artifactId>hazelcast-spring</artifactId> - <version>5.3.7</version> + <version>5.5.0</version> </dependency> <dependency> <groupId>com.squareup.okhttp3</groupId> @@ -173,6 +173,11 @@ <scope>import</scope> </dependency> <dependency> + <groupId>io.github.mweirauch</groupId> + <artifactId>micrometer-jvm-extras</artifactId> + <version>0.2.2</version> + </dependency> + <dependency> <groupId>io.gsonfire</groupId> <artifactId>gson-fire</artifactId> <version>1.9.0</version> diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cache/HazelcastCacheConfig.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cache/HazelcastCacheConfig.java index 75007e2e35..5a6e1ce269 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cache/HazelcastCacheConfig.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cache/HazelcastCacheConfig.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================== - * Copyright (C) 2023-2024 Nordix Foundation + * Copyright (C) 2023-2025 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -130,6 +130,10 @@ public class HazelcastCacheConfig { } } + /*Note: Need to keep this for the meantime as Hazelcast community version 5.5 has marked RestApiConfig + for removal in future version and we have clients relying on these endpoints. + https://lf-onap.atlassian.net/browse/CPS-2599 created to address the issue. */ + @SuppressWarnings("squid:S5738") protected void exposeClusterInformation(final Config config) { config.getNetworkConfig().getRestApiConfig().setEnabled(true) .enableGroups(RestEndpointGroup.HEALTH_CHECK, RestEndpointGroup.CLUSTER_READ); diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImpl.java index 59d0f9704e..ae913ddfe7 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImpl.java @@ -38,7 +38,6 @@ import org.onap.cps.api.CpsQueryService; import org.onap.cps.api.model.DataNode; import org.onap.cps.api.parameters.FetchDescendantsOption; import org.onap.cps.cpspath.parser.CpsPathUtil; -import org.onap.cps.impl.utils.CpsValidator; import org.onap.cps.ncmp.api.inventory.DataStoreSyncState; import org.onap.cps.ncmp.api.inventory.models.CmHandleState; import org.onap.cps.ncmp.api.inventory.models.TrustLevel; @@ -46,6 +45,7 @@ import org.onap.cps.ncmp.impl.inventory.models.ModelledDmiServiceLeaves; import org.onap.cps.ncmp.impl.inventory.models.PropertyType; import org.onap.cps.ncmp.impl.inventory.trustlevel.TrustLevelCacheConfig; import org.onap.cps.ncmp.impl.utils.YangDataConverter; +import org.onap.cps.utils.CpsValidator; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationService.java index e7fd247a08..75c52f3c60 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationService.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationService.java @@ -23,7 +23,6 @@ package org.onap.cps.ncmp.impl.inventory; -import static org.onap.cps.ncmp.api.NcmpResponseStatus.ALTERNATE_ID_ALREADY_ASSOCIATED; 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; @@ -347,7 +346,7 @@ public class CmHandleRegistrationService { final Collection<String> rejectedCmHandleIds = alternateIdChecker .getIdsOfCmHandlesWithRejectedAlternateId(cmHandlesToBeCreated, AlternateIdChecker.Operation.CREATE); cmHandleRegistrationResponses.addAll(CmHandleRegistrationResponse.createFailureResponses( - rejectedCmHandleIds, ALTERNATE_ID_ALREADY_ASSOCIATED)); + rejectedCmHandleIds, CM_HANDLE_ALREADY_EXIST)); return rejectedCmHandleIds; } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServicePropertyHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServicePropertyHandler.java index b7a13d9989..3415793478 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServicePropertyHandler.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServicePropertyHandler.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2022-2024 Nordix Foundation + * Copyright (C) 2022-2025 Nordix Foundation * Modifications Copyright (C) 2022 Bell Canada * Modifications Copyright (C) 2024 TechMahindra Ltd. * ================================================================================ @@ -22,8 +22,8 @@ package org.onap.cps.ncmp.impl.inventory; -import static org.onap.cps.ncmp.api.NcmpResponseStatus.ALTERNATE_ID_ALREADY_ASSOCIATED; import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLES_NOT_FOUND; +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.impl.inventory.CmHandleRegistrationServicePropertyHandler.PropertyType.DMI_PROPERTY; import static org.onap.cps.ncmp.impl.inventory.CmHandleRegistrationServicePropertyHandler.PropertyType.PUBLIC_PROPERTY; @@ -49,7 +49,7 @@ import org.onap.cps.api.CpsDataService; import org.onap.cps.api.exceptions.DataNodeNotFoundException; import org.onap.cps.api.exceptions.DataValidationException; import org.onap.cps.api.model.DataNode; -import org.onap.cps.api.model.DataNodeBuilder; +import org.onap.cps.impl.DataNodeBuilder; import org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse; import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle; import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; @@ -81,7 +81,7 @@ public class CmHandleRegistrationServicePropertyHandler { final Collection<String> rejectedCmHandleIds = alternateIdChecker .getIdsOfCmHandlesWithRejectedAlternateId(updatedNcmpServiceCmHandles, AlternateIdChecker.Operation.UPDATE); final List<CmHandleRegistrationResponse> failureResponses = - CmHandleRegistrationResponse.createFailureResponses(rejectedCmHandleIds, ALTERNATE_ID_ALREADY_ASSOCIATED); + CmHandleRegistrationResponse.createFailureResponses(rejectedCmHandleIds, CM_HANDLE_ALREADY_EXIST); final List<CmHandleRegistrationResponse> cmHandleRegistrationResponses = new ArrayList<>(failureResponses); for (final NcmpServiceCmHandle updatedNcmpServiceCmHandle : updatedNcmpServiceCmHandles) { final String cmHandleId = updatedNcmpServiceCmHandle.getCmHandleId(); diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImpl.java index e7ec9cd13c..e145c62921 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImpl.java @@ -45,13 +45,13 @@ import org.onap.cps.api.model.DataNode; import org.onap.cps.api.model.ModuleDefinition; import org.onap.cps.api.model.ModuleReference; import org.onap.cps.api.parameters.FetchDescendantsOption; -import org.onap.cps.impl.utils.CpsValidator; import org.onap.cps.ncmp.api.exceptions.CmHandleNotFoundException; import org.onap.cps.ncmp.api.inventory.models.CompositeState; import org.onap.cps.ncmp.api.inventory.models.CompositeStateBuilder; import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; import org.onap.cps.ncmp.impl.utils.YangDataConverter; import org.onap.cps.utils.ContentType; +import org.onap.cps.utils.CpsValidator; import org.onap.cps.utils.JsonObjectMapper; import org.springframework.stereotype.Component; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/DmiModelOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/DmiModelOperations.java index 1e24671f8d..2cc4375447 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/DmiModelOperations.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/DmiModelOperations.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2021-2024 Nordix Foundation + * Copyright (C) 2021-2025 Nordix Foundation * Modifications Copyright (C) 2022 Bell Canada * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -61,13 +61,14 @@ public class DmiModelOperations { * Retrieves module references. * * @param yangModelCmHandle the yang model cm handle + * @param targetModuleSetTag module set tag to send to dmi * @return module references */ @Timed(value = "cps.ncmp.inventory.module.references.from.dmi", description = "Time taken to get all module references for a cm handle from dmi") - public List<ModuleReference> getModuleReferences(final YangModelCmHandle yangModelCmHandle) { - final DmiRequestBody dmiRequestBody = DmiRequestBody.builder() - .moduleSetTag(yangModelCmHandle.getModuleSetTag()).build(); + public List<ModuleReference> getModuleReferences(final YangModelCmHandle yangModelCmHandle, + final String targetModuleSetTag) { + final DmiRequestBody dmiRequestBody = DmiRequestBody.builder().moduleSetTag(targetModuleSetTag).build(); dmiRequestBody.asDmiProperties(yangModelCmHandle.getDmiProperties()); final ResponseEntity<Object> dmiFetchModulesResponseEntity = getResourceFromDmiWithJsonData( yangModelCmHandle.resolveDmiServiceName(MODEL), @@ -79,18 +80,20 @@ public class DmiModelOperations { * Retrieve yang resources from dmi for any modules that CPS-NCMP hasn't cached before. * * @param yangModelCmHandle the yangModelCmHandle + * @param targetModuleSetTag module set tag to send to dmi * @param newModuleReferences the unknown module references * @return yang resources as map of module name to yang(re)source */ @Timed(value = "cps.ncmp.inventory.yang.resources.from.dmi", description = "Time taken to get list of yang resources from dmi") public Map<String, String> getNewYangResourcesFromDmi(final YangModelCmHandle yangModelCmHandle, + final String targetModuleSetTag, final Collection<ModuleReference> newModuleReferences) { if (newModuleReferences.isEmpty()) { return Collections.emptyMap(); } final String jsonWithDataAndDmiProperties = getRequestBodyToFetchYangResources(newModuleReferences, - yangModelCmHandle.getDmiProperties(), yangModelCmHandle.getModuleSetTag()); + yangModelCmHandle.getDmiProperties(), targetModuleSetTag); final ResponseEntity<Object> responseEntity = getResourceFromDmiWithJsonData( yangModelCmHandle.resolveDmiServiceName(MODEL), jsonWithDataAndDmiProperties, @@ -123,13 +126,13 @@ public class DmiModelOperations { private static String getRequestBodyToFetchYangResources(final Collection<ModuleReference> newModuleReferences, final List<YangModelCmHandle.Property> dmiProperties, - final String moduleSetTag) { + final String targetModuleSetTag) { final JsonArray moduleReferencesAsJson = getModuleReferencesAsJson(newModuleReferences); final JsonObject data = new JsonObject(); data.add("modules", moduleReferencesAsJson); final JsonObject jsonRequestObject = new JsonObject(); - if (!moduleSetTag.isEmpty()) { - jsonRequestObject.addProperty("moduleSetTag", moduleSetTag); + if (!targetModuleSetTag.isEmpty()) { + jsonRequestObject.addProperty("moduleSetTag", targetModuleSetTag); } jsonRequestObject.add("data", data); jsonRequestObject.add("cmHandleProperties", toJsonObject(dmiProperties)); diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleOperationsUtils.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleOperationsUtils.java index e9f3d9b475..80e41652ee 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleOperationsUtils.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleOperationsUtils.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2022-2024 Nordix Foundation + * Copyright (C) 2022-2025 Nordix Foundation * Modifications Copyright (C) 2022 Bell Canada * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -189,7 +189,12 @@ public class ModuleOperationsUtils { .getLockReasonCategory())); } - public static String getTargetModuleSetTagFromLockReason(final CompositeState.LockReason lockReason) { + public static String getTargetModuleSetTagForUpgrade(final YangModelCmHandle yangModelCmHandle) { + final CompositeState.LockReason lockReason = yangModelCmHandle.getCompositeState().getLockReason(); + return getTargetModuleSetTagFromLockReason(lockReason); + } + + private static String getTargetModuleSetTagFromLockReason(final CompositeState.LockReason lockReason) { return getLockedCompositeStateDetails(lockReason).getOrDefault(MODULE_SET_TAG_KEY, ""); } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncService.java index 9534cf35b1..f929d6708c 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncService.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncService.java @@ -36,7 +36,6 @@ import org.onap.cps.api.CpsAnchorService; import org.onap.cps.api.CpsDataService; import org.onap.cps.api.CpsModuleService; import org.onap.cps.api.exceptions.AlreadyDefinedException; -import org.onap.cps.api.exceptions.DuplicatedYangResourceException; import org.onap.cps.api.model.ModuleReference; import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; import org.onap.cps.utils.ContentType; @@ -67,10 +66,15 @@ public class ModuleSyncService { */ public void syncAndCreateSchemaSetAndAnchor(final YangModelCmHandle yangModelCmHandle) { final String cmHandleId = yangModelCmHandle.getId(); - final String moduleSetTag = yangModelCmHandle.getModuleSetTag(); - final String schemaSetName = getSchemaSetName(cmHandleId, moduleSetTag); - syncAndCreateSchemaSet(yangModelCmHandle, schemaSetName); - cpsAnchorService.createAnchor(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, schemaSetName, cmHandleId); + final String targetModuleSetTag = yangModelCmHandle.getModuleSetTag(); + final String schemaSetName = getSchemaSetNameForModuleSetTag(cmHandleId, targetModuleSetTag); + syncAndCreateSchemaSet(yangModelCmHandle, schemaSetName, targetModuleSetTag); + try { + cpsAnchorService.createAnchor(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, schemaSetName, cmHandleId); + } catch (final AlreadyDefinedException alreadyDefinedException) { + log.warn("Ignoring (Anchor) already exists exception for {}. Exception details: {}", cmHandleId, + alreadyDefinedException.getDetails()); + } } /** @@ -81,39 +85,40 @@ public class ModuleSyncService { public void syncAndUpgradeSchemaSet(final YangModelCmHandle yangModelCmHandle) { final String cmHandleId = yangModelCmHandle.getId(); final String sourceModuleSetTag = yangModelCmHandle.getModuleSetTag(); - final String targetModuleSetTag = ModuleOperationsUtils.getTargetModuleSetTagFromLockReason( - yangModelCmHandle.getCompositeState().getLockReason()); + final String targetModuleSetTag = ModuleOperationsUtils.getTargetModuleSetTagForUpgrade(yangModelCmHandle); + final String schemaSetName = getSchemaSetNameForModuleSetTag(cmHandleId, targetModuleSetTag); if (sourceModuleSetTag.isEmpty() && targetModuleSetTag.isEmpty()) { - final ModuleDelta moduleDelta = getModuleDelta(yangModelCmHandle); + final ModuleDelta moduleDelta = getModuleDelta(yangModelCmHandle, targetModuleSetTag); cpsModuleService.upgradeSchemaSetFromModules(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, - cmHandleId, moduleDelta.newModuleNameToContentMap, moduleDelta.allModuleReferences); + schemaSetName, moduleDelta.newModuleNameToContentMap, moduleDelta.allModuleReferences); } else { - final String targetSchemaSetName = getSchemaSetName(cmHandleId, targetModuleSetTag); - syncAndCreateSchemaSet(yangModelCmHandle, targetSchemaSetName); - cpsAnchorService.updateAnchorSchemaSet(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandleId, - targetSchemaSetName); + syncAndCreateSchemaSet(yangModelCmHandle, schemaSetName, targetModuleSetTag); + cpsAnchorService.updateAnchorSchemaSet(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandleId, schemaSetName); setCmHandleModuleSetTag(yangModelCmHandle, targetModuleSetTag); log.info("Upgrading schema set for CM handle ID: {}, Source Tag: {}, Target Tag: {}", cmHandleId, sourceModuleSetTag, targetModuleSetTag); } } - private void syncAndCreateSchemaSet(final YangModelCmHandle yangModelCmHandle, final String schemaSetName) { + private void syncAndCreateSchemaSet(final YangModelCmHandle yangModelCmHandle, + final String schemaSetName, + final String targetModuleSetTag) { if (isNewSchemaSet(schemaSetName)) { - final ModuleDelta moduleDelta = getModuleDelta(yangModelCmHandle); + final String cmHandleId = yangModelCmHandle.getId(); + final ModuleDelta moduleDelta = getModuleDelta(yangModelCmHandle, targetModuleSetTag); try { - log.info("Creating Schema Set {} for CM Handle {}", schemaSetName, yangModelCmHandle.getId()); + log.info("Creating Schema Set {} for CM Handle {}", schemaSetName, cmHandleId); cpsModuleService.createSchemaSetFromModules( - NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, - schemaSetName, - moduleDelta.newModuleNameToContentMap, - moduleDelta.allModuleReferences + NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, + schemaSetName, + moduleDelta.newModuleNameToContentMap, + moduleDelta.allModuleReferences ); - log.info("Successfully created Schema Set {} for CM Handle {}", - schemaSetName, yangModelCmHandle.getId()); - } catch (final AlreadyDefinedException | DuplicatedYangResourceException exception) { - log.warn("Schema Set {} already exists, no need to (re)create it for {}", - schemaSetName, yangModelCmHandle.getId()); + log.info("Successfully created Schema Set {} for CM Handle {}", schemaSetName, + yangModelCmHandle.getId()); + } catch (final AlreadyDefinedException alreadyDefinedException) { + log.warn("Ignoring (Schema Set) already exists exception for {}. Exception details: {}", cmHandleId, + alreadyDefinedException.getDetails()); } } } @@ -122,13 +127,14 @@ public class ModuleSyncService { return !cpsModuleService.schemaSetExists(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, schemaSetName); } - private ModuleDelta getModuleDelta(final YangModelCmHandle yangModelCmHandle) { + private ModuleDelta getModuleDelta(final YangModelCmHandle yangModelCmHandle, + final String targetModuleSetTag) { final Collection<ModuleReference> allModuleReferences = - dmiModelOperations.getModuleReferences(yangModelCmHandle); + dmiModelOperations.getModuleReferences(yangModelCmHandle, targetModuleSetTag); final Collection<ModuleReference> newModuleReferences = cpsModuleService.identifyNewModuleReferences(allModuleReferences); final Map<String, String> newYangResources = dmiModelOperations.getNewYangResourcesFromDmi(yangModelCmHandle, - newModuleReferences); + targetModuleSetTag, newModuleReferences); log.debug("Module delta calculated for CM handle ID: {}. All references: {}. New modules: {}", yangModelCmHandle.getId(), allModuleReferences, newYangResources.keySet()); return new ModuleDelta(allModuleReferences, newYangResources); @@ -141,7 +147,7 @@ public class ModuleSyncService { jsonForUpdate, OffsetDateTime.now(), ContentType.JSON); } - private static String getSchemaSetName(final String cmHandleId, final String moduleSetTag) { + private static String getSchemaSetNameForModuleSetTag(final String cmHandleId, final String moduleSetTag) { return moduleSetTag.isEmpty() ? cmHandleId : moduleSetTag; } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasks.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasks.java index 40404b719a..f039cf3c02 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasks.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasks.java @@ -114,7 +114,7 @@ public class ModuleSyncTasks { compositeState.setLockReason(null); return CmHandleState.READY; } catch (final Exception e) { - log.warn("Processing of {} failed,reason : {}.", yangModelCmHandle.getId(), e.getMessage()); + log.warn("Processing of {} failed, reason: {}.", yangModelCmHandle.getId(), e.getMessage()); final LockReasonCategory lockReasonCategory = inUpgrade ? LockReasonCategory.MODULE_UPGRADE_FAILED : LockReasonCategory.MODULE_SYNC_FAILED; diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/models/CmHandleRegistrationResponseSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/models/CmHandleRegistrationResponseSpec.groovy index 055a6e7448..c49af0f01b 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/models/CmHandleRegistrationResponseSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/models/CmHandleRegistrationResponseSpec.groovy @@ -1,7 +1,7 @@ /* * ============LICENSE_START======================================================= * Copyright (C) 2022 Bell Canada - * Modifications Copyright (C) 2023-2024 Nordix Foundation + * Modifications Copyright (C) 2023-2025 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,7 +26,6 @@ import spock.lang.Specification import java.util.stream.Collectors -import static org.onap.cps.ncmp.api.NcmpResponseStatus.ALTERNATE_ID_ALREADY_ASSOCIATED import static org.onap.cps.ncmp.api.NcmpResponseStatus.CM_HANDLE_ALREADY_EXIST import static org.onap.cps.ncmp.api.NcmpResponseStatus.UNKNOWN_ERROR @@ -89,14 +88,14 @@ class CmHandleRegistrationResponseSpec extends Specification { } def 'Failed cm-handle registration based on cm handle id and registration error'() { - when: 'the failure response is created with "alternate id already associated" error code for 1 cm handle' + when: 'the failure response is created with "cm-handle already exists" error code for 1 cm handle' def cmHandleRegistrationResponses = - CmHandleRegistrationResponse.createFailureResponses(['ch 1'], ALTERNATE_ID_ALREADY_ASSOCIATED) + CmHandleRegistrationResponse.createFailureResponses(['ch 1'], CM_HANDLE_ALREADY_EXIST) then: 'the response with expected values' assert cmHandleRegistrationResponses[0].cmHandle == 'ch 1' assert cmHandleRegistrationResponses[0].status == Status.FAILURE - assert cmHandleRegistrationResponses[0].ncmpResponseStatus == ALTERNATE_ID_ALREADY_ASSOCIATED - assert cmHandleRegistrationResponses[0].errorText == 'alternate id already associated' + assert cmHandleRegistrationResponses[0].ncmpResponseStatus == CM_HANDLE_ALREADY_EXIST + assert cmHandleRegistrationResponses[0].errorText == 'cm-handle already exists' } } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/models/CompositeStateBuilderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/models/CompositeStateBuilderSpec.groovy index 4d42e62025..8b04568239 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/models/CompositeStateBuilderSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/models/CompositeStateBuilderSpec.groovy @@ -24,7 +24,7 @@ package org.onap.cps.ncmp.api.inventory.models import org.onap.cps.ncmp.api.inventory.DataStoreSyncState import org.onap.cps.api.model.DataNode -import org.onap.cps.api.model.DataNodeBuilder +import org.onap.cps.impl.DataNodeBuilder import spock.lang.Specification import java.time.OffsetDateTime diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImplSpec.groovy index 811e4ea526..1cbdc7beca 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImplSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImplSpec.groovy @@ -26,7 +26,7 @@ import com.hazelcast.core.Hazelcast import com.hazelcast.instance.impl.HazelcastInstanceFactory import org.onap.cps.api.CpsDataService import org.onap.cps.api.CpsQueryService -import org.onap.cps.impl.utils.CpsValidator +import org.onap.cps.utils.CpsValidator import org.onap.cps.ncmp.api.inventory.DataStoreSyncState import org.onap.cps.ncmp.api.inventory.models.TrustLevel import org.onap.cps.ncmp.api.inventory.models.CmHandleState diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServicePropertyHandlerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServicePropertyHandlerSpec.groovy index b600d02be5..70bd418026 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServicePropertyHandlerSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServicePropertyHandlerSpec.groovy @@ -32,7 +32,7 @@ import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle import org.onap.cps.api.exceptions.DataNodeNotFoundException import org.onap.cps.api.exceptions.DataValidationException import org.onap.cps.api.model.DataNode -import org.onap.cps.api.model.DataNodeBuilder +import org.onap.cps.impl.DataNodeBuilder import org.onap.cps.utils.ContentType import org.onap.cps.utils.JsonObjectMapper import org.slf4j.LoggerFactory diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImplSpec.groovy index d8d92e99f5..0ed9dd8aae 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImplSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImplSpec.groovy @@ -35,7 +35,7 @@ import org.onap.cps.api.model.DataNode import org.onap.cps.api.model.ModuleDefinition import org.onap.cps.api.model.ModuleReference import org.onap.cps.api.parameters.FetchDescendantsOption -import org.onap.cps.impl.utils.CpsValidator +import org.onap.cps.utils.CpsValidator import org.onap.cps.ncmp.api.exceptions.CmHandleNotFoundException import org.onap.cps.ncmp.api.inventory.models.CompositeState import org.onap.cps.ncmp.api.inventory.models.CmHandleState diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/DmiModelOperationsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/DmiModelOperationsSpec.groovy index 714555958a..302e43f170 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/DmiModelOperationsSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/DmiModelOperationsSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2021-2024 Nordix Foundation + * Copyright (C) 2021-2025 Nordix Foundation * Modifications Copyright (C) 2022 Bell Canada * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -21,14 +21,11 @@ package org.onap.cps.ncmp.impl.inventory.sync -import com.fasterxml.jackson.core.JsonProcessingException -import com.fasterxml.jackson.databind.ObjectMapper import org.onap.cps.ncmp.impl.dmi.DmiOperationsBaseSpec import org.onap.cps.ncmp.impl.dmi.DmiProperties import org.onap.cps.ncmp.impl.utils.http.UrlTemplateParameters import org.onap.cps.api.model.ModuleReference import org.onap.cps.utils.JsonObjectMapper -import org.spockframework.spring.SpringBean import org.springframework.beans.factory.annotation.Autowired import org.springframework.boot.test.context.SpringBootTest import org.springframework.http.HttpStatus @@ -40,9 +37,12 @@ import static org.onap.cps.ncmp.api.data.models.OperationType.READ import static org.onap.cps.ncmp.impl.models.RequiredDmiService.MODEL @SpringBootTest -@ContextConfiguration(classes = [DmiProperties, DmiModelOperations]) +@ContextConfiguration(classes = [DmiProperties, DmiModelOperations, JsonObjectMapper]) class DmiModelOperationsSpec extends DmiOperationsBaseSpec { + def NO_AUTH_HEADER = null + def NO_MODULE_SET_TAG = '' + def expectedModulesUrlTemplateWithVariables = new UrlTemplateParameters('myServiceName/dmi/v1/ch/{cmHandleId}/modules', ['cmHandleId': cmHandleId]) def expectedModuleResourcesUrlTemplateWithVariables = new UrlTemplateParameters('myServiceName/dmi/v1/ch/{cmHandleId}/moduleResources', ['cmHandleId': cmHandleId]) @@ -52,11 +52,6 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { @Autowired DmiModelOperations objectUnderTest - @SpringBean - JsonObjectMapper spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper())) - - def NO_AUTH_HEADER = null - def 'Retrieving module references.'() { given: 'a cm handle' mockYangModelCmHandleRetrieval([]) @@ -65,7 +60,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { def responseFromDmi = new ResponseEntity([schemas: moduleReferencesAsLisOfMaps], HttpStatus.OK) mockDmiRestClient.synchronousPostOperationWithJsonData(MODEL, expectedModulesUrlTemplateWithVariables, '{"cmHandleProperties":{},"moduleSetTag":""}', READ, NO_AUTH_HEADER) >> responseFromDmi when: 'get module references is called' - def result = objectUnderTest.getModuleReferences(yangModelCmHandle) + def result = objectUnderTest.getModuleReferences(yangModelCmHandle, NO_MODULE_SET_TAG) then: 'the result consists of expected module references' assert result == [new ModuleReference(moduleName: 'mod1', revision: 'A'), new ModuleReference(moduleName: 'mod2', revision: 'X')] } @@ -78,7 +73,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { def responseFromDmi = new ResponseEntity(bodyAsMap, HttpStatus.NO_CONTENT) mockDmiRestClient.synchronousPostOperationWithJsonData(*_) >> responseFromDmi when: 'get module references is called' - def result = objectUnderTest.getModuleReferences(yangModelCmHandle) + def result = objectUnderTest.getModuleReferences(yangModelCmHandle, NO_MODULE_SET_TAG) then: 'the result is empty' assert result == [] where: 'the DMI response body has the following content' @@ -97,7 +92,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { mockDmiRestClient.synchronousPostOperationWithJsonData(MODEL, expectedModulesUrlTemplateWithVariables, '{"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + ',"moduleSetTag":""}', READ, NO_AUTH_HEADER) >> responseFromDmi when: 'a get module references is called' - def result = objectUnderTest.getModuleReferences(yangModelCmHandle) + def result = objectUnderTest.getModuleReferences(yangModelCmHandle, NO_MODULE_SET_TAG) then: 'the result is the response from DMI service' assert result == [] where: 'the following DMI properties are used' @@ -116,7 +111,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { mockDmiRestClient.synchronousPostOperationWithJsonData(MODEL, expectedModuleResourcesUrlTemplateWithVariables, '{"data":{"modules":[' + expectedModuleReferencesInRequest + ']},"cmHandleProperties":{}}', READ, NO_AUTH_HEADER) >> responseFromDmi when: 'get new yang resources from DMI service' - def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, newModuleReferences) + def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, NO_MODULE_SET_TAG, newModuleReferences) then: 'the result has the 2 expected yang (re)sources (order is not guaranteed)' assert result.size() == 2 assert result.get('mod1') == 'some yang source' @@ -131,7 +126,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { def responseFromDmi = new ResponseEntity(responseFromDmiBody, HttpStatus.NO_CONTENT) mockDmiRestClient.synchronousPostOperationWithJsonData(*_) >> responseFromDmi when: 'get new yang resources from DMI service' - def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, newModuleReferences) + def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, NO_MODULE_SET_TAG, newModuleReferences) then: 'the result is empty' assert result == [:] where: 'the DMI response body has the following content' @@ -149,7 +144,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { '{"data":{"modules":[{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}]},"cmHandleProperties":' + expectedAdditionalPropertiesInRequest + '}', READ, NO_AUTH_HEADER) >> responseFromDmi when: 'get new yang resources from DMI service' - def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, newModuleReferences) + def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, NO_MODULE_SET_TAG, newModuleReferences) then: 'the result is the response from DMI service' assert result == [mod1:'some yang source'] where: 'the following DMI properties are used' @@ -166,7 +161,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { mockDmiRestClient.synchronousPostOperationWithJsonData(MODEL, expectedModuleResourcesUrlTemplateWithVariables, '{' + expectedModuleSetTagInRequest + '"data":{"modules":[{"name":"mod1","revision":"A"},{"name":"mod2","revision":"X"}]},"cmHandleProperties":{}}', READ, NO_AUTH_HEADER) >> responseFromDmi when: 'get new yang resources from DMI service' - def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, newModuleReferences) + def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, moduleSetTag, newModuleReferences) then: 'the result is the response from DMI service' assert result == [mod1:'some yang source'] where: 'the following Module Set Tags are used' @@ -180,7 +175,7 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { given: 'a cm handle' mockYangModelCmHandleRetrieval([]) when: 'a get new yang resources from DMI is called with no module references' - def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, []) + def result = objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, NO_MODULE_SET_TAG, []) then: 'no resources are returned' assert result == [:] and: 'no request is sent to DMI' @@ -191,21 +186,35 @@ class DmiModelOperationsSpec extends DmiOperationsBaseSpec { given: 'a cm handle' mockYangModelCmHandleRetrieval(null) when: 'a get new yang resources from DMI is called' - objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, [new ModuleReference('mod1', 'A')]) + objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, NO_MODULE_SET_TAG, [new ModuleReference('mod1', 'A')]) then: 'a null pointer is thrown (we might need to address this later)' thrown(NullPointerException) } - def 'Retrieving module references with Json processing exception.'() { - given: 'a cm handle' - mockYangModelCmHandleRetrieval([]) - and: 'a Json processing exception occurs' - spiedJsonObjectMapper.asJsonString(_) >> {throw (new JsonProcessingException('parsing error'))} - when: 'a DMI operation is executed' - objectUnderTest.getModuleReferences(yangModelCmHandle) - then: 'an ncmp exception is thrown' - def exceptionThrown = thrown(JsonProcessingException) - and: 'the message indicates a parsing error' - exceptionThrown.message.toLowerCase().contains('parsing error') + def 'Retrieving module references forwards the new module set tag to DMI during CM-handle upgrade.'() { + given: 'a cm handle with an existing module set tag' + mockYangModelCmHandleRetrieval([], 'OLD-TAG') + when: 'get module references is called' + objectUnderTest.getModuleReferences(yangModelCmHandle, 'NEW-TAG') + then: 'a request was sent to DMI with the NEW module set tag in the body' + 1 * mockDmiRestClient.synchronousPostOperationWithJsonData(*_) >> { args -> + def requestBodyAsJson = args[2] as String + assert requestBodyAsJson.contains('"moduleSetTag":"NEW-TAG"') + return new ResponseEntity([schemas: [[moduleName: 'mod1', revision: 'A'], [moduleName: 'mod2', revision: 'X']]], HttpStatus.OK) + } + } + + def 'Retrieving yang resources forwards the new module set tag to DMI during CM-handle upgrade.'() { + given: 'a cm handle with an existing module set tag' + mockYangModelCmHandleRetrieval([], 'OLD-TAG') + when: 'get new yang resources from DMI service' + objectUnderTest.getNewYangResourcesFromDmi(yangModelCmHandle, 'NEW-TAG', newModuleReferences) + then: 'a request was sent to DMI with the NEW module set tag in the body' + 1 * mockDmiRestClient.synchronousPostOperationWithJsonData(*_) >> { args -> + def requestBodyAsJson = args[2] as String + assert requestBodyAsJson.contains('"moduleSetTag":"NEW-TAG"') + return new ResponseEntity([[moduleName: 'mod1', revision: 'A', yangSource: 'some yang source'], + [moduleName: 'mod2', revision: 'X', yangSource: 'other yang source']], HttpStatus.OK) + } } } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncServiceSpec.groovy index f8adfe5578..b4837f7bab 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncServiceSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncServiceSpec.groovy @@ -39,6 +39,8 @@ import static org.onap.cps.ncmp.api.inventory.models.LockReasonCategory.MODULE_U class ModuleSyncServiceSpec extends Specification { + def NO_MODULE_SET_TAG = '' + def mockCpsModuleService = Mock(CpsModuleService) def mockDmiModelOperations = Mock(DmiModelOperations) def mockCpsAnchorService = Mock(CpsAnchorService) @@ -53,9 +55,9 @@ class ModuleSyncServiceSpec extends Specification { def yangModelCmHandle = createAdvisedCmHandle(moduleSetTag) and: 'DMI operations returns some module references' def moduleReferences = [ new ModuleReference('module1','1'), new ModuleReference('module2','2') ] - mockDmiModelOperations.getModuleReferences(yangModelCmHandle) >> moduleReferences + mockDmiModelOperations.getModuleReferences(yangModelCmHandle, moduleSetTag) >> moduleReferences and: 'DMI-Plugin returns resource(s) for "new" module(s)' - mockDmiModelOperations.getNewYangResourcesFromDmi(yangModelCmHandle, identifiedNewModuleReferences) >> newModuleNameContentToMap + mockDmiModelOperations.getNewYangResourcesFromDmi(yangModelCmHandle, moduleSetTag, identifiedNewModuleReferences) >> newModuleNameContentToMap and: 'the module service identifies #identifiedNewModuleReferences.size() new modules' mockCpsModuleService.identifyNewModuleReferences(moduleReferences) >> identifiedNewModuleReferences when: 'module sync is triggered' @@ -90,20 +92,45 @@ class ModuleSyncServiceSpec extends Specification { 'without' | '' } - def 'Attempt Sync models for a cm handle with existing schema set (#exception).'() { + def 'Sync models for a cm handle with already defined exception upon schema set creation.'() { given: 'a cm handle to be synced' def yangModelCmHandle = createAdvisedCmHandle('existing tag') and: 'dmi returns no new yang resources' mockDmiModelOperations.getNewYangResourcesFromDmi(*_) >> [:] and: 'already defined exception occurs when creating schema (existing)' - mockCpsModuleService.createSchemaSetFromModules(*_) >> { throw exception } + mockCpsModuleService.createSchemaSetFromModules(*_) >> { throw AlreadyDefinedException.forSchemaSet('', '', null) } when: 'module sync is triggered' objectUnderTest.syncAndCreateSchemaSetAndAnchor(yangModelCmHandle) - then: 'no exception is thrown up' + then: 'the exception is ignored' noExceptionThrown() - where: 'following exceptions occur' - exception << [ AlreadyDefinedException.forSchemaSet('', '', null), - new DuplicatedYangResourceException('', '', null) ] + } + + def 'Sync models for a cm handle with already defined exception upon anchor set creation.'() { + given: 'a cm handle to be synced' + def yangModelCmHandle = createAdvisedCmHandle('existing tag') + and: 'dmi returns no new yang resources' + mockDmiModelOperations.getNewYangResourcesFromDmi(*_) >> [:] + and: 'already defined exception occurs when creating schema (existing)' + mockCpsAnchorService.createAnchor(*_) >> { throw AlreadyDefinedException.forAnchor('', '', null) } + when: 'module sync is triggered' + objectUnderTest.syncAndCreateSchemaSetAndAnchor(yangModelCmHandle) + then: 'the exception is ignored' + noExceptionThrown() + } + + def 'Attempt Sync models for a cm handle with duplicate yang resources exception).'() { + given: 'a cm handle to be synced' + def yangModelCmHandle = createAdvisedCmHandle('existing tag') + and: 'dmi returns no new yang resources' + mockDmiModelOperations.getNewYangResourcesFromDmi(*_) >> [:] + and: 'duplicate yang resource exception occurs when creating schema' + def originalException = new DuplicatedYangResourceException('', '', null) + mockCpsModuleService.createSchemaSetFromModules(*_) >> { throw originalException } + when: 'module sync is triggered' + objectUnderTest.syncAndCreateSchemaSetAndAnchor(yangModelCmHandle) + then: 'same exception is thrown up' + def thrownException = thrown(Exception) + assert thrownException == originalException } def 'Model upgrade without using Module Set Tags (legacy) where the modules are in database.'() { @@ -115,8 +142,8 @@ class ModuleSyncServiceSpec extends Specification { def yangModelCmHandle = YangModelCmHandle.toYangModelCmHandle(dmiServiceName, '', '', ncmpServiceCmHandle,'', '', '') and: 'DMI operations returns some module references for upgraded cm handle' def moduleReferences = [ new ModuleReference('module1','1') ] - mockDmiModelOperations.getModuleReferences(yangModelCmHandle) >> moduleReferences - mockDmiModelOperations.getNewYangResourcesFromDmi(_, []) >> [:] + mockDmiModelOperations.getModuleReferences(yangModelCmHandle, NO_MODULE_SET_TAG) >> moduleReferences + mockDmiModelOperations.getNewYangResourcesFromDmi(_, NO_MODULE_SET_TAG, []) >> [:] and: 'none of these module references are new (all already known to the system)' mockCpsModuleService.identifyNewModuleReferences(_) >> [] when: 'module sync is triggered' @@ -138,7 +165,7 @@ class ModuleSyncServiceSpec extends Specification { mockCpsModuleService.schemaSetExists(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, tagTo) >> schemaExists and: 'DMI operations returns some module references for upgraded cm handle' def moduleReferences = [ new ModuleReference('module1','1') ] - expectedCallsToDmi * mockDmiModelOperations.getModuleReferences(yangModelCmHandle) >> moduleReferences + expectedCallsToDmi * mockDmiModelOperations.getModuleReferences(yangModelCmHandle, tagTo) >> moduleReferences and: 'dmi returns no new yang resources' mockDmiModelOperations.getNewYangResourcesFromDmi(*_) >> [:] and: 'none of these module references are new (all already known to the system)' diff --git a/cps-rest/docs/openapi/cpsAdmin.yml b/cps-rest/docs/openapi/cpsAdmin.yml index f394270dd5..6cfffa48f3 100644 --- a/cps-rest/docs/openapi/cpsAdmin.yml +++ b/cps-rest/docs/openapi/cpsAdmin.yml @@ -1,6 +1,6 @@ # ============LICENSE_START======================================================= # Copyright (c) 2021 Bell Canada. -# Modifications Copyright (C) 2021-2022 Nordix Foundation +# Modifications Copyright (C) 2021-2025 Nordix Foundation # Modifications Copyright (C) 2022 TechMahindra Ltd. # ================================================================================ # Licensed under the Apache License, Version 2.0 (the "License"); @@ -230,3 +230,23 @@ adminDataspace: $ref: 'components.yml#/components/responses/Forbidden' '500': $ref: 'components.yml#/components/responses/InternalServerError' + +adminCleanDataspace: + post: + description: Clean the dataspace (remove orphaned schema sets and modules) + tags: + - cps-admin + summary: Clean the dataspace + operationId: cleanDataspace + parameters: + - $ref: 'components.yml#/components/parameters/apiVersionInPath' + - $ref: 'components.yml#/components/parameters/dataspaceNameInPath' + responses: + '204': + $ref: 'components.yml#/components/responses/NoContent' + '400': + $ref: 'components.yml#/components/responses/BadRequest' + '403': + $ref: 'components.yml#/components/responses/Forbidden' + '500': + $ref: 'components.yml#/components/responses/InternalServerError' diff --git a/cps-rest/docs/openapi/openapi.yml b/cps-rest/docs/openapi/openapi.yml index f4eab61875..c85bf7cac7 100644 --- a/cps-rest/docs/openapi/openapi.yml +++ b/cps-rest/docs/openapi/openapi.yml @@ -1,5 +1,5 @@ # ============LICENSE_START======================================================= -# Copyright (C) 2021-2024 Nordix Foundation +# Copyright (C) 2021-2025 Nordix Foundation # Modifications Copyright (C) 2021 Pantheon.tech # Modifications Copyright (C) 2021 Bell Canada. # Modifications Copyright (C) 2022-2024 TechMahindra Ltd. @@ -61,6 +61,9 @@ paths: /{apiVersion}/admin/dataspaces/{dataspace-name}: $ref: 'cpsAdmin.yml#/adminDataspace' + /{apiVersion}/admin/dataspaces/{dataspace-name}/actions/clean: + $ref: 'cpsAdmin.yml#/adminCleanDataspace' + /v1/dataspaces/{dataspace-name}/anchors: $ref: 'cpsAdminV1Deprecated.yml#/anchorsByDataspace' diff --git a/cps-rest/pom.xml b/cps-rest/pom.xml index b04daf03bd..f72cef9f28 100644 --- a/cps-rest/pom.xml +++ b/cps-rest/pom.xml @@ -62,10 +62,6 @@ <artifactId>spring-boot-starter-jetty</artifactId> </dependency> <dependency> - <groupId>org.springframework.retry</groupId> - <artifactId>spring-retry</artifactId> - </dependency> - <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> </dependency> diff --git a/cps-rest/src/main/java/org/onap/cps/rest/controller/AdminRestController.java b/cps-rest/src/main/java/org/onap/cps/rest/controller/AdminRestController.java index 675c0eaec4..4c6bd6cdc5 100755 --- a/cps-rest/src/main/java/org/onap/cps/rest/controller/AdminRestController.java +++ b/cps-rest/src/main/java/org/onap/cps/rest/controller/AdminRestController.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2020-2023 Nordix Foundation + * Copyright (C) 2020-2025 Nordix Foundation * Modifications Copyright (C) 2020-2021 Bell Canada. * Modifications Copyright (C) 2021 Pantheon.tech * Modifications Copyright (C) 2022 TechMahindra Ltd. @@ -176,6 +176,20 @@ public class AdminRestController implements CpsAdminApi { } /** + * Clean the given dataspace of any orphaned (module) data. + * + * @param apiVersion api version + * @param dataspaceName dataspace name + * + * @return a {@Link ResponseEntity} of {@link HttpStatus} NO_CONTENT + */ + @Override + public ResponseEntity<Void> cleanDataspace(final String apiVersion, final String dataspaceName) { + cpsModuleService.deleteAllUnusedYangModuleData(dataspaceName); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + /** * Create a new anchor. * * @param dataspaceName dataspace name diff --git a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/AdminRestControllerSpec.groovy b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/AdminRestControllerSpec.groovy index 2335a5e770..0d189783fd 100755 --- a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/AdminRestControllerSpec.groovy +++ b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/AdminRestControllerSpec.groovy @@ -2,7 +2,7 @@ * ============LICENSE_START======================================================= * Copyright (C) 2020-2021 Pantheon.tech * Modifications Copyright (C) 2020-2021 Bell Canada. - * Modifications Copyright (C) 2021-2022 Nordix Foundation + * Modifications Copyright (C) 2021-2025 Nordix Foundation * Modifications Copyright (C) 2022 TechMahindra Ltd. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); @@ -23,15 +23,8 @@ package org.onap.cps.rest.controller -import org.onap.cps.api.CpsAnchorService - -import static org.onap.cps.api.parameters.CascadeDeleteAllowed.CASCADE_DELETE_PROHIBITED -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post - import org.mapstruct.factory.Mappers +import org.onap.cps.api.CpsAnchorService import org.onap.cps.api.CpsDataspaceService import org.onap.cps.api.CpsModuleService import org.onap.cps.api.exceptions.AlreadyDefinedException @@ -51,6 +44,12 @@ import org.springframework.util.LinkedMultiValueMap import org.springframework.util.MultiValueMap import spock.lang.Specification +import static org.onap.cps.api.parameters.CascadeDeleteAllowed.CASCADE_DELETE_PROHIBITED +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post + @WebMvcTest(AdminRestController) class AdminRestControllerSpec extends Specification { @@ -79,7 +78,7 @@ class AdminRestControllerSpec extends Specification { def dataspace = new Dataspace(name: dataspaceName) def 'Create new dataspace with #scenario.'() { - when: 'post is invoked' + when: 'post is invoked on endpoint for creating a dataspace' def response = mvc.perform( post("/cps/api/${apiVersion}/dataspaces") @@ -97,7 +96,7 @@ class AdminRestControllerSpec extends Specification { } def 'Create dataspace over existing with same name.'() { - given: 'an endpoint' + given: 'the endpoint to create a dataspace' def createDataspaceEndpoint = "$basePath/v1/dataspaces" and: 'the service method throws an exception indicating the dataspace is already defined' def thrownException = new AlreadyDefinedException(dataspaceName, new RuntimeException()) @@ -115,7 +114,7 @@ class AdminRestControllerSpec extends Specification { def 'Get a dataspace.'() { given: 'service method returns a dataspace' mockCpsDataspaceService.getDataspace(dataspaceName) >> dataspace - and: 'an endpoint' + and: 'the endpoint for getting a dataspace by name' def getDataspaceEndpoint = "$basePath/v1/admin/dataspaces/$dataspaceName" when: 'get dataspace API is invoked' def response = mvc.perform(get(getDataspaceEndpoint)).andReturn().response @@ -124,6 +123,17 @@ class AdminRestControllerSpec extends Specification { response.getContentAsString().contains(dataspaceName) } + def 'Clean a dataspace.'() { + given: 'service method returns a dataspace' + mockCpsDataspaceService.getDataspace(dataspaceName) >> dataspace + and: 'the endpoint for cleaning a dataspace' + def postCleanDataspaceEndpoint = "$basePath/v1/admin/dataspaces/$dataspaceName/actions/clean" + when: 'post is invoked on the clean dataspace endpoint' + def response = mvc.perform(post(postCleanDataspaceEndpoint)).andReturn().response + then: 'no content is returned' + response.status == HttpStatus.NO_CONTENT.value() + } + def 'Get all dataspaces.'() { given: 'service method returns all dataspace' mockCpsDataspaceService.getAllDataspaces() >> [dataspace, new Dataspace(name: "dataspace-test2")] @@ -173,8 +183,7 @@ class AdminRestControllerSpec extends Specification { .param('schema-set-name', schemaSetName)) .andReturn().response then: 'associated service method is invoked with expected parameters' - 1 * mockCpsModuleService.createSchemaSet(dataspaceName, schemaSetName, _) >> - { args -> yangResourceMapCapture = args[2] } + 1 * mockCpsModuleService.createSchemaSet(dataspaceName, schemaSetName, _) >> { args -> yangResourceMapCapture = args[2] } yangResourceMapCapture['assembly.yang'] == "fake assembly content 1\n" yangResourceMapCapture['component.yang'] == "fake component content 1\n" and: 'response code indicates success' @@ -208,7 +217,7 @@ class AdminRestControllerSpec extends Specification { } def 'Create schema set from zip archive having #caseDescriptor.'() { - given: 'an endpoint' + given: 'the endpoint to create a schema set' def schemaSetEndpoint = "$basePath/v1/dataspaces/$dataspaceName/schema-sets" when: 'zip archive having #caseDescriptor is uploaded with create schema set request' def response = @@ -228,7 +237,7 @@ class AdminRestControllerSpec extends Specification { def 'Create schema set from file with unsupported filename extension.'() { given: 'file with unsupported filename extension (.doc)' def multipartFile = createMultipartFile("filename.doc", "content") - and: 'an endpoint' + and: 'the endpoint to create a schema set' def schemaSetEndpoint = "$basePath/v1/dataspaces/$dataspaceName/schema-sets" when: 'file uploaded with schema set create request' def response = @@ -242,7 +251,7 @@ class AdminRestControllerSpec extends Specification { } def 'Create schema set from #fileType file with IOException occurrence on processing.'() { - given: 'an endpoint' + given: 'the endpoint to create a schema set' def schemaSetEndpoint = "$basePath/v1/dataspaces/$dataspaceName/schema-sets" when: 'file uploaded with schema set create request' def multipartFile = createMultipartFileForIOException(fileType) @@ -259,7 +268,7 @@ class AdminRestControllerSpec extends Specification { } def 'Delete schema set.'() { - given: 'an endpoint' + given: 'the endpoint for deleting a schema set' def schemaSetEndpoint = "$basePath/v1/dataspaces/$dataspaceName/schema-sets/$schemaSetName" when: 'delete schema set endpoint is invoked' def response = mvc.perform(delete(schemaSetEndpoint)).andReturn().response @@ -274,7 +283,7 @@ class AdminRestControllerSpec extends Specification { def thrownException = new SchemaSetInUseException(dataspaceName, schemaSetName) mockCpsModuleService.deleteSchemaSet(dataspaceName, schemaSetName, CASCADE_DELETE_PROHIBITED) >> { throw thrownException } - and: 'an endpoint' + and: 'the endpoint for deleting a schema set' def schemaSetEndpoint = "$basePath/v1/dataspaces/$dataspaceName/schema-sets/$schemaSetName" when: 'delete schema set endpoint is invoked' def response = mvc.perform(delete(schemaSetEndpoint)).andReturn().response @@ -286,7 +295,7 @@ class AdminRestControllerSpec extends Specification { given: 'service method returns a new schema set' mockCpsModuleService.getSchemaSet(dataspaceName, schemaSetName) >> new SchemaSet(name: schemaSetName, dataspaceName: dataspaceName) - and: 'an endpoint' + and: 'the endpoint for getting a schema set' def schemaSetEndpoint = "$basePath/v1/dataspaces/$dataspaceName/schema-sets/$schemaSetName" when: 'get schema set API is invoked' def response = mvc.perform(get(schemaSetEndpoint)).andReturn().response @@ -300,7 +309,7 @@ class AdminRestControllerSpec extends Specification { mockCpsModuleService.getSchemaSets(dataspaceName) >> [new SchemaSet(name: schemaSetName, dataspaceName: dataspaceName), new SchemaSet(name: "test-schemaset", dataspaceName: dataspaceName)] - and: 'an endpoint' + and: 'the endpoint for getting all schema sets' def schemaSetEndpoint = "$basePath/v1/dataspaces/$dataspaceName/schema-sets" when: 'get schema sets API is invoked' def response = mvc.perform(get(schemaSetEndpoint)).andReturn().response @@ -315,7 +324,7 @@ class AdminRestControllerSpec extends Specification { def requestParams = new LinkedMultiValueMap<>() requestParams.add('schema-set-name', schemaSetName) requestParams.add('anchor-name', anchorName) - when: 'post is invoked' + when: 'post is invoked on the create anchors endpoint' def response = mvc.perform( post("/cps/api/${apiVersion}/dataspaces/my_dataspace/anchors") @@ -332,10 +341,10 @@ class AdminRestControllerSpec extends Specification { 'V2 API' | 'v2' || '' } - def 'Get existing anchor.'() { - given: 'service method returns a list of anchors' + def 'Get existing anchors.'() { + given: 'service method returns a list of (one) anchors' mockCpsAnchorService.getAnchors(dataspaceName) >> [anchor] - and: 'an endpoint' + and: 'the endpoint for getting all anchors' def anchorEndpoint = "$basePath/v1/dataspaces/$dataspaceName/anchors" when: 'get all anchors API is invoked' def response = mvc.perform(get(anchorEndpoint)).andReturn().response @@ -348,7 +357,7 @@ class AdminRestControllerSpec extends Specification { given: 'service method returns an anchor' mockCpsAnchorService.getAnchor(dataspaceName, anchorName) >> new Anchor(name: anchorName, dataspaceName: dataspaceName, schemaSetName: schemaSetName) - and: 'an endpoint' + and: 'the endpoint for getting an anchor' def anchorEndpoint = "$basePath/v1/dataspaces/$dataspaceName/anchors/$anchorName" when: 'get anchor API is invoked' def response = mvc.perform(get(anchorEndpoint)).andReturn().response @@ -361,7 +370,7 @@ class AdminRestControllerSpec extends Specification { } def 'Delete anchor.'() { - given: 'an endpoint' + given: 'the endpoint for deleting an anchor' def anchorEndpoint = "$basePath/v1/dataspaces/$dataspaceName/anchors/$anchorName" when: 'delete method is invoked on anchor endpoint' def response = mvc.perform(delete(anchorEndpoint)).andReturn().response @@ -372,7 +381,7 @@ class AdminRestControllerSpec extends Specification { } def 'Delete dataspace.'() { - given: 'an endpoint' + given: 'the endpoint for deleting a dataspace' def dataspaceEndpoint = "$basePath/v1/dataspaces" when: 'delete dataspace endpoint is invoked' def response = mvc.perform(delete(dataspaceEndpoint) diff --git a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy index ca89fafe83..f2f962422f 100755 --- a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy +++ b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy @@ -30,8 +30,8 @@ import org.onap.cps.api.CpsAnchorService import org.onap.cps.api.CpsDataService import org.onap.cps.api.parameters.FetchDescendantsOption import org.onap.cps.api.model.DataNode -import org.onap.cps.api.model.DataNodeBuilder -import org.onap.cps.api.model.DeltaReportBuilder +import org.onap.cps.impl.DataNodeBuilder +import org.onap.cps.impl.DeltaReportBuilder import org.onap.cps.utils.ContentType import org.onap.cps.utils.DateTimeUtility import org.onap.cps.utils.JsonObjectMapper diff --git a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy index f29654c99f..2b5c471287 100644 --- a/cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy +++ b/cps-rest/src/test/groovy/org/onap/cps/rest/controller/QueryRestControllerSpec.groovy @@ -27,7 +27,7 @@ import com.fasterxml.jackson.databind.ObjectMapper import org.onap.cps.api.CpsAnchorService import org.onap.cps.api.CpsQueryService import org.onap.cps.api.parameters.PaginationOption -import org.onap.cps.api.model.DataNodeBuilder +import org.onap.cps.impl.DataNodeBuilder import org.onap.cps.utils.JsonObjectMapper import org.onap.cps.utils.PrefixResolver import org.spockframework.spring.SpringBean diff --git a/cps-ri/pom.xml b/cps-ri/pom.xml index 2492cb837e..f065421ec9 100644 --- a/cps-ri/pom.xml +++ b/cps-ri/pom.xml @@ -56,10 +56,6 @@ <artifactId>spring-boot-starter-validation</artifactId>
</dependency>
<dependency>
- <groupId>org.springframework.retry</groupId>
- <artifactId>spring-retry</artifactId>
- </dependency>
- <dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
diff --git a/cps-ri/src/main/java/org/onap/cps/ri/CpsDataPersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/ri/CpsDataPersistenceServiceImpl.java index c43c8e2999..52fd7f2be1 100644 --- a/cps-ri/src/main/java/org/onap/cps/ri/CpsDataPersistenceServiceImpl.java +++ b/cps-ri/src/main/java/org/onap/cps/ri/CpsDataPersistenceServiceImpl.java @@ -50,12 +50,12 @@ import org.onap.cps.api.exceptions.CpsPathException; import org.onap.cps.api.exceptions.DataNodeNotFoundException; import org.onap.cps.api.exceptions.DataNodeNotFoundExceptionBatch; import org.onap.cps.api.model.DataNode; -import org.onap.cps.api.model.DataNodeBuilder; import org.onap.cps.api.parameters.FetchDescendantsOption; import org.onap.cps.api.parameters.PaginationOption; import org.onap.cps.cpspath.parser.CpsPathQuery; import org.onap.cps.cpspath.parser.CpsPathUtil; import org.onap.cps.cpspath.parser.PathParsingException; +import org.onap.cps.impl.DataNodeBuilder; import org.onap.cps.ri.models.AnchorEntity; import org.onap.cps.ri.models.DataspaceEntity; import org.onap.cps.ri.models.FragmentEntity; diff --git a/cps-ri/src/main/java/org/onap/cps/ri/CpsModulePersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/ri/CpsModulePersistenceServiceImpl.java index cf9fb021a6..aaf6165471 100755 --- a/cps-ri/src/main/java/org/onap/cps/ri/CpsModulePersistenceServiceImpl.java +++ b/cps-ri/src/main/java/org/onap/cps/ri/CpsModulePersistenceServiceImpl.java @@ -70,10 +70,6 @@ import org.opendaylight.yangtools.yang.model.repo.api.YangTextSchemaSource; import org.opendaylight.yangtools.yang.parser.api.YangSyntaxErrorException; import org.opendaylight.yangtools.yang.parser.rfc7950.repo.YangModelDependencyInfo; import org.springframework.dao.DataIntegrityViolationException; -import org.springframework.retry.RetryContext; -import org.springframework.retry.annotation.Backoff; -import org.springframework.retry.annotation.Retryable; -import org.springframework.retry.support.RetrySynchronizationManager; import org.springframework.stereotype.Component; @Slf4j @@ -154,10 +150,6 @@ public class CpsModulePersistenceServiceImpl implements CpsModulePersistenceServ @Override @Transactional - // A retry is made to store the schema set if it fails because of duplicated yang resource exception that - // can occur in case of specific concurrent requests. - @Retryable(retryFor = DuplicatedYangResourceException.class, maxAttempts = 5, backoff = - @Backoff(random = true, delay = 200, maxDelay = 2000, multiplier = 2)) public void storeSchemaSet(final String dataspaceName, final String schemaSetName, final Map<String, String> moduleReferenceNameToContentMap) { final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName); @@ -189,12 +181,8 @@ public class CpsModulePersistenceServiceImpl implements CpsModulePersistenceServ @Override @Transactional - // A retry is made to store the schema set if it fails because of duplicated yang resource exception that - // can occur in case of specific concurrent requests. - @Retryable(retryFor = DuplicatedYangResourceException.class, maxAttempts = 5, backoff = - @Backoff(random = true, delay = 200, maxDelay = 2000, multiplier = 2)) @Timed(value = "cps.module.persistence.schemaset.store", - description = "Time taken to store a schemaset (list of module references") + description = "Time taken to store a schemaset (list of module references)") public void storeSchemaSetFromModules(final String dataspaceName, final String schemaSetName, final Map<String, String> newModuleNameToContentMap, final Collection<ModuleReference> allModuleReferences) { @@ -237,8 +225,9 @@ public class CpsModulePersistenceServiceImpl implements CpsModulePersistenceServ @Override @Transactional - public void deleteAllUnusedYangModuleData() { - schemaSetRepository.deleteOrphanedSchemaSets(); + public void deleteAllUnusedYangModuleData(final String dataspaceName) { + final DataspaceEntity dataspaceEntity = dataspaceRepository.getByName(dataspaceName); + schemaSetRepository.deleteOrphanedSchemaSets(dataspaceEntity.getId()); yangResourceRepository.deleteOrphanedYangResources(); } @@ -278,18 +267,10 @@ public class CpsModulePersistenceServiceImpl implements CpsModulePersistenceServ yangResourceRepository.saveAll(newYangResourceEntities); } catch (final DataIntegrityViolationException dataIntegrityViolationException) { // Throw a CPS duplicated Yang resource exception if the cause of the error is a yang checksum - // database constraint violation. - // If it is not, then throw the original exception + // database constraint violation. If it is not, then throw the original exception final Optional<DuplicatedYangResourceException> convertedException = convertToDuplicatedYangResourceException( dataIntegrityViolationException, newYangResourceEntities); - convertedException.ifPresent( - e -> { - final RetryContext retryContext = RetrySynchronizationManager.getContext(); - int retryCount = retryContext == null ? 0 : retryContext.getRetryCount(); - log.warn("Cannot persist duplicated yang resource. System will attempt this method " - + "up to 5 times. Current retry count : {}", ++retryCount, e); - }); throw convertedException.isPresent() ? convertedException.get() : dataIntegrityViolationException; } } diff --git a/cps-ri/src/main/java/org/onap/cps/ri/repository/SchemaSetRepository.java b/cps-ri/src/main/java/org/onap/cps/ri/repository/SchemaSetRepository.java index b8dd7b755c..fdd72624ba 100644 --- a/cps-ri/src/main/java/org/onap/cps/ri/repository/SchemaSetRepository.java +++ b/cps-ri/src/main/java/org/onap/cps/ri/repository/SchemaSetRepository.java @@ -83,8 +83,8 @@ public interface SchemaSetRepository extends JpaRepository<SchemaSetEntity, Inte */ @Modifying @Query(value = """ - DELETE FROM schema_set WHERE NOT EXISTS - (SELECT 1 FROM anchor WHERE anchor.schema_set_id = schema_set.id) + DELETE FROM schema_set WHERE schema_set.dataspace_id = :dataspaceId AND + NOT EXISTS (SELECT 1 FROM anchor WHERE anchor.schema_set_id = schema_set.id) """, nativeQuery = true) - void deleteOrphanedSchemaSets(); + void deleteOrphanedSchemaSets(@Param("dataspaceId") final int dataspaceId); } diff --git a/cps-ri/src/main/java/org/onap/cps/ri/utils/CpsValidatorImpl.java b/cps-ri/src/main/java/org/onap/cps/ri/utils/CpsValidatorImpl.java index fa9feee1e7..9e89c8aed9 100644 --- a/cps-ri/src/main/java/org/onap/cps/ri/utils/CpsValidatorImpl.java +++ b/cps-ri/src/main/java/org/onap/cps/ri/utils/CpsValidatorImpl.java @@ -27,7 +27,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.onap.cps.api.exceptions.DataValidationException; import org.onap.cps.api.parameters.PaginationOption; -import org.onap.cps.impl.utils.CpsValidator; +import org.onap.cps.utils.CpsValidator; import org.springframework.stereotype.Component; @Slf4j diff --git a/cps-ri/src/test/groovy/org/onap/cps/ri/CpsDataPersistenceServiceImplSpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/ri/CpsDataPersistenceServiceImplSpec.groovy index c818f3ba1f..e927922acf 100644 --- a/cps-ri/src/test/groovy/org/onap/cps/ri/CpsDataPersistenceServiceImplSpec.groovy +++ b/cps-ri/src/test/groovy/org/onap/cps/ri/CpsDataPersistenceServiceImplSpec.groovy @@ -33,7 +33,7 @@ import org.onap.cps.api.parameters.FetchDescendantsOption import org.onap.cps.api.exceptions.ConcurrencyException import org.onap.cps.api.exceptions.DataValidationException import org.onap.cps.api.model.DataNode -import org.onap.cps.api.model.DataNodeBuilder +import org.onap.cps.impl.DataNodeBuilder import org.onap.cps.utils.JsonObjectMapper import org.springframework.dao.DataIntegrityViolationException import spock.lang.Specification diff --git a/cps-ri/src/test/groovy/org/onap/cps/ri/CpsModulePersistenceServiceConcurrencySpec.groovy b/cps-ri/src/test/groovy/org/onap/cps/ri/CpsModulePersistenceServiceConcurrencySpec.groovy deleted file mode 100644 index 28a615b0e8..0000000000 --- a/cps-ri/src/test/groovy/org/onap/cps/ri/CpsModulePersistenceServiceConcurrencySpec.groovy +++ /dev/null @@ -1,145 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2022 Bell Canada. - * Modifications Copyright (C) 2021-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.ri - -import org.hibernate.exception.ConstraintViolationException -import org.onap.cps.ri.models.DataspaceEntity -import org.onap.cps.ri.models.SchemaSetEntity -import org.onap.cps.ri.repository.DataspaceRepository -import org.onap.cps.ri.repository.ModuleReferenceRepository -import org.onap.cps.ri.repository.SchemaSetRepository -import org.onap.cps.ri.repository.YangResourceRepository -import org.onap.cps.spi.CpsAdminPersistenceService -import org.onap.cps.spi.CpsModulePersistenceService -import org.onap.cps.api.exceptions.DuplicatedYangResourceException -import org.onap.cps.api.model.ModuleReference -import org.spockframework.spring.SpringBean -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import org.springframework.dao.DataIntegrityViolationException -import org.springframework.retry.annotation.EnableRetry -import spock.lang.Specification - -import java.sql.SQLException - -@SpringBootTest(classes=[CpsModulePersistenceServiceImpl]) -@EnableRetry -class CpsModulePersistenceServiceConcurrencySpec extends Specification { - - @Autowired - CpsModulePersistenceService objectUnderTest - - @SpringBean - DataspaceRepository dataspaceRepository = Mock() - - @SpringBean - YangResourceRepository yangResourceRepository = Mock() - - @SpringBean - SchemaSetRepository schemaSetRepository = Mock() - - @SpringBean - CpsAdminPersistenceService cpsAdminPersistenceService = Mock() - - @SpringBean - ModuleReferenceRepository moduleReferenceRepository = Mock() - - def NEW_RESOURCE_NAME = 'some new resource' - def NEW_RESOURCE_CONTENT = 'module stores {\n' + - ' yang-version 1.1;\n' + - ' namespace "org:onap:ccsdk:sample";\n' + - '}' - - def newYangResourcesNameToContentMap = [(NEW_RESOURCE_NAME):NEW_RESOURCE_CONTENT] - - def yangResourceChecksum = 'b13faef573ed1374139d02c40d8ce09c80ea1dc70e63e464c1ed61568d48d539' - - def yangResourceChecksumDbConstraint = 'yang_resource_checksum_key' - - def sqlExceptionMessage = String.format('(checksum)=(%s)', yangResourceChecksum) - - def checksumIntegrityException = new DataIntegrityViolationException("checksum integrity exception", - new ConstraintViolationException('', new SQLException(sqlExceptionMessage), yangResourceChecksumDbConstraint)) - - def 'Store new schema set, maximum retries.'() { - given: 'no pre-existing schemaset in database' - dataspaceRepository.getByName(_) >> new DataspaceEntity() - yangResourceRepository.findAllByChecksumIn(_) >> Collections.emptyList() - when: 'a new schemaset is stored' - objectUnderTest.storeSchemaSet('some dataspace', 'some new schema set', newYangResourcesNameToContentMap) - then: 'a duplicated yang resource exception is thrown ' - thrown(DuplicatedYangResourceException) - and: 'the system will attempt to save the data 5 times (because checksum integrity exception is thrown each time)' - 5 * yangResourceRepository.saveAll(_) >> { throw checksumIntegrityException } - } - - def 'Store new schema set, succeed on third attempt.'() { - given: 'no pre-existing schemaset in database' - dataspaceRepository.getByName(_) >> new DataspaceEntity() - yangResourceRepository.findAllByChecksumIn(_) >> Collections.emptyList() - when: 'a new schemaset is stored' - objectUnderTest.storeSchemaSet('some dataspace', 'some new schema set', newYangResourcesNameToContentMap) - then: 'no exception is thrown ' - noExceptionThrown() - and: 'the system will attempt to save the data 2 times with checksum integrity exception but then succeed' - 2 * yangResourceRepository.saveAll(_) >> { throw checksumIntegrityException } - 1 * yangResourceRepository.saveAll(_) >> [] - } - - def 'Store schema set using modules, maximum retries.'() { - given: 'map of new modules, a list of existing modules, module reference' - def mapOfNewModules = [newModule1: 'module newmodule { yang-version 1.1; revision "2021-10-12" { } }'] - def moduleReferenceForExistingModule = new ModuleReference("test","2021-10-12") - def listOfExistingModulesModuleReference = [moduleReferenceForExistingModule] - and: 'no pre-existing schemaset in database' - dataspaceRepository.getByName(_) >> new DataspaceEntity() - yangResourceRepository.findAllByChecksumIn(_) >> Collections.emptyList() - when: 'a new schemaset is stored from a module' - objectUnderTest.storeSchemaSetFromModules('some dataspace', 'some new schema set' , mapOfNewModules, listOfExistingModulesModuleReference) - then: 'a duplicated yang resource exception is thrown ' - thrown(DuplicatedYangResourceException) - and: 'the system will attempt to save the data 5 times (because checksum integrity exception is thrown each time)' - 5 * yangResourceRepository.saveAll(_) >> { throw checksumIntegrityException } - } - - def 'Store schema set using modules, succeed on third attempt.'() { - given: 'map of new modules, a list of existing modules, module reference' - def mapOfNewModules = [newModule1: 'module newmodule { yang-version 1.1; revision "2021-10-12" { } }'] - def moduleReferenceForExistingModule = new ModuleReference("test","2021-10-12") - def listOfExistingModulesModuleReference = [moduleReferenceForExistingModule] - and: 'no pre-existing schemaset in database' - def dataspaceEntity = new DataspaceEntity() - dataspaceRepository.getByName(_) >> new DataspaceEntity() - yangResourceRepository.findAllByChecksumIn(_) >> Collections.emptyList() - yangResourceRepository.getResourceIdsByModuleReferences(_) >> [] - and: 'can retrieve schemaset details after storing it' - def schemaSetEntity = new SchemaSetEntity() - schemaSetRepository.getByDataspaceAndName(dataspaceEntity, 'new schema set') >> schemaSetEntity - when: 'a new schemaset is stored from a module' - objectUnderTest.storeSchemaSetFromModules('some dataspace', 'new schema set' , mapOfNewModules, listOfExistingModulesModuleReference) - then: 'no exception is thrown ' - noExceptionThrown() - and: 'the system will attempt to save the data 2 times with checksum integrity exception but then succeed' - 2 * yangResourceRepository.saveAll(_) >> { throw checksumIntegrityException } - 1 * yangResourceRepository.saveAll(_) >> [] - } - -} 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 81b6439efc..c6b8c60ab9 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 @@ -164,8 +164,11 @@ public interface CpsModuleService { Collection<ModuleReference> identifyNewModuleReferences(Collection<ModuleReference> moduleReferencesToCheck); /** - * Remove any Yang Resource Modules and Schema Sets from the DB that are no longer referenced by any anchor. + * Remove any Yang Resource Modules and Schema Sets from the given dataspace that are no longer referenced + * by any anchor. + * + * @param dataspaceName dataspace name */ - void deleteAllUnusedYangModuleData(); + void deleteAllUnusedYangModuleData(String dataspaceName); } diff --git a/cps-service/src/main/java/org/onap/cps/api/model/DataNode.java b/cps-service/src/main/java/org/onap/cps/api/model/DataNode.java index be80b636ad..6597aa3908 100644 --- a/cps-service/src/main/java/org/onap/cps/api/model/DataNode.java +++ b/cps-service/src/main/java/org/onap/cps/api/model/DataNode.java @@ -26,20 +26,19 @@ import java.io.Serializable; import java.util.Collection; import java.util.Collections; import java.util.Map; -import lombok.AccessLevel; import lombok.EqualsAndHashCode; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; -@Setter(AccessLevel.PROTECTED) +@Setter @Getter @EqualsAndHashCode +@NoArgsConstructor public class DataNode implements Serializable { private static final long serialVersionUID = 1482619410918597467L; - DataNode() {} - private String dataspace; private String schemaSetName; private String anchorName; diff --git a/cps-service/src/main/java/org/onap/cps/api/model/DeltaReport.java b/cps-service/src/main/java/org/onap/cps/api/model/DeltaReport.java index df642628d0..761c6ad01d 100644 --- a/cps-service/src/main/java/org/onap/cps/api/model/DeltaReport.java +++ b/cps-service/src/main/java/org/onap/cps/api/model/DeltaReport.java @@ -23,21 +23,20 @@ package org.onap.cps.api.model; import com.fasterxml.jackson.annotation.JsonInclude; import java.io.Serializable; import java.util.Map; -import lombok.AccessLevel; import lombok.Getter; +import lombok.NoArgsConstructor; import lombok.Setter; -@Setter(AccessLevel.PROTECTED) +@Setter @Getter @JsonInclude(JsonInclude.Include.NON_NULL) +@NoArgsConstructor public class DeltaReport { public static final String CREATE_ACTION = "create"; public static final String REMOVE_ACTION = "remove"; public static final String REPLACE_ACTION = "replace"; - DeltaReport() {} - private String action; private String xpath; private Map<String, Serializable> sourceData; diff --git a/cps-service/src/main/java/org/onap/cps/impl/CpsAnchorServiceImpl.java b/cps-service/src/main/java/org/onap/cps/impl/CpsAnchorServiceImpl.java index fb22311128..f18ae74c73 100644 --- a/cps-service/src/main/java/org/onap/cps/impl/CpsAnchorServiceImpl.java +++ b/cps-service/src/main/java/org/onap/cps/impl/CpsAnchorServiceImpl.java @@ -24,9 +24,9 @@ import java.util.Collection; import lombok.RequiredArgsConstructor; import org.onap.cps.api.CpsAnchorService; import org.onap.cps.api.model.Anchor; -import org.onap.cps.impl.utils.CpsValidator; import org.onap.cps.spi.CpsAdminPersistenceService; import org.onap.cps.spi.CpsDataPersistenceService; +import org.onap.cps.utils.CpsValidator; import org.springframework.stereotype.Service; @Service diff --git a/cps-service/src/main/java/org/onap/cps/impl/CpsDataServiceImpl.java b/cps-service/src/main/java/org/onap/cps/impl/CpsDataServiceImpl.java index f2513173a6..71e6f79bb7 100644 --- a/cps-service/src/main/java/org/onap/cps/impl/CpsDataServiceImpl.java +++ b/cps-service/src/main/java/org/onap/cps/impl/CpsDataServiceImpl.java @@ -42,15 +42,14 @@ import org.onap.cps.api.CpsDeltaService; import org.onap.cps.api.exceptions.DataValidationException; import org.onap.cps.api.model.Anchor; import org.onap.cps.api.model.DataNode; -import org.onap.cps.api.model.DataNodeBuilder; import org.onap.cps.api.model.DeltaReport; import org.onap.cps.api.parameters.FetchDescendantsOption; import org.onap.cps.cpspath.parser.CpsPathUtil; import org.onap.cps.events.CpsDataUpdateEventsService; import org.onap.cps.events.model.Data.Operation; -import org.onap.cps.impl.utils.CpsValidator; import org.onap.cps.spi.CpsDataPersistenceService; import org.onap.cps.utils.ContentType; +import org.onap.cps.utils.CpsValidator; import org.onap.cps.utils.DataMapUtils; import org.onap.cps.utils.JsonObjectMapper; import org.onap.cps.utils.PrefixResolver; diff --git a/cps-service/src/main/java/org/onap/cps/impl/CpsDataspaceServiceImpl.java b/cps-service/src/main/java/org/onap/cps/impl/CpsDataspaceServiceImpl.java index 15caa2276d..1a85147b64 100644 --- a/cps-service/src/main/java/org/onap/cps/impl/CpsDataspaceServiceImpl.java +++ b/cps-service/src/main/java/org/onap/cps/impl/CpsDataspaceServiceImpl.java @@ -27,8 +27,8 @@ import java.util.Collection; import lombok.RequiredArgsConstructor; import org.onap.cps.api.CpsDataspaceService; import org.onap.cps.api.model.Dataspace; -import org.onap.cps.impl.utils.CpsValidator; import org.onap.cps.spi.CpsAdminPersistenceService; +import org.onap.cps.utils.CpsValidator; import org.springframework.stereotype.Service; @Service diff --git a/cps-service/src/main/java/org/onap/cps/impl/CpsDeltaServiceImpl.java b/cps-service/src/main/java/org/onap/cps/impl/CpsDeltaServiceImpl.java index 7a9d142506..d532001aec 100644 --- a/cps-service/src/main/java/org/onap/cps/impl/CpsDeltaServiceImpl.java +++ b/cps-service/src/main/java/org/onap/cps/impl/CpsDeltaServiceImpl.java @@ -32,7 +32,6 @@ import lombok.extern.slf4j.Slf4j; import org.onap.cps.api.CpsDeltaService; import org.onap.cps.api.model.DataNode; import org.onap.cps.api.model.DeltaReport; -import org.onap.cps.api.model.DeltaReportBuilder; import org.springframework.stereotype.Service; @Slf4j diff --git a/cps-service/src/main/java/org/onap/cps/impl/CpsModuleServiceImpl.java b/cps-service/src/main/java/org/onap/cps/impl/CpsModuleServiceImpl.java index 7622ba5fe2..b16abcc31f 100644 --- a/cps-service/src/main/java/org/onap/cps/impl/CpsModuleServiceImpl.java +++ b/cps-service/src/main/java/org/onap/cps/impl/CpsModuleServiceImpl.java @@ -36,8 +36,8 @@ import org.onap.cps.api.model.ModuleDefinition; import org.onap.cps.api.model.ModuleReference; import org.onap.cps.api.model.SchemaSet; import org.onap.cps.api.parameters.CascadeDeleteAllowed; -import org.onap.cps.impl.utils.CpsValidator; import org.onap.cps.spi.CpsModulePersistenceService; +import org.onap.cps.utils.CpsValidator; import org.onap.cps.yang.TimedYangTextSchemaSourceSetBuilder; import org.onap.cps.yang.YangTextSchemaSourceSet; import org.springframework.stereotype.Service; @@ -175,8 +175,9 @@ public class CpsModuleServiceImpl implements CpsModuleService { } @Override - public void deleteAllUnusedYangModuleData() { - cpsModulePersistenceService.deleteAllUnusedYangModuleData(); + public void deleteAllUnusedYangModuleData(final String dataspaceName) { + cpsValidator.validateNameCharacters(dataspaceName); + cpsModulePersistenceService.deleteAllUnusedYangModuleData(dataspaceName); } private boolean isCascadeDeleteProhibited(final CascadeDeleteAllowed cascadeDeleteAllowed) { diff --git a/cps-service/src/main/java/org/onap/cps/impl/CpsQueryServiceImpl.java b/cps-service/src/main/java/org/onap/cps/impl/CpsQueryServiceImpl.java index e534e0aea1..2687d8faee 100644 --- a/cps-service/src/main/java/org/onap/cps/impl/CpsQueryServiceImpl.java +++ b/cps-service/src/main/java/org/onap/cps/impl/CpsQueryServiceImpl.java @@ -29,8 +29,8 @@ import org.onap.cps.api.CpsQueryService; import org.onap.cps.api.model.DataNode; import org.onap.cps.api.parameters.FetchDescendantsOption; import org.onap.cps.api.parameters.PaginationOption; -import org.onap.cps.impl.utils.CpsValidator; import org.onap.cps.spi.CpsDataPersistenceService; +import org.onap.cps.utils.CpsValidator; import org.springframework.stereotype.Service; @Service diff --git a/cps-service/src/main/java/org/onap/cps/api/model/DataNodeBuilder.java b/cps-service/src/main/java/org/onap/cps/impl/DataNodeBuilder.java index d509f53525..a78f3d9826 100644 --- a/cps-service/src/main/java/org/onap/cps/api/model/DataNodeBuilder.java +++ b/cps-service/src/main/java/org/onap/cps/impl/DataNodeBuilder.java @@ -20,7 +20,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.api.model; +package org.onap.cps.impl; import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; @@ -33,6 +33,7 @@ import java.util.Set; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; import org.onap.cps.api.exceptions.DataValidationException; +import org.onap.cps.api.model.DataNode; import org.onap.cps.utils.YangUtils; import org.opendaylight.yangtools.yang.common.Ordering; import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier; diff --git a/cps-service/src/main/java/org/onap/cps/api/model/DeltaReportBuilder.java b/cps-service/src/main/java/org/onap/cps/impl/DeltaReportBuilder.java index a8e922f3df..fdc2e939d6 100644 --- a/cps-service/src/main/java/org/onap/cps/api/model/DeltaReportBuilder.java +++ b/cps-service/src/main/java/org/onap/cps/impl/DeltaReportBuilder.java @@ -18,11 +18,12 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.api.model; +package org.onap.cps.impl; import java.io.Serializable; import java.util.Map; import lombok.extern.slf4j.Slf4j; +import org.onap.cps.api.model.DeltaReport; @Slf4j public class DeltaReportBuilder { diff --git a/cps-service/src/main/java/org/onap/cps/impl/YangTextSchemaSourceSetCache.java b/cps-service/src/main/java/org/onap/cps/impl/YangTextSchemaSourceSetCache.java index 688669c941..e7e7b1c5ce 100644 --- a/cps-service/src/main/java/org/onap/cps/impl/YangTextSchemaSourceSetCache.java +++ b/cps-service/src/main/java/org/onap/cps/impl/YangTextSchemaSourceSetCache.java @@ -27,8 +27,8 @@ import io.micrometer.core.instrument.Metrics; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import lombok.RequiredArgsConstructor; -import org.onap.cps.impl.utils.CpsValidator; import org.onap.cps.spi.CpsModulePersistenceService; +import org.onap.cps.utils.CpsValidator; import org.onap.cps.yang.YangTextSchemaSourceSet; import org.onap.cps.yang.YangTextSchemaSourceSetBuilder; import org.springframework.cache.annotation.CacheConfig; diff --git a/cps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java b/cps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java index b1f8aad88f..86ad50252d 100755 --- a/cps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java +++ b/cps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java @@ -146,9 +146,11 @@ public interface CpsModulePersistenceService { String moduleName, String moduleRevision); /** - * Remove any unused Yang Resource Modules and Schema Sets. + * Remove any unused Yang Resource Modules and Schema Sets from the given dataspace. + * + * @param dataspaceName dataspace name */ - void deleteAllUnusedYangModuleData(); + void deleteAllUnusedYangModuleData(String dataspaceName); /** * Identify new module references from those returned by a node compared to what is in CPS already. diff --git a/cps-service/src/main/java/org/onap/cps/impl/utils/CpsValidator.java b/cps-service/src/main/java/org/onap/cps/utils/CpsValidator.java index 75bcf126a4..93f51ee58d 100644 --- a/cps-service/src/main/java/org/onap/cps/impl/utils/CpsValidator.java +++ b/cps-service/src/main/java/org/onap/cps/utils/CpsValidator.java @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.impl.utils; +package org.onap.cps.utils; import org.onap.cps.api.parameters.PaginationOption; diff --git a/cps-service/src/test/groovy/org/onap/cps/impl/CpsAnchorServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/impl/CpsAnchorServiceImplSpec.groovy index 22f5c9f83e..d78c8bb47f 100644 --- a/cps-service/src/test/groovy/org/onap/cps/impl/CpsAnchorServiceImplSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/impl/CpsAnchorServiceImplSpec.groovy @@ -21,7 +21,7 @@ package org.onap.cps.impl -import org.onap.cps.impl.utils.CpsValidator +import org.onap.cps.utils.CpsValidator import org.onap.cps.spi.CpsAdminPersistenceService import org.onap.cps.spi.CpsDataPersistenceService import org.onap.cps.api.exceptions.ModuleNamesNotFoundException diff --git a/cps-service/src/test/groovy/org/onap/cps/impl/CpsDataServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/impl/CpsDataServiceImplSpec.groovy index 3ea859ae6d..34d2b7564a 100644 --- a/cps-service/src/test/groovy/org/onap/cps/impl/CpsDataServiceImplSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/impl/CpsDataServiceImplSpec.groovy @@ -31,7 +31,7 @@ import org.onap.cps.TestUtils import org.onap.cps.api.CpsAnchorService import org.onap.cps.api.CpsDeltaService import org.onap.cps.events.CpsDataUpdateEventsService -import org.onap.cps.impl.utils.CpsValidator +import org.onap.cps.utils.CpsValidator import org.onap.cps.spi.CpsDataPersistenceService import org.onap.cps.api.parameters.FetchDescendantsOption import org.onap.cps.api.exceptions.ConcurrencyException @@ -40,7 +40,6 @@ import org.onap.cps.api.exceptions.DataValidationException import org.onap.cps.api.exceptions.SessionManagerException import org.onap.cps.api.exceptions.SessionTimeoutException import org.onap.cps.api.model.Anchor -import org.onap.cps.api.model.DataNodeBuilder import org.onap.cps.utils.ContentType import org.onap.cps.utils.JsonObjectMapper import org.onap.cps.utils.PrefixResolver diff --git a/cps-service/src/test/groovy/org/onap/cps/impl/CpsDataspaceServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/impl/CpsDataspaceServiceImplSpec.groovy index 468fe76d41..97f6fba4d3 100644 --- a/cps-service/src/test/groovy/org/onap/cps/impl/CpsDataspaceServiceImplSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/impl/CpsDataspaceServiceImplSpec.groovy @@ -21,7 +21,7 @@ package org.onap.cps.impl -import org.onap.cps.impl.utils.CpsValidator +import org.onap.cps.utils.CpsValidator import org.onap.cps.spi.CpsAdminPersistenceService import org.onap.cps.api.model.Dataspace import spock.lang.Specification diff --git a/cps-service/src/test/groovy/org/onap/cps/impl/CpsModuleServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/impl/CpsModuleServiceImplSpec.groovy index ce871621e5..041ce605c4 100644 --- a/cps-service/src/test/groovy/org/onap/cps/impl/CpsModuleServiceImplSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/impl/CpsModuleServiceImplSpec.groovy @@ -25,7 +25,7 @@ package org.onap.cps.impl import org.onap.cps.TestUtils import org.onap.cps.api.CpsAnchorService -import org.onap.cps.impl.utils.CpsValidator +import org.onap.cps.utils.CpsValidator import org.onap.cps.spi.CpsModulePersistenceService import org.onap.cps.api.exceptions.DuplicatedYangResourceException import org.onap.cps.api.exceptions.ModelValidationException @@ -252,11 +252,11 @@ class CpsModuleServiceImplSpec extends Specification { 1 * mockCpsValidator.validateNameCharacters('some-dataspace-name', 'some-anchor-name') } - def 'Delete all unused yang module data.'() { + def 'Delete unused yang module data for a dataspace.'() { when: 'deleting unused yang module data' - objectUnderTest.deleteAllUnusedYangModuleData() - then: 'it is delegated to the module persistence service' - 1 * mockCpsModulePersistenceService.deleteAllUnusedYangModuleData() + objectUnderTest.deleteAllUnusedYangModuleData('some-dataspace-name') + then: 'it is delegated to the module persistence service with the correct parameters' + 1 * mockCpsModulePersistenceService.deleteAllUnusedYangModuleData('some-dataspace-name') } def 'Schema set exists.'() { diff --git a/cps-service/src/test/groovy/org/onap/cps/impl/CpsQueryServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/impl/CpsQueryServiceImplSpec.groovy index 80db83b27a..237e4e4592 100644 --- a/cps-service/src/test/groovy/org/onap/cps/impl/CpsQueryServiceImplSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/impl/CpsQueryServiceImplSpec.groovy @@ -22,7 +22,7 @@ package org.onap.cps.impl -import org.onap.cps.impl.utils.CpsValidator +import org.onap.cps.utils.CpsValidator import org.onap.cps.spi.CpsDataPersistenceService import org.onap.cps.api.parameters.FetchDescendantsOption import org.onap.cps.api.parameters.PaginationOption diff --git a/cps-service/src/test/groovy/org/onap/cps/api/model/DataNodeBuilderSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/impl/DataNodeBuilderSpec.groovy index 24c78864a5..1597d45761 100644 --- a/cps-service/src/test/groovy/org/onap/cps/api/model/DataNodeBuilderSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/impl/DataNodeBuilderSpec.groovy @@ -19,10 +19,11 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.api.model +package org.onap.cps.impl import org.onap.cps.TestUtils import org.onap.cps.api.exceptions.DataValidationException +import org.onap.cps.api.model.DataNode import org.onap.cps.utils.ContentType import org.onap.cps.utils.DataMapUtils import org.onap.cps.utils.YangParserHelper diff --git a/cps-service/src/test/groovy/org/onap/cps/api/model/DeltaReportBuilderSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/impl/DeltaReportBuilderSpec.groovy index 94e3ed5c26..2decefff21 100644 --- a/cps-service/src/test/groovy/org/onap/cps/api/model/DeltaReportBuilderSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/impl/DeltaReportBuilderSpec.groovy @@ -18,7 +18,7 @@ * ============LICENSE_END========================================================= */ -package org.onap.cps.api.model +package org.onap.cps.impl import spock.lang.Specification diff --git a/cps-service/src/test/groovy/org/onap/cps/impl/E2ENetworkSliceSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/impl/E2ENetworkSliceSpec.groovy index 4ab71f7228..8171209947 100755 --- a/cps-service/src/test/groovy/org/onap/cps/impl/E2ENetworkSliceSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/impl/E2ENetworkSliceSpec.groovy @@ -28,7 +28,7 @@ import org.onap.cps.TestUtils import org.onap.cps.api.CpsAnchorService import org.onap.cps.api.CpsDeltaService import org.onap.cps.events.CpsDataUpdateEventsService -import org.onap.cps.impl.utils.CpsValidator +import org.onap.cps.utils.CpsValidator import org.onap.cps.spi.CpsDataPersistenceService import org.onap.cps.spi.CpsModulePersistenceService import org.onap.cps.api.model.Anchor diff --git a/cps-service/src/test/groovy/org/onap/cps/impl/YangTextSchemaSourceSetCacheSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/impl/YangTextSchemaSourceSetCacheSpec.groovy index fe49d04f3c..6694e7712f 100644 --- a/cps-service/src/test/groovy/org/onap/cps/impl/YangTextSchemaSourceSetCacheSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/impl/YangTextSchemaSourceSetCacheSpec.groovy @@ -22,7 +22,7 @@ package org.onap.cps.impl import org.onap.cps.TestUtils -import org.onap.cps.impl.utils.CpsValidator +import org.onap.cps.utils.CpsValidator import org.onap.cps.spi.CpsModulePersistenceService import org.onap.cps.yang.YangTextSchemaSourceSet import org.onap.cps.yang.YangTextSchemaSourceSetBuilder diff --git a/cps-service/src/test/groovy/org/onap/cps/utils/DataMapUtilsSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/utils/DataMapUtilsSpec.groovy index bb0f5b0911..6ff41c128f 100644 --- a/cps-service/src/test/groovy/org/onap/cps/utils/DataMapUtilsSpec.groovy +++ b/cps-service/src/test/groovy/org/onap/cps/utils/DataMapUtilsSpec.groovy @@ -22,7 +22,7 @@ package org.onap.cps.utils -import org.onap.cps.api.model.DataNodeBuilder +import org.onap.cps.impl.DataNodeBuilder import spock.lang.Specification class DataMapUtilsSpec extends Specification { diff --git a/docker-compose/config/grafana/lcm-state-dashboard.json b/docker-compose/config/grafana/inventory-dashboard.json index 5339b038d7..f6a7e8cbb2 100644 --- a/docker-compose/config/grafana/lcm-state-dashboard.json +++ b/docker-compose/config/grafana/inventory-dashboard.json @@ -18,7 +18,7 @@ "editable": true, "fiscalYearStartMonth": 0, "graphTooltip": 0, - "id": 2, + "id": 12, "links": [], "panels": [ { @@ -100,7 +100,7 @@ "sort": "none" } }, - "pluginVersion": "11.4.0", + "pluginVersion": "11.3.1", "targets": [ { "disableTextWrap": false, @@ -179,111 +179,11 @@ }, "gridPos": { "h": 8, - "w": 12, + "w": 24, "x": 0, "y": 9 }, - "id": 1, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "11.4.0", - "targets": [ - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "disableTextWrap": false, - "editorMode": "builder", - "expr": "cmHandlesByState{state=\"ADVISED\", instance=\"$Instance\", job=\"$Job\"}", - "fullMetaSearch": false, - "includeNullMetadata": true, - "legendFormat": "__auto", - "range": true, - "refId": "A", - "useBackend": false - } - ], - "title": "ADVISED", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 9 - }, - "id": 3, + "id": 6, "options": { "legend": { "calcs": [], @@ -296,12 +196,12 @@ "sort": "none" } }, - "pluginVersion": "11.4.0", + "pluginVersion": "11.3.1", "targets": [ { "disableTextWrap": false, "editorMode": "builder", - "expr": "cmHandlesByState{state=\"READY\", instance=\"$Instance\", job=\"$Job\"}", + "expr": "http_server_requests_seconds_count{instance=\"$Instance\", job=\"$Job\", status=~\"201|200\", uri=\"/ncmpInventory/v1/ch\"}", "fullMetaSearch": false, "includeNullMetadata": true, "legendFormat": "__auto", @@ -310,7 +210,7 @@ "useBackend": false } ], - "title": "READY", + "title": "Inventory API calls by URI and STATUS", "type": "timeseries" }, { @@ -375,107 +275,11 @@ }, "gridPos": { "h": 8, - "w": 12, + "w": 24, "x": 0, "y": 17 }, - "id": 2, - "options": { - "legend": { - "calcs": [], - "displayMode": "list", - "placement": "bottom", - "showLegend": true - }, - "tooltip": { - "mode": "single", - "sort": "none" - } - }, - "pluginVersion": "11.4.0", - "targets": [ - { - "disableTextWrap": false, - "editorMode": "builder", - "expr": "cmHandlesByState{state=\"LOCKED\", instance=\"$Instance\", job=\"$Job\"}", - "fullMetaSearch": false, - "includeNullMetadata": true, - "legendFormat": "__auto", - "range": true, - "refId": "A", - "useBackend": false - } - ], - "title": "LOCKED", - "type": "timeseries" - }, - { - "datasource": { - "type": "prometheus", - "uid": "PBFA97CFB590B2093" - }, - "fieldConfig": { - "defaults": { - "color": { - "mode": "palette-classic" - }, - "custom": { - "axisBorderShow": false, - "axisCenteredZero": false, - "axisColorMode": "text", - "axisLabel": "", - "axisPlacement": "auto", - "barAlignment": 0, - "barWidthFactor": 0.6, - "drawStyle": "line", - "fillOpacity": 0, - "gradientMode": "none", - "hideFrom": { - "legend": false, - "tooltip": false, - "viz": false - }, - "insertNulls": false, - "lineInterpolation": "linear", - "lineWidth": 1, - "pointSize": 5, - "scaleDistribution": { - "type": "linear" - }, - "showPoints": "auto", - "spanNulls": false, - "stacking": { - "group": "A", - "mode": "none" - }, - "thresholdsStyle": { - "mode": "off" - } - }, - "mappings": [], - "thresholds": { - "mode": "absolute", - "steps": [ - { - "color": "green", - "value": null - }, - { - "color": "red", - "value": 80 - } - ] - } - }, - "overrides": [] - }, - "gridPos": { - "h": 8, - "w": 12, - "x": 12, - "y": 17 - }, - "id": 4, + "id": 7, "options": { "legend": { "calcs": [], @@ -488,12 +292,12 @@ "sort": "none" } }, - "pluginVersion": "11.4.0", + "pluginVersion": "11.3.1", "targets": [ { "disableTextWrap": false, "editorMode": "builder", - "expr": "cmHandlesByState{state=\"DELETING\", instance=\"$Instance\", job=\"$Job\"}", + "expr": "sum({error=\"OutOfMemoryError\", instance=\"$Instance\", job=\"$Job\"})", "fullMetaSearch": false, "includeNullMetadata": true, "legendFormat": "__auto", @@ -502,19 +306,23 @@ "useBackend": false } ], - "title": "DELETING", + "title": "Out of Memory Errors", "type": "timeseries" } ], "preload": false, "schemaVersion": 40, - "tags": [], + "tags": [ + "CPS", + "NCMP", + "k6" + ], "templating": { "list": [ { "current": { - "text": "172.17.0.1:8799", - "value": "172.17.0.1:8799" + "text": "129.192.80.24:9998", + "value": "129.192.80.24:9998" }, "definition": "label_values(instance)", "label": "Instance", @@ -531,8 +339,8 @@ }, { "current": { - "text": "cps-and-ncmp-endurance", - "value": "cps-and-ncmp-endurance" + "text": "cps-and-ncmp-kpi", + "value": "cps-and-ncmp-kpi" }, "definition": "label_values(job)", "label": "job", @@ -555,8 +363,8 @@ }, "timepicker": {}, "timezone": "browser", - "title": "LCM State", - "uid": "ae9zcowku03k0d", - "version": 1, + "title": "Inventory REST Interfaces", + "uid": "beao8xrt6qjnkc", + "version": 7, "weekStart": "" }
\ No newline at end of file diff --git a/docker-compose/docker-compose.yml b/docker-compose/docker-compose.yml index c9df8b9889..0828d6f3a9 100644 --- a/docker-compose/docker-compose.yml +++ b/docker-compose/docker-compose.yml @@ -68,7 +68,8 @@ services: ONAP_OTEL_EXPORTER_ENDPOINT: http://jaeger-service:4317 POLICY_SERVICE_ENABLED: 'false' POLICY_SERVICE_DEFAULT_DECISION: 'deny from env' - JAVA_TOOL_OPTIONS: "-XX:InitialRAMPercentage=75.0 -XX:MaxRAMPercentage=75.0" + CPS_MONITORING_MICROMETER_JVM_EXTRAS: 'true' + JAVA_TOOL_OPTIONS: "-XX:InitialRAMPercentage=70.0 -XX:MaxRAMPercentage=70.0" ### DEBUG: Uncomment next line to enable java debugging ### JAVA_TOOL_OPTIONS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 restart: unless-stopped @@ -80,7 +81,7 @@ services: resources: limits: cpus: '3' - memory: 2G + memory: 3G nginx: container_name: ${NGINX_CONTAINER_NAME:-nginx-loadbalancer} @@ -199,7 +200,7 @@ services: volumes: - ./config/grafana/provisioning/:/etc/grafana/provisioning/ - ./config/grafana/jvm-micrometer-dashboard.json:/var/lib/grafana/dashboards/jvm-micrometer-dashboard.json - - ./config/grafana/lcm-state-dashboard.json:/var/lib/grafana/dashboards/lcm-state-dashboard.json + - ./config/grafana/inventory-dashboard.json:/var/lib/grafana/dashboards/inventory-dashboard.json - grafana:/var/lib/grafana environment: - GF_SECURITY_ADMIN_PASSWORD=admin diff --git a/docs/admin-guide.rst b/docs/admin-guide.rst index 4a40f9b29c..156a5df832 100644 --- a/docs/admin-guide.rst +++ b/docs/admin-guide.rst @@ -1,6 +1,6 @@ .. This work is licensed under a Creative Commons Attribution 4.0 International License. .. http://creativecommons.org/licenses/by/4.0 -.. Copyright (C) 2021-2022 Nordix Foundation +.. Copyright (C) 2021-2025 Nordix Foundation .. DO NOT CHANGE THIS LABEL FOR RELEASE NOTES - EVEN THOUGH IT GIVES A WARNING .. _adminGuide: @@ -12,6 +12,40 @@ CPS Admin Guide .. toctree:: :maxdepth: 1 +Regular Maintenance +=================== +This section details tasks that an administrator of the CPS application should execute on regular basis +to ensure optimum working of CPS. + +Dataspace Clean Up +------------------ +Certain data in the CPS database might not be explicitly removed after it is no longer required ('orphaned data'). +For example, schema sets and their associated unique module resources no longer used by any anchor because of model upgrades. +This data would unnecessarily take up space and could eventually affect the performance of the DB if it is not deleted. +How often this needs to be done depends on how often schema sets are being deprecated. +Typically once per month should suffice. + +To remove orphaned data in a given dataspace use the following post request: + +.. code:: + + http://<cps-component-service-name>:<cps-port>/v2/admin/dataspaces/<dataspace-name>/actions/clean + +for example + +.. code-block:: bash + + curl --location --request POST 'http://cps:8080/admin/datsaspaces/bookstore/actions/clean' \ + --header 'Content-Type: application/json; charset=utf-8' + + Response : HTTP Status 204 + +For more details refer to the CPS-Core API: :doc:`design`. + +.. note:: + NCMP has no specific maintenance tasks but it will also build up orphaned data when CM Handles get updated and or deleted. + To delete this data execute the above procedure for the dataspace named 'NFP-Operational'. + Logging Configuration ===================== @@ -192,8 +226,20 @@ Prometheus Metrics can be checked at the following endpoint http://<cps-component-service-name>:8080/actuator/prometheus +Heap Dump and Thread Dump +------------------------- + +On demand heap dump and thread dump generation using the below endpoints. + +.. code:: + + http://<cps-component-service-name>:8080/actuator/heapdump + http://<cps-component-service-name>:8080/actuator/threaddump + Hazelcast --------- +.. note:: + The below endpoints will be removed from hazelcast community version in the future release. Hazelcast cluster state and health check can be seen using the below endpoints @@ -210,9 +256,8 @@ Naming Validation As part of the Kohn 3.1.0 release, CPS has added validation to the names of the following components: - Dataspace names - - Schema Set names - Anchor names - - Cm-Handle identifiers + - CM Handle identifiers The following characters along with spaces are no longer valid for naming of these components. diff --git a/docs/api/swagger/cps/openapi.yaml b/docs/api/swagger/cps/openapi.yaml index c84609b638..f6baadc8ea 100644 --- a/docs/api/swagger/cps/openapi.yaml +++ b/docs/api/swagger/cps/openapi.yaml @@ -330,6 +330,65 @@ paths: summary: Get a dataspace tags: - cps-admin + /{apiVersion}/admin/dataspaces/{dataspace-name}/actions/clean: + post: + description: Clean the dataspace (remove orphaned schema sets and modules) + operationId: cleanDataspace + parameters: + - description: apiVersion + in: path + name: apiVersion + required: true + schema: + default: v2 + enum: + - v1 + - v2 + type: string + - description: dataspace-name + in: path + name: dataspace-name + required: true + schema: + example: my-dataspace + type: string + responses: + "204": + content: {} + description: No Content + "400": + content: + application/json: + example: + status: 400 + message: Bad Request + details: The provided request is not valid + schema: + $ref: '#/components/schemas/ErrorMessage' + description: Bad Request + "403": + content: + application/json: + example: + status: 403 + message: Request Forbidden + details: This request is forbidden + schema: + $ref: '#/components/schemas/ErrorMessage' + description: Forbidden + "500": + content: + application/json: + example: + status: 500 + message: Internal Server Error + details: Internal Server Error occurred + schema: + $ref: '#/components/schemas/ErrorMessage' + description: Internal Server Error + summary: Clean the dataspace + tags: + - cps-admin /v1/dataspaces/{dataspace-name}/anchors: post: deprecated: true diff --git a/docs/cm-handle-lcm-events.rst b/docs/cm-handle-lcm-events.rst index 8446834c31..38339e206a 100644 --- a/docs/cm-handle-lcm-events.rst +++ b/docs/cm-handle-lcm-events.rst @@ -1,6 +1,6 @@ .. This work is licensed under a Creative Commons Attribution 4.0 International License. .. http://creativecommons.org/licenses/by/4.0 -.. Copyright (C) 2023 Nordix Foundation +.. Copyright (C) 2023-2025 Nordix Foundation .. DO NOT CHANGE THIS LABEL FOR RELEASE NOTES - EVEN THOUGH IT GIVES A WARNING .. _cmHandleLcmEvents: @@ -15,7 +15,7 @@ CM Handle Lifecycle Management (LCM) Events Introduction ============ -LCM events for CM Handles are published when a CM Handle is created, deleted or another change in the cm handle state occurs. +LCM events for CM Handles are published when a CM Handle is created, deleted or another change in the CM Handle state occurs. **3 possible event types:** @@ -55,7 +55,7 @@ Event payload varies based on the type of event. **CREATE** -Event payload for this event contains the properties of the new cm handle created. +Event payload for this event contains the properties of the new CM Handle created. *Create event payload prototype* @@ -77,7 +77,7 @@ Event payload for this event contains the properties of the new cm handle create **UPDATE** -Event payload for this event contains the difference in state and properties of the cm handle. +Event payload for this event contains the difference in state and properties of the CM Handle. *Update event payload prototype* @@ -106,7 +106,7 @@ Event payload for this event contains the difference in state and properties of **DELETE** -Event payload for this event contains the identifier of the deleted cm handle. +Event payload for this event contains the identifier of the deleted CM Handle. *Delete event payload prototype* @@ -114,4 +114,4 @@ Event payload for this event contains the identifier of the deleted cm handle. "event": { "cmHandleId" : "cmhandle-001", - }
\ No newline at end of file + } diff --git a/docs/cps-events.rst b/docs/cps-events.rst index 47aa73f12e..1097af9a12 100644 --- a/docs/cps-events.rst +++ b/docs/cps-events.rst @@ -1,6 +1,6 @@ .. This work is licensed under a Creative Commons Attribution 4.0 International License. .. http://creativecommons.org/licenses/by/4.0 -.. Copyright (C) 2022-2023 Nordix Foundation +.. Copyright (C) 2022-2025 Nordix Foundation .. DO NOT CHANGE THIS LABEL FOR RELEASE NOTES - EVEN THOUGH IT GIVES A WARNING .. _cpsEvents: @@ -16,9 +16,9 @@ CPS Events cm-notification-subscriptions.rst .. note:: - Legacy async response on a client supplied topic for single cm handle data request are no longer supported. Click link below for the legacy specification. + Legacy async response on a client supplied topic for single CM Handle data request are no longer supported. Click link below for the legacy specification. .. toctree:: :maxdepth: 0 - ncmp-async-events.rst
\ No newline at end of file + ncmp-async-events.rst diff --git a/docs/cps-ncmp-message-status-codes.rst b/docs/cps-ncmp-message-status-codes.rst index e0a3f0308b..799838ae44 100644 --- a/docs/cps-ncmp-message-status-codes.rst +++ b/docs/cps-ncmp-message-status-codes.rst @@ -1,6 +1,6 @@ .. This work is licensed under a Creative Commons Attribution 4.0 International License. .. http://creativecommons.org/licenses/by/4.0 -.. Copyright (C) 2023-2024 Nordix Foundation +.. Copyright (C) 2023-2025 Nordix Foundation .. DO NOT CHANGE THIS LABEL FOR RELEASE NOTES - EVEN THOUGH IT GIVES A WARNING .. _dataOperationMessageStatusCodes: @@ -16,9 +16,9 @@ CPS-NCMP Message Status Codes +-----------------+------------------------------------------------------+-----------------------------------+ | 1 | ACCEPTED | CM Data Notification Subscription | +-----------------+------------------------------------------------------+-----------------------------------+ - | 100 | cm handle id(s) is(are) not found | All features | + | 100 | CM Handle id(s) is(are) not found | All features | +-----------------+------------------------------------------------------+-----------------------------------+ - | 101 | cm handle(s) not ready | Data Operation | + | 101 | CM Handle(s) not ready | Data Operation | +-----------------+------------------------------------------------------+-----------------------------------+ | 102 | dmi plugin service is not responding | Data Operation | +-----------------+------------------------------------------------------+-----------------------------------+ @@ -30,9 +30,9 @@ CPS-NCMP Message Status Codes +-----------------+------------------------------------------------------+-----------------------------------+ | 108 | Unknown error | All features | +-----------------+------------------------------------------------------+-----------------------------------+ - | 109 | cm-handle already exists | Inventory | + | 109 | CM Handle already exists | Inventory | +-----------------+------------------------------------------------------+-----------------------------------+ - | 110 | cm-handle has an invalid character(s) in id | Inventory | + | 110 | CM Handle has an invalid character(s) in id | Inventory | +-----------------+------------------------------------------------------+-----------------------------------+ | 111 | alternate id already associated | Inventory | +-----------------+------------------------------------------------------+-----------------------------------+ diff --git a/docs/cps-scheduled-processes.rst b/docs/cps-scheduled-processes.rst index c204e6ca0a..9af9a81c0c 100644 --- a/docs/cps-scheduled-processes.rst +++ b/docs/cps-scheduled-processes.rst @@ -1,6 +1,6 @@ .. This work is licensed under a Creative Commons Attribution 4.0 International License. .. http://creativecommons.org/licenses/by/4.0 -.. Copyright (C) 2022 Nordix Foundation +.. Copyright (C) 2022-2025 Nordix Foundation .. DO NOT CHANGE THIS LABEL FOR RELEASE NOTES - EVEN THOUGH IT GIVES A WARNING @@ -21,17 +21,17 @@ The following section is a list of the current scheduled processes running withi Module Sync ----------- The module sync is a user :ref:`configurable timed process<additional-cps-ncmp-customizations>`, -which is set to search for CM-Handles within CPS with an *'ADVISED'* state. -Once the CM-Handle is processed by the module sync, the CM-Handle state is then set to *'READY'*, if the process completes successfully. -If for any reason the module sync fails, the CM-Handle state will then be set to *'LOCKED'*, +which is set to search for CM Handles within CPS with an *'ADVISED'* state. +Once the CM Handle is processed by the module sync, the CM Handle state is then set to *'READY'*, if the process completes successfully. +If for any reason the module sync fails, the CM Handle state will then be set to *'LOCKED'*, and the reason for the lock will also be stored within CPS. -CM-Handles in the *'LOCKED'* state will be retried when the system has availability. CM-Handles in a *'LOCKED'* -state are processed by the retry mechanism, by setting CM-Handle state back to *'ADVISED'* so the next sync cycle will process those again. +CM Handles in the *'LOCKED'* state will be retried when the system has availability. CM Handles in a *'LOCKED'* +state are processed by the retry mechanism, by setting CM Handle state back to *'ADVISED'* so the next sync cycle will process those again. Data Sync --------- The data sync is a user :ref:`configurable timed process<additional-cps-ncmp-customizations>`, -which is set to search for CM-Handles with a sync state of *'UNSYNCHRONIZED'*. -Once the CM-Handle(s) with a sync state of *'UNSYNCHRONIZED'* is processed by the data sync, -the CM-Handle sync state is then set to *'SYNCHRONIZED'*, if the process completes successfully. -If the data sync fails, the CM-Handle sync state will remain as *'UNSYNCHRONIZED'*, and will be re-attempted. +which is set to search for CM Handles with a sync state of *'UNSYNCHRONIZED'*. +Once the CM Handle(s) with a sync state of *'UNSYNCHRONIZED'* is processed by the data sync, +the CM Handle sync state is then set to *'SYNCHRONIZED'*, if the process completes successfully. +If the data sync fails, the CM Handle sync state will remain as *'UNSYNCHRONIZED'*, and will be re-attempted. diff --git a/docs/deployment.rst b/docs/deployment.rst index 940bc50923..2af0dd0cd5 100644 --- a/docs/deployment.rst +++ b/docs/deployment.rst @@ -191,21 +191,16 @@ Any spring supported property can be configured by providing in ``config.additio | Property | Description | Default Value | +===========================================+=========================================================================================================+===============================+ | config.appUserName | User name used by cps-core service to configure the authentication for REST API it exposes. | ``cpsuser`` | -| | | | | | This is the user name to be used by cps-core REST clients to authenticate themselves. | | +-------------------------------------------+---------------------------------------------------------------------------------------------------------+-------------------------------+ | config.appUserPassword | Password used by cps-core service to configure the authentication for REST API it exposes. | Not defined | -| | | | | | If not defined, the password is generated when deploying the application. | | -| | | | | | See also :ref:`cps_common_credentials_retrieval`. | | +-------------------------------------------+---------------------------------------------------------------------------------------------------------+-------------------------------+ | postgres.config.pgUserName | Internal user name used by cps-core to connect to its own database. | ``cps`` | +-------------------------------------------+---------------------------------------------------------------------------------------------------------+-------------------------------+ | postgres.config.pgUserPassword | Internal password used by cps-core to connect to its own database. | Not defined | -| | | | | | If not defined, the password is generated when deploying the application. | | -| | | | | | See also :ref:`cps_common_credentials_retrieval`. | | +-------------------------------------------+---------------------------------------------------------------------------------------------------------+-------------------------------+ | postgres.config.pgDatabase | Database name used by cps-core | ``cpsdb`` | @@ -225,28 +220,24 @@ Any spring supported property can be configured by providing in ``config.additio +-------------------------------------------+---------------------------------------------------------------------------------------------------------+-------------------------------+ | config.eventPublisher. | Kafka security protocol. | ``SASL_PLAINTEXT`` | | spring.kafka.security.protocol | Some possible values are: | | -| | | | | | * ``PLAINTEXT`` | | | | * ``SASL_PLAINTEXT``, for authentication | | | | * ``SASL_SSL``, for authentication and encryption | | +-------------------------------------------+---------------------------------------------------------------------------------------------------------+-------------------------------+ | config.eventPublisher. | Kafka security SASL mechanism. Required for SASL_PLAINTEXT and SASL_SSL protocols. | Not defined | | spring.kafka.properties. | Some possible values are: | | -| sasl.mechanism | | | -| | * ``PLAIN``, for PLAINTEXT | | +| sasl.mechanism | * ``PLAIN``, for PLAINTEXT | | | | * ``SCRAM-SHA-512``, for SSL | | +-------------------------------------------+---------------------------------------------------------------------------------------------------------+-------------------------------+ | config.eventPublisher. | Kafka security SASL JAAS configuration. Required for SASL_PLAINTEXT and SASL_SSL protocols. | Not defined | | spring.kafka.properties. | Some possible values are: | | -| sasl.jaas.config | | | -| | * ``org.apache.kafka.common.security.plain.PlainLoginModule required username="..." password="...";``, | | -| | for PLAINTEXT | | +| sasl.jaas.config | * ``org.apache.kafka.common.security.plain.PlainLoginModule required username="..." password="...";``, | | +| | for PLAINTEXT | | | | * ``org.apache.kafka.common.security.scram.ScramLoginModule required username="..." password="...";``, | | -| | for SSL | | +| | for SSL | | +-------------------------------------------+---------------------------------------------------------------------------------------------------------+-------------------------------+ | config.eventPublisher. | Kafka security SASL SSL store type. Required for SASL_SSL protocol. | Not defined | | spring.kafka.ssl.trust-store-type | Some possible values are: | | -| | | | | | * ``JKS`` | | +-------------------------------------------+---------------------------------------------------------------------------------------------------------+-------------------------------+ | config.eventPublisher. | Kafka security SASL SSL store file location. Required for SASL_SSL protocol. | Not defined | @@ -293,35 +284,84 @@ Any spring supported property can be configured by providing in ``config.additio Additional CPS-NCMP Customizations ================================== -+-------------------------------------------+---------------------------------------------------------------------------------------------------------+-------------------------------+ -| config.dmiPluginUserName | User name used by cps-core to authenticate themselves for using ncmp-dmi-plugin service. | ``dmiuser`` | -+-------------------------------------------+---------------------------------------------------------------------------------------------------------+-------------------------------+ -| config.dmiPluginUserPassword | Internal password used by cps-core to connect to ncmp-dmi-plugin service. | Not defined | -| | | | -| | If not defined, the password is generated when deploying the application. | | -| | | | -| | See also :ref:`cps_common_credentials_retrieval`. | | -+-------------------------------------------+---------------------------------------------------------------------------------------------------------+-------------------------------+ -| config.ncmp.timers | Specifies the delay in milliseconds in which the module sync watch dog will wake again after finishing. | ``5000`` | -| .advised-modules-sync.sleep-time-ms | | | -| | | | -+-------------------------------------------+---------------------------------------------------------------------------------------------------------+-------------------------------+ -| config.ncmp.timers | Specifies the delay in milliseconds in which the data sync watch dog will wake again after finishing. | ``30000`` | -| .cm-handle-data-sync.sleep-time-ms | | | -| | | | -+-------------------------------------------+---------------------------------------------------------------------------------------------------------+-------------------------------+ -| config.additional.ncmp.dmi.httpclient | Specifies the maximum time in seconds, to wait for establishing a connection for the HTTP Client. | ``30`` | -| .connectionTimeoutInSeconds | | | -+-------------------------------------------+---------------------------------------------------------------------------------------------------------+-------------------------------+ -| config.additional.ncmp.dmi.httpclient | Specifies the maximum number of connections allowed per route in the HTTP client. | ``50`` | -| .maximumConnectionsPerRoute | | | -+-------------------------------------------+---------------------------------------------------------------------------------------------------------+-------------------------------+ -| config.additional.ncmp.dmi.httpclient | Specifies the maximum total number of connections that can be held by the HTTP client. | ``100`` | -| .maximumConnectionsTotal | | | -+-------------------------------------------+---------------------------------------------------------------------------------------------------------+-------------------------------+ -| config.additional.ncmp.dmi.httpclient | Specifies the duration in seconds for the threshold, after which idle connections will be evicted | ``5`` | -| .idleConnectionEvictionThresholdInSeconds | from the connection pool by the HTTP client. | | -+-------------------------------------------+---------------------------------------------------------------------------------------------------------+-------------------------------+ + ++-------------------------------------------------+---------------------------------------------------------------------------------------+---------------------------------+ +| Property | Description | Default Value | ++=================================================+=======================================================================================+=================================+ +| config.dmiPluginUserName | User name used by cps-core to authenticate themselves for using ncmp-dmi-plugin | ``dmiuser`` | +| | service. | | ++-------------------------------------------------+---------------------------------------------------------------------------------------+---------------------------------+ +| config.dmiPluginUserPassword | Internal password used by cps-core to connect to ncmp-dmi-plugin service. | Not defined | +| | If not defined, the password is generated when deploying the application. | | +| | See also :ref:`cps_common_credentials_retrieval`. | | ++-------------------------------------------------+---------------------------------------------------------------------------------------+---------------------------------+ +| config.ncmp.timers | Specifies the delay in milliseconds in which the module sync watch dog will wake again| ``5000`` | +| .advised-modules-sync.sleep-time-ms | after finishing. | | ++-------------------------------------------------+---------------------------------------------------------------------------------------+---------------------------------+ +| config.ncmp.timers | Specifies the delay in milliseconds in which the data sync watch dog will wake again | ``30000`` | +| .cm-handle-data-sync.sleep-time-ms | after finishing. | | +| | | | ++-------------------------------------------------+---------------------------------------------------------------------------------------+---------------------------------+ +| config.additional.ncmp | Maximum size (in MB) of the in-memory buffer for HTTP response data. | ``16`` | +| .[app] | | | +| .httpclient | | | +| .[services] | | | +| .maximumInMemorySizeInMegabytes | | | ++-------------------------------------------------+---------------------------------------------------------------------------------------+---------------------------------+ +| config.additional.ncmp | Maximum number of simultaneous connections allowed in the connection pool. | ``100`` | +| .[app] | | | +| .httpclient | | | +| .[services] | | | +| .maximumConnectionsTotal | | | ++-------------------------------------------------+---------------------------------------------------------------------------------------+---------------------------------+ +| config.additional.ncmp | Maximum number of pending requests when the connection pool is full. | ``50`` | +| .[app] | | | +| .httpclient | | | +| .[services] | | | +| .pendingAcquireMaxCount | | | ++-------------------------------------------------+---------------------------------------------------------------------------------------+---------------------------------+ +| config.additional.ncmp | Specifies the maximum time in seconds, to wait for establishing a connection for the | ``30`` | +| .[app] | HTTP Client. | | +| .httpclient | | | +| .[services] | | | +| .connectionTimeoutInSeconds | | | ++-------------------------------------------------+---------------------------------------------------------------------------------------+---------------------------------+ +| config.additional.ncmp | Timeout (in seconds) for reading data from the server after the connection is | ``30`` | +| .[app] | established. | | +| .httpclient | | | +| .[services] | | | +| .readTimeoutInSeconds | | | ++-------------------------------------------------+---------------------------------------------------------------------------------------+---------------------------------+ +| config.additional.ncmp | Timeout (in seconds) for writing data to the server. | ``30`` | +| .[app] | | | +| .httpclient | | | +| .[services] | | | +| .writeTimeoutInSeconds | | | ++-------------------------------------------------+---------------------------------------------------------------------------------------+---------------------------------+ +| config.additional.ncmp | Total timeout (in seconds) for receiving a complete response, including all processing| ``60`` | +| .[app] | stages. | | +| .httpclient | | | +| .[services] | | | +| .responseTimeoutInSeconds | | | ++-------------------------------------------------+---------------------------------------------------------------------------------------+---------------------------------+ +| config.additional.ncmp.policy-executor | Enables or disables the policy-executor feature. | ``false`` | +| .enabled | | | ++-------------------------------------------------+---------------------------------------------------------------------------------------+---------------------------------+ +| config.additional.ncmp.policy-executor | The default (fallback) decision in case a problem with the external service occurs. | ``allow`` | +| .defaultDecision | | | ++-------------------------------------------------+---------------------------------------------------------------------------------------+---------------------------------+ +| config.additional.ncmp.policy-executor | The server address for the external policy executor service. | ``http://policy-executor-stub`` | +| .server.address | | | ++-------------------------------------------------+---------------------------------------------------------------------------------------+---------------------------------+ +| config.additional.ncmp.policy-executor | The port used for the external policy executor service. | ``8093`` | +| .server.port | | | ++-------------------------------------------------+---------------------------------------------------------------------------------------+---------------------------------+ + +.. note:: + + - [app] : can be 'policy-executor' or 'dmi'. + - [services] 'all-services' for 'policy-executor'. + - [services] 'data-services' and 'model-services' for 'dmi'. CPS-Core Docker Installation ============================ @@ -342,13 +382,13 @@ Below are the list of distributed datastructures that we have. +--------------+------------------------------------+-----------------------------------------------------------+ | Component | Data Structure Name | Use | +==============+====================================+===========================================================+ -| cps-ncmp | moduleSyncStartedOnCmHandles | Watchdog process to register cm handles. | +| cps-ncmp | moduleSyncStartedOnCmHandles | Watchdog process to register CM Handles. | +--------------+------------------------------------+-----------------------------------------------------------+ | cps-ncmp | dataSyncSemaphores | Watchdog process to sync data from the nodes. | +--------------+------------------------------------+-----------------------------------------------------------+ | cps-ncmp | moduleSyncWorkQueue | Queue used internally for workers to pick the task. | +--------------+------------------------------------+-----------------------------------------------------------+ -| cps-ncmp | trustLevelPerCmHandle | Stores the trust level per cm handle id | +| cps-ncmp | trustLevelPerCmHandle | Stores the trust level per CM Handle id | +--------------+------------------------------------+-----------------------------------------------------------+ | cps-ncmp | trustLevelPerDmiPlugin | Stores the trust level for the dmi-plugins. | +--------------+------------------------------------+-----------------------------------------------------------+ diff --git a/docs/modeling.rst b/docs/modeling.rst index 7ebf6fecd5..65e4aa97ca 100644 --- a/docs/modeling.rst +++ b/docs/modeling.rst @@ -1,7 +1,7 @@ .. This work is licensed under a Creative Commons Attribution 4.0 International License. .. http://creativecommons.org/licenses/by/4.0 .. Copyright (C) 2021 Pantheon.tech -.. Modifications Copyright (C) 2021-2023 Nordix Foundation +.. Modifications Copyright (C) 2021-2025 Nordix Foundation .. _modeling: .. toctree:: @@ -89,31 +89,31 @@ Note: Although additional-properties are present in the model of the dmi-registr Basic Concepts -------------- -- **CM-Handle** represents an instance a modeled Network Function(node) in ONAP. +- **CM Handle** represents an instance a modeled Network Function(node) in ONAP. These are stored as Anchors within CPS-Core. - - **CM-Handle States** are used to represent the potential states in which a CM-Handle can transition between. + - **CM Handle States** are used to represent the potential states in which a CM Handle can transition between. - The 5 possible CM-Handle states are: ADVISED, READY, LOCKED, DELETING, DELETED + The 5 possible CM Handle states are: ADVISED, READY, LOCKED, DELETING, DELETED - **ADVISED** indicates that a CM-Handle has been registered successfully, and is waiting for the module synchronization process to sync the CM-Handle. + **ADVISED** indicates that a CM Handle has been registered successfully, and is waiting for the module synchronization process to sync the CM Handle. - **READY** indicates that the CM-Handle has been synced successfully. + **READY** indicates that the CM Handle has been synced successfully. - **LOCKED** indicates that the CM-Handle has not synced successfully. A retry mechanism within CPS will set the state back to ADVISED after a set time. + **LOCKED** indicates that the CM Handle has not synced successfully. A retry mechanism within CPS will set the state back to ADVISED after a set time. - **DELETING** indicates that the CM-Handle is currently being deleted. + **DELETING** indicates that the CM Handle is currently being deleted. - **DELETED** indicates that the CM-Handle has been deleted successfully. + **DELETED** indicates that the CM Handle has been deleted successfully. - - **Data-sync state** is the state of the data synchronization process of the CM-Handle + - **Data-sync state** is the state of the data synchronization process of the CM Handle There are 3 possibles states: NONE_REQUESTED, UNSYNCHRONIZED, SYNCHRONIZED **NONE_REQUESTED** indicates that the data sync is not requested by the user - **UNSYNCHRONIZED** indicates the cm-handle is waiting for the data sync watchdog operation to carry out the sync process + **UNSYNCHRONIZED** indicates the CM Handle is waiting for the data sync watchdog operation to carry out the sync process **SYNCHRONIZED** indicates the watchdog process has finished the data synchronization successfully diff --git a/docs/ncmp-data-operation.rst b/docs/ncmp-data-operation.rst index 10c3bfaca5..e0b7bb88cd 100644 --- a/docs/ncmp-data-operation.rst +++ b/docs/ncmp-data-operation.rst @@ -1,6 +1,6 @@ .. This work is licensed under a Creative Commons Attribution 4.0 International License. .. http://creativecommons.org/licenses/by/4.0 -.. Copyright (C) 2023-2024 Nordix Foundation +.. Copyright (C) 2023-2025 Nordix Foundation .. DO NOT CHANGE THIS LABEL FOR RELEASE NOTES - EVEN THOUGH IT GIVES A WARNING .. _cmHandleDataOperation: @@ -15,7 +15,7 @@ Data Operations Endpoint Introduction ============ -For all data operations on cm handle(s), we have a post endpoint: +For all data operations on CM Handle(s), we have a post endpoint: - /ncmp/v1/data?topic={client-topic-name} forward request to it's dmi plugin service. @@ -50,7 +50,7 @@ This endpoint executes data operation for given array of operations: | | | implementation. For ONAP DMI Plugin it will be RESTConf paths but it can| | | | really be anything. | +--------------------------+-------------+-------------------------------------------------------------------------+ - | targetIds | Yes | List of cm handle references | + | targetIds | Yes | List of CM Handle references | +--------------------------+-------------+-------------------------------------------------------------------------+ The status codes used in the events resulting from these operations are defined here: @@ -156,4 +156,4 @@ DMI Service 2 (POST) : `http://{dmi-host-name}:{dmi-port}/dmi/v1/data?topic=my-t Above examples are for illustration purposes only. Please refer to link below for latest schema. -:download:`Data operation event schema <schemas/data-operation-event-schema-1.0.0.json>`
\ No newline at end of file +:download:`Data operation event schema <schemas/data-operation-event-schema-1.0.0.json>` diff --git a/docs/overview.rst b/docs/overview.rst index 19ab8b4847..bc99214e2e 100644 --- a/docs/overview.rst +++ b/docs/overview.rst @@ -1,6 +1,8 @@ .. This work is licensed under a Creative Commons Attribution 4.0 International License. .. http://creativecommons.org/licenses/by/4.0 -.. Copyright (C) 2021 Pantheon.tech, Nordix Foundation +.. Copyright (C) 2021 Pantheon.tech +.. Modifications Copyright (C) 2021-2025 Nordix Foundation + .. _overview: CPS Overview @@ -45,7 +47,7 @@ even though CPS-Core could be deployed without the NCMP extension. NCMP-DMI-Plugin --------------- -The Data-Model-Inventory (DMI) Plugin is a rest interface used to synchronize CM-Handles data between CPS and DMI through the DMI-Plugin. +The Data-Model-Inventory (DMI) Plugin is a rest interface used to synchronize CM Handles data between CPS and DMI through the DMI-Plugin. This is built previously from the CPS-NF-Proxy component. CPS Project diff --git a/docs/policy-executor.rst b/docs/policy-executor.rst index b934a579b1..712b4fcf38 100644 --- a/docs/policy-executor.rst +++ b/docs/policy-executor.rst @@ -1,11 +1,10 @@ .. This work is licensed under a Creative Commons Attribution 4.0 International License. .. http://creativecommons.org/licenses/by/4.0 -.. Copyright (C) 2024 Nordix Foundation +.. Copyright (C) 2024-2025 Nordix Foundation -.. DO NOT CHANGE THIS LABEL FOR RELEASE NOTES - EVEN THOUGH IT GIVES A WARNING +.. DO NOT CHANGE THIS LABEL - EVEN THOUGH IT GIVES A WARNING .. _policy_executor: - Policy Executor ############### @@ -15,7 +14,16 @@ Policy Executor Introduction ============ -Work In Progress: This feature is not yet completed and does not affect current NCMP functionality. +The Policy Executor feature can be used to connect an external system to make decisions on CM write operation. +When the feature is enabled, NCMP will first call the configured external system and depending on the response, return an error or continue. +The details of the interface can be found in the ':ref:`policy_executor_consumed_apis`' section. + +This feature is available on 'legacy data interface' for operation on a single cm handle: "/v1/ch/{cm-handle}/data/ds/{datastore-name}" and only applies to "ncmp-datastore:passthrough-running". + +By default, the feature is not enabled. This is controlled by 'config.additional.ncmp.policy-executor.enabled' and other deployment parameters in the same group to enable it. See :ref:`additional-cps-ncmp-customizations` + +.. DO NOT CHANGE THIS LABEL - EVEN THOUGH IT GIVES A WARNING +.. _policy_executor_consumed_apis: Consumed APIs ------------- diff --git a/docs/release-notes.rst b/docs/release-notes.rst index 9c825e4d35..1f37612570 100644 --- a/docs/release-notes.rst +++ b/docs/release-notes.rst @@ -1,6 +1,6 @@ .. This work is licensed under a Creative Commons Attribution 4.0 International License. .. http://creativecommons.org/licenses/by/4.0 -.. Copyright (C) 2021-2024 Nordix Foundation +.. Copyright (C) 2021-2025 Nordix Foundation .. DO NOT CHANGE THIS LABEL FOR RELEASE NOTES - EVEN THOUGH IT GIVES A WARNING .. _release_notes: @@ -40,6 +40,7 @@ Bug Fixes Features -------- + - `CPS-2249 <https://lf-onap.atlassian.net/browse/CPS-2249>`_ NCMP to support Conflict Handling. .. ==================== @@ -68,21 +69,19 @@ Release Data Bug Fixes --------- -3.5.5 - `CPS-2509 <https://lf-onap.atlassian.net/browse/CPS-2509>`_ Fix module endpoints using alternate identifier. - `CPS-2517 <https://lf-onap.atlassian.net/browse/CPS-2517>`_ Make Content-Type header default to JSON for CPS APIs. - - `CPS-2530 <https://lf-onap.atlassian.net/browse/CPS-2530>`_ NCMP Modules API giving empty response on READY cm handles if two sub systems discovered in parallel. + - `CPS-2530 <https://lf-onap.atlassian.net/browse/CPS-2530>`_ NCMP Modules API giving empty response on READY CM Handles if two sub systems discovered in parallel. Features -------- -3.5.5 - `CPS-2009 <https://lf-onap.atlassian.net/browse/CPS-2009>`_ Update legacy NCMP APIs interfaces to support alternate id. - `CPS-2082 <https://lf-onap.atlassian.net/browse/CPS-2082>`_ Support XML content type to data node APIs in cps-core. - `CPS-2433 <https://lf-onap.atlassian.net/browse/CPS-2433>`_ Remove traces of unmaintained CPS-TBDMT repository. - `CPS-2436 <https://lf-onap.atlassian.net/browse/CPS-2436>`_ CM Avc Event to publish source key to target key while forwarding. - `CPS-2445 <https://lf-onap.atlassian.net/browse/CPS-2445>`_ Expose CPS and NCMP version information using git plugin. - `CPS-2451 <https://lf-onap.atlassian.net/browse/CPS-2451>`_ Removing oparent from CPS-NCMP and ONAP DMI Plugin repository. - - `CPS-2478 <https://lf-onap.atlassian.net/browse/CPS-2478>`_ Optimized Cm Handle Registration and De-Registration use case. + - `CPS-2478 <https://lf-onap.atlassian.net/browse/CPS-2478>`_ Optimized CM Handle Registration and De-Registration use case. - `CPS-2507 <https://lf-onap.atlassian.net/browse/CPS-2507>`_ Upgrade liquibase to 4.30.0 version. Performance @@ -111,12 +110,10 @@ Release Data Bug Fixes --------- -3.5.4 - `CPS-2403 <https://lf-onap.atlassian.net/browse/CPS-2403>`_ Improve lock handling and queue management during CM-handle Module Sync. Features -------- -3.5.4 - `CPS-2408 <https://lf-onap.atlassian.net/browse/CPS-2408>`_ One Hazelcast instance per JVM to manage the distributed data structures. Version: 3.5.3 @@ -141,7 +138,6 @@ Release Data Bug Fixes --------- -3.5.3 - `CPS-2353 <https://lf-onap.atlassian.net/browse/CPS-2353>`_ Slow cmHandle registration when we use moduleSetTag, alternateId and dataProducerIdentifier - `CPS-2395 <https://lf-onap.atlassian.net/browse/CPS-2395>`_ Retry mechanism (with back off algorithm) is removed with more frequent watchdog poll - `CPS-2409 <https://lf-onap.atlassian.net/browse/CPS-2409>`_ Return NONE for get effective trust level api if the trust level caches empty (restart case) @@ -150,9 +146,6 @@ Bug Fixes Features -------- -3.5.3 - - `CPS-2247 <https://lf-onap.atlassian.net/browse/CPS-2247>`_ Policy Executor: Invoke Policy Executor and handle 'deny' response - - `CPS-2412 <https://lf-onap.atlassian.net/browse/CPS-2412>`_ Policy Executor: handle errors - `CPS-2417 <https://lf-onap.atlassian.net/browse/CPS-2417>`_ Remove Hazelcast cache for prefix resolver @@ -178,14 +171,12 @@ Release Data Bug Fixes --------- -3.5.2 - `CPS-2306 <https://lf-onap.atlassian.net/browse/CPS-2306>`_ Update response message for data validation failure and make it consistent across APIs - `CPS-2319 <https://lf-onap.atlassian.net/browse/CPS-2319>`_ Fix "Create a node" and "Add List Elements" APIs response code - `CPS-2372 <https://lf-onap.atlassian.net/browse/CPS-2372>`_ Blank alternate ID overwrites existing one Features -------- -3.5.2 - `CPS-1812 <https://lf-onap.atlassian.net/browse/CPS-1812>`_ CM Data Subscriptions ( Create, Delete and Merging ) with positive scenarios - `CPS-2326 <https://lf-onap.atlassian.net/browse/CPS-2326>`_ Uplift liquibase-core dependency to 4.28.0 - `CPS-2353 <https://lf-onap.atlassian.net/browse/CPS-2353>`_ Improve registration performance with moduleSetTag @@ -213,14 +204,12 @@ Release Data Bug Fixes --------- -3.5.1 - `CPS-2302 <https://lf-onap.atlassian.net/browse/CPS-2302>`_ Fix handling of special characters in moduleSetTag. Features -------- -3.5.1 - `CPS-2121 <https://lf-onap.atlassian.net/browse/CPS-2121>`_ Enabled http client prometheus metrics and manage high cardinality using URL template. - - `CPS-2289 <https://lf-onap.atlassian.net/browse/CPS-2289>`_ Support for CPS Path Query in NCMP Inventory Cm Handle Search. + - `CPS-2289 <https://lf-onap.atlassian.net/browse/CPS-2289>`_ Support for CPS Path Query in NCMP Inventory CM Handle Search. Version: 3.5.0 ============== @@ -242,13 +231,8 @@ Release Data | | | +--------------------------------------+--------------------------------------------------------+ -Bug Fixes ---------- -3.5.0 - Features -------- -3.5.0 - `CPS-989 <https://lf-onap.atlassian.net/browse/CPS-989>`_ Replace RestTemplate with WebClient. - `CPS-2172 <https://lf-onap.atlassian.net/browse/CPS-2172>`_ Support for OpenTelemetry Tracing. @@ -278,12 +262,10 @@ Release Data Bug Fixes --------- -3.4.9 - `CPS-2211 <https://lf-onap.atlassian.net/browse/CPS-2211>`_ Toggle switch to disable CPS Core change events if not used by application. Set CPS_CHANGE_EVENT_NOTIFICATIONS_ENABLED environment variable for the same. Features -------- -3.4.9 - `CPS-1836 <https://lf-onap.atlassian.net/browse/CPS-1836>`_ Delta between anchor and JSON payload. Version: 3.4.8 @@ -308,15 +290,11 @@ Release Data Bug Fixes --------- -3.4.8 - `CPS-2186 <https://lf-onap.atlassian.net/browse/CPS-2186>`_ Report async task failures to client topic during data operations request - `CPS-2190 <https://lf-onap.atlassian.net/browse/CPS-2190>`_ Improve performance of NCMP module searches - `CPS-2194 <https://lf-onap.atlassian.net/browse/CPS-2194>`_ Added defaults for CPS and DMI username and password - `CPS-2204 <https://lf-onap.atlassian.net/browse/CPS-2204>`_ Added error handling for yang module upgrade operation -Features --------- - Version: 3.4.7 ============== @@ -339,12 +317,10 @@ Release Data Bug Fixes --------- -3.4.7 - `CPS-2150 <https://lf-onap.atlassian.net/browse/CPS-2150>`_ Fix for Async task execution failed by TimeoutException. Features -------- -3.4.7 - `CPS-2061 <https://lf-onap.atlassian.net/browse/CPS-2061>`_ Liquibase Steps Condensing and Cleanup. - `CPS-2101 <https://lf-onap.atlassian.net/browse/CPS-2101>`_ Uplift Spring Boot to 3.2.4 version. @@ -370,7 +346,6 @@ Release Data Bug Fixes --------- -3.4.6 - `CPS-2126 <https://lf-onap.atlassian.net/browse/CPS-2126>`_ Passing HTTP Authorization Bearer Token to DMI Plugins. @@ -406,10 +381,6 @@ Release Data | | | +--------------------------------------+--------------------------------------------------------+ -Bug Fixes ---------- -3.4.5 - Features -------- @@ -438,7 +409,6 @@ Release Data Bug Fixes --------- -3.4.4 - `CPS-2027 <https://lf-onap.atlassian.net/browse/CPS-2027>`_ Upgrade Yang modules using module set tag functionalities fix Features @@ -469,7 +439,6 @@ Release Data Bug Fixes --------- -3.4.3 - `CPS-2000 <https://lf-onap.atlassian.net/browse/CPS-2000>`_ Fix for Schema object cache not being distributed. - `CPS-2027 <https://lf-onap.atlassian.net/browse/CPS-2027>`_ Fixes for upgrade yang modules using module set tag. - `CPS-2070 <https://lf-onap.atlassian.net/browse/CPS-2070>`_ Add retry interval for Kafka consumer. @@ -506,11 +475,6 @@ Release Data | | | +--------------------------------------+--------------------------------------------------------+ -Bug Fixes ---------- -3.4.2 - - Features -------- - `CPS-1638 <https://lf-onap.atlassian.net/browse/CPS-1638>`_ Introduce trust level for CM handle. @@ -530,7 +494,7 @@ Known Limitations, Issues and Workarounds For upgrading, CPS uses Liquibase for database upgrades. In order to enable Hibernate write batching (`CPS-1795 <https://lf-onap.atlassian.net/browse/CPS-1795>`_), a change to the database entity ID generation is required. As such, *this release does not fully support In-Service Software Upgrade* - CPS will not store new DataNodes and -NCMP will not register new CM-handles during an upgrade with old and new versions of CPS running concurrently. +NCMP will not register new CM Handles during an upgrade with old and new versions of CPS running concurrently. Other operations (read, update, delete) are not impacted. @@ -556,7 +520,6 @@ Release Data Bug Fixes --------- -3.4.1 - `CPS-1979 <https://lf-onap.atlassian.net/browse/CPS-1979>`_ Bug fix for Invalid topic name suffix. Features @@ -594,7 +557,6 @@ Release Data Bug Fixes --------- -3.4.0 - `CPS-1956 <https://lf-onap.atlassian.net/browse/CPS-1956>`_ Bug fix for No yang resources stored during cmhandle discovery. .. ======================== @@ -623,13 +585,9 @@ Release Data Bug Fixes --------- -3.3.9 - `CPS-1923 <https://lf-onap.atlassian.net/browse/CPS-1923>`_ CPS and NCMP changed management endpoint and port from /manage to /actuator and port same as cps application port. - `CPS-1933 <https://lf-onap.atlassian.net/browse/CPS-1933>`_ Setting up the class loader explicitly in hazelcast config. -Features --------- - Version: 3.3.8 ============== @@ -650,10 +608,6 @@ Release Data | | | +--------------------------------------+--------------------------------------------------------+ -Bug Fixes ---------- -3.3.8 - Features -------- - `CPS-1888 <https://lf-onap.atlassian.net/browse/CPS-1888>`_ Uplift Spring Boot to 3.1.2. @@ -680,7 +634,6 @@ Release Data Bug Fixes --------- -3.3.7 - `CPS-1866 <https://lf-onap.atlassian.net/browse/CPS-1866>`_ Fix ClassDefNotFoundError in opendaylight Yang parser Features @@ -713,7 +666,6 @@ Release Data Bug Fixes --------- -3.3.6 - `CPS-1841 <https://lf-onap.atlassian.net/browse/CPS-1841>`_ Update of top-level data node fails with exception - `CPS-1842 <https://lf-onap.atlassian.net/browse/CPS-1842>`_ Replace event-id with correlation-id for data read operation cloud event @@ -743,10 +695,6 @@ Release Data | | | +--------------------------------------+--------------------------------------------------------+ -Bug Fixes ---------- -3.3.5 - Features -------- - `CPS-1760 <https://lf-onap.atlassian.net/browse/CPS-1760>`_ Improve handling of special characters in Cps Paths @@ -771,10 +719,6 @@ Release Data | | | +--------------------------------------+--------------------------------------------------------+ -Bug Fixes ---------- -3.3.4 - Features -------- - `CPS-1767 <https://lf-onap.atlassian.net/browse/CPS-1767>`_ Upgrade CPS to java 17 @@ -799,13 +743,9 @@ Release Data | | | +--------------------------------------+--------------------------------------------------------+ -Bug Fixes ---------- -3.3.3 - Features -------- - - `CPS-1515 <https://lf-onap.atlassian.net/browse/CPS-1515>`_ Support Multiple CM-Handles for NCMP Get Operation + - `CPS-1515 <https://lf-onap.atlassian.net/browse/CPS-1515>`_ Support Multiple CM Handles for NCMP Get Operation - `CPS-1675 <https://lf-onap.atlassian.net/browse/CPS-1675>`_ Persistence write performance improvement(s) - `CPS-1745 <https://lf-onap.atlassian.net/browse/CPS-1745>`_ Upgrade to Openapi 3.0.3 @@ -831,7 +771,6 @@ Release Data Bug Fixes --------- -3.3.2 - `CPS-1716 <https://lf-onap.atlassian.net/browse/CPS-1716>`_ NCMP: Java Heap OutOfMemory errors and slow registration in case of 20k cmhandles Features @@ -862,11 +801,6 @@ Release Data | | | +--------------------------------------+--------------------------------------------------------+ -Bug Fixes ---------- -3.3.1 - - None - Features -------- - `CPS-1272 <https://lf-onap.atlassian.net/browse/CPS-1272>`_ Add Contains operation to CPS Path @@ -895,11 +829,6 @@ Release Data | | | +--------------------------------------+--------------------------------------------------------+ -Bug Fixes ---------- -3.3.0 - - None - Features -------- - `CPS-1215 <https://lf-onap.atlassian.net/browse/CPS-1215>`_ Add OR operation for CPS Path @@ -931,7 +860,6 @@ Release Data Bug Fixes --------- -3.2.6 - `CPS-1526 <https://lf-onap.atlassian.net/browse/CPS-1526>`_ Fix response message for PATCH operation - `CPS-1563 <https://lf-onap.atlassian.net/browse/CPS-1563>`_ Fix 500 response error on id-searches with empty parameters @@ -961,13 +889,8 @@ Release Data Bug Fixes --------- -3.2.5 - `CPS-1537 <https://lf-onap.atlassian.net/browse/CPS-1537>`_ Introduce control switch for model loader functionality. -Features --------- - - None - Version: 3.2.4 ============== @@ -1265,7 +1188,7 @@ Features - `CPS-869 <https://lf-onap.atlassian.net/browse/CPS-869>`_ Apply Standardized logging fields to adhere to ONAP Best practice REQ-1072 - `CPS-870 <https://lf-onap.atlassian.net/browse/CPS-870>`_ Align CPS-Core output with SDN-C output (add module name) - `CPS-875 <https://lf-onap.atlassian.net/browse/CPS-875>`_ CM Handle State: Watchdog-process that syncs 'ADVISED' CM Handles - - `CPS-877 <https://lf-onap.atlassian.net/browse/CPS-877>`_ CM Handle State: Exclude any CM-Handles from queries/operations that are not in state 'READY' + - `CPS-877 <https://lf-onap.atlassian.net/browse/CPS-877>`_ CM Handle State: Exclude any CM Handles from queries/operations that are not in state 'READY' - `CPS-899 <https://lf-onap.atlassian.net/browse/CPS-899>`_ Start and stop sessions on Java API - `CPS-909 <https://lf-onap.atlassian.net/browse/CPS-909>`_ Separate NCMP endpoint for ch/{cm-handle}/properties and ch/{cm-handle}/state - `CPS-917 <https://lf-onap.atlassian.net/browse/CPS-917>`_ Structured Errors response for passthrough use-cases in NCMP @@ -1278,7 +1201,7 @@ Features - `CPS-1099 <https://lf-onap.atlassian.net/browse/CPS-1099>`_ Expose simplified 'external' lock reason enum state over REST interface - `CPS-1101 <https://lf-onap.atlassian.net/browse/CPS-1101>`_ Introducing the DELETING and DELETED Cmhandle State - `CPS-1102 <https://lf-onap.atlassian.net/browse/CPS-1102>`_ Register the Cmhandle Sends Advised State notification. - - `CPS-1133 <https://lf-onap.atlassian.net/browse/CPS-1133>`_ Enable/Disable Data Sync for Cm Handle + - `CPS-1133 <https://lf-onap.atlassian.net/browse/CPS-1133>`_ Enable/Disable Data Sync for CM Handle - `CPS-1136 <https://lf-onap.atlassian.net/browse/CPS-1136>`_ DMI Audit Support (get all CM Handles for a registered DMI) @@ -1379,27 +1302,27 @@ Features - `CPS-559 <https://lf-onap.atlassian.net/browse/CPS-559>`_ Define response objects (schemas) in cps-ncmp - `CPS-636 <https://lf-onap.atlassian.net/browse/CPS-636>`_ Update operation for datastore pass through running - `CPS-638 <https://lf-onap.atlassian.net/browse/CPS-638>`_ Delete operation for datastore pass through running - - `CPS-677 <https://lf-onap.atlassian.net/browse/CPS-677>`_ Support 'public' Cm Handle Properties - - `CPS-741 <https://lf-onap.atlassian.net/browse/CPS-741>`_ Re sync after removing cm handles + - `CPS-677 <https://lf-onap.atlassian.net/browse/CPS-677>`_ Support 'public' CM Handle Properties + - `CPS-741 <https://lf-onap.atlassian.net/browse/CPS-741>`_ Re sync after removing CM Handles - `CPS-777 <https://lf-onap.atlassian.net/browse/CPS-777>`_ Ensure all DMI operations use POST method - `CPS-780 <https://lf-onap.atlassian.net/browse/CPS-780>`_ Add examples for parameters, request and response in openapi yaml for cps-core - `CPS-789 <https://lf-onap.atlassian.net/browse/CPS-789>`_ CPS Data Updated Event Schema V2 to support delete operation - `CPS-791 <https://lf-onap.atlassian.net/browse/CPS-791>`_ CPS-Core sends delete notification event - - `CPS-817 <https://lf-onap.atlassian.net/browse/CPS-817>`_ Create Endpoint For Get Cm Handles (incl. public properties) By Name + - `CPS-817 <https://lf-onap.atlassian.net/browse/CPS-817>`_ Create Endpoint For Get CM Handles (incl. public properties) By Name - `CPS-837 <https://lf-onap.atlassian.net/browse/CPS-837>`_ Add Remove and Update properties (DMI and Public) as part of CM Handle Registration update Bug Fixes --------- - - `CPS-762 <https://lf-onap.atlassian.net/browse/CPS-762>`_ Query cm handles for module names returns incorrect cm handle identifiers + - `CPS-762 <https://lf-onap.atlassian.net/browse/CPS-762>`_ Query CM Handles for module names returns incorrect CM Handle identifiers - `CPS-788 <https://lf-onap.atlassian.net/browse/CPS-788>`_ Yang Resource formatting is incorrect - - `CPS-783 <https://lf-onap.atlassian.net/browse/CPS-783>`_ Remove cm handle does not completely remove all cm handle information + - `CPS-783 <https://lf-onap.atlassian.net/browse/CPS-783>`_ Remove CM Handle does not completely remove all CM Handle information - `CPS-841 <https://lf-onap.atlassian.net/browse/CPS-841>`_ Upgrade log4j to 2.17.1 as recommended by ONAP SECCOM - `CPS-856 <https://lf-onap.atlassian.net/browse/CPS-856>`_ Retry mechanism not working for concurrent CmHandle registration - `CPS-867 <https://lf-onap.atlassian.net/browse/CPS-867>`_ Database port made configurable through env variable DB_PORT - `CPS-886 <https://lf-onap.atlassian.net/browse/CPS-886>`_ Fragment handling decreasing performance for large number of cmHandles - `CPS-887 <https://lf-onap.atlassian.net/browse/CPS-887>`_ Increase performance of cmHandle registration for large number of schema sets in DB - - `CPS-892 <https://lf-onap.atlassian.net/browse/CPS-892>`_ Fixed the response code during CM-Handle Registration from 201 CREATED to 204 NO_CONTENT + - `CPS-892 <https://lf-onap.atlassian.net/browse/CPS-892>`_ Fixed the response code during CM Handle Registration from 201 CREATED to 204 NO_CONTENT - `CPS-893 <https://lf-onap.atlassian.net/browse/CPS-893>`_ NCMP Java API depends on NCMP-Rest-API (cyclic) through json properties on Java API Known Limitations, Issues and Workarounds @@ -1407,9 +1330,9 @@ Known Limitations, Issues and Workarounds *System Limitations* -Null can no longer be passed within the dmi plugin service names when registering a cm handle, as part of +Null can no longer be passed within the dmi plugin service names when registering a CM Handle, as part of `CPS-837 <https://lf-onap.atlassian.net/browse/CPS-837>`_ null is now used to indicate if a property should be removed as part -of cm handle registration. +of CM Handle registration. The Absolute path to list with integer key will not work. Please refer `CPS-961 <https://lf-onap.atlassian.net/browse/CPS-961>`_ for more information. diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy index b9b1c162e7..3f7b25d2fa 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy @@ -158,11 +158,12 @@ abstract class CpsIntegrationSpecBase extends Specification { static initialized = false def now = OffsetDateTime.now() + enum ModuleNameStrategy { UNIQUE, OVERLAPPING } + def setup() { if (!initialized) { cpsDataspaceService.createDataspace(GENERAL_TEST_DATASPACE) createStandardBookStoreSchemaSet(GENERAL_TEST_DATASPACE) - cpsAnchorService.createAnchor(GENERAL_TEST_DATASPACE, BOOKSTORE_SCHEMA_SET, 'owner-of-bookstore-schema-set-do-not-delete') initialized = true } mockDmiServer1.setDispatcher(dmiDispatcher1) @@ -182,7 +183,7 @@ abstract class CpsIntegrationSpecBase extends Specification { mockDmiServer1.shutdown() mockDmiServer2.shutdown() mockPolicyServer.shutdown() - cpsModuleService.deleteAllUnusedYangModuleData() + cpsModuleService.deleteAllUnusedYangModuleData('NFP-Operational') } def static readResourceDataFile(filename) { @@ -265,9 +266,14 @@ abstract class CpsIntegrationSpecBase extends Specification { } def registerSequenceOfCmHandlesWithManyModuleReferencesButDoNotWaitForReady(dmiPlugin, moduleSetTag, numberOfCmHandles, offset) { + registerSequenceOfCmHandlesWithManyModuleReferencesButDoNotWaitForReady(dmiPlugin, moduleSetTag, numberOfCmHandles, offset, ModuleNameStrategy.UNIQUE) + } + + def registerSequenceOfCmHandlesWithManyModuleReferencesButDoNotWaitForReady(dmiPlugin, moduleSetTag, numberOfCmHandles, offset, ModuleNameStrategy moduleNameStrategy ) { def cmHandles = [] def id = offset - def moduleReferences = (1..200).collect { "${moduleSetTag}Module${it}" } + def modulePrefix = moduleNameStrategy.OVERLAPPING.equals(moduleNameStrategy) ? 'same' : moduleSetTag + def moduleReferences = (1..200).collect { "${modulePrefix}Module${it}" } (1..numberOfCmHandles).each { def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: "ch-${id}", moduleSetTag: moduleSetTag, alternateId: NO_ALTERNATE_ID) cmHandles.add(ncmpServiceCmHandle) diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/AnchorServiceIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/AnchorServiceIntegrationSpec.groovy index 2bd5a4a1be..ca321119ea 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/AnchorServiceIntegrationSpec.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/AnchorServiceIntegrationSpec.groovy @@ -59,17 +59,17 @@ class AnchorServiceIntegrationSpec extends FunctionalSpecBase { and: '1 anchor with "other" schema set is created' createStandardBookStoreSchemaSet(GENERAL_TEST_DATASPACE, 'otherSchemaSet') objectUnderTest.createAnchor(GENERAL_TEST_DATASPACE, 'otherSchemaSet', 'anchor3') - then: 'there are 4 anchors in the general test database' - assert objectUnderTest.getAnchors(GENERAL_TEST_DATASPACE).size() == 4 - and: 'there are 3 anchors associated with bookstore schema set' - assert objectUnderTest.getAnchorsBySchemaSetName(GENERAL_TEST_DATASPACE, BOOKSTORE_SCHEMA_SET).size() == 3 + then: 'there are 3 anchors in the general test database' + assert objectUnderTest.getAnchors(GENERAL_TEST_DATASPACE).size() == 3 + and: 'there are 2 anchors associated with bookstore schema set' + assert objectUnderTest.getAnchorsBySchemaSetName(GENERAL_TEST_DATASPACE, BOOKSTORE_SCHEMA_SET).size() == 2 and: 'there is 1 anchor associated with other schema set' assert objectUnderTest.getAnchorsBySchemaSetName(GENERAL_TEST_DATASPACE, 'otherSchemaSet').size() == 1 } def 'Querying anchor(name)s (depends on previous test!).'() { - expect: 'there are now 4 anchors using the "stores" module (both schema sets use the same modules) ' - assert objectUnderTest.queryAnchorNames(GENERAL_TEST_DATASPACE, ['stores', 'bookstore-types']).size() == 4 + expect: 'there are now 3 anchors using the "stores" module (both schema sets use the same modules)' + assert objectUnderTest.queryAnchorNames(GENERAL_TEST_DATASPACE, ['stores', 'bookstore-types']).size() == 3 and: 'there are no anchors using both "stores" and a "unused-model"' assert objectUnderTest.queryAnchorNames(GENERAL_TEST_DATASPACE, ['stores', 'unused-model']).size() == 0 } diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/DataspaceServiceIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/DataspaceServiceIntegrationSpec.groovy index 178b0227ca..47a332adc9 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/DataspaceServiceIntegrationSpec.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/DataspaceServiceIntegrationSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2023 Nordix Foundation + * Copyright (C) 2023-2025 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the 'License'); * you may not use this file except in compliance with the License. @@ -32,8 +32,6 @@ class DataspaceServiceIntegrationSpec extends FunctionalSpecBase { def setup() { objectUnderTest = cpsDataspaceService } - def cleanup() { cpsModuleService.deleteAllUnusedYangModuleData() } - def 'Dataspace CRUD operations.'() { when: 'a dataspace is created' objectUnderTest.createDataspace('newDataspace') diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/ModuleServiceIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/ModuleServiceIntegrationSpec.groovy index d8010875c1..c787b4209e 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/ModuleServiceIntegrationSpec.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/cps/ModuleServiceIntegrationSpec.groovy @@ -61,8 +61,6 @@ class ModuleServiceIntegrationSpec extends FunctionalSpecBase { def setup() { objectUnderTest = cpsModuleService } - def cleanup() { objectUnderTest.deleteAllUnusedYangModuleData() } - /* C R E A T E S C H E M A S E T U S E - C A S E S */ diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleCreateSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleCreateSpec.groovy index 6f063fb222..c4946b48b9 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleCreateSpec.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleCreateSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2024 Nordix Foundation + * Copyright (C) 2024-2025 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the 'License'); * you may not use this file except in compliance with the License. @@ -178,9 +178,9 @@ class CmHandleCreateSpec extends CpsIntegrationSpecBase { assert dmiPluginRegistrationResponse.createdCmHandles.sort { it.cmHandle } == [ CmHandleRegistrationResponse.createSuccessResponse('ch-3'), CmHandleRegistrationResponse.createSuccessResponse('ch-4'), - CmHandleRegistrationResponse.createFailureResponse('ch-5', NcmpResponseStatus.ALTERNATE_ID_ALREADY_ASSOCIATED), + CmHandleRegistrationResponse.createFailureResponse('ch-5', NcmpResponseStatus.CM_HANDLE_ALREADY_EXIST), CmHandleRegistrationResponse.createSuccessResponse('ch-6'), - CmHandleRegistrationResponse.createFailureResponse('ch-7', NcmpResponseStatus.ALTERNATE_ID_ALREADY_ASSOCIATED), + CmHandleRegistrationResponse.createFailureResponse('ch-7', NcmpResponseStatus.CM_HANDLE_ALREADY_EXIST), ] cleanup: 'deregister CM handles' diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleUpdateSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleUpdateSpec.groovy index f2593ce587..22bbaa81df 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleUpdateSpec.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleUpdateSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2024 Nordix Foundation + * Copyright (C) 2024-2025 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the 'License'); * you may not use this file except in compliance with the License. @@ -76,8 +76,8 @@ class CmHandleUpdateSpec extends CpsIntegrationSpecBase { def dmiPluginRegistrationResponse = objectUnderTest.updateDmiRegistration(new DmiPluginRegistration(dmiPlugin: DMI1_URL, updatedCmHandles: [cmHandleToUpdate])) - then: 'registration gives failure response, due to alternate ID being already associated' - assert dmiPluginRegistrationResponse.updatedCmHandles == [CmHandleRegistrationResponse.createFailureResponse('ch-1', NcmpResponseStatus.ALTERNATE_ID_ALREADY_ASSOCIATED)] + then: 'registration gives failure response, due to cm-handle already existing' + assert dmiPluginRegistrationResponse.updatedCmHandles == [CmHandleRegistrationResponse.createFailureResponse('ch-1', NcmpResponseStatus.CM_HANDLE_ALREADY_EXIST)] and: 'the CM-handle still has the old alternate ID' assert objectUnderTest.getNcmpServiceCmHandle('ch-1').alternateId == 'original' diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleUpgradeSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleUpgradeSpec.groovy index 28714fd123..097a043556 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleUpgradeSpec.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleUpgradeSpec.groovy @@ -79,7 +79,6 @@ class CmHandleUpgradeSpec extends CpsIntegrationSpecBase { cleanup: 'deregister CM-handle and remove all associated module resources' deregisterCmHandle(DMI1_URL, cmHandleId) - cpsModuleService.deleteAllUnusedYangModuleData() where: 'following module set tags are used' initialModuleSetTag | updatedModuleSetTag diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/ModuleSyncWatchdogIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/ModuleSyncWatchdogIntegrationSpec.groovy index 43db9b208e..81fbc3c4f7 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/ModuleSyncWatchdogIntegrationSpec.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/ModuleSyncWatchdogIntegrationSpec.groovy @@ -20,17 +20,18 @@ package org.onap.cps.integration.functional.ncmp +import com.hazelcast.map.IMap import io.micrometer.core.instrument.MeterRegistry -import spock.lang.Ignore - -import java.util.concurrent.Executors -import java.util.concurrent.TimeUnit import org.onap.cps.integration.base.CpsIntegrationSpecBase import org.onap.cps.ncmp.impl.inventory.sync.ModuleSyncWatchdog import org.springframework.beans.factory.annotation.Autowired import org.springframework.util.StopWatch +import spock.lang.Ignore import spock.util.concurrent.PollingConditions +import java.util.concurrent.Executors +import java.util.concurrent.TimeUnit + class ModuleSyncWatchdogIntegrationSpec extends CpsIntegrationSpecBase { ModuleSyncWatchdog objectUnderTest @@ -38,11 +39,15 @@ class ModuleSyncWatchdogIntegrationSpec extends CpsIntegrationSpecBase { @Autowired MeterRegistry meterRegistry + @Autowired + IMap<String, Integer> cmHandlesByState + def executorService = Executors.newFixedThreadPool(2) def PARALLEL_SYNC_SAMPLE_SIZE = 100 def setup() { objectUnderTest = moduleSyncWatchdog + clearCmHandleStateGauge() } def cleanup() { @@ -64,18 +69,16 @@ class ModuleSyncWatchdogIntegrationSpec extends CpsIntegrationSpecBase { deregisterSequenceOfCmHandles(DMI1_URL, PARALLEL_SYNC_SAMPLE_SIZE, 1) } - @Ignore - /** this test has intermittent failures, due to timeouts. + /** this test has intermittent failures, due to race conditions * Ignored but left here as it might be valuable to further optimization investigations. **/ - + @Ignore def 'CPS-2478 Highlight (and improve) module sync inefficiencies.'() { given: 'register 250 cm handles with module set tag cps-2478-A' def numberOfTags = 2 def cmHandlesPerTag = 250 def totalCmHandles = numberOfTags * cmHandlesPerTag def offset = 1 - def minimumBatches = totalCmHandles / 100 registerSequenceOfCmHandlesWithManyModuleReferencesButDoNotWaitForReady(DMI1_URL, 'cps-2478-A', cmHandlesPerTag, offset) and: 'register anther 250 cm handles with module set tag cps-2478-B' offset += cmHandlesPerTag @@ -85,23 +88,21 @@ class ModuleSyncWatchdogIntegrationSpec extends CpsIntegrationSpecBase { when: 'sync all advised cm handles' objectUnderTest.moduleSyncAdvisedCmHandles() Thread.sleep(100) - then: 'retry until both schema sets are stored in db (1 schema set for each module set tag)' - def dbSchemaSetStorageTimer = meterRegistry.get('cps.module.persistence.schemaset.store').timer() - new PollingConditions().within(10, () -> { - objectUnderTest.moduleSyncAdvisedCmHandles() - Thread.sleep(100) - assert dbSchemaSetStorageTimer.count() == 2 - }) - then: 'wait till at least 5 batches of state updates are done (often more because of retries of locked cm handles)' - def dbStateUpdateTimer = meterRegistry.get('cps.ncmp.cmhandle.state.update.batch').timer() + then: 'Keep processing until there are no more LOCKED or ADVISED cm handles' new PollingConditions().within(10, () -> { - assert dbStateUpdateTimer.count() >= minimumBatches + def advised = cmHandlesByState.get('advisedCmHandlesCount') + def locked = cmHandlesByState.get('lockedCmHandlesCount') + if ( locked > 0 | advised > 0 ) { + println "CPS-2576 Need to retry ${locked} LOCKED / ${advised} ADVISED cm Handles" + objectUnderTest.moduleSyncAdvisedCmHandles() + Thread.sleep(100) + } + assert cmHandlesByState.get('lockedCmHandlesCount') + cmHandlesByState.get('advisedCmHandlesCount') == 0 }) - and: 'one call to DMI per module set tag to get module references (may be more due to parallel processing of batches)' - def dmiModuleRetrievalTimer = meterRegistry.get('cps.ncmp.inventory.module.references.from.dmi').timer() - assert dmiModuleRetrievalTimer.count() >= numberOfTags && dmiModuleRetrievalTimer.count() <= minimumBatches - and: 'log the relevant instrumentation' + def dmiModuleRetrievalTimer = meterRegistry.get('cps.ncmp.inventory.module.references.from.dmi').timer() + def dbSchemaSetStorageTimer = meterRegistry.get('cps.module.persistence.schemaset.store').timer() + def dbStateUpdateTimer = meterRegistry.get('cps.ncmp.cmhandle.state.update.batch').timer() logInstrumentation(dmiModuleRetrievalTimer, 'get modules from DMI ') logInstrumentation(dbSchemaSetStorageTimer, 'store schema sets ') logInstrumentation(dbStateUpdateTimer, 'batch state updates ') @@ -110,7 +111,6 @@ class ModuleSyncWatchdogIntegrationSpec extends CpsIntegrationSpecBase { def stopWatch = new StopWatch() stopWatch.start() deregisterSequenceOfCmHandles(DMI1_URL, totalCmHandles, 1) - cpsModuleService.deleteAllUnusedYangModuleData() stopWatch.stop() println "*** CPS-2478, Deletion of $totalCmHandles cm handles took ${stopWatch.getTotalTimeMillis()} milliseconds" } @@ -131,6 +131,30 @@ class ModuleSyncWatchdogIntegrationSpec extends CpsIntegrationSpecBase { deregisterSequenceOfCmHandles(DMI1_URL, PARALLEL_SYNC_SAMPLE_SIZE, 1) } + /** this test has intermittent failures, due to race conditions + * Ignored but left here as it might be valuable to further optimization investigations. + **/ + @Ignore + def 'Schema sets with overlapping modules processed at the same time (DB constraint violation).'() { + given: 'register one batch (100) cm handles of tag A (with overlapping module names)' + registerSequenceOfCmHandlesWithManyModuleReferencesButDoNotWaitForReady(DMI1_URL, 'tagA', 100, 1, ModuleNameStrategy.OVERLAPPING) + and: 'register another batch cm handles of tag B (with overlapping module names)' + registerSequenceOfCmHandlesWithManyModuleReferencesButDoNotWaitForReady(DMI1_URL, 'tagB', 100, 101, ModuleNameStrategy.OVERLAPPING) + and: 'populate the work queue with both batches' + objectUnderTest.populateWorkQueueIfNeeded() + when: 'advised cm handles are processed on 2 threads (exactly one batch for each)' + objectUnderTest.moduleSyncAdvisedCmHandles() + executorService.execute(moduleSyncAdvisedCmHandles) + then: 'wait till all cm handles have been processed' + new PollingConditions().within(10, () -> { + assert getNumberOfProcessedCmHandles() == 200 + }) + then: 'at least 1 cm handle is in state LOCKED' + assert cmHandlesByState.get('lockedCmHandlesCount') >= 1 + cleanup: 'remove all test cm handles' + deregisterSequenceOfCmHandles(DMI1_URL, 200, 1) + } + def 'Populate module sync work queue on two parallel threads with a slight difference in start time.'() { // This test proved that the issue in CPS-2403 did not arise if the the queue was populated and given time to be distributed given: 'the queue is empty at the start' @@ -169,4 +193,21 @@ class ModuleSyncWatchdogIntegrationSpec extends CpsIntegrationSpecBase { } } + def moduleSyncAdvisedCmHandles = () -> { + try { + objectUnderTest.moduleSyncAdvisedCmHandles() + } catch (InterruptedException e) { + e.printStackTrace() + } + } + + def clearCmHandleStateGauge() { + cmHandlesByState.keySet().each { cmHandlesByState.put(it, 0)} + } + + def getNumberOfProcessedCmHandles() { + return cmHandlesByState.get('readyCmHandlesCount') + cmHandlesByState.get('lockedCmHandlesCount') + } + + } diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/ModuleQueryPerfTest.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/ModuleQueryPerfTest.groovy index 613f760b0c..e52d3f819c 100644 --- a/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/ModuleQueryPerfTest.groovy +++ b/integration-test/src/test/groovy/org/onap/cps/integration/performance/cps/ModuleQueryPerfTest.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2024 Nordix Foundation + * Copyright (C) 2024-2025 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -100,7 +100,7 @@ class ModuleQueryPerfTest extends CpsPerfTestBase { cpsModuleService.deleteSchemaSetsWithCascade(CPS_PERFORMANCE_TEST_DATASPACE, (i..i+100).collect {SCHEMA_SET_PREFIX + it}) } cpsModuleService.deleteSchemaSetsWithCascade(CPS_PERFORMANCE_TEST_DATASPACE, [SCHEMA_SET_PREFIX + '0']) - cpsModuleService.deleteAllUnusedYangModuleData() + cpsModuleService.deleteAllUnusedYangModuleData(CPS_PERFORMANCE_TEST_DATASPACE) } // This makes a Yang module of approximately target length in bytes by padding the description field with many '*' diff --git a/k6-tests/ncmp/common/utils.js b/k6-tests/ncmp/common/utils.js index 66d2dfe448..6bedb1f949 100644 --- a/k6-tests/ncmp/common/utils.js +++ b/k6-tests/ncmp/common/utils.js @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2024 Nordix Foundation + * Copyright (C) 2024-2025 Nordix Foundation * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,7 +26,7 @@ export const NCMP_BASE_URL = testConfig.hosts.ncmpBaseUrl; export const DMI_PLUGIN_URL = testConfig.hosts.dmiStubUrl; export const CONTAINER_UP_TIME_IN_SECONDS = testConfig.hosts.containerUpTimeInSeconds; export const LEGACY_BATCH_TOPIC_NAME = 'legacy_batch_topic'; -export const TOTAL_CM_HANDLES = 20000; +export const TOTAL_CM_HANDLES = 50000; export const REGISTRATION_BATCH_SIZE = 100; export const READ_DATA_FOR_CM_HANDLE_DELAY_MS = 300; // must have same value as in docker-compose.yml export const WRITE_DATA_FOR_CM_HANDLE_DELAY_MS = 670; // must have same value as in docker-compose.yml |