Add PNF support to new CDS actor 22/106222/2
authorJim Hahn <jrh3@att.com>
Fri, 17 Apr 2020 19:09:21 +0000 (15:09 -0400)
committerJim Hahn <jrh3@att.com>
Fri, 17 Apr 2020 23:31:23 +0000 (19:31 -0400)
Made the following updates:
- added new A&AI get-PNF Operation by refactoring AaiGetOperation,
  separating out Tenant and PNF operations
- added PNF support to the CDS actor
- added logging to the CDS Handler
- added get-pnf to the A&AI simulator

Issue-ID: POLICY-2505
Change-Id: Iff140e7c864f762790d8e2ecaba62c161c859e6e
Signed-off-by: Jim Hahn <jrh3@att.com>
20 files changed:
models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiActorServiceProvider.java
models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiCustomQueryOperation.java
models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiGetOperation.java
models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiGetPnfOperation.java [new file with mode: 0644]
models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiGetTenantOperation.java [new file with mode: 0644]
models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiActorServiceProviderTest.java
models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiCustomQueryOperationTest.java
models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiGetOperationTest.java
models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiGetPnfOperationTest.java [new file with mode: 0644]
models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiGetTenantOperationTest.java [new file with mode: 0644]
models-interactions/model-actors/actor.aai/src/test/resources/service.yaml
models-interactions/model-actors/actor.cds/src/main/java/org/onap/policy/controlloop/actor/cds/GrpcOperation.java
models-interactions/model-actors/actor.cds/src/test/java/org/onap/policy/controlloop/actor/cds/GrpcOperationTest.java
models-interactions/model-actors/actor.cds/src/test/java/org/onap/policy/controlloop/actor/cds/GrpcOperatorTest.java
models-interactions/model-impl/cds/pom.xml
models-interactions/model-impl/cds/src/main/java/org/onap/policy/cds/client/CdsProcessorGrpcClient.java
models-interactions/model-impl/cds/src/main/java/org/onap/policy/cds/client/CdsProcessorHandler.java
models-interactions/model-impl/cds/src/test/java/org/onap/policy/cds/client/CdsProcessorGrpcClientTest.java
models-interactions/model-simulators/src/main/java/org/onap/policy/simulators/AaiSimulatorJaxRs.java
models-interactions/model-simulators/src/main/resources/org/onap/policy/simulators/aai/AaiGetPnfResponse.json [new file with mode: 0644]

index a65a000..0fe70b7 100644 (file)
@@ -38,10 +38,7 @@ public class AaiActorServiceProvider extends HttpActor<HttpActorParams> {
         super(NAME, HttpActorParams.class);
 
         addOperator(new HttpOperator(NAME, AaiCustomQueryOperation.NAME, AaiCustomQueryOperation::new));
-
-        // add all "get" operators
-        for (String operation : AaiGetOperation.OPERATIONS) {
-            addOperator(new HttpOperator(NAME, operation, AaiGetOperation::new));
-        }
+        addOperator(new HttpOperator(NAME, AaiGetTenantOperation.NAME, AaiGetTenantOperation::new));
+        addOperator(new HttpOperator(NAME, AaiGetPnfOperation.NAME, AaiGetPnfOperation::new));
     }
 }
index b009288..2cc2a69 100644 (file)
@@ -84,10 +84,10 @@ public class AaiCustomQueryOperation extends HttpOperation<String> {
     @Override
     protected CompletableFuture<OperationOutcome> startPreprocessorAsync() {
         ControlLoopOperationParams tenantParams =
-                        params.toBuilder().actor(AaiConstants.ACTOR_NAME).operation(AaiGetOperation.TENANT)
+                        params.toBuilder().actor(AaiConstants.ACTOR_NAME).operation(AaiGetTenantOperation.NAME)
                                         .targetEntity(vserver).payload(null).retry(null).timeoutSec(null).build();
 
-        return params.getContext().obtain(AaiGetOperation.getTenantKey(vserver), tenantParams);
+        return params.getContext().obtain(AaiGetTenantOperation.getKey(vserver), tenantParams);
     }
 
     @Override
@@ -137,7 +137,7 @@ public class AaiCustomQueryOperation extends HttpOperation<String> {
      * Constructs the custom query using the previously retrieved tenant data.
      */
     private Map<String, String> makeRequest() {
-        StandardCoderObject tenant = params.getContext().getProperty(AaiGetOperation.getTenantKey(vserver));
+        StandardCoderObject tenant = params.getContext().getProperty(AaiGetTenantOperation.getKey(vserver));
 
         String resourceLink = tenant.getString(RESULT_DATA, 0, RESOURCE_LINK);
         if (resourceLink == null) {
index a202008..07738b0 100644 (file)
@@ -22,15 +22,10 @@ package org.onap.policy.controlloop.actor.aai;
 
 import java.util.Map;
 import java.util.Map.Entry;
-import java.util.Set;
 import java.util.concurrent.CompletableFuture;
 import javax.ws.rs.client.Invocation.Builder;
 import javax.ws.rs.client.WebTarget;
-import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
-import org.onap.policy.aai.AaiConstants;
-import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
-import org.onap.policy.common.endpoints.utils.NetLoggerUtil.EventType;
 import org.onap.policy.common.utils.coder.StandardCoderObject;
 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
 import org.onap.policy.controlloop.actorserviceprovider.impl.HttpOperation;
@@ -49,17 +44,6 @@ public class AaiGetOperation extends HttpOperation<StandardCoderObject> {
 
     public static final int DEFAULT_RETRY = 3;
 
-    // operation names
-    public static final String TENANT = "Tenant";
-
-    // property prefixes
-    private static final String TENANT_KEY_PREFIX = AaiConstants.CONTEXT_PREFIX + TENANT + ".";
-
-    /**
-     * Operation names supported by this operator.
-     */
-    public static final Set<String> OPERATIONS = Set.of(TENANT);
-
 
     /**
      * Responses that are retrieved from A&AI are placed in the operation context under
@@ -78,50 +62,22 @@ public class AaiGetOperation extends HttpOperation<StandardCoderObject> {
         this.propertyPrefix = getFullName() + ".";
     }
 
-    /**
-     * Gets the "context key" for the tenant query response associated with the given
-     * target entity.
-     *
-     * @param targetEntity target entity
-     * @return the "context key" for the response associated with the given target
-     */
-    public static String getTenantKey(String targetEntity) {
-        return (TENANT_KEY_PREFIX + targetEntity);
-    }
-
     @Override
     public void generateSubRequestId(int attempt) {
         setSubRequestId(String.valueOf(attempt));
     }
 
-    @Override
-    protected CompletableFuture<OperationOutcome> startOperationAsync(int attempt, OperationOutcome outcome) {
-        Map<String, Object> headers = makeHeaders();
-
-        headers.put("Accept", MediaType.APPLICATION_JSON);
-
-        StringBuilder str = new StringBuilder(getClient().getBaseUrl());
-
-        String path = getPath();
-        WebTarget web = getClient().getWebTarget().path(path);
-        str.append(path);
-
-        web = addQuery(web, str, "?", "search-node-type", "vserver");
-        web = addQuery(web, str, "&", "filter", "vserver-name:EQUALS:" + params.getTargetEntity());
-
-        Builder webldr = web.request();
-        for (Entry<String, Object> header : headers.entrySet()) {
-            webldr.header(header.getKey(), header.getValue());
-        }
-
-        String url = str.toString();
-
-        logMessage(EventType.OUT, CommInfrastructure.REST, url, null);
-
-        return handleResponse(outcome, url, callback -> webldr.async().get(callback));
-    }
-
-    private WebTarget addQuery(WebTarget web, StringBuilder str, String separator, String name, String value) {
+    /**
+     * Adds a query parameter to a web target.
+     *
+     * @param web target to which the parameter should be added
+     * @param str the separator and parameter are appended here, for logging purposes
+     * @param separator separator to be added to "str"; that's its only use
+     * @param name parameter name
+     * @param value parameter value
+     * @return "web"
+     */
+    protected WebTarget addQuery(WebTarget web, StringBuilder str, String separator, String name, String value) {
         str.append(separator);
         str.append(name);
         str.append('=');
@@ -130,6 +86,18 @@ public class AaiGetOperation extends HttpOperation<StandardCoderObject> {
         return web.queryParam(name, value);
     }
 
+    /**
+     * Adds headers to the web builder.
+     *
+     * @param webldr builder to which the headers should be added
+     * @param headers headers to be added
+     */
+    protected void addHeaders(Builder webldr, Map<String, Object> headers) {
+        for (Entry<String, Object> header : headers.entrySet()) {
+            webldr.header(header.getKey(), header.getValue());
+        }
+    }
+
     @Override
     protected Map<String, Object> makeHeaders() {
         return AaiUtil.makeHeaders(params);
diff --git a/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiGetPnfOperation.java b/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiGetPnfOperation.java
new file mode 100644 (file)
index 0000000..fbf4096
--- /dev/null
@@ -0,0 +1,92 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * 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.
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.controlloop.actor.aai;
+
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import javax.ws.rs.client.Invocation.Builder;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.MediaType;
+import org.onap.policy.aai.AaiConstants;
+import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
+import org.onap.policy.common.endpoints.utils.NetLoggerUtil.EventType;
+import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpConfig;
+
+/**
+ * A&AI get-pnf operator.
+ */
+public class AaiGetPnfOperation extends AaiGetOperation {
+    private static final String URI_SEP = "/";
+
+    public static final String NAME = "Pnf";
+
+    // property prefixes
+    private static final String KEY_PREFIX = AaiConstants.CONTEXT_PREFIX + NAME + ".";
+
+    /**
+     * Constructs the object.
+     *
+     * @param params operation parameters
+     * @param config configuration for this operation
+     */
+    public AaiGetPnfOperation(ControlLoopOperationParams params, HttpConfig config) {
+        super(params, config);
+    }
+
+    /**
+     * Gets the "context key" for the PNF query response associated with the given
+     * target entity.
+     *
+     * @param targetEntity target entity
+     * @return the "context key" for the response associated with the given target
+     */
+    public static String getKey(String targetEntity) {
+        return (KEY_PREFIX + targetEntity);
+    }
+
+    @Override
+    protected CompletableFuture<OperationOutcome> startOperationAsync(int attempt, OperationOutcome outcome) {
+        Map<String, Object> headers = makeHeaders();
+
+        headers.put("Accept", MediaType.APPLICATION_JSON);
+
+        StringBuilder str = new StringBuilder(getClient().getBaseUrl());
+
+        String path = getPath() + URI_SEP + URLEncoder.encode(params.getTargetEntity(), StandardCharsets.UTF_8);
+        WebTarget web = getClient().getWebTarget().path(path);
+        str.append(path);
+
+        web = addQuery(web, str, "?", "depth", "0");
+
+        Builder webldr = web.request();
+        addHeaders(webldr, headers);
+
+        String url = str.toString();
+
+        logMessage(EventType.OUT, CommInfrastructure.REST, url, null);
+
+        return handleResponse(outcome, url, callback -> webldr.async().get(callback));
+    }
+}
diff --git a/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiGetTenantOperation.java b/models-interactions/model-actors/actor.aai/src/main/java/org/onap/policy/controlloop/actor/aai/AaiGetTenantOperation.java
new file mode 100644 (file)
index 0000000..cbd1791
--- /dev/null
@@ -0,0 +1,90 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * 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.
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.controlloop.actor.aai;
+
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import javax.ws.rs.client.Invocation.Builder;
+import javax.ws.rs.client.WebTarget;
+import javax.ws.rs.core.MediaType;
+import org.onap.policy.aai.AaiConstants;
+import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
+import org.onap.policy.common.endpoints.utils.NetLoggerUtil.EventType;
+import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.ControlLoopOperationParams;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpConfig;
+
+/**
+ * A&AI get-tenant operator.
+ */
+public class AaiGetTenantOperation extends AaiGetOperation {
+
+    public static final String NAME = "Tenant";
+
+    // property prefixes
+    private static final String KEY_PREFIX = AaiConstants.CONTEXT_PREFIX + NAME + ".";
+
+    /**
+     * Constructs the object.
+     *
+     * @param params operation parameters
+     * @param config configuration for this operation
+     */
+    public AaiGetTenantOperation(ControlLoopOperationParams params, HttpConfig config) {
+        super(params, config);
+    }
+
+    /**
+     * Gets the "context key" for the tenant query response associated with the given
+     * target entity.
+     *
+     * @param targetEntity target entity
+     * @return the "context key" for the response associated with the given target
+     */
+    public static String getKey(String targetEntity) {
+        return (KEY_PREFIX + targetEntity);
+    }
+
+    @Override
+    protected CompletableFuture<OperationOutcome> startOperationAsync(int attempt, OperationOutcome outcome) {
+        Map<String, Object> headers = makeHeaders();
+
+        headers.put("Accept", MediaType.APPLICATION_JSON);
+
+        StringBuilder str = new StringBuilder(getClient().getBaseUrl());
+
+        String path = getPath();
+        WebTarget web = getClient().getWebTarget().path(path);
+        str.append(path);
+
+        web = addQuery(web, str, "?", "search-node-type", "vserver");
+        web = addQuery(web, str, "&", "filter", "vserver-name:EQUALS:" + params.getTargetEntity());
+
+        Builder webldr = web.request();
+        addHeaders(webldr, headers);
+
+        String url = str.toString();
+
+        logMessage(EventType.OUT, CommInfrastructure.REST, url, null);
+
+        return handleResponse(outcome, url, callback -> webldr.async().get(callback));
+    }
+}
index 12b6ca4..97a8491 100644 (file)
@@ -38,7 +38,8 @@ public class AaiActorServiceProviderTest extends BasicActor {
         // verify that it has the operators we expect
         List<String> expected = new LinkedList<>();
         expected.add(AaiCustomQueryOperation.NAME);
-        expected.addAll(AaiGetOperation.OPERATIONS);
+        expected.add(AaiGetTenantOperation.NAME);
+        expected.add(AaiGetPnfOperation.NAME);
 
         Collections.sort(expected);
 
index aa8165e..243a0c6 100644 (file)
@@ -103,7 +103,7 @@ public class AaiCustomQueryOperationTest extends BasicAaiOperation<Map<String, S
         MyTenantOperator tenantOperator = new MyTenantOperator();
 
         when(service.getActor(AaiConstants.ACTOR_NAME)).thenReturn(tenantActor);
-        when(tenantActor.getOperator(AaiGetOperation.TENANT)).thenReturn(tenantOperator);
+        when(tenantActor.getOperator(AaiGetTenantOperation.NAME)).thenReturn(tenantOperator);
 
         oper = new AaiCustomQueryOperation(params, config);
     }
@@ -160,7 +160,7 @@ public class AaiCustomQueryOperationTest extends BasicAaiOperation<Map<String, S
         assertEquals(PolicyResult.SUCCESS, getResult(future2));
 
         // tenant response should have been cached within the context
-        assertNotNull(context.getProperty(AaiGetOperation.getTenantKey(MY_VSERVER)));
+        assertNotNull(context.getProperty(AaiGetTenantOperation.getKey(MY_VSERVER)));
 
         // custom query response should have been cached within the context
         AaiCqResponse cqData = context.getProperty(AaiCqResponse.CONTEXT_KEY);
@@ -187,7 +187,7 @@ public class AaiCustomQueryOperationTest extends BasicAaiOperation<Map<String, S
         assertEquals(PolicyResult.SUCCESS, getResult(future2));
 
         // should not have replaced tenant response
-        assertSame(data, context.getProperty(AaiGetOperation.getTenantKey(MY_VSERVER)));
+        assertSame(data, context.getProperty(AaiGetTenantOperation.getKey(MY_VSERVER)));
 
         // custom query response should have been cached within the context
         AaiCqResponse cqData = context.getProperty(AaiCqResponse.CONTEXT_KEY);
@@ -252,8 +252,8 @@ public class AaiCustomQueryOperationTest extends BasicAaiOperation<Map<String, S
     }
 
     private void preloadTenantData(StandardCoderObject data) {
-        context.setProperty(AaiGetOperation.getTenantKey(MY_VSERVER), data);
-        context.setProperty(AaiGetOperation.getTenantKey(SIM_VSERVER), data);
+        context.setProperty(AaiGetTenantOperation.getKey(MY_VSERVER), data);
+        context.setProperty(AaiGetTenantOperation.getKey(SIM_VSERVER), data);
     }
 
     private PolicyResult getResult(CompletableFuture<OperationOutcome> future2)
@@ -267,17 +267,17 @@ public class AaiCustomQueryOperationTest extends BasicAaiOperation<Map<String, S
 
     protected class MyTenantOperator extends HttpOperator {
         public MyTenantOperator() {
-            super(AaiConstants.ACTOR_NAME, AaiGetOperation.TENANT);
+            super(AaiConstants.ACTOR_NAME, AaiGetTenantOperation.NAME);
 
             HttpParams http = HttpParams.builder().clientName(MY_CLIENT).path(PATH).timeoutSec(1).build();
 
-            configure(Util.translateToMap(AaiGetOperation.TENANT, http));
+            configure(Util.translateToMap(AaiGetTenantOperation.NAME, http));
             start();
         }
 
         @Override
         public Operation buildOperation(ControlLoopOperationParams params) {
-            return new AaiGetOperation(params, getCurrentConfig());
+            return new AaiGetTenantOperation(params, getCurrentConfig());
         }
 
         @Override
index 72b27ea..673b651 100644 (file)
 package org.onap.policy.controlloop.actor.aai;
 
 import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertFalse;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.assertSame;
 import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import java.util.Map;
 import java.util.concurrent.CompletableFuture;
-import javax.ws.rs.client.InvocationCallback;
+import javax.ws.rs.client.Invocation.Builder;
+import javax.ws.rs.client.WebTarget;
 import org.junit.AfterClass;
 import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
 import org.onap.policy.aai.AaiConstants;
-import org.onap.policy.common.endpoints.http.client.HttpClientFactoryInstance;
-import org.onap.policy.common.utils.coder.StandardCoder;
 import org.onap.policy.common.utils.coder.StandardCoderObject;
 import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
-import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpConfig;
-import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpParams;
-import org.onap.policy.controlloop.policy.PolicyResult;
 
 public class AaiGetOperationTest extends BasicAaiOperation<Void> {
-    private static final String INPUT_FIELD = "input";
-    private static final String TEXT = "my-text";
+    private static final String MY_NAME = "my-operation-name";
+    private static final String PARAM_NAME = "my-param";
+    private static final String PARAM_VALUE = "my-value";
+    private static final String MY_URL = "my-url";
 
     private AaiGetOperation oper;
 
     public AaiGetOperationTest() {
-        super(AaiConstants.ACTOR_NAME, AaiGetOperation.TENANT);
+        super(AaiConstants.ACTOR_NAME, MY_NAME);
     }
 
     @BeforeClass
@@ -73,45 +71,10 @@ public class AaiGetOperationTest extends BasicAaiOperation<Void> {
         oper = new AaiGetOperation(params, config);
     }
 
-    /**
-     * Tests "success" case with simulator.
-     */
     @Test
-    public void testSuccess() throws Exception {
-        HttpParams opParams = HttpParams.builder().clientName(MY_CLIENT).path("v16/search/nodes-query").build();
-        config = new HttpConfig(blockingExecutor, opParams, HttpClientFactoryInstance.getClientFactory());
-
-        params = params.toBuilder().targetEntity("OzVServer").retry(0).timeoutSec(5).executor(blockingExecutor).build();
-        oper = new AaiGetOperation(params, config);
-
-        outcome = oper.start().get();
-        assertEquals(PolicyResult.SUCCESS, outcome.getResult());
-    }
-
-    /**
-     * Tests "failure" case with simulator.
-     */
-    @Test
-    public void testFailure() throws Exception {
-        HttpParams opParams = HttpParams.builder().clientName(MY_CLIENT).path("v16/search/nodes-query").build();
-        config = new HttpConfig(blockingExecutor, opParams, HttpClientFactoryInstance.getClientFactory());
-
-        params = params.toBuilder().targetEntity("failedVserver").retry(0).timeoutSec(5).executor(blockingExecutor)
-                        .build();
-        oper = new AaiGetOperation(params, config);
-
-        outcome = oper.start().get();
-        assertEquals(PolicyResult.FAILURE, outcome.getResult());
-    }
-
-    @Test
-    public void testGetRetry() {
-        // use default if null retry
-        assertEquals(AaiGetOperation.DEFAULT_RETRY, oper.getRetry(null));
-
-        // otherwise, use specified value
-        assertEquals(0, oper.getRetry(0));
-        assertEquals(10, oper.getRetry(10));
+    public void testConstructor() {
+        assertEquals(AaiConstants.ACTOR_NAME, oper.getActorName());
+        assertEquals(MY_NAME, oper.getName());
     }
 
     @Test
@@ -121,71 +84,47 @@ public class AaiGetOperationTest extends BasicAaiOperation<Void> {
     }
 
     @Test
-    @SuppressWarnings("unchecked")
-    public void testStartOperationAsync_testStartQueryAsync_testPostProcessResponse() throws Exception {
-
-        // return a map in the reply
-        Map<String, String> reply = Map.of(INPUT_FIELD, TEXT);
-        when(rawResponse.readEntity(String.class)).thenReturn(new StandardCoder().encode(reply));
+    public void testAddQuery() {
+        WebTarget web = mock(WebTarget.class);
+        when(web.queryParam(any(), any())).thenReturn(web);
 
-        when(webAsync.get(any(InvocationCallback.class))).thenAnswer(provideResponse(rawResponse));
+        StringBuilder bldr = new StringBuilder();
 
-        oper.generateSubRequestId(1);
-        outcome.setSubRequestId(oper.getSubRequestId());
-
-        CompletableFuture<OperationOutcome> future2 = oper.startOperationAsync(1, outcome);
-        assertFalse(future2.isDone());
-
-        executor.runAll(100);
-        assertTrue(future2.isDone());
-
-        assertEquals(PolicyResult.SUCCESS, future2.get().getResult());
-
-        // data should have been cached within the context
-        StandardCoderObject data = context.getProperty(AaiGetOperation.getTenantKey(TARGET_ENTITY));
-        assertNotNull(data);
-        assertEquals(TEXT, data.getString(INPUT_FIELD));
-
-        assertEquals("1", future2.get().getSubRequestId());
+        assertSame(web, oper.addQuery(web, bldr, ",", PARAM_NAME, PARAM_VALUE));
+        assertEquals(",my-param=my-value", bldr.toString());
     }
 
-    /**
-     * Tests startOperationAsync() when there's a failure.
-     */
     @Test
-    @SuppressWarnings("unchecked")
-    public void testStartOperationAsyncFailure() throws Exception {
+    public void testAddHeaders() {
+        Builder bldr = mock(Builder.class);
+        oper.addHeaders(bldr, Map.of("hdrA", "valA", "hdrB", "valB"));
 
-        when(rawResponse.getStatus()).thenReturn(500);
-        when(rawResponse.readEntity(String.class)).thenReturn("");
-
-        when(webAsync.get(any(InvocationCallback.class))).thenAnswer(provideResponse(rawResponse));
-
-        CompletableFuture<OperationOutcome> future2 = oper.startOperationAsync(1, outcome);
-        assertFalse(future2.isDone());
-
-        executor.runAll(100);
-        assertTrue(future2.isDone());
-
-        assertEquals(PolicyResult.FAILURE, future2.get().getResult());
-
-        // data should NOT have been cached within the context
-        assertNull(context.getProperty(AaiGetOperation.getTenantKey(TARGET_ENTITY)));
+        verify(bldr, times(2)).header(any(), any());
+        verify(bldr).header("hdrA", "valA");
+        verify(bldr).header("hdrB", "valB");
     }
 
     @Test
-    public void testMakeHeaders() {
-        verifyHeaders(oper.makeHeaders());
+    public void testPostProcessResponse() throws Exception {
+        StandardCoderObject resp = new StandardCoderObject();
+        CompletableFuture<OperationOutcome> future2 = oper.postProcessResponse(outcome, MY_URL, null, resp);
+
+        assertSame(outcome, future2.get());
+        assertSame(resp, context.getProperty("AAI.my-operation-name.my-target"));
     }
 
     @Test
-    public void testAaiGetOperator() {
-        assertEquals(AaiConstants.ACTOR_NAME, oper.getActorName());
-        assertEquals(AaiGetOperation.TENANT, oper.getName());
+    public void testGetRetry() {
+        // use default if null retry
+        assertEquals(AaiGetOperation.DEFAULT_RETRY, oper.getRetry(null));
+
+        // otherwise, use specified value
+        assertEquals(0, oper.getRetry(0));
+        assertEquals(10, oper.getRetry(10));
     }
 
     @Test
-    public void testGetTenantKey() {
-        assertEquals("AAI.Tenant." + TARGET_ENTITY, AaiGetOperation.getTenantKey(TARGET_ENTITY));
+    public void testMakeHeaders() {
+        verifyHeaders(oper.makeHeaders());
     }
 }
diff --git a/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiGetPnfOperationTest.java b/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiGetPnfOperationTest.java
new file mode 100644 (file)
index 0000000..2270240
--- /dev/null
@@ -0,0 +1,169 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * 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.
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.controlloop.actor.aai;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import javax.ws.rs.client.InvocationCallback;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.onap.policy.aai.AaiConstants;
+import org.onap.policy.common.endpoints.http.client.HttpClientFactoryInstance;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.common.utils.coder.StandardCoderObject;
+import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpConfig;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpParams;
+import org.onap.policy.controlloop.policy.PolicyResult;
+
+public class AaiGetPnfOperationTest extends BasicAaiOperation<Void> {
+    private static final String INPUT_FIELD = "input";
+    private static final String TEXT = "my-text";
+
+    private AaiGetPnfOperation oper;
+
+    public AaiGetPnfOperationTest() {
+        super(AaiConstants.ACTOR_NAME, AaiGetPnfOperation.NAME);
+    }
+
+    @BeforeClass
+    public static void setUpBeforeClass() throws Exception {
+        initBeforeClass();
+    }
+
+    @AfterClass
+    public static void tearDownAfterClass() {
+        destroyAfterClass();
+    }
+
+    /**
+     * Sets up.
+     */
+    @Before
+    public void setUp() throws Exception {
+        super.setUpBasic();
+        oper = new AaiGetPnfOperation(params, config);
+    }
+
+    @Test
+    public void testConstructor() {
+        assertEquals(AaiConstants.ACTOR_NAME, oper.getActorName());
+        assertEquals(AaiGetPnfOperation.NAME, oper.getName());
+    }
+
+    /**
+     * Tests "success" case with simulator.
+     */
+    @Test
+    public void testSuccess() throws Exception {
+        HttpParams opParams = HttpParams.builder().clientName(MY_CLIENT).path("v16/network/pnfs/pnf").build();
+        config = new HttpConfig(blockingExecutor, opParams, HttpClientFactoryInstance.getClientFactory());
+
+        params = params.toBuilder().targetEntity("OzVServer").retry(0).timeoutSec(5).executor(blockingExecutor).build();
+        oper = new AaiGetPnfOperation(params, config);
+
+        outcome = oper.start().get();
+        assertEquals(PolicyResult.SUCCESS, outcome.getResult());
+    }
+
+    /**
+     * Tests "failure" case with simulator.
+     */
+    @Test
+    public void testFailure() throws Exception {
+        HttpParams opParams = HttpParams.builder().clientName(MY_CLIENT).path("v16/network/pnfs/pnf").build();
+        config = new HttpConfig(blockingExecutor, opParams, HttpClientFactoryInstance.getClientFactory());
+
+        params = params.toBuilder().targetEntity("getFail").retry(0).timeoutSec(5).executor(blockingExecutor).build();
+        oper = new AaiGetPnfOperation(params, config);
+
+        outcome = oper.start().get();
+        assertEquals(PolicyResult.FAILURE, outcome.getResult());
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testStartOperationAsync_testStartQueryAsync() throws Exception {
+
+        // return a map in the reply
+        Map<String, String> reply = Map.of(INPUT_FIELD, TEXT);
+        when(rawResponse.readEntity(String.class)).thenReturn(new StandardCoder().encode(reply));
+
+        when(webAsync.get(any(InvocationCallback.class))).thenAnswer(provideResponse(rawResponse));
+
+        oper.generateSubRequestId(1);
+        outcome.setSubRequestId(oper.getSubRequestId());
+
+        CompletableFuture<OperationOutcome> future2 = oper.startOperationAsync(1, outcome);
+        assertFalse(future2.isDone());
+
+        executor.runAll(100);
+        assertTrue(future2.isDone());
+
+        assertEquals(PolicyResult.SUCCESS, future2.get().getResult());
+
+        // data should have been cached within the context
+        StandardCoderObject data = context.getProperty(AaiGetPnfOperation.getKey(TARGET_ENTITY));
+        assertNotNull(data);
+        assertEquals(TEXT, data.getString(INPUT_FIELD));
+
+        assertEquals("1", future2.get().getSubRequestId());
+    }
+
+    /**
+     * Tests startOperationAsync() when there's a failure.
+     */
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testStartOperationAsyncFailure() throws Exception {
+
+        when(rawResponse.getStatus()).thenReturn(500);
+        when(rawResponse.readEntity(String.class)).thenReturn("");
+
+        when(webAsync.get(any(InvocationCallback.class))).thenAnswer(provideResponse(rawResponse));
+
+        CompletableFuture<OperationOutcome> future2 = oper.startOperationAsync(1, outcome);
+        assertFalse(future2.isDone());
+
+        executor.runAll(100);
+        assertTrue(future2.isDone());
+
+        assertEquals(PolicyResult.FAILURE, future2.get().getResult());
+
+        // data should NOT have been cached within the context
+        assertNull(context.getProperty(AaiGetPnfOperation.getKey(TARGET_ENTITY)));
+    }
+
+    @Test
+    public void testGetKey() {
+        assertEquals("AAI.Pnf." + TARGET_ENTITY, AaiGetPnfOperation.getKey(TARGET_ENTITY));
+    }
+}
diff --git a/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiGetTenantOperationTest.java b/models-interactions/model-actors/actor.aai/src/test/java/org/onap/policy/controlloop/actor/aai/AaiGetTenantOperationTest.java
new file mode 100644 (file)
index 0000000..496d2ea
--- /dev/null
@@ -0,0 +1,170 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * ONAP
+ * ================================================================================
+ * 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.
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.controlloop.actor.aai;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.when;
+
+import java.util.Map;
+import java.util.concurrent.CompletableFuture;
+import javax.ws.rs.client.InvocationCallback;
+import org.junit.AfterClass;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+import org.onap.policy.aai.AaiConstants;
+import org.onap.policy.common.endpoints.http.client.HttpClientFactoryInstance;
+import org.onap.policy.common.utils.coder.StandardCoder;
+import org.onap.policy.common.utils.coder.StandardCoderObject;
+import org.onap.policy.controlloop.actorserviceprovider.OperationOutcome;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpConfig;
+import org.onap.policy.controlloop.actorserviceprovider.parameters.HttpParams;
+import org.onap.policy.controlloop.policy.PolicyResult;
+
+public class AaiGetTenantOperationTest extends BasicAaiOperation<Void> {
+    private static final String INPUT_FIELD = "input";
+    private static final String TEXT = "my-text";
+
+    private AaiGetTenantOperation oper;
+
+    public AaiGetTenantOperationTest() {
+        super(AaiConstants.ACTOR_NAME, AaiGetTenantOperation.NAME);
+    }
+
+    @BeforeClass
+    public static void setUpBeforeClass() throws Exception {
+        initBeforeClass();
+    }
+
+    @AfterClass
+    public static void tearDownAfterClass() {
+        destroyAfterClass();
+    }
+
+    /**
+     * Sets up.
+     */
+    @Before
+    public void setUp() throws Exception {
+        super.setUpBasic();
+        oper = new AaiGetTenantOperation(params, config);
+    }
+
+    @Test
+    public void testConstructor() {
+        assertEquals(AaiConstants.ACTOR_NAME, oper.getActorName());
+        assertEquals(AaiGetTenantOperation.NAME, oper.getName());
+    }
+
+    /**
+     * Tests "success" case with simulator.
+     */
+    @Test
+    public void testSuccess() throws Exception {
+        HttpParams opParams = HttpParams.builder().clientName(MY_CLIENT).path("v16/search/nodes-query").build();
+        config = new HttpConfig(blockingExecutor, opParams, HttpClientFactoryInstance.getClientFactory());
+
+        params = params.toBuilder().targetEntity("OzVServer").retry(0).timeoutSec(5).executor(blockingExecutor).build();
+        oper = new AaiGetTenantOperation(params, config);
+
+        outcome = oper.start().get();
+        assertEquals(PolicyResult.SUCCESS, outcome.getResult());
+    }
+
+    /**
+     * Tests "failure" case with simulator.
+     */
+    @Test
+    public void testFailure() throws Exception {
+        HttpParams opParams = HttpParams.builder().clientName(MY_CLIENT).path("v16/search/nodes-query").build();
+        config = new HttpConfig(blockingExecutor, opParams, HttpClientFactoryInstance.getClientFactory());
+
+        params = params.toBuilder().targetEntity("failedVserver").retry(0).timeoutSec(5).executor(blockingExecutor)
+                        .build();
+        oper = new AaiGetTenantOperation(params, config);
+
+        outcome = oper.start().get();
+        assertEquals(PolicyResult.FAILURE, outcome.getResult());
+    }
+
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testStartOperationAsync_testStartQueryAsync() throws Exception {
+
+        // return a map in the reply
+        Map<String, String> reply = Map.of(INPUT_FIELD, TEXT);
+        when(rawResponse.readEntity(String.class)).thenReturn(new StandardCoder().encode(reply));
+
+        when(webAsync.get(any(InvocationCallback.class))).thenAnswer(provideResponse(rawResponse));
+
+        oper.generateSubRequestId(1);
+        outcome.setSubRequestId(oper.getSubRequestId());
+
+        CompletableFuture<OperationOutcome> future2 = oper.startOperationAsync(1, outcome);
+        assertFalse(future2.isDone());
+
+        executor.runAll(100);
+        assertTrue(future2.isDone());
+
+        assertEquals(PolicyResult.SUCCESS, future2.get().getResult());
+
+        // data should have been cached within the context
+        StandardCoderObject data = context.getProperty(AaiGetTenantOperation.getKey(TARGET_ENTITY));
+        assertNotNull(data);
+        assertEquals(TEXT, data.getString(INPUT_FIELD));
+
+        assertEquals("1", future2.get().getSubRequestId());
+    }
+
+    /**
+     * Tests startOperationAsync() when there's a failure.
+     */
+    @Test
+    @SuppressWarnings("unchecked")
+    public void testStartOperationAsyncFailure() throws Exception {
+
+        when(rawResponse.getStatus()).thenReturn(500);
+        when(rawResponse.readEntity(String.class)).thenReturn("");
+
+        when(webAsync.get(any(InvocationCallback.class))).thenAnswer(provideResponse(rawResponse));
+
+        CompletableFuture<OperationOutcome> future2 = oper.startOperationAsync(1, outcome);
+        assertFalse(future2.isDone());
+
+        executor.runAll(100);
+        assertTrue(future2.isDone());
+
+        assertEquals(PolicyResult.FAILURE, future2.get().getResult());
+
+        // data should NOT have been cached within the context
+        assertNull(context.getProperty(AaiGetTenantOperation.getKey(TARGET_ENTITY)));
+    }
+
+    @Test
+    public void testGetKey() {
+        assertEquals("AAI.Tenant." + TARGET_ENTITY, AaiGetTenantOperation.getKey(TARGET_ENTITY));
+    }
+}
index d0c11be..db18602 100644 (file)
@@ -30,4 +30,6 @@ actors:
       CustomQuery:
         path: cq
       Tenant:
-        path: tenant
\ No newline at end of file
+        path: tenant
+      Pnf:
+        path: pnf
index 702802d..820f4de 100644 (file)
@@ -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;
 
     /**
@@ -61,6 +73,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.
      *
@@ -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) {
index 5dca290..9477a15 100644 (file)
@@ -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);
+    }
 }
index 2fd54e4..cfb20ab 100644 (file)
@@ -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));
index 96a9426..02a4c5a 100644 (file)
       <artifactId>common-parameters</artifactId>
       <version>${policy.common.version}</version>
     </dependency>
+    <dependency>
+        <groupId>org.onap.policy.common</groupId>
+        <artifactId>policy-endpoints</artifactId>
+        <version>${policy.common.version}</version>
+        <scope>provided</scope>
+    </dependency>
 
     <!-- junit dependencies -->
     <dependency>
index b8ec7ac..efa8369 100644 (file)
@@ -1,6 +1,7 @@
 /*-
  * ============LICENSE_START=======================================================
  * Copyright (C) 2019 Bell Canada.
+ * 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.
@@ -55,11 +56,19 @@ public class CdsProcessorGrpcClient implements AutoCloseable {
         Preconditions.checkState(validationResult.getStatus().isValid(), "Error validating CDS server "
             + "properties: " + validationResult.getResult());
 
+        StringBuilder bldr = new StringBuilder("gRPC://");
+        bldr.append(props.getHost());
+        bldr.append(":");
+        bldr.append(props.getPort());
+        bldr.append('/');
+
+        String url = bldr.toString();
+
         this.channel = NettyChannelBuilder.forAddress(props.getHost(), props.getPort())
             .nameResolverFactory(new DnsNameResolverProvider())
             .loadBalancerFactory(new PickFirstLoadBalancerProvider())
             .intercept(new BasicAuthClientHeaderInterceptor(props)).usePlaintext().build();
-        this.handler = new CdsProcessorHandler(listener);
+        this.handler = new CdsProcessorHandler(listener, url);
         LOGGER.info("CdsProcessorListener started");
     }
 
index 5c011d8..84baecd 100644 (file)
@@ -1,6 +1,7 @@
 /*-
  * ============LICENSE_START=======================================================
  * Copyright (C) 2019 Bell Canada.
+ * 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.
@@ -27,6 +28,9 @@ import org.onap.ccsdk.cds.controllerblueprints.processing.api.BluePrintProcessin
 import org.onap.ccsdk.cds.controllerblueprints.processing.api.ExecutionServiceInput;
 import org.onap.ccsdk.cds.controllerblueprints.processing.api.ExecutionServiceOutput;
 import org.onap.policy.cds.api.CdsProcessorListener;
+import org.onap.policy.common.endpoints.event.comm.Topic.CommInfrastructure;
+import org.onap.policy.common.endpoints.utils.NetLoggerUtil;
+import org.onap.policy.common.endpoints.utils.NetLoggerUtil.EventType;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -35,9 +39,11 @@ public class CdsProcessorHandler {
     private static final Logger LOGGER = LoggerFactory.getLogger(CdsProcessorHandler.class);
 
     private CdsProcessorListener listener;
+    private String url;
 
-    CdsProcessorHandler(final CdsProcessorListener listener) {
+    CdsProcessorHandler(final CdsProcessorListener listener, String url) {
         this.listener = listener;
+        this.url = url;
     }
 
     CountDownLatch process(ExecutionServiceInput request, ManagedChannel channel) {
@@ -50,11 +56,18 @@ public class CdsProcessorHandler {
         final StreamObserver<ExecutionServiceOutput> responseObserver = new StreamObserver<ExecutionServiceOutput>() {
             @Override
             public void onNext(ExecutionServiceOutput output) {
+                LOGGER.info("[{}|{}|{}|]{}{}", EventType.IN, CommInfrastructure.REST, url, NetLoggerUtil.SYSTEM_LS,
+                                output.toString());
+                NetLoggerUtil.log(EventType.IN, CommInfrastructure.REST, url, output.toString());
+
                 listener.onMessage(output);
             }
 
             @Override
             public void onError(Throwable throwable) {
+                LOGGER.info("[{}|{}|{}|]{}{}", EventType.IN, CommInfrastructure.REST, url, NetLoggerUtil.SYSTEM_LS,
+                                throwable.toString());
+                NetLoggerUtil.log(EventType.IN, CommInfrastructure.REST, url, throwable.toString());
                 listener.onError(throwable);
                 finishLatch.countDown();
             }
@@ -69,6 +82,10 @@ public class CdsProcessorHandler {
 
         final StreamObserver<ExecutionServiceInput> requestObserver = asyncStub.process(responseObserver);
         try {
+            LOGGER.info("[{}|{}|{}|]{}{}", EventType.OUT, CommInfrastructure.REST, url, NetLoggerUtil.SYSTEM_LS,
+                            request.toString());
+            NetLoggerUtil.log(EventType.OUT, CommInfrastructure.REST, url, request.toString());
+
             // Send the message to CDS backend for processing
             requestObserver.onNext(request);
             // Mark the end of requests
index 9d01ec8..0922fc4 100644 (file)
@@ -92,7 +92,7 @@ public class CdsProcessorGrpcClientTest {
             .register(InProcessChannelBuilder.forName(SERVER_NAME).directExecutor().build());
 
         // Create an instance of the gRPC client
-        client = new CdsProcessorGrpcClient(channel, new CdsProcessorHandler(listener));
+        client = new CdsProcessorGrpcClient(channel, new CdsProcessorHandler(listener, "gRPC://localhost:1234/"));
 
         // Implement the test gRPC server
         BluePrintProcessingServiceImplBase testCdsBlueprintServerImpl = new BluePrintProcessingServiceImplBase() {
index 8c96ee5..8a3d6a8 100644 (file)
@@ -2,7 +2,7 @@
  * ============LICENSE_START=======================================================
  * simulators
  * ================================================================================
- * Copyright (C) 2017-2018 AT&T Intellectual Property. All rights reserved.
+ * Copyright (C) 2017-2018, 2020 AT&T Intellectual Property. All rights reserved.
  * Modifications Copyright (C) 2019 Nordix Foundation.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
@@ -51,7 +51,7 @@ public class AaiSimulatorJaxRs {
     @Path("/v8/network/generic-vnfs/generic-vnf/{vnfId}")
     @Consumes(MediaType.APPLICATION_JSON)
     @Produces("application/json")
-    public String aaiGetQuery(@PathParam("vnfID") final String vnfId) {
+    public String aaiGetQuery(@PathParam("vnfId") final String vnfId) {
         return "{\"relationship-list\": {\"relationship\":[{\"related-to-property\": [{\"property-key\": "
             + "\"service-instance.service-instance-name\"}]},{\"related-to-property\": [ {\"property-key\": "
             + "\"vserver.vserver-name\",\"property-value\": \"USUCP0PCOIL0110UJZZ01-vsrx\" }]} ]}}";
@@ -95,6 +95,25 @@ public class AaiSimulatorJaxRs {
             StandardCharsets.UTF_8);
     }
 
+    /**
+     * A&AI get PNF query.
+     *
+     * @return the result
+     * @throws IOException if a response file cannot be read
+     */
+    @GET
+    @Path("/v16/network/pnfs/pnf/{pnfName}")
+    @Consumes(MediaType.APPLICATION_JSON)
+    @Produces("application/json")
+    public String aaiGetPnfQuery(@PathParam("pnfName") final String pnfName) throws IOException {
+        if (GETFAIL.equals(pnfName)) {
+            throw new IllegalArgumentException("query failed, as requested");
+        }
+
+        return IOUtils.toString(getClass().getResource("aai/AaiGetPnfResponse.json"),
+                        StandardCharsets.UTF_8);
+    }
+
     /**
      * Get by VNF name.
      *
diff --git a/models-interactions/model-simulators/src/main/resources/org/onap/policy/simulators/aai/AaiGetPnfResponse.json b/models-interactions/model-simulators/src/main/resources/org/onap/policy/simulators/aai/AaiGetPnfResponse.json
new file mode 100644 (file)
index 0000000..ce8eb75
--- /dev/null
@@ -0,0 +1,12 @@
+{
+  "equip-vendor":"Vendor-A",
+  "ipaddress-v4-oam":"10.10.10.10",
+  "in-maint":false,
+  "pnf-ipv4-address":"3.3.3.3",
+  "resource-version":"1570746989505",
+  "nf-role":"ToR DC101",
+  "equip-type":"Router",
+  "equip-model":"model-123456",
+  "frame-id":"3",
+  "pnf-name":"demo-pnf"
+}