From e18239631ff2f2f56961c8534a0edf294ee15fdd Mon Sep 17 00:00:00 2001 From: ToineSiebelink Date: Tue, 25 Jun 2024 14:40:40 +0100 Subject: Move TrustLevel Feature -Moved TrustLevel impl from Controller to Inventory Facade -Applied new package name convention using impl\inventory\trustlevel for this (sub)feature -Renamed some trustlevel related classes to better describe their role -Disabled failing architecture test (agreed this is tech. debt and created CPS-2293) -Refactored YangDataConverter method names and signatures (moved Spec to correct place) -Cleaned up names and javadoc of class now called DeviceTrustLevelMessageConsumer -Applied conventions to modified test methods Issue-ID: CPS-2255 Change-Id: Iccd20541488e6b61444bb2c7406c90e61a34124d Signed-off-by: ToineSiebelink --- .../cps/architecture/LayeredArchitectureTest.java | 4 + .../rest/controller/NetworkCmProxyController.java | 18 +-- .../rest/controller/NcmpRestInputMapperSpec.groovy | 2 +- .../controller/NetworkCmProxyControllerSpec.groovy | 32 ++--- .../embeddedcache/TrustLevelCacheConfig.java | 64 ---------- .../LcmEventsCmHandleStateHandlerAsyncHelper.java | 2 +- .../lcm/LcmEventsCmHandleStateHandlerImpl.java | 2 +- .../impl/trustlevel/DeviceHeartbeatConsumer.java | 59 --------- .../cps/ncmp/api/impl/trustlevel/TrustLevel.java | 52 -------- .../api/impl/trustlevel/TrustLevelManager.java | 136 --------------------- .../dmiavailability/DmiPluginWatchDog.java | 80 ------------ .../inventory/NetworkCmProxyInventoryFacade.java | 26 ++-- .../api/inventory/models/NcmpServiceCmHandle.java | 4 +- .../cps/ncmp/api/inventory/models/TrustLevel.java | 52 ++++++++ .../ncmp/impl/datajobs/WriteRequestExaminer.java | 2 +- .../impl/inventory/CmHandleQueryServiceImpl.java | 4 +- .../inventory/CmHandleRegistrationService.java | 6 +- ...CmHandleRegistrationServicePropertyHandler.java | 3 +- .../impl/inventory/InventoryPersistenceImpl.java | 4 +- .../ParameterizedCmHandleQueryServiceImpl.java | 6 +- .../impl/inventory/sync/ModuleOperationsUtils.java | 2 +- .../impl/inventory/sync/ModuleSyncService.java | 2 +- .../ncmp/impl/inventory/sync/ModuleSyncTasks.java | 3 +- .../DeviceTrustLevelMessageConsumer.java | 59 +++++++++ .../trustlevel/DmiPluginTrustLevelWatchDog.java | 78 ++++++++++++ .../trustlevel/TrustLevelCacheConfig.java | 64 ++++++++++ .../inventory/trustlevel/TrustLevelManager.java | 136 +++++++++++++++++++++ .../cps/ncmp/impl/utils/YangDataConverter.java | 36 +++--- .../embeddedcache/TrustLevelCacheConfigSpec.groovy | 103 ---------------- .../trustlevel/DeviceHeartbeatConsumerSpec.groovy | 63 ---------- .../impl/trustlevel/TrustLevelManagerSpec.groovy | 127 ------------------- .../ncmp/api/impl/trustlevel/TrustLevelSpec.groovy | 37 ------ .../dmiavailability/DmiPluginWatchDogSpec.groovy | 57 --------- .../api/impl/utils/YangDataConverterSpec.groovy | 59 --------- .../api/inventory/models/TrustLevelSpec.groovy | 37 ++++++ .../inventory/CmHandleQueryServiceImplSpec.groovy | 2 +- .../CmHandleRegistrationServiceSpec.groovy | 4 +- .../NetworkCmProxyInventoryFacadeSpec.groovy | 57 +++++---- .../DeviceTrustLevelMessageConsumerSpec.groovy | 64 ++++++++++ .../DmiPluginTrustLevelWatchDogSpec.groovy | 56 +++++++++ .../trustlevel/TrustLevelCacheConfigSpec.groovy | 103 ++++++++++++++++ .../trustlevel/TrustLevelManagerSpec.groovy | 128 +++++++++++++++++++ .../ncmp/impl/utils/YangDataConverterSpec.groovy | 57 +++++++++ 43 files changed, 945 insertions(+), 947 deletions(-) delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/TrustLevelCacheConfig.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/DeviceHeartbeatConsumer.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevel.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelManager.java delete mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDog.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/TrustLevel.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/DeviceTrustLevelMessageConsumer.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDog.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelCacheConfig.java create mode 100644 cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManager.java delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/TrustLevelCacheConfigSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/DeviceHeartbeatConsumerSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelManagerSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDogSpec.groovy delete mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/YangDataConverterSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/models/TrustLevelSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/DeviceTrustLevelMessageConsumerSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDogSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelCacheConfigSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManagerSpec.groovy create mode 100644 cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/YangDataConverterSpec.groovy diff --git a/cps-application/src/test/java/org/onap/cps/architecture/LayeredArchitectureTest.java b/cps-application/src/test/java/org/onap/cps/architecture/LayeredArchitectureTest.java index c18a3ed10..91452a7fc 100644 --- a/cps-application/src/test/java/org/onap/cps/architecture/LayeredArchitectureTest.java +++ b/cps-application/src/test/java/org/onap/cps/architecture/LayeredArchitectureTest.java @@ -25,6 +25,7 @@ import static com.tngtech.archunit.library.freeze.FreezingArchRule.freeze; import com.tngtech.archunit.core.importer.ImportOption; import com.tngtech.archunit.junit.AnalyzeClasses; +import com.tngtech.archunit.junit.ArchIgnore; import com.tngtech.archunit.junit.ArchTest; import com.tngtech.archunit.lang.ArchRule; @@ -47,12 +48,15 @@ public class LayeredArchitectureTest { private static final String CPS_CACHE_PACKAGE = "org.onap.cps.cache.."; private static final String CPS_EVENTS_PACKAGE = "org.onap.cps.events.."; + //TODO We need to revisit these rules, the first one doesn't even make any sense: CPS-2293 + @ArchTest static final ArchRule restControllerShouldOnlyDependOnRestController = classes().that().resideInAPackage(REST_CONTROLLER_PACKAGE).should().onlyHaveDependentClassesThat() .resideInAPackage(REST_CONTROLLER_PACKAGE); @ArchTest + @ArchIgnore static final ArchRule apiOrSpiServiceShouldOnlyBeDependedOnByControllerAndServicesAndCommonUtilityPackages = freeze(classes().that().resideInAPackage(API_SERVICE_PACKAGE) .or().resideInAPackage(SPI_SERVICE_PACKAGE).should().onlyHaveDependentClassesThat() 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 f21c6ecbd..11252b750 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 @@ -34,15 +34,12 @@ import io.micrometer.core.annotation.Timed; import java.util.ArrayList; import java.util.Collection; import java.util.List; -import java.util.Map; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.onap.cps.ncmp.api.impl.NetworkCmProxyFacade; -import org.onap.cps.ncmp.api.impl.config.embeddedcache.TrustLevelCacheConfig; import org.onap.cps.ncmp.api.impl.exception.InvalidDatastoreException; import org.onap.cps.ncmp.api.impl.operations.DatastoreType; -import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel; import org.onap.cps.ncmp.api.inventory.NetworkCmProxyInventoryFacade; import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryApiParameters; import org.onap.cps.ncmp.api.inventory.models.CompositeState; @@ -63,7 +60,6 @@ import org.onap.cps.ncmp.rest.util.DeprecationHelper; import org.onap.cps.spi.model.DataNode; import org.onap.cps.spi.model.ModuleDefinition; import org.onap.cps.utils.JsonObjectMapper; -import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.util.StringUtils; @@ -83,12 +79,8 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { private final DeprecationHelper deprecationHelper; private final NcmpRestInputMapper ncmpRestInputMapper; private final CmHandleStateMapper cmHandleStateMapper; - private final DataOperationRequestMapper dataOperationRequestMapper; - @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_CM_HANDLE) - private final Map trustLevelPerCmHandle; - /** * Get resource data from datastore. * @@ -268,9 +260,9 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { deprecationHelper.mapOldConditionProperties(cmHandleQueryParameters); final Collection cmHandles = networkCmProxyInventoryFacade .executeCmHandleSearch(cmHandleQueryApiParameters); - final List outputCmHandles = + final List restOutputCmHandles = cmHandles.stream().map(this::toRestOutputCmHandle).collect(Collectors.toList()); - return ResponseEntity.ok(outputCmHandles); + return ResponseEntity.ok(restOutputCmHandles); } /** @@ -394,18 +386,16 @@ public class NetworkCmProxyController implements NetworkCmProxyApi { return new ResponseEntity<>(HttpStatus.OK); } - private RestOutputCmHandle toRestOutputCmHandle(final NcmpServiceCmHandle ncmpServiceCmHandle) { final RestOutputCmHandle restOutputCmHandle = new RestOutputCmHandle(); final CmHandlePublicProperties cmHandlePublicProperties = new CmHandlePublicProperties(); - final TrustLevel cmHandleCurrentTrustLevel = trustLevelPerCmHandle.get(ncmpServiceCmHandle.getCmHandleId()); restOutputCmHandle.setCmHandle(ncmpServiceCmHandle.getCmHandleId()); cmHandlePublicProperties.add(ncmpServiceCmHandle.getPublicProperties()); restOutputCmHandle.setPublicCmHandleProperties(cmHandlePublicProperties); restOutputCmHandle.setState(cmHandleStateMapper.toCmHandleCompositeStateExternalLockReason( ncmpServiceCmHandle.getCompositeState())); - if (cmHandleCurrentTrustLevel != null) { - restOutputCmHandle.setTrustLevel(cmHandleCurrentTrustLevel.toString()); + if (ncmpServiceCmHandle.getCurrentTrustLevel() != null) { + restOutputCmHandle.setTrustLevel(ncmpServiceCmHandle.getCurrentTrustLevel().toString()); } restOutputCmHandle.setModuleSetTag(ncmpServiceCmHandle.getModuleSetTag()); restOutputCmHandle.setAlternateId(ncmpServiceCmHandle.getAlternateId()); diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NcmpRestInputMapperSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NcmpRestInputMapperSpec.groovy index f6b9e3591..41521f639 100644 --- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NcmpRestInputMapperSpec.groovy +++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NcmpRestInputMapperSpec.groovy @@ -21,9 +21,9 @@ package org.onap.cps.ncmp.rest.controller import org.mapstruct.factory.Mappers -import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel import org.onap.cps.ncmp.api.inventory.models.CmHandleQueryServiceParameters import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle +import org.onap.cps.ncmp.api.inventory.models.TrustLevel import org.onap.cps.ncmp.rest.model.CmHandleQueryParameters import org.onap.cps.ncmp.rest.model.ConditionProperties import org.onap.cps.ncmp.rest.model.RestDmiPluginRegistration diff --git a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy index 398d63246..65d6d8ca7 100644 --- a/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy +++ b/cps-ncmp-rest/src/test/groovy/org/onap/cps/ncmp/rest/controller/NetworkCmProxyControllerSpec.groovy @@ -33,10 +33,10 @@ import org.mapstruct.factory.Mappers import org.onap.cps.TestUtils import org.onap.cps.events.EventsPublisher import org.onap.cps.ncmp.api.impl.NetworkCmProxyFacade -import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel import org.onap.cps.ncmp.api.inventory.NetworkCmProxyInventoryFacade import org.onap.cps.ncmp.api.inventory.models.CompositeState import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle +import org.onap.cps.ncmp.api.inventory.models.TrustLevel import org.onap.cps.ncmp.api.models.CmResourceAddress import org.onap.cps.ncmp.impl.inventory.DataStoreSyncState import org.onap.cps.ncmp.impl.inventory.models.CmHandleState @@ -107,9 +107,6 @@ class NetworkCmProxyControllerSpec extends Specification { @SpringBean DataOperationRequestMapper dataOperationRequestMapper = Mappers.getMapper(DataOperationRequestMapper) - @SpringBean - Map trustLevelPerCmHandle = [:] - @SpringBean DeprecationHelper stubbedDeprecationHelper = Stub() @@ -123,7 +120,6 @@ class NetworkCmProxyControllerSpec extends Specification { @Shared def NO_TOPIC = null def NO_OPTIONS = null - def NO_REQUEST_ID = null def NO_AUTH_HEADER = null def logger = Spy(ListAppender) @@ -272,6 +268,7 @@ class NetworkCmProxyControllerSpec extends Specification { def cmHandle1 = new NcmpServiceCmHandle() cmHandle1.cmHandleId = 'ch-1' cmHandle1.publicProperties = [color: 'yellow'] + cmHandle1.currentTrustLevel = TrustLevel.NONE def cmHandle2 = new NcmpServiceCmHandle() cmHandle2.cmHandleId = 'ch-2' cmHandle2.publicProperties = [color: 'green'] @@ -279,8 +276,6 @@ class NetworkCmProxyControllerSpec extends Specification { cmHandle2.moduleSetTag = 'someModuleSetTag' cmHandle2.dataProducerIdentifier = 'someDataProducerIdentifier' mockNetworkCmProxyInventoryFacade.executeCmHandleSearch(_) >> [cmHandle1, cmHandle2] - and: 'map for trust level per cmHandle has value for only one cm handle' - trustLevelPerCmHandle.put('ch-1', TrustLevel.NONE) when: 'the searches api is invoked' def response = mvc.perform(post(searchesEndpoint).contentType(MediaType.APPLICATION_JSON).content(jsonString)).andReturn().response then: 'response status returns OK' @@ -297,11 +292,9 @@ class NetworkCmProxyControllerSpec extends Specification { def dmiProperties = [prop: 'some DMI property'] def publicProperties = ["public prop": 'some public property'] def compositeState = compositeStateTestObject() - def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, dmiProperties: dmiProperties, publicProperties: publicProperties, compositeState: compositeState) + def ncmpServiceCmHandle = new NcmpServiceCmHandle(cmHandleId: cmHandleId, dmiProperties: dmiProperties, publicProperties: publicProperties, compositeState: compositeState, currentTrustLevel: TrustLevel.COMPLETE) and: 'the service method is invoked with the cm handle id' 1 * mockNetworkCmProxyInventoryFacade.getNcmpServiceCmHandle('some-cm-handle') >> ncmpServiceCmHandle - and: 'map for trust level per cmHandle has values' - trustLevelPerCmHandle.get('some-cm-handle') >> { TrustLevel.COMPLETE } when: 'the cm handle details api is invoked' def response = mvc.perform( get(cmHandleDetailsEndpoint)).andReturn().response @@ -350,16 +343,15 @@ class NetworkCmProxyControllerSpec extends Specification { def searchesEndpoint = "$ncmpBasePathV1/ch/searches" String jsonString = TestUtils.getResourceFileContent('invalid-cmhandle-search.json') and: 'the service method is invoked with module names and returns two cm handles' - def cmHandel1 = new NcmpServiceCmHandle() - cmHandel1.cmHandleId = 'ch-1' - cmHandel1.publicProperties = [color: 'yellow'] - def cmHandel2 = new NcmpServiceCmHandle() - cmHandel2.cmHandleId = 'ch-2' - cmHandel2.publicProperties = [color: 'green'] - mockNetworkCmProxyInventoryFacade.executeCmHandleSearch(_) >> [cmHandel1, cmHandel2] - and: 'map for trust level per cmHandle has values' - trustLevelPerCmHandle.put('ch-1', TrustLevel.COMPLETE) - trustLevelPerCmHandle.put('ch-2', TrustLevel.NONE) + def cmHandle1 = new NcmpServiceCmHandle() + cmHandle1.cmHandleId = 'ch-1' + cmHandle1.publicProperties = [color: 'yellow'] + cmHandle1.currentTrustLevel = TrustLevel.COMPLETE + def cmHandle2 = new NcmpServiceCmHandle() + cmHandle2.cmHandleId = 'ch-2' + cmHandle2.publicProperties = [color: 'green'] + cmHandle2.currentTrustLevel = TrustLevel.NONE + mockNetworkCmProxyInventoryFacade.executeCmHandleSearch(_) >> [cmHandle1, cmHandle2] when: 'the searches api is invoked' def response = mvc.perform(post(searchesEndpoint).contentType(MediaType.APPLICATION_JSON).content(jsonString)).andReturn().response then: 'an empty cm handle identifier is returned' diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/TrustLevelCacheConfig.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/TrustLevelCacheConfig.java deleted file mode 100644 index 440cd3ded..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/config/embeddedcache/TrustLevelCacheConfig.java +++ /dev/null @@ -1,64 +0,0 @@ -/* - * ============LICENSE_START======================================================== - * Copyright (C) 2023-2024 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.impl.config.embeddedcache; - -import com.hazelcast.config.MapConfig; -import java.util.Map; -import org.onap.cps.cache.HazelcastCacheConfig; -import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel; -import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.Configuration; - -@Configuration -public class TrustLevelCacheConfig extends HazelcastCacheConfig { - - public static final String TRUST_LEVEL_PER_DMI_PLUGIN = "trustLevelPerDmiPlugin"; - - public static final String TRUST_LEVEL_PER_CM_HANDLE = "trustLevelPerCmHandle"; - private static final MapConfig trustLevelPerCmHandleCacheConfig = - createMapConfig("trustLevelPerCmHandleCacheConfig"); - - private static final MapConfig trustLevelPerDmiPluginCacheConfig = - createMapConfig("trustLevelPerDmiPluginCacheConfig"); - - /** - * Distributed instance of trust level cache containing the trust level per cm handle. - * - * @return configured map of cm handle name as keys to trust-level for values. - */ - @Bean(TRUST_LEVEL_PER_CM_HANDLE) - public Map trustLevelPerCmHandle() { - return createHazelcastInstance("hazelcastInstanceTrustLevelPerCmHandleMap", - trustLevelPerCmHandleCacheConfig).getMap(TRUST_LEVEL_PER_CM_HANDLE); - } - - /** - * Distributed instance of trust level cache containing the trust level per dmi plugin service(name). - * - * @return configured map of dmi-plugin name as keys to trust-level for values. - */ - @Bean(TRUST_LEVEL_PER_DMI_PLUGIN) - public Map trustLevelPerDmiPlugin() { - return createHazelcastInstance("hazelcastInstanceTrustLevelPerDmiPluginMap", - trustLevelPerDmiPluginCacheConfig).getMap(TRUST_LEVEL_PER_DMI_PLUGIN); - } - -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerAsyncHelper.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerAsyncHelper.java index b7e6a7457..af745caa4 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerAsyncHelper.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerAsyncHelper.java @@ -74,6 +74,6 @@ public class LcmEventsCmHandleStateHandlerAsyncHelper { } private static NcmpServiceCmHandle toNcmpServiceCmHandle(final YangModelCmHandle yangModelCmHandle) { - return YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle(yangModelCmHandle); + return YangDataConverter.toNcmpServiceCmHandle(yangModelCmHandle); } } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImpl.java index 97e519351..4376014f3 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/events/lcm/LcmEventsCmHandleStateHandlerImpl.java @@ -194,7 +194,7 @@ public class LcmEventsCmHandleStateHandlerImpl implements LcmEventsCmHandleState } private NcmpServiceCmHandle toNcmpServiceCmHandle(final YangModelCmHandle yangModelCmHandle) { - return YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle(yangModelCmHandle); + return YangDataConverter.toNcmpServiceCmHandle(yangModelCmHandle); } @Getter diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/DeviceHeartbeatConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/DeviceHeartbeatConsumer.java deleted file mode 100644 index 230a370d6..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/DeviceHeartbeatConsumer.java +++ /dev/null @@ -1,59 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2023 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.impl.trustlevel; - -import io.cloudevents.CloudEvent; -import io.cloudevents.kafka.impl.KafkaHeaders; -import lombok.RequiredArgsConstructor; -import org.apache.kafka.clients.consumer.ConsumerRecord; -import org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper; -import org.onap.cps.ncmp.events.trustlevel.DeviceTrustLevel; -import org.springframework.kafka.annotation.KafkaListener; -import org.springframework.stereotype.Component; - -@Component -@RequiredArgsConstructor -public class DeviceHeartbeatConsumer { - - private static final String CLOUD_EVENT_ID_HEADER_NAME = "ce_id"; - private final TrustLevelManager trustLevelManager; - - /** - * Listening the device heartbeats. - * - * @param deviceHeartbeatConsumerRecord Device Heartbeat record. - */ - @KafkaListener(topics = "${app.dmi.device-heartbeat.topic}", - containerFactory = "cloudEventConcurrentKafkaListenerContainerFactory") - public void heartbeatListener(final ConsumerRecord deviceHeartbeatConsumerRecord) { - - final String cmHandleId = KafkaHeaders.getParsedKafkaHeader(deviceHeartbeatConsumerRecord.headers(), - CLOUD_EVENT_ID_HEADER_NAME); - - final DeviceTrustLevel deviceTrustLevel = - CloudEventMapper.toTargetEvent(deviceHeartbeatConsumerRecord.value(), DeviceTrustLevel.class); - final TrustLevel newDeviceTrustLevel = TrustLevel.valueOf(deviceTrustLevel.getData().getTrustLevel()); - trustLevelManager.handleUpdateOfDeviceTrustLevel(cmHandleId, newDeviceTrustLevel); - - } - -} - diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevel.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevel.java deleted file mode 100644 index f130604a6..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevel.java +++ /dev/null @@ -1,52 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2023 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.impl.trustlevel; - -import lombok.Getter; - -@Getter -public enum TrustLevel { - NONE(0), COMPLETE(99); - private final int level; - - /** - * Creates TrustLevel enum from a numeric value. - * - * @param level numeric value between 0-99 - */ - TrustLevel(final int level) { - this.level = level; - } - - /** - * Gets the lower trust level (effective) among two. - * - * @param other the trust level compared with this - * @return the lower trust level - */ - public final TrustLevel getEffectiveTrustLevel(final TrustLevel other) { - if (other.level < this.level) { - return other; - } - return this; - } - -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelManager.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelManager.java deleted file mode 100644 index d01acb8a3..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelManager.java +++ /dev/null @@ -1,136 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2023-2024 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.impl.trustlevel; - -import java.util.Collection; -import java.util.Map; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.impl.config.embeddedcache.TrustLevelCacheConfig; -import org.onap.cps.ncmp.api.impl.events.avc.ncmptoclient.AvcEventPublisher; -import org.onap.cps.ncmp.api.impl.operations.RequiredDmiService; -import org.onap.cps.ncmp.impl.inventory.InventoryPersistence; -import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.stereotype.Service; - -@Slf4j -@Service -@RequiredArgsConstructor -public class TrustLevelManager { - - @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_CM_HANDLE) - private final Map trustLevelPerCmHandle; - - @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_DMI_PLUGIN) - private final Map trustLevelPerDmiPlugin; - - private final InventoryPersistence inventoryPersistence; - private final AvcEventPublisher avcEventPublisher; - private static final String AVC_CHANGED_ATTRIBUTE_NAME = "trustLevel"; - private static final String AVC_NO_OLD_VALUE = null; - - /** - * Add cmHandles to the cache and publish notification for initial trust level of cmHandles if it is NONE. - * - * @param cmHandlesToBeCreated a list of cmHandles being created - */ - public void handleInitialRegistrationOfTrustLevels(final Map cmHandlesToBeCreated) { - for (final Map.Entry entry : cmHandlesToBeCreated.entrySet()) { - final String cmHandleId = entry.getKey(); - if (trustLevelPerCmHandle.containsKey(cmHandleId)) { - log.warn("Cm handle: {} already registered", cmHandleId); - } else { - TrustLevel initialTrustLevel = entry.getValue(); - if (initialTrustLevel == null) { - initialTrustLevel = TrustLevel.COMPLETE; - } - trustLevelPerCmHandle.put(cmHandleId, initialTrustLevel); - if (TrustLevel.NONE.equals(initialTrustLevel)) { - avcEventPublisher.publishAvcEvent(cmHandleId, - AVC_CHANGED_ATTRIBUTE_NAME, - AVC_NO_OLD_VALUE, - initialTrustLevel.name()); - } - } - } - } - - /** - * Updates trust level of dmi plugin in the cache and publish notification for trust level of cmHandles if it - * has changed. - * - * @param dmiServiceName dmi service name - * @param affectedCmHandleIds cm handle ids belonging to dmi service name - * @param newDmiTrustLevel new trust level of the dmi plugin - */ - public void handleUpdateOfDmiTrustLevel(final String dmiServiceName, - final Collection affectedCmHandleIds, - final TrustLevel newDmiTrustLevel) { - final TrustLevel oldDmiTrustLevel = trustLevelPerDmiPlugin.get(dmiServiceName); - trustLevelPerDmiPlugin.put(dmiServiceName, newDmiTrustLevel); - for (final String affectedCmHandleId : affectedCmHandleIds) { - final TrustLevel deviceTrustLevel = trustLevelPerCmHandle.get(affectedCmHandleId); - final TrustLevel oldEffectiveTrustLevel = deviceTrustLevel.getEffectiveTrustLevel(oldDmiTrustLevel); - final TrustLevel newEffectiveTrustLevel = deviceTrustLevel.getEffectiveTrustLevel(newDmiTrustLevel); - sendAvcNotificationIfRequired(affectedCmHandleId, oldEffectiveTrustLevel, newEffectiveTrustLevel); - } - } - - /** - * Updates trust level of device in the cache and publish notification for trust level of device if it has - * changed. - * - * @param cmHandleId cm handle id - * @param newDeviceTrustLevel new trust level of the device - */ - public void handleUpdateOfDeviceTrustLevel(final String cmHandleId, - final TrustLevel newDeviceTrustLevel) { - final YangModelCmHandle yangModelCmHandle = inventoryPersistence.getYangModelCmHandle(cmHandleId); - final String dmiServiceName = yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA); - - final TrustLevel dmiTrustLevel = trustLevelPerDmiPlugin.get(dmiServiceName); - final TrustLevel oldDeviceTrustLevel = trustLevelPerCmHandle.get(cmHandleId); - - final TrustLevel oldEffectiveTrustLevel = oldDeviceTrustLevel.getEffectiveTrustLevel(dmiTrustLevel); - final TrustLevel newEffectiveTrustLevel = newDeviceTrustLevel.getEffectiveTrustLevel(dmiTrustLevel); - - trustLevelPerCmHandle.put(cmHandleId, newDeviceTrustLevel); - sendAvcNotificationIfRequired(cmHandleId, oldEffectiveTrustLevel, newEffectiveTrustLevel); - } - - private void sendAvcNotificationIfRequired(final String notificationCandidateCmHandleId, - final TrustLevel oldEffectiveTrustLevel, - final TrustLevel newEffectiveTrustLevel) { - if (oldEffectiveTrustLevel.equals(newEffectiveTrustLevel)) { - log.debug("The Cm Handle: {} has already the same trust level: {}", notificationCandidateCmHandleId, - newEffectiveTrustLevel); - } else { - log.info("The trust level for Cm Handle: {} is now: {} ", notificationCandidateCmHandleId, - newEffectiveTrustLevel); - avcEventPublisher.publishAvcEvent(notificationCandidateCmHandleId, - AVC_CHANGED_ATTRIBUTE_NAME, - oldEffectiveTrustLevel.name(), - newEffectiveTrustLevel.name()); - } - } - -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDog.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDog.java deleted file mode 100644 index c5098936c..000000000 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDog.java +++ /dev/null @@ -1,80 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2023-2024 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.impl.trustlevel.dmiavailability; - -import java.util.Collection; -import java.util.Map; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; -import org.onap.cps.ncmp.api.impl.client.DmiRestClient; -import org.onap.cps.ncmp.api.impl.config.embeddedcache.TrustLevelCacheConfig; -import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel; -import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevelManager; -import org.onap.cps.ncmp.impl.inventory.CmHandleQueryService; -import org.springframework.beans.factory.annotation.Qualifier; -import org.springframework.scheduling.annotation.Scheduled; -import org.springframework.stereotype.Service; - -@Slf4j -@RequiredArgsConstructor -@Service -public class DmiPluginWatchDog { - - private final DmiRestClient dmiRestClient; - private final CmHandleQueryService cmHandleQueryService; - private final TrustLevelManager trustLevelManager; - - @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_DMI_PLUGIN) - private final Map trustLevelPerDmiPlugin; - - /** - * This class monitors the trust level of all DMI plugin by checking the health status - * the resulting trust level wil be stored in the relevant cache. - * The @fixedDelayString is the time interval, in milliseconds, between consecutive checks. - */ - @Scheduled(fixedDelayString = "${ncmp.timers.trust-level.dmi-availability-watchdog-ms:30000}") - public void checkDmiAvailability() { - trustLevelPerDmiPlugin.entrySet().forEach(entry -> { - final TrustLevel newDmiTrustLevel; - final TrustLevel oldDmiTrustLevel = entry.getValue(); - final String dmiServiceName = entry.getKey(); - final String dmiHealthStatus = getDmiHealthStatus(dmiServiceName); - log.debug("The health status for dmi-plugin: {} is {}", dmiServiceName, dmiHealthStatus); - - if ("UP".equals(dmiHealthStatus)) { - newDmiTrustLevel = TrustLevel.COMPLETE; - } else { - newDmiTrustLevel = TrustLevel.NONE; - } - if (oldDmiTrustLevel.equals(newDmiTrustLevel)) { - log.debug("The Dmi Plugin: {} has already the same trust level: {}", dmiServiceName, newDmiTrustLevel); - } else { - final Collection cmHandleIds = - cmHandleQueryService.getCmHandleIdsByDmiPluginIdentifier(dmiServiceName); - trustLevelManager.handleUpdateOfDmiTrustLevel(dmiServiceName, cmHandleIds, newDmiTrustLevel); - } - }); - } - - private String getDmiHealthStatus(final String dmiServiceName) { - return dmiRestClient.getDmiHealthStatus(dmiServiceName); - } -} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/NetworkCmProxyInventoryFacade.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/NetworkCmProxyInventoryFacade.java index 0ff59c131..794bc238f 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/NetworkCmProxyInventoryFacade.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/NetworkCmProxyInventoryFacade.java @@ -27,8 +27,6 @@ package org.onap.cps.ncmp.api.inventory; import static org.onap.cps.ncmp.impl.inventory.CmHandleQueryParametersValidator.validateCmHandleQueryParameters; import java.util.Collection; -import java.util.HashMap; -import java.util.List; import java.util.Map; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -38,6 +36,7 @@ import org.onap.cps.ncmp.api.inventory.models.CompositeState; import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration; import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistrationResponse; import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle; +import org.onap.cps.ncmp.api.inventory.models.TrustLevel; import org.onap.cps.ncmp.impl.inventory.CmHandleQueryService; import org.onap.cps.ncmp.impl.inventory.CmHandleRegistrationService; import org.onap.cps.ncmp.impl.inventory.InventoryPersistence; @@ -45,10 +44,12 @@ import org.onap.cps.ncmp.impl.inventory.ParameterizedCmHandleQueryService; import org.onap.cps.ncmp.impl.inventory.models.CmHandleQueryConditions; import org.onap.cps.ncmp.impl.inventory.models.InventoryQueryConditions; import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; +import org.onap.cps.ncmp.impl.inventory.trustlevel.TrustLevelCacheConfig; import org.onap.cps.ncmp.impl.utils.YangDataConverter; import org.onap.cps.spi.model.ModuleDefinition; import org.onap.cps.spi.model.ModuleReference; import org.onap.cps.utils.JsonObjectMapper; +import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; @Slf4j @@ -62,6 +63,9 @@ public class NetworkCmProxyInventoryFacade { private final InventoryPersistence inventoryPersistence; private final JsonObjectMapper jsonObjectMapper; + @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_CM_HANDLE) + private final Map trustLevelPerCmHandle; + /** * Registration of Created, Removed, Updated or Upgraded CM Handles. * @@ -142,7 +146,10 @@ public class NetworkCmProxyInventoryFacade { final CmHandleQueryServiceParameters cmHandleQueryServiceParameters = jsonObjectMapper.convertToValueType( cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class); validateCmHandleQueryParameters(cmHandleQueryServiceParameters, CmHandleQueryConditions.ALL_CONDITION_NAMES); - return parameterizedCmHandleQueryService.queryCmHandles(cmHandleQueryServiceParameters); + final Collection ncmpServiceCmHandles = + parameterizedCmHandleQueryService.queryCmHandles(cmHandleQueryServiceParameters); + ncmpServiceCmHandles.forEach(this::applyCurrentTrustLevel); + return ncmpServiceCmHandles; } /** @@ -176,8 +183,10 @@ public class NetworkCmProxyInventoryFacade { * @return cm handle details */ public NcmpServiceCmHandle getNcmpServiceCmHandle(final String cmHandleId) { - return YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle( + final NcmpServiceCmHandle ncmpServiceCmHandle = YangDataConverter.toNcmpServiceCmHandle( inventoryPersistence.getYangModelCmHandle(cmHandleId)); + applyCurrentTrustLevel(ncmpServiceCmHandle); + return ncmpServiceCmHandle; } /** @@ -188,10 +197,7 @@ public class NetworkCmProxyInventoryFacade { */ public Map getCmHandlePublicProperties(final String cmHandleId) { final YangModelCmHandle yangModelCmHandle = inventoryPersistence.getYangModelCmHandle(cmHandleId); - final List yangModelPublicProperties = yangModelCmHandle.getPublicProperties(); - final Map cmHandlePublicProperties = new HashMap<>(); - YangDataConverter.asPropertiesMap(yangModelPublicProperties, cmHandlePublicProperties); - return cmHandlePublicProperties; + return YangDataConverter.toPropertiesMap(yangModelCmHandle.getPublicProperties()); } /** @@ -204,5 +210,9 @@ public class NetworkCmProxyInventoryFacade { return inventoryPersistence.getYangModelCmHandle(cmHandleId).getCompositeState(); } + private void applyCurrentTrustLevel(final NcmpServiceCmHandle ncmpServiceCmHandle) { + ncmpServiceCmHandle.setCurrentTrustLevel(trustLevelPerCmHandle.get(ncmpServiceCmHandle.getCmHandleId())); + } + } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/NcmpServiceCmHandle.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/NcmpServiceCmHandle.java index 69b33a16f..3ebceed9d 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/NcmpServiceCmHandle.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/NcmpServiceCmHandle.java @@ -27,7 +27,6 @@ import java.util.Map; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; -import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel; import org.springframework.validation.annotation.Validated; /** @@ -57,6 +56,9 @@ public class NcmpServiceCmHandle { @JsonSetter(nulls = Nulls.AS_EMPTY) private TrustLevel registrationTrustLevel; + @JsonSetter(nulls = Nulls.AS_EMPTY) + private TrustLevel currentTrustLevel; + @JsonSetter(nulls = Nulls.AS_EMPTY) private String alternateId; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/TrustLevel.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/TrustLevel.java new file mode 100644 index 000000000..83e6ecf91 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/api/inventory/models/TrustLevel.java @@ -0,0 +1,52 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 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.models; + +import lombok.Getter; + +@Getter +public enum TrustLevel { + NONE(0), COMPLETE(99); + private final int level; + + /** + * Creates TrustLevel enum from a numeric value. + * + * @param level numeric value between 0-99 + */ + TrustLevel(final int level) { + this.level = level; + } + + /** + * Gets the lower trust level (effective) among two. + * + * @param other the trust level compared with this + * @return the lower trust level + */ + public final TrustLevel getEffectiveTrustLevel(final TrustLevel other) { + if (other.level < this.level) { + return other; + } + return this; + } + +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/WriteRequestExaminer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/WriteRequestExaminer.java index 0e51f0c44..70d08dccd 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/WriteRequestExaminer.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/datajobs/WriteRequestExaminer.java @@ -99,7 +99,7 @@ public class WriteRequestExaminer { } private Map getPrivatePropertiesFromDataNode(final DataNode dataNode) { - final YangModelCmHandle yangModelCmHandle = YangDataConverter.convertCmHandleToYangModel(dataNode); + final YangModelCmHandle yangModelCmHandle = YangDataConverter.toYangModelCmHandle(dataNode); final Map cmHandleDmiProperties = new LinkedHashMap<>(); yangModelCmHandle.getDmiProperties() .forEach(dmiProperty -> cmHandleDmiProperties.put(dmiProperty.getName(), dmiProperty.getValue())); diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImpl.java index 4c2f93a95..e36477f8c 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImpl.java @@ -34,11 +34,11 @@ import java.util.List; import java.util.Map; import java.util.stream.Collectors; import lombok.RequiredArgsConstructor; -import org.onap.cps.ncmp.api.impl.config.embeddedcache.TrustLevelCacheConfig; -import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel; +import org.onap.cps.ncmp.api.inventory.models.TrustLevel; import org.onap.cps.ncmp.impl.inventory.models.CmHandleState; import org.onap.cps.ncmp.impl.inventory.models.ModelledDmiServiceLeaves; import org.onap.cps.ncmp.impl.inventory.models.PropertyType; +import org.onap.cps.ncmp.impl.inventory.trustlevel.TrustLevelCacheConfig; import org.onap.cps.spi.CpsDataPersistenceService; import org.onap.cps.spi.FetchDescendantsOption; import org.onap.cps.spi.model.DataNode; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationService.java index f10ccd4ae..1cbba7d6c 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationService.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationService.java @@ -47,10 +47,7 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.StringUtils; import org.onap.cps.api.CpsDataService; -import org.onap.cps.ncmp.api.impl.config.embeddedcache.TrustLevelCacheConfig; import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler; -import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel; -import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevelManager; import org.onap.cps.ncmp.api.impl.utils.AlternateIdChecker; import org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse; import org.onap.cps.ncmp.api.inventory.models.CompositeState; @@ -58,9 +55,12 @@ import org.onap.cps.ncmp.api.inventory.models.CompositeStateBuilder; import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration; import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistrationResponse; import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle; +import org.onap.cps.ncmp.api.inventory.models.TrustLevel; import org.onap.cps.ncmp.impl.inventory.models.CmHandleState; import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; import org.onap.cps.ncmp.impl.inventory.sync.ModuleOperationsUtils; +import org.onap.cps.ncmp.impl.inventory.trustlevel.TrustLevelCacheConfig; +import org.onap.cps.ncmp.impl.inventory.trustlevel.TrustLevelManager; import org.onap.cps.spi.exceptions.AlreadyDefinedException; import org.onap.cps.spi.exceptions.CpsException; import org.onap.cps.spi.exceptions.DataNodeNotFoundException; diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServicePropertyHandler.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServicePropertyHandler.java index 164d91725..fe47c0e2f 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServicePropertyHandler.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServicePropertyHandler.java @@ -129,8 +129,7 @@ public class CmHandleRegistrationServicePropertyHandler { final NcmpServiceCmHandle ncmpServiceCmHandle) { final String newDataProducerIdentifier = ncmpServiceCmHandle.getDataProducerIdentifier(); if (StringUtils.hasText(newDataProducerIdentifier)) { - final YangModelCmHandle yangModelCmHandle = - YangDataConverter.convertCmHandleToYangModel(cmHandleDataNode); + final YangModelCmHandle yangModelCmHandle = YangDataConverter.toYangModelCmHandle(cmHandleDataNode); final String existingDataProducerIdentifier = yangModelCmHandle.getDataProducerIdentifier(); if (StringUtils.hasText(existingDataProducerIdentifier)) { if (!existingDataProducerIdentifier.equals(newDataProducerIdentifier)) { diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImpl.java index 40aefed2a..2930d4f87 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/InventoryPersistenceImpl.java @@ -112,7 +112,7 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv public YangModelCmHandle getYangModelCmHandle(final String cmHandleId) { cpsValidator.validateNameCharacters(cmHandleId); final DataNode dataNode = getCmHandleDataNodeByCmHandleId(cmHandleId).iterator().next(); - return YangDataConverter.convertCmHandleToYangModel(dataNode); + return YangDataConverter.toYangModelCmHandle(dataNode); } @Override @@ -127,7 +127,7 @@ public class InventoryPersistenceImpl extends NcmpPersistenceImpl implements Inv dataValidationException.getMessage()); } }); - return YangDataConverter.convertDataNodesToYangModelCmHandles(getCmHandleDataNodes(validCmHandleIds)); + return YangDataConverter.toYangModelCmHandles(getCmHandleDataNodes(validCmHandleIds)); } @Override diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryServiceImpl.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryServiceImpl.java index 51e403fd6..45922454f 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryServiceImpl.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/ParameterizedCmHandleQueryServiceImpl.java @@ -27,7 +27,7 @@ import static org.onap.cps.ncmp.impl.inventory.models.CmHandleQueryConditions.HA import static org.onap.cps.ncmp.impl.inventory.models.CmHandleQueryConditions.HAS_ALL_PROPERTIES; import static org.onap.cps.ncmp.impl.inventory.models.CmHandleQueryConditions.WITH_CPS_PATH; import static org.onap.cps.ncmp.impl.inventory.models.CmHandleQueryConditions.WITH_TRUST_LEVEL; -import static org.onap.cps.ncmp.impl.utils.YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle; +import static org.onap.cps.ncmp.impl.utils.YangDataConverter.toNcmpServiceCmHandle; import static org.onap.cps.spi.FetchDescendantsOption.DIRECT_CHILDREN_ONLY; import static org.onap.cps.spi.FetchDescendantsOption.OMIT_DESCENDANTS; @@ -232,13 +232,13 @@ public class ParameterizedCmHandleQueryServiceImpl implements ParameterizedCmHan final Collection ncmpServiceCmHandles = new ArrayList<>(yangModelcmHandles.size()); yangModelcmHandles.forEach(yangModelcmHandle -> - ncmpServiceCmHandles.add(YangDataConverter.convertYangModelCmHandleToNcmpServiceCmHandle(yangModelcmHandle)) + ncmpServiceCmHandles.add(YangDataConverter.toNcmpServiceCmHandle(yangModelcmHandle)) ); return ncmpServiceCmHandles; } private NcmpServiceCmHandle createNcmpServiceCmHandle(final DataNode dataNode) { - return convertYangModelCmHandleToNcmpServiceCmHandle(YangDataConverter.convertCmHandleToYangModel(dataNode)); + return toNcmpServiceCmHandle(YangDataConverter.toYangModelCmHandle(dataNode)); } private Collection executeQueries(final CmHandleQueryServiceParameters cmHandleQueryServiceParameters, diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleOperationsUtils.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleOperationsUtils.java index 15e4653c9..e344be8e1 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleOperationsUtils.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleOperationsUtils.java @@ -238,7 +238,7 @@ public class ModuleOperationsUtils { private List convertCmHandlesDataNodesToYangModelCmHandles( final List cmHandlesAsDataNodeList) { - return cmHandlesAsDataNodeList.stream().map(YangDataConverter::convertCmHandleToYangModel).toList(); + return cmHandlesAsDataNodeList.stream().map(YangDataConverter::toYangModelCmHandle).toList(); } private boolean isRetryDue(final CompositeState.LockReason compositeStateLockReason, final OffsetDateTime time) { diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncService.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncService.java index 2c8639a4d..57d28aa74 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncService.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncService.java @@ -139,7 +139,7 @@ public class ModuleSyncService { final List dataNodes = cmHandleQueryService.queryNcmpRegistryByCpsPath( NCMP_DMI_REGISTRY_PARENT + "/cm-handles[@module-set-tag='" + escapedModuleSetTag + "']", FetchDescendantsOption.DIRECT_CHILDREN_ONLY); - return dataNodes.stream().map(YangDataConverter::convertCmHandleToYangModel) + return dataNodes.stream().map(YangDataConverter::toYangModelCmHandle) .filter(cmHandle -> cmHandle.getCompositeState().getCmHandleState() == CmHandleState.READY) .findFirst().orElse(null); } diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasks.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasks.java index 80c290cb5..08db195ad 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasks.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/sync/ModuleSyncTasks.java @@ -64,8 +64,7 @@ public class ModuleSyncTasks { = new HashMap<>(cmHandlesAsDataNodes.size()); for (final DataNode cmHandleAsDataNode : cmHandlesAsDataNodes) { final String cmHandleId = String.valueOf(cmHandleAsDataNode.getLeaves().get("id")); - final YangModelCmHandle yangModelCmHandle = - YangDataConverter.convertCmHandleToYangModel(cmHandleAsDataNode); + final YangModelCmHandle yangModelCmHandle = YangDataConverter.toYangModelCmHandle(cmHandleAsDataNode); final CompositeState compositeState = inventoryPersistence.getCmHandleState(cmHandleId); final boolean inUpgrade = ModuleOperationsUtils.inUpgradeOrUpgradeFailed(compositeState); try { diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/DeviceTrustLevelMessageConsumer.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/DeviceTrustLevelMessageConsumer.java new file mode 100644 index 000000000..64ae80087 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/DeviceTrustLevelMessageConsumer.java @@ -0,0 +1,59 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 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.trustlevel; + +import io.cloudevents.CloudEvent; +import io.cloudevents.kafka.impl.KafkaHeaders; +import lombok.RequiredArgsConstructor; +import org.apache.kafka.clients.consumer.ConsumerRecord; +import org.onap.cps.ncmp.api.impl.events.mapper.CloudEventMapper; +import org.onap.cps.ncmp.api.inventory.models.TrustLevel; +import org.onap.cps.ncmp.events.trustlevel.DeviceTrustLevel; +import org.springframework.kafka.annotation.KafkaListener; +import org.springframework.stereotype.Component; + +@Component +@RequiredArgsConstructor +public class DeviceTrustLevelMessageConsumer { + + private static final String CLOUD_EVENT_ID_HEADER_NAME = "ce_id"; + private final TrustLevelManager trustLevelManager; + + /** + * Listening to the device trust level updates. + * + * @param consumerRecord Device trust level record. + */ + @KafkaListener(topics = "${app.dmi.device-heartbeat.topic}", + containerFactory = "cloudEventConcurrentKafkaListenerContainerFactory") + public void deviceTrustLevelListener(final ConsumerRecord consumerRecord) { + + final String cmHandleId = KafkaHeaders.getParsedKafkaHeader(consumerRecord.headers(), + CLOUD_EVENT_ID_HEADER_NAME); + + final DeviceTrustLevel deviceTrustLevel = + CloudEventMapper.toTargetEvent(consumerRecord.value(), DeviceTrustLevel.class); + final String trustLevelAsString = deviceTrustLevel.getData().getTrustLevel(); + trustLevelManager.handleUpdateOfDeviceTrustLevel(cmHandleId, TrustLevel.valueOf(trustLevelAsString)); + } + +} + diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDog.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDog.java new file mode 100644 index 000000000..19597a205 --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDog.java @@ -0,0 +1,78 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023-2024 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.trustlevel; + +import java.util.Collection; +import java.util.Map; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.api.impl.client.DmiRestClient; +import org.onap.cps.ncmp.api.inventory.models.TrustLevel; +import org.onap.cps.ncmp.impl.inventory.CmHandleQueryService; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Service; + +@Slf4j +@RequiredArgsConstructor +@Service +public class DmiPluginTrustLevelWatchDog { + + private final DmiRestClient dmiRestClient; + private final CmHandleQueryService cmHandleQueryService; + private final TrustLevelManager trustLevelManager; + + @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_DMI_PLUGIN) + private final Map trustLevelPerDmiPlugin; + + /** + * This class monitors the trust level of all DMI plugin by checking the health status + * the resulting trust level wil be stored in the relevant cache. + * The @fixedDelayString is the time interval, in milliseconds, between consecutive checks. + */ + @Scheduled(fixedDelayString = "${ncmp.timers.trust-level.dmi-availability-watchdog-ms:30000}") + public void checkDmiAvailability() { + trustLevelPerDmiPlugin.entrySet().forEach(entry -> { + final TrustLevel newDmiTrustLevel; + final TrustLevel oldDmiTrustLevel = entry.getValue(); + final String dmiServiceName = entry.getKey(); + final String dmiHealthStatus = getDmiHealthStatus(dmiServiceName); + log.debug("The health status for dmi-plugin: {} is {}", dmiServiceName, dmiHealthStatus); + + if ("UP".equals(dmiHealthStatus)) { + newDmiTrustLevel = TrustLevel.COMPLETE; + } else { + newDmiTrustLevel = TrustLevel.NONE; + } + if (oldDmiTrustLevel.equals(newDmiTrustLevel)) { + log.debug("The Dmi Plugin: {} has already the same trust level: {}", dmiServiceName, newDmiTrustLevel); + } else { + final Collection cmHandleIds = + cmHandleQueryService.getCmHandleIdsByDmiPluginIdentifier(dmiServiceName); + trustLevelManager.handleUpdateOfDmiTrustLevel(dmiServiceName, cmHandleIds, newDmiTrustLevel); + } + }); + } + + private String getDmiHealthStatus(final String dmiServiceName) { + return dmiRestClient.getDmiHealthStatus(dmiServiceName); + } +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelCacheConfig.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelCacheConfig.java new file mode 100644 index 000000000..b64d3a24b --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelCacheConfig.java @@ -0,0 +1,64 @@ +/* + * ============LICENSE_START======================================================== + * Copyright (C) 2023-2024 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.trustlevel; + +import com.hazelcast.config.MapConfig; +import java.util.Map; +import org.onap.cps.cache.HazelcastCacheConfig; +import org.onap.cps.ncmp.api.inventory.models.TrustLevel; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +@Configuration +public class TrustLevelCacheConfig extends HazelcastCacheConfig { + + public static final String TRUST_LEVEL_PER_DMI_PLUGIN = "trustLevelPerDmiPlugin"; + + public static final String TRUST_LEVEL_PER_CM_HANDLE = "trustLevelPerCmHandle"; + private static final MapConfig trustLevelPerCmHandleCacheConfig = + createMapConfig("trustLevelPerCmHandleCacheConfig"); + + private static final MapConfig trustLevelPerDmiPluginCacheConfig = + createMapConfig("trustLevelPerDmiPluginCacheConfig"); + + /** + * Distributed instance of trust level cache containing the trust level per cm handle. + * + * @return configured map of cm handle name as keys to trust-level for values. + */ + @Bean(TRUST_LEVEL_PER_CM_HANDLE) + public Map trustLevelPerCmHandle() { + return createHazelcastInstance("hazelcastInstanceTrustLevelPerCmHandleMap", + trustLevelPerCmHandleCacheConfig).getMap(TRUST_LEVEL_PER_CM_HANDLE); + } + + /** + * Distributed instance of trust level cache containing the trust level per dmi plugin service(name). + * + * @return configured map of dmi-plugin name as keys to trust-level for values. + */ + @Bean(TRUST_LEVEL_PER_DMI_PLUGIN) + public Map trustLevelPerDmiPlugin() { + return createHazelcastInstance("hazelcastInstanceTrustLevelPerDmiPluginMap", + trustLevelPerDmiPluginCacheConfig).getMap(TRUST_LEVEL_PER_DMI_PLUGIN); + } + +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManager.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManager.java new file mode 100644 index 000000000..c7bfb1dbb --- /dev/null +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManager.java @@ -0,0 +1,136 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023-2024 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.trustlevel; + +import java.util.Collection; +import java.util.Map; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.onap.cps.ncmp.api.impl.events.avc.ncmptoclient.AvcEventPublisher; +import org.onap.cps.ncmp.api.impl.operations.RequiredDmiService; +import org.onap.cps.ncmp.api.inventory.models.TrustLevel; +import org.onap.cps.ncmp.impl.inventory.InventoryPersistence; +import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.stereotype.Service; + +@Slf4j +@Service +@RequiredArgsConstructor +public class TrustLevelManager { + + @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_CM_HANDLE) + private final Map trustLevelPerCmHandle; + + @Qualifier(TrustLevelCacheConfig.TRUST_LEVEL_PER_DMI_PLUGIN) + private final Map trustLevelPerDmiPlugin; + + private final InventoryPersistence inventoryPersistence; + private final AvcEventPublisher avcEventPublisher; + private static final String AVC_CHANGED_ATTRIBUTE_NAME = "trustLevel"; + private static final String AVC_NO_OLD_VALUE = null; + + /** + * Add cmHandles to the cache and publish notification for initial trust level of cmHandles if it is NONE. + * + * @param cmHandlesToBeCreated a list of cmHandles being created + */ + public void handleInitialRegistrationOfTrustLevels(final Map cmHandlesToBeCreated) { + for (final Map.Entry entry : cmHandlesToBeCreated.entrySet()) { + final String cmHandleId = entry.getKey(); + if (trustLevelPerCmHandle.containsKey(cmHandleId)) { + log.warn("Cm handle: {} already registered", cmHandleId); + } else { + TrustLevel initialTrustLevel = entry.getValue(); + if (initialTrustLevel == null) { + initialTrustLevel = TrustLevel.COMPLETE; + } + trustLevelPerCmHandle.put(cmHandleId, initialTrustLevel); + if (TrustLevel.NONE.equals(initialTrustLevel)) { + avcEventPublisher.publishAvcEvent(cmHandleId, + AVC_CHANGED_ATTRIBUTE_NAME, + AVC_NO_OLD_VALUE, + initialTrustLevel.name()); + } + } + } + } + + /** + * Updates trust level of dmi plugin in the cache and publish notification for trust level of cmHandles if it + * has changed. + * + * @param dmiServiceName dmi service name + * @param affectedCmHandleIds cm handle ids belonging to dmi service name + * @param newDmiTrustLevel new trust level of the dmi plugin + */ + public void handleUpdateOfDmiTrustLevel(final String dmiServiceName, + final Collection affectedCmHandleIds, + final TrustLevel newDmiTrustLevel) { + final TrustLevel oldDmiTrustLevel = trustLevelPerDmiPlugin.get(dmiServiceName); + trustLevelPerDmiPlugin.put(dmiServiceName, newDmiTrustLevel); + for (final String affectedCmHandleId : affectedCmHandleIds) { + final TrustLevel deviceTrustLevel = trustLevelPerCmHandle.get(affectedCmHandleId); + final TrustLevel oldEffectiveTrustLevel = deviceTrustLevel.getEffectiveTrustLevel(oldDmiTrustLevel); + final TrustLevel newEffectiveTrustLevel = deviceTrustLevel.getEffectiveTrustLevel(newDmiTrustLevel); + sendAvcNotificationIfRequired(affectedCmHandleId, oldEffectiveTrustLevel, newEffectiveTrustLevel); + } + } + + /** + * Updates trust level of device in the cache and publish notification for trust level of device if it has + * changed. + * + * @param cmHandleId cm handle id + * @param newDeviceTrustLevel new trust level of the device + */ + public void handleUpdateOfDeviceTrustLevel(final String cmHandleId, + final TrustLevel newDeviceTrustLevel) { + final YangModelCmHandle yangModelCmHandle = inventoryPersistence.getYangModelCmHandle(cmHandleId); + final String dmiServiceName = yangModelCmHandle.resolveDmiServiceName(RequiredDmiService.DATA); + + final TrustLevel dmiTrustLevel = trustLevelPerDmiPlugin.get(dmiServiceName); + final TrustLevel oldDeviceTrustLevel = trustLevelPerCmHandle.get(cmHandleId); + + final TrustLevel oldEffectiveTrustLevel = oldDeviceTrustLevel.getEffectiveTrustLevel(dmiTrustLevel); + final TrustLevel newEffectiveTrustLevel = newDeviceTrustLevel.getEffectiveTrustLevel(dmiTrustLevel); + + trustLevelPerCmHandle.put(cmHandleId, newDeviceTrustLevel); + sendAvcNotificationIfRequired(cmHandleId, oldEffectiveTrustLevel, newEffectiveTrustLevel); + } + + private void sendAvcNotificationIfRequired(final String notificationCandidateCmHandleId, + final TrustLevel oldEffectiveTrustLevel, + final TrustLevel newEffectiveTrustLevel) { + if (oldEffectiveTrustLevel.equals(newEffectiveTrustLevel)) { + log.debug("The Cm Handle: {} has already the same trust level: {}", notificationCandidateCmHandleId, + newEffectiveTrustLevel); + } else { + log.info("The trust level for Cm Handle: {} is now: {} ", notificationCandidateCmHandleId, + newEffectiveTrustLevel); + avcEventPublisher.publishAvcEvent(notificationCandidateCmHandleId, + AVC_CHANGED_ATTRIBUTE_NAME, + oldEffectiveTrustLevel.name(), + newEffectiveTrustLevel.name()); + } + } + +} diff --git a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/YangDataConverter.java b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/YangDataConverter.java index bde13684a..ac0c44e1c 100644 --- a/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/YangDataConverter.java +++ b/cps-ncmp-service/src/main/java/org/onap/cps/ncmp/impl/utils/YangDataConverter.java @@ -43,12 +43,12 @@ public class YangDataConverter { private static final Pattern cmHandleIdInXpathPattern = Pattern.compile("\\[@id='(.*?)']"); /** - * This method convert yang model cm handle to ncmp service cm handle. + * This method converts yang model cm handle to ncmp service cm handle. * @param yangModelCmHandle the yang model of the cm handle * @return ncmp service cm handle */ - public static NcmpServiceCmHandle convertYangModelCmHandleToNcmpServiceCmHandle( - final YangModelCmHandle yangModelCmHandle) { + public static NcmpServiceCmHandle toNcmpServiceCmHandle( + final YangModelCmHandle yangModelCmHandle) { final NcmpServiceCmHandle ncmpServiceCmHandle = new NcmpServiceCmHandle(); final List dmiProperties = yangModelCmHandle.getDmiProperties(); final List publicProperties = yangModelCmHandle.getPublicProperties(); @@ -63,23 +63,24 @@ public class YangDataConverter { } /** - * This method convert yang model cm handle properties to simple map. + * This method converts yang model cm handle properties to simple map. * @param properties the yang model cm handle properties - * @param propertiesMap the String, String map for the results + * @return simple map representing the properties */ - public static void asPropertiesMap(final List properties, - final Map propertiesMap) { + public static Map toPropertiesMap(final List properties) { + final Map propertiesMap = new LinkedHashMap<>(properties.size()); for (final YangModelCmHandle.Property property : properties) { propertiesMap.put(property.getName(), property.getValue()); } + return propertiesMap; } /** - * This method convert cm handle data node to yang model cm handle. + * This method converts cm handle data node to yang model cm handle. * @param cmHandleDataNode the datanode of the cm handle * @return yang model cm handle */ - public static YangModelCmHandle convertCmHandleToYangModel(final DataNode cmHandleDataNode) { + public static YangModelCmHandle toYangModelCmHandle(final DataNode cmHandleDataNode) { final NcmpServiceCmHandle ncmpServiceCmHandle = new NcmpServiceCmHandle(); final String cmHandleId = cmHandleDataNode.getLeaves().get("id").toString(); ncmpServiceCmHandle.setCmHandleId(cmHandleId); @@ -96,18 +97,17 @@ public class YangDataConverter { } /** - * This method convert cm handle data nodes to yang model cm handles. + * This method converts cm handle data nodes to yang model cm handles. * @param cmHandleDataNodes the datanode of the cm handle * @return yang model cm handles */ - public static Collection convertDataNodesToYangModelCmHandles( + public static Collection toYangModelCmHandles( final Collection cmHandleDataNodes) { - return cmHandleDataNodes.stream().map(YangDataConverter::convertCmHandleToYangModel) - .collect(Collectors.toList()); + return cmHandleDataNodes.stream().map(YangDataConverter::toYangModelCmHandle).collect(Collectors.toList()); } /** - * This method extract cm handle id from xpath of data node. + * This method extracts cm handle id from xpath of data node. * @param xpath for data node of the cm handle * @return cm handle Id */ @@ -145,15 +145,11 @@ public class YangDataConverter { private static void setDmiProperties(final List dmiProperties, final NcmpServiceCmHandle ncmpServiceCmHandle) { - final Map dmiPropertiesMap = new LinkedHashMap<>(dmiProperties.size()); - asPropertiesMap(dmiProperties, dmiPropertiesMap); - ncmpServiceCmHandle.setDmiProperties(dmiPropertiesMap); + ncmpServiceCmHandle.setDmiProperties(toPropertiesMap(dmiProperties)); } private static void setPublicProperties(final List publicProperties, final NcmpServiceCmHandle ncmpServiceCmHandle) { - final Map publicPropertiesMap = new LinkedHashMap<>(); - asPropertiesMap(publicProperties, publicPropertiesMap); - ncmpServiceCmHandle.setPublicProperties(publicPropertiesMap); + ncmpServiceCmHandle.setPublicProperties(toPropertiesMap(publicProperties)); } } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/TrustLevelCacheConfigSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/TrustLevelCacheConfigSpec.groovy deleted file mode 100644 index c213ab626..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/config/embeddedcache/TrustLevelCacheConfigSpec.groovy +++ /dev/null @@ -1,103 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2023 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.impl.config.embeddedcache - -import com.hazelcast.config.Config -import com.hazelcast.core.Hazelcast -import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel -import org.springframework.beans.factory.annotation.Autowired -import org.springframework.boot.test.context.SpringBootTest -import spock.lang.Specification - -@SpringBootTest(classes = [TrustLevelCacheConfig]) -class TrustLevelCacheConfigSpec extends Specification { - - @Autowired - private Map trustLevelPerDmiPlugin - - @Autowired - private Map trustLevelPerCmHandle - - def 'Hazelcast cache for trust level per dmi plugin'() { - expect: 'system is able to create an instance of the trust level per dmi plugin cache' - assert null != trustLevelPerDmiPlugin - and: 'there is at least 1 instance' - assert Hazelcast.allHazelcastInstances.size() > 0 - and: 'Dmi Plugin Trust Level Cache is present' - assert Hazelcast.allHazelcastInstances.name.contains('hazelcastInstanceTrustLevelPerDmiPluginMap') - } - - def 'Hazelcast cache for trust level per cm handle'() { - expect: 'system is able to create an instance of the trust level per cm handle cache' - assert null != trustLevelPerCmHandle - and: 'there is at least 1 instance' - assert Hazelcast.allHazelcastInstances.size() > 0 - and: 'Hazelcast cache instance for trust level is present' - assert Hazelcast.allHazelcastInstances.name.contains('hazelcastInstanceTrustLevelPerCmHandleMap') - } - - def 'Trust level cache configurations: #scenario'() { - when: 'retrieving the cache config for trustLevel' - def cacheConfig = Hazelcast.getHazelcastInstanceByName(hazelcastInstanceName).config - then: 'the cache config has the right cluster' - assert cacheConfig.clusterName == 'cps-and-ncmp-test-caches' - when: 'retrieving the map config for trustLevel' - def mapConfig = cacheConfig.mapConfigs.get(hazelcastMapConfigName) - then: 'the map config has the correct backup counts' - assert mapConfig.backupCount == 1 - assert mapConfig.asyncBackupCount == 0 - where: 'the following caches are used' - scenario | hazelcastInstanceName | hazelcastMapConfigName - 'cmhandle map' | 'hazelcastInstanceTrustLevelPerCmHandleMap' | 'trustLevelPerCmHandleCacheConfig' - 'dmi plugin map' | 'hazelcastInstanceTrustLevelPerDmiPluginMap' | 'trustLevelPerDmiPluginCacheConfig' - } - - def 'Verify deployment network configs for Distributed Caches'() { - given: 'the Trust Level Per Dmi Plugin Cache config' - def trustLevelDmiPerPluginCacheConfig = Hazelcast.getHazelcastInstanceByName('hazelcastInstanceTrustLevelPerDmiPluginMap').config.networkConfig - expect: 'system created instance with correct config' - assert trustLevelDmiPerPluginCacheConfig.join.autoDetectionConfig.enabled - assert !trustLevelDmiPerPluginCacheConfig.join.kubernetesConfig.enabled - } - - def 'Verify deployment network configs for Cm Handle Distributed Caches'() { - given: 'the Trust Level Per Cm Handle Cache config' - def trustLevelPerCmHandlePluginCacheConfig = Hazelcast.getHazelcastInstanceByName('hazelcastInstanceTrustLevelPerCmHandleMap').config.networkConfig - expect: 'system created instance with correct config' - assert trustLevelPerCmHandlePluginCacheConfig.join.autoDetectionConfig.enabled - assert !trustLevelPerCmHandlePluginCacheConfig.join.kubernetesConfig.enabled - } - - def 'Verify network config'() { - given: 'Synchronization config object and test configuration' - def objectUnderTest = new TrustLevelCacheConfig() - def testConfig = new Config() - when: 'kubernetes properties are enabled' - objectUnderTest.cacheKubernetesEnabled = true - objectUnderTest.cacheKubernetesServiceName = 'test-service-name' - and: 'method called to update the discovery mode' - objectUnderTest.updateDiscoveryMode(testConfig) - then: 'applied properties are reflected' - assert testConfig.networkConfig.join.kubernetesConfig.enabled - assert testConfig.networkConfig.join.kubernetesConfig.properties.get('service-name') == 'test-service-name' - } - -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/DeviceHeartbeatConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/DeviceHeartbeatConsumerSpec.groovy deleted file mode 100644 index 42a1c5d5a..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/DeviceHeartbeatConsumerSpec.groovy +++ /dev/null @@ -1,63 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2023 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.impl.trustlevel - -import com.fasterxml.jackson.databind.ObjectMapper -import io.cloudevents.CloudEvent -import io.cloudevents.core.builder.CloudEventBuilder -import org.apache.kafka.clients.consumer.ConsumerRecord -import org.onap.cps.ncmp.events.trustlevel.DeviceTrustLevel -import org.onap.cps.utils.JsonObjectMapper -import org.springframework.boot.test.context.SpringBootTest -import spock.lang.Specification - -@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper]) -class DeviceHeartbeatConsumerSpec extends Specification { - - def mockTrustLevelManager = Mock(TrustLevelManager) - - def objectUnderTest = new DeviceHeartbeatConsumer(mockTrustLevelManager) - def objectMapper = new ObjectMapper() - def jsonObjectMapper = new JsonObjectMapper(objectMapper) - - def 'Consume a trust level event'() { - given: 'an event from dmi with trust level complete' - def payload = jsonObjectMapper.convertJsonString('{"data":{"trustLevel": "COMPLETE"}}', DeviceTrustLevel.class) - def eventFromDmi = createTrustLevelEvent(payload) - and: 'transformed to a consumer record with a cloud event id (ce_id)' - def consumerRecord = new ConsumerRecord('test-device-heartbeat', 0, 0, 'sample-message-key', eventFromDmi) - consumerRecord.headers().add('ce_id', objectMapper.writeValueAsBytes('ch-1')) - when: 'the event is consumed' - objectUnderTest.heartbeatListener(consumerRecord) - then: 'cm handles are stored with correct trust level' - 1 * mockTrustLevelManager.handleUpdateOfDeviceTrustLevel('"ch-1"', TrustLevel.COMPLETE) - } - - def createTrustLevelEvent(eventPayload) { - return CloudEventBuilder.v1().withData(objectMapper.writeValueAsBytes(eventPayload)) - .withId('ch-1') - .withSource(URI.create('DMI')) - .withDataSchema(URI.create('test')) - .withType('org.onap.cps.ncmp.events.trustlevel.DeviceTrustLevel') - .build() - } - -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelManagerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelManagerSpec.groovy deleted file mode 100644 index 65ab7a7fd..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelManagerSpec.groovy +++ /dev/null @@ -1,127 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2023 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.impl.trustlevel - -import org.onap.cps.ncmp.api.impl.events.avc.ncmptoclient.AvcEventPublisher -import org.onap.cps.ncmp.impl.inventory.InventoryPersistence -import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle -import spock.lang.Specification - -class TrustLevelManagerSpec extends Specification { - - def trustLevelPerCmHandle = [:] - def trustLevelPerDmiPlugin = [:] - - def mockInventoryPersistence = Mock(InventoryPersistence) - def mockAttributeValueChangeEventPublisher = Mock(AvcEventPublisher) - def objectUnderTest = new TrustLevelManager(trustLevelPerCmHandle, trustLevelPerDmiPlugin, mockInventoryPersistence, mockAttributeValueChangeEventPublisher) - - def 'Initial cm handle registration'() { - given: 'two cm handles: one with no trust level and one trusted' - def cmHandleModelsToBeCreated = ['ch-1': null, 'ch-2': TrustLevel.COMPLETE] - when: 'the initial registration handled' - objectUnderTest.handleInitialRegistrationOfTrustLevels(cmHandleModelsToBeCreated) - then: 'no notification sent' - 0 * mockAttributeValueChangeEventPublisher.publishAvcEvent(*_) - and: 'both cm handles are in the cache and are trusted' - assert trustLevelPerCmHandle.get('ch-1') == TrustLevel.COMPLETE - assert trustLevelPerCmHandle.get('ch-2') == TrustLevel.COMPLETE - } - - def 'Initial cm handle registration with a cm handle that is not trusted'() { - given: 'a not trusted cm handle' - def cmHandleModelsToBeCreated = ['ch-2': TrustLevel.NONE] - when: 'the initial registration handled' - objectUnderTest.handleInitialRegistrationOfTrustLevels(cmHandleModelsToBeCreated) - then: 'notification is sent' - 1 * mockAttributeValueChangeEventPublisher.publishAvcEvent(*_) - } - - def 'Dmi trust level updated'() { - given: 'a trusted dmi plugin' - trustLevelPerDmiPlugin.put('my-dmi', TrustLevel.COMPLETE) - and: 'a trusted cm handle' - trustLevelPerCmHandle.put('ch-1', TrustLevel.COMPLETE) - when: 'the update is handled' - objectUnderTest.handleUpdateOfDmiTrustLevel('my-dmi', ['ch-1'], TrustLevel.NONE) - then: 'notification is sent' - 1 * mockAttributeValueChangeEventPublisher.publishAvcEvent('ch-1', 'trustLevel', 'COMPLETE', 'NONE') - and: 'the dmi in the cache is not trusted' - assert trustLevelPerDmiPlugin.get('my-dmi') == TrustLevel.NONE - } - - def 'Dmi trust level updated with same value'() { - given: 'a trusted dmi plugin' - trustLevelPerDmiPlugin.put('my-dmi', TrustLevel.COMPLETE) - and: 'a trusted cm handle' - trustLevelPerCmHandle.put('ch-1', TrustLevel.COMPLETE) - when: 'the update is handled' - objectUnderTest.handleUpdateOfDmiTrustLevel('my-dmi', ['ch-1'], TrustLevel.COMPLETE) - then: 'no notification is sent' - 0 * mockAttributeValueChangeEventPublisher.publishAvcEvent(*_) - and: 'the dmi in the cache is trusted' - assert trustLevelPerDmiPlugin.get('my-dmi') == TrustLevel.COMPLETE - } - - def 'Device trust level updated'() { - given: 'a non trusted cm handle' - trustLevelPerCmHandle.put('ch-1', TrustLevel.NONE) - and: 'a trusted dmi plugin' - trustLevelPerDmiPlugin.put('my-dmi', TrustLevel.COMPLETE) - and: 'inventory persistence service returns yang model cm handle' - mockInventoryPersistence.getYangModelCmHandle('ch-1') >> new YangModelCmHandle(id: 'ch-1', dmiDataServiceName: 'my-dmi') - when: 'update of device to COMPLETE trust level handled' - objectUnderTest.handleUpdateOfDeviceTrustLevel('ch-1', TrustLevel.COMPLETE) - then: 'the cm handle in the cache is trusted' - assert trustLevelPerCmHandle.get('ch-1', TrustLevel.COMPLETE) - and: 'notification is sent' - 1 * mockAttributeValueChangeEventPublisher.publishAvcEvent('ch-1', 'trustLevel', 'NONE', 'COMPLETE') - } - - def 'Device trust level updated with same value'() { - given: 'a non trusted cm handle' - trustLevelPerCmHandle.put('ch-1', TrustLevel.NONE) - and: 'a trusted dmi plugin' - trustLevelPerDmiPlugin.put('my-dmi', TrustLevel.COMPLETE) - and: 'inventory persistence service returns yang model cm handle' - mockInventoryPersistence.getYangModelCmHandle('ch-1') >> new YangModelCmHandle(id: 'ch-1', dmiDataServiceName: 'my-dmi') - when: 'update of device trust to the same level (NONE)' - objectUnderTest.handleUpdateOfDeviceTrustLevel('ch-1', TrustLevel.NONE) - then: 'the cm handle in the cache is not trusted' - assert trustLevelPerCmHandle.get('ch-1', TrustLevel.NONE) - and: 'no notification is sent' - 0 * mockAttributeValueChangeEventPublisher.publishAvcEvent(*_) - } - - def 'Dmi trust level restored to complete with non trusted device'() { - given: 'a non trusted dmi' - trustLevelPerDmiPlugin.put('my-dmi', TrustLevel.NONE) - and: 'a non trusted device' - trustLevelPerCmHandle.put('ch-1', TrustLevel.NONE) - when: 'restore the dmi trust level to COMPLETE' - objectUnderTest.handleUpdateOfDmiTrustLevel('my-dmi', ['ch-1'], TrustLevel.COMPLETE) - then: 'the cm handle in the cache is still NONE' - assert trustLevelPerCmHandle.get('ch-1') == TrustLevel.NONE - and: 'no notification is sent' - 0 * mockAttributeValueChangeEventPublisher.publishAvcEvent(*_) - } - -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelSpec.groovy deleted file mode 100644 index f2521b560..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/TrustLevelSpec.groovy +++ /dev/null @@ -1,37 +0,0 @@ -/* - * ============LICENSE_START======================================================== - * Copyright (c) 2023 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.impl.trustlevel - -import spock.lang.Specification - -class TrustLevelSpec extends Specification { - - def 'Get effective trust level between this and other.'() { - expect: 'the lower of two is returned' - assert effectiveLevel == current.getEffectiveTrustLevel(other) - where: 'the following trust level is used' - current | other || effectiveLevel - TrustLevel.COMPLETE | TrustLevel.NONE || TrustLevel.NONE - TrustLevel.NONE | TrustLevel.COMPLETE || TrustLevel.NONE - TrustLevel.COMPLETE | TrustLevel.COMPLETE || TrustLevel.COMPLETE - } - -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDogSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDogSpec.groovy deleted file mode 100644 index f5835ff85..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/trustlevel/dmiavailability/DmiPluginWatchDogSpec.groovy +++ /dev/null @@ -1,57 +0,0 @@ -/* - * ============LICENSE_START======================================================= - * Copyright (C) 2023 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.impl.trustlevel.dmiavailability - -import org.onap.cps.ncmp.api.impl.client.DmiRestClient -import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel -import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevelManager -import org.onap.cps.ncmp.impl.inventory.CmHandleQueryService -import spock.lang.Specification - -class DmiPluginWatchDogSpec extends Specification { - - def mockDmiRestClient = Mock(DmiRestClient) - def mockCmHandleQueryService = Mock(CmHandleQueryService) - def mockTrustLevelManager = Mock(TrustLevelManager) - def trustLevelPerDmiPlugin = [:] - - - def objectUnderTest = new DmiPluginWatchDog(mockDmiRestClient, mockCmHandleQueryService, mockTrustLevelManager, trustLevelPerDmiPlugin) - - def 'watch dmi plugin health status for #dmiHealhStatus'() { - given: 'the cache has been initialised and "knows" about dmi-1' - trustLevelPerDmiPlugin.put('dmi-1', dmiOldTrustLevel) - and: 'dmi client returns health status #dmiHealhStatus' - mockDmiRestClient.getDmiHealthStatus('dmi-1') >> dmiHealhStatus - when: 'dmi watch dog method runs' - objectUnderTest.checkDmiAvailability() - then: 'the update delegated to manager' - numberOfCalls * mockTrustLevelManager.handleUpdateOfDmiTrustLevel('dmi-1', _, newDmiTrustLevel) - where: 'the following parameters are used' - dmiHealhStatus | dmiOldTrustLevel | newDmiTrustLevel || numberOfCalls - 'UP' | TrustLevel.COMPLETE | TrustLevel.COMPLETE || 0 - 'DOWN' | TrustLevel.COMPLETE | TrustLevel.NONE || 1 - 'DOWN' | TrustLevel.NONE | TrustLevel.NONE || 0 - 'UP' | TrustLevel.NONE | TrustLevel.COMPLETE || 1 - '' | TrustLevel.COMPLETE | TrustLevel.NONE || 1 - } - -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/YangDataConverterSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/YangDataConverterSpec.groovy deleted file mode 100644 index 3f0d98934..000000000 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/impl/utils/YangDataConverterSpec.groovy +++ /dev/null @@ -1,59 +0,0 @@ -/* - * ============LICENSE_START======================================================== - * Copyright (C) 2022-2024 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.impl.utils - -import org.onap.cps.ncmp.impl.utils.YangDataConverter -import org.onap.cps.spi.model.DataNode -import spock.lang.Specification - -class YangDataConverterSpec extends Specification{ - - def 'Convert a cm handle data node with private and public properties.'() { - given: 'a datanode with some additional (dmi, private) and public properties' - def dataNodeAdditionalProperties = new DataNode(xpath:'/additional-properties[@name="dmiProp1"]', - leaves: ['name': 'dmiProp1', 'value': 'dmiValue1']) - def dataNodePublicProperties = new DataNode(xpath:'/public-properties[@name="pubProp1"]', - leaves: ['name': 'pubProp1', 'value': 'pubValue1']) - def dataNodeCmHandle = new DataNode(leaves:['id':'sample-id'], childDataNodes:[dataNodeAdditionalProperties, dataNodePublicProperties]) - when: 'the dataNode is converted' - def yangModelCmHandle = - YangDataConverter.convertCmHandleToYangModel(dataNodeCmHandle) - then: 'the converted object has the correct id' - assert yangModelCmHandle.id == 'sample-id' - and: 'the additional (dmi, private) properties are included' - assert yangModelCmHandle.dmiProperties[0].name == 'dmiProp1' - assert yangModelCmHandle.dmiProperties[0].value == 'dmiValue1' - and: 'the public properties are included' - assert yangModelCmHandle.publicProperties[0].name == 'pubProp1' - assert yangModelCmHandle.publicProperties[0].value == 'pubValue1' - } - - def 'Convert multiple cm handle data nodes'(){ - given: 'two data nodes in a collection' - def dataNodes = [new DataNode(xpath:'/dmi-registry/cm-handles[@id=\'some-cm-handle\']', leaves: ['id':'some-cm-handle']), - new DataNode(xpath:'/dmi-registry/cm-handles[@id=\'another-cm-handle\']', leaves: ['id':'another-cm-handle'])] - when: 'the data nodes are converted' - def yangModelCmHandles = YangDataConverter.convertDataNodesToYangModelCmHandles(dataNodes) - then: 'verify both have returned and CmHandleIds are correct' - assert yangModelCmHandles.size() == 2 - assert yangModelCmHandles.id.containsAll(['some-cm-handle', 'another-cm-handle']) - } -} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/models/TrustLevelSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/models/TrustLevelSpec.groovy new file mode 100644 index 000000000..1e1dfaaa9 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/api/inventory/models/TrustLevelSpec.groovy @@ -0,0 +1,37 @@ +/* + * ============LICENSE_START======================================================== + * Copyright (c) 2023 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.models + +import spock.lang.Specification + +class TrustLevelSpec extends Specification { + + def 'Get effective trust level between this and other.'() { + expect: 'the lower of two is returned' + assert effectiveLevel == current.getEffectiveTrustLevel(other) + where: 'the following trust level is used' + current | other || effectiveLevel + TrustLevel.COMPLETE | TrustLevel.NONE || TrustLevel.NONE + TrustLevel.NONE | TrustLevel.COMPLETE || TrustLevel.NONE + TrustLevel.COMPLETE | TrustLevel.COMPLETE || TrustLevel.COMPLETE + } + +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImplSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImplSpec.groovy index 52ddcfb6c..36fd75577 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImplSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleQueryServiceImplSpec.groovy @@ -21,7 +21,7 @@ package org.onap.cps.ncmp.impl.inventory -import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel +import org.onap.cps.ncmp.api.inventory.models.TrustLevel import org.onap.cps.ncmp.impl.inventory.models.CmHandleState import org.onap.cps.spi.CpsDataPersistenceService import org.onap.cps.spi.model.DataNode diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServiceSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServiceSpec.groovy index da3116283..9d4d9565e 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServiceSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/CmHandleRegistrationServiceSpec.groovy @@ -26,16 +26,16 @@ import org.onap.cps.api.CpsDataService import org.onap.cps.api.CpsModuleService import org.onap.cps.ncmp.api.impl.events.lcm.LcmEventsCmHandleStateHandler import org.onap.cps.ncmp.api.impl.exception.DmiRequestException -import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevel -import org.onap.cps.ncmp.api.impl.trustlevel.TrustLevelManager import org.onap.cps.ncmp.api.impl.utils.AlternateIdChecker import org.onap.cps.ncmp.api.inventory.models.CmHandleRegistrationResponse import org.onap.cps.ncmp.api.inventory.models.CompositeState import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle +import org.onap.cps.ncmp.api.inventory.models.TrustLevel import org.onap.cps.ncmp.api.inventory.models.UpgradedCmHandles import org.onap.cps.ncmp.impl.inventory.models.CmHandleState import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle +import org.onap.cps.ncmp.impl.inventory.trustlevel.TrustLevelManager import org.onap.cps.spi.exceptions.AlreadyDefinedException import org.onap.cps.spi.exceptions.CpsException import org.onap.cps.spi.exceptions.DataNodeNotFoundException diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/NetworkCmProxyInventoryFacadeSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/NetworkCmProxyInventoryFacadeSpec.groovy index 49d4c39a1..716efd8fd 100644 --- a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/NetworkCmProxyInventoryFacadeSpec.groovy +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/NetworkCmProxyInventoryFacadeSpec.groovy @@ -31,6 +31,7 @@ import org.onap.cps.ncmp.api.inventory.models.CompositeState import org.onap.cps.ncmp.api.inventory.models.ConditionApiProperties import org.onap.cps.ncmp.api.inventory.models.DmiPluginRegistration import org.onap.cps.ncmp.api.inventory.models.NcmpServiceCmHandle +import org.onap.cps.ncmp.api.inventory.models.TrustLevel import org.onap.cps.ncmp.impl.inventory.models.CmHandleState import org.onap.cps.ncmp.impl.inventory.models.LockReasonCategory import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle @@ -38,8 +39,6 @@ import org.onap.cps.spi.model.ConditionProperties import org.onap.cps.utils.JsonObjectMapper import spock.lang.Specification -import java.util.stream.Collectors - class NetworkCmProxyInventoryFacadeSpec extends Specification { def mockCmHandleRegistrationService = Mock(CmHandleRegistrationService) @@ -47,8 +46,9 @@ class NetworkCmProxyInventoryFacadeSpec extends Specification { def mockParameterizedCmHandleQueryService = Mock(ParameterizedCmHandleQueryService) def spiedJsonObjectMapper = Spy(new JsonObjectMapper(new ObjectMapper())) def mockInventoryPersistence = Mock(InventoryPersistence) + def trustLevelPerCmHandle = [:] - def objectUnderTest = new NetworkCmProxyInventoryFacade(mockCmHandleRegistrationService, mockCmHandleQueryService, mockParameterizedCmHandleQueryService, mockInventoryPersistence, spiedJsonObjectMapper) + def objectUnderTest = new NetworkCmProxyInventoryFacade(mockCmHandleRegistrationService, mockCmHandleQueryService, mockParameterizedCmHandleQueryService, mockInventoryPersistence, spiedJsonObjectMapper, trustLevelPerCmHandle) def 'Update DMI Registration'() { given: 'an (updated) dmi plugin registration' @@ -98,7 +98,7 @@ class NetworkCmProxyInventoryFacadeSpec extends Specification { given: 'the system returns a yang modelled cm handle' def dmiServiceName = 'some service name' def compositeState = new CompositeState(cmHandleState: CmHandleState.ADVISED, - lockReason: CompositeState.LockReason.builder().lockReasonCategory(LockReasonCategory.MODULE_SYNC_FAILED).details("lock details").build(), + lockReason: CompositeState.LockReason.builder().lockReasonCategory(LockReasonCategory.MODULE_SYNC_FAILED).details('lock details').build(), lastUpdateTime: 'some-timestamp', dataSyncEnabled: false, dataStores: dataStores()) @@ -106,26 +106,29 @@ class NetworkCmProxyInventoryFacadeSpec extends Specification { def publicProperties = [new YangModelCmHandle.Property('Public Book', 'Public Romance Novel')] def moduleSetTag = 'some-module-set-tag' def alternateId = 'some-alternate-id' - def yangModelCmHandle = new YangModelCmHandle(id: 'some-cm-handle', dmiServiceName: dmiServiceName, - dmiProperties: dmiProperties, publicProperties: publicProperties, compositeState: compositeState, - moduleSetTag: moduleSetTag, alternateId: alternateId) - 1 * mockInventoryPersistence.getYangModelCmHandle('some-cm-handle') >> yangModelCmHandle + def yangModelCmHandle = new YangModelCmHandle(id: 'ch-1', dmiServiceName: dmiServiceName, dmiProperties: dmiProperties, + publicProperties: publicProperties, compositeState: compositeState, moduleSetTag: moduleSetTag, alternateId: alternateId) + 1 * mockInventoryPersistence.getYangModelCmHandle('ch-1') >> yangModelCmHandle + and: 'a trust level for the cm handle in the cache' + trustLevelPerCmHandle.put('ch-1', TrustLevel.COMPLETE) when: 'getting cm handle details for a given cm handle id from ncmp service' - def result = objectUnderTest.getNcmpServiceCmHandle('some-cm-handle') + def result = objectUnderTest.getNcmpServiceCmHandle('ch-1') then: 'the result is a ncmpServiceCmHandle' - result.class == NcmpServiceCmHandle.class + assert result.class == NcmpServiceCmHandle.class and: 'the cm handle contains the cm handle id' - result.cmHandleId == 'some-cm-handle' + assert result.cmHandleId == 'ch-1' and: 'the cm handle contains the alternate id' - result.alternateId == 'some-alternate-id' + assert result.alternateId == 'some-alternate-id' and: 'the cm handle contains the module-set-tag' - result.moduleSetTag == 'some-module-set-tag' + assert result.moduleSetTag == 'some-module-set-tag' and: 'the cm handle contains the DMI Properties' - result.dmiProperties ==[ Book:'Romance Novel' ] + assert result.dmiProperties ==[ Book:'Romance Novel' ] and: 'the cm handle contains the public Properties' - result.publicProperties == [ "Public Book":'Public Romance Novel' ] + assert result.publicProperties == [ "Public Book":'Public Romance Novel' ] and: 'the cm handle contains the cm handle composite state' - result.compositeState == compositeState + assert result.compositeState == compositeState + and: 'the cm handle contains the trust level from the cache' + assert result.currentTrustLevel == TrustLevel.COMPLETE } def 'Get cm handle public properties'() { @@ -138,7 +141,7 @@ class NetworkCmProxyInventoryFacadeSpec extends Specification { when: 'getting cm handle public properties for a given cm handle id from ncmp service' def result = objectUnderTest.getCmHandlePublicProperties('some-cm-handle') then: 'the result returns the correct data' - result == [ 'public prop' : 'some public prop' ] + assert result == [ 'public prop' : 'some public prop' ] } def 'Get cm handle composite state'() { @@ -156,7 +159,7 @@ class NetworkCmProxyInventoryFacadeSpec extends Specification { when: 'getting cm handle composite state for a given cm handle id from ncmp service' def result = objectUnderTest.getCmHandleCompositeState('some-cm-handle') then: 'the result returns the correct data' - result == compositeState + assert result == compositeState } def 'Execute cm handle id search'() { @@ -197,14 +200,21 @@ class NetworkCmProxyInventoryFacadeSpec extends Specification { conditionApiProperties.conditionName = 'hasAllModules' conditionApiProperties.conditionParameters = [[moduleName: 'module-name-1']] cmHandleQueryApiParameters.cmHandleQueryParameters = [conditionApiProperties] - and: 'query cm handle method return with a data node list' + and: 'query cm handle method returns two cm handles' mockParameterizedCmHandleQueryService.queryCmHandles( spiedJsonObjectMapper.convertToValueType(cmHandleQueryApiParameters, CmHandleQueryServiceParameters.class)) - >> [new NcmpServiceCmHandle(cmHandleId: 'cm-handle-id-1')] + >> [new NcmpServiceCmHandle(cmHandleId: 'ch-0'), new NcmpServiceCmHandle(cmHandleId: 'ch-1')] + and: ' a trust level for ch-1' + trustLevelPerCmHandle.put('ch-1', TrustLevel.COMPLETE) when: 'execute cm handle search is called' def result = objectUnderTest.executeCmHandleSearch(cmHandleQueryApiParameters) - then: 'result is the same collection as returned by the CPS Data Service' - assert result.stream().map(cmHandle -> cmHandle.cmHandleId).collect(Collectors.toSet()) == ['cm-handle-id-1'] as Set + then: 'result consists of the two cm handles returned by the CPS Data Service' + assert result.size() == 2 + assert result[0].cmHandleId == 'ch-0' + assert result[1].cmHandleId == 'ch-1' + and: 'only ch-1 has a trust level' + assert result[0].currentTrustLevel == null + assert result[1].currentTrustLevel == TrustLevel.COMPLETE } def 'Set Cm Handle Data Sync flag.'() { @@ -215,8 +225,7 @@ class NetworkCmProxyInventoryFacadeSpec extends Specification { } def dataStores() { - CompositeState.DataStores.builder() - .operationalDataStore(CompositeState.Operational.builder() + CompositeState.DataStores.builder().operationalDataStore(CompositeState.Operational.builder() .dataStoreSyncState(DataStoreSyncState.NONE_REQUESTED) .lastSyncTime('some-timestamp').build()).build() } diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/DeviceTrustLevelMessageConsumerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/DeviceTrustLevelMessageConsumerSpec.groovy new file mode 100644 index 000000000..6db304acd --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/DeviceTrustLevelMessageConsumerSpec.groovy @@ -0,0 +1,64 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 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.trustlevel + +import com.fasterxml.jackson.databind.ObjectMapper +import io.cloudevents.CloudEvent +import io.cloudevents.core.builder.CloudEventBuilder +import org.apache.kafka.clients.consumer.ConsumerRecord +import org.onap.cps.ncmp.api.inventory.models.TrustLevel +import org.onap.cps.ncmp.events.trustlevel.DeviceTrustLevel +import org.onap.cps.utils.JsonObjectMapper +import org.springframework.boot.test.context.SpringBootTest +import spock.lang.Specification + +@SpringBootTest(classes = [ObjectMapper, JsonObjectMapper]) +class DeviceTrustLevelMessageConsumerSpec extends Specification { + + def mockTrustLevelManager = Mock(TrustLevelManager) + + def objectUnderTest = new DeviceTrustLevelMessageConsumer(mockTrustLevelManager) + def objectMapper = new ObjectMapper() + def jsonObjectMapper = new JsonObjectMapper(objectMapper) + + def 'Consume a trust level event'() { + given: 'an event from dmi with trust level complete' + def payload = jsonObjectMapper.convertJsonString('{"data":{"trustLevel": "COMPLETE"}}', DeviceTrustLevel.class) + def eventFromDmi = createTrustLevelEvent(payload) + and: 'transformed to a consumer record with a cloud event id (ce_id)' + def consumerRecord = new ConsumerRecord('test-device-heartbeat', 0, 0, 'sample-message-key', eventFromDmi) + consumerRecord.headers().add('ce_id', objectMapper.writeValueAsBytes('ch-1')) + when: 'the event is consumed' + objectUnderTest.deviceTrustLevelListener(consumerRecord) + then: 'cm handles are stored with correct trust level' + 1 * mockTrustLevelManager.handleUpdateOfDeviceTrustLevel('"ch-1"', TrustLevel.COMPLETE) + } + + def createTrustLevelEvent(eventPayload) { + return CloudEventBuilder.v1().withData(objectMapper.writeValueAsBytes(eventPayload)) + .withId('ch-1') + .withSource(URI.create('DMI')) + .withDataSchema(URI.create('test')) + .withType('org.onap.cps.ncmp.events.trustlevel.DeviceTrustLevel') + .build() + } + +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDogSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDogSpec.groovy new file mode 100644 index 000000000..7fa8b2cce --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/DmiPluginTrustLevelWatchDogSpec.groovy @@ -0,0 +1,56 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 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.trustlevel + +import org.onap.cps.ncmp.api.impl.client.DmiRestClient +import org.onap.cps.ncmp.api.inventory.models.TrustLevel +import org.onap.cps.ncmp.impl.inventory.CmHandleQueryService +import spock.lang.Specification + +class DmiPluginTrustLevelWatchDogSpec extends Specification { + + def mockDmiRestClient = Mock(DmiRestClient) + def mockCmHandleQueryService = Mock(CmHandleQueryService) + def mockTrustLevelManager = Mock(TrustLevelManager) + def trustLevelPerDmiPlugin = [:] + + + def objectUnderTest = new DmiPluginTrustLevelWatchDog(mockDmiRestClient, mockCmHandleQueryService, mockTrustLevelManager, trustLevelPerDmiPlugin) + + def 'watch dmi plugin health status for #dmiHealhStatus'() { + given: 'the cache has been initialised and "knows" about dmi-1' + trustLevelPerDmiPlugin.put('dmi-1', dmiOldTrustLevel) + and: 'dmi client returns health status #dmiHealhStatus' + mockDmiRestClient.getDmiHealthStatus('dmi-1') >> dmiHealhStatus + when: 'dmi watch dog method runs' + objectUnderTest.checkDmiAvailability() + then: 'the update delegated to manager' + numberOfCalls * mockTrustLevelManager.handleUpdateOfDmiTrustLevel('dmi-1', _, newDmiTrustLevel) + where: 'the following parameters are used' + dmiHealhStatus | dmiOldTrustLevel | newDmiTrustLevel || numberOfCalls + 'UP' | TrustLevel.COMPLETE | TrustLevel.COMPLETE || 0 + 'DOWN' | TrustLevel.COMPLETE | TrustLevel.NONE || 1 + 'DOWN' | TrustLevel.NONE | TrustLevel.NONE || 0 + 'UP' | TrustLevel.NONE | TrustLevel.COMPLETE || 1 + '' | TrustLevel.COMPLETE | TrustLevel.NONE || 1 + } + +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelCacheConfigSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelCacheConfigSpec.groovy new file mode 100644 index 000000000..e79a47101 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelCacheConfigSpec.groovy @@ -0,0 +1,103 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 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.trustlevel + +import com.hazelcast.config.Config +import com.hazelcast.core.Hazelcast +import org.onap.cps.ncmp.api.inventory.models.TrustLevel +import org.springframework.beans.factory.annotation.Autowired +import org.springframework.boot.test.context.SpringBootTest +import spock.lang.Specification + +@SpringBootTest(classes = [TrustLevelCacheConfig]) +class TrustLevelCacheConfigSpec extends Specification { + + @Autowired + private Map trustLevelPerDmiPlugin + + @Autowired + private Map trustLevelPerCmHandle + + def 'Hazelcast cache for trust level per dmi plugin'() { + expect: 'system is able to create an instance of the trust level per dmi plugin cache' + assert null != trustLevelPerDmiPlugin + and: 'there is at least 1 instance' + assert Hazelcast.allHazelcastInstances.size() > 0 + and: 'Dmi Plugin Trust Level Cache is present' + assert Hazelcast.allHazelcastInstances.name.contains('hazelcastInstanceTrustLevelPerDmiPluginMap') + } + + def 'Hazelcast cache for trust level per cm handle'() { + expect: 'system is able to create an instance of the trust level per cm handle cache' + assert null != trustLevelPerCmHandle + and: 'there is at least 1 instance' + assert Hazelcast.allHazelcastInstances.size() > 0 + and: 'Hazelcast cache instance for trust level is present' + assert Hazelcast.allHazelcastInstances.name.contains('hazelcastInstanceTrustLevelPerCmHandleMap') + } + + def 'Trust level cache configurations: #scenario'() { + when: 'retrieving the cache config for trustLevel' + def cacheConfig = Hazelcast.getHazelcastInstanceByName(hazelcastInstanceName).config + then: 'the cache config has the right cluster' + assert cacheConfig.clusterName == 'cps-and-ncmp-test-caches' + when: 'retrieving the map config for trustLevel' + def mapConfig = cacheConfig.mapConfigs.get(hazelcastMapConfigName) + then: 'the map config has the correct backup counts' + assert mapConfig.backupCount == 1 + assert mapConfig.asyncBackupCount == 0 + where: 'the following caches are used' + scenario | hazelcastInstanceName | hazelcastMapConfigName + 'cmhandle map' | 'hazelcastInstanceTrustLevelPerCmHandleMap' | 'trustLevelPerCmHandleCacheConfig' + 'dmi plugin map' | 'hazelcastInstanceTrustLevelPerDmiPluginMap' | 'trustLevelPerDmiPluginCacheConfig' + } + + def 'Verify deployment network configs for Distributed Caches'() { + given: 'the Trust Level Per Dmi Plugin Cache config' + def trustLevelDmiPerPluginCacheConfig = Hazelcast.getHazelcastInstanceByName('hazelcastInstanceTrustLevelPerDmiPluginMap').config.networkConfig + expect: 'system created instance with correct config' + assert trustLevelDmiPerPluginCacheConfig.join.autoDetectionConfig.enabled + assert !trustLevelDmiPerPluginCacheConfig.join.kubernetesConfig.enabled + } + + def 'Verify deployment network configs for Cm Handle Distributed Caches'() { + given: 'the Trust Level Per Cm Handle Cache config' + def trustLevelPerCmHandlePluginCacheConfig = Hazelcast.getHazelcastInstanceByName('hazelcastInstanceTrustLevelPerCmHandleMap').config.networkConfig + expect: 'system created instance with correct config' + assert trustLevelPerCmHandlePluginCacheConfig.join.autoDetectionConfig.enabled + assert !trustLevelPerCmHandlePluginCacheConfig.join.kubernetesConfig.enabled + } + + def 'Verify network config'() { + given: 'Synchronization config object and test configuration' + def objectUnderTest = new TrustLevelCacheConfig() + def testConfig = new Config() + when: 'kubernetes properties are enabled' + objectUnderTest.cacheKubernetesEnabled = true + objectUnderTest.cacheKubernetesServiceName = 'test-service-name' + and: 'method called to update the discovery mode' + objectUnderTest.updateDiscoveryMode(testConfig) + then: 'applied properties are reflected' + assert testConfig.networkConfig.join.kubernetesConfig.enabled + assert testConfig.networkConfig.join.kubernetesConfig.properties.get('service-name') == 'test-service-name' + } + +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManagerSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManagerSpec.groovy new file mode 100644 index 000000000..4c22dbaed --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/inventory/trustlevel/TrustLevelManagerSpec.groovy @@ -0,0 +1,128 @@ +/* + * ============LICENSE_START======================================================= + * Copyright (C) 2023 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.trustlevel + +import org.onap.cps.ncmp.api.impl.events.avc.ncmptoclient.AvcEventPublisher +import org.onap.cps.ncmp.api.inventory.models.TrustLevel +import org.onap.cps.ncmp.impl.inventory.InventoryPersistence +import org.onap.cps.ncmp.impl.inventory.models.YangModelCmHandle +import spock.lang.Specification + +class TrustLevelManagerSpec extends Specification { + + def trustLevelPerCmHandle = [:] + def trustLevelPerDmiPlugin = [:] + + def mockInventoryPersistence = Mock(InventoryPersistence) + def mockAttributeValueChangeEventPublisher = Mock(AvcEventPublisher) + def objectUnderTest = new TrustLevelManager(trustLevelPerCmHandle, trustLevelPerDmiPlugin, mockInventoryPersistence, mockAttributeValueChangeEventPublisher) + + def 'Initial cm handle registration'() { + given: 'two cm handles: one with no trust level and one trusted' + def cmHandleModelsToBeCreated = ['ch-1': null, 'ch-2': TrustLevel.COMPLETE] + when: 'the initial registration handled' + objectUnderTest.handleInitialRegistrationOfTrustLevels(cmHandleModelsToBeCreated) + then: 'no notification sent' + 0 * mockAttributeValueChangeEventPublisher.publishAvcEvent(*_) + and: 'both cm handles are in the cache and are trusted' + assert trustLevelPerCmHandle.get('ch-1') == TrustLevel.COMPLETE + assert trustLevelPerCmHandle.get('ch-2') == TrustLevel.COMPLETE + } + + def 'Initial cm handle registration with a cm handle that is not trusted'() { + given: 'a not trusted cm handle' + def cmHandleModelsToBeCreated = ['ch-2': TrustLevel.NONE] + when: 'the initial registration handled' + objectUnderTest.handleInitialRegistrationOfTrustLevels(cmHandleModelsToBeCreated) + then: 'notification is sent' + 1 * mockAttributeValueChangeEventPublisher.publishAvcEvent(*_) + } + + def 'Dmi trust level updated'() { + given: 'a trusted dmi plugin' + trustLevelPerDmiPlugin.put('my-dmi', TrustLevel.COMPLETE) + and: 'a trusted cm handle' + trustLevelPerCmHandle.put('ch-1', TrustLevel.COMPLETE) + when: 'the update is handled' + objectUnderTest.handleUpdateOfDmiTrustLevel('my-dmi', ['ch-1'], TrustLevel.NONE) + then: 'notification is sent' + 1 * mockAttributeValueChangeEventPublisher.publishAvcEvent('ch-1', 'trustLevel', 'COMPLETE', 'NONE') + and: 'the dmi in the cache is not trusted' + assert trustLevelPerDmiPlugin.get('my-dmi') == TrustLevel.NONE + } + + def 'Dmi trust level updated with same value'() { + given: 'a trusted dmi plugin' + trustLevelPerDmiPlugin.put('my-dmi', TrustLevel.COMPLETE) + and: 'a trusted cm handle' + trustLevelPerCmHandle.put('ch-1', TrustLevel.COMPLETE) + when: 'the update is handled' + objectUnderTest.handleUpdateOfDmiTrustLevel('my-dmi', ['ch-1'], TrustLevel.COMPLETE) + then: 'no notification is sent' + 0 * mockAttributeValueChangeEventPublisher.publishAvcEvent(*_) + and: 'the dmi in the cache is trusted' + assert trustLevelPerDmiPlugin.get('my-dmi') == TrustLevel.COMPLETE + } + + def 'Device trust level updated'() { + given: 'a non trusted cm handle' + trustLevelPerCmHandle.put('ch-1', TrustLevel.NONE) + and: 'a trusted dmi plugin' + trustLevelPerDmiPlugin.put('my-dmi', TrustLevel.COMPLETE) + and: 'inventory persistence service returns yang model cm handle' + mockInventoryPersistence.getYangModelCmHandle('ch-1') >> new YangModelCmHandle(id: 'ch-1', dmiDataServiceName: 'my-dmi') + when: 'update of device to COMPLETE trust level handled' + objectUnderTest.handleUpdateOfDeviceTrustLevel('ch-1', TrustLevel.COMPLETE) + then: 'the cm handle in the cache is trusted' + assert trustLevelPerCmHandle.get('ch-1', TrustLevel.COMPLETE) + and: 'notification is sent' + 1 * mockAttributeValueChangeEventPublisher.publishAvcEvent('ch-1', 'trustLevel', 'NONE', 'COMPLETE') + } + + def 'Device trust level updated with same value'() { + given: 'a non trusted cm handle' + trustLevelPerCmHandle.put('ch-1', TrustLevel.NONE) + and: 'a trusted dmi plugin' + trustLevelPerDmiPlugin.put('my-dmi', TrustLevel.COMPLETE) + and: 'inventory persistence service returns yang model cm handle' + mockInventoryPersistence.getYangModelCmHandle('ch-1') >> new YangModelCmHandle(id: 'ch-1', dmiDataServiceName: 'my-dmi') + when: 'update of device trust to the same level (NONE)' + objectUnderTest.handleUpdateOfDeviceTrustLevel('ch-1', TrustLevel.NONE) + then: 'the cm handle in the cache is not trusted' + assert trustLevelPerCmHandle.get('ch-1', TrustLevel.NONE) + and: 'no notification is sent' + 0 * mockAttributeValueChangeEventPublisher.publishAvcEvent(*_) + } + + def 'Dmi trust level restored to complete with non trusted device'() { + given: 'a non trusted dmi' + trustLevelPerDmiPlugin.put('my-dmi', TrustLevel.NONE) + and: 'a non trusted device' + trustLevelPerCmHandle.put('ch-1', TrustLevel.NONE) + when: 'restore the dmi trust level to COMPLETE' + objectUnderTest.handleUpdateOfDmiTrustLevel('my-dmi', ['ch-1'], TrustLevel.COMPLETE) + then: 'the cm handle in the cache is still NONE' + assert trustLevelPerCmHandle.get('ch-1') == TrustLevel.NONE + and: 'no notification is sent' + 0 * mockAttributeValueChangeEventPublisher.publishAvcEvent(*_) + } + +} diff --git a/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/YangDataConverterSpec.groovy b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/YangDataConverterSpec.groovy new file mode 100644 index 000000000..bb45e8ad9 --- /dev/null +++ b/cps-ncmp-service/src/test/groovy/org/onap/cps/ncmp/impl/utils/YangDataConverterSpec.groovy @@ -0,0 +1,57 @@ +/* + * ============LICENSE_START======================================================== + * Copyright (C) 2022-2024 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.utils + +import org.onap.cps.spi.model.DataNode +import spock.lang.Specification + +class YangDataConverterSpec extends Specification{ + + def 'Convert a cm handle data node with private and public properties.'() { + given: 'a datanode with some additional (dmi, private) and public properties' + def dataNodeAdditionalProperties = new DataNode(xpath:'/additional-properties[@name="dmiProp1"]', + leaves: ['name': 'dmiProp1', 'value': 'dmiValue1']) + def dataNodePublicProperties = new DataNode(xpath:'/public-properties[@name="pubProp1"]', + leaves: ['name': 'pubProp1', 'value': 'pubValue1']) + def dataNodeCmHandle = new DataNode(leaves:['id':'sample-id'], childDataNodes:[dataNodeAdditionalProperties, dataNodePublicProperties]) + when: 'the dataNode is converted' + def yangModelCmHandle = YangDataConverter.toYangModelCmHandle(dataNodeCmHandle) + then: 'the converted object has the correct id' + assert yangModelCmHandle.id == 'sample-id' + and: 'the additional (dmi, private) properties are included' + assert yangModelCmHandle.dmiProperties[0].name == 'dmiProp1' + assert yangModelCmHandle.dmiProperties[0].value == 'dmiValue1' + and: 'the public properties are included' + assert yangModelCmHandle.publicProperties[0].name == 'pubProp1' + assert yangModelCmHandle.publicProperties[0].value == 'pubValue1' + } + + def 'Convert multiple cm handle data nodes'(){ + given: 'two data nodes in a collection' + def dataNodes = [new DataNode(xpath:'/dmi-registry/cm-handles[@id=\'some-cm-handle\']', leaves: ['id':'some-cm-handle']), + new DataNode(xpath:'/dmi-registry/cm-handles[@id=\'another-cm-handle\']', leaves: ['id':'another-cm-handle'])] + when: 'the data nodes are converted' + def yangModelCmHandles = YangDataConverter.toYangModelCmHandles(dataNodes) + then: 'verify both have returned and CmHandleIds are correct' + assert yangModelCmHandles.size() == 2 + assert yangModelCmHandles.id.containsAll(['some-cm-handle', 'another-cm-handle']) + } +} -- cgit 1.2.3-korg