summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cps-application/src/main/resources/application.yml4
-rwxr-xr-xcps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java38
-rw-r--r--cps-ncmp-rest/src/test/resources/application.yml3
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/NcmpAsyncRequestResponseEventConsumer.java2
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsService.java18
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CompositeStateBuilder.java5
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdog.java15
-rw-r--r--cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/SyncUtils.java25
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsServiceSpec.groovy21
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncSpec.groovy17
-rw-r--r--cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy22
-rw-r--r--cps-service/src/main/java/org/onap/cps/config/AsyncConfig.java3
-rw-r--r--cps-service/src/main/java/org/onap/cps/notification/NotificationProperties.java6
-rw-r--r--cps-service/src/test/resources/application.yml3
-rw-r--r--[-rwxr-xr-x]csit/plans/cps/pnfsim/docker-compose.yml0
-rwxr-xr-xcsit/plans/cps/setup.sh6
-rw-r--r--[-rwxr-xr-x]docker-compose/docker-compose.yml71
-rw-r--r--docs/deployment.rst7
18 files changed, 140 insertions, 126 deletions
diff --git a/cps-application/src/main/resources/application.yml b/cps-application/src/main/resources/application.yml
index 802a18b84..14abebb2b 100644
--- a/cps-application/src/main/resources/application.yml
+++ b/cps-application/src/main/resources/application.yml
@@ -88,14 +88,14 @@ app:
topic: ${NCMP_ASYNC_M2M_TOPIC:ncmp-async-m2m}
events:
topic: ${NCMP_EVENTS_TOPIC:ncmp-events}
+
notification:
+ enabled: true
data-updated:
- enabled: false
topic: ${CPS_CHANGE_EVENT_TOPIC:cps.data-updated-events}
filters:
enabled-dataspaces: ${NOTIFICATION_DATASPACE_FILTER_PATTERNS:""}
async:
- enabled: false
executor:
core-pool-size: 2
max-pool-size: 10
diff --git a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java
index 7abefe679..e0488c227 100755
--- a/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java
+++ b/cps-ncmp-rest/src/main/java/org/onap/cps/ncmp/rest/controller/NetworkCmProxyController.java
@@ -28,7 +28,6 @@ import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum
import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.PATCH;
import static org.onap.cps.ncmp.api.impl.operations.DmiRequestBody.OperationEnum.UPDATE;
-import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
@@ -77,9 +76,10 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
private final NcmpRestInputMapper ncmpRestInputMapper;
private final CmHandleStateMapper cmHandleStateMapper;
private final CpsNcmpTaskExecutor cpsNcmpTaskExecutor;
-
@Value("${notification.async.executor.time-out-value-in-ms:2000}")
private int timeOutInMilliSeconds;
+ @Value("${notification.enabled:true}")
+ private boolean asyncEnabled;
/**
* Get resource data from operational datastore.
@@ -95,15 +95,18 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
final @NotNull @Valid String resourceIdentifier,
final @Valid String optionsParamInQuery,
final @Valid String topicParamInQuery) {
- if (isValidTopic(topicParamInQuery)) {
+ if (asyncEnabled && isValidTopic(topicParamInQuery)) {
final String requestId = UUID.randomUUID().toString();
+ log.info("Received Async passthrough-operational request with id {}", requestId);
cpsNcmpTaskExecutor.executeTask(() ->
- networkCmProxyDataService.getResourceDataOperationalForCmHandle(
- cmHandle, resourceIdentifier, optionsParamInQuery, topicParamInQuery,
- requestId
- ), timeOutInMilliSeconds
+ networkCmProxyDataService.getResourceDataOperationalForCmHandle(
+ cmHandle, resourceIdentifier, optionsParamInQuery, topicParamInQuery, requestId
+ ), timeOutInMilliSeconds
);
- return acknowledgeAsyncRequest(requestId);
+ return ResponseEntity.ok(Map.of("requestId", requestId));
+ } else {
+ log.warn("Asynchronous messaging is currently disabled for passthrough-operational."
+ + " Will use synchronous operation.");
}
final Object responseObject = networkCmProxyDataService.getResourceDataOperationalForCmHandle(
@@ -126,15 +129,18 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
final @NotNull @Valid String resourceIdentifier,
final @Valid String optionsParamInQuery,
final @Valid String topicParamInQuery) {
- if (isValidTopic(topicParamInQuery)) {
- final String resourceDataRequestId = UUID.randomUUID().toString();
+ if (asyncEnabled && isValidTopic(topicParamInQuery)) {
+ final String requestId = UUID.randomUUID().toString();
+ log.info("Received Async passthrough-running request with id {}", requestId);
cpsNcmpTaskExecutor.executeTask(() ->
networkCmProxyDataService.getResourceDataPassThroughRunningForCmHandle(
- cmHandle, resourceIdentifier, optionsParamInQuery, topicParamInQuery,
- resourceDataRequestId
+ cmHandle, resourceIdentifier, optionsParamInQuery, topicParamInQuery, requestId
), timeOutInMilliSeconds
);
- return acknowledgeAsyncRequest(resourceDataRequestId);
+ return ResponseEntity.ok(Map.of("requestId", requestId));
+ } else {
+ log.warn("Asynchronous messaging is currently disabled for passthrough-running."
+ + " Will use synchronous operation.");
}
final Object responseObject = networkCmProxyDataService.getResourceDataPassThroughRunningForCmHandle(
@@ -318,11 +324,5 @@ public class NetworkCmProxyController implements NetworkCmProxyApi {
throw new InvalidTopicException("Topic name " + topicName + " is invalid", "invalid topic");
}
- private ResponseEntity<Object> acknowledgeAsyncRequest(final String requestId) {
- final Map<String, Object> acknowledgeData = new HashMap<>(1);
- acknowledgeData.put("requestId", requestId);
- return ResponseEntity.ok(acknowledgeData);
- }
-
}
diff --git a/cps-ncmp-rest/src/test/resources/application.yml b/cps-ncmp-rest/src/test/resources/application.yml
index 0241696c5..9df1e580f 100644
--- a/cps-ncmp-rest/src/test/resources/application.yml
+++ b/cps-ncmp-rest/src/test/resources/application.yml
@@ -1,5 +1,5 @@
# ============LICENSE_START=======================================================
-# Copyright (C) 2021 Nordix Foundation
+# Copyright (C) 2021-2022 Nordix Foundation
# Modifications Copyright (C) 2021 Bell Canada.
# ================================================================================
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -23,6 +23,7 @@ rest:
ncmp-inventory-base-path: /ncmpInventory
notification:
+ enabled: true
async:
executor:
time-out-value-in-ms: 2000 \ No newline at end of file
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/NcmpAsyncRequestResponseEventConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/NcmpAsyncRequestResponseEventConsumer.java
index 4e5c57ba5..a9e7164fd 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/NcmpAsyncRequestResponseEventConsumer.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/async/NcmpAsyncRequestResponseEventConsumer.java
@@ -24,6 +24,7 @@ import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.onap.cps.ncmp.event.model.DmiAsyncRequestResponseEvent;
import org.onap.cps.ncmp.event.model.NcmpAsyncRequestResponseEvent;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.kafka.annotation.KafkaListener;
import org.springframework.stereotype.Component;
@@ -33,6 +34,7 @@ import org.springframework.stereotype.Component;
@Component
@Slf4j
@RequiredArgsConstructor
+@ConditionalOnProperty(name = "notification.enabled", havingValue = "true", matchIfMissing = true)
public class NcmpAsyncRequestResponseEventConsumer {
private final NcmpAsyncRequestResponseEventProducer ncmpAsyncRequestResponseEventProducer;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsService.java
index 6804ac0f0..7b5ceb57a 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsService.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/event/NcmpEventsService.java
@@ -47,17 +47,23 @@ public class NcmpEventsService {
@Value("${app.ncmp.events.topic:ncmp-events}")
private String topicName;
+ @Value("${notification.enabled:true}")
+ private boolean notificationsEnabled;
+
/**
* Publish the NcmpEvent to the public topic.
*
* @param cmHandleId Cm Handle Id
*/
public void publishNcmpEvent(final String cmHandleId) {
-
- final NcmpServiceCmHandle ncmpServiceCmHandle = YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle(
- inventoryPersistence.getYangModelCmHandle(cmHandleId));
- final NcmpEvent ncmpEvent = ncmpEventsCreator.populateNcmpEvent(cmHandleId, ncmpServiceCmHandle);
- ncmpEventsPublisher.publishEvent(topicName, cmHandleId, ncmpEvent);
-
+ if (notificationsEnabled) {
+ final NcmpServiceCmHandle ncmpServiceCmHandle =
+ YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle(
+ inventoryPersistence.getYangModelCmHandle(cmHandleId));
+ final NcmpEvent ncmpEvent = ncmpEventsCreator.populateNcmpEvent(cmHandleId, ncmpServiceCmHandle);
+ ncmpEventsPublisher.publishEvent(topicName, cmHandleId, ncmpEvent);
+ } else {
+ log.debug("Notifications disabled.");
+ }
}
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CompositeStateBuilder.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CompositeStateBuilder.java
index 012ba5ede..91e92ea6f 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CompositeStateBuilder.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CompositeStateBuilder.java
@@ -111,8 +111,9 @@ public class CompositeStateBuilder {
* @return CompositeState
*/
public CompositeStateBuilder fromDataNode(final DataNode dataNode) {
- this.cmHandleState = CmHandleState.valueOf((String) dataNode.getLeaves()
- .get("cm-handle-state"));
+ this.cmHandleState = CmHandleState.valueOf((String) dataNode.getLeaves()
+ .get("cm-handle-state"));
+ this.lastUpdatedTime = (String) dataNode.getLeaves().get("last-update-time");
for (final DataNode stateChildNode : dataNode.getChildDataNodes()) {
if (stateChildNode.getXpath().endsWith("/lock-reason")) {
this.lockReason = getLockReason(stateChildNode);
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdog.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdog.java
index e590ca1cd..402f9f6b4 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdog.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdog.java
@@ -74,13 +74,16 @@ public class ModuleSyncWatchdog {
* Execute Cm Handle poll which changes the cm handle state from 'LOCKED' to 'ADVISED'.
*/
@Scheduled(fixedDelayString = "${timers.locked-modules-sync.sleep-time-ms:300000}")
- public void executeLockedMisbehavingCmHandlePoll() {
+ public void executeLockedCmHandlePoll() {
final List<YangModelCmHandle> lockedMisbehavingCmHandles = syncUtils.getLockedMisbehavingYangModelCmHandles();
- for (final YangModelCmHandle lockedMisbehavingModelCmHandle : lockedMisbehavingCmHandles) {
- final CompositeState compositeState = lockedMisbehavingModelCmHandle.getCompositeState();
- setCompositeStateToAdvisedAndRetainOldLockReasonDetails(compositeState);
- log.debug("Locked misbehaving cm handle {} is being recycled", lockedMisbehavingModelCmHandle.getId());
- inventoryPersistence.saveCmHandleState(lockedMisbehavingModelCmHandle.getId(), compositeState);
+ for (final YangModelCmHandle moduleSyncFailedCmHandle : lockedMisbehavingCmHandles) {
+ final CompositeState compositeState = moduleSyncFailedCmHandle.getCompositeState();
+ final boolean isReadyForRetry = syncUtils.isReadyForRetry(compositeState);
+ if (isReadyForRetry) {
+ setCompositeStateToAdvisedAndRetainOldLockReasonDetails(compositeState);
+ log.debug("Locked misbehaving cm handle {} is being recycled", moduleSyncFailedCmHandle.getId());
+ inventoryPersistence.saveCmHandleState(moduleSyncFailedCmHandle.getId(), compositeState);
+ }
}
}
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/SyncUtils.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/SyncUtils.java
index 42edcb7ec..8b7dfe6b8 100644
--- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/SyncUtils.java
+++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/SyncUtils.java
@@ -24,6 +24,9 @@ package org.onap.cps.ncmp.api.inventory.sync;
import com.fasterxml.jackson.databind.JsonNode;
import com.google.common.collect.ImmutableMap;
import java.security.SecureRandom;
+import java.time.Duration;
+import java.time.OffsetDateTime;
+import java.time.format.DateTimeFormatter;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
@@ -140,6 +143,28 @@ public class SyncUtils {
.lockReasonCategory(lockReasonCategory).build());
}
+
+ /**
+ * Check if the retry mechanism should attempt to unlock the cm handle based on the last update time.
+ *
+ * @param compositeState the composite state currently in the locked state
+ * @return if the retry mechanism should be attempted
+ */
+ public boolean isReadyForRetry(final CompositeState compositeState) {
+ int timeUntilNextAttempt = 1;
+ final OffsetDateTime time =
+ OffsetDateTime.parse(compositeState.getLastUpdateTime(),
+ DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ"));
+ final Matcher matcher = retryAttemptPattern.matcher(compositeState.getLockReason().getDetails());
+ if (matcher.find()) {
+ timeUntilNextAttempt = (int) Math.pow(2, Integer.parseInt(matcher.group(1)));
+ } else {
+ log.debug("First Attempt: no current attempts found.");
+ }
+ final int timeSinceLastAttempt = (int) Duration.between(time, OffsetDateTime.now()).toMinutes();
+ return timeSinceLastAttempt > timeUntilNextAttempt;
+ }
+
/**
* Get the Resourece Data from Node through DMI Passthrough service.
*
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsServiceSpec.groovy
index e265fef05..52806a867 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsServiceSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/event/NcmpEventsServiceSpec.groovy
@@ -30,17 +30,25 @@ class NcmpEventsServiceSpec extends Specification {
def mockInventoryPersistence = Mock(InventoryPersistence)
def mockNcmpEventsPublisher = Mock(NcmpEventsPublisher)
- def mockNcmpEventsMapper = Mock(NcmpEventsCreator)
+ def mockNcmpEventsCreator = Mock(NcmpEventsCreator)
- def objectUnderTest = new NcmpEventsService(mockInventoryPersistence, mockNcmpEventsPublisher, mockNcmpEventsMapper)
+ def objectUnderTest = new NcmpEventsService(mockInventoryPersistence, mockNcmpEventsPublisher, mockNcmpEventsCreator)
- def 'Create and Publish event for #operation'() {
+ def 'Create and Publish ncmp event where events are #scenario'() {
given: 'a cm handle id and operation and responses are mocked'
mockResponses('test-cm-handle-id', 'test-topic')
+ and: 'notifications enabled is #notificationsEnabled'
+ objectUnderTest.notificationsEnabled = notificationsEnabled
when: 'service is called to publish ncmp event'
objectUnderTest.publishNcmpEvent('test-cm-handle-id')
- then: 'no exception is thrown'
- noExceptionThrown()
+ then: 'creator is called #expectedTimesMethodCalled times'
+ expectedTimesMethodCalled * mockNcmpEventsCreator.populateNcmpEvent('test-cm-handle-id', _)
+ and: 'publisher is called #expectedTimesMethodCalled times'
+ expectedTimesMethodCalled * mockNcmpEventsPublisher.publishEvent(*_)
+ where: 'the following values are used'
+ scenario | notificationsEnabled|| expectedTimesMethodCalled
+ 'enabled' | true || 1
+ 'disabled' | false || 0
}
def mockResponses(cmHandleId, topicName) {
@@ -50,9 +58,8 @@ class NcmpEventsServiceSpec extends Specification {
def ncmpServiceCmhandle = YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle(yangModelCmHandle)
mockInventoryPersistence.getYangModelCmHandle(cmHandleId) >> yangModelCmHandle
- mockNcmpEventsMapper.populateNcmpEvent(cmHandleId, ncmpServiceCmhandle) >> ncmpEvent
+ mockNcmpEventsCreator.populateNcmpEvent(cmHandleId, ncmpServiceCmhandle) >> ncmpEvent
mockNcmpEventsPublisher.publishEvent(topicName, cmHandleId, ncmpEvent) >> {}
}
-
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncSpec.groovy
index 614783efd..0f89a428b 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncSpec.groovy
@@ -90,16 +90,25 @@ class ModuleSyncSpec extends Specification {
}
- def 'Schedule a Cm-Handle Sync for LOCKED with reason LOCKED_MISBEHAVING Cm-Handles '() {
+ def 'Schedule a Cm-Handle Sync for LOCKED with reason LOCKED_MISBEHAVING Cm-Handles with #scenario'() {
given: 'cm handles in an locked state'
def compositeState = new CompositeStateBuilder().withCmHandleState(CmHandleState.LOCKED)
- .withLockReason(LockReasonCategory.LOCKED_MISBEHAVING, '').build()
+ .withLockReason(LockReasonCategory.LOCKED_MISBEHAVING, '').withLastUpdatedTimeNow().build()
def yangModelCmHandle = new YangModelCmHandle(id: 'some-cm-handle', compositeState: compositeState)
and: 'sync utilities return a cm handle twice'
mockSyncUtils.getLockedMisbehavingYangModelCmHandles() >> [yangModelCmHandle, yangModelCmHandle]
+ and: 'inventory persistence returns the composite state of the cm handle'
+ mockInventoryPersistence.getCmHandleState(yangModelCmHandle.getId()) >> compositeState
+ and: 'sync utils retry locked cm handle returns #isReadyForRetry'
+ mockSyncUtils.isReadyForRetry(compositeState) >>> isReadyForRetry
when: 'module sync poll is executed'
- objectUnderTest.executeLockedMisbehavingCmHandlePoll()
+ objectUnderTest.executeLockedCmHandlePoll()
then: 'the first cm handle is updated to state "ADVISED" from "READY"'
- 2 * mockInventoryPersistence.saveCmHandleState(yangModelCmHandle.id, compositeState)
+ expectedNumberOfInvocationsToSaveCmHandleState * mockInventoryPersistence.saveCmHandleState(yangModelCmHandle.id, compositeState)
+ where:
+ scenario | isReadyForRetry || expectedNumberOfInvocationsToSaveCmHandleState
+ 'retry locked cm handle once' | [true, false] || 1
+ 'retry locked cm handle twice' | [true, true] || 2
+ 'do not retry locked cm handle' | [false, false] || 0
}
}
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy
index 2c45ab769..dd299146f 100644
--- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy
+++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy
@@ -27,6 +27,7 @@ import org.onap.cps.ncmp.api.impl.operations.DmiDataOperations
import org.onap.cps.ncmp.api.impl.operations.DmiOperations
import org.onap.cps.ncmp.api.inventory.CmHandleState
import org.onap.cps.ncmp.api.inventory.CompositeState
+import org.onap.cps.ncmp.api.inventory.CompositeStateBuilder
import org.onap.cps.ncmp.api.inventory.InventoryPersistence
import org.onap.cps.ncmp.api.inventory.LockReasonCategory
import org.onap.cps.ncmp.api.inventory.SyncState
@@ -38,6 +39,9 @@ import org.springframework.http.ResponseEntity
import spock.lang.Shared
import spock.lang.Specification
+import java.time.OffsetDateTime
+import java.time.format.DateTimeFormatter
+
class SyncUtilsSpec extends Specification{
def mockInventoryPersistence = Mock(InventoryPersistence)
@@ -49,6 +53,9 @@ class SyncUtilsSpec extends Specification{
def objectUnderTest = new SyncUtils(mockInventoryPersistence, mockDmiDataOperations, jsonObjectMapper)
@Shared
+ def formattedDateAndTime = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ").format(OffsetDateTime.now())
+
+ @Shared
def dataNode = new DataNode(leaves: ['id': 'cm-handle-123'])
def 'Get an advised Cm-Handle where ADVISED cm handle #scenario'() {
@@ -94,6 +101,21 @@ class SyncUtilsSpec extends Specification{
result[0].id == 'cm-handle-123'
}
+ def 'Retry Locked Cm-Handle where the last update time is #scenario'() {
+ when: 'retry locked cm handle is invoked'
+ def result = objectUnderTest.isReadyForRetry(new CompositeStateBuilder()
+ .withLockReason(LockReasonCategory.LOCKED_MISBEHAVING, details)
+ .withLastUpdatedTime(lastUpdateTime).build())
+ then: 'result returns #expectedResult'
+ result == expectedResult
+ where:
+ scenario | lastUpdateTime | details || expectedResult
+ 'is the first attempt' | '1900-01-01T00:00:00.000+0100' | 'First Attempt' || true
+ 'is greater than one minute' | '1900-01-01T00:00:00.000+0100' | 'Attempt #1 failed:' || true
+ 'is less than eight minutes' | formattedDateAndTime | 'Attempt #3 failed:' || false
+ }
+
+
def 'Get a Cm-Handle where Operational Sync state is UnSynchronized and Cm-handle state is READY and #scenario'() {
given: 'the inventory persistence service returns a collection of data nodes'
mockInventoryPersistence.getCmHandlesByOperationalSyncState(SyncState.UNSYNCHRONIZED) >> unSynchronizedDataNodes
diff --git a/cps-service/src/main/java/org/onap/cps/config/AsyncConfig.java b/cps-service/src/main/java/org/onap/cps/config/AsyncConfig.java
index 2667ef490..2d8f7fb08 100644
--- a/cps-service/src/main/java/org/onap/cps/config/AsyncConfig.java
+++ b/cps-service/src/main/java/org/onap/cps/config/AsyncConfig.java
@@ -1,6 +1,7 @@
/*
* ============LICENSE_START=======================================================
* Copyright (c) 2021 Bell Canada.
+ * Modifications Copyright (C) 2022 Nordix Foundation.
* ================================================================================
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -33,7 +34,7 @@ import org.springframework.validation.annotation.Validated;
@EnableAsync
@Configuration
-@ConditionalOnProperty(name = "notification.async.enabled", havingValue = "true", matchIfMissing = false)
+@ConditionalOnProperty(name = "notification.enabled", havingValue = "true", matchIfMissing = true)
@ConfigurationProperties("notification.async.executor")
@Validated
@Setter
diff --git a/cps-service/src/main/java/org/onap/cps/notification/NotificationProperties.java b/cps-service/src/main/java/org/onap/cps/notification/NotificationProperties.java
index eb75e3f75..3776a93d9 100644
--- a/cps-service/src/main/java/org/onap/cps/notification/NotificationProperties.java
+++ b/cps-service/src/main/java/org/onap/cps/notification/NotificationProperties.java
@@ -23,6 +23,7 @@ import java.util.Collections;
import java.util.Map;
import javax.validation.constraints.NotNull;
import lombok.Data;
+import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.validation.annotation.Validated;
@@ -36,6 +37,7 @@ public class NotificationProperties {
@NotNull
private String topic;
private Map<String, String> filters = Collections.emptyMap();
- @NotNull
- private boolean enabled = false;
+
+ @Value("${notification.enabled:true}")
+ private boolean enabled;
}
diff --git a/cps-service/src/test/resources/application.yml b/cps-service/src/test/resources/application.yml
index a28b40083..04295eb74 100644
--- a/cps-service/src/test/resources/application.yml
+++ b/cps-service/src/test/resources/application.yml
@@ -18,13 +18,12 @@
# ============LICENSE_END=========================================================
notification:
+ enabled: true
data-updated:
filters:
enabled-dataspaces: ".*-published,.*-important"
- enabled: true
topic: cps-event
async:
- enabled: true
executor:
core-pool-size: 2
max-pool-size: 10
diff --git a/csit/plans/cps/pnfsim/docker-compose.yml b/csit/plans/cps/pnfsim/docker-compose.yml
index 568f98f41..568f98f41 100755..100644
--- a/csit/plans/cps/pnfsim/docker-compose.yml
+++ b/csit/plans/cps/pnfsim/docker-compose.yml
diff --git a/csit/plans/cps/setup.sh b/csit/plans/cps/setup.sh
index 59542402f..43575f944 100755
--- a/csit/plans/cps/setup.sh
+++ b/csit/plans/cps/setup.sh
@@ -61,12 +61,12 @@ mkdir -p $WORKSPACE/archives/dc-cps
cp $WORKSPACE/../docker-compose/*.yml $WORKSPACE/archives/dc-cps
cd $WORKSPACE/archives/dc-cps
-# download docker-compose of a required version (1.25.0 supports configuration of version 3.7)
-curl -L https://github.com/docker/compose/releases/download/1.25.0/docker-compose-`uname -s`-`uname -m` > docker-compose
+curl -L https://github.com/docker/compose/releases/download/1.29.2/docker-compose-`uname -s`-`uname -m` > docker-compose
chmod +x docker-compose
+docker-compose version
# start CPS/NCMP, DMI, and PostgreSQL containers with docker compose
-./docker-compose up -d
+docker-compose up -d
###################### setup sdnc #######################################
source $WORKSPACE/plans/cps/sdnc/sdnc_setup.sh
diff --git a/docker-compose/docker-compose.yml b/docker-compose/docker-compose.yml
index 9edea3526..eafcb3c9f 100755..100644
--- a/docker-compose/docker-compose.yml
+++ b/docker-compose/docker-compose.yml
@@ -16,74 +16,12 @@
# limitations under the License.
# ============LICENSE_END=========================================================
-version: "3.7"
+version: '3.3'
services:
- ### Services cps-service, cps-ncmp, zookeeper and kafka are commented below, these
- ### services can be un-commented and used on need to use basis. Only minimal
- ### services will run (dbpostgresql, cps-and-ncmp and ncmp-dmi-plugin) by default.
- #cps-standalone:
- # container_name: cps-service
- # image: ${DOCKER_REPO:-nexus3.onap.org:10003}/onap/cps-service:${VERSION:-latest}
- # ports:
- # - "8881:8080"
- # - "8887:8081"
- # environment:
- # CPS_USERNAME: ${CPS_CORE_USERNAME:-cpsuser}
- # CPS_PASSWORD: ${CPS_CORE_PASSWORD:-cpsr0cks!}
- # DB_HOST: dbpostgresql
- # DB_USERNAME: ${DB_USERNAME:-cps}
- # DB_PASSWORD: ${DB_PASSWORD:-cps}
- # #KAFKA_BOOTSTRAP_SERVER: kafka:9092
- # #notification.data-updated.enabled: 'true'
- # #NOTIFICATION_DATASPACE_FILTER_PATTERNS: '.*'
- # restart: unless-stopped
- # depends_on:
- # - dbpostgresql
-
- #ncmp-standalone:
- # container_name: cps-ncmp
- # image: ${DOCKER_REPO:-nexus3.onap.org:10003}/onap/cps-ncmp:${VERSION:-latest}
- # ports:
- # - "8882:8080"
- # - "8887:8081"
- # environment:
- # CPS_USERNAME: ${CPS_CORE_USERNAME:-cpsuser}
- # CPS_PASSWORD: ${CPS_CORE_PASSWORD:-cpsr0cks!}
- # DB_HOST: dbpostgresql
- # DB_USERNAME: ${DB_USERNAME:-cps}
- # DB_PASSWORD: ${DB_PASSWORD:-cps}
- # DMI_USERNAME: ${DMI_USERNAME:-cpsuser}
- # DMI_PASSWORD: ${DMI_PASSWORD:-cpsr0cks!}
- # #KAFKA_BOOTSTRAP_SERVER: kafka:9092
- # #notification.data-updated.enabled: 'true'
- # #NOTIFICATION_DATASPACE_FILTER_PATTERNS: '.*'
- # restart: unless-stopped
- # depends_on:
- # - dbpostgresql
-
- # zookeeper:
- # image: confluentinc/cp-zookeeper:6.2.1
- # environment:
- # ZOOKEEPER_CLIENT_PORT: 2181
- # ZOOKEEPER_TICK_TIME: 2000
- # ports:
- # - 22181:2181
- #
- # kafka:
- # image: confluentinc/cp-kafka:6.2.1
- # depends_on:
- # - zookeeper
- # ports:
- # - 29092:29092
- # environment:
- # KAFKA_BROKER_ID: 1
- # KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
- # KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092
- # KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
- # KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
- # KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
+ ### docker-compose up -d -> run ALL services ###
+ ### to disable notifications make notification.enabled to false & comment out kafka/zookeeper services ###
dbpostgresql:
container_name: dbpostgresql
@@ -110,7 +48,8 @@ services:
DMI_USERNAME: ${DMI_USERNAME:-cpsuser}
DMI_PASSWORD: ${DMI_PASSWORD:-cpsr0cks!}
KAFKA_BOOTSTRAP_SERVER: kafka:9092
- notification.data-updated.enabled: 'true'
+ notification.enabled: 'true'
+ notification.async.executor.time-out-value-in-ms: 2000
NOTIFICATION_DATASPACE_FILTER_PATTERNS: '.*'
TIMERS_ADVISED-MODULES-SYNC_SLEEP-TIME-MS: 2000
restart: unless-stopped
diff --git a/docs/deployment.rst b/docs/deployment.rst
index 7dd4494f2..c0d8b6029 100644
--- a/docs/deployment.rst
+++ b/docs/deployment.rst
@@ -246,15 +246,12 @@ Any spring supported property can be configured by providing in ``config.additio
| config.additional. | Kafka topic to publish to cps-temporal | ``cps.data-updated-events`` |
| notification.data-updated.topic | | |
+---------------------------------------+---------------------------------------------------------------------------------------------------------+-------------------------------+
-| config.additional. | If notification from cps-core to cps-temporal is enabled or not. | ``true`` |
-| notification.data-updated.enabled | If this is set to false, then the config.publisher properties could be skipped. | |
-+---------------------------------------+---------------------------------------------------------------------------------------------------------+-------------------------------+
| config.additional. | Dataspaces to be enabled for publishing events to cps-temporal | ```` |
| notification.data-updated.filters. | | |
| enabled-dataspaces | | |
+---------------------------------------+---------------------------------------------------------------------------------------------------------+-------------------------------+
-| config.additional. | If notifications should be processed in synchronous or asynchronous manner | ``false`` |
-| notification.async.enabled | | |
+| config.additional. | If asynchronous messaging, user notifications, and updated event persistence should be enabled | ``true`` |
+| notification.enabled | | |
+---------------------------------------+---------------------------------------------------------------------------------------------------------+-------------------------------+
| config.additional. | Core pool size in asynchronous execution of notification. | ``2`` |
| notification.async.executor. | | |