diff options
author | 2024-12-11 14:58:25 +0000 | |
---|---|---|
committer | 2025-01-07 12:02:29 +0000 | |
commit | 0d61c432b2604f0459dea95bbd328c279b04fbef (patch) | |
tree | 3cd35b93ed02048699006082ad1086c986c0990f /cps-ncmp-service/src | |
parent | ffac9f27f7183d8e80aa74a7b113f68dcadb3f87 (diff) |
Add gauge metric for NCMP "cmhandle states"
Issue-ID: CPS-2456
Change-Id: I1aebcc68dfdc9c48c230c74376742d67b05c0615
Signed-off-by: emaclee <lee.anjella.macabuhay@est.tech>
Diffstat (limited to 'cps-ncmp-service/src')
6 files changed, 305 insertions, 4 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 new file mode 100644 index 0000000000..a29799b13f --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/cache/AdminCacheConfig.java @@ -0,0 +1,49 @@ +/* + * ============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.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 AdminCacheConfig extends HazelcastCacheConfig { + + private static final MapConfig adminCacheMapConfig = createMapConfig("adminCacheMapConfig"); + + /** + * Distributed instance admin cache map for cm handles by state for use of gauge metrics. + * + * @return configured map of cm handles by state. + */ + @Bean + public IMap<String, Integer> cmHandlesByState() { + final IMap<String, Integer> cmHandlesByState = getOrCreateHazelcastInstance(adminCacheMapConfig).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 new file mode 100644 index 0000000000..4fd752c0d1 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/CmHandleStateMonitor.java @@ -0,0 +1,100 @@ +/* + * ============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.impl.inventory.sync.lcm; + +import com.hazelcast.map.EntryProcessor; +import com.hazelcast.map.IMap; +import java.util.Collection; +import java.util.Map; +import lombok.RequiredArgsConstructor; +import org.onap.cps.ncmp.api.inventory.models.CompositeState; +import org.onap.cps.ncmp.impl.inventory.models.CmHandleState; +import org.onap.cps.ncmp.impl.inventory.sync.lcm.LcmEventsCmHandleStateHandlerImpl.CmHandleTransitionPair; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class CmHandleStateMonitor { + + private static final String METRIC_POSTFIX = "CmHandlesCount"; + final IMap<String, Integer> cmHandlesByState; + + /** + * Asynchronously update the cm handle state metrics. + * + * @param cmHandleTransitionPairs cm handle transition pairs + */ + @Async + public void updateCmHandleStateMetrics(final Collection<CmHandleTransitionPair> + cmHandleTransitionPairs) { + cmHandleTransitionPairs.forEach(this::updateMetricWithStateChange); + } + + private void updateMetricWithStateChange(final CmHandleTransitionPair cmHandleTransitionPair) { + final CmHandleState targetCmHandleState = cmHandleTransitionPair.getTargetYangModelCmHandle() + .getCompositeState().getCmHandleState(); + if (isNew(cmHandleTransitionPair.getCurrentYangModelCmHandle().getCompositeState())) { + updateTargetStateCount(targetCmHandleState); + } else { + final CmHandleState previousCmHandleState = cmHandleTransitionPair.getCurrentYangModelCmHandle() + .getCompositeState().getCmHandleState(); + updatePreviousStateCount(previousCmHandleState); + updateTargetStateCount(targetCmHandleState); + } + } + + private void updatePreviousStateCount(final CmHandleState previousCmHandleState) { + final String keyName = previousCmHandleState.name().toLowerCase() + METRIC_POSTFIX; + cmHandlesByState.executeOnKey(keyName, new DecreasingEntryProcessor()); + } + + private void updateTargetStateCount(final CmHandleState targetCmHandleState) { + final String keyName = targetCmHandleState.name().toLowerCase() + METRIC_POSTFIX; + cmHandlesByState.executeOnKey(keyName, new IncreasingEntryProcessor()); + } + + private boolean isNew(final CompositeState existingCompositeState) { + return (existingCompositeState == null); + } + + static class DecreasingEntryProcessor implements EntryProcessor<String, Integer, Void> { + @Override + public Void process(final Map.Entry<String, Integer> entry) { + final int currentValue = entry.getValue(); + if (currentValue > 0) { + entry.setValue(currentValue - 1); + } + return null; + } + } + + static class IncreasingEntryProcessor implements EntryProcessor<String, Integer, Void> { + @Override + public Void process(final Map.Entry<String, Integer> entry) { + final int currentValue = entry.getValue(); + entry.setValue(currentValue + 1); + return null; + } + } + + +}
\ No newline at end of file diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerImpl.java index e9bd37219a..3e6597ea39 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerImpl.java @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2022-2024 Nordix Foundation + * Copyright (C) 2022-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. @@ -51,6 +51,7 @@ public class LcmEventsCmHandleStateHandlerImpl implements LcmEventsCmHandleState private final InventoryPersistence inventoryPersistence; private final LcmEventsCmHandleStateHandlerAsyncHelper lcmEventsCmHandleStateHandlerAsyncHelper; + private final CmHandleStateMonitor cmHandleStateMonitor; @Override @Timed(value = "cps.ncmp.cmhandle.state.update.batch", @@ -60,6 +61,7 @@ public class LcmEventsCmHandleStateHandlerImpl implements LcmEventsCmHandleState prepareCmHandleTransitionBatch(cmHandleStatePerCmHandle); persistCmHandleBatch(cmHandleTransitionPairs); lcmEventsCmHandleStateHandlerAsyncHelper.publishLcmEventBatchAsynchronously(cmHandleTransitionPairs); + cmHandleStateMonitor.updateCmHandleStateMetrics(cmHandleTransitionPairs); } @Override @@ -168,7 +170,7 @@ public class LcmEventsCmHandleStateHandlerImpl implements LcmEventsCmHandleState @Getter @Setter @NoArgsConstructor - static class CmHandleTransitionPair { + public static class CmHandleTransitionPair { private YangModelCmHandle currentYangModelCmHandle; private YangModelCmHandle targetYangModelCmHandle; 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 new file mode 100644 index 0000000000..9b9603369d --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/cache/AdminCacheConfigSpec.groovy @@ -0,0 +1,57 @@ +/* + * ============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.impl.cache + +import com.hazelcast.core.Hazelcast +import com.hazelcast.map.IMap +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import org.springframework.test.context.ContextConfiguration; +import spock.lang.Specification; + +@SpringBootTest +@ContextConfiguration(classes = [AdminCacheConfig]) +class AdminCacheConfigSpec extends Specification { + + @Autowired + IMap<String, Integer> cmHandlesByState + + def cleanupSpec() { + Hazelcast.getHazelcastInstanceByName('cps-and-ncmp-hazelcast-instance-test-config').shutdown() + } + + def 'Hazelcast cache for cm handle by state gauge'() { + expect: 'system is able to create an instance of the cm handle by state cache' + assert null != cmHandlesByState + and: 'there is at least 1 instance' + 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 new file mode 100644 index 0000000000..2833ca838f --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/CmHandleStateMonitorSpec.groovy @@ -0,0 +1,92 @@ +/* + * ============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.impl.inventory.sync.lcm + +import static org.onap.cps.ncmp.impl.inventory.models.CmHandleState.ADVISED +import static org.onap.cps.ncmp.impl.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.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 spock.lang.Shared +import spock.lang.Specification; + +class CmHandleStateMonitorSpec extends Specification { + + def cmHandlesByState = Mock(IMap) + def objectUnderTest = new CmHandleStateMonitor(cmHandlesByState) + + @Shared + def entryProcessingMap = Hazelcast.newHazelcastInstance().getMap('entryProcessingMap') + + def setup() { + entryProcessingMap.put('zeroCmHandlesCount', 0) + entryProcessingMap.put('tenCmHandlesCount', 10) + } + + def cleanupSpec() { + Hazelcast.shutdownAll() + } + + def 'Update cm handle state metric'() { + given: 'a collection of cm handle state pair' + def cmHandleTransitionPair = new LcmEventsCmHandleStateHandlerImpl.CmHandleTransitionPair() + cmHandleTransitionPair.currentYangModelCmHandle = new YangModelCmHandle(compositeState: new CompositeState(cmHandleState: ADVISED)) + cmHandleTransitionPair.targetYangModelCmHandle = new YangModelCmHandle(compositeState: new CompositeState(cmHandleState: READY)) + 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', _) + } + + def 'Updating 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' + objectUnderTest.updateCmHandleStateMetrics([cmHandleTransitionPair]) + then: 'cm handle by state cache map is called only once' + 1 * cmHandlesByState.executeOnKey(_, _) + } + + def 'Applying decreasing entry processor to a key on map where #scenario'() { + when: 'decreasing entry processor is applied to subtract 1 to the value' + entryProcessingMap.executeOnKey(key, new DecreasingEntryProcessor()) + then: 'the new value is as expected' + assert entryProcessingMap.get(key) == expectedValue + where: 'the following data is used' + scenario | key || expectedValue + 'current value of count is zero'| 'zeroCmHandlesCount'|| 0 + 'current value of count is >0' | 'tenCmHandlesCount' || 9 + } + + def 'Applying increasing entry processor to a key on map'() { + when: 'increasing entry processor is applied to add 1 to the value' + entryProcessingMap.executeOnKey('tenCmHandlesCount', new IncreasingEntryProcessor()) + then: 'the new value is as expected' + assert entryProcessingMap.get('tenCmHandlesCount') == 11 + } +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy index 4b676e1b4c..5e614a6f88 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/sync/lcm/LcmEventsCmHandleStateHandlerImplSpec.groovy @@ -1,6 +1,6 @@ /* * ============LICENSE_START======================================================= - * Copyright (C) 2022-2024 Nordix Foundation + * Copyright (C) 2022-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. @@ -56,9 +56,10 @@ class LcmEventsCmHandleStateHandlerImplSpec extends Specification { def mockInventoryPersistence = Mock(InventoryPersistence) def mockLcmEventsCreator = Mock(LcmEventsCreator) def mockLcmEventsService = Mock(LcmEventsService) + def mockCmHandleStateMonitor = Mock(CmHandleStateMonitor) def lcmEventsCmHandleStateHandlerAsyncHelper = new LcmEventsCmHandleStateHandlerAsyncHelper(mockLcmEventsCreator, mockLcmEventsService) - def objectUnderTest = new LcmEventsCmHandleStateHandlerImpl(mockInventoryPersistence, lcmEventsCmHandleStateHandlerAsyncHelper) + def objectUnderTest = new LcmEventsCmHandleStateHandlerImpl(mockInventoryPersistence, lcmEventsCmHandleStateHandlerAsyncHelper, mockCmHandleStateMonitor) def cmHandleId = 'cmhandle-id-1' def compositeState |