Watchdog-process that syncs 'ADVISED' CM Handles 02/129102/10
authorDylanB95EST <dylan.byrne@est.tech>
Thu, 5 May 2022 10:53:12 +0000 (11:53 +0100)
committerDylanB95EST <dylan.byrne@est.tech>
Thu, 12 May 2022 15:14:17 +0000 (16:14 +0100)
- Sync and Create Schema Set during
module sync watchdog process.

- Add a cm handle state transition machine to handle
state changes for a cm handle during watchdog
which syncs module service.

Issue-ID: CPS-875
Change-Id: I3b178f5693cb7ac30577dd81cdc82b462555389a
Signed-off-by: DylanB95EST <dylan.byrne@est.tech>
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/NcmpConfiguration.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandle.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CmHandleState.java [new file with mode: 0644]
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdog.java
cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/SyncUtils.java
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/CmHandleStateSpec.groovy [new file with mode: 0644]
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncSpec.groovy
cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy

index 3aa17b7..11683ad 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2021 Nordix Foundation
+ *  Copyright (C) 2021-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.
@@ -21,7 +21,9 @@
 package org.onap.cps.ncmp.api.impl.config;
 
 import java.util.Arrays;
+import lombok.AccessLevel;
 import lombok.Getter;
+import lombok.RequiredArgsConstructor;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.boot.web.client.RestTemplateBuilder;
 import org.springframework.context.annotation.Bean;
@@ -29,10 +31,13 @@ import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Scope;
 import org.springframework.http.MediaType;
 import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
+import org.springframework.scheduling.annotation.EnableScheduling;
 import org.springframework.stereotype.Component;
 import org.springframework.web.client.RestTemplate;
 
+@EnableScheduling
 @Configuration
+@RequiredArgsConstructor(access = AccessLevel.PROTECTED)
 public class NcmpConfiguration {
 
     @Getter
@@ -67,4 +72,5 @@ public class NcmpConfiguration {
             Arrays.asList(MediaType.APPLICATION_JSON, MediaType.TEXT_PLAIN));
         restTemplate.getMessageConverters().add(mappingJackson2HttpMessageConverter);
     }
+
 }
index 289d782..5680d54 100644 (file)
@@ -34,6 +34,7 @@ import lombok.Getter;
 import lombok.NoArgsConstructor;
 import lombok.Setter;
 import org.onap.cps.ncmp.api.impl.operations.RequiredDmiService;
+import org.onap.cps.ncmp.api.inventory.CmHandleState;
 import org.onap.cps.ncmp.api.models.NcmpServiceCmHandle;
 import org.onap.cps.utils.CpsValidator;
 
@@ -56,7 +57,7 @@ public class YangModelCmHandle {
     private String dmiDataServiceName;
 
     @JsonProperty("state")
-    private String cmHandleState;
+    private CmHandleState cmHandleState;
 
     @JsonProperty("dmi-model-service-name")
     private String dmiModelServiceName;
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CmHandleState.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/CmHandleState.java
new file mode 100644 (file)
index 0000000..0fce1d1
--- /dev/null
@@ -0,0 +1,41 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  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.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.ncmp.api.inventory;
+
+public enum CmHandleState {
+
+    ADVISED {
+        @Override
+        public CmHandleState ready() {
+            return READY;
+        }
+    },
+    READY {
+        @Override
+        public CmHandleState ready() {
+            return this;
+        }
+
+    };
+
+    public abstract CmHandleState ready();
+
+}
index 0d8f852..368262b 100644 (file)
@@ -23,32 +23,32 @@ package org.onap.cps.ncmp.api.inventory.sync;
 import lombok.RequiredArgsConstructor;
 import lombok.extern.slf4j.Slf4j;
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
-import org.springframework.scheduling.annotation.EnableScheduling;
+import org.onap.cps.ncmp.api.inventory.CmHandleState;
 import org.springframework.scheduling.annotation.Scheduled;
 import org.springframework.stereotype.Component;
 
 @Slf4j
-@EnableScheduling
 @RequiredArgsConstructor
 @Component
 public class ModuleSyncWatchdog {
 
     private final SyncUtils syncUtils;
 
+    private final ModuleSyncService moduleSyncService;
+
     /**
      * Execute Cm Handle poll which changes the cm handle state from 'ADVISED' to 'READY'.
      */
     @Scheduled(fixedDelayString = "${ncmp.timers.advised-modules-sync.sleep-time-ms}")
     public void executeAdvisedCmHandlePoll() {
-        YangModelCmHandle newAdvisedCmHandle = syncUtils.getAnAdvisedCmHandle();
-        while (newAdvisedCmHandle != null) {
-            // ToDo When Cm-Handle in the 'ADVISED' state is Retrieved, Set CM-Handle state to 'LOCKED'
-            //  and give lock reason
-            // ToDo if lock fails, move to next cm handle.
-            // ToDo Update last update time with a timestamp everytime Cm-handle state is changed
-            syncUtils.updateCmHandleState(newAdvisedCmHandle, "READY");
-            log.info("{} is now in READY state", newAdvisedCmHandle.getId());
-            newAdvisedCmHandle = syncUtils.getAnAdvisedCmHandle();
+        YangModelCmHandle advisedCmHandle = syncUtils.getAnAdvisedCmHandle();
+        while (advisedCmHandle != null) {
+            final CmHandleState cmHandleState = advisedCmHandle.getCmHandleState();
+            moduleSyncService.syncAndCreateSchemaSet(advisedCmHandle);
+            // ToDo Lock Cm Handle if module sync fails
+            syncUtils.updateCmHandleState(advisedCmHandle, cmHandleState.ready());
+            log.info("{} is now in {} state", advisedCmHandle.getId(), advisedCmHandle.getCmHandleState());
+            advisedCmHandle = syncUtils.getAnAdvisedCmHandle();
         }
         log.debug("No Cm-Handles currently found in an ADVISED state");
     }
index 9245464..019ab08 100644 (file)
@@ -32,6 +32,7 @@ import lombok.extern.slf4j.Slf4j;
 import org.onap.cps.api.CpsDataService;
 import org.onap.cps.ncmp.api.impl.operations.YangModelCmHandleRetriever;
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle;
+import org.onap.cps.ncmp.api.inventory.CmHandleState;
 import org.onap.cps.spi.CpsDataPersistenceService;
 import org.onap.cps.spi.FetchDescendantsOption;
 import org.onap.cps.spi.model.DataNode;
@@ -74,10 +75,10 @@ public class SyncUtils {
      * Update the Cm Handle state to "READY".
      *
      * @param yangModelCmHandle yang model cm handle
-     * @param state cm handle state
+     * @param cmHandleState cm handle state
      */
-    public void updateCmHandleState(final YangModelCmHandle yangModelCmHandle, final String state) {
-        yangModelCmHandle.setCmHandleState(state);
+    public void updateCmHandleState(final YangModelCmHandle yangModelCmHandle, final CmHandleState cmHandleState) {
+        yangModelCmHandle.setCmHandleState(cmHandleState);
         final String cmHandleJsonData = String.format("{\"cm-handles\":[%s]}",
             jsonObjectMapper.asJsonString(yangModelCmHandle));
         cpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, NCMP_DMI_REGISTRY_PARENT,
diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/CmHandleStateSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/CmHandleStateSpec.groovy
new file mode 100644 (file)
index 0000000..923a903
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * ============LICENSE_START=======================================================
+ *  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.
+ *  You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ *
+ *  SPDX-License-Identifier: Apache-2.0
+ *  ============LICENSE_END=========================================================
+ */
+
+package org.onap.cps.ncmp.api.inventory.sync
+
+import org.onap.cps.ncmp.api.inventory.CmHandleState
+import spock.lang.Specification
+
+class CmHandleStateSpec extends Specification{
+
+    def 'Transition to READY state from ADVISED state'() {
+        given: 'a cm handle with an ADVISED state'
+            def cmHandleState = CmHandleState.ADVISED
+        when: 'the state transitions to the READY state'
+            cmHandleState = cmHandleState.ready()
+        then: 'the cm handle state changes to READY'
+            assert CmHandleState.READY == cmHandleState
+    }
+
+    def 'Transition to READY state from READY state'() {
+        given: 'a cm handle with a READY state'
+            def cmHandleState = CmHandleState.READY
+        when: 'the state transitions to READY state'
+            cmHandleState = cmHandleState.ready()
+        then: 'the cm handle state remains as READY'
+            assert CmHandleState.READY == cmHandleState
+    }
+
+}
index bcc6bb4..0a06fba 100644 (file)
@@ -22,25 +22,35 @@ package org.onap.cps.ncmp.api.inventory.sync
 
 
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
+import org.onap.cps.ncmp.api.inventory.CmHandleState
 import spock.lang.Specification
 
 class ModuleSyncSpec extends Specification {
 
     def mockSyncUtils = Mock(SyncUtils)
 
-    def objectUnderTest = new ModuleSyncWatchdog(mockSyncUtils)
+    def mockModuleSyncService = Mock(ModuleSyncService)
+
+    def cmHandleState = CmHandleState.ADVISED
+
+    def objectUnderTest = new ModuleSyncWatchdog(mockSyncUtils, mockModuleSyncService)
 
     def 'Schedule a Cm-Handle Sync for ADVISED Cm-Handles'() {
-        given: 'a cm handle'
-            def yangModelCmHandle1 = new YangModelCmHandle()
-            def yangModelCmHandle2 = new YangModelCmHandle()
+        given: 'cm handles in an advised state'
+            def yangModelCmHandle1 = new YangModelCmHandle(cmHandleState: cmHandleState)
+            def yangModelCmHandle2 = new YangModelCmHandle(cmHandleState: cmHandleState)
         and: 'sync utilities return a cm handle twice'
             mockSyncUtils.getAnAdvisedCmHandle() >>> [yangModelCmHandle1, yangModelCmHandle2, null]
         when: 'module sync poll is executed'
             objectUnderTest.executeAdvisedCmHandlePoll()
-        then: 'each cm handle is updated to state "READY"'
-            1 * mockSyncUtils.updateCmHandleState(yangModelCmHandle1, 'READY')
-            1 * mockSyncUtils.updateCmHandleState(yangModelCmHandle2, 'READY')
+        then: 'module sync service syncs the first cm handle and creates a schema set'
+            1 * mockModuleSyncService.syncAndCreateSchemaSet(yangModelCmHandle1)
+        and: 'the first cm handle is updated to state "READY" from "ADVISED"'
+            1 * mockSyncUtils.updateCmHandleState(yangModelCmHandle1, CmHandleState.READY)
+        then: 'module sync service syncs the second cm handle and creates a schema set'
+            1 * mockModuleSyncService.syncAndCreateSchemaSet(yangModelCmHandle2)
+        then: 'the second cm handle is updated to state "READY" from "ADVISED"'
+            1 * mockSyncUtils.updateCmHandleState(yangModelCmHandle2, CmHandleState.READY)
     }
 
 }
index 04b2d55..e5d3652 100644 (file)
@@ -24,6 +24,7 @@ import com.fasterxml.jackson.databind.ObjectMapper
 import org.onap.cps.api.CpsDataService
 import org.onap.cps.ncmp.api.impl.operations.YangModelCmHandleRetriever
 import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle
+import org.onap.cps.ncmp.api.inventory.CmHandleState
 import org.onap.cps.spi.CpsDataPersistenceService
 import org.onap.cps.spi.FetchDescendantsOption
 import org.onap.cps.spi.model.DataNode
@@ -67,10 +68,10 @@ class SyncUtilsSpec extends Specification{
 
     def 'Update cm handle state from Advised to Ready'() {
         given: 'a yang model cm handle and the expected json data'
-            def yangModelCmHandle = new YangModelCmHandle('id': 'Some-Cm-Handle', 'cmHandleState': 'ADVISED')
+            def yangModelCmHandle = new YangModelCmHandle(id: 'Some-Cm-Handle', cmHandleState: CmHandleState.ADVISED)
             def expectedJsonData = '{"cm-handles":[{"id":"Some-Cm-Handle","state":"READY"}]}'
         when: 'update cm handle state is called'
-            objectUnderTest.updateCmHandleState(yangModelCmHandle, 'READY')
+            objectUnderTest.updateCmHandleState(yangModelCmHandle, CmHandleState.READY)
         then: 'update data note leaves is invoked with the correct params'
             1 * mockCpsDataService.updateNodeLeaves('NCMP-Admin', 'ncmp-dmi-registry', '/dmi-registry', expectedJsonData, _ as OffsetDateTime)
     }