aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/main/java/org/onap/cps/ncmp/rest/stub/controller/NetworkCmProxyStubController.java6
-rw-r--r--cps-ncmp-rest/docs/openapi/components.yaml18
-rwxr-xr-xcps-ncmp-rest/docs/openapi/ncmp.yml12
-rwxr-xr-xcps-ncmp-rest/docs/openapi/openapi.yml4
-rwxr-xr-xcps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java35
-rw-r--r--cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy102
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java14
-rwxr-xr-xcps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java13
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistence.java12
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImpl.java9
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleOperationsUtils.java9
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncService.java5
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/CmHandleIdMapper.java8
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy17
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy21
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImplSpec.groovy18
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleOperationsUtilsSpec.groovy7
-rwxr-xr-xcps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java32
-rw-r--r--cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceRepository.java9
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/CpsModuleService.java14
-rw-r--r--cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java11
-rwxr-xr-xcps-service/src/main/java/org/onap/cps/spi/CpsModulePersistenceService.java14
-rw-r--r--cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy18
-rw-r--r--dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/bookStoreAWithModules_M1_M2_ResourcesResponse.json12
-rw-r--r--dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/bookStoreAWithModules_M1_M2_Response.json12
-rw-r--r--dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/bookStoreBWithModules_M1_M3_ResourcesResponse.json12
-rw-r--r--dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/bookStoreBWithModules_M1_M3_Response.json12
-rw-r--r--dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/bookStoreCWithModules_M1_M2_ResourcesResponse.json12
-rw-r--r--dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/bookStoreCWithModules_M1_M2_Response.json12
-rw-r--r--docker-compose/docker-compose.yml18
-rw-r--r--docs/_static/cps-delta-mechanism.pngbin0 -> 69416 bytes
-rw-r--r--docs/cps-delta-endpoints.rst66
-rw-r--r--docs/cps-delta-feature.rst44
-rw-r--r--docs/modeling.rst8
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsModuleServiceIntegrationSpec.groovy14
35 files changed, 534 insertions, 96 deletions
diff --git a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/main/java/org/onap/cps/ncmp/rest/stub/controller/NetworkCmProxyStubController.java b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/main/java/org/onap/cps/ncmp/rest/stub/controller/NetworkCmProxyStubController.java
index e33af45f9..0e4f7f987 100644
--- a/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/main/java/org/onap/cps/ncmp/rest/stub/controller/NetworkCmProxyStubController.java
+++ b/cps-ncmp-rest-stub/cps-ncmp-rest-stub-service/src/main/java/org/onap/cps/ncmp/rest/stub/controller/NetworkCmProxyStubController.java
@@ -1,7 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2022 Bell Canada
- * Modifications Copyright (c) 2022-2023 Nordix Foundation
+ * Modifications Copyright (c) 2022-2024 Nordix Foundation
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -167,7 +167,9 @@ public class NetworkCmProxyStubController implements NetworkCmProxyApi {
}
@Override
- public ResponseEntity<List<RestModuleDefinition>> getModuleDefinitionsByCmHandleId(final String cmHandle) {
+ public ResponseEntity<List<RestModuleDefinition>> getModuleDefinitions(final String cmHandleId,
+ final String moduleName,
+ final String revision) {
return new ResponseEntity<>(HttpStatus.NOT_IMPLEMENTED);
}
diff --git a/cps-ncmp-rest/docs/openapi/components.yaml b/cps-ncmp-rest/docs/openapi/components.yaml
index 3bee63390..6b53292af 100644
--- a/cps-ncmp-rest/docs/openapi/components.yaml
+++ b/cps-ncmp-rest/docs/openapi/components.yaml
@@ -1,5 +1,5 @@
# ============LICENSE_START=======================================================
-# Copyright (C) 2021-2023 Nordix Foundation
+# Copyright (C) 2021-2024 Nordix Foundation
# Modifications Copyright (C) 2021 Pantheon.tech
# Modifications Copyright (C) 2022 Bell Canada
# ================================================================================
@@ -492,6 +492,22 @@ components:
schema:
type: string
example: my-cm-handle
+ moduleNameInQuery:
+ name: module-name
+ in: query
+ description: Filter for a module name.This is an optional parameter
+ required: false
+ schema:
+ type: string
+ example: my-module
+ revisionInQuery:
+ name: revision
+ in: query
+ description: Filter for a module revision.This is an optional parameter and ignored when no module name is supplied
+ required: false
+ schema:
+ type: string
+ example: 2024-01-22
dataSyncEnabled:
name: dataSyncEnabled
in: query
diff --git a/cps-ncmp-rest/docs/openapi/ncmp.yml b/cps-ncmp-rest/docs/openapi/ncmp.yml
index 95ca6ccdc..2f90155cb 100755
--- a/cps-ncmp-rest/docs/openapi/ncmp.yml
+++ b/cps-ncmp-rest/docs/openapi/ncmp.yml
@@ -1,5 +1,5 @@
# ============LICENSE_START=======================================================
-# Copyright (C) 2021-2023 Nordix Foundation
+# Copyright (C) 2021-2024 Nordix Foundation
# Modifications Copyright (C) 2021 Pantheon.tech
# Modifications Copyright (C) 2021-2022 Bell Canada
# ================================================================================
@@ -289,15 +289,17 @@ fetchModuleReferencesByCmHandle:
500:
$ref: 'components.yaml#/components/responses/InternalServerError'
-fetchModuleDefinitionsByCmHandle:
+getModuleDefinitions:
get:
- description: Fetch all module definitions (name, revision, yang resource) for a given cm handle
tags:
- network-cm-proxy
- summary: Fetch all module definitions (name, revision, yang resource) for a given cm handle
- operationId: getModuleDefinitionsByCmHandleId
+ summary: Get module definitions
+ description: Get module definitions (module name, revision, yang resource) with options to filter on module name and revision
+ operationId: getModuleDefinitions
parameters:
- $ref: 'components.yaml#/components/parameters/cmHandleInPath'
+ - $ref: 'components.yaml#/components/parameters/moduleNameInQuery'
+ - $ref: 'components.yaml#/components/parameters/revisionInQuery'
responses:
200:
description: OK
diff --git a/cps-ncmp-rest/docs/openapi/openapi.yml b/cps-ncmp-rest/docs/openapi/openapi.yml
index 7ceb4fe70..dd6d7c8ba 100755
--- a/cps-ncmp-rest/docs/openapi/openapi.yml
+++ b/cps-ncmp-rest/docs/openapi/openapi.yml
@@ -1,5 +1,5 @@
# ============LICENSE_START=======================================================
-# Copyright (C) 2021-2023 Nordix Foundation
+# Copyright (C) 2021-2024 Nordix Foundation
# Modifications Copyright (C) 2021 Pantheon.tech
# Modifications Copyright (C) 2021 Bell Canada
# ================================================================================
@@ -44,7 +44,7 @@ paths:
$ref: 'ncmp.yml#/fetchModuleReferencesByCmHandle'
/v1/ch/{cm-handle}/modules/definitions:
- $ref: 'ncmp.yml#/fetchModuleDefinitionsByCmHandle'
+ $ref: 'ncmp.yml#/getModuleDefinitions'
/v1/ch/searches:
$ref: 'ncmp.yml#/searchCmHandles'
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java
index be33c6a01..6ec24448d 100755
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java
+++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java
@@ -1,7 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2021 Pantheon.tech
- * Modifications Copyright (C) 2021-2023 Nordix Foundation
+ * Modifications Copyright (C) 2021-2024 Nordix Foundation
* Modifications Copyright (C) 2021 highstreet technologies GmbH
* Modifications Copyright (C) 2021-2022 Bell Canada
* ================================================================================
@@ -31,6 +31,7 @@ import static org.onap.cps.ncmp.api.impl.operations.OperationType.PATCH;
import static org.onap.cps.ncmp.api.impl.operations.OperationType.UPDATE;
import io.micrometer.core.annotation.Timed;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -59,9 +60,11 @@ import org.onap.cps.ncmp.rest.model.RestOutputCmHandle;
import org.onap.cps.ncmp.rest.model.RestOutputCmHandleCompositeState;
import org.onap.cps.ncmp.rest.model.RestOutputCmHandlePublicProperties;
import org.onap.cps.ncmp.rest.util.DeprecationHelper;
+import org.onap.cps.spi.model.ModuleDefinition;
import org.onap.cps.utils.JsonObjectMapper;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
+import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@@ -317,18 +320,32 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
}
/**
- * Return module definitions for a cm handle.
+ * Return module definitions.
*
- * @param cmHandleId cm-handle identifier
+ * @param cmHandleId cm-handle identifier
+ * @param moduleName module name
+ * @param revision the revision of the module
* @return list of module definitions (module name, revision, yang resource content)
*/
@Override
- public ResponseEntity<List<RestModuleDefinition>> getModuleDefinitionsByCmHandleId(final String cmHandleId) {
- final List<RestModuleDefinition> restModuleDefinitions =
- networkCmProxyDataService.getModuleDefinitionsByCmHandleId(cmHandleId).stream()
- .map(ncmpRestInputMapper::toRestModuleDefinition)
- .collect(Collectors.toList());
- return new ResponseEntity<>(restModuleDefinitions, HttpStatus.OK);
+ public ResponseEntity<List<RestModuleDefinition>> getModuleDefinitions(final String cmHandleId,
+ final String moduleName,
+ final String revision) {
+ final Collection<ModuleDefinition> moduleDefinitions;
+ if (StringUtils.hasText(moduleName)) {
+ moduleDefinitions =
+ networkCmProxyDataService.getModuleDefinitionsByCmHandleAndModule(cmHandleId, moduleName, revision);
+ } else {
+ moduleDefinitions = networkCmProxyDataService.getModuleDefinitionsByCmHandleId(cmHandleId);
+ if (StringUtils.hasText(revision)) {
+ log.warn("Ignoring revision filter as no module name is provided");
+ }
+ }
+ final List<RestModuleDefinition> response = new ArrayList<>();
+ for (final ModuleDefinition moduleDefinition: moduleDefinitions) {
+ response.add(ncmpRestInputMapper.toRestModuleDefinition(moduleDefinition));
+ }
+ return new ResponseEntity<>(response, HttpStatus.OK);
}
/**
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
index 314a0b221..983f2438c 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy
@@ -2,7 +2,7 @@
* ============LICENSE_START=======================================================
* Copyright (C) 2021 Pantheon.tech
* Modifications Copyright (C) 2021 highstreet technologies GmbH
- * Modifications Copyright (C) 2021-2023 Nordix Foundation
+ * Modifications Copyright (C) 2021-2024 Nordix Foundation
* Modifications Copyright (C) 2021-2022 Bell Canada.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,26 +23,14 @@
package org.onap.cps.ncmp.rest.controller
-import static org.onap.cps.ncmp.api.impl.inventory.CompositeState.DataStores
-import static org.onap.cps.ncmp.api.impl.inventory.CompositeState.Operational
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch
-import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.CREATE
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.UPDATE
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.PATCH
-import static org.onap.cps.ncmp.api.impl.operations.OperationType.DELETE
-import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_OPERATIONAL
-import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING
-import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.OPERATIONAL
-import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
-import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
-
+import ch.qos.logback.classic.Level
+import ch.qos.logback.classic.Logger
+import ch.qos.logback.classic.spi.ILoggingEvent
+import ch.qos.logback.core.read.ListAppender
import com.fasterxml.jackson.databind.ObjectMapper
import org.mapstruct.factory.Mappers
import org.onap.cps.TestUtils
+import org.onap.cps.events.EventsPublisher
import org.onap.cps.ncmp.api.NetworkCmProxyDataService
import org.onap.cps.ncmp.api.NetworkCmProxyQueryService
import org.onap.cps.ncmp.api.impl.inventory.CmHandleState
@@ -50,19 +38,20 @@ import org.onap.cps.ncmp.api.impl.inventory.CompositeState
import org.onap.cps.ncmp.api.impl.inventory.DataStoreSyncState
import org.onap.cps.ncmp.api.impl.inventory.LockReasonCategory
import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel
-import org.onap.cps.ncmp.rest.model.DataOperationRequest
-import org.onap.cps.ncmp.rest.model.DataOperationDefinition
import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle
import org.onap.cps.ncmp.rest.controller.handlers.NcmpCachedResourceRequestHandler
import org.onap.cps.ncmp.rest.controller.handlers.NcmpPassthroughResourceRequestHandler
import org.onap.cps.ncmp.rest.executor.CpsNcmpTaskExecutor
import org.onap.cps.ncmp.rest.mapper.CmHandleStateMapper
import org.onap.cps.ncmp.rest.mapper.DataOperationRequestMapper
+import org.onap.cps.ncmp.rest.model.DataOperationDefinition
+import org.onap.cps.ncmp.rest.model.DataOperationRequest
import org.onap.cps.ncmp.rest.util.DeprecationHelper
import org.onap.cps.spi.FetchDescendantsOption
import org.onap.cps.spi.model.ModuleDefinition
import org.onap.cps.spi.model.ModuleReference
import org.onap.cps.utils.JsonObjectMapper
+import org.slf4j.LoggerFactory
import org.spockframework.spring.SpringBean
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.beans.factory.annotation.Value
@@ -72,10 +61,28 @@ import org.springframework.http.MediaType
import org.springframework.test.web.servlet.MockMvc
import spock.lang.Shared
import spock.lang.Specification
+
import java.time.OffsetDateTime
import java.time.ZoneOffset
import java.time.format.DateTimeFormatter
+import static org.onap.cps.ncmp.api.impl.inventory.CompositeState.DataStores
+import static org.onap.cps.ncmp.api.impl.inventory.CompositeState.Operational
+import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.OPERATIONAL
+import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_OPERATIONAL
+import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RUNNING
+import static org.onap.cps.ncmp.api.impl.operations.OperationType.CREATE
+import static org.onap.cps.ncmp.api.impl.operations.OperationType.DELETE
+import static org.onap.cps.ncmp.api.impl.operations.OperationType.PATCH
+import static org.onap.cps.ncmp.api.impl.operations.OperationType.UPDATE
+import static org.onap.cps.spi.FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS
+import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS
+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.patch
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post
+import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put
+
@WebMvcTest(NetworkCmProxyController)
class NetworkCmProxyControllerSpec extends Specification {
@@ -130,11 +137,18 @@ class NetworkCmProxyControllerSpec extends Specification {
def NO_REQUEST_ID = null
def TIMOUT_FOR_TEST = 1234
+ def logger = Spy(ListAppender<ILoggingEvent>)
+
def setup() {
ncmpCachedResourceRequestHandler.notificationFeatureEnabled = true
ncmpCachedResourceRequestHandler.timeOutInMilliSeconds = TIMOUT_FOR_TEST
ncmpPassthroughResourceRequestHandler.notificationFeatureEnabled = true
ncmpPassthroughResourceRequestHandler.timeOutInMilliSeconds = TIMOUT_FOR_TEST
+ setupLogger()
+ }
+
+ def cleanup() {
+ ((Logger) LoggerFactory.getLogger(EventsPublisher.class)).detachAndStopAllAppenders()
}
def 'Get Resource Data from pass-through operational.'() {
@@ -516,21 +530,46 @@ class NetworkCmProxyControllerSpec extends Specification {
':passthrough-running' | 'passthrough-running'
}
- def 'Get module definitions based on cmHandleId.'() {
- when: 'get module definition request is performed'
+ def 'Getting module definitions for a module'() {
+ when: 'get module definition request is performed with module name'
def response = mvc.perform(
- get("$ncmpBasePathV1/ch/some-cmhandle/modules/definitions"))
- .andReturn().response
- then: 'ncmp service method to get module definitions is called'
- mockNetworkCmProxyDataService.getModuleDefinitionsByCmHandleId('some-cmhandle')
- >> [new ModuleDefinition('sampleModuleName', '2021-10-03',
- 'module sampleModuleName{ sample module content }')]
+ get("$ncmpBasePathV1/ch/some-cmhandle/modules/definitions?module-name=sampleModuleName"))
+ .andReturn().response
+ then: 'ncmp service method is invoked with correct parameters'
+ mockNetworkCmProxyDataService.getModuleDefinitionsByCmHandleAndModule('some-cmhandle', 'sampleModuleName', _)
+ >> [new ModuleDefinition('sampleModuleName', '2021-10-03',
+ 'module sampleModuleName{ sample module content }')]
and: 'response contains an array with the module name, revision and content'
response.getContentAsString() == '[{"moduleName":"sampleModuleName","revision":"2021-10-03","content":"module sampleModuleName{ sample module content }"}]'
and: 'response returns an OK http code'
response.status == HttpStatus.OK.value()
}
+ def 'Getting module definitions filtering on #scenario'() {
+ when: 'get module definition request is performed'
+ def response = mvc.perform(
+ get("$ncmpBasePathV1/ch/some-cmhandle/modules/definitions?module-name=" + moduleName + "&revision=" + revision))
+ .andReturn().response
+ then: 'ncmp service method to get definitions by cm handle is invoked when needed'
+ numberOfCallsToByCmHandleId * mockNetworkCmProxyDataService.getModuleDefinitionsByCmHandleId('some-cmhandle') >> []
+ and: 'ncmp service method to get definitions by module is invoked when needed'
+ numberOfCallsToByModule * mockNetworkCmProxyDataService.getModuleDefinitionsByCmHandleAndModule('some-cmhandle', moduleName, revision) >> []
+ and: 'response returns an OK http code'
+ response.status == HttpStatus.OK.value()
+ and: 'the correct message is logged when needed'
+ if (expectLogWarning) {
+ def lastLoggingEvent = logger.list[0]
+ assert lastLoggingEvent.level == Level.WARN
+ assert lastLoggingEvent.formattedMessage.contains('Ignoring revision')
+ }
+ where: 'following parameters are used'
+ scenario | moduleName | revision || numberOfCallsToByCmHandleId | numberOfCallsToByModule | expectLogWarning
+ 'module name' | 'some-module' | '' || 0 | 1 | false
+ 'module name and revision' | 'some-module' | 'some-revision' || 0 | 1 | false
+ 'no filtering' | '' | '' || 1 | 0 | false
+ 'only revision' | '' | 'some-revision' || 1 | 0 | true
+ }
+
def 'Set the data sync enabled based on the cm handle id and the data sync flag is #scenario'() {
when: 'the set data sync enabled request is invoked'
def response = mvc.perform(
@@ -667,5 +706,12 @@ class NetworkCmProxyControllerSpec extends Specification {
return dataOperationDefinition
}
+ def setupLogger() {
+ def setupLogger = ((Logger) LoggerFactory.getLogger(NetworkCmProxyController.class))
+ setupLogger.setLevel(Level.DEBUG)
+ setupLogger.addAppender(logger)
+ logger.start()
+ }
+
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java
index 0c1287553..0c8474839 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/NetworkCmProxyDataService.java
@@ -1,7 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2021 highstreet technologies GmbH
- * Modifications Copyright (C) 2021-2023 Nordix Foundation
+ * Modifications Copyright (C) 2021-2024 Nordix Foundation
* Modifications Copyright (C) 2021 Pantheon.tech
* Modifications Copyright (C) 2022 Bell Canada
* ================================================================================
@@ -126,6 +126,18 @@ public interface NetworkCmProxyDataService {
Collection<ModuleDefinition> getModuleDefinitionsByCmHandleId(String cmHandleId);
/**
+ * Get module definitions for the given parameters.
+ *
+ * @param cmHandleId cm-handle identifier
+ * @param moduleName module name
+ * @param moduleRevision the revision of the module
+ * @return list of module definitions (module name, revision, yang resource content)
+ */
+ Collection<ModuleDefinition> getModuleDefinitionsByCmHandleAndModule(String cmHandleId,
+ String moduleName,
+ String moduleRevision);
+
+ /**
* Query cm handle details by cm handle's name.
*
* @param cmHandleId cm handle identifier
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java
index 3fa050454..05b83b98e 100755
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java
@@ -107,6 +107,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
private final Map<String, TrustLevel> trustLevelPerDmiPlugin;
private final TrustLevelManager trustLevelManager;
private final CmHandleIdMapper cmHandleIdMapper;
+ private final Map<String, Collection<ModuleReference>> moduleSetTagCache;
@Override
public DmiPluginRegistrationResponse updateDmiRegistrationAndSyncModule(
@@ -192,6 +193,13 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
return inventoryPersistence.getModuleDefinitionsByCmHandleId(cmHandleId);
}
+ @Override
+ public Collection<ModuleDefinition> getModuleDefinitionsByCmHandleAndModule(final String cmHandleId,
+ final String moduleName,
+ final String moduleRevision) {
+ return inventoryPersistence.getModuleDefinitionsByCmHandleAndModule(cmHandleId, moduleName, moduleRevision);
+ }
+
/**
* Retrieve cm handles with details for the given query parameters.
*
@@ -346,13 +354,16 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService
new ArrayList<>(tobeRemovedCmHandles.size());
final Collection<YangModelCmHandle> yangModelCmHandles =
inventoryPersistence.getYangModelCmHandles(tobeRemovedCmHandles);
-
+ final Set<String> moduleSetTags = yangModelCmHandles.stream().map(YangModelCmHandle::getModuleSetTag)
+ .collect(Collectors.toSet());
updateCmHandleStateBatch(yangModelCmHandles, CmHandleState.DELETING);
final Set<String> notDeletedCmHandles = new HashSet<>();
for (final List<String> tobeRemovedCmHandleBatch : Lists.partition(tobeRemovedCmHandles, DELETE_BATCH_SIZE)) {
try {
batchDeleteCmHandlesFromDbAndModuleSyncMap(tobeRemovedCmHandleBatch);
+ moduleSetTags.forEach(moduleSetTagCache::remove);
+ log.debug("Removed module set tags: {}", moduleSetTags);
tobeRemovedCmHandleBatch.forEach(cmHandleId ->
cmHandleRegistrationResponses.add(CmHandleRegistrationResponse.createSuccessResponse(cmHandleId)));
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistence.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistence.java
index 9024eac33..dcd036870 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistence.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistence.java
@@ -80,6 +80,18 @@ public interface InventoryPersistence extends NcmpPersistence {
Collection<ModuleDefinition> getModuleDefinitionsByCmHandleId(String cmHandleId);
/**
+ * Method to return module definitions for the given parameters.
+ *
+ * @param cmHandleId cm-handle identifier
+ * @param moduleName module name
+ * @param moduleRevision the revision of the module
+ * @return list of module definitions (module name, revision, yang resource content)
+ */
+ Collection<ModuleDefinition> getModuleDefinitionsByCmHandleAndModule(String cmHandleId,
+ String moduleName,
+ String moduleRevision);
+
+ /**
* Method to return module references by cmHandleId.
*
* @param cmHandleId cm handle ID
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImpl.java
index 33d6e9a9c..3b7078603 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImpl.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImpl.java
@@ -128,6 +128,15 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv
}
@Override
+ public Collection<ModuleDefinition> getModuleDefinitionsByCmHandleAndModule(final String cmHandleId,
+ final String moduleName,
+ final String moduleRevision) {
+ cpsValidator.validateNameCharacters(cmHandleId, moduleName);
+ return cpsModuleService.getModuleDefinitionsByAnchorAndModule(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME,
+ cmHandleId, moduleName, moduleRevision);
+ }
+
+ @Override
public Collection<ModuleReference> getYangResourcesModuleReferences(final String cmHandleId) {
cpsValidator.validateNameCharacters(cmHandleId);
return cpsModuleService.getYangResourcesModuleReferences(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME, cmHandleId);
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleOperationsUtils.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleOperationsUtils.java
index 750be2dc8..22bbc7383 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleOperationsUtils.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleOperationsUtils.java
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2022-2023 Nordix Foundation
+ * Copyright (C) 2022-2024 Nordix Foundation
* Modifications Copyright (C) 2022 Bell Canada
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -68,6 +68,10 @@ public class ModuleOperationsUtils {
private static final String LOCK_REASON_DETAILS_MSG_FORMAT = UPGRADE_FORMAT + " Attempt #%d failed: %s";
private static final Pattern retryAttemptPattern = Pattern.compile("Attempt #(\\d+) failed:.+");
private static final Pattern moduleSetTagPattern = Pattern.compile("Upgrade to ModuleSetTag: (\\S+)");
+ private static final String CPS_PATH_CM_HANDLES_MODEL_SYNC_FAILED_OR_UPGRADE = """
+ //lock-reason[@reason="MODULE_SYNC_FAILED"
+ or @reason="MODULE_UPGRADE"
+ or @reason="MODULE_UPGRADE_FAILED"]""";
/**
* Query data nodes for cm handles with an "ADVISED" cm handle state.
@@ -110,8 +114,7 @@ public class ModuleOperationsUtils {
*/
public List<YangModelCmHandle> getCmHandlesThatFailedModelSyncOrUpgrade() {
final List<DataNode> lockedCmHandlesAsDataNodeList
- = cmHandleQueries.queryCmHandleAncestorsByCpsPath(
- "//lock-reason[@reason=\"MODULE_SYNC_FAILED\" or @reason=\"MODULE_UPGRADE\"]",
+ = cmHandleQueries.queryCmHandleAncestorsByCpsPath(CPS_PATH_CM_HANDLES_MODEL_SYNC_FAILED_OR_UPGRADE,
FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS);
return convertCmHandlesDataNodesToYangModelCmHandles(lockedCmHandlesAsDataNodeList);
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncService.java
index b21a2f1f8..72d322605 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncService.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleSyncService.java
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2022-2023 Nordix Foundation
+ * Copyright (C) 2022-2024 Nordix Foundation
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -91,6 +91,9 @@ public class ModuleSyncService {
existingAnchorName, inUpgrade);
updateModuleSetTagCache(moduleSetTag, moduleReferencesFromExistingCmHandle);
} else {
+ if (inUpgrade) {
+ deleteSchemaSetIfExists(cmHandleId);
+ }
final Collection<ModuleReference> allModuleReferencesFromCmHandle
= syncAndCreateSchemaSet(yangModelCmHandle);
updateModuleSetTagCache(moduleSetTag, allModuleReferencesFromCmHandle);
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/CmHandleIdMapper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/CmHandleIdMapper.java
index 8175fb5e7..a88adbd11 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/CmHandleIdMapper.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/utils/CmHandleIdMapper.java
@@ -73,7 +73,13 @@ public class CmHandleIdMapper {
public void removeMapping(final String cmHandleId) {
final String alternateId = alternateIdPerCmHandleId.remove(cmHandleId);
- cmHandleIdPerAlternateId.remove(alternateId);
+ removeAlternateIdWithValidation(alternateId);
+ }
+
+ private void removeAlternateIdWithValidation(final String alternateId) {
+ if (alternateId != null) {
+ cmHandleIdPerAlternateId.remove(alternateId);
+ }
}
private void initializeCache() {
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy
index 59bf9420c..c7ac8ab8b 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplRegistrationSpec.groovy
@@ -21,16 +21,15 @@
package org.onap.cps.ncmp.api.impl
-import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevelManager
-import org.onap.cps.ncmp.api.impl.utils.CmHandleIdMapper
-import org.onap.cps.ncmp.api.models.UpgradedCmHandles
-
+import static org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.Status
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.api.NcmpResponseStatus.UNKNOWN_ERROR
-import static org.onap.cps.ncmp.api.models.CmHandleRegistrationResponse.Status
+import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevelManager
+import org.onap.cps.ncmp.api.impl.utils.CmHandleIdMapper
+import org.onap.cps.ncmp.api.models.UpgradedCmHandles
import com.fasterxml.jackson.databind.ObjectMapper
import com.hazelcast.map.IMap
import org.onap.cps.api.CpsDataService
@@ -52,14 +51,11 @@ import org.onap.cps.spi.exceptions.DataNodeNotFoundException
import org.onap.cps.spi.exceptions.DataValidationException
import org.onap.cps.spi.exceptions.SchemaSetNotFoundException
import org.onap.cps.utils.JsonObjectMapper
-import spock.lang.Shared
import spock.lang.Specification
class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
- @Shared
def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: 'some-cm-handle-id')
-
def mockCpsModuleService = Mock(CpsModuleService)
def spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper()))
def mockDmiDataOperations = Mock(DmiDataOperations)
@@ -74,6 +70,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
def mockTrustLevelManager = Mock(TrustLevelManager)
def mockCmHandleIdMapper = Mock(CmHandleIdMapper)
def objectUnderTest = getObjectUnderTest()
+ def mockModuleSetTagCache = [:]
def 'DMI Registration: Create, Update, Delete & Upgrade operations are processed in the right order'() {
given: 'a registration with operations of all types'
@@ -91,7 +88,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
then: 'cm-handles are removed first'
1 * objectUnderTest.parseAndProcessDeletedCmHandlesInRegistration(*_)
and: 'de-registered cm handle entry is removed from in progress map'
- 1 * mockModuleSyncStartedOnCmHandles.remove('cmhandle-2')
+ 2 * mockModuleSyncStartedOnCmHandles.remove('cmhandle-2')
then: 'cm-handles are created'
1 * objectUnderTest.parseAndProcessCreatedCmHandlesInRegistration(*_)
then: 'cm-handles are updated'
@@ -448,7 +445,7 @@ class NetworkCmProxyDataServiceImplRegistrationSpec extends Specification {
return Spy(new NetworkCmProxyDataServiceImpl(spiedJsonObjectMapper, mockDmiDataOperations,
mockNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence, mockCmHandleQueries,
stubbedNetworkCmProxyCmHandlerQueryService, mockLcmEventsCmHandleStateHandler, mockCpsDataService,
- mockModuleSyncStartedOnCmHandles, trustLevelPerDmiPlugin as Map<String, TrustLevel>, mockTrustLevelManager, mockCmHandleIdMapper))
+ mockModuleSyncStartedOnCmHandles, trustLevelPerDmiPlugin, mockTrustLevelManager, mockCmHandleIdMapper, mockModuleSetTagCache))
}
def addPersistedYangModelCmHandles(ids) {
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy
index c1af902a0..c835056f3 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy
@@ -23,8 +23,6 @@
package org.onap.cps.ncmp.api.impl
-import org.onap.cps.ncmp.api.impl.utils.CmHandleIdMapper
-
import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME
import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DATASPACE_NAME
import static org.onap.cps.ncmp.api.impl.ncmppersistence.NcmpPersistence.NCMP_DMI_REGISTRY_ANCHOR
@@ -34,6 +32,7 @@ import static org.onap.cps.ncmp.api.impl.operations.DatastoreType.PASSTHROUGH_RU
import static org.onap.cps.ncmp.api.impl.operations.OperationType.CREATE
import static org.onap.cps.ncmp.api.impl.operations.OperationType.UPDATE
+import org.onap.cps.ncmp.api.impl.utils.CmHandleIdMapper
import com.hazelcast.map.IMap
import org.onap.cps.ncmp.api.NetworkCmProxyCmHandleQueryService
import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler
@@ -82,6 +81,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
def stubTrustLevelPerDmiPlugin = Stub(Map<String, TrustLevel>)
def mockTrustLevelManager = Mock(TrustLevelManager)
def mockCmHandleIdMapper = Mock(CmHandleIdMapper)
+ def mockModuleSetTagCache = [:]
def NO_TOPIC = null
def NO_REQUEST_ID = null
@@ -102,8 +102,8 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
stubModuleSyncStartedOnCmHandles,
stubTrustLevelPerDmiPlugin,
mockTrustLevelManager,
- mockCmHandleIdMapper
- )
+ mockCmHandleIdMapper,
+ mockModuleSetTagCache)
def cmHandleXPath = "/dmi-registry/cm-handles[@id='testCmHandle']"
@@ -298,10 +298,17 @@ class NetworkCmProxyDataServiceImplSpec extends Specification {
assert result == ['cm-handle-id-1']
}
- def 'Getting module definitions.'() {
- when: 'get module definitions method is called with a valid cm handle ID'
+ def 'Getting module definitions by module'() {
+ when: 'get module definitions is performed with module name'
+ objectUnderTest.getModuleDefinitionsByCmHandleAndModule('some-cm-handle', 'some-module', '2021-08-04')
+ then: 'ncmp inventory persistence service is invoked once with correct parameters'
+ 1 * mockInventoryPersistence.getModuleDefinitionsByCmHandleAndModule('some-cm-handle', 'some-module', '2021-08-04')
+ }
+
+ def 'Getting module definitions by cm handle id'() {
+ when: 'get module definitions is performed with cm handle id'
objectUnderTest.getModuleDefinitionsByCmHandleId('some-cm-handle')
- then: 'CPS module services is invoked once'
+ then: 'ncmp inventory persistence service is invoked once with correct parameter'
1 * mockInventoryPersistence.getModuleDefinitionsByCmHandleId('some-cm-handle')
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImplSpec.groovy
index cb2f3fddd..a3b923f93 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImplSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/InventoryPersistenceImplSpec.groovy
@@ -184,11 +184,23 @@ class InventoryPersistenceImplSpec extends Specification {
'DELETING' | CmHandleState.DELETING || ['/dmi-registry/cm-handles[@id=\'Some-Cm-Handle1\']':'{"state":{"cm-handle-state":"DELETING","last-update-time":"2022-12-31T20:30:40.000+0000"}}', '/dmi-registry/cm-handles[@id=\'Some-Cm-Handle2\']':'{"state":{"cm-handle-state":"DELETING","last-update-time":"2022-12-31T20:30:40.000+0000"}}']
}
- def 'Get module definitions'() {
- given: 'cps module service returns a collection of module definitions'
+ def 'Getting module definitions by module'() {
+ given: 'cps module service returns module definition for module name'
+ def moduleDefinitions = [new ModuleDefinition('moduleName','revision','content')]
+ mockCpsModuleService.getModuleDefinitionsByAnchorAndModule(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME,'some-cmHandle-Id', 'some-module', '2024-01-25') >> moduleDefinitions
+ when: 'get module definitions is invoked with module name'
+ def result = objectUnderTest.getModuleDefinitionsByCmHandleAndModule('some-cmHandle-Id', 'some-module', '2024-01-25')
+ then: 'returned result are the same module definitions as returned from module service'
+ assert result == moduleDefinitions
+ and: 'cm handle id and module name validated'
+ 1 * mockCpsValidator.validateNameCharacters('some-cmHandle-Id', 'some-module')
+ }
+
+ def 'Getting module definitions with cm handle id'() {
+ given: 'cps module service returns module definitions for cm handle id'
def moduleDefinitions = [new ModuleDefinition('moduleName','revision','content')]
mockCpsModuleService.getModuleDefinitionsByAnchorName(NFP_OPERATIONAL_DATASTORE_DATASPACE_NAME,'some-cmHandle-Id') >> moduleDefinitions
- when: 'get module definitions by cmHandle is invoked'
+ when: 'get module definitions is invoked with cm handle id'
def result = objectUnderTest.getModuleDefinitionsByCmHandleId('some-cmHandle-Id')
then: 'the returned result are the same module definitions as returned from the module service'
assert result == moduleDefinitions
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleOperationsUtilsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleOperationsUtilsSpec.groovy
index 8f3d8d97b..827a548ae 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleOperationsUtilsSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/inventory/sync/ModuleOperationsUtilsSpec.groovy
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2022-2023 Nordix Foundation
+ * Copyright (C) 2022-2024 Nordix Foundation
* Modifications Copyright (C) 2022 Bell Canada
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -128,10 +128,9 @@ class ModuleOperationsUtilsSpec extends Specification{
'empty module set tag' | '' || 'not-specified'
}
- def 'Get all locked Cm-Handle where Lock Reason is MODULE_SYNC_FAILED cm handle #scenario'() {
+ def 'Get all locked cm-Handles where lock reasons are model sync failed or upgrade'() {
given: 'the cps (persistence service) returns a collection of data nodes'
- mockCmHandleQueries.queryCmHandleAncestorsByCpsPath(
- '//lock-reason[@reason="MODULE_SYNC_FAILED" or @reason="MODULE_UPGRADE"]',
+ mockCmHandleQueries.queryCmHandleAncestorsByCpsPath(ModuleOperationsUtils.CPS_PATH_CM_HANDLES_MODEL_SYNC_FAILED_OR_UPGRADE,
FetchDescendantsOption.INCLUDE_ALL_DESCENDANTS) >> [dataNode]
when: 'get locked Misbehaving cm handle is called'
def result = objectUnderTest.getCmHandlesThatFailedModelSyncOrUpgrade()
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java
index b115f9a3c..1e42702ab 100755
--- a/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/impl/CpsModulePersistenceServiceImpl.java
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2020-2023 Nordix Foundation
+ * Copyright (C) 2020-2024 Nordix Foundation
* Modifications Copyright (C) 2020-2022 Bell Canada.
* Modifications Copyright (C) 2021 Pantheon.tech
* Modifications Copyright (C) 2022 TechMahindra Ltd.
@@ -32,6 +32,7 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
@@ -79,6 +80,8 @@ import org.springframework.stereotype.Component;
public class CpsModulePersistenceServiceImpl implements CpsModulePersistenceService {
private static final String YANG_RESOURCE_CHECKSUM_CONSTRAINT_NAME = "yang_resource_checksum_key";
+ private static final String NO_MODULE_NAME_FILTER = null;
+ private static final String NO_MODULE_REVISION = null;
private static final Pattern CHECKSUM_EXCEPTION_PATTERN = Pattern.compile(".*\\(checksum\\)=\\((\\w+)\\).*");
private static final Pattern RFC6020_RECOMMENDED_FILENAME_PATTERN = Pattern
.compile("([\\w-]+)@(\\d{4}-\\d{2}-\\d{2})(?:\\.yang)?", Pattern.CASE_INSENSITIVE);
@@ -122,10 +125,29 @@ public class CpsModulePersistenceServiceImpl implements CpsModulePersistenceServ
public Collection<ModuleDefinition> getYangResourceDefinitions(final String dataspaceName,
final String anchorName) {
final Set<YangResourceEntity> yangResourceEntities =
- yangResourceRepository
- .findAllModuleDefinitionsByDataspaceAndAnchor(dataspaceName, anchorName);
- return yangResourceEntities.stream().map(CpsModulePersistenceServiceImpl::toModuleDefinition)
- .collect(Collectors.toList());
+ yangResourceRepository.findAllModuleDefinitionsByDataspaceAndAnchorAndModule(dataspaceName, anchorName,
+ NO_MODULE_NAME_FILTER, NO_MODULE_REVISION);
+ return convertYangResourceEntityToModuleDefinition(yangResourceEntities);
+ }
+
+ @Override
+ public Collection<ModuleDefinition> getYangResourceDefinitionsByAnchorAndModule(final String dataspaceName,
+ final String anchorName,
+ final String moduleName,
+ final String moduleRevision) {
+ final Set<YangResourceEntity> yangResourceEntities =
+ yangResourceRepository.findAllModuleDefinitionsByDataspaceAndAnchorAndModule(dataspaceName, anchorName,
+ moduleName, moduleRevision);
+ return convertYangResourceEntityToModuleDefinition(yangResourceEntities);
+ }
+
+ private List<ModuleDefinition> convertYangResourceEntityToModuleDefinition(final Set<YangResourceEntity>
+ yangResourceEntities) {
+ final List<ModuleDefinition> resultModuleDefinitions = new ArrayList<>(yangResourceEntities.size());
+ for (final YangResourceEntity yangResourceEntity: yangResourceEntities) {
+ resultModuleDefinitions.add(toModuleDefinition(yangResourceEntity));
+ }
+ return resultModuleDefinitions;
}
@Override
diff --git a/cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceRepository.java b/cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceRepository.java
index 3fec462b4..b37f6357c 100644
--- a/cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceRepository.java
+++ b/cps-ri/src/main/java/org/onap/cps/spi/repository/YangResourceRepository.java
@@ -1,7 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (C) 2020 Pantheon.tech
- * Modifications Copyright (C) 2021-2023 Nordix Foundation
+ * Modifications Copyright (C) 2021-2024 Nordix Foundation
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -84,9 +84,12 @@ public interface YangResourceRepository extends JpaRepository<YangResourceEntity
WHERE
dataspace.name = :dataspaceName
AND anchor.name = :anchorName
+ AND (:moduleName IS NULL OR yang_resource.module_name = :moduleName)
+ AND (:revision IS NULL OR yang_resource.revision = :revision)
""", nativeQuery = true)
- Set<YangResourceEntity> findAllModuleDefinitionsByDataspaceAndAnchor(
- @Param("dataspaceName") String dataspaceName, @Param("anchorName") String anchorName);
+ Set<YangResourceEntity> findAllModuleDefinitionsByDataspaceAndAnchorAndModule(
+ @Param("dataspaceName") String dataspaceName, @Param("anchorName") String anchorName,
+ @Param("moduleName") String moduleName, @Param("revision") String revision);
@Query(value = """
SELECT DISTINCT
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 292846446..bdd361458 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
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2020-2023 Nordix Foundation
+ * Copyright (C) 2020-2024 Nordix Foundation
* Modifications Copyright (C) 2020-2021 Pantheon.tech
* Modifications Copyright (C) 2022 TechMahindra Ltd.
* ================================================================================
@@ -134,6 +134,18 @@ public interface CpsModuleService {
Collection<ModuleDefinition> getModuleDefinitionsByAnchorName(String dataspaceName, String anchorName);
/**
+ * Retrieve module definitions for the given parameters.
+ *
+ * @param dataspaceName dataspace name
+ * @param anchorName anchor name
+ * @param moduleName module name
+ * @param moduleRevision the revision of the module
+ * @return a collection of module definitions (moduleName, revision, yang resource content)
+ */
+ Collection<ModuleDefinition> getModuleDefinitionsByAnchorAndModule(String dataspaceName, String anchorName,
+ String moduleName, String moduleRevision);
+
+ /**
* Identify previously unknown Yang Resource module references.
* The system will ignore the namespace of all module references.
*
diff --git a/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java b/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java
index 61a4e623a..0f9eb3c64 100644
--- a/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java
+++ b/cps-service/src/main/java/org/onap/cps/api/impl/CpsModuleServiceImpl.java
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2020-2023 Nordix Foundation
+ * Copyright (C) 2020-2024 Nordix Foundation
* Modifications Copyright (C) 2020-2021 Pantheon.tech
* Modifications Copyright (C) 2022 Bell Canada
* Modifications Copyright (C) 2022 TechMahindra Ltd
@@ -156,6 +156,15 @@ public class CpsModuleServiceImpl implements CpsModuleService {
}
@Override
+ public Collection<ModuleDefinition> getModuleDefinitionsByAnchorAndModule(final String dataspaceName,
+ final String anchorName,
+ final String moduleName,
+ final String moduleRevision) {
+ return cpsModulePersistenceService.getYangResourceDefinitionsByAnchorAndModule(dataspaceName, anchorName,
+ moduleName, moduleRevision);
+ }
+
+ @Override
public Collection<ModuleReference> identifyNewModuleReferences(
final Collection<ModuleReference> moduleReferencesToCheck) {
return cpsModulePersistenceService.identifyNewModuleReferences(moduleReferencesToCheck);
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 aaca2ee5b..eeaaa4799 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
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2020-2023 Nordix Foundation
+ * Copyright (C) 2020-2024 Nordix Foundation
* Modifications Copyright (C) 2020-2022 Bell Canada.
* Modifications Copyright (C) 2022 TechMahindra Ltd.
* ================================================================================
@@ -126,6 +126,18 @@ public interface CpsModulePersistenceService {
Collection<ModuleDefinition> getYangResourceDefinitions(String dataspaceName, String anchorName);
/**
+ * Get YANG resource definitions for the given parameters.
+ *
+ * @param dataspaceName dataspace name
+ * @param anchorName anchor name
+ * @param moduleName module name
+ * @param moduleRevision the revision of the module
+ * @return a collection of module definitions (moduleName, revision and yang resource content)
+ */
+ Collection<ModuleDefinition> getYangResourceDefinitionsByAnchorAndModule(String dataspaceName, String anchorName,
+ String moduleName, String moduleRevision);
+
+ /**
* Remove unused Yang Resource Modules.
*/
void deleteUnusedYangResourceModules();
diff --git a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy
index d909e27ab..0bad0de6a 100644
--- a/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy
+++ b/cps-service/src/test/groovy/org/onap/cps/api/impl/CpsModuleServiceImplSpec.groovy
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2020-2023 Nordix Foundation
+ * Copyright (C) 2020-2024 Nordix Foundation
* Modifications Copyright (C) 2020-2021 Pantheon.tech
* Modifications Copyright (C) 2020-2022 Bell Canada.
* Modifications Copyright (C) 2022 TechMahindra Ltd.
@@ -238,15 +238,25 @@ class CpsModuleServiceImplSpec extends Specification {
1 * mockCpsModulePersistenceService.identifyNewModuleReferences(moduleReferencesToCheck)
}
- def 'Getting module definitions.'() {
- given: 'the module persistence service returns a collection of module definitions'
+ def 'Getting module definitions with module name'() {
+ given: 'module persistence service returns module definitions for module name'
+ def moduleDefinitionsFromPersistenceService = [ new ModuleDefinition('name', 'revision', 'content' ) ]
+ mockCpsModulePersistenceService.getYangResourceDefinitionsByAnchorAndModule('some-dataspace-name', 'some-anchor-name', 'some-module', '2024-01-01') >> moduleDefinitionsFromPersistenceService
+ when: 'get module definitions method is called with anchor and module name'
+ def result = objectUnderTest.getModuleDefinitionsByAnchorAndModule('some-dataspace-name', 'some-anchor-name', 'some-module', '2024-01-01')
+ then: 'the result is the same collection returned by the persistence service'
+ assert result == moduleDefinitionsFromPersistenceService
+ }
+
+ def 'Getting module definitions with anchor name'() {
+ given: 'the module persistence service returns module definitions for cm handle id'
def moduleDefinitionsFromPersistenceService = [ new ModuleDefinition('name', 'revision', 'content' ) ]
mockCpsModulePersistenceService.getYangResourceDefinitions('some-dataspace-name', 'some-anchor-name') >> moduleDefinitionsFromPersistenceService
when: 'get module definitions method is called with a valid dataspace and anchor name'
def result = objectUnderTest.getModuleDefinitionsByAnchorName('some-dataspace-name', 'some-anchor-name')
then: 'the result is the same collection returned by the persistence service'
assert result == moduleDefinitionsFromPersistenceService
- and: 'the CpsValidator is called on the dataspaceName and schemaSetName'
+ and: 'cps validator is called on the dataspace and anchor name'
1 * mockCpsValidator.validateNameCharacters('some-dataspace-name', 'some-anchor-name')
}
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/bookStoreAWithModules_M1_M2_ResourcesResponse.json b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/bookStoreAWithModules_M1_M2_ResourcesResponse.json
new file mode 100644
index 000000000..5d713914d
--- /dev/null
+++ b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/bookStoreAWithModules_M1_M2_ResourcesResponse.json
@@ -0,0 +1,12 @@
+[
+ {
+ "moduleName": "M1",
+ "revision": "2024-01-01",
+ "yangSource": "module M1 {\n\n namespace \"urn:ietf:params:xml:ns:yang:M1\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2024-01-01 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
+ },
+ {
+ "moduleName": "M2",
+ "revision": "2024-01-02",
+ "yangSource": "module M2 {\n\n namespace \"urn:ietf:params:xml:ns:yang:M2\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2024-01-02 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
+ }
+] \ No newline at end of file
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/bookStoreAWithModules_M1_M2_Response.json b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/bookStoreAWithModules_M1_M2_Response.json
new file mode 100644
index 000000000..9f20564f0
--- /dev/null
+++ b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/bookStoreAWithModules_M1_M2_Response.json
@@ -0,0 +1,12 @@
+{
+ "schemas": [
+ {
+ "moduleName": "M1",
+ "revision": "2024-01-01"
+ },
+ {
+ "moduleName": "M2",
+ "revision": "2024-01-02"
+ }
+ ]
+} \ No newline at end of file
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/bookStoreBWithModules_M1_M3_ResourcesResponse.json b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/bookStoreBWithModules_M1_M3_ResourcesResponse.json
new file mode 100644
index 000000000..ef9b85f92
--- /dev/null
+++ b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/bookStoreBWithModules_M1_M3_ResourcesResponse.json
@@ -0,0 +1,12 @@
+[
+ {
+ "moduleName": "M1",
+ "revision": "2024-01-01",
+ "yangSource": "module M1 {\n\n namespace \"urn:ietf:params:xml:ns:yang:M1\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2024-01-01 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
+ },
+ {
+ "moduleName": "M3",
+ "revision": "2024-01-03",
+ "yangSource": "module M3 {\n\n namespace \"urn:ietf:params:xml:ns:yang:M3\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2024-01-03 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
+ }
+] \ No newline at end of file
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/bookStoreBWithModules_M1_M3_Response.json b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/bookStoreBWithModules_M1_M3_Response.json
new file mode 100644
index 000000000..513c749a2
--- /dev/null
+++ b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/bookStoreBWithModules_M1_M3_Response.json
@@ -0,0 +1,12 @@
+{
+ "schemas": [
+ {
+ "moduleName": "M1",
+ "revision": "2024-01-01"
+ },
+ {
+ "moduleName": "M3",
+ "revision": "2024-01-03"
+ }
+ ]
+} \ No newline at end of file
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/bookStoreCWithModules_M1_M2_ResourcesResponse.json b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/bookStoreCWithModules_M1_M2_ResourcesResponse.json
new file mode 100644
index 000000000..5d713914d
--- /dev/null
+++ b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/bookStoreCWithModules_M1_M2_ResourcesResponse.json
@@ -0,0 +1,12 @@
+[
+ {
+ "moduleName": "M1",
+ "revision": "2024-01-01",
+ "yangSource": "module M1 {\n\n namespace \"urn:ietf:params:xml:ns:yang:M1\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2024-01-01 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
+ },
+ {
+ "moduleName": "M2",
+ "revision": "2024-01-02",
+ "yangSource": "module M2 {\n\n namespace \"urn:ietf:params:xml:ns:yang:M2\";\n prefix \"yang\";\n\n organization\n \"IETF NETMOD (NETCONF Data Modeling Language) Working Group\";\n\n contact\n \"WG Web: <http://tools.ietf.org/wg/netmod/>\n WG List: <mailto:netmod@ietf.org>\n\n WG Chair: David Kessens\n <mailto:david.kessens@nsn.com>\n\n WG Chair: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\n\n Editor: Juergen Schoenwaelder\n <mailto:j.schoenwaelder@jacobs-university.de>\";\n\n description\n \"This module contains a collection of generally useful derived\n YANG data types.\n\n Copyright (c) 2013 IETF Trust and the persons identified as\n authors of the code. All rights reserved.\n\n Redistribution and use in source and binary forms, with or\n without modification, is permitted pursuant to, and subject\n to the license terms contained in, the Simplified BSD License\n set forth in Section 4.c of the IETF Trust's Legal Provisions\n Relating to IETF Documents\n (http://trustee.ietf.org/license-info).\n\n This version of this YANG module is part of RFC 6991; see\n the RFC itself for full legal notices.\";\n\n revision 2024-01-02 {\n description\n \"This revision adds the following new data types:\n - yang-identifier\n - hex-string\n - uuid\n - dotted-quad\";\n reference\n \"RFC 6991: Common YANG Data Types\";\n }\n\n revision 2010-09-24 {\n description\n \"Initial revision.\";\n reference\n \"RFC 6021: Common YANG Data Types\";\n }\n\n /*** collection of counter and gauge types ***/\n\n typedef counter32 {\n type uint32;\n description\n \"The counter32 type represents a non-negative integer\n that monotonically increases until it reaches a\n maximum value of 2^32-1 (4294967295 decimal), when it\n wraps around and starts increasing again from zero.\n\n Counters have no defined 'initial' value, and thus, a\n single value of a counter has (in general) no information\n content. Discontinuities in the monotonically increasing\n value normally occur at re-initialization of the\n management system, and at other times as specified in the\n description of a schema node using this type. If such\n other times can occur, for example, the creation of\n a schema node of type counter32 at times other than\n re-initialization, then a corresponding schema node\n should be defined, with an appropriate type, to indicate\n the last discontinuity.\n\n The counter32 type should not be used for configuration\n schema nodes. A default statement SHOULD NOT be used in\n combination with the type counter32.\n\n In the value set and its semantics, this type is equivalent\n to the Counter32 type of the SMIv2.\";\n reference\n \"RFC 2578: Structure of Management Information Version 2\n (SMIv2)\";\n }\n}\n"
+ }
+] \ No newline at end of file
diff --git a/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/bookStoreCWithModules_M1_M2_Response.json b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/bookStoreCWithModules_M1_M2_Response.json
new file mode 100644
index 000000000..9f20564f0
--- /dev/null
+++ b/dmi-plugin-demo-and-csit-stub/dmi-plugin-demo-and-csit-stub-service/src/main/resources/module/bookStoreCWithModules_M1_M2_Response.json
@@ -0,0 +1,12 @@
+{
+ "schemas": [
+ {
+ "moduleName": "M1",
+ "revision": "2024-01-01"
+ },
+ {
+ "moduleName": "M2",
+ "revision": "2024-01-02"
+ }
+ ]
+} \ No newline at end of file
diff --git a/docker-compose/docker-compose.yml b/docker-compose/docker-compose.yml
index 11d39b59d..906945de4 100644
--- a/docker-compose/docker-compose.yml
+++ b/docker-compose/docker-compose.yml
@@ -1,7 +1,7 @@
# ============LICENSE_START=======================================================
# Copyright (c) 2020 Pantheon.tech.
# Modifications Copyright (C) 2021 Bell Canada.
-# Modifications Copyright (C) 2022-2023 Nordix Foundation.
+# Modifications Copyright (C) 2022-2024 Nordix Foundation.
# ================================================================================
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -31,6 +31,14 @@ services:
POSTGRES_DB: cpsdb
POSTGRES_USER: ${DB_USERNAME:-cps}
POSTGRES_PASSWORD: ${DB_PASSWORD:-cps}
+ deploy:
+ resources:
+ reservations:
+ cpus: '1'
+ memory: 1G
+ limits:
+ cpus: '6'
+ memory: 3G
cps-and-ncmp:
container_name: cps-and-ncmp
@@ -55,6 +63,14 @@ services:
restart: unless-stopped
depends_on:
- dbpostgresql
+ deploy:
+ resources:
+ reservations:
+ cpus: '2'
+ memory: 2G
+ limits:
+ cpus: '3'
+ memory: 3G
### if kafka is not required comment out zookeeper and kafka ###
zookeeper:
diff --git a/docs/_static/cps-delta-mechanism.png b/docs/_static/cps-delta-mechanism.png
new file mode 100644
index 000000000..ab78ad9a1
--- /dev/null
+++ b/docs/_static/cps-delta-mechanism.png
Binary files differ
diff --git a/docs/cps-delta-endpoints.rst b/docs/cps-delta-endpoints.rst
new file mode 100644
index 000000000..b2e4e6041
--- /dev/null
+++ b/docs/cps-delta-endpoints.rst
@@ -0,0 +1,66 @@
+.. 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
+.. Copyright (C) 2024 TechMahindra Ltd.
+.. _cpsDeltaEndpoints:
+
+.. toctree::
+ :maxdepth: 1
+
+CPS Delta Endpoints
+###################
+
+The CPS Delta feature provides 1 endpoint:
+
+- /v2/dataspaces/{dataspace-name}/anchors/{anchor-name}/delta
+
+Description
+-----------
+The following is a Get endpoint, which allows the user to find the delta between configurations stored under two anchors within the same dataspace.
+
+Path Parameters
+---------------
+The endpoint takes 2 path parameters as input:
+ - **dataspace-name:** name of dataspace where the 2 anchors to be used for delta generation are stored.
+ - **anchor-name:** the source anchor name, the data under this anchor will be the reference data for delta report generation
+
+Query Parameters
+----------------
+The endpoint takes 3 query parameters as input:
+ - **target-anchor-name:** the data retrieved from target anchor gets compared against the data retrieved from source anchor
+ - **xpath:** the xpath to a particular data node, Example: /bookstore/categories[@code='1']
+ - **descendants:** specifies the number of descendants to query.
+
+Sample Delta Report
+-------------------
+
+.. code-block:: json
+
+ [
+ {
+ "action": "ADD",
+ "xpath": "/bookstore/categories/[@code=3]",
+ "target-data": {
+ "code": "3,",
+ "name": "kidz"
+ }
+ },
+ {
+ "action": "REMOVE",
+ "xpath": "/bookstore/categories/[@code=1]",
+ "source-data": {
+ "code": "1,",
+ "name": "Fiction"
+ }
+ },
+ {
+ "action": "UPDATE",
+ "xpath": "/bookstore/categories/[@code=2]",
+ "source-data": {
+ "name": "Funny"
+ },
+ "target-data": {
+ "name": "Comic"
+ }
+ }
+ ] \ No newline at end of file
diff --git a/docs/cps-delta-feature.rst b/docs/cps-delta-feature.rst
new file mode 100644
index 000000000..f3a2f947e
--- /dev/null
+++ b/docs/cps-delta-feature.rst
@@ -0,0 +1,44 @@
+.. 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
+.. Copyright (C) 2024 TechMahindra Ltd.
+.. _cpsDelta:
+
+.. toctree::
+ :maxdepth: 1
+
+CPS Delta Feature
+#################
+
+- The concept of CPS Delta Feature is to have the ability to find the delta or difference between two configurations stored in CPS DB.
+
+- The Delta feature brings a new functionality:
+
+ - Ability to find the delta between the configurations stored in two anchors within the same dataspace.
+
+The calculated differences can then be used to generate a Delta Report which can be sent over the Kafka Notification Service to the user.
+
+Delta Report Format
+-------------------
+
+The Delta Report is based on the RFC 9144, which defines a set of parameters to be included in the Delta Report. In CPS only the relevant parameters defined in RFC 9144 are used. These include:
+ - **action:** This parameter defines how the data nodes changed between two configurations. If data nodes are added, deleted or modified then the 'action' parameter in the delta report will be set to ADD, DELETE or UPDATE respectively for each data node.
+ - **xpath:** This parameter will provide the xpath of each data node that has been either added, deleted or modified.
+ - **source-data:** this parameter is added to the delta report when a data node is deleted or updated, this represents the source/reference data against which the delta is being generated. In case of newly added data node this field is not included in the delta report.
+ - **target-data:** this parameter is added to the delta report when a data node is added or updated, this represents the data values that are being compared to the source data. In case of a data node being deleted this field is not included in the delta report.
+
+**Note.** In case of an existing data node being modified, both the source-data and target-data fields are present in the delta report.
+
+Mechanism for Delta generation
+------------------------------
+
+.. image:: _static/cps-delta-mechanism.png
+ :alt: Mechanism for Delta generation
+
+Endpoints provided as part of Delta Feature
+-------------------------------------------
+
+.. toctree::
+ :maxdepth: 1
+
+ cps-delta-endpoints.rst \ No newline at end of file
diff --git a/docs/modeling.rst b/docs/modeling.rst
index ceaaefda5..7ebf6fecd 100644
--- a/docs/modeling.rst
+++ b/docs/modeling.rst
@@ -63,6 +63,14 @@ Querying
xpath.rst
cps-path.rst
+Additional information on CPS-Core Interfaces
+---------------------------------------------
+
+.. toctree::
+ :maxdepth: 1
+
+ cps-delta-feature.rst
+
.. Below Label is used by documentation for other CPS components to link here, do not remove even if it gives a warning
.. _cps_ncmp_modelling:
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsModuleServiceIntegrationSpec.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsModuleServiceIntegrationSpec.groovy
index cf0e0b594..8029ae042 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsModuleServiceIntegrationSpec.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/functional/CpsModuleServiceIntegrationSpec.groovy
@@ -1,6 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2023 Nordix Foundation
+ * Copyright (C) 2023-2024 Nordix Foundation
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the 'License');
* you may not use this file except in compliance with the License.
@@ -21,7 +21,6 @@
package org.onap.cps.integration.functional
import org.onap.cps.api.CpsModuleService
-import org.onap.cps.api.impl.CpsModuleServiceImpl
import org.onap.cps.integration.base.FunctionalSpecBase
import org.onap.cps.spi.CascadeDeleteAllowed
import org.onap.cps.spi.exceptions.AlreadyDefinedException
@@ -153,6 +152,17 @@ class CpsModuleServiceIntegrationSpec extends FunctionalSpecBase {
result == [new ModuleDefinition('stores','2020-09-15','')]
}
+ def 'Retrieving module definitions: #scenarios'() {
+ when: 'module definitions for module name are retrieved'
+ def result = objectUnderTest.getModuleDefinitionsByAnchorAndModule(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1, moduleName, moduleRevision)
+ then: 'the correct module definitions are returned'
+ result == [new ModuleDefinition('stores','2020-09-15','')]
+ where: 'following parameters are used'
+ scenarios | moduleName | moduleRevision
+ 'both specified' | 'stores' | '2020-09-15'
+ 'module name specified' | 'stores' | null
+ }
+
def 'Retrieving yang resource module references by anchor.'() {
when: 'the yang resource module references for an anchor are retrieved'
def result = objectUnderTest.getYangResourcesModuleReferences(FUNCTIONAL_TEST_DATASPACE_1, BOOKSTORE_ANCHOR_1)