diff options
Diffstat (limited to 'models-interactions/model-actors/actor.cds/src')
3 files changed, 210 insertions, 9 deletions
diff --git a/models-interactions/model-actors/actor.cds/src/main/java/org/onap/policy/controlloop/actor/cds/GrpcOperation.java b/models-interactions/model-actors/actor.cds/src/main/java/org/onap/policy/controlloop/actor/cds/GrpcOperation.java index 702802d48..820f4de34 100644 --- a/models-interactions/model-actors/actor.cds/src/main/java/org/onap/policy/controlloop/actor/cds/GrpcOperation.java +++ b/models-interactions/model-actors/actor.cds/src/main/java/org/onap/policy/controlloop/actor/cds/GrpcOperation.java @@ -26,11 +26,15 @@ import com.google.protobuf.Struct; import com.google.protobuf.Struct.Builder; import com.google.protobuf.util.JsonFormat; import java.util.HashMap; +import java.util.LinkedHashMap; import java.util.Map; import java.util.Map.Entry; import java.util.UUID; import java.util.concurrent.CompletableFuture; +import java.util.function.Supplier; import lombok.Getter; +import org.onap.aai.domain.yang.GenericVnf; +import org.onap.aai.domain.yang.ServiceInstance; import org.onap.ccsdk.cds.controllerblueprints.common.api.ActionIdentifiers; import org.onap.ccsdk.cds.controllerblueprints.common.api.CommonHeader; import org.onap.ccsdk.cds.controllerblueprints.processing.api.ExecutionServiceInput; @@ -38,12 +42,16 @@ import org.onap.policy.aai.AaiConstants; import org.onap.policy.aai.AaiCqResponse; import org.onap.policy.cds.client.CdsProcessorGrpcClient; import org.onap.policy.common.utils.coder.CoderException; +import org.onap.policy.common.utils.coder.StandardCoderObject; import org.onap.policy.controlloop.actor.aai.AaiCustomQueryOperation; +import org.onap.policy.controlloop.actor.aai.AaiGetPnfOperation; import org.onap.policy.controlloop.actor.cds.constants.CdsActorConstants; import org.onap.policy.controlloop.actor.cds.request.CdsActionRequest; import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome; +import org.onap.policy.controlloop.actorserviceprovider.Util; import org.onap.policy.controlloop.actorserviceprovider.impl.OperationPartial; import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams; +import org.onap.policy.controlloop.policy.TargetType; /** * Operation that uses gRPC to send request to CDS. @@ -54,6 +62,10 @@ public class GrpcOperation extends OperationPartial { public static final String NAME = "any"; + private static final String AAI_PNF_PREFIX = "pnf."; + private static final String AAI_VNF_ID_KEY = "generic-vnf.vnf-id"; + private static final String AAI_SERVICE_INSTANCE_ID_KEY = "service-instance.service-instance-id"; + private CdsProcessorGrpcClient client; /** @@ -62,6 +74,16 @@ public class GrpcOperation extends OperationPartial { private final GrpcConfig config; /** + * Function to request the A&AI data appropriate to the target type. + */ + private final Supplier<CompletableFuture<OperationOutcome>> aaiRequestor; + + /** + * Function to convert the A&AI data associated with the target type. + */ + private final Supplier<Map<String, String>> aaiConverter; + + /** * Constructs the object. * * @param params operation parameters @@ -70,6 +92,14 @@ public class GrpcOperation extends OperationPartial { public GrpcOperation(ControlLoopOperationParams params, GrpcConfig config) { super(params, config); this.config = config; + + if (TargetType.PNF.equals(params.getTarget().getType())) { + aaiRequestor = this::getPnf; + aaiConverter = this::convertPnfToAaiProperties; + } else { + aaiRequestor = this::getCq; + aaiConverter = this::convertCqToAaiProperties; + } } /** @@ -81,16 +111,84 @@ public class GrpcOperation extends OperationPartial { } /** - * Ensures that A&AI customer query has been performed. + * Ensures that A&AI query has been performed, and runs the guard. */ @Override @SuppressWarnings("unchecked") protected CompletableFuture<OperationOutcome> startPreprocessorAsync() { + // run A&AI Query and Guard, in parallel + return allOf(aaiRequestor, this::startGuardAsync); + } + + /** + * Requests the A&AI PNF data. + * + * @return a future to get the PNF data + */ + private CompletableFuture<OperationOutcome> getPnf() { + ControlLoopOperationParams pnfParams = params.toBuilder().actor(AaiConstants.ACTOR_NAME) + .operation(AaiGetPnfOperation.NAME).payload(null).retry(null).timeoutSec(null).build(); + + return params.getContext().obtain(AaiGetPnfOperation.getKey(params.getTargetEntity()), pnfParams); + } + + /** + * Requests the A&AI Custom Query data. + * + * @return a future to get the custom query data + */ + private CompletableFuture<OperationOutcome> getCq() { ControlLoopOperationParams cqParams = params.toBuilder().actor(AaiConstants.ACTOR_NAME) .operation(AaiCustomQueryOperation.NAME).payload(null).retry(null).timeoutSec(null).build(); - // run Custom Query and Guard, in parallel - return allOf(() -> params.getContext().obtain(AaiCqResponse.CONTEXT_KEY, cqParams), this::startGuardAsync); + return params.getContext().obtain(AaiCqResponse.CONTEXT_KEY, cqParams); + } + + /** + * Converts the A&AI PNF data to a map suitable for passing via the "aaiProperties" + * field in the CDS request. + * + * @return a map of the PNF data + */ + private Map<String, String> convertPnfToAaiProperties() { + // convert PNF data to a Map + StandardCoderObject pnf = params.getContext().getProperty(AaiGetPnfOperation.getKey(params.getTargetEntity())); + Map<String, Object> source = Util.translateToMap(getFullName(), pnf); + + Map<String, String> result = new LinkedHashMap<>(); + + for (Entry<String, Object> ent : source.entrySet()) { + result.put(AAI_PNF_PREFIX + ent.getKey(), ent.getValue().toString()); + } + + return result; + } + + /** + * Converts the A&AI Custom Query data to a map suitable for passing via the + * "aaiProperties" field in the CDS request. + * + * @return a map of the custom query data + */ + private Map<String, String> convertCqToAaiProperties() { + AaiCqResponse aaicq = params.getContext().getProperty(AaiCqResponse.CONTEXT_KEY); + + Map<String, String> result = new LinkedHashMap<>(); + + ServiceInstance serviceInstance = aaicq.getServiceInstance(); + if (serviceInstance == null) { + throw new IllegalArgumentException("Target service instance could not be found"); + } + + GenericVnf genericVnf = aaicq.getGenericVnfByModelInvariantId(params.getTarget().getResourceID()); + if (genericVnf == null) { + throw new IllegalArgumentException("Target generic vnf could not be found"); + } + + result.put(AAI_SERVICE_INSTANCE_ID_KEY, serviceInstance.getServiceInstanceId()); + result.put(AAI_VNF_ID_KEY, genericVnf.getVnfId()); + + return result; } @Override @@ -152,7 +250,10 @@ public class GrpcOperation extends OperationPartial { // implementation to inject whatever AAI parameters are of interest to them. // E.g. For vFW usecase El-Alto inject service-instance-id, generic-vnf-id as // needed by CDS. - request.setAaiProperties(params.getContext().getEnrichment()); + // + // Note: that is a future enhancement. For now, the actor is hard-coded to + // use the A&AI query result specific to the target type + request.setAaiProperties(aaiConverter.get()); // Inject any additional event parameters that may be present in the onset event if (params.getContext().getEvent().getAdditionalEventParams() != null) { diff --git a/models-interactions/model-actors/actor.cds/src/test/java/org/onap/policy/controlloop/actor/cds/GrpcOperationTest.java b/models-interactions/model-actors/actor.cds/src/test/java/org/onap/policy/controlloop/actor/cds/GrpcOperationTest.java index 5dca2909f..9477a1585 100644 --- a/models-interactions/model-actors/actor.cds/src/test/java/org/onap/policy/controlloop/actor/cds/GrpcOperationTest.java +++ b/models-interactions/model-actors/actor.cds/src/test/java/org/onap/policy/controlloop/actor/cds/GrpcOperationTest.java @@ -42,30 +42,44 @@ import org.junit.Before; import org.junit.Test; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import org.onap.aai.domain.yang.GenericVnf; +import org.onap.aai.domain.yang.ServiceInstance; import org.onap.ccsdk.cds.controllerblueprints.processing.api.ExecutionServiceInput; import org.onap.policy.aai.AaiCqResponse; import org.onap.policy.cds.client.CdsProcessorGrpcClient; import org.onap.policy.cds.properties.CdsServerProperties; +import org.onap.policy.common.utils.coder.Coder; +import org.onap.policy.common.utils.coder.CoderException; +import org.onap.policy.common.utils.coder.StandardCoder; +import org.onap.policy.common.utils.coder.StandardCoderObject; import org.onap.policy.common.utils.time.PseudoExecutor; import org.onap.policy.controlloop.VirtualControlLoopEvent; +import org.onap.policy.controlloop.actor.aai.AaiGetPnfOperation; import org.onap.policy.controlloop.actor.cds.constants.CdsActorConstants; import org.onap.policy.controlloop.actorserviceprovider.ActorService; import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome; import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext; import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams; import org.onap.policy.controlloop.policy.PolicyResult; +import org.onap.policy.controlloop.policy.Target; +import org.onap.policy.controlloop.policy.TargetType; public class GrpcOperationTest { - + private static final String TARGET_ENTITY = "entity"; + private static final String MY_VNF = "my-vnf"; + private static final String MY_SVC_ID = "my-service-instance-id"; + private static final String RESOURCE_ID = "my-resource-id"; private static final String CDS_BLUEPRINT_NAME = "vfw-cds"; private static final String CDS_BLUEPRINT_VERSION = "1.0.0"; private static final UUID REQUEST_ID = UUID.randomUUID(); + private static final Coder coder = new StandardCoder(); @Mock private CdsProcessorGrpcClient cdsClient; private CdsServerProperties cdsProps; private VirtualControlLoopEvent onset; private PseudoExecutor executor; + private Target target; private GrpcOperation operation; /** @@ -92,6 +106,10 @@ public class GrpcOperationTest { // Setup executor executor = new PseudoExecutor(); + + target = new Target(); + target.setType(TargetType.VM); + target.setResourceID(RESOURCE_ID); } @Test @@ -106,7 +124,7 @@ public class GrpcOperationTest { ControlLoopOperationParams params = ControlLoopOperationParams.builder().actor(CdsActorConstants.CDS_ACTOR) .operation(GrpcOperation.NAME).context(context).actorService(new ActorService()) - .targetEntity("entity").build(); + .targetEntity(TARGET_ENTITY).target(target).build(); GrpcConfig config = new GrpcConfig(executor, cdsProps); operation = new GrpcOperation(params, config) { @@ -128,10 +146,65 @@ public class GrpcOperationTest { assertTrue(future3.isDone()); } + /** + * Tests startPreprocessorAsync() when the target type is PNF. + */ + @Test + public void testStartPreprocessorAsyncPnf() throws InterruptedException, ExecutionException, TimeoutException { + + CompletableFuture<OperationOutcome> future2 = new CompletableFuture<>(); + ControlLoopEventContext context = mock(ControlLoopEventContext.class); + when(context.obtain(eq(AaiCqResponse.CONTEXT_KEY), any())).thenReturn(future2); + when(context.getEvent()).thenReturn(onset); + + AtomicBoolean guardStarted = new AtomicBoolean(); + + target.setType(TargetType.PNF); + + ControlLoopOperationParams params = ControlLoopOperationParams.builder().actor(CdsActorConstants.CDS_ACTOR) + .operation(GrpcOperation.NAME).context(context).actorService(new ActorService()) + .targetEntity(TARGET_ENTITY).target(target).build(); + GrpcConfig config = new GrpcConfig(executor, cdsProps); + + operation = new GrpcOperation(params, config) { + @Override + protected CompletableFuture<OperationOutcome> startGuardAsync() { + guardStarted.set(true); + return future2; + } + }; + + CompletableFuture<OperationOutcome> future3 = operation.startPreprocessorAsync(); + assertNotNull(future3); + assertTrue(guardStarted.get()); + verify(context).obtain(eq(AaiGetPnfOperation.getKey(TARGET_ENTITY)), any()); + + future2.complete(params.makeOutcome()); + assertTrue(executor.runAll(100)); + assertEquals(PolicyResult.SUCCESS, future3.get(2, TimeUnit.SECONDS).getResult()); + assertTrue(future3.isDone()); + } + @Test public void testStartOperationAsync() throws Exception { ControlLoopEventContext context = new ControlLoopEventContext(onset); + loadCqData(context); + + verifyOperation(context); + } + + /** + * Tests startOperationAsync() when the target type is PNF. + */ + @Test + public void testStartOperationAsyncPnf() throws Exception { + + target.setType(TargetType.PNF); + + ControlLoopEventContext context = new ControlLoopEventContext(onset); + loadPnfData(context); + verifyOperation(context); } @@ -142,6 +215,7 @@ public class GrpcOperationTest { additionalParams.put("test", "additionalParams"); onset.setAdditionalEventParams(additionalParams); ControlLoopEventContext context = new ControlLoopEventContext(onset); + loadCqData(context); verifyOperation(context); } @@ -151,7 +225,7 @@ public class GrpcOperationTest { ControlLoopEventContext context = new ControlLoopEventContext(onset); ControlLoopOperationParams params = ControlLoopOperationParams.builder().actor(CdsActorConstants.CDS_ACTOR) .operation(GrpcOperation.NAME).context(context).actorService(new ActorService()) - .targetEntity("entity").build(); + .targetEntity(TARGET_ENTITY).target(target).build(); GrpcConfig config = new GrpcConfig(executor, cdsProps); operation = new GrpcOperation(params, config); @@ -166,7 +240,7 @@ public class GrpcOperationTest { ControlLoopOperationParams params = ControlLoopOperationParams.builder().actor(CdsActorConstants.CDS_ACTOR) .operation(GrpcOperation.NAME).context(context).actorService(new ActorService()) - .targetEntity("entity").payload(payloadMap).build(); + .targetEntity(TARGET_ENTITY).target(target).payload(payloadMap).build(); GrpcConfig config = new GrpcConfig(executor, cdsProps); operation = new GrpcOperation(params, config); @@ -177,4 +251,25 @@ public class GrpcOperationTest { CompletableFuture<OperationOutcome> future3 = operation.startOperationAsync(1, params.makeOutcome()); assertNotNull(future3); } + + private void loadPnfData(ControlLoopEventContext context) throws CoderException { + String json = "{'dataA': 'valueA', 'dataB': 'valueB'}".replace('\'', '"'); + StandardCoderObject sco = coder.decode(json, StandardCoderObject.class); + + context.setProperty(AaiGetPnfOperation.getKey(TARGET_ENTITY), sco); + } + + private void loadCqData(ControlLoopEventContext context) { + GenericVnf genvnf = new GenericVnf(); + genvnf.setVnfId(MY_VNF); + + ServiceInstance serviceInstance = new ServiceInstance(); + serviceInstance.setServiceInstanceId(MY_SVC_ID); + + AaiCqResponse cq = mock(AaiCqResponse.class); + when(cq.getGenericVnfByModelInvariantId(any())).thenReturn(genvnf); + when(cq.getServiceInstance()).thenReturn(serviceInstance); + + context.setProperty(AaiCqResponse.CONTEXT_KEY, cq); + } } diff --git a/models-interactions/model-actors/actor.cds/src/test/java/org/onap/policy/controlloop/actor/cds/GrpcOperatorTest.java b/models-interactions/model-actors/actor.cds/src/test/java/org/onap/policy/controlloop/actor/cds/GrpcOperatorTest.java index 2fd54e40c..cfb20ab6c 100644 --- a/models-interactions/model-actors/actor.cds/src/test/java/org/onap/policy/controlloop/actor/cds/GrpcOperatorTest.java +++ b/models-interactions/model-actors/actor.cds/src/test/java/org/onap/policy/controlloop/actor/cds/GrpcOperatorTest.java @@ -1,6 +1,7 @@ /*- * ============LICENSE_START======================================================= * Copyright (C) 2020 Bell Canada. All rights reserved. + * Modifications Copyright (C) 2020 AT&T Intellectual Property. All rights reserved. * ================================================================================ * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -35,6 +36,8 @@ import org.onap.policy.controlloop.actorserviceprovider.Util; import org.onap.policy.controlloop.actorserviceprovider.controlloop.ControlLoopEventContext; import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams; import org.onap.policy.controlloop.actorserviceprovider.parameters.ParameterValidationRuntimeException; +import org.onap.policy.controlloop.policy.Target; +import org.onap.policy.controlloop.policy.TargetType; public class GrpcOperatorTest { @@ -85,8 +88,10 @@ public class GrpcOperatorTest { public void testBuildOperation() { VirtualControlLoopEvent event = new VirtualControlLoopEvent(); ControlLoopEventContext context = new ControlLoopEventContext(event); + Target target = new Target(); + target.setType(TargetType.VM); ControlLoopOperationParams params = ControlLoopOperationParams.builder().actor(CdsActorConstants.CDS_ACTOR) - .operation(GrpcOperation.NAME).context(context).build(); + .operation(GrpcOperation.NAME).context(context).target(target).build(); // not configured yet assertThatIllegalStateException().isThrownBy(() -> operation.buildOperation(params)); |