aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy4
-rw-r--r--cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy4
-rw-r--r--cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyRestExceptionHandlerSpec.groovy4
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/NetworkCmProxyInventoryFacade.java134
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/NetworkCmProxyInventoryFacadeImpl.java169
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cache/CpsAndNcmpLockConfig.java48
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cache/HazelcastCacheConfig.java16
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionComparator.java8
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutor.java73
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationService.java5
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasks.java5
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncWatchdog.java14
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/SynchronizationCacheConfig.java22
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelCacheConfig.java6
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManager.java30
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorSpec.groovy4
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImplSpec.groovy18
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServiceSpec.groovy18
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImplSpec.groovy57
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/NetworkCmProxyInventoryFacadeSpec.groovy6
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasksSpec.groovy14
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncWatchdogSpec.groovy32
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDogSpec.groovy12
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManagerSpec.groovy13
-rw-r--r--cps-rest/docs/openapi/components.yml2
-rw-r--r--cps-rest/docs/openapi/cpsData.yml4
-rwxr-xr-xcps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java61
-rwxr-xr-xcps-rest/src/test/groovy/org/onap/cps/rest/controller/DataRestControllerSpec.groovy95
-rw-r--r--docs/api/swagger/cps/openapi.yaml56
-rw-r--r--docs/api/swagger/policy-executor/openapi.yaml369
-rw-r--r--docs/ncmp-data-operation.rst7
-rw-r--r--docs/release-notes.rst1
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/base/CpsIntegrationSpecBase.groovy8
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/base/PolicyDispatcher.groovy10
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleCreateSpec.groovy4
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleUpdateSpec.groovy4
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/CmHandleUpgradeSpec.groovy4
-rw-r--r--integration-test/src/test/groovy/org/onap/cps/integration/functional/ncmp/ModuleSyncWatchdogIntegrationSpec.groovy9
-rw-r--r--k6-tests/ncmp/common/utils.js31
-rw-r--r--k6-tests/ncmp/config/endurance.json3
-rw-r--r--k6-tests/ncmp/config/kpi.json159
-rw-r--r--k6-tests/ncmp/ncmp-test-runner.js6
-rw-r--r--policy-executor-stub/src/main/java/org/onap/cps/policyexecutor/stub/controller/PolicyExecutorStubController.java67
-rw-r--r--policy-executor-stub/src/test/groovy/org/onap/cps/policyexecutor/stub/controller/PolicyExecutorStubControllerSpec.groovy83
44 files changed, 1016 insertions, 683 deletions
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 b998a16b2d..be7f449326 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
@@ -32,7 +32,7 @@ import groovy.json.JsonSlurper
import org.mapstruct.factory.Mappers
import org.onap.cps.TestUtils
import org.onap.cps.events.EventsPublisher
-import org.onap.cps.ncmp.api.inventory.NetworkCmProxyInventoryFacade
+import org.onap.cps.ncmp.impl.NetworkCmProxyInventoryFacadeImpl
import org.onap.cps.ncmp.api.inventory.models.CompositeState
import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle
import org.onap.cps.ncmp.api.inventory.models.TrustLevel
@@ -91,7 +91,7 @@ class NetworkCmProxyControllerSpec extends Specification {
NetworkCmProxyFacade mockNetworkCmProxyFacade = Mock()
@SpringBean
- NetworkCmProxyInventoryFacade mockNetworkCmProxyInventoryFacade = Mock()
+ NetworkCmProxyInventoryFacadeImpl mockNetworkCmProxyInventoryFacade = Mock()
@SpringBean
AlternateIdMatcher mockAlternateIdMatcher = Mock()
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy
index 59307640ef..9d79922478 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyInventoryControllerSpec.groovy
@@ -23,7 +23,7 @@ package org.onap.cps.ncmp.rest.controller
import com.fasterxml.jackson.databind.ObjectMapper
import org.onap.cps.TestUtils
-import org.onap.cps.ncmp.api.inventory.NetworkCmProxyInventoryFacade
+import org.onap.cps.ncmp.impl.NetworkCmProxyInventoryFacadeImpl
import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryServiceParameters
import org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse
import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration
@@ -55,7 +55,7 @@ class NetworkCmProxyInventoryControllerSpec extends Specification {
MockMvc mvc
@SpringBean
- NetworkCmProxyInventoryFacade mockNetworkCmProxyInventoryFacade = Mock()
+ NetworkCmProxyInventoryFacadeImpl mockNetworkCmProxyInventoryFacade = Mock()
@SpringBean
NcmpRestInputMapper ncmpRestInputMapper = Mock()
diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyRestExceptionHandlerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyRestExceptionHandlerSpec.groovy
index 26060a02d2..aad04a18ae 100644
--- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyRestExceptionHandlerSpec.groovy
+++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyRestExceptionHandlerSpec.groovy
@@ -31,7 +31,7 @@ import org.onap.cps.ncmp.api.exceptions.DmiRequestException
import org.onap.cps.ncmp.api.exceptions.PayloadTooLargeException
import org.onap.cps.ncmp.api.exceptions.PolicyExecutorException
import org.onap.cps.ncmp.api.exceptions.ServerNcmpException
-import org.onap.cps.ncmp.api.inventory.NetworkCmProxyInventoryFacade
+import org.onap.cps.ncmp.impl.NetworkCmProxyInventoryFacadeImpl
import org.onap.cps.ncmp.impl.data.NcmpCachedResourceRequestHandler
import org.onap.cps.ncmp.impl.data.NcmpPassthroughResourceRequestHandler
import org.onap.cps.ncmp.impl.data.NetworkCmProxyFacade
@@ -76,7 +76,7 @@ class NetworkCmProxyRestExceptionHandlerSpec extends Specification {
NetworkCmProxyFacade mockNetworkCmProxyFacade = Mock()
@SpringBean
- NetworkCmProxyInventoryFacade mockNetworkCmProxyInventoryFacade = Mock()
+ NetworkCmProxyInventoryFacadeImpl mockNetworkCmProxyInventoryFacade = Mock()
@SpringBean
InventoryPersistence mockInventoryPersistence = Mock()
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/NetworkCmProxyInventoryFacade.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/NetworkCmProxyInventoryFacade.java
index 64bec06fec..9bfb775d55 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/NetworkCmProxyInventoryFacade.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/NetworkCmProxyInventoryFacade.java
@@ -1,10 +1,6 @@
/*
* ============LICENSE_START=======================================================
- * Copyright (C) 2021 highstreet technologies GmbH
- * Modifications Copyright (C) 2021-2024 Nordix Foundation
- * Modifications Copyright (C) 2021 Pantheon.tech
- * Modifications Copyright (C) 2021-2022 Bell Canada
- * Modifications Copyright (C) 2023 TechMahindra Ltd.
+ * Copyright (C) 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.
@@ -24,47 +20,18 @@
package org.onap.cps.ncmp.api.inventory;
-import static org.onap.cps.ncmp.impl.inventory.CmHandleQueryParametersValidator.validateCmHandleQueryParameters;
-
import java.util.Collection;
-import java.util.Collections;
import java.util.Map;
-import lombok.RequiredArgsConstructor;
import org.onap.cps.api.model.ModuleDefinition;
import org.onap.cps.api.model.ModuleReference;
-import org.onap.cps.ncmp.api.exceptions.CmHandleNotFoundException;
import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryApiParameters;
import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryServiceParameters;
import org.onap.cps.ncmp.api.inventory.models.CompositeState;
import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration;
import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistrationResponse;
import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle;
-import org.onap.cps.ncmp.impl.inventory.CmHandleQueryService;
-import org.onap.cps.ncmp.impl.inventory.CmHandleRegistrationService;
-import org.onap.cps.ncmp.impl.inventory.InventoryPersistence;
-import org.onap.cps.ncmp.impl.inventory.ParameterizedCmHandleQueryService;
-import org.onap.cps.ncmp.impl.inventory.models.CmHandleQueryConditions;
-import org.onap.cps.ncmp.impl.inventory.models.InventoryQueryConditions;
-import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
-import org.onap.cps.ncmp.impl.inventory.trustlevel.TrustLevelManager;
-import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher;
-import org.onap.cps.ncmp.impl.utils.YangDataConverter;
-import org.onap.cps.utils.JsonObjectMapper;
-import org.springframework.stereotype.Service;
-
-@Service
-@RequiredArgsConstructor
-public class NetworkCmProxyInventoryFacade {
-
- private final CmHandleRegistrationService cmHandleRegistrationService;
- private final CmHandleQueryService cmHandleQueryService;
- private final ParameterizedCmHandleQueryService parameterizedCmHandleQueryService;
- private final InventoryPersistence inventoryPersistence;
- private final JsonObjectMapper jsonObjectMapper;
- private final TrustLevelManager trustLevelManager;
- private final AlternateIdMatcher alternateIdMatcher;
-
+public interface NetworkCmProxyInventoryFacade {
/**
* Registration of Created, Removed, Updated or Upgraded CM Handles.
@@ -72,9 +39,7 @@ public class NetworkCmProxyInventoryFacade {
* @param dmiPluginRegistration Dmi Plugin Registration details
* @return dmiPluginRegistrationResponse
*/
- public DmiPluginRegistrationResponse updateDmiRegistration(final DmiPluginRegistration dmiPluginRegistration) {
- return cmHandleRegistrationService.updateDmiRegistration(dmiPluginRegistration);
- }
+ DmiPluginRegistrationResponse updateDmiRegistration(final DmiPluginRegistration dmiPluginRegistration);
/**
* Get all cm handle references by DMI plugin identifier.
@@ -84,10 +49,8 @@ public class NetworkCmProxyInventoryFacade {
* cm handle id (false) or alternate id (true)
* @return collection of cm handle references
*/
- public Collection<String> getAllCmHandleReferencesByDmiPluginIdentifier(final String dmiPluginIdentifier,
- final boolean outputAlternateId) {
- return cmHandleQueryService.getCmHandleReferencesByDmiPluginIdentifier(dmiPluginIdentifier, outputAlternateId);
- }
+ Collection<String> getAllCmHandleReferencesByDmiPluginIdentifier(final String dmiPluginIdentifier,
+ final boolean outputAlternateId);
/**
* Get all cm handle IDs by various properties.
@@ -97,14 +60,9 @@ public class NetworkCmProxyInventoryFacade {
* cm handle id (false) or alternate id (true)
* @return collection of cm handle references
*/
- public Collection<String> executeParameterizedCmHandleIdSearch(
- final CmHandleQueryServiceParameters cmHandleQueryServiceParameters, final boolean outputAlternateId) {
- validateCmHandleQueryParameters(cmHandleQueryServiceParameters, InventoryQueryConditions.ALL_CONDITION_NAMES);
-
- return parameterizedCmHandleQueryService.queryCmHandleIdsForInventory(cmHandleQueryServiceParameters,
- outputAlternateId);
- }
-
+ Collection<String> executeParameterizedCmHandleIdSearch(final CmHandleQueryServiceParameters
+ cmHandleQueryServiceParameters,
+ final boolean outputAlternateId);
/**
* Retrieve module references for the given cm handle reference.
@@ -112,14 +70,7 @@ public class NetworkCmProxyInventoryFacade {
* @param cmHandleReference cm handle or alternate id identifier
* @return a collection of modules names and revisions
*/
- public Collection<ModuleReference> getYangResourcesModuleReferences(final String cmHandleReference) {
- try {
- final String cmHandleId = alternateIdMatcher.getCmHandleId(cmHandleReference);
- return inventoryPersistence.getYangResourcesModuleReferences(cmHandleId);
- } catch (final CmHandleNotFoundException cmHandleNotFoundException) {
- return Collections.emptyList();
- }
- }
+ Collection<ModuleReference> getYangResourcesModuleReferences(final String cmHandleReference);
/**
* Retrieve module definitions for the given cm handle.
@@ -127,14 +78,7 @@ public class NetworkCmProxyInventoryFacade {
* @param cmHandleReference cm handle or alternate id identifier
* @return a collection of module definition (moduleName, revision and yang resource content)
*/
- public Collection<ModuleDefinition> getModuleDefinitionsByCmHandleReference(final String cmHandleReference) {
- try {
- final String cmHandleId = alternateIdMatcher.getCmHandleId(cmHandleReference);
- return inventoryPersistence.getModuleDefinitionsByCmHandleId(cmHandleId);
- } catch (final CmHandleNotFoundException cmHandleNotFoundException) {
- return Collections.emptyList();
- }
- }
+ Collection<ModuleDefinition> getModuleDefinitionsByCmHandleReference(final String cmHandleReference);
/**
* Get module definitions for the given parameters.
@@ -144,16 +88,9 @@ public class NetworkCmProxyInventoryFacade {
* @param moduleRevision the revision of the module
* @return list of module definitions (module name, revision, yang resource content)
*/
- public Collection<ModuleDefinition> getModuleDefinitionsByCmHandleAndModule(final String cmHandleReference,
- final String moduleName,
- final String moduleRevision) {
- try {
- final String cmHandleId = alternateIdMatcher.getCmHandleId(cmHandleReference);
- return inventoryPersistence.getModuleDefinitionsByCmHandleAndModule(cmHandleId, moduleName, moduleRevision);
- } catch (final CmHandleNotFoundException cmHandleNotFoundException) {
- return Collections.emptyList();
- }
- }
+ Collection<ModuleDefinition> getModuleDefinitionsByCmHandleAndModule(final String cmHandleReference,
+ final String moduleName,
+ final String moduleRevision);
/**
* Retrieve cm handles with details for the given query parameters.
@@ -161,16 +98,7 @@ public class NetworkCmProxyInventoryFacade {
* @param cmHandleQueryApiParameters cm handle query parameters
* @return cm handles with details
*/
- public Collection<NcmpServiceCmHandle> executeCmHandleSearch(
- final CmHandleQueryApiParameters cmHandleQueryApiParameters) {
- final CmHandleQueryServiceParameters cmHandleQueryServiceParameters = jsonObjectMapper.convertToValueType(
- cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class);
- validateCmHandleQueryParameters(cmHandleQueryServiceParameters, CmHandleQueryConditions.ALL_CONDITION_NAMES);
- final Collection<NcmpServiceCmHandle> ncmpServiceCmHandles =
- parameterizedCmHandleQueryService.queryCmHandles(cmHandleQueryServiceParameters);
- trustLevelManager.applyEffectiveTrustLevels(ncmpServiceCmHandles);
- return ncmpServiceCmHandles;
- }
+ Collection<NcmpServiceCmHandle> executeCmHandleSearch(final CmHandleQueryApiParameters cmHandleQueryApiParameters);
/**
* Retrieve cm handle ids for the given query parameters.
@@ -179,14 +107,8 @@ public class NetworkCmProxyInventoryFacade {
* @param outputAlternateId boolean for cm handle reference type either cmHandleId (false) or AlternateId (true)
* @return cm handle ids
*/
- public Collection<String> executeCmHandleIdSearch(final CmHandleQueryApiParameters cmHandleQueryApiParameters,
- final boolean outputAlternateId) {
- final CmHandleQueryServiceParameters cmHandleQueryServiceParameters = jsonObjectMapper.convertToValueType(
- cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class);
- validateCmHandleQueryParameters(cmHandleQueryServiceParameters, CmHandleQueryConditions.ALL_CONDITION_NAMES);
- return parameterizedCmHandleQueryService.queryCmHandleReferenceIds(cmHandleQueryServiceParameters,
- outputAlternateId);
- }
+ Collection<String> executeCmHandleIdSearch(final CmHandleQueryApiParameters cmHandleQueryApiParameters,
+ final boolean outputAlternateId);
/**
* Set the data sync enabled flag, along with the data sync state
@@ -195,9 +117,7 @@ public class NetworkCmProxyInventoryFacade {
* @param cmHandleId cm handle id
* @param dataSyncEnabledTargetValue data sync enabled flag
*/
- public void setDataSyncEnabled(final String cmHandleId, final Boolean dataSyncEnabledTargetValue) {
- cmHandleRegistrationService.setDataSyncEnabled(cmHandleId, dataSyncEnabledTargetValue);
- }
+ void setDataSyncEnabled(final String cmHandleId, final Boolean dataSyncEnabledTargetValue);
/**
* Retrieve cm handle details for a given cm handle reference.
@@ -205,13 +125,7 @@ public class NetworkCmProxyInventoryFacade {
* @param cmHandleReference cm handle or alternate identifier
* @return cm handle details
*/
- public NcmpServiceCmHandle getNcmpServiceCmHandle(final String cmHandleReference) {
- final String cmHandleId = alternateIdMatcher.getCmHandleId(cmHandleReference);
- final NcmpServiceCmHandle ncmpServiceCmHandle = YangDataConverter.toNcmpServiceCmHandle(
- inventoryPersistence.getYangModelCmHandle(cmHandleId));
- trustLevelManager.applyEffectiveTrustLevel(ncmpServiceCmHandle);
- return ncmpServiceCmHandle;
- }
+ NcmpServiceCmHandle getNcmpServiceCmHandle(final String cmHandleReference);
/**
* Get cm handle public properties for a given cm handle or alternate id.
@@ -219,11 +133,7 @@ public class NetworkCmProxyInventoryFacade {
* @param cmHandleReference cm handle or alternate identifier
* @return cm handle public properties
*/
- public Map<String, String> getCmHandlePublicProperties(final String cmHandleReference) {
- final String cmHandleId = alternateIdMatcher.getCmHandleId(cmHandleReference);
- final YangModelCmHandle yangModelCmHandle = inventoryPersistence.getYangModelCmHandle(cmHandleId);
- return YangDataConverter.toPropertiesMap(yangModelCmHandle.getPublicProperties());
- }
+ Map<String, String> getCmHandlePublicProperties(final String cmHandleReference);
/**
* Get cm handle composite state for a given cm handle id.
@@ -231,9 +141,5 @@ public class NetworkCmProxyInventoryFacade {
* @param cmHandleReference cm handle or alternate identifier
* @return cm handle state
*/
- public CompositeState getCmHandleCompositeState(final String cmHandleReference) {
- final String cmHandleId = alternateIdMatcher.getCmHandleId(cmHandleReference);
- return inventoryPersistence.getYangModelCmHandle(cmHandleId).getCompositeState();
- }
-
+ CompositeState getCmHandleCompositeState(final String cmHandleReference);
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/NetworkCmProxyInventoryFacadeImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/NetworkCmProxyInventoryFacadeImpl.java
new file mode 100644
index 0000000000..118c2bba70
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/NetworkCmProxyInventoryFacadeImpl.java
@@ -0,0 +1,169 @@
+/*
+ * ============LICENSE_START=======================================================
+ * Copyright (C) 2021 highstreet technologies GmbH
+ * Modifications Copyright (C) 2021-2024 Nordix Foundation
+ * Modifications Copyright (C) 2021 Pantheon.tech
+ * Modifications Copyright (C) 2021-2022 Bell Canada
+ * Modifications Copyright (C) 2023 TechMahindra Ltd.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.ncmp.impl;
+
+import static org.onap.cps.ncmp.impl.inventory.CmHandleQueryParametersValidator.validateCmHandleQueryParameters;
+
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Map;
+import lombok.RequiredArgsConstructor;
+import org.onap.cps.api.model.ModuleDefinition;
+import org.onap.cps.api.model.ModuleReference;
+import org.onap.cps.ncmp.api.exceptions.CmHandleNotFoundException;
+import org.onap.cps.ncmp.api.inventory.NetworkCmProxyInventoryFacade;
+import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryApiParameters;
+import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryServiceParameters;
+import org.onap.cps.ncmp.api.inventory.models.CompositeState;
+import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration;
+import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistrationResponse;
+import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle;
+import org.onap.cps.ncmp.impl.inventory.CmHandleQueryService;
+import org.onap.cps.ncmp.impl.inventory.CmHandleRegistrationService;
+import org.onap.cps.ncmp.impl.inventory.InventoryPersistence;
+import org.onap.cps.ncmp.impl.inventory.ParameterizedCmHandleQueryService;
+import org.onap.cps.ncmp.impl.inventory.models.CmHandleQueryConditions;
+import org.onap.cps.ncmp.impl.inventory.models.InventoryQueryConditions;
+import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle;
+import org.onap.cps.ncmp.impl.inventory.trustlevel.TrustLevelManager;
+import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher;
+import org.onap.cps.ncmp.impl.utils.YangDataConverter;
+import org.onap.cps.utils.JsonObjectMapper;
+import org.springframework.stereotype.Service;
+
+@Service
+@RequiredArgsConstructor
+public class NetworkCmProxyInventoryFacadeImpl implements NetworkCmProxyInventoryFacade {
+
+ private final CmHandleRegistrationService cmHandleRegistrationService;
+ private final CmHandleQueryService cmHandleQueryService;
+ private final ParameterizedCmHandleQueryService parameterizedCmHandleQueryService;
+ private final InventoryPersistence inventoryPersistence;
+ private final JsonObjectMapper jsonObjectMapper;
+ private final TrustLevelManager trustLevelManager;
+ private final AlternateIdMatcher alternateIdMatcher;
+
+ @Override
+ public DmiPluginRegistrationResponse updateDmiRegistration(final DmiPluginRegistration dmiPluginRegistration) {
+ return cmHandleRegistrationService.updateDmiRegistration(dmiPluginRegistration);
+ }
+
+ @Override
+ public Collection<String> getAllCmHandleReferencesByDmiPluginIdentifier(final String dmiPluginIdentifier,
+ final boolean outputAlternateId) {
+ return cmHandleQueryService.getCmHandleReferencesByDmiPluginIdentifier(dmiPluginIdentifier, outputAlternateId);
+ }
+
+ @Override
+ public Collection<String> executeParameterizedCmHandleIdSearch(
+ final CmHandleQueryServiceParameters cmHandleQueryServiceParameters, final boolean outputAlternateId) {
+ validateCmHandleQueryParameters(cmHandleQueryServiceParameters, InventoryQueryConditions.ALL_CONDITION_NAMES);
+
+ return parameterizedCmHandleQueryService.queryCmHandleIdsForInventory(cmHandleQueryServiceParameters,
+ outputAlternateId);
+ }
+
+ @Override
+ public Collection<ModuleReference> getYangResourcesModuleReferences(final String cmHandleReference) {
+ try {
+ final String cmHandleId = alternateIdMatcher.getCmHandleId(cmHandleReference);
+ return inventoryPersistence.getYangResourcesModuleReferences(cmHandleId);
+ } catch (final CmHandleNotFoundException cmHandleNotFoundException) {
+ return Collections.emptyList();
+ }
+ }
+
+ @Override
+ public Collection<ModuleDefinition> getModuleDefinitionsByCmHandleReference(final String cmHandleReference) {
+ try {
+ final String cmHandleId = alternateIdMatcher.getCmHandleId(cmHandleReference);
+ return inventoryPersistence.getModuleDefinitionsByCmHandleId(cmHandleId);
+ } catch (final CmHandleNotFoundException cmHandleNotFoundException) {
+ return Collections.emptyList();
+ }
+ }
+
+ @Override
+ public Collection<ModuleDefinition> getModuleDefinitionsByCmHandleAndModule(final String cmHandleReference,
+ final String moduleName,
+ final String moduleRevision) {
+ try {
+ final String cmHandleId = alternateIdMatcher.getCmHandleId(cmHandleReference);
+ return inventoryPersistence.getModuleDefinitionsByCmHandleAndModule(cmHandleId, moduleName, moduleRevision);
+ } catch (final CmHandleNotFoundException cmHandleNotFoundException) {
+ return Collections.emptyList();
+ }
+ }
+
+ @Override
+ public Collection<NcmpServiceCmHandle> executeCmHandleSearch(
+ final CmHandleQueryApiParameters cmHandleQueryApiParameters) {
+ final CmHandleQueryServiceParameters cmHandleQueryServiceParameters = jsonObjectMapper.convertToValueType(
+ cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class);
+ validateCmHandleQueryParameters(cmHandleQueryServiceParameters, CmHandleQueryConditions.ALL_CONDITION_NAMES);
+ final Collection<NcmpServiceCmHandle> ncmpServiceCmHandles =
+ parameterizedCmHandleQueryService.queryCmHandles(cmHandleQueryServiceParameters);
+ trustLevelManager.applyEffectiveTrustLevels(ncmpServiceCmHandles);
+ return ncmpServiceCmHandles;
+ }
+
+ @Override
+ public Collection<String> executeCmHandleIdSearch(final CmHandleQueryApiParameters cmHandleQueryApiParameters,
+ final boolean outputAlternateId) {
+ final CmHandleQueryServiceParameters cmHandleQueryServiceParameters = jsonObjectMapper.convertToValueType(
+ cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class);
+ validateCmHandleQueryParameters(cmHandleQueryServiceParameters, CmHandleQueryConditions.ALL_CONDITION_NAMES);
+ return parameterizedCmHandleQueryService.queryCmHandleReferenceIds(cmHandleQueryServiceParameters,
+ outputAlternateId);
+ }
+
+ @Override
+ public void setDataSyncEnabled(final String cmHandleId, final Boolean dataSyncEnabledTargetValue) {
+ cmHandleRegistrationService.setDataSyncEnabled(cmHandleId, dataSyncEnabledTargetValue);
+ }
+
+ @Override
+ public NcmpServiceCmHandle getNcmpServiceCmHandle(final String cmHandleReference) {
+ final String cmHandleId = alternateIdMatcher.getCmHandleId(cmHandleReference);
+ final NcmpServiceCmHandle ncmpServiceCmHandle = YangDataConverter.toNcmpServiceCmHandle(
+ inventoryPersistence.getYangModelCmHandle(cmHandleId));
+ trustLevelManager.applyEffectiveTrustLevel(ncmpServiceCmHandle);
+ return ncmpServiceCmHandle;
+ }
+
+ @Override
+ public Map<String, String> getCmHandlePublicProperties(final String cmHandleReference) {
+ final String cmHandleId = alternateIdMatcher.getCmHandleId(cmHandleReference);
+ final YangModelCmHandle yangModelCmHandle = inventoryPersistence.getYangModelCmHandle(cmHandleId);
+ return YangDataConverter.toPropertiesMap(yangModelCmHandle.getPublicProperties());
+ }
+
+ @Override
+ public CompositeState getCmHandleCompositeState(final String cmHandleReference) {
+ final String cmHandleId = alternateIdMatcher.getCmHandleId(cmHandleReference);
+ return inventoryPersistence.getYangModelCmHandle(cmHandleId).getCompositeState();
+ }
+
+}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cache/CpsAndNcmpLockConfig.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cache/CpsAndNcmpLockConfig.java
new file mode 100644
index 0000000000..61cf939a51
--- /dev/null
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cache/CpsAndNcmpLockConfig.java
@@ -0,0 +1,48 @@
+/*
+ * ============LICENSE_START========================================================
+ * Copyright (C) 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.ncmp.impl.cache;
+
+import com.hazelcast.config.MapConfig;
+import com.hazelcast.map.IMap;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class CpsAndNcmpLockConfig extends HazelcastCacheConfig {
+
+ // Lock names for different use cases ( to be used as cpsAndNcmpLock keys)
+ public static final String MODULE_SYNC_WORK_QUEUE_LOCK_NAME = "workQueueLock";
+
+ private static final MapConfig cpsAndNcmpLockMapConfig = createMapConfig("cpsAndNcmpLockConfig");
+
+ /**
+ * Distributed instance used for locking purpose for various use cases in cps-and-ncmp.
+ * The key of the map entry is name of the lock and should be based on the use case we are locking.
+ *
+ * @return configured map of lock object to have distributed coordination.
+ */
+ @Bean
+ public IMap<String, String> cpsAndNcmpLock() {
+ return getOrCreateHazelcastInstance(cpsAndNcmpLockMapConfig).getMap("cpsAndNcmpLock");
+ }
+
+
+}
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 770dde1c08..75007e2e35 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
@@ -23,6 +23,7 @@ package org.onap.cps.ncmp.impl.cache;
import com.hazelcast.config.Config;
import com.hazelcast.config.MapConfig;
import com.hazelcast.config.NamedConfig;
+import com.hazelcast.config.NearCacheConfig;
import com.hazelcast.config.QueueConfig;
import com.hazelcast.config.RestEndpointGroup;
import com.hazelcast.config.SetConfig;
@@ -94,6 +95,21 @@ public class HazelcastCacheConfig {
return mapConfig;
}
+ protected static MapConfig createMapConfigWithTimeToLiveInSeconds(final String configName,
+ final int timeToLiveInSeconds) {
+ final MapConfig mapConfig = new MapConfig(configName);
+ mapConfig.setBackupCount(1);
+ mapConfig.setTimeToLiveSeconds(timeToLiveInSeconds);
+ return mapConfig;
+ }
+
+ protected static MapConfig createNearCacheMapConfig(final String configName) {
+ final MapConfig mapConfig = new MapConfig(configName);
+ mapConfig.setBackupCount(1);
+ mapConfig.setNearCacheConfig(new NearCacheConfig(configName));
+ return mapConfig;
+ }
+
protected static QueueConfig createQueueConfig(final String configName) {
final QueueConfig commonQueueConfig = new QueueConfig(configName);
commonQueueConfig.setBackupCount(1);
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionComparator.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionComparator.java
index d7f15a2c72..99c5695850 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionComparator.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cmnotificationsubscription/ncmp/CmSubscriptionComparator.java
@@ -46,24 +46,20 @@ public class CmSubscriptionComparator {
final List<DmiCmSubscriptionPredicate> existingDmiCmSubscriptionPredicates) {
final List<DmiCmSubscriptionPredicate> newDmiCmSubscriptionPredicates =
new ArrayList<>();
-
for (final DmiCmSubscriptionPredicate dmiCmSubscriptionPredicate : existingDmiCmSubscriptionPredicates) {
-
final Set<String> targetCmHandleIds = new HashSet<>();
final Set<String> xpaths = new HashSet<>();
final DatastoreType datastoreType = dmiCmSubscriptionPredicate.getDatastoreType();
-
for (final String cmHandleId : dmiCmSubscriptionPredicate.getTargetCmHandleIds()) {
for (final String xpath : dmiCmSubscriptionPredicate.getXpaths()) {
if (!cmSubscriptionPersistenceService.isOngoingCmSubscription(datastoreType,
cmHandleId, xpath)) {
- xpaths.add(xpath);
targetCmHandleIds.add(cmHandleId);
+ xpaths.add(xpath);
}
}
}
-
populateValidDmiSubscriptionPredicates(targetCmHandleIds, xpaths, datastoreType,
newDmiCmSubscriptionPredicates);
}
@@ -73,7 +69,7 @@ public class CmSubscriptionComparator {
private void populateValidDmiSubscriptionPredicates(final Set<String> targetCmHandleIds,
final Set<String> xpaths, final DatastoreType datastoreType,
final List<DmiCmSubscriptionPredicate> dmiCmSubscriptionPredicates) {
- if (!(targetCmHandleIds.isEmpty() || xpaths.isEmpty())) {
+ if (!targetCmHandleIds.isEmpty()) {
final DmiCmSubscriptionPredicate dmiCmSubscriptionPredicate =
new DmiCmSubscriptionPredicate(targetCmHandleIds, datastoreType, xpaths);
dmiCmSubscriptionPredicates.add(dmiCmSubscriptionPredicate);
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutor.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutor.java
index af4331893d..38105329d1 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutor.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutor.java
@@ -26,9 +26,9 @@ import com.fasterxml.jackson.databind.ObjectMapper;
import java.net.UnknownHostException;
import java.time.Duration;
import java.time.temporal.ChronoUnit;
+import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
-import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeoutException;
import lombok.RequiredArgsConstructor;
@@ -68,6 +68,10 @@ public class PolicyExecutor {
@Value("${ncmp.policy-executor.httpclient.all-services.readTimeoutInSeconds:30}")
private long readTimeoutInSeconds;
+ private static final String CHANGE_REQUEST_FORMAT = "cm-legacy";
+ private static final String PERMISSION_BASE_PATH = "operation-permission";
+ private static final String REQUEST_PATH = "permissions";
+
@Qualifier("policyExecutorWebClient")
private final WebClient policyExecutorWebClient;
@@ -110,38 +114,33 @@ public class PolicyExecutor {
}
}
- private Map<String, Object> getSingleRequestAsMap(final YangModelCmHandle yangModelCmHandle,
- final OperationType operationType,
- final String resourceIdentifier,
- final String changeRequestAsJson) {
- final Map<String, Object> data = new HashMap<>(4);
- data.put("cmHandleId", yangModelCmHandle.getId());
- data.put("resourceIdentifier", resourceIdentifier);
- data.put("targetIdentifier", yangModelCmHandle.getAlternateId());
+ private Map<String, Object> getSingleOperationAsMap(final YangModelCmHandle yangModelCmHandle,
+ final OperationType operationType,
+ final String resourceIdentifier,
+ final String changeRequestAsJson) {
+ final Map<String, Object> operationAsMap = new HashMap<>(5);
+ operationAsMap.put("operation", operationType.getOperationName());
+ operationAsMap.put("entityHandleId", yangModelCmHandle.getId());
+ operationAsMap.put("resourceIdentifier", resourceIdentifier);
+ operationAsMap.put("targetIdentifier", yangModelCmHandle.getAlternateId());
if (!OperationType.DELETE.equals(operationType)) {
try {
final Object changeRequestAsObject = objectMapper.readValue(changeRequestAsJson, Object.class);
- data.put("cmChangeRequest", changeRequestAsObject);
+ operationAsMap.put("changeRequest", changeRequestAsObject);
} catch (final JsonProcessingException e) {
throw new NcmpException("Cannot convert Change Request data to Object",
"Invalid Json: " + changeRequestAsJson);
}
}
- final Map<String, Object> request = new HashMap<>(2);
- request.put("schema", getAssociatedPolicyDataSchemaName(operationType));
- request.put("data", data);
- return request;
- }
-
- private static String getAssociatedPolicyDataSchemaName(final OperationType operationType) {
- return "urn:cps:org.onap.cps.ncmp.policy-executor.ncmp-" + operationType.getOperationName() + "-schema:1.0.0";
+ return operationAsMap;
}
- private Object createBodyAsObject(final List<Object> requests) {
- final Map<String, Object> bodyAsMap = new HashMap<>(2);
- bodyAsMap.put("decisionType", "allow");
- bodyAsMap.put("requests", requests);
- return bodyAsMap;
+ private Object createBodyAsObject(final Map<String, Object> operationAsMap) {
+ final Collection<Map<String, Object>> operations = Collections.singletonList(operationAsMap);
+ final Map<String, Object> permissionRequestAsMap = new HashMap<>(2);
+ permissionRequestAsMap.put("changeRequestFormat", CHANGE_REQUEST_FORMAT);
+ permissionRequestAsMap.put("operations", operations);
+ return permissionRequestAsMap;
}
private ResponseEntity<JsonNode> getPolicyExecutorResponse(final YangModelCmHandle yangModelCmHandle,
@@ -149,17 +148,16 @@ public class PolicyExecutor {
final String authorization,
final String resourceIdentifier,
final String changeRequestAsJson) {
- final Map<String, Object> requestAsMap = getSingleRequestAsMap(yangModelCmHandle,
+ final Map<String, Object> operationAsMap = getSingleOperationAsMap(yangModelCmHandle,
operationType,
resourceIdentifier,
changeRequestAsJson);
- final Object bodyAsObject = createBodyAsObject(Collections.singletonList(requestAsMap));
+ final Object bodyAsObject = createBodyAsObject(operationAsMap);
final UrlTemplateParameters urlTemplateParameters = RestServiceUrlTemplateBuilder.newInstance()
- .fixedPathSegment("execute")
- .createUrlTemplateParameters(String.format("%s:%s", serverAddress, serverPort),
- "policy-executor/api");
+ .fixedPathSegment(REQUEST_PATH)
+ .createUrlTemplateParameters(String.format("%s:%s", serverAddress, serverPort), PERMISSION_BASE_PATH);
return policyExecutorWebClient.post()
.uri(urlTemplateParameters.urlTemplate(), urlTemplateParameters.urlVariables())
@@ -172,23 +170,23 @@ public class PolicyExecutor {
}
private static void processSuccessResponse(final JsonNode responseBody) {
- final String decisionId = responseBody.path("decisionId").asText("unknown id");
- final String decision = responseBody.path("decision").asText("unknown");
+ final String id = responseBody.path("id").asText("unknown id");
+ final String permissionResult = responseBody.path("permissionResult").asText("unknown");
final String messageFromPolicyExecutor = responseBody.path("message").asText();
- processDecision(decisionId, decision, messageFromPolicyExecutor, NO_ERROR);
+ processDecision(id, permissionResult, messageFromPolicyExecutor, NO_ERROR);
}
- private static void processDecision(final String decisionId,
- final String decision,
+ private static void processDecision(final String id,
+ final String permissionResult,
final String details,
final Throwable optionalCauseOfError) {
- log.trace("Policy Executor decision id: {} ", decisionId);
- if ("allow".equals(decision)) {
+ log.trace("Policy Executor Decision id: {} ", id);
+ if ("allow".equals(permissionResult)) {
log.trace("Operation allowed.");
} else {
- log.warn("Policy Executor decision: {}", decision);
+ log.warn("Policy Executor permission result: {}", permissionResult);
log.warn("Policy Executor message: {}", details);
- final String message = "Operation not allowed. Decision id " + decisionId + " : " + decision;
+ final String message = "Operation not allowed. Decision id " + id + " : " + permissionResult;
throw new PolicyExecutorException(message, details, optionalCauseOfError);
}
}
@@ -196,6 +194,7 @@ public class PolicyExecutor {
private void processException(final RuntimeException runtimeException) {
if (runtimeException instanceof WebClientResponseException) {
final WebClientResponseException webClientResponseException = (WebClientResponseException) runtimeException;
+ log.warn("HTTP Error Message: {}", webClientResponseException.getMessage());
final int httpStatusCode = webClientResponseException.getStatusCode().value();
processFallbackResponse("Policy Executor returned HTTP Status code " + httpStatusCode + ".",
webClientResponseException);
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 daac63fce4..ed5e703eef 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
@@ -319,9 +319,8 @@ public class CmHandleRegistrationService {
// CPS-1239 Robustness cleaning of in progress cache
private void removeDeletedCmHandleFromModuleSyncMap(final String cmHandleId) {
- if (moduleSyncStartedOnCmHandles.remove(cmHandleId) != null) {
- log.debug("{} removed from in progress map", cmHandleId);
- }
+ moduleSyncStartedOnCmHandles.removeAsync(cmHandleId);
+ log.debug("{} will be removed asynchronously from in progress map", cmHandleId);
}
private List<CmHandleRegistrationResponse> upgradeCmHandles(final Map<YangModelCmHandle, CmHandleState>
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 c97b284bf1..9450805eaf 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
@@ -125,9 +125,8 @@ public class ModuleSyncTasks {
}
private void removeResetCmHandleFromModuleSyncMap(final String resetCmHandleId) {
- if (moduleSyncStartedOnCmHandles.remove(resetCmHandleId) != null) {
- log.info("{} removed from in progress map", resetCmHandleId);
- }
+ moduleSyncStartedOnCmHandles.removeAsync(resetCmHandleId);
+ log.info("{} will be removed asynchronously from in progress map", resetCmHandleId);
}
private static boolean isCmHandleInAdvisedState(final YangModelCmHandle yangModelCmHandle) {
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncWatchdog.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncWatchdog.java
index 74bef43d0b..5b71a8af70 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncWatchdog.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncWatchdog.java
@@ -21,13 +21,14 @@
package org.onap.cps.ncmp.impl.inventory.sync;
+import static org.onap.cps.ncmp.impl.cache.CpsAndNcmpLockConfig.MODULE_SYNC_WORK_QUEUE_LOCK_NAME;
+
import com.hazelcast.map.IMap;
import java.util.Collection;
import java.util.HashSet;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
-import java.util.concurrent.locks.Lock;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
@@ -46,7 +47,7 @@ public class ModuleSyncWatchdog {
private final IMap<String, Object> moduleSyncStartedOnCmHandles;
private final ModuleSyncTasks moduleSyncTasks;
private final AsyncTaskExecutor asyncTaskExecutor;
- private final Lock workQueueLock;
+ private final IMap<String, String> cpsAndNcmpLock;
private final Sleeper sleeper;
private static final int MODULE_SYNC_BATCH_SIZE = 100;
@@ -90,14 +91,16 @@ public class ModuleSyncWatchdog {
* So it can be tested without the queue being emptied immediately as the main public method does.
*/
public void populateWorkQueueIfNeeded() {
- if (moduleSyncWorkQueue.isEmpty() && workQueueLock.tryLock()) {
+ if (moduleSyncWorkQueue.isEmpty() && cpsAndNcmpLock.tryLock(MODULE_SYNC_WORK_QUEUE_LOCK_NAME)) {
+ log.info("Lock acquired by thread : {}", Thread.currentThread().getName());
try {
populateWorkQueue();
if (moduleSyncWorkQueue.isEmpty()) {
setPreviouslyLockedCmHandlesToAdvised();
}
} finally {
- workQueueLock.unlock();
+ cpsAndNcmpLock.unlock(MODULE_SYNC_WORK_QUEUE_LOCK_NAME);
+ log.info("Lock released by thread : {}", Thread.currentThread().getName());
}
}
}
@@ -139,8 +142,7 @@ public class ModuleSyncWatchdog {
log.info("nextBatchCandidates size : {}", nextBatchCandidates.size());
for (final String cmHandleId : nextBatchCandidates) {
final boolean alreadyAddedToInProgressMap = VALUE_FOR_HAZELCAST_IN_PROGRESS_MAP.equals(
- moduleSyncStartedOnCmHandles.putIfAbsent(cmHandleId, VALUE_FOR_HAZELCAST_IN_PROGRESS_MAP,
- SynchronizationCacheConfig.MODULE_SYNC_STARTED_TTL_SECS, TimeUnit.SECONDS));
+ moduleSyncStartedOnCmHandles.putIfAbsent(cmHandleId, VALUE_FOR_HAZELCAST_IN_PROGRESS_MAP));
if (alreadyAddedToInProgressMap) {
log.info("module sync for {} already in progress by other instance", cmHandleId);
} else {
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/SynchronizationCacheConfig.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/SynchronizationCacheConfig.java
index 671e791ac2..d6ac242b30 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/SynchronizationCacheConfig.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/SynchronizationCacheConfig.java
@@ -26,7 +26,6 @@ import com.hazelcast.config.QueueConfig;
import com.hazelcast.config.SetConfig;
import com.hazelcast.map.IMap;
import java.util.concurrent.BlockingQueue;
-import java.util.concurrent.locks.Lock;
import lombok.extern.slf4j.Slf4j;
import org.onap.cps.ncmp.impl.cache.HazelcastCacheConfig;
import org.springframework.context.annotation.Bean;
@@ -43,11 +42,11 @@ public class SynchronizationCacheConfig extends HazelcastCacheConfig {
public static final int DATA_SYNC_SEMAPHORE_TTL_SECS = 1800;
private static final QueueConfig commonQueueConfig = createQueueConfig("defaultQueueConfig");
- private static final MapConfig moduleSyncStartedConfig = createMapConfig("moduleSyncStartedConfig");
+ private static final MapConfig moduleSyncStartedConfig =
+ createMapConfigWithTimeToLiveInSeconds("moduleSyncStartedConfig", MODULE_SYNC_STARTED_TTL_SECS);
private static final MapConfig dataSyncSemaphoresConfig = createMapConfig("dataSyncSemaphoresConfig");
private static final SetConfig moduleSetTagsBeingProcessedConfig
= createSetConfig("moduleSetTagsBeingProcessedConfig");
- private static final String LOCK_NAME_FOR_WORK_QUEUE = "workQueueLock";
/**
* Module Sync Distributed Queue Instance.
@@ -89,21 +88,4 @@ public class SynchronizationCacheConfig extends HazelcastCacheConfig {
public ISet<String> moduleSetTagsBeingProcessed() {
return getOrCreateHazelcastInstance(moduleSetTagsBeingProcessedConfig).getSet("moduleSetTagsBeingProcessed");
}
-
- /**
- * Retrieves a distributed lock used to control access to the work queue for module synchronization.
- * This lock ensures that the population and modification of the work queue are thread-safe and
- * protected from concurrent access across different nodes in the distributed system.
- * The lock guarantees that only one instance of the application can populate or modify the
- * module sync work queue at a time, preventing race conditions and potential data inconsistencies.
- * The lock is obtained using the Hazelcast CP Subsystem's {@link Lock}, which provides
- * strong consistency guarantees for distributed operations.
- *
- * @return a {@link Lock} instance used for synchronizing access to the work queue.
- */
- @Bean
- public Lock workQueueLock() {
- // TODO Method below does not use commonQueueConfig for creating lock (Refactor later)
- return getOrCreateHazelcastInstance(commonQueueConfig).getCPSubsystem().getLock(LOCK_NAME_FOR_WORK_QUEUE);
- }
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelCacheConfig.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelCacheConfig.java
index f9ad3ff937..779024bf9f 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelCacheConfig.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelCacheConfig.java
@@ -33,8 +33,8 @@ public class TrustLevelCacheConfig extends HazelcastCacheConfig {
public static final String TRUST_LEVEL_PER_DMI_PLUGIN = "trustLevelPerDmiPlugin";
public static final String TRUST_LEVEL_PER_CM_HANDLE = "trustLevelPerCmHandle";
- private static final MapConfig trustLevelPerCmHandleIdCacheConfig =
- createMapConfig("trustLevelPerCmHandleCacheConfig");
+ private static final MapConfig trustLevelPerCmHandleIdNearCacheConfig =
+ createNearCacheMapConfig("trustLevelPerCmHandleCacheConfig");
private static final MapConfig trustLevelPerDmiPluginCacheConfig =
createMapConfig("trustLevelPerDmiPluginCacheConfig");
@@ -46,7 +46,7 @@ public class TrustLevelCacheConfig extends HazelcastCacheConfig {
*/
@Bean(TRUST_LEVEL_PER_CM_HANDLE)
public IMap<String, TrustLevel> trustLevelPerCmHandleId() {
- return getOrCreateHazelcastInstance(trustLevelPerCmHandleIdCacheConfig).getMap(TRUST_LEVEL_PER_CM_HANDLE);
+ return getOrCreateHazelcastInstance(trustLevelPerCmHandleIdNearCacheConfig).getMap(TRUST_LEVEL_PER_CM_HANDLE);
}
/**
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManager.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManager.java
index b61e53854e..f68bb3b543 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManager.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManager.java
@@ -64,7 +64,7 @@ public class TrustLevelManager {
public void registerDmiPlugin(final DmiPluginRegistration dmiPluginRegistration) {
final String dmiServiceName = DmiServiceNameResolver.resolveDmiServiceName(RequiredDmiService.DATA,
dmiPluginRegistration);
- trustLevelPerDmiPlugin.put(dmiServiceName, TrustLevel.COMPLETE);
+ trustLevelPerDmiPlugin.putAsync(dmiServiceName, TrustLevel.COMPLETE);
}
/**
@@ -73,24 +73,22 @@ public class TrustLevelManager {
* @param cmHandlesToBeCreated a list of cmHandles being created
*/
public void registerCmHandles(final Map<String, TrustLevel> cmHandlesToBeCreated) {
+ final Map<String, TrustLevel> trustLevelPerCmHandleIdForCache = new HashMap<>();
for (final Map.Entry<String, TrustLevel> entry : cmHandlesToBeCreated.entrySet()) {
final String cmHandleId = entry.getKey();
- if (trustLevelPerCmHandleId.containsKey(cmHandleId)) {
- log.warn("Cm handle: {} already registered", cmHandleId);
- } else {
- TrustLevel initialTrustLevel = entry.getValue();
- if (initialTrustLevel == null) {
- initialTrustLevel = TrustLevel.COMPLETE;
- }
- trustLevelPerCmHandleId.put(cmHandleId, initialTrustLevel);
- if (TrustLevel.NONE.equals(initialTrustLevel)) {
- cmAvcEventPublisher.publishAvcEvent(cmHandleId,
+ TrustLevel initialTrustLevel = entry.getValue();
+ if (initialTrustLevel == null) {
+ initialTrustLevel = TrustLevel.COMPLETE;
+ }
+ trustLevelPerCmHandleIdForCache.put(cmHandleId, initialTrustLevel);
+ if (TrustLevel.NONE.equals(initialTrustLevel)) {
+ cmAvcEventPublisher.publishAvcEvent(cmHandleId,
AVC_CHANGED_ATTRIBUTE_NAME,
AVC_NO_OLD_VALUE,
initialTrustLevel.name());
- }
}
}
+ trustLevelPerCmHandleId.putAllAsync(trustLevelPerCmHandleIdForCache);
}
/**
@@ -105,7 +103,7 @@ public class TrustLevelManager {
final Collection<String> affectedCmHandleIds,
final TrustLevel newDmiTrustLevel) {
final TrustLevel oldDmiTrustLevel = trustLevelPerDmiPlugin.get(dmiServiceName);
- trustLevelPerDmiPlugin.put(dmiServiceName, newDmiTrustLevel);
+ trustLevelPerDmiPlugin.putAsync(dmiServiceName, newDmiTrustLevel);
for (final String affectedCmHandleId : affectedCmHandleIds) {
final TrustLevel cmHandleTrustLevel = trustLevelPerCmHandleId.get(affectedCmHandleId);
final TrustLevel oldEffectiveTrustLevel = cmHandleTrustLevel.getEffectiveTrustLevel(oldDmiTrustLevel);
@@ -131,7 +129,7 @@ public class TrustLevelManager {
final TrustLevel oldEffectiveTrustLevel = oldCmHandleTrustLevel.getEffectiveTrustLevel(dmiTrustLevel);
final TrustLevel newEffectiveTrustLevel = newCmHandleTrustLevel.getEffectiveTrustLevel(dmiTrustLevel);
- trustLevelPerCmHandleId.put(cmHandleId, newCmHandleTrustLevel);
+ trustLevelPerCmHandleId.putAsync(cmHandleId, newCmHandleTrustLevel);
sendAvcNotificationIfRequired(cmHandleId, oldEffectiveTrustLevel, newEffectiveTrustLevel);
}
@@ -175,9 +173,7 @@ public class TrustLevelManager {
*/
public void removeCmHandles(final Collection<String> cmHandleIds) {
for (final String cmHandleId : cmHandleIds) {
- if (trustLevelPerCmHandleId.remove(cmHandleId) == null) {
- log.debug("Removed Cm handle: {} is not in trust level cache", cmHandleId);
- }
+ trustLevelPerCmHandleId.removeAsync(cmHandleId);
}
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorSpec.groovy
index 33dcf5d623..9423246134 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/data/policyexecutor/PolicyExecutorSpec.groovy
@@ -75,7 +75,7 @@ class PolicyExecutorSpec extends Specification {
def 'Permission check with "allow" decision.'() {
given: 'allow response'
- mockResponse([decision:'allow'], HttpStatus.OK)
+ mockResponse([permissionResult:'allow'], HttpStatus.OK)
when: 'permission is checked for an operation'
objectUnderTest.checkPermission(new YangModelCmHandle(), operationType, 'my credentials','my resource',someValidJson)
then: 'system logs the operation is allowed'
@@ -88,7 +88,7 @@ class PolicyExecutorSpec extends Specification {
def 'Permission check with "other" decision (not allowed).'() {
given: 'other response'
- mockResponse([decision:'other', decisionId:123, message:'I dont like Mondays' ], HttpStatus.OK)
+ mockResponse([permissionResult:'other', id:123, message:'I dont like Mondays' ], HttpStatus.OK)
when: 'permission is checked for an operation'
objectUnderTest.checkPermission(new YangModelCmHandle(), PATCH, 'my credentials','my resource',someValidJson)
then: 'Policy Executor exception is thrown'
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 d19081cee5..1c8a19a3bd 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
@@ -21,6 +21,9 @@
package org.onap.cps.ncmp.impl.inventory
+import com.hazelcast.config.Config
+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
@@ -39,12 +42,11 @@ class CmHandleQueryServiceImplSpec extends Specification {
def mockCpsQueryService = Mock(CpsQueryService)
def mockCpsDataService = Mock(CpsDataService)
- def trustLevelPerDmiPlugin = [:]
- def trustLevelPerCmHandleId = [ 'PNFDemo': TrustLevel.COMPLETE, 'PNFDemo2': TrustLevel.NONE, 'PNFDemo4': TrustLevel.NONE ]
+ def trustLevelPerDmiPlugin = HazelcastInstanceFactory.getOrCreateHazelcastInstance(new Config('hazelcastInstanceName')).getMap('trustLevelPerDmiPlugin')
+ def trustLevelPerCmHandleId = HazelcastInstanceFactory.getOrCreateHazelcastInstance(new Config('hazelcastInstanceName')).getMap('trustLevelPerCmHandleId')
def mockCpsValidator = Mock(CpsValidator)
def objectUnderTest = new CmHandleQueryServiceImpl(mockCpsDataService, mockCpsQueryService, trustLevelPerDmiPlugin, trustLevelPerCmHandleId, mockCpsValidator)
-
def static sampleDataNodes = [new DataNode(xpath: "/dmi-registry/cm-handles[@id='ch-1']"),
new DataNode(xpath: "/dmi-registry/cm-handles[@id='ch-2']")]
@@ -56,6 +58,16 @@ class CmHandleQueryServiceImplSpec extends Specification {
def static pnfDemo4 = createDataNode('PNFDemo4')
def static pnfDemo5 = createDataNode('PNFDemo5')
+ def setup() {
+ trustLevelPerCmHandleId.put("PNFDemo", TrustLevel.COMPLETE)
+ trustLevelPerCmHandleId.put("PNFDemo2", TrustLevel.NONE)
+ trustLevelPerCmHandleId.put("PNFDemo4", TrustLevel.NONE)
+ }
+
+ def cleanupSpec() {
+ Hazelcast.getHazelcastInstanceByName('hazelcastInstanceName').shutdown()
+ }
+
def 'Query CmHandles with public properties query pair.'() {
given: 'the DataNodes queried for a given cpsPath are returned from the persistence service.'
mockResponses()
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServiceSpec.groovy
index 67778fc0a3..0706a1e19f 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServiceSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServiceSpec.groovy
@@ -64,7 +64,7 @@ class CmHandleRegistrationServiceSpec extends Specification {
def objectUnderTest = Spy(new CmHandleRegistrationService(
mockNetworkCmProxyDataServicePropertyHandler, mockInventoryPersistence, mockCpsDataService, mockLcmEventsCmHandleStateHandler,
- mockModuleSyncStartedOnCmHandles, mockTrustLevelManager, mockAlternateIdChecker))
+ mockModuleSyncStartedOnCmHandles as IMap<String, Object>, mockTrustLevelManager, mockAlternateIdChecker))
def setup() {
// always accept all cm handles
@@ -86,14 +86,14 @@ class CmHandleRegistrationServiceSpec extends Specification {
mockInventoryPersistence.getYangModelCmHandle('cmhandle-3') >> new YangModelCmHandle(id: 'cmhandle-3', moduleSetTag: '', compositeState: new CompositeState(cmHandleState: CmHandleState.READY))
and: 'cm handle is in READY state'
mockCmHandleQueries.cmHandleHasState('cmhandle-3', CmHandleState.READY) >> true
+ and: 'cm handles is present in in-progress map'
+ mockModuleSyncStartedOnCmHandles.containsKey('cmhandle-2') >> true
when: 'registration is processed'
objectUnderTest.updateDmiRegistration(dmiRegistration)
then: 'cm-handles are removed first'
1 * objectUnderTest.processRemovedCmHandles(*_)
and: 'de-registered cm handle entry is removed from in progress map'
- 1 * mockModuleSyncStartedOnCmHandles.remove('cmhandle-2')
- then: 'cm-handles are created'
- 1 * objectUnderTest.processCreatedCmHandles(*_)
+ 1 * mockModuleSyncStartedOnCmHandles.removeAsync('cmhandle-2')
then: 'cm-handles are updated'
1 * objectUnderTest.processUpdatedCmHandles(*_)
1 * mockNetworkCmProxyDataServicePropertyHandler.updateCmHandleProperties(*_) >> []
@@ -310,6 +310,9 @@ class CmHandleRegistrationServiceSpec extends Specification {
given: 'a registration with three cm-handles to be deleted'
def dmiPluginRegistration = new DmiPluginRegistration(dmiPlugin: 'my-server',
removedCmHandles: ['cmhandle1', 'cmhandle2', 'cmhandle3'])
+ and: 'cm handles to be deleted in the progress map'
+ mockModuleSyncStartedOnCmHandles.containsKey("cmhandle1") >> true
+ mockModuleSyncStartedOnCmHandles.containsKey("cmhandle3") >> true
and: 'cm-handle deletion fails on batch'
mockInventoryPersistence.deleteDataNodes(_) >> { throw new RuntimeException("Failed") }
and: 'cm-handle deletion is successful for 1st and 3rd; failed for 2nd'
@@ -321,11 +324,11 @@ class CmHandleRegistrationServiceSpec extends Specification {
and: 'a response is received for all cm-handles'
response.removedCmHandles.size() == 3
and: 'successfully de-registered cm handle 1 is removed from in progress map'
- 1 * mockModuleSyncStartedOnCmHandles.remove('cmhandle1')
+ 1 * mockModuleSyncStartedOnCmHandles.removeAsync('cmhandle1')
and: 'successfully de-registered cm handle 3 is removed from in progress map even though it was already being removed'
- 1 * mockModuleSyncStartedOnCmHandles.remove('cmhandle3') >> 'already in progress'
+ 1 * mockModuleSyncStartedOnCmHandles.removeAsync('cmhandle3')
and: 'failed de-registered cm handle entries should NOT be removed from in progress map'
- 0 * mockModuleSyncStartedOnCmHandles.remove('cmhandle2')
+ 0 * mockModuleSyncStartedOnCmHandles.removeAsync('cmhandle2')
and: '1st and 3rd cm-handle deletes successfully'
with(response.removedCmHandles[0]) {
assert it.status == Status.SUCCESS
@@ -349,7 +352,6 @@ class CmHandleRegistrationServiceSpec extends Specification {
})
and: 'No cm handles state updates for "upgraded cm handles"'
1 * mockLcmEventsCmHandleStateHandler.updateCmHandleStateBatch([:])
-
}
def 'Remove CmHandle Error Handling: Schema Set Deletion failed'() {
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 de69927d36..c1a8589c48 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
@@ -26,6 +26,8 @@ import com.fasterxml.jackson.databind.ObjectMapper
import org.onap.cps.api.CpsAnchorService
import org.onap.cps.api.CpsDataService
import org.onap.cps.api.CpsModuleService
+import org.onap.cps.api.exceptions.DataNodeNotFoundException
+import org.onap.cps.api.exceptions.DataValidationException
import org.onap.cps.impl.utils.CpsValidator
import org.onap.cps.ncmp.api.exceptions.CmHandleNotFoundException
import org.onap.cps.ncmp.api.inventory.models.CompositeState
@@ -85,7 +87,7 @@ class InventoryPersistenceImplSpec extends Specification {
def alternateId2 = 'another-alternate-id'
def xpath2 = "/dmi-registry/cm-handles[@id='another-cm-handle']"
- def dataNode = new DataNode(xpath: "/dmi-registry/cm-handles[@id='some cm handle']/additional-properties[@name='name1']", leaves: ["name":"name1", "value":"value1"])
+ def dataNode = new DataNode(xpath: "/dmi-registry/cm-handles[@id='some cm handle']/additional-properties[@name='name1']", leaves: leaves)
@Shared
def childDataNodesForCmHandleWithAllProperties = [new DataNode(xpath: "/dmi-registry/cm-handles[@id='some cm handle']/additional-properties[@name='name1']", leaves: ["name":"name1", "value":"value1"]),
@@ -100,7 +102,7 @@ class InventoryPersistenceImplSpec extends Specification {
@Shared
def childDataNodesForCmHandleWithState = [new DataNode(xpath: "/dmi-registry/cm-handles[@id='some-cm-handle']/state", leaves: ['cm-handle-state': 'ADVISED'])]
- def "Retrieve CmHandle using datanode with #scenario."() {
+ def 'Retrieve CmHandle using datanode with #scenario.'() {
given: 'the cps data service returns a data node from the DMI registry'
def dataNode = new DataNode(childDataNodes:childDataNodes, leaves: leaves)
mockCpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, xpath, INCLUDE_ALL_DESCENDANTS) >> [dataNode]
@@ -127,7 +129,7 @@ class InventoryPersistenceImplSpec extends Specification {
'with state details' | childDataNodesForCmHandleWithState || [] || [] || CmHandleState.ADVISED
}
- def "Handling missing service names as null."() {
+ def 'Handling missing service names as null.'() {
given: 'the cps data service returns a data node from the DMI registry with empty child and leaf attributes'
def dataNode = new DataNode(childDataNodes:[], leaves: ['id':cmHandleId])
mockCpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, xpath, INCLUDE_ALL_DESCENDANTS) >> [dataNode]
@@ -141,17 +143,28 @@ class InventoryPersistenceImplSpec extends Specification {
1 * mockCpsValidator.validateNameCharacters(cmHandleId)
}
- def "Retrieve multiple YangModelCmHandles using cm handle ids"() {
+ def 'Retrieve multiple YangModelCmHandles using cm handle ids'() {
given: 'the cps data service returns 2 data nodes from the DMI registry'
def dataNodes = [new DataNode(xpath: xpath, leaves: ['id': cmHandleId]), new DataNode(xpath: xpath2, leaves: ['id': cmHandleId2])]
mockCpsDataService.getDataNodesForMultipleXpaths(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, [xpath, xpath2] , INCLUDE_ALL_DESCENDANTS) >> dataNodes
- when: 'retrieving the yang modelled cm handle'
+ when: 'retrieving the yang modelled cm handles'
def results = objectUnderTest.getYangModelCmHandles([cmHandleId, cmHandleId2])
- then: 'verify both have returned and cmhandleIds are correct'
+ then: 'verify both have returned and cm handle Ids are correct'
assert results.size() == 2
assert results.id.containsAll([cmHandleId, cmHandleId2])
}
+ def 'YangModelCmHandles are not returned for invalid cm handle ids'() {
+ given: 'invalid cm handle id throws a data validation exception'
+ mockCpsValidator.validateNameCharacters('Invalid Cm Handle Id') >> {throw new DataValidationException('','')}
+ and: 'empty collection is returned as no valid cm handle ids are given'
+ mockCpsDataService.getDataNodesForMultipleXpaths(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, [] , INCLUDE_ALL_DESCENDANTS) >> []
+ when: 'retrieving the yang modelled cm handles'
+ def results = objectUnderTest.getYangModelCmHandles(['Invalid Cm Handle Id'])
+ then: 'no YangModelCmHandle is returned'
+ assert results.size() == 0
+ }
+
def "Retrieve multiple YangModelCmHandles using cm handle references"() {
given: 'the cps data service returns 2 data nodes from the DMI registry'
def dataNodes = [new DataNode(xpath: xpath, leaves: ['id': cmHandleId, 'alternate-id':alternateId]), new DataNode(xpath: xpath2, leaves: ['id': cmHandleId2,'alternate-id':alternateId2])]
@@ -337,11 +350,15 @@ class InventoryPersistenceImplSpec extends Specification {
assert thrownException.getDetails().contains('No cm handles found with reference alternate id')
}
- def 'Get multiple yang model cm handles by alternate ids, passing empty collection'() {
- when: 'getting the yang model cm handle for no alternate ids'
- objectUnderTest.getYangModelCmHandleByAlternateIds([])
- then: 'query service is not invoked'
- 0 * mockCmHandleQueries.queryNcmpRegistryByCpsPath(_, _)
+ def 'Get multiple yang model cm handles by alternate ids #scenario'() {
+ when: 'getting the yang model cm handle with a empty/populated collection of alternate Ids'
+ objectUnderTest.getYangModelCmHandleByAlternateIds(alternateIdCollection)
+ then: 'query service invoked when needed'
+ expectedInvocations * mockCmHandleQueries.queryNcmpRegistryByCpsPath(*_) >> [dataNode]
+ where: 'collections are either empty or populated with alternate ids'
+ scenario | alternateIdCollection || expectedInvocations
+ 'empty collection' | [] || 0
+ 'populated collection' | ['alt'] || 1
}
def 'Get CM handle ids for CM Handles that has given module names'() {
@@ -384,10 +401,24 @@ class InventoryPersistenceImplSpec extends Specification {
1 * mockCpsDataService.deleteDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, ['xpath1', 'xpath2'], NO_TIMESTAMP);
}
- def 'Check if cm handle exists for a given cm handle id'() {
+ def 'CM handle exists'() {
given: 'data service returns a datanode with correct cm handle id'
mockCpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, xpath, INCLUDE_ALL_DESCENDANTS) >> [dataNode]
expect: 'cm handle exists for given cm handle id'
- assert true == objectUnderTest.isExistingCmHandleId('some-cm-handle')
+ assert true == objectUnderTest.isExistingCmHandleId(cmHandleId)
+ }
+
+ def 'CM handle does not exist, empty dataNode collection returned'() {
+ given: 'data service returns an empty datanode'
+ mockCpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, xpath, INCLUDE_ALL_DESCENDANTS) >> []
+ expect: 'false is returned for non-existent cm handle'
+ assert false == objectUnderTest.isExistingCmHandleId(cmHandleId)
+ }
+
+ def 'CM handle does not exist, exception thrown'() {
+ given: 'data service throws an exception'
+ mockCpsDataService.getDataNodes(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, "/dmi-registry/cm-handles[@id='non-existent-cm-handle']", INCLUDE_ALL_DESCENDANTS) >> {throw new DataNodeNotFoundException('','')}
+ expect: 'false is returned for non-existent cm handle'
+ assert false == objectUnderTest.isExistingCmHandleId('non-existent-cm-handle')
}
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/NetworkCmProxyInventoryFacadeSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/NetworkCmProxyInventoryFacadeSpec.groovy
index ae2554762f..c62a87f5c3 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/NetworkCmProxyInventoryFacadeSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/NetworkCmProxyInventoryFacadeSpec.groovy
@@ -24,7 +24,7 @@
package org.onap.cps.ncmp.impl.inventory
import com.fasterxml.jackson.databind.ObjectMapper
-import org.onap.cps.ncmp.api.inventory.NetworkCmProxyInventoryFacade
+import org.onap.cps.api.model.ConditionProperties
import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryApiParameters
import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryServiceParameters
import org.onap.cps.ncmp.api.inventory.models.CompositeState
@@ -32,12 +32,12 @@ import org.onap.cps.ncmp.api.inventory.models.ConditionApiProperties
import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration
import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle
import org.onap.cps.ncmp.api.inventory.models.TrustLevel
+import org.onap.cps.ncmp.impl.NetworkCmProxyInventoryFacadeImpl
import org.onap.cps.ncmp.impl.inventory.models.CmHandleState
import org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory
import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle
import org.onap.cps.ncmp.impl.inventory.trustlevel.TrustLevelManager
import org.onap.cps.ncmp.impl.utils.AlternateIdMatcher
-import org.onap.cps.api.model.ConditionProperties
import org.onap.cps.utils.JsonObjectMapper
import spock.lang.Specification
@@ -50,7 +50,7 @@ class NetworkCmProxyInventoryFacadeSpec extends Specification {
def mockInventoryPersistence = Mock(InventoryPersistence)
def mockTrustLevelManager = Mock(TrustLevelManager)
def mockAlternateIdMatcher = Mock(AlternateIdMatcher)
- def objectUnderTest = new NetworkCmProxyInventoryFacade(mockCmHandleRegistrationService, mockCmHandleQueryService, mockParameterizedCmHandleQueryService, mockInventoryPersistence, spiedJsonObjectMapper, mockTrustLevelManager, mockAlternateIdMatcher)
+ def objectUnderTest = new NetworkCmProxyInventoryFacadeImpl(mockCmHandleRegistrationService, mockCmHandleQueryService, mockParameterizedCmHandleQueryService, mockInventoryPersistence, spiedJsonObjectMapper, mockTrustLevelManager, mockAlternateIdMatcher)
def 'Update DMI Registration'() {
given: 'an (updated) dmi plugin registration'
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasksSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasksSpec.groovy
index 97c2488bc3..c7fe45db90 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasksSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasksSpec.groovy
@@ -194,7 +194,7 @@ class ModuleSyncTasksSpec extends Specification {
def loggingEvent = getLoggingEvent()
assert loggingEvent.level == Level.INFO
and: 'the log indicates the cm handle entry is removed successfully'
- assert loggingEvent.formattedMessage == 'ch-1 removed from in progress map'
+ assert loggingEvent.formattedMessage == 'ch-1 will be removed asynchronously from in progress map'
}
def 'Sync and upgrade CM handle if in upgrade state for #scenario'() {
@@ -214,18 +214,6 @@ class ModuleSyncTasksSpec extends Specification {
'module upgrade failed' | MODULE_UPGRADE_FAILED
}
-
- def 'Remove non-existing cm handle id from hazelcast map'() {
- given: 'hazelcast map does not contains cm handle id'
- def result = moduleSyncStartedOnCmHandles.get('non-existing-cm-handle')
- assert result == null
- when: 'remove cm handle entry from hazelcast map'
- objectUnderTest.removeResetCmHandleFromModuleSyncMap('non-existing-cm-handle')
- then: 'no event is logged'
- def loggingEvent = getLoggingEvent()
- assert loggingEvent == null
- }
-
def cmHandleByIdAndState(cmHandleId, cmHandleState) {
return new YangModelCmHandle(id: cmHandleId, compositeState: new CompositeState(cmHandleState: cmHandleState))
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncWatchdogSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncWatchdogSpec.groovy
index 4cf07e4c24..a9b88c2d3b 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncWatchdogSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncWatchdogSpec.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");
@@ -44,11 +44,11 @@ class ModuleSyncWatchdogSpec extends Specification {
def spiedAsyncTaskExecutor = Spy(AsyncTaskExecutor)
- def mockWorkQueueLock = Mock(Lock)
+ def mockCpsAndNcmpLock = Mock(IMap<String,String>)
def spiedSleeper = Spy(Sleeper)
- def objectUnderTest = new ModuleSyncWatchdog(mockModuleOperationsUtils, moduleSyncWorkQueue , mockModuleSyncStartedOnCmHandles, mockModuleSyncTasks, spiedAsyncTaskExecutor, mockWorkQueueLock, spiedSleeper)
+ def objectUnderTest = new ModuleSyncWatchdog(mockModuleOperationsUtils, moduleSyncWorkQueue , mockModuleSyncStartedOnCmHandles, mockModuleSyncTasks, spiedAsyncTaskExecutor, mockCpsAndNcmpLock, spiedSleeper)
void setup() {
spiedAsyncTaskExecutor.setupThreadPool()
@@ -59,14 +59,16 @@ class ModuleSyncWatchdogSpec extends Specification {
mockModuleOperationsUtils.getAdvisedCmHandleIds() >> createCmHandleIds(numberOfAdvisedCmHandles)
and: 'module sync utilities returns no failed (locked) cm handles'
mockModuleOperationsUtils.getCmHandlesThatFailedModelSyncOrUpgrade() >> []
- and: 'the work queue is not locked'
- mockWorkQueueLock.tryLock() >> true
+ and: 'the work queue can be locked'
+ mockCpsAndNcmpLock.tryLock('workQueueLock') >> true
and: 'the executor has enough available threads'
spiedAsyncTaskExecutor.getAsyncTaskParallelismLevel() >> 3
when: ' module sync is started'
objectUnderTest.moduleSyncAdvisedCmHandles()
then: 'it performs #expectedNumberOfTaskExecutions tasks'
expectedNumberOfTaskExecutions * spiedAsyncTaskExecutor.executeTask(*_)
+ and: 'the executing thread is unlocked'
+ 1 * mockCpsAndNcmpLock.unlock('workQueueLock')
where: 'the following parameter are used'
scenario | numberOfAdvisedCmHandles || expectedNumberOfTaskExecutions
'none at all' | 0 || 0
@@ -80,8 +82,8 @@ class ModuleSyncWatchdogSpec extends Specification {
def 'Module sync cm handles starts with no available threads.'() {
given: 'module sync utilities returns a advise cm handles'
mockModuleOperationsUtils.getAdvisedCmHandleIds() >> createCmHandleIds(1)
- and: 'the work queue is not locked'
- mockWorkQueueLock.tryLock() >> true
+ and: 'the work queue can be locked'
+ mockCpsAndNcmpLock.tryLock('workQueueLock') >> true
and: 'the executor first has no threads but has one thread on the second attempt'
spiedAsyncTaskExecutor.getAsyncTaskParallelismLevel() >>> [ 0, 1 ]
when: ' module sync is started'
@@ -93,8 +95,8 @@ class ModuleSyncWatchdogSpec extends Specification {
def 'Module sync advised cm handle already handled by other thread.'() {
given: 'module sync utilities returns an advised cm handle'
mockModuleOperationsUtils.getAdvisedCmHandleIds() >> createCmHandleIds(1)
- and: 'the work queue is not locked'
- mockWorkQueueLock.tryLock() >> true
+ and: 'the work queue can be locked'
+ mockCpsAndNcmpLock.tryLock('workQueueLock') >> true
and: 'the executor has a thread available'
spiedAsyncTaskExecutor.getAsyncTaskParallelismLevel() >> 1
and: 'the semaphore cache indicates the cm handle is already being processed'
@@ -131,16 +133,18 @@ class ModuleSyncWatchdogSpec extends Specification {
def 'Module Sync Locking.'() {
given: 'module sync utilities returns an advised cm handle'
mockModuleOperationsUtils.getAdvisedCmHandleIds() >> createCmHandleIds(1)
- and: 'can lock is : #canLock'
- mockWorkQueueLock.tryLock() >> canLock
+ and: 'can be locked is : #canLock'
+ mockCpsAndNcmpLock.tryLock('workQueueLock') >> canLock
when: 'attempt to populate the work queue'
objectUnderTest.populateWorkQueueIfNeeded()
then: 'the queue remains empty is #expectQueueRemainsEmpty'
assert moduleSyncWorkQueue.isEmpty() == expectQueueRemainsEmpty
+ and: 'unlock is called only when thread is able to enter the critical section'
+ expectedInvocationToUnlock * mockCpsAndNcmpLock.unlock('workQueueLock')
where: 'the following lock states are applied'
- canLock | expectQueueRemainsEmpty
- false | true
- true | false
+ canLock || expectQueueRemainsEmpty || expectedInvocationToUnlock
+ false || true || 0
+ true || false || 1
}
def 'Sleeper gets interrupted.'() {
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDogSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDogSpec.groovy
index 32f4503005..097387c038 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDogSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDogSpec.groovy
@@ -20,6 +20,9 @@
package org.onap.cps.ncmp.impl.inventory.trustlevel
+import com.hazelcast.config.Config
+import com.hazelcast.core.Hazelcast
+import com.hazelcast.instance.impl.HazelcastInstanceFactory
import org.onap.cps.ncmp.api.inventory.models.TrustLevel
import org.onap.cps.ncmp.impl.dmi.DmiRestClient
import org.onap.cps.ncmp.impl.inventory.CmHandleQueryService
@@ -32,11 +35,16 @@ class DmiPluginTrustLevelWatchDogSpec extends Specification {
def mockDmiRestClient = Mock(DmiRestClient)
def mockCmHandleQueryService = Mock(CmHandleQueryService)
def mockTrustLevelManager = Mock(TrustLevelManager)
- def trustLevelPerDmiPlugin = [:]
-
+ def trustLevelPerDmiPlugin = HazelcastInstanceFactory
+ .getOrCreateHazelcastInstance(new Config('hazelcastInstanceName'))
+ .getMap('trustLevelPerDmiPlugin')
def objectUnderTest = new DmiPluginTrustLevelWatchDog(mockDmiRestClient, mockCmHandleQueryService, mockTrustLevelManager, trustLevelPerDmiPlugin)
+ def cleanupSpec() {
+ Hazelcast.getHazelcastInstanceByName('hazelcastInstanceName').shutdown()
+ }
+
def 'watch dmi plugin health status for #dmiHealhStatus'() {
given: 'the cache has been initialised and "knows" about dmi-1'
trustLevelPerDmiPlugin.put('dmi-1', dmiOldTrustLevel)
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManagerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManagerSpec.groovy
index 1088ca8e06..1ab517cdcf 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManagerSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManagerSpec.groovy
@@ -77,19 +77,6 @@ class TrustLevelManagerSpec extends Specification {
assert trustLevelPerCmHandleId.get('ch-2') == TrustLevel.COMPLETE
}
- def 'Initial cm handle registration where a cm handle is already in the cache'() {
- given: 'a trusted cm handle'
- def cmHandleModelsToBeCreated = ['ch-1': TrustLevel.NONE]
- and: 'the cm handle id already in the cache'
- trustLevelPerCmHandleId.put('ch-1', TrustLevel.COMPLETE)
- when: 'method to register to the cache is called'
- objectUnderTest.registerCmHandles(cmHandleModelsToBeCreated)
- then: 'no notification sent'
- 0 * mockAttributeValueChangeEventPublisher.publishAvcEvent(*_)
- and: 'cm handle cache is not updated'
- assert trustLevelPerCmHandleId.get('ch-1') == TrustLevel.COMPLETE
- }
-
def 'Initial cm handle registration with a cm handle that is not trusted'() {
given: 'a not trusted cm handle'
def cmHandleModelsToBeCreated = ['ch-2': TrustLevel.NONE]
diff --git a/cps-rest/docs/openapi/components.yml b/cps-rest/docs/openapi/components.yml
index 1db4185330..1a7e4308d9 100644
--- a/cps-rest/docs/openapi/components.yml
+++ b/cps-rest/docs/openapi/components.yml
@@ -326,7 +326,7 @@ components:
dryRunInQuery:
name: dry-run
in: query
- description: Boolean flag to validate data, without persisting it. Default value is set to false.
+ description: Boolean flag to validate data, without persisting it. Default value is false.
required: false
schema:
type: boolean
diff --git a/cps-rest/docs/openapi/cpsData.yml b/cps-rest/docs/openapi/cpsData.yml
index 36000fd7d8..178a68fb77 100644
--- a/cps-rest/docs/openapi/cpsData.yml
+++ b/cps-rest/docs/openapi/cpsData.yml
@@ -31,6 +31,7 @@ listElementByDataspaceAndAnchor:
- $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
- $ref: 'components.yml#/components/parameters/anchorNameInPath'
- $ref: 'components.yml#/components/parameters/requiredXpathInQuery'
+ - $ref: 'components.yml#/components/parameters/dryRunInQuery'
- $ref: 'components.yml#/components/parameters/observedTimestampInQuery'
- $ref: 'components.yml#/components/parameters/contentTypeInHeader'
requestBody:
@@ -70,6 +71,7 @@ listElementByDataspaceAndAnchor:
- $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
- $ref: 'components.yml#/components/parameters/anchorNameInPath'
- $ref: 'components.yml#/components/parameters/requiredXpathInQuery'
+ - $ref: 'components.yml#/components/parameters/dryRunInQuery'
- $ref: 'components.yml#/components/parameters/observedTimestampInQuery'
- $ref: 'components.yml#/components/parameters/contentTypeInHeader'
requestBody:
@@ -154,6 +156,7 @@ nodesByDataspaceAndAnchor:
- $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
- $ref: 'components.yml#/components/parameters/anchorNameInPath'
- $ref: 'components.yml#/components/parameters/xpathInQuery'
+ - $ref: 'components.yml#/components/parameters/dryRunInQuery'
- $ref: 'components.yml#/components/parameters/observedTimestampInQuery'
- $ref: 'components.yml#/components/parameters/contentTypeInHeader'
requestBody:
@@ -214,6 +217,7 @@ nodesByDataspaceAndAnchor:
- $ref: 'components.yml#/components/parameters/dataspaceNameInPath'
- $ref: 'components.yml#/components/parameters/anchorNameInPath'
- $ref: 'components.yml#/components/parameters/xpathInQuery'
+ - $ref: 'components.yml#/components/parameters/dryRunInQuery'
- $ref: 'components.yml#/components/parameters/observedTimestampInQuery'
- $ref: 'components.yml#/components/parameters/contentTypeInHeader'
requestBody:
diff --git a/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java b/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java
index d460f52415..be552ecc6a 100755
--- a/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java
+++ b/cps-rest/src/main/java/org/onap/cps/rest/controller/DataRestController.java
@@ -102,12 +102,17 @@ public class DataRestController implements CpsDataApi {
@Override
public ResponseEntity<String> addListElements(final String apiVersion, final String dataspaceName,
final String anchorName, final String parentNodeXpath,
- final String nodeData, final String observedTimestamp,
- final String contentTypeInHeader) {
+ final String nodeData, final Boolean dryRunEnabled,
+ final String observedTimestamp, final String contentTypeInHeader) {
final ContentType contentType = ContentType.fromString(contentTypeInHeader);
- cpsDataService.saveListElements(dataspaceName, anchorName, parentNodeXpath,
- nodeData, toOffsetDateTime(observedTimestamp), contentType);
- return new ResponseEntity<>(HttpStatus.CREATED);
+ if (Boolean.TRUE.equals(dryRunEnabled)) {
+ cpsDataService.validateData(dataspaceName, anchorName, parentNodeXpath, nodeData, contentType);
+ return ResponseEntity.ok().build();
+ } else {
+ cpsDataService.saveListElements(dataspaceName, anchorName, parentNodeXpath,
+ nodeData, toOffsetDateTime(observedTimestamp), contentType);
+ }
+ return ResponseEntity.status(HttpStatus.CREATED).build();
}
@Override
@@ -151,34 +156,50 @@ public class DataRestController implements CpsDataApi {
@Override
public ResponseEntity<Object> updateNodeLeaves(final String apiVersion, final String dataspaceName,
final String anchorName, final String nodeData,
- final String parentNodeXpath, final String observedTimestamp,
- final String contentTypeInHeader) {
+ final String parentNodeXpath, final Boolean dryRunEnabled,
+ final String observedTimestamp, final String contentTypeInHeader) {
final ContentType contentType = ContentType.fromString(contentTypeInHeader);
- cpsDataService.updateNodeLeaves(dataspaceName, anchorName, parentNodeXpath,
- nodeData, toOffsetDateTime(observedTimestamp), contentType);
- return new ResponseEntity<>(HttpStatus.OK);
+ if (Boolean.TRUE.equals(dryRunEnabled)) {
+ cpsDataService.validateData(dataspaceName, anchorName, parentNodeXpath, nodeData, contentType);
+ return ResponseEntity.ok().build();
+ } else {
+ cpsDataService.updateNodeLeaves(dataspaceName, anchorName, parentNodeXpath,
+ nodeData, toOffsetDateTime(observedTimestamp), contentType);
+ }
+ return ResponseEntity.status(HttpStatus.OK).build();
}
@Override
public ResponseEntity<Object> replaceNode(final String apiVersion, final String dataspaceName,
final String anchorName, final String nodeData,
- final String parentNodeXpath, final String observedTimestamp,
- final String contentTypeInHeader) {
+ final String parentNodeXpath, final Boolean dryRunEnabled,
+ final String observedTimestamp, final String contentTypeInHeader) {
final ContentType contentType = ContentType.fromString(contentTypeInHeader);
- cpsDataService.updateDataNodeAndDescendants(dataspaceName, anchorName, parentNodeXpath,
- nodeData, toOffsetDateTime(observedTimestamp), contentType);
- return new ResponseEntity<>(HttpStatus.OK);
+ if (Boolean.TRUE.equals(dryRunEnabled)) {
+ cpsDataService.validateData(dataspaceName, anchorName, parentNodeXpath, nodeData, contentType);
+ return ResponseEntity.ok().build();
+ } else {
+ cpsDataService.updateDataNodeAndDescendants(dataspaceName, anchorName, parentNodeXpath,
+ nodeData, toOffsetDateTime(observedTimestamp), contentType);
+ }
+ return ResponseEntity.status(HttpStatus.OK).build();
}
@Override
public ResponseEntity<Object> replaceListContent(final String apiVersion, final String dataspaceName,
final String anchorName, final String parentNodeXpath,
- final String nodeData, final String observedTimestamp,
- final String contentTypeInHeader) {
+ final String nodeData, final Boolean dryRunEnabled,
+ final String observedTimestamp, final String contentTypeInHeader) {
final ContentType contentType = ContentType.fromString(contentTypeInHeader);
- cpsDataService.replaceListContent(dataspaceName, anchorName, parentNodeXpath,
- nodeData, toOffsetDateTime(observedTimestamp), contentType);
- return new ResponseEntity<>(HttpStatus.OK);
+ if (Boolean.TRUE.equals(dryRunEnabled)) {
+ cpsDataService.validateData(dataspaceName, anchorName, parentNodeXpath, nodeData,
+ ContentType.JSON);
+ return ResponseEntity.ok().build();
+ } else {
+ cpsDataService.replaceListContent(dataspaceName, anchorName, parentNodeXpath,
+ nodeData, toOffsetDateTime(observedTimestamp), contentType);
+ }
+ return ResponseEntity.status(HttpStatus.OK).build();
}
@Override
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 915fbdecf5..ca89fafe83 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
@@ -168,16 +168,17 @@ class DataRestControllerSpec extends Specification {
given: 'an endpoint to create a node'
def endpoint = "$dataNodeBaseEndpointV1/anchors/$anchorName/nodes"
def parentNodeXpath = '/'
+ and: 'dryRunEnabled flag is set to true'
def dryRunEnabled = 'true'
when: 'post is invoked with json data and dry-run flag enabled'
def response =
- mvc.perform(
- post(endpoint)
- .contentType(MediaType.APPLICATION_JSON)
- .param('xpath', parentNodeXpath)
- .param('dry-run', dryRunEnabled)
- .content(requestBodyJson)
- ).andReturn().response
+ mvc.perform(
+ post(endpoint)
+ .contentType(MediaType.APPLICATION_JSON)
+ .param('xpath', parentNodeXpath)
+ .param('dry-run', dryRunEnabled)
+ .content(requestBodyJson)
+ ).andReturn().response
then: 'a 200 OK response is returned'
response.status == HttpStatus.OK.value()
then: 'the service was called with correct parameters'
@@ -263,6 +264,26 @@ class DataRestControllerSpec extends Specification {
'Content type XML with invalid observed-timestamp' | 'invalid' | MediaType.APPLICATION_XML | requestBodyXml || 0 | HttpStatus.BAD_REQUEST | expectedXmlData | ContentType.XML
}
+ def 'Validate data using Save list elements API'() {
+ given: 'endpoint to save list elements'
+ def endpoint = "$dataNodeBaseEndpointV1/anchors/$anchorName/list-nodes"
+ and: 'dryRunEnabled flag is set to true'
+ def dryRunEnabled = 'true'
+ when: 'post request is performed'
+ def response =
+ mvc.perform(
+ post(endpoint)
+ .contentType(MediaType.APPLICATION_JSON)
+ .param('xpath', '/')
+ .content(requestBodyJson)
+ .param('dry-run', dryRunEnabled)
+ ).andReturn().response
+ then: 'a 200 OK response is returned'
+ response.status == HttpStatus.OK.value()
+ then: 'the service was called with correct parameters'
+ 1 * mockCpsDataService.validateData(dataspaceName, anchorName, '/', requestBodyJson, ContentType.JSON)
+ }
+
def 'Get data node with leaves'() {
given: 'the service returns data node leaves'
def xpath = 'parent-1'
@@ -515,6 +536,26 @@ class DataRestControllerSpec extends Specification {
'with invalid observed-timestamp' | 'invalid' || 0 | HttpStatus.BAD_REQUEST
}
+ def 'Validate data using Update a node API'() {
+ given: 'endpoint to update a node leaves'
+ def endpoint = "$dataNodeBaseEndpointV1/anchors/$anchorName/nodes"
+ and: 'dryRunEnabled flag is set to true'
+ def dryRunEnabled = 'true'
+ when: 'patch request is performed'
+ def response =
+ mvc.perform(
+ patch(endpoint)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(requestBodyJson)
+ .param('xpath', '/')
+ .param('dry-run', dryRunEnabled)
+ ).andReturn().response
+ then: 'a 200 OK response is returned'
+ response.status == HttpStatus.OK.value()
+ then: 'the service was called with correct parameters'
+ 1 * mockCpsDataService.validateData(dataspaceName, anchorName, '/', requestBodyJson, ContentType.JSON)
+ }
+
def 'Replace data node tree: #scenario.'() {
given: 'endpoint to replace node'
def endpoint = "$dataNodeBaseEndpointV1/anchors/$anchorName/nodes"
@@ -540,6 +581,26 @@ class DataRestControllerSpec extends Specification {
'XML content: some xpath by parent' | '/some/xpath' | MediaType.APPLICATION_XML || '/some/xpath' | requestBodyXml | expectedXmlData | ContentType.XML
}
+ def 'Validate data using Replace data node API'() {
+ given: 'endpoint to replace node'
+ def endpoint = "$dataNodeBaseEndpointV1/anchors/$anchorName/nodes"
+ and: 'dryRunEnabled flag is set to true'
+ def dryRunEnabled = 'true'
+ when: 'put request is performed'
+ def response =
+ mvc.perform(
+ put(endpoint)
+ .contentType(MediaType.APPLICATION_JSON)
+ .content(requestBodyJson)
+ .param('xpath', '/')
+ .param('dry-run', dryRunEnabled)
+ ).andReturn().response
+ then: 'a 200 OK response is returned'
+ response.status == HttpStatus.OK.value()
+ then: 'the service was called with correct parameters'
+ 1 * mockCpsDataService.validateData(dataspaceName, anchorName, '/', requestBodyJson, ContentType.JSON)
+ }
+
def 'Update data node and descendants with observedTimestamp.'() {
given: 'endpoint to replace node'
def endpoint = "$dataNodeBaseEndpointV1/anchors/$anchorName/nodes"
@@ -605,6 +666,26 @@ class DataRestControllerSpec extends Specification {
'with invalid observed-timestamp' | 'invalid' || 0 | HttpStatus.BAD_REQUEST
}
+ def 'Validate data using Replace list content API'() {
+ given: 'endpoint to replace list-nodes'
+ def endpoint = "$dataNodeBaseEndpointV1/anchors/$anchorName/list-nodes"
+ and: 'dryRunEnabled flag is set to true'
+ def dryRunEnabled = 'true'
+ when: 'put request is performed'
+ def response =
+ mvc.perform(
+ put(endpoint)
+ .contentType(MediaType.APPLICATION_JSON)
+ .param('xpath', '/')
+ .content(requestBodyJson)
+ .param('dry-run', dryRunEnabled)
+ ).andReturn().response
+ then: 'a 200 OK response is returned'
+ response.status == HttpStatus.OK.value()
+ then: 'the service was called with correct parameters'
+ 1 * mockCpsDataService.validateData(dataspaceName, anchorName, '/', requestBodyJson, ContentType.JSON)
+ }
+
def 'Delete list element #scenario.'() {
when: 'list-nodes endpoint is invoked with delete operation'
def deleteRequestBuilder = delete("$dataNodeBaseEndpointV1/anchors/$anchorName/list-nodes")
diff --git a/docs/api/swagger/cps/openapi.yaml b/docs/api/swagger/cps/openapi.yaml
index 7a300207cf..c84609b638 100644
--- a/docs/api/swagger/cps/openapi.yaml
+++ b/docs/api/swagger/cps/openapi.yaml
@@ -1354,6 +1354,15 @@ paths:
schema:
default: /
type: string
+ - description: "Boolean flag to validate data, without persisting it. Default\
+ \ value is false."
+ in: query
+ name: dry-run
+ required: false
+ schema:
+ default: false
+ example: false
+ type: boolean
- description: observed-timestamp
in: query
name: observed-timestamp
@@ -1474,7 +1483,7 @@ paths:
default: /
type: string
- description: "Boolean flag to validate data, without persisting it. Default\
- \ value is set to false."
+ \ value is false."
in: query
name: dry-run
required: false
@@ -1610,6 +1619,15 @@ paths:
schema:
default: /
type: string
+ - description: "Boolean flag to validate data, without persisting it. Default\
+ \ value is false."
+ in: query
+ name: dry-run
+ required: false
+ schema:
+ default: false
+ example: false
+ type: boolean
- description: observed-timestamp
in: query
name: observed-timestamp
@@ -1804,6 +1822,15 @@ paths:
required: true
schema:
type: string
+ - description: "Boolean flag to validate data, without persisting it. Default\
+ \ value is false."
+ in: query
+ name: dry-run
+ required: false
+ schema:
+ default: false
+ example: false
+ type: boolean
- description: observed-timestamp
in: query
name: observed-timestamp
@@ -1920,6 +1947,15 @@ paths:
required: true
schema:
type: string
+ - description: "Boolean flag to validate data, without persisting it. Default\
+ \ value is false."
+ in: query
+ name: dry-run
+ required: false
+ schema:
+ default: false
+ example: false
+ type: boolean
- description: observed-timestamp
in: query
name: observed-timestamp
@@ -2623,17 +2659,9 @@ components:
- application/json
- application/xml
type: string
- observedTimestampInQuery:
- description: observed-timestamp
- in: query
- name: observed-timestamp
- required: false
- schema:
- example: 2021-03-21T00:10:34.030-0100
- type: string
dryRunInQuery:
description: "Boolean flag to validate data, without persisting it. Default\
- \ value is set to false."
+ \ value is false."
in: query
name: dry-run
required: false
@@ -2641,6 +2669,14 @@ components:
default: false
example: false
type: boolean
+ observedTimestampInQuery:
+ description: observed-timestamp
+ in: query
+ name: observed-timestamp
+ required: false
+ schema:
+ example: 2021-03-21T00:10:34.030-0100
+ type: string
requiredXpathInQuery:
description: "For more details on xpath, please refer https://docs.onap.org/projects/onap-cps/en/latest/xpath.html"
examples:
diff --git a/docs/api/swagger/policy-executor/openapi.yaml b/docs/api/swagger/policy-executor/openapi.yaml
index 1248c0d08b..ba341b2d57 100644
--- a/docs/api/swagger/policy-executor/openapi.yaml
+++ b/docs/api/swagger/policy-executor/openapi.yaml
@@ -18,229 +18,179 @@
openapi: 3.0.3
info:
- description: Allows NCMP to execute a policy defined by a third party implementation
- before proceeding with a CM operation
- title: Policy Executor
- version: 1.0.0
+ title: Operation permission API
+ description: "Allows a client application to execute a permission request defined by a third party implementation before proceeding with an operation. As an example, a permission can be requested before performing any configuration management operation."
+ version: 1.0.0-alpha.1+1
+ contact:
+ name: CPS team
+ url: https://lf-onap.atlassian.net/wiki/spaces/DW/pages/16442177/Configuration+Persistence+Service+Developer+s+Landing+Page
+ email: cpsteam@est.tech
+ license:
+ name: Copyright (C) 2024 Nordix Foundation
+ x-audience: external-partner
+ x-api-id: c7fc2f5b-16bd-4bcb-8ac8-ea8d543fcc15
+tags:
+ - name: Operation permission
+ description: "Initiate a permission request on an operation."
servers:
-- url: /
+ - url: http://{hostname}/operation-permission/v1
security:
-- bearerAuth: []
-tags:
-- description: Execute all your policies
- name: policy-executor
+ - bearerAuth: []
paths:
- /policy-executor/api/v1/{action}:
+ /permissions:
post:
- description: Fire a Policy action
- operationId: executePolicyAction
+ description: "Initiate permission request"
+ operationId: initiatePermissionRequest
parameters:
- - description: Bearer token may be used to identify client as part of a policy
- explode: false
- in: header
- name: Authorization
- required: false
- schema:
- type: string
- style: simple
- - description: "The policy action. Currently supported options: 'execute'"
- explode: false
- in: path
- name: action
- required: true
- schema:
- example: execute
- type: string
- style: simple
+ - name: Content-Type
+ description: This specifies the media type of the request sent by the client to the server
+ in: header
+ required: true
+ schema:
+ type: string
+ default: application/json
+ - name: Accept
+ description: Indicates the response media type accepted by the client.
+ in: header
+ required: false
+ schema:
+ type: string
+ default: application/json
+ - description: Bearer token may be used to identify client as part of a policy
+ explode: false
+ in: header
+ name: Authorization
+ required: false
+ schema:
+ type: string
+ style: simple
requestBody:
content:
application/json:
schema:
- $ref: '#/components/schemas/PolicyExecutionRequest'
- description: The action request body
+ $ref: '#/components/schemas/PermissionRequest'
+ description: "The permission request body"
required: true
responses:
- "200":
- content:
- application/json:
- schema:
- $ref: '#/components/schemas/PolicyExecutionResponse'
- description: Successful policy execution
- "400":
+ '200':
+ description: "OK"
content:
application/json:
- example:
- status: 400
- message: Bad Request
- details: The provided request is not valid
schema:
- $ref: '#/components/schemas/ErrorMessage'
- description: Bad request
- "401":
- content:
- application/json:
- example:
- status: 401
- message: Unauthorized request
- details: This request is unauthorized
- schema:
- $ref: '#/components/schemas/ErrorMessage'
- description: Unauthorized request
- "403":
- content:
- application/json:
- example:
- status: 403
- message: Request Forbidden
- details: This request is forbidden
- schema:
- $ref: '#/components/schemas/ErrorMessage'
- description: Request 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
+ $ref: '#/components/schemas/PermissionResponse'
+ '400':
+ $ref: '#/components/responses/BadRequest'
+ '401':
+ $ref: '#/components/responses/Unauthorized'
+ '403':
+ $ref: '#/components/responses/Forbidden'
+ '500':
+ $ref: '#/components/responses/InternalServerError'
tags:
- - policy-executor
+ - Operation permission
components:
- parameters:
- actionInPath:
- description: "The policy action. Currently supported options: 'execute'"
- explode: false
- in: path
- name: action
- required: true
- schema:
- example: execute
- type: string
- style: simple
- authorizationInHeader:
- description: Bearer token may be used to identify client as part of a policy
- explode: false
- in: header
- name: Authorization
- required: false
- schema:
- type: string
- style: simple
- responses:
- BadRequest:
- content:
- application/json:
- example:
- status: 400
- message: Bad Request
- details: The provided request is not valid
- schema:
- $ref: '#/components/schemas/ErrorMessage'
- description: Bad request
- Unauthorized:
- content:
- application/json:
- example:
- status: 401
- message: Unauthorized request
- details: This request is unauthorized
- schema:
- $ref: '#/components/schemas/ErrorMessage'
- description: Unauthorized request
- Forbidden:
- content:
- application/json:
- example:
- status: 403
- message: Request Forbidden
- details: This request is forbidden
- schema:
- $ref: '#/components/schemas/ErrorMessage'
- description: Request forbidden
- InternalServerError:
- content:
- application/json:
- example:
- status: 500
- message: Internal Server Error
- details: Internal server error occurred
- schema:
- $ref: '#/components/schemas/ErrorMessage'
- description: Internal server error
- NotImplemented:
- content:
- application/json:
- example:
- status: 501
- message: Not Implemented
- details: Method not implemented
- schema:
- $ref: '#/components/schemas/ErrorMessage'
- description: Method not (yet) implemented
+ securitySchemes:
+ bearerAuth:
+ type: http
+ description: "Bearer token (from a client),used by policies to identify the client"
+ scheme: bearer
schemas:
ErrorMessage:
+ type: object
+ title: Error
properties:
status:
type: string
- message:
+ title:
type: string
details:
type: string
- title: Error
- type: object
- Request:
+ Operation:
example:
- schema: org.onap.cps.ncmp.policy-executor:ncmp-create-schema:1.0.0
- data: "{}"
+ operation: update
+ entityHandleId: ABCD123450d7A822AB27B386829FD9E12
+ resourceIdentifier: ManagedElement=Kista/GNBDUFunction=1/UECC=1
+ targetIdentifier: MEContext=RadioNode-K6_0001,ManagedElement=RadioNode-K6_0001
+ changeRequest:
+ Cell:
+ - id: Cell-id
+ attributes:
+ administrativeState: UNLOCKED
properties:
- schema:
- description: The schema for the data in this request. The schema name should
- include the type of operation
- example: org.onap.cps.ncmp.policy-executor:ncmp-create-schema:1.0.0
+ operation:
+ description: Currently supported operations are 'create', 'update', 'patch', 'delete'. For other possible operation types see the client documentation.
+ example: update
+ type: string
+ entityHandleId:
+ description: A unique identifier for the network element.
+ example: ABCD123450d7A822AB27B386829FD9E12
type: string
- data:
- description: The data related to the request. The format of the object is
- determined by the schema
+ resourceIdentifier:
+ description: Identifies the object in the node model. Currently supported separators are '/' and ','. For other possible format see the client documentation.
+ example: ManagedElement=Kista/GNBDUFunction=1/UECC=1
+ type: string
+ targetIdentifier:
+ description: FDN of the target node. Currently supported separators are '/' and ','. For other possible format see the client documentation.
+ example: MEContext=RadioNode-K6_0001/ManagedElement=RadioNode-K6_0001
+ type: string
+ changeRequest:
+ description: All the information that is required to identify which parameters and attributes of the network is changing.
+ example:
+ Cell:
+ - id: Cell-id
+ attributes:
+ administrativeState: UNLOCKED
type: object
required:
- - data
- - schema
+ - operation
+ - targetIdentifier
type: object
- PolicyExecutionRequest:
+ PermissionRequest:
example:
- decisionType: allow
- requests:
- - schema: org.onap.cps.ncmp.policy-executor:ncmp-create-schema:1.0.0
- data: "{}"
- - schema: org.onap.cps.ncmp.policy-executor:ncmp-create-schema:1.0.0
- data: "{}"
+ permissionId: 550e8400-e29b-41d4-a716-446655440000
+ changeRequestFormat: cm-legacy
+ operations:
+ - operation: update
+ entityHandleId: ABCD123450d7A822AB27B386829FD9E12
+ resourceIdentifier: ManagedElement=Kista/GNBDUFunction=1/UECC=1
+ targetIdentifier: MEContext=RadioNode-K6_0001/ManagedElement=RadioNode-K6_0001
+ changeRequest:
+ Cell:
+ - id: Cell-id
+ attributes:
+ administrativeState: UNLOCKED
+ - operation: delete
+ entityHandleId: DCBA123450d7A822AB27B386829FD9E12
+ resourceIdentifier: ManagedElement=Kista/GNBDUFunction=1/UECC=1
+ targetIdentifier: MEContext=RadioNode-K6_0002/ManagedElement=RadioNode-K6_0002
properties:
- decisionType:
- description: "The type of decision. Currently supported options: 'allow'"
- example: allow
+ permissionId:
+ description: Unique ID for the permission request (for auditing purposes)
+ example: 550e8400-e29b-41d4-a716-446655440000
+ type: string
+ changeRequestFormat:
+ description: Format of the change request. Currently supported 'cm-legacy'. For other possible formats see the client documentation.
+ example: cm-legacy
type: string
- requests:
+ operations:
items:
- $ref: '#/components/schemas/Request'
+ $ref: '#/components/schemas/Operation'
type: array
required:
- - decisionType
- - requests
+ - operations
+ - changeRequestFormat
type: object
- PolicyExecutionResponse:
+ PermissionResponse:
example:
- decision: deny
- decisionId: 550e8400-e29b-41d4-a716-446655440000
- message: Object locked due to recent change
+ id: 550e8400-e29b-41d4-a716-446655440000
+ permissionResult: deny
+ message: Object locked due to recent changes
properties:
- decisionId:
- description: Unique ID for the decision (for auditing purposes)
+ id:
+ description: Unique ID for the permission request (for auditing purposes)
example: 550e8400-e29b-41d4-a716-446655440000
type: string
- decision:
+ permissionResult:
description: "The decision outcome. Currently supported values: 'allow','deny'"
example: deny
type: string
@@ -249,13 +199,50 @@ components:
example: Object locked due to recent change
type: string
required:
- - decision
- - decisionId
- - message
+ - id
+ - permissionResult
+ - message
type: object
- securitySchemes:
- bearerAuth:
- description: "Bearer token (from client that called CPS-NCMP),used by policies\
- \ to identify the client"
- scheme: bearer
- type: http
+
+ responses:
+ BadRequest:
+ description: "Bad Request"
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ example:
+ status: '400'
+ title: "Bad Request"
+ details: "The provided request is not valid"
+ Unauthorized:
+ description: "Unauthorized request"
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ example:
+ status: '401'
+ title: "Unauthorized request"
+ details: "This request is unauthorized"
+ Forbidden:
+ description: "Forbidden"
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ example:
+ status: '403'
+ title: "Request Forbidden"
+ details: "This request is forbidden"
+
+ InternalServerError:
+ description: "Internal Server Error"
+ content:
+ application/problem+json:
+ schema:
+ $ref: '#/components/schemas/ErrorMessage'
+ example:
+ status: '500'
+ title: "Internal Server Error"
+ details: "Internal server error occurred"
diff --git a/docs/ncmp-data-operation.rst b/docs/ncmp-data-operation.rst
index 3352e03cf0..f2f3a476bb 100644
--- a/docs/ncmp-data-operation.rst
+++ b/docs/ncmp-data-operation.rst
@@ -21,6 +21,13 @@ For all data operations on cm handle(s), we have a post endpoint:
- When asynchronous (with topic) operations are executed, a request id (UUID) will be returned.
+**Note.** The client topic is validated to ensure it adheres to Kafka's topic naming conventions. Additionally, if a client specifies a topic that does not exist, the request might be delayed. To enable a fail-fast mechanism, the max.block.ms parameter can be adjusted to define the maximum duration the request is allowed to block. The parameter is 60000ms by default but can be set to a lower value.
+
+.. code:: bash
+
+ spring.kafka.producer.properties.max.block.ms: <value_in_ms>
+
+
Request Body
============
diff --git a/docs/release-notes.rst b/docs/release-notes.rst
index d60c2c0d73..9c825e4d35 100644
--- a/docs/release-notes.rst
+++ b/docs/release-notes.rst
@@ -38,7 +38,6 @@ Release Data
Bug Fixes
---------
-
Features
--------
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 0725fe82d0..16b4460492 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
@@ -22,6 +22,7 @@
package org.onap.cps.integration.base
import com.hazelcast.collection.ISet
+import com.hazelcast.map.IMap
import okhttp3.mockwebserver.MockWebServer
import org.onap.cps.api.CpsAnchorService
import org.onap.cps.api.CpsDataService
@@ -30,7 +31,7 @@ import org.onap.cps.api.CpsModuleService
import org.onap.cps.api.CpsQueryService
import org.onap.cps.integration.DatabaseTestContainer
import org.onap.cps.integration.KafkaTestContainer
-import org.onap.cps.ncmp.api.inventory.NetworkCmProxyInventoryFacade
+import org.onap.cps.ncmp.impl.NetworkCmProxyInventoryFacadeImpl
import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration
import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle
import org.onap.cps.ncmp.impl.data.NetworkCmProxyFacade
@@ -108,7 +109,7 @@ abstract class CpsIntegrationSpecBase extends Specification {
NetworkCmProxyFacade networkCmProxyFacade
@Autowired
- NetworkCmProxyInventoryFacade NetworkCmProxyInventoryFacade
+ NetworkCmProxyInventoryFacadeImpl NetworkCmProxyInventoryFacade
@Autowired
NetworkCmProxyQueryService networkCmProxyQueryService
@@ -123,6 +124,9 @@ abstract class CpsIntegrationSpecBase extends Specification {
BlockingQueue<String> moduleSyncWorkQueue
@Autowired
+ IMap<String, String> cpsAndNcmpLock
+
+ @Autowired
JsonObjectMapper jsonObjectMapper
@Autowired
diff --git a/integration-test/src/test/groovy/org/onap/cps/integration/base/PolicyDispatcher.groovy b/integration-test/src/test/groovy/org/onap/cps/integration/base/PolicyDispatcher.groovy
index b08d1c1548..f1e5449476 100644
--- a/integration-test/src/test/groovy/org/onap/cps/integration/base/PolicyDispatcher.groovy
+++ b/integration-test/src/test/groovy/org/onap/cps/integration/base/PolicyDispatcher.groovy
@@ -46,22 +46,22 @@ class PolicyDispatcher extends Dispatcher {
return new MockResponse().setResponseCode(401)
}
- if (recordedRequest.path != '/policy-executor/api/v1/execute') {
+ if (recordedRequest.path != '/operation-permission/v1/permissions') {
return new MockResponse().setResponseCode(400)
}
def body = objectMapper.readValue(recordedRequest.getBody().readUtf8(), Map.class)
- def targetIdentifier = body.get('requests').get(0).get('data').get('targetIdentifier')
+ def targetIdentifier = body.get('operations').get(0).get('targetIdentifier')
def responseAsMap = [:]
- responseAsMap.put('decisionId',1)
+ responseAsMap.put('id',1)
if (targetIdentifier == "mock slow response") {
TimeUnit.SECONDS.sleep(2) // One second more then configured readTimeoutInSeconds
}
if (allowAll || targetIdentifier == 'fdn1') {
- responseAsMap.put('decision','allow')
+ responseAsMap.put('permissionResult','allow')
responseAsMap.put('message','')
} else {
- responseAsMap.put('decision','deny from mock server (dispatcher)')
+ responseAsMap.put('permissionResult','deny from mock server (dispatcher)')
responseAsMap.put('message','I only like fdn1')
}
def responseAsString = objectMapper.writeValueAsString(responseAsMap)
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 ffcba025e8..e9fac48676 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
@@ -25,7 +25,7 @@ import org.apache.kafka.common.serialization.StringDeserializer
import org.onap.cps.integration.KafkaTestContainer
import org.onap.cps.integration.base.CpsIntegrationSpecBase
import org.onap.cps.ncmp.api.NcmpResponseStatus
-import org.onap.cps.ncmp.api.inventory.NetworkCmProxyInventoryFacade
+import org.onap.cps.ncmp.impl.NetworkCmProxyInventoryFacadeImpl
import org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse
import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration
import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle
@@ -38,7 +38,7 @@ import java.time.Duration
class CmHandleCreateSpec extends CpsIntegrationSpecBase {
- NetworkCmProxyInventoryFacade objectUnderTest
+ NetworkCmProxyInventoryFacadeImpl objectUnderTest
def uniqueId = 'ch-unique-id-for-create-test'
static KafkaConsumer kafkaConsumer
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 67011f811b..f2593ce587 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
@@ -22,14 +22,14 @@ package org.onap.cps.integration.functional.ncmp
import org.onap.cps.integration.base.CpsIntegrationSpecBase
import org.onap.cps.ncmp.api.NcmpResponseStatus
-import org.onap.cps.ncmp.api.inventory.NetworkCmProxyInventoryFacade
+import org.onap.cps.ncmp.impl.NetworkCmProxyInventoryFacadeImpl
import org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse
import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration
import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle
class CmHandleUpdateSpec extends CpsIntegrationSpecBase {
- NetworkCmProxyInventoryFacade objectUnderTest
+ NetworkCmProxyInventoryFacadeImpl objectUnderTest
def setup() {
objectUnderTest = networkCmProxyInventoryFacade
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 a5e3daf289..5ce5658c1b 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
@@ -21,7 +21,7 @@
package org.onap.cps.integration.functional.ncmp
import org.onap.cps.integration.base.CpsIntegrationSpecBase
-import org.onap.cps.ncmp.api.inventory.NetworkCmProxyInventoryFacade
+import org.onap.cps.ncmp.impl.NetworkCmProxyInventoryFacadeImpl
import org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse
import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration
import org.onap.cps.ncmp.api.inventory.models.UpgradedCmHandles
@@ -31,7 +31,7 @@ import spock.util.concurrent.PollingConditions
class CmHandleUpgradeSpec extends CpsIntegrationSpecBase {
- NetworkCmProxyInventoryFacade objectUnderTest
+ NetworkCmProxyInventoryFacadeImpl objectUnderTest
def cmHandleId = 'ch-1'
def cmHandleIdWithExistingModuleSetTag = 'ch-2'
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 43bcbdb4f4..a6e56ab22d 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
@@ -151,6 +151,15 @@ class ModuleSyncWatchdogIntegrationSpec extends CpsIntegrationSpecBase {
}
}
+ def populateQueueWithoutDelayCallable = () -> {
+ try {
+ objectUnderTest.populateWorkQueueIfNeeded()
+ return 'task acquired the lock first'
+ } catch (InterruptedException e) {
+ e.printStackTrace()
+ }
+ }
+
def populateQueueWithDelay = () -> {
try {
Thread.sleep(10)
diff --git a/k6-tests/ncmp/common/utils.js b/k6-tests/ncmp/common/utils.js
index b937b4beb3..8e68edd438 100644
--- a/k6-tests/ncmp/common/utils.js
+++ b/k6-tests/ncmp/common/utils.js
@@ -24,6 +24,7 @@ export const testConfig = JSON.parse(open(`../config/${__ENV.TEST_PROFILE}.json`
export const KAFKA_BOOTSTRAP_SERVERS = testConfig.hosts.kafkaBootstrapServer;
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 REGISTRATION_BATCH_SIZE = 100;
@@ -89,21 +90,21 @@ export function makeCustomSummaryReport(testResults, scenarioConfig) {
makeSummaryCsvLine('0', 'HTTP request failures for all tests', 'rate of failed requests', 'http_req_failed', 0, testResults, scenarioConfig),
makeSummaryCsvLine('1', 'Registration of CM-handles', 'CM-handles/second', 'cmhandles_created_per_second', 50, testResults, scenarioConfig),
makeSummaryCsvLine('2', 'De-registration of CM-handles', 'CM-handles/second', 'cmhandles_deleted_per_second', 100, testResults, scenarioConfig),
- makeSummaryCsvLine('3a', 'CM-handle ID search with No filter', 'milliseconds', 'id_search_nofilter_duration', 500, testResults, scenarioConfig),
- makeSummaryCsvLine('3b', 'CM-handle ID search with Module filter', 'milliseconds', 'id_search_module_duration', 500, testResults, scenarioConfig),
- makeSummaryCsvLine('3c', 'CM-handle ID search with Property filter', 'milliseconds', 'id_search_property_duration', 1200, testResults, scenarioConfig),
- makeSummaryCsvLine('3d', 'CM-handle ID search with Cps Path filter', 'milliseconds', 'id_search_cpspath_duration', 1200, testResults, scenarioConfig),
- makeSummaryCsvLine('3e', 'CM-handle ID search with Trust Level filter', 'milliseconds', 'id_search_trustlevel_duration', 4200, testResults, scenarioConfig),
- makeSummaryCsvLine('4a', 'CM-handle search with No filter', 'milliseconds', 'cm_search_nofilter_duration', 8000, testResults, scenarioConfig),
- makeSummaryCsvLine('4b', 'CM-handle search with Module filter', 'milliseconds', 'cm_search_module_duration', 10000, testResults, scenarioConfig),
- makeSummaryCsvLine('4c', 'CM-handle search with Property filter', 'milliseconds', 'cm_search_property_duration', 10000, testResults, scenarioConfig),
- makeSummaryCsvLine('4d', 'CM-handle search with Cps Path filter', 'milliseconds', 'cm_search_cpspath_duration', 10000, testResults, scenarioConfig),
- makeSummaryCsvLine('4e', 'CM-handle search with Trust Level filter', 'milliseconds', 'cm_search_trustlevel_duration', 13000, testResults, scenarioConfig),
- makeSummaryCsvLine('5a', 'NCMP overhead for Synchronous single CM-handle pass-through read', 'milliseconds', 'ncmp_overhead_passthrough_read', 30, testResults, scenarioConfig),
- makeSummaryCsvLine('5b', 'NCMP overhead for Synchronous single CM-handle pass-through read with alternate id', 'milliseconds', 'ncmp_overhead_passthrough_read_alt_id', 60, testResults, scenarioConfig),
- makeSummaryCsvLine('6a', 'NCMP overhead for Synchronous single CM-handle pass-through write', 'milliseconds', 'ncmp_overhead_passthrough_write', 30, testResults, scenarioConfig),
- makeSummaryCsvLine('6b', 'NCMP overhead for Synchronous single CM-handle pass-through write with alternate id', 'milliseconds', 'ncmp_overhead_passthrough_write_alt_id', 60, testResults, scenarioConfig),
- makeSummaryCsvLine('7', 'Legacy batch read operation', 'events/second', 'legacy_batch_read_cmhandles_per_second', 1500, testResults, scenarioConfig),
+ makeSummaryCsvLine('3a', 'CM-handle ID search with No filter', 'milliseconds', 'id_search_nofilter_duration', 300, testResults, scenarioConfig),
+ makeSummaryCsvLine('3b', 'CM-handle ID search with Module filter', 'milliseconds', 'id_search_module_duration', 300, testResults, scenarioConfig),
+ makeSummaryCsvLine('3c', 'CM-handle ID search with Property filter', 'milliseconds', 'id_search_property_duration', 750, testResults, scenarioConfig),
+ makeSummaryCsvLine('3d', 'CM-handle ID search with Cps Path filter', 'milliseconds', 'id_search_cpspath_duration', 750, testResults, scenarioConfig),
+ makeSummaryCsvLine('3e', 'CM-handle ID search with Trust Level filter', 'milliseconds', 'id_search_trustlevel_duration', 3000, testResults, scenarioConfig),
+ makeSummaryCsvLine('4a', 'CM-handle search with No filter', 'milliseconds', 'cm_search_nofilter_duration', 3000, testResults, scenarioConfig),
+ makeSummaryCsvLine('4b', 'CM-handle search with Module filter', 'milliseconds', 'cm_search_module_duration', 4000, testResults, scenarioConfig),
+ makeSummaryCsvLine('4c', 'CM-handle search with Property filter', 'milliseconds', 'cm_search_property_duration', 4500, testResults, scenarioConfig),
+ makeSummaryCsvLine('4d', 'CM-handle search with Cps Path filter', 'milliseconds', 'cm_search_cpspath_duration', 4500, testResults, scenarioConfig),
+ makeSummaryCsvLine('4e', 'CM-handle search with Trust Level filter', 'milliseconds', 'cm_search_trustlevel_duration', 7000, testResults, scenarioConfig),
+ makeSummaryCsvLine('5a', 'NCMP overhead for Synchronous single CM-handle pass-through read', 'milliseconds', 'ncmp_overhead_passthrough_read', 20, testResults, scenarioConfig),
+ makeSummaryCsvLine('5b', 'NCMP overhead for Synchronous single CM-handle pass-through read with alternate id', 'milliseconds', 'ncmp_overhead_passthrough_read_alt_id', 40, testResults, scenarioConfig),
+ makeSummaryCsvLine('6a', 'NCMP overhead for Synchronous single CM-handle pass-through write', 'milliseconds', 'ncmp_overhead_passthrough_write', 20, testResults, scenarioConfig),
+ makeSummaryCsvLine('6b', 'NCMP overhead for Synchronous single CM-handle pass-through write with alternate id', 'milliseconds', 'ncmp_overhead_passthrough_write_alt_id', 40, testResults, scenarioConfig),
+ makeSummaryCsvLine('7', 'Legacy batch read operation', 'events/second', 'legacy_batch_read_cmhandles_per_second', 300, testResults, scenarioConfig),
];
return summaryCsvLines.join('\n') + '\n';
}
diff --git a/k6-tests/ncmp/config/endurance.json b/k6-tests/ncmp/config/endurance.json
index d215d0a1e1..d4893a45cc 100644
--- a/k6-tests/ncmp/config/endurance.json
+++ b/k6-tests/ncmp/config/endurance.json
@@ -2,7 +2,8 @@
"hosts": {
"ncmpBaseUrl": "http://localhost:8884",
"dmiStubUrl": "http://ncmp-dmi-plugin-demo-and-csit-stub:8092",
- "kafkaBootstrapServer": "localhost:9093"
+ "kafkaBootstrapServer": "localhost:9093",
+ "containerUpTimeInSeconds": 420
},
"scenarios": {
"passthrough_read_scenario": {
diff --git a/k6-tests/ncmp/config/kpi.json b/k6-tests/ncmp/config/kpi.json
index 742321f709..eed041de85 100644
--- a/k6-tests/ncmp/config/kpi.json
+++ b/k6-tests/ncmp/config/kpi.json
@@ -2,93 +2,140 @@
"hosts": {
"ncmpBaseUrl": "http://localhost:8883",
"dmiStubUrl": "http://ncmp-dmi-plugin-demo-and-csit-stub:8092",
- "kafkaBootstrapServer": "localhost:9092"
+ "kafkaBootstrapServer": "localhost:9092",
+ "containerUpTimeInSeconds": 300
},
"scenarios": {
"passthrough_read_scenario": {
- "executor": "constant-vus",
+ "executor": "constant-arrival-rate",
"exec": "passthroughReadScenario",
- "vus": 2,
- "duration": "15m"
+ "rate": 5,
+ "timeUnit": "1s",
+ "duration": "15m",
+ "preAllocatedVUs": 5,
+ "startTime": "0ms"
},
"passthrough_read_alt_id_scenario": {
- "executor": "constant-vus",
+ "executor": "constant-arrival-rate",
"exec": "passthroughReadAltIdScenario",
- "vus": 2,
- "duration": "15m"
+ "rate": 5,
+ "timeUnit": "1s",
+ "duration": "15m",
+ "preAllocatedVUs": 5,
+ "startTime": "200ms"
},
+
"passthrough_write_scenario": {
- "executor": "constant-vus",
+ "executor": "constant-arrival-rate",
"exec": "passthroughWriteScenario",
- "vus": 2,
- "duration": "15m"
+ "rate": 5,
+ "timeUnit": "1s",
+ "duration": "15m",
+ "preAllocatedVUs": 5,
+ "startTime": "400ms"
},
"passthrough_write_alt_id_scenario": {
- "executor": "constant-vus",
+ "executor": "constant-arrival-rate",
"exec": "passthroughWriteAltIdScenario",
- "vus": 2,
- "duration": "15m"
+ "rate": 5,
+ "timeUnit": "1s",
+ "duration": "15m",
+ "preAllocatedVUs": 5,
+ "startTime": "600ms"
},
+
"cm_handle_id_search_nofilter_scenario": {
- "executor": "constant-vus",
+ "executor": "constant-arrival-rate",
"exec": "cmHandleIdSearchNoFilterScenario",
- "vus": 1,
- "duration": "15m"
- },
- "cm_handle_search_nofilter_scenario": {
- "executor": "constant-vus",
- "exec": "cmHandleSearchNoFilterScenario",
- "vus": 1,
- "duration": "15m"
+ "rate": 1,
+ "timeUnit": "2s",
+ "duration": "15m",
+ "preAllocatedVUs": 1,
+ "startTime": "0ms"
},
"cm_handle_id_search_module_scenario": {
- "executor": "constant-vus",
+ "executor": "constant-arrival-rate",
"exec": "cmHandleIdSearchModuleScenario",
- "vus": 1,
- "duration": "15m"
- },
- "cm_handle_search_module_scenario": {
- "executor": "constant-vus",
- "exec": "cmHandleSearchModuleScenario",
- "vus": 1,
- "duration": "15m"
+ "rate": 1,
+ "timeUnit": "2s",
+ "duration": "15m",
+ "preAllocatedVUs": 1,
+ "startTime": "400ms"
},
"cm_handle_id_search_property_scenario": {
- "executor": "constant-vus",
+ "executor": "constant-arrival-rate",
"exec": "cmHandleIdSearchPropertyScenario",
- "vus": 1,
- "duration": "15m"
- },
- "cm_handle_search_property_scenario": {
- "executor": "constant-vus",
- "exec": "cmHandleSearchPropertyScenario",
- "vus": 1,
- "duration": "15m"
+ "rate": 1,
+ "timeUnit": "2s",
+ "duration": "15m",
+ "preAllocatedVUs": 1,
+ "startTime": "800ms"
},
"cm_handle_id_search_cpspath_scenario": {
- "executor": "constant-vus",
+ "executor": "constant-arrival-rate",
"exec": "cmHandleIdSearchCpsPathScenario",
- "vus": 1,
- "duration": "15m"
- },
- "cm_handle_search_cpspath_scenario": {
- "executor": "constant-vus",
- "exec": "cmHandleSearchCpsPathScenario",
- "vus": 1,
- "duration": "15m"
+ "rate": 1,
+ "timeUnit": "2s",
+ "duration": "15m",
+ "preAllocatedVUs": 1,
+ "startTime": "1200ms"
},
"cm_handle_id_search_trustlevel_scenario": {
- "executor": "constant-vus",
+ "executor": "constant-arrival-rate",
"exec": "cmHandleIdSearchTrustLevelScenario",
- "vus": 1,
- "duration": "15m"
+ "rate": 1,
+ "timeUnit": "2s",
+ "duration": "15m",
+ "preAllocatedVUs": 1,
+ "startTime": "1600ms"
+ },
+
+ "cm_handle_search_nofilter_scenario": {
+ "executor": "constant-arrival-rate",
+ "exec": "cmHandleSearchNoFilterScenario",
+ "rate": 1,
+ "timeUnit": "15s",
+ "duration": "15m",
+ "preAllocatedVUs": 1,
+ "startTime": "0s"
+ },
+ "cm_handle_search_module_scenario": {
+ "executor": "constant-arrival-rate",
+ "exec": "cmHandleSearchModuleScenario",
+ "rate": 1,
+ "timeUnit": "15s",
+ "duration": "15m",
+ "preAllocatedVUs": 1,
+ "startTime": "3s"
+ },
+ "cm_handle_search_property_scenario": {
+ "executor": "constant-arrival-rate",
+ "exec": "cmHandleSearchPropertyScenario",
+ "rate": 1,
+ "timeUnit": "15s",
+ "duration": "15m",
+ "preAllocatedVUs": 1,
+ "startTime": "6s"
+ },
+ "cm_handle_search_cpspath_scenario": {
+ "executor": "constant-arrival-rate",
+ "exec": "cmHandleSearchCpsPathScenario",
+ "rate": 1,
+ "timeUnit": "15s",
+ "duration": "15m",
+ "preAllocatedVUs": 1,
+ "startTime": "9s"
},
"cm_handle_search_trustlevel_scenario": {
- "executor": "constant-vus",
+ "executor": "constant-arrival-rate",
"exec": "cmHandleSearchTrustLevelScenario",
- "vus": 1,
- "duration": "15m"
+ "rate": 1,
+ "timeUnit": "15s",
+ "duration": "15m",
+ "preAllocatedVUs": 1,
+ "startTime": "12s"
},
+
"legacy_batch_produce_scenario": {
"executor": "shared-iterations",
"exec": "legacyBatchProduceScenario",
@@ -122,4 +169,4 @@
"cm_search_trustlevel_duration": ["avg <= 15000"],
"legacy_batch_read_cmhandles_per_second": ["avg >= 150"]
}
-} \ No newline at end of file
+}
diff --git a/k6-tests/ncmp/ncmp-test-runner.js b/k6-tests/ncmp/ncmp-test-runner.js
index e33ff1852a..9ab326c44c 100644
--- a/k6-tests/ncmp/ncmp-test-runner.js
+++ b/k6-tests/ncmp/ncmp-test-runner.js
@@ -18,14 +18,14 @@
* ============LICENSE_END=========================================================
*/
-import { check } from 'k6';
+import { check, sleep } from 'k6';
import { Trend } from 'k6/metrics';
import { Reader } from 'k6/x/kafka';
import {
TOTAL_CM_HANDLES, READ_DATA_FOR_CM_HANDLE_DELAY_MS, WRITE_DATA_FOR_CM_HANDLE_DELAY_MS,
makeCustomSummaryReport, makeBatchOfCmHandleIds, LEGACY_BATCH_THROUGHPUT_TEST_BATCH_SIZE,
REGISTRATION_BATCH_SIZE, LEGACY_BATCH_THROUGHPUT_TEST_NUMBER_OF_REQUESTS, KAFKA_BOOTSTRAP_SERVERS,
- LEGACY_BATCH_TOPIC_NAME, testConfig
+ LEGACY_BATCH_TOPIC_NAME, CONTAINER_UP_TIME_IN_SECONDS, testConfig
} from './common/utils.js';
import { createCmHandles, deleteCmHandles, waitForAllCmHandlesToBeReady } from './common/cmhandle-crud.js';
import { executeCmHandleSearch, executeCmHandleIdSearch } from './common/search-base.js';
@@ -97,6 +97,8 @@ export function teardown() {
const totalDeregistrationTimeInSeconds = (endTimeInMillis - startTimeInMillis) / 1000.0;
cmHandlesDeletedPerSecondTrend.add(DEREGISTERED_CM_HANDLES / totalDeregistrationTimeInSeconds);
+
+ sleep(CONTAINER_UP_TIME_IN_SECONDS);
}
export function passthroughReadScenario() {
diff --git a/policy-executor-stub/src/main/java/org/onap/cps/policyexecutor/stub/controller/PolicyExecutorStubController.java b/policy-executor-stub/src/main/java/org/onap/cps/policyexecutor/stub/controller/PolicyExecutorStubController.java
index 88073c0a0f..aef27a6389 100644
--- a/policy-executor-stub/src/main/java/org/onap/cps/policyexecutor/stub/controller/PolicyExecutorStubController.java
+++ b/policy-executor-stub/src/main/java/org/onap/cps/policyexecutor/stub/controller/PolicyExecutorStubController.java
@@ -20,72 +20,66 @@
package org.onap.cps.policyexecutor.stub.controller;
-import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.Locale;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
-import org.onap.cps.policyexecutor.stub.api.PolicyExecutorApi;
-import org.onap.cps.policyexecutor.stub.model.NcmpDelete;
-import org.onap.cps.policyexecutor.stub.model.PolicyExecutionRequest;
-import org.onap.cps.policyexecutor.stub.model.PolicyExecutionResponse;
-import org.onap.cps.policyexecutor.stub.model.Request;
+import org.onap.cps.policyexecutor.stub.api.OperationPermissionApi;
+import org.onap.cps.policyexecutor.stub.model.Operation;
+import org.onap.cps.policyexecutor.stub.model.PermissionRequest;
+import org.onap.cps.policyexecutor.stub.model.PermissionResponse;
import org.springframework.http.HttpStatus;
import org.springframework.http.HttpStatusCode;
import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
+@RequestMapping("/operation-permission/v1")
@RequiredArgsConstructor
@Slf4j
-public class PolicyExecutorStubController implements PolicyExecutorApi {
+public class PolicyExecutorStubController implements OperationPermissionApi {
private final Sleeper sleeper;
- private final ObjectMapper objectMapper;
private static final Pattern ERROR_CODE_PATTERN = Pattern.compile("(\\d{3})");
private int decisionCounter = 0;
private static int slowResponseTimeInSeconds = 40;
@Override
- public ResponseEntity<PolicyExecutionResponse> executePolicyAction(
- final String action,
- final PolicyExecutionRequest policyExecutionRequest,
- final String authorization) {
- log.info("Stub Policy Executor Invoked (only supports 'delete' operations)");
- if (policyExecutionRequest.getRequests().isEmpty()) {
+ public ResponseEntity<PermissionResponse> initiatePermissionRequest(final String contentType,
+ final PermissionRequest permissionRequest,
+ final String accept,
+ final String authorization) {
+ log.info("Stub Policy Executor Invoked");
+ if (permissionRequest.getOperations().isEmpty()) {
return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
- final Request firstRequest = policyExecutionRequest.getRequests().iterator().next();
- log.info("1st Request Schema:{}", firstRequest.getSchema());
- if (firstRequest.getSchema().contains("ncmp-delete-schema:1.0.0")) {
- return handleNcmpDeleteSchema(firstRequest);
+ final Operation firstOperation = permissionRequest.getOperations().iterator().next();
+ log.info("1st Operation: {}", firstOperation.getOperation());
+ if (!"delete".equals(firstOperation.getOperation()) && firstOperation.getChangeRequest() == null) {
+ log.warn("Change Request is required for " + firstOperation.getOperation() + " operations");
+ return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
}
- log.warn("This stub only supports 'delete' operations");
- return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
+ return handleOperation(firstOperation);
}
- private ResponseEntity<PolicyExecutionResponse> handleNcmpDeleteSchema(final Request request) {
- final NcmpDelete ncmpDelete = objectMapper.convertValue(request.getData(), NcmpDelete.class);
-
- final String targetIdentifier = ncmpDelete.getTargetIdentifier();
-
- if (targetIdentifier == null) {
- return new ResponseEntity<>(HttpStatus.BAD_REQUEST);
- }
+ private ResponseEntity<PermissionResponse> handleOperation(final Operation operation) {
+ final String targetIdentifier = operation.getTargetIdentifier();
final Matcher matcher = ERROR_CODE_PATTERN.matcher(targetIdentifier);
if (matcher.find()) {
final int errorCode = Integer.parseInt(matcher.group(1));
+ log.warn("Stub is mocking an error response, code: " + errorCode);
return new ResponseEntity<>(HttpStatusCode.valueOf(errorCode));
}
return createPolicyExecutionResponse(targetIdentifier);
}
- private ResponseEntity<PolicyExecutionResponse> createPolicyExecutionResponse(final String targetIdentifier) {
- final String decisionId = String.valueOf(++decisionCounter);
- final String decision;
+ private ResponseEntity<PermissionResponse> createPolicyExecutionResponse(final String targetIdentifier) {
+ final String id = String.valueOf(++decisionCounter);
+ final String permissionResult;
final String message;
if (targetIdentifier.toLowerCase(Locale.getDefault()).contains("slow")) {
try {
@@ -96,17 +90,14 @@ public class PolicyExecutorStubController implements PolicyExecutorApi {
}
}
if (targetIdentifier.toLowerCase(Locale.getDefault()).contains("cps-is-great")) {
- decision = "allow";
+ permissionResult = "allow";
message = "All good";
} else {
- decision = "deny";
+ permissionResult = "deny";
message = "Only FDNs containing 'cps-is-great' are allowed";
}
- log.info("Decision: {} ({})", decision, message);
- final PolicyExecutionResponse policyExecutionResponse =
- new PolicyExecutionResponse(decisionId, decision, message);
-
- return ResponseEntity.ok(policyExecutionResponse);
+ log.info("Decision: {} ({})", permissionResult, message);
+ return ResponseEntity.ok(new PermissionResponse(id, permissionResult, message));
}
}
diff --git a/policy-executor-stub/src/test/groovy/org/onap/cps/policyexecutor/stub/controller/PolicyExecutorStubControllerSpec.groovy b/policy-executor-stub/src/test/groovy/org/onap/cps/policyexecutor/stub/controller/PolicyExecutorStubControllerSpec.groovy
index 44460daa7e..75bd676b2f 100644
--- a/policy-executor-stub/src/test/groovy/org/onap/cps/policyexecutor/stub/controller/PolicyExecutorStubControllerSpec.groovy
+++ b/policy-executor-stub/src/test/groovy/org/onap/cps/policyexecutor/stub/controller/PolicyExecutorStubControllerSpec.groovy
@@ -21,10 +21,9 @@
package org.onap.cps.policyexecutor.stub.controller
import com.fasterxml.jackson.databind.ObjectMapper
-import org.onap.cps.policyexecutor.stub.model.NcmpDelete
-import org.onap.cps.policyexecutor.stub.model.PolicyExecutionRequest
-import org.onap.cps.policyexecutor.stub.model.PolicyExecutionResponse
-import org.onap.cps.policyexecutor.stub.model.Request
+import org.onap.cps.policyexecutor.stub.model.Operation
+import org.onap.cps.policyexecutor.stub.model.PermissionRequest
+import org.onap.cps.policyexecutor.stub.model.PermissionResponse
import org.spockframework.spring.SpringBean
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
@@ -47,14 +46,14 @@ class PolicyExecutorStubControllerSpec extends Specification {
@SpringBean
Sleeper sleeper = Spy()
- def url = '/policy-executor/api/v1/some-action'
+ def url = '/operation-permission/v1/permissions'
def setup() {
PolicyExecutorStubController.slowResponseTimeInSeconds = 1
}
- def 'Execute policy action.'() {
- given: 'a policy execution request with target: #targetIdentifier'
+ def 'Permission request with #targetIdentifier.'() {
+ given: 'a permission request with target: #targetIdentifier'
def requestBody = createRequestBody(targetIdentifier)
when: 'request is posted'
def response = mockMvc.perform(post(url)
@@ -66,19 +65,19 @@ class PolicyExecutorStubControllerSpec extends Specification {
assert response.status == HttpStatus.OK.value()
and: 'the response body has the expected decision details'
def responseBody = response.contentAsString
- def policyExecutionResponse = objectMapper.readValue(responseBody, PolicyExecutionResponse.class)
- assert policyExecutionResponse.decisionId == expectedDecsisonId
- assert policyExecutionResponse.decision == expectedDecision
- assert policyExecutionResponse.message == expectedMessage
+ def permissionResponse = objectMapper.readValue(responseBody, PermissionResponse.class)
+ assert permissionResponse.id == expectedId
+ assert permissionResponse.permissionResult == expectedResult
+ assert permissionResponse.message == expectedMessage
where: 'the following targets are used'
- targetIdentifier || expectedDecsisonId | expectedDecision | expectedMessage
- 'some fdn' || '1' | 'deny' | "Only FDNs containing 'cps-is-great' are allowed"
- 'fdn with cps-is-great' || '2' | 'allow' | 'All good'
- 'slow' || '3' | 'deny' | "Only FDNs containing 'cps-is-great' are allowed"
+ targetIdentifier || expectedId | expectedResult | expectedMessage
+ 'some fdn' || '1' | 'deny' | "Only FDNs containing 'cps-is-great' are allowed"
+ 'fdn with cps-is-great' || '2' | 'allow' | 'All good'
+ 'slow' || '3' | 'deny' | "Only FDNs containing 'cps-is-great' are allowed"
}
- def 'Execute policy action with a HTTP error code.'() {
- given: 'a policy execution request with a target fdn with a 3-digit error code'
+ def 'Permission request with a HTTP error code.'() {
+ given: 'a permission request with a target fdn with a 3-digit error code'
def requestBody = createRequestBody('target with error code 418')
when: 'request is posted'
def response = mockMvc.perform(post(url)
@@ -90,8 +89,8 @@ class PolicyExecutorStubControllerSpec extends Specification {
assert response.status == 418
}
- def 'Execute policy action without authorization header.'() {
- given: 'a valid policy execution request'
+ def 'Permission request without authorization header.'() {
+ given: 'a valid permission request'
def requestBody = createRequestBody('some target')
when: 'request is posted without authorization header'
def response = mockMvc.perform(post(url)
@@ -102,10 +101,10 @@ class PolicyExecutorStubControllerSpec extends Specification {
assert response.status == HttpStatus.OK.value()
}
- def 'Execute policy action with no requests.'() {
- given: 'a policy execution request'
- def policyExecutionRequest = new PolicyExecutionRequest('some decision type', [])
- def requestBody = objectMapper.writeValueAsString(policyExecutionRequest)
+ def 'Permission request with no operations.'() {
+ given: 'a permission request with no operations'
+ def permissionRequest = new PermissionRequest('some decision type', [])
+ def requestBody = objectMapper.writeValueAsString(permissionRequest)
when: 'request is posted'
def response = mockMvc.perform(post(url)
.header('Authorization','some string')
@@ -116,8 +115,8 @@ class PolicyExecutorStubControllerSpec extends Specification {
assert response.status == HttpStatus.BAD_REQUEST.value()
}
- def 'Execute policy action with invalid json for request data.'() {
- when: 'request is posted'
+ def 'Request with invalid json for request data.'() {
+ when: 'request with invalid json is posted'
def response = mockMvc.perform(post(url)
.header('Authorization','some string')
.contentType(MediaType.APPLICATION_JSON)
@@ -127,8 +126,8 @@ class PolicyExecutorStubControllerSpec extends Specification {
assert response.status == HttpStatus.BAD_REQUEST.value()
}
- def 'Execute policy action with interrupted exception during slow response.'() {
- given: 'a policy execution request with target: "slow"'
+ def 'Permission request with interrupted exception during slow response.'() {
+ given: 'a permission request with target: "slow" (stub will be slow)'
def requestBody = createRequestBody('slow')
sleeper.haveALittleRest(_) >> { throw new InterruptedException() }
when: 'request is posted'
@@ -140,9 +139,9 @@ class PolicyExecutorStubControllerSpec extends Specification {
noExceptionThrown()
}
- def 'Execute policy action with missing or invalid attributes.'() {
- given: 'a policy execution request with decisionType=#decisionType, schema=#schema, targetIdentifier=#targetIdentifier'
- def requestBody = createRequestBody(decisionType, schema, targetIdentifier)
+ def 'Permission request with missing or invalid attributes.'() {
+ given: 'Permission request with operation=#operation and targetIdentifier=#targetIdentifier'
+ def requestBody = createRequestBody(operation, targetIdentifier, changeRequest)
when: 'request is posted'
def response = mockMvc.perform(post(url)
.header('Authorization','something')
@@ -152,22 +151,22 @@ class PolicyExecutorStubControllerSpec extends Specification {
then: 'response status as expected'
assert response.status == expectedStatus.value()
where: 'following parameters are used'
- decisionType | schema | targetIdentifier || expectedStatus
- 'something' | 'ncmp-delete-schema:1.0.0' | 'something' || HttpStatus.OK
- null | 'ncmp-delete-schema:1.0.0' | 'something' || HttpStatus.BAD_REQUEST
- 'something' | 'other schema' | 'something' || HttpStatus.BAD_REQUEST
- 'something' | 'ncmp-delete-schema:1.0.0' | null || HttpStatus.BAD_REQUEST
+ operation | targetIdentifier | changeRequest || expectedStatus
+ 'delete' | 'something' | null || HttpStatus.OK
+ 'other' | 'something' | '{}' || HttpStatus.OK
+ 'delete' | null | null || HttpStatus.BAD_REQUEST
+ 'other' | 'something' | null || HttpStatus.BAD_REQUEST
}
- def createRequestBody(decisionType, schema, targetIdentifier) {
- def ncmpDelete = new NcmpDelete(targetIdentifier: targetIdentifier)
- def request = new Request(schema, ncmpDelete)
- def policyExecutionRequest = new PolicyExecutionRequest(decisionType, [request])
- return objectMapper.writeValueAsString(policyExecutionRequest)
+ def createRequestBody(targetIdentifier) {
+ return createRequestBody('delete', targetIdentifier, '{}')
}
- def createRequestBody(targetIdentifier) {
- return createRequestBody('some decision type', 'ncmp-delete-schema:1.0.0', targetIdentifier)
+ def createRequestBody(operationName, targetIdentifier, changeRequest) {
+ def operation = new Operation(operationName, targetIdentifier)
+ operation.setChangeRequest(changeRequest)
+ def permissionRequest = new PermissionRequest('cm-legacy', [operation])
+ return objectMapper.writeValueAsString(permissionRequest)
}
}