diff options
Diffstat (limited to 'cps-ncmp-service')
11 files changed, 280 insertions, 10 deletions
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java index e624953f54..c0f73d92d6 100755 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImpl.java @@ -184,7 +184,7 @@ public class NetworkCmProxyDataServiceImpl implements NetworkCmProxyDataService CpsValidator.validateNameCharacters(cmHandleId); final NcmpServiceCmHandle ncmpServiceCmHandle = new NcmpServiceCmHandle(); final YangModelCmHandle yangModelCmHandle = - yangModelCmHandleRetriever.getDmiServiceNamesAndProperties(cmHandleId); + yangModelCmHandleRetriever.getYangModelCmHandle(cmHandleId); final List<YangModelCmHandle.Property> dmiProperties = yangModelCmHandle.getDmiProperties(); final List<YangModelCmHandle.Property> publicProperties = yangModelCmHandle.getPublicProperties(); ncmpServiceCmHandle.setCmHandleId(yangModelCmHandle.getId()); diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java index ad85edde7b..f145379406 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/DmiDataOperations.java @@ -72,7 +72,7 @@ public class DmiDataOperations extends DmiOperations { final String topicParamInQuery) { CpsValidator.validateNameCharacters(cmHandleId); final YangModelCmHandle yangModelCmHandle = - yangModelCmHandleRetriever.getDmiServiceNamesAndProperties(cmHandleId); + yangModelCmHandleRetriever.getYangModelCmHandle(cmHandleId); final DmiRequestBody dmiRequestBody = DmiRequestBody.builder() .operation(READ) .requestId(requestId) @@ -104,7 +104,7 @@ public class DmiDataOperations extends DmiOperations { final String dataType) { CpsValidator.validateNameCharacters(cmHandleId); final YangModelCmHandle yangModelCmHandle = - yangModelCmHandleRetriever.getDmiServiceNamesAndProperties(cmHandleId); + yangModelCmHandleRetriever.getYangModelCmHandle(cmHandleId); final DmiRequestBody dmiRequestBody = DmiRequestBody.builder() .operation(operation) .data(requestData) diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/YangModelCmHandleRetriever.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/YangModelCmHandleRetriever.java index 0efe8d5b62..b1ac91d7a3 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/YangModelCmHandleRetriever.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/operations/YangModelCmHandleRetriever.java @@ -48,7 +48,7 @@ public class YangModelCmHandleRetriever { * @param cmHandleId the id of the cm handle * @return yang model cm handle */ - public YangModelCmHandle getDmiServiceNamesAndProperties(final String cmHandleId) { + public YangModelCmHandle getYangModelCmHandle(final String cmHandleId) { CpsValidator.validateNameCharacters(cmHandleId); final DataNode cmHandleDataNode = getCmHandleDataNode(cmHandleId); final NcmpServiceCmHandle ncmpServiceCmHandle = new NcmpServiceCmHandle(); diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandle.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandle.java index fd3528187e..289d782cde 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandle.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/yangmodels/YangModelCmHandle.java @@ -55,6 +55,9 @@ public class YangModelCmHandle { @JsonProperty("dmi-data-service-name") private String dmiDataServiceName; + @JsonProperty("state") + private String cmHandleState; + @JsonProperty("dmi-model-service-name") private String dmiModelServiceName; 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 new file mode 100644 index 0000000000..69413171d6 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncWatchdog.java @@ -0,0 +1,56 @@ +/* + * ============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 lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.api.impl.yangmodels.YangModelCmHandle; +import org.springframework.scheduling.annotation.EnableScheduling; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +@Slf4j +@EnableScheduling +@RequiredArgsConstructor +@Component +public class ModuleSyncWatchdog { + + private final SyncUtils syncUtils; + + /** + * Execute Cm Handle poll which changes the cm handle state from 'ADVISED' to 'READY'. + */ + @Scheduled(fixedDelay = 30000) + 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(); + } + log.debug("No Cm-Handles currently found in an ADVISED state"); + } + +} 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 new file mode 100644 index 0000000000..924546433e --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/sync/SyncUtils.java @@ -0,0 +1,87 @@ +/* + * ============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 static org.onap.cps.ncmp.api.impl.constants.DmiRegistryConstants.NCMP_DATASPACE_NAME; +import static org.onap.cps.ncmp.api.impl.constants.DmiRegistryConstants.NCMP_DMI_REGISTRY_ANCHOR; +import static org.onap.cps.ncmp.api.impl.constants.DmiRegistryConstants.NCMP_DMI_REGISTRY_PARENT; + +import java.security.SecureRandom; +import java.time.OffsetDateTime; +import java.util.List; +import lombok.RequiredArgsConstructor; +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.spi.CpsDataPersistenceService; +import org.onap.cps.spi.FetchDescendantsOption; +import org.onap.cps.spi.model.DataNode; +import org.onap.cps.utils.JsonObjectMapper; +import org.springframework.stereotype.Component; + +@Slf4j +@Component +@RequiredArgsConstructor +public class SyncUtils { + + private static final SecureRandom secureRandom = new SecureRandom(); + private final CpsDataService cpsDataService; + + private final CpsDataPersistenceService cpsDataPersistenceService; + + private final JsonObjectMapper jsonObjectMapper; + + private final YangModelCmHandleRetriever yangModelCmHandleRetriever; + + /** + * Query data nodes for cm handles with an "ADVISED" cm handle state, and select a random entry for processing. + * + * @return a random yang model cm handle with an ADVISED state, return null if not found + */ + public YangModelCmHandle getAnAdvisedCmHandle() { + final List<DataNode> advisedCmHandles = cpsDataPersistenceService.queryDataNodes("NCMP-Admin", + "ncmp-dmi-registry", "//cm-handles[@state=\"ADVISED\"]", + FetchDescendantsOption.OMIT_DESCENDANTS); + if (advisedCmHandles.isEmpty()) { + return null; + } + final int randomElementIndex = secureRandom.nextInt(advisedCmHandles.size()); + final String cmHandleId = advisedCmHandles.get(randomElementIndex).getLeaves() + .get("id").toString(); + return yangModelCmHandleRetriever.getYangModelCmHandle(cmHandleId); + } + + /** + * Update the Cm Handle state to "READY". + * + * @param yangModelCmHandle yang model cm handle + * @param state cm handle state + */ + public void updateCmHandleState(final YangModelCmHandle yangModelCmHandle, final String state) { + yangModelCmHandle.setCmHandleState(state); + final String cmHandleJsonData = String.format("{\"cm-handles\":[%s]}", + jsonObjectMapper.asJsonString(yangModelCmHandle)); + cpsDataService.updateNodeLeaves(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, NCMP_DMI_REGISTRY_PARENT, + cmHandleJsonData, OffsetDateTime.now()); + } + +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy index 7629500db0..65f007d14f 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/NetworkCmProxyDataServiceImplSpec.groovy @@ -74,7 +74,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { def cmHandleXPath = "/dmi-registry/cm-handles[@id='testCmHandle']" - def dataNode = new DataNode(leaves: ['dmi-service-name': 'testDmiService']) + def dataNode = new DataNode(leaves: ['id': 'Some-Cm-Handle', 'dmi-service-name': 'testDmiService']) def 'Write resource data for pass-through running from DMI using POST #scenario cm handle properties.'() { given: 'cpsDataService returns valid datanode' @@ -285,7 +285,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { def dmiProperties = [new YangModelCmHandle.Property('Book', 'Romance Novel')] def publicProperties = [new YangModelCmHandle.Property('Public Book', 'Public Romance Novel')] def yangModelCmHandle = new YangModelCmHandle(id:'Some-Cm-Handle', dmiServiceName: dmiServiceName, dmiProperties: dmiProperties, publicProperties: publicProperties) - 1 * mockYangModelCmHandleRetriever.getDmiServiceNamesAndProperties('Some-Cm-Handle') >> yangModelCmHandle + 1 * mockYangModelCmHandleRetriever.getYangModelCmHandle('Some-Cm-Handle') >> yangModelCmHandle when: 'getting cm handle details for a given cm handle id from ncmp service' def result = objectUnderTest.getNcmpServiceCmHandle('Some-Cm-Handle') then: 'the result returns the correct data' @@ -301,7 +301,7 @@ class NetworkCmProxyDataServiceImplSpec extends Specification { then: 'an exception is thrown' thrown(DataValidationException) and: 'the yang model cm handle retriever is not invoked' - 0 * mockYangModelCmHandleRetriever.getDmiServiceNamesAndProperties(_) + 0 * mockYangModelCmHandleRetriever.getYangModelCmHandle(_) } def 'Update resource data for pass-through running from dmi using POST #scenario DMI properties.'() { diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy index 563116f402..dae2bcc0ae 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/DmiOperationsBaseSpec.groovy @@ -56,6 +56,6 @@ abstract class DmiOperationsBaseSpec extends Specification { yangModelCmHandle.dmiServiceName = dmiServiceName yangModelCmHandle.dmiProperties = dmiProperties yangModelCmHandle.id = cmHandleId - mockCmHandlePropertiesRetriever.getDmiServiceNamesAndProperties(cmHandleId) >> yangModelCmHandle + mockCmHandlePropertiesRetriever.getYangModelCmHandle(cmHandleId) >> yangModelCmHandle } } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/YangModelCmHandleRetrieverSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/YangModelCmHandleRetrieverSpec.groovy index bc30c9c777..beea1faada 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/YangModelCmHandleRetrieverSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/operations/YangModelCmHandleRetrieverSpec.groovy @@ -54,7 +54,7 @@ class YangModelCmHandleRetrieverSpec extends Specification { def dataNode = new DataNode(childDataNodes:childDataNodes, leaves: leaves) mockCpsDataService.getDataNode('NCMP-Admin', 'ncmp-dmi-registry', xpath, INCLUDE_ALL_DESCENDANTS) >> dataNode when: 'retrieving the yang modelled cm handle' - def result = objectUnderTest.getDmiServiceNamesAndProperties(cmHandleId) + def result = objectUnderTest.getYangModelCmHandle(cmHandleId) then: 'the result has the correct id and service names' result.id == cmHandleId result.dmiServiceName == 'common service name' @@ -73,7 +73,7 @@ class YangModelCmHandleRetrieverSpec extends Specification { def "Retrieve CmHandle using datanode with invalid CmHandle id."() { when: 'retrieving the yang modelled cm handle with an invalid id' - def result = objectUnderTest.getDmiServiceNamesAndProperties('cm handle id with spaces') + def result = objectUnderTest.getYangModelCmHandle('cm handle id with spaces') then: 'a data validation exception is thrown' thrown(DataValidationException) and: 'the result is not returned' 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 new file mode 100644 index 0000000000..bcc6bb4676 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/ModuleSyncSpec.groovy @@ -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.impl.yangmodels.YangModelCmHandle +import spock.lang.Specification + +class ModuleSyncSpec extends Specification { + + def mockSyncUtils = Mock(SyncUtils) + + def objectUnderTest = new ModuleSyncWatchdog(mockSyncUtils) + + def 'Schedule a Cm-Handle Sync for ADVISED Cm-Handles'() { + given: 'a cm handle' + def yangModelCmHandle1 = new YangModelCmHandle() + def yangModelCmHandle2 = new YangModelCmHandle() + 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') + } + +} 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 new file mode 100644 index 0000000000..04b2d55133 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/sync/SyncUtilsSpec.groovy @@ -0,0 +1,78 @@ +/* + * ============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 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.spi.CpsDataPersistenceService +import org.onap.cps.spi.FetchDescendantsOption +import org.onap.cps.spi.model.DataNode +import org.onap.cps.utils.JsonObjectMapper +import spock.lang.Shared +import spock.lang.Specification + +import java.time.OffsetDateTime + +class SyncUtilsSpec extends Specification{ + + def mockCpsDataService = Mock(CpsDataService) + def mockCpsDataPersistenceService = Mock(CpsDataPersistenceService) + def spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper())) + def mockYangModelCmHandleRetriever = Mock(YangModelCmHandleRetriever) + + def objectUnderTest = new SyncUtils(mockCpsDataService, mockCpsDataPersistenceService, spiedJsonObjectMapper, mockYangModelCmHandleRetriever) + + @Shared + def dataNode = new DataNode(leaves: ['id': 'cm-handle-123']) + + + + def 'Get an advised Cm-Handle where ADVISED cm handle #scenario'() { + given: 'the cps (persistence service) returns a collection of data nodes' + mockCpsDataPersistenceService.queryDataNodes('NCMP-Admin', + 'ncmp-dmi-registry', '//cm-handles[@state=\"ADVISED\"]', + FetchDescendantsOption.OMIT_DESCENDANTS) >> dataNodeCollection + when: 'get advised cm handle is called' + objectUnderTest.getAnAdvisedCmHandle() + then: 'the returned data node collection is the correct size' + dataNodeCollection.size() == expectedDataNodeSize + and: 'get yang model cm handles is invoked the correct number of times' + expectedCallsToGetYangModelCmHandle * mockYangModelCmHandleRetriever.getYangModelCmHandle('cm-handle-123') + where: 'the following scenarios are used' + scenario | dataNodeCollection || expectedCallsToGetYangModelCmHandle | expectedDataNodeSize + 'exists' | [ dataNode ] || 1 | 1 + 'does not exist' | [ ] || 0 | 0 + + } + + 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 expectedJsonData = '{"cm-handles":[{"id":"Some-Cm-Handle","state":"READY"}]}' + when: 'update cm handle state is called' + objectUnderTest.updateCmHandleState(yangModelCmHandle, '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) + } + +} |