diff options
author | emaclee <lee.anjella.macabuhay@est.tech> | 2025-01-12 12:39:55 +0000 |
---|---|---|
committer | emaclee <lee.anjella.macabuhay@est.tech> | 2025-01-16 15:28:15 +0000 |
commit | e0ea27a6e0902a4bff75ae5cd4b6025ee0d40a1c (patch) | |
tree | 80623f25990b8b2043c7e5690c1f96ba954da8a7 /cps-ncmp-service | |
parent | ecfff5cb108e9679ee155a45becaa36a7e9c9059 (diff) |
Handle restart case for cps-ncmp gauge metrics
Issue-ID: CPS-2456
Change-Id: I9ac5d6774fcd745d8141551eeff8a1deb1938f57
Signed-off-by: emaclee <lee.anjella.macabuhay@est.tech>
Diffstat (limited to 'cps-ncmp-service')
7 files changed, 109 insertions, 27 deletions
diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cache/AdminCacheConfig.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cache/AdminCacheConfig.java index a29799b13f..fe933d766f 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cache/AdminCacheConfig.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cache/AdminCacheConfig.java @@ -28,7 +28,7 @@ import org.springframework.context.annotation.Configuration; @Configuration public class AdminCacheConfig extends HazelcastCacheConfig { - private static final MapConfig adminCacheMapConfig = createMapConfig("adminCacheMapConfig"); + private static final MapConfig cmHandleStateCacheMapConfig = createMapConfig("cmHandleStateCacheMapConfig"); /** * Distributed instance admin cache map for cm handles by state for use of gauge metrics. @@ -37,13 +37,7 @@ public class AdminCacheConfig extends HazelcastCacheConfig { */ @Bean public IMap<String, Integer> cmHandlesByState() { - final IMap<String, Integer> cmHandlesByState = getOrCreateHazelcastInstance(adminCacheMapConfig).getMap( + return getOrCreateHazelcastInstance(cmHandleStateCacheMapConfig).getMap( "cmHandlesByState"); - cmHandlesByState.putIfAbsent("advisedCmHandlesCount", 0); - cmHandlesByState.putIfAbsent("readyCmHandlesCount", 0); - cmHandlesByState.putIfAbsent("lockedCmHandlesCount", 0); - cmHandlesByState.putIfAbsent("deletingCmHandlesCount", 0); - cmHandlesByState.putIfAbsent("deletedCmHandlesCount", 0); - return cmHandlesByState; } } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/CmHandleStateMonitor.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/CmHandleStateMonitor.java index 31270ca9fc..708508e9d8 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/CmHandleStateMonitor.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/CmHandleStateMonitor.java @@ -25,18 +25,42 @@ import com.hazelcast.map.IMap; import java.util.Collection; import java.util.Map; import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.onap.cps.ncmp.api.inventory.models.CmHandleState; import org.onap.cps.ncmp.api.inventory.models.CompositeState; +import org.onap.cps.ncmp.impl.inventory.CmHandleQueryService; import org.onap.cps.ncmp.impl.inventory.sync.lcm.LcmEventsCmHandleStateHandlerImpl.CmHandleTransitionPair; +import org.onap.cps.ncmp.utils.events.NcmpInventoryModelOnboardingFinishedEvent; +import org.springframework.context.event.EventListener; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Component; @Component @RequiredArgsConstructor +@Slf4j public class CmHandleStateMonitor { - private static final String METRIC_POSTFIX = "CmHandlesCount"; - final IMap<String, Integer> cmHandlesByState; + + private final CmHandleQueryService cmHandleQueryService; + private final IMap<String, Integer> cmHandlesByState; + + /** + * Method to initialise cm handle state monitor by querying the current state counts + * and storing them in the provided map. This method is triggered by NcmpInventoryModelOnboardingFinishedEvent. + * + * @param ncmpInventoryModelOnboardingFinishedEvent the event that triggers the initialization + */ + @EventListener + public void initialiseCmHandleStateMonitor( + final NcmpInventoryModelOnboardingFinishedEvent ncmpInventoryModelOnboardingFinishedEvent) { + for (final CmHandleState cmHandleState : CmHandleState.values()) { + final String cmHandleStateAsString = cmHandleState.name().toLowerCase(); + final String stateMetricKey = cmHandleStateAsString + METRIC_POSTFIX; + final int cmHandleCountForState = cmHandleQueryService.queryCmHandleIdsByState(cmHandleState).size(); + cmHandlesByState.putIfAbsent(stateMetricKey, cmHandleCountForState); + log.info("Cm handle state monitor has set " + stateMetricKey + " to " + cmHandleCountForState); + } + } /** * Asynchronously update the cm handle state metrics. diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/InventoryModelLoader.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/InventoryModelLoader.java index 58a5f553af..514d9b8fe4 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/InventoryModelLoader.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/init/InventoryModelLoader.java @@ -30,11 +30,15 @@ import org.onap.cps.api.CpsDataService; import org.onap.cps.api.CpsDataspaceService; import org.onap.cps.api.CpsModuleService; import org.onap.cps.init.AbstractModelLoader; +import org.onap.cps.ncmp.utils.events.NcmpInventoryModelOnboardingFinishedEvent; +import org.springframework.context.ApplicationEventPublisher; import org.springframework.stereotype.Service; @Slf4j @Service public class InventoryModelLoader extends AbstractModelLoader { + + private final ApplicationEventPublisher applicationEventPublisher; private static final String NEW_MODEL_FILE_NAME = "dmi-registry@2024-02-23.yang"; private static final String NEW_SCHEMA_SET_NAME = "dmi-registry-2024-02-23"; private static final String REGISTRY_DATANODE_NAME = "dmi-registry"; @@ -42,14 +46,17 @@ public class InventoryModelLoader extends AbstractModelLoader { public InventoryModelLoader(final CpsDataspaceService cpsDataspaceService, final CpsModuleService cpsModuleService, final CpsAnchorService cpsAnchorService, - final CpsDataService cpsDataService) { + final CpsDataService cpsDataService, + final ApplicationEventPublisher applicationEventPublisher) { super(cpsDataspaceService, cpsModuleService, cpsAnchorService, cpsDataService); + this.applicationEventPublisher = applicationEventPublisher; } @Override public void onboardOrUpgradeModel() { updateInventoryModel(); log.info("Inventory Model updated successfully"); + applicationEventPublisher.publishEvent(new NcmpInventoryModelOnboardingFinishedEvent(this)); } private void updateInventoryModel() { diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/NcmpInventoryModelOnboardingFinishedEvent.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/NcmpInventoryModelOnboardingFinishedEvent.java new file mode 100644 index 0000000000..92d5e8241d --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/utils/events/NcmpInventoryModelOnboardingFinishedEvent.java @@ -0,0 +1,39 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2025 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.utils.events; + +import org.springframework.context.ApplicationEvent; + +/** + * Custom event triggered when the NCMP inventory model onboarding process is completed. + * Extends Spring's {@link ApplicationEvent} to be used within Spring's event-driven architecture. + */ +public class NcmpInventoryModelOnboardingFinishedEvent extends ApplicationEvent { + + /** + * Creates a new instance of NcmpModelOnboardingFinishedEvent. + * + * @param source the object that is the source of the event (i.e. the source that completed the onboarding process) + */ + public NcmpInventoryModelOnboardingFinishedEvent(final Object source) { + super(source); + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cache/AdminCacheConfigSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cache/AdminCacheConfigSpec.groovy index 9b9603369d..a576865262 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cache/AdminCacheConfigSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cache/AdminCacheConfigSpec.groovy @@ -45,13 +45,5 @@ class AdminCacheConfigSpec extends Specification { assert Hazelcast.allHazelcastInstances.size() > 0 and: 'Hazelcast cache instance for cm handle by state is present' assert Hazelcast.getHazelcastInstanceByName('cps-and-ncmp-hazelcast-instance-test-config').getMap('cmHandlesByState') != null - and: 'the cache already contains 5 entries, an entry for each state' - def cmHandleByState = Hazelcast.getHazelcastInstanceByName('cps-and-ncmp-hazelcast-instance-test-config').getMap('cmHandlesByState') - assert cmHandleByState.size() == 5 - assert cmHandleByState.containsKey('advisedCmHandlesCount') - assert cmHandleByState.containsKey('lockedCmHandlesCount') - assert cmHandleByState.containsKey('readyCmHandlesCount') - assert cmHandleByState.containsKey('deletingCmHandlesCount') - assert cmHandleByState.containsKey('deletedCmHandlesCount') } } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/CmHandleStateMonitorSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/CmHandleStateMonitorSpec.groovy index 9fd40b9605..4d7c22a200 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/CmHandleStateMonitorSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/CmHandleStateMonitorSpec.groovy @@ -26,16 +26,19 @@ import static org.onap.cps.ncmp.api.inventory.models.CmHandleState.READY import com.hazelcast.core.Hazelcast import com.hazelcast.map.IMap import org.onap.cps.ncmp.api.inventory.models.CompositeState +import org.onap.cps.ncmp.impl.inventory.CmHandleQueryService import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle import org.onap.cps.ncmp.impl.inventory.sync.lcm.CmHandleStateMonitor.DecreasingEntryProcessor import org.onap.cps.ncmp.impl.inventory.sync.lcm.CmHandleStateMonitor.IncreasingEntryProcessor +import org.onap.cps.ncmp.utils.events.NcmpInventoryModelOnboardingFinishedEvent import spock.lang.Shared import spock.lang.Specification; class CmHandleStateMonitorSpec extends Specification { - def cmHandlesByState = Mock(IMap) - def objectUnderTest = new CmHandleStateMonitor(cmHandlesByState) + def mockCmHandlesByState = Mock(IMap) + def mockCmHandleQueryService = Mock(CmHandleQueryService) + def objectUnderTest = new CmHandleStateMonitor(mockCmHandleQueryService, mockCmHandlesByState) @Shared def entryProcessingMap = Hazelcast.newHazelcastInstance().getMap('entryProcessingMap') @@ -49,6 +52,25 @@ class CmHandleStateMonitorSpec extends Specification { Hazelcast.shutdownAll() } + def 'Initialise cm handle state monitor: #scenario'() { + given: 'the query service returns a list of cm-handle ids for the given state' + mockCmHandleQueryService.queryCmHandleIdsByState(_) >> queryResult + and: 'a mocked NcmpModelOnboardingFinishedEvent is triggered' + def mockNcmpModelOnboardingFinishedEvent = Mock(NcmpInventoryModelOnboardingFinishedEvent) + when: 'the method to initialise cm handle state monitor is triggered by onboarding event' + objectUnderTest.initialiseCmHandleStateMonitor(mockNcmpModelOnboardingFinishedEvent) + then: 'metrics map is called correct number of times for each state except DELETED, with expected value' + 1 * mockCmHandlesByState.putIfAbsent("advisedCmHandlesCount", expectedValue) + 1 * mockCmHandlesByState.putIfAbsent("readyCmHandlesCount", expectedValue) + 1 * mockCmHandlesByState.putIfAbsent("lockedCmHandlesCount", expectedValue) + 1 * mockCmHandlesByState.putIfAbsent("deletingCmHandlesCount", expectedValue) + where: + scenario | queryResult || expectedValue + 'query service returns zero cm handle id'| [] || 0 + 'query service returns 1 cm handle id' | ['someId'] || 1 + } + + def 'Update cm handle state metric'() { given: 'a collection of cm handle state pair' def cmHandleTransitionPair = new LcmEventsCmHandleStateHandlerImpl.CmHandleTransitionPair() @@ -57,19 +79,19 @@ class CmHandleStateMonitorSpec extends Specification { when: 'method to update cm handle state metrics is called' objectUnderTest.updateCmHandleStateMetrics([cmHandleTransitionPair]) then: 'cm handle by state cache map is called once for current and target state for entry processing' - 1 * cmHandlesByState.executeOnKey('advisedCmHandlesCount', _) - 1 * cmHandlesByState.executeOnKey('readyCmHandlesCount', _) + 1 * mockCmHandlesByState.executeOnKey('advisedCmHandlesCount', _) + 1 * mockCmHandlesByState.executeOnKey('readyCmHandlesCount', _) } - def 'Updating cm handle state metric with no previous state'() { + def 'Update cm handle state metric with no previous state'() { given: 'a collection of cm handle state pair wherein current state is null' def cmHandleTransitionPair = new LcmEventsCmHandleStateHandlerImpl.CmHandleTransitionPair() cmHandleTransitionPair.currentYangModelCmHandle = new YangModelCmHandle(compositeState: null) cmHandleTransitionPair.targetYangModelCmHandle = new YangModelCmHandle(compositeState: new CompositeState(cmHandleState: ADVISED)) - when: 'method to update cm handle state metrics is called' + when: 'updating cm handle state metrics' objectUnderTest.updateCmHandleStateMetrics([cmHandleTransitionPair]) then: 'cm handle by state cache map is called only once' - 1 * cmHandlesByState.executeOnKey(_, _) + 1 * mockCmHandlesByState.executeOnKey(_, _) } def 'Applying decreasing entry processor to a key on map where #scenario'() { diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/InventoryModelLoaderSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/InventoryModelLoaderSpec.groovy index ffd1d89fe1..dc6ec4120b 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/InventoryModelLoaderSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/init/InventoryModelLoaderSpec.groovy @@ -30,6 +30,7 @@ import org.onap.cps.api.CpsModuleService import org.onap.cps.api.model.Dataspace import org.slf4j.LoggerFactory import org.springframework.boot.context.event.ApplicationStartedEvent +import org.springframework.context.ApplicationEventPublisher import org.springframework.context.annotation.AnnotationConfigApplicationContext import spock.lang.Specification @@ -42,7 +43,8 @@ class InventoryModelLoaderSpec extends Specification { def mockCpsModuleService = Mock(CpsModuleService) def mockCpsDataService = Mock(CpsDataService) def mockCpsAnchorService = Mock(CpsAnchorService) - def objectUnderTest = new InventoryModelLoader(mockCpsAdminService, mockCpsModuleService, mockCpsAnchorService, mockCpsDataService) + def mockApplicationEventPublisher = Mock(ApplicationEventPublisher) + def objectUnderTest = new InventoryModelLoader(mockCpsAdminService, mockCpsModuleService, mockCpsAnchorService, mockCpsDataService, mockApplicationEventPublisher) def applicationContext = new AnnotationConfigApplicationContext() @@ -75,6 +77,8 @@ class InventoryModelLoaderSpec extends Specification { 1 * mockCpsAnchorService.updateAnchorSchemaSet(NCMP_DATASPACE_NAME, NCMP_DMI_REGISTRY_ANCHOR, 'dmi-registry-2024-02-23') and: 'No schema sets are being removed by the module service (yet)' 0 * mockCpsModuleService.deleteSchemaSet(NCMP_DATASPACE_NAME, _, _) + and: 'application event publisher is called once' + 1 * mockApplicationEventPublisher.publishEvent(_) } } |