Query deployed policies by regex 22/120922/9
authorarkadiusz.adamski <aadamski@est.tech>
Tue, 13 Apr 2021 10:23:28 +0000 (11:23 +0100)
committerarkadiusz.adamski <aadamski@est.tech>
Thu, 6 May 2021 09:04:35 +0000 (10:04 +0100)
- Query deployed policies by regex on the name, for a given policy type

Issue-ID: POLICY-2535
Signed-off-by: arkadiusz.adamski <aadamski@est.tech>
Change-Id: Ia2be683d044b22e4104ae14e2ce301882091c8ea

main/src/main/java/org/onap/policy/pap/main/rest/PolicyStatusControllerV1.java
main/src/main/java/org/onap/policy/pap/main/rest/PolicyStatusProvider.java
main/src/test/java/org/onap/policy/pap/main/rest/TestPolicyStatusControllerV1.java
main/src/test/java/org/onap/policy/pap/main/rest/TestPolicyStatusProvider.java

index 055e129..d6388a5 100644 (file)
@@ -22,6 +22,7 @@
 
 package org.onap.policy.pap.main.rest;
 
+import com.google.re2j.PatternSyntaxException;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiParam;
 import io.swagger.annotations.ApiResponse;
@@ -36,6 +37,7 @@ import javax.ws.rs.GET;
 import javax.ws.rs.HeaderParam;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
+import javax.ws.rs.QueryParam;
 import javax.ws.rs.core.Response;
 import org.onap.policy.models.base.PfModelException;
 import org.onap.policy.models.base.PfModelRuntimeException;
@@ -50,6 +52,8 @@ import org.slf4j.LoggerFactory;
  * policies.
  */
 public class PolicyStatusControllerV1 extends PapRestControllerV1 {
+    private static final String EMPTY_REGEX_ERROR_MESSAGE = "An empty string passed as a regex is not allowed";
+    private static final String EMPTY_REGEX_WARNING = ". Empty string passed as Regex.";
     private static final String GET_DEPLOYMENTS_FAILED = "get deployments failed";
 
     private static final Logger logger = LoggerFactory.getLogger(PolicyStatusControllerV1.class);
@@ -57,9 +61,11 @@ public class PolicyStatusControllerV1 extends PapRestControllerV1 {
     private final PolicyStatusProvider provider = new PolicyStatusProvider();
 
     /**
-     * Queries status of all deployed policies.
+     * Queries status of all deployed policies. If regex is not null or empty, the function will only return
+     * policies that match regex
      *
      * @param requestId request ID used in ONAP logging
+     * @param regex regex for a policy name
      * @return a response
      */
     // @formatter:off
@@ -88,16 +94,27 @@ public class PolicyStatusControllerV1 extends PapRestControllerV1 {
     // @formatter:on
 
     public Response queryAllDeployedPolicies(
-                    @HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) final UUID requestId) {
-
+        @HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) final UUID requestId,
+        @ApiParam(value = "Regex for a policy name") @QueryParam("regex") String regex) {
         try {
-            return addLoggingHeaders(addVersionControlHeaders(Response.status(Response.Status.OK)), requestId)
-                            .entity(provider.getStatus()).build();
+            final Collection<PolicyStatus> result;
+            if (regex == null) {
+                result = provider.getStatus();
+            } else if (regex.isBlank()) {
+                return makeRegexNotFoundResponse(requestId);
+            } else {
+                result = provider.getByRegex(regex);
+            }
+            return makeListOrNotFoundResponse(requestId, result);
 
         } catch (PfModelException | PfModelRuntimeException e) {
             logger.warn(GET_DEPLOYMENTS_FAILED, e);
             return addLoggingHeaders(addVersionControlHeaders(Response.status(e.getErrorResponse().getResponseCode())),
                 requestId).entity(e.getErrorResponse().getErrorMessage()).build();
+        } catch (PatternSyntaxException e) {
+            logger.warn(GET_DEPLOYMENTS_FAILED, e);
+            return addLoggingHeaders(addVersionControlHeaders(Response.status(Response.Status.BAD_REQUEST)), requestId)
+                .entity(e.getMessage()).build();
         }
     }
 
@@ -255,10 +272,12 @@ public class PolicyStatusControllerV1 extends PapRestControllerV1 {
     }
 
     /**
-     * Queries status of policies in a specific PdpGroup.
+     * Queries status of policies in a specific PdpGroup. if regex is not null or empty, the function will only return
+     * policies that match regex
      *
      * @param pdpGroupName name of the PdpGroup
      * @param requestId request ID used in ONAP logging
+     * @param regex regex for a policy name
      * @return a response
      */
     // @formatter:off
@@ -288,23 +307,29 @@ public class PolicyStatusControllerV1 extends PapRestControllerV1 {
     // @formatter:on
 
     public Response getStatusOfPoliciesByGroup(
-                    @ApiParam(value = "PDP Group Name", required = true) @PathParam("pdpGroupName") String pdpGroupName,
-                    @HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) final UUID requestId) {
+        @ApiParam(value = "PDP Group Name", required = true) @PathParam("pdpGroupName") String pdpGroupName,
+        @HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) final UUID requestId,
+        @ApiParam(value = "Regex for a policy name") @QueryParam("regex") String regex) {
 
         try {
-            Collection<PdpPolicyStatus> result = provider.getPolicyStatus(pdpGroupName);
-            if (result.isEmpty()) {
-                return makeNotFoundResponse(requestId);
-
+            final Collection<PdpPolicyStatus> result;
+            if (regex == null) {
+                result = provider.getPolicyStatus(pdpGroupName);
+            } else if (regex.isBlank()) {
+                return makeRegexNotFoundResponse(requestId);
             } else {
-                return addLoggingHeaders(addVersionControlHeaders(Response.status(Response.Status.OK)), requestId)
-                                .entity(result).build();
+                result = provider.getPolicyStatusByRegex(pdpGroupName, regex);
             }
+            return makeListOrNotFoundResponse(requestId, result);
 
         } catch (PfModelException | PfModelRuntimeException e) {
             logger.warn(GET_DEPLOYMENTS_FAILED, e);
             return addLoggingHeaders(addVersionControlHeaders(Response.status(e.getErrorResponse().getResponseCode())),
                 requestId).entity(e.getErrorResponse().getErrorMessage()).build();
+        } catch (PatternSyntaxException e) {
+            logger.warn(GET_DEPLOYMENTS_FAILED, e);
+            return addLoggingHeaders(addVersionControlHeaders(Response.status(Response.Status.BAD_REQUEST)), requestId)
+                .entity(e.getMessage()).build();
         }
     }
 
@@ -435,4 +460,19 @@ public class PolicyStatusControllerV1 extends PapRestControllerV1 {
         return addLoggingHeaders(addVersionControlHeaders(Response.status(Response.Status.NOT_FOUND)), requestId)
                         .build();
     }
+
+    private Response makeRegexNotFoundResponse(UUID requestId) {
+        logger.warn(GET_DEPLOYMENTS_FAILED + EMPTY_REGEX_WARNING);
+        return addLoggingHeaders(addVersionControlHeaders(Response.status(Response.Status.BAD_REQUEST)),
+            requestId).entity(EMPTY_REGEX_ERROR_MESSAGE).build();
+    }
+
+    private Response makeListOrNotFoundResponse(UUID requestId, Collection<?> result) {
+        if (result.isEmpty()) {
+            return makeNotFoundResponse(requestId);
+        } else {
+            return addLoggingHeaders(addVersionControlHeaders(Response.status(Response.Status.OK)), requestId)
+                .entity(result).build();
+        }
+    }
 }
index 8c96978..1765187 100644 (file)
@@ -4,6 +4,7 @@
  * ================================================================================
  * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
  * Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
+ * Modifications Copyright (C) 2021 Nordix Foundation.
  * ================================================================================
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
 
 package org.onap.policy.pap.main.rest;
 
+import com.google.re2j.Matcher;
+import com.google.re2j.Pattern;
 import java.util.Collection;
+import java.util.List;
 import java.util.stream.Collectors;
 import org.onap.policy.common.utils.services.Registry;
 import org.onap.policy.models.base.PfModelException;
@@ -76,6 +80,28 @@ public class PolicyStatusProvider {
         }
     }
 
+    /**
+     * Gets the deployment status of a policy, returns only statuses, which matches the regex.
+     *
+     * @param patternString policy of interest
+     * @return the deployment status of all policies
+     * @throws PfModelException if a DB error occurs
+     */
+    public Collection<PolicyStatus> getByRegex(String patternString) throws PfModelException {
+        // try to make pattern out of regex
+        final Pattern pattern = Pattern.compile(patternString);
+        // get all the statuses
+        final List<PdpPolicyStatus> policyStatuses;
+        try (PolicyModelsProvider dao = daoFactory.create()) {
+            policyStatuses = dao.getAllPolicyStatus();
+        }
+        // filter out statuses with the wrong name
+        final Collection<PdpPolicyStatus> pdpPolicyStatuses = filterWithPattern(pattern, policyStatuses);
+
+        return accumulate(pdpPolicyStatuses);
+    }
+
+
     /**
      * Accumulates the deployment status of individual PDP/policy pairs into a status for
      * a policy.
@@ -125,7 +151,7 @@ public class PolicyStatusProvider {
      * Gets the status of a policy in a PdpGroup.
      *
      * @param pdpGroupName the pdp group
-     * @param policy the policy
+     * @param policy       the policy
      * @return the deployment status of the policy
      * @throws PfModelException if a DB error occurs
      */
@@ -136,4 +162,35 @@ public class PolicyStatusProvider {
                 .collect(Collectors.toList());
         }
     }
+
+    /**
+     * Gets the status of policies in a PdpGroup that match the given regex.
+     *
+     * @param pdpGroupName  the pdp group
+     * @param patternString regex
+     * @return the deployment status of policies
+     * @throws PfModelException if a DB error occurs
+     */
+    public Collection<PdpPolicyStatus> getPolicyStatusByRegex(String pdpGroupName, String patternString)
+        throws PfModelException {
+        final Pattern pattern = Pattern.compile(patternString);
+        // get all the statuses
+        final Collection<PdpPolicyStatus> policyStatuses = getPolicyStatus(pdpGroupName);
+        // filter out statuses with the wrong name
+        return filterWithPattern(pattern, policyStatuses);
+    }
+
+    private Collection<PdpPolicyStatus> filterWithPattern(Pattern pattern, Collection<PdpPolicyStatus> policyStatuses) {
+        return policyStatuses
+            .stream()
+            .filter(policyStatus -> {
+                // Check policy name
+                final String policyName = policyStatus
+                    .getPolicy()
+                    .getName();
+                final Matcher matcher = pattern.matcher(policyName);
+                return matcher.matches();
+            })
+            .collect(Collectors.toList());
+    }
 }
index 1d0c7aa..fc86fef 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * ============LICENSE_START=======================================================
- *  Copyright (C) 2019 Nordix Foundation.
+ *  Copyright (C) 2019,2021 Nordix Foundation.
  *  Modifications Copyright (C) 2019-2020 AT&T Intellectual Property.
  *  Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
  * ================================================================================
@@ -22,6 +22,7 @@
 
 package org.onap.policy.pap.main.rest;
 
+import static org.assertj.core.api.Assertions.assertThat;
 import static org.junit.Assert.assertEquals;
 
 import javax.ws.rs.client.Invocation;
@@ -54,6 +55,14 @@ public class TestPolicyStatusControllerV1 extends CommonPapRestServer {
 
         // verify it fails when no authorization info is included
         checkUnauthRequest(uri, req -> req.get());
+        checkRequest(POLICY_STATUS_ENDPOINT);
+    }
+
+    @Test
+    public void testQueryAllDeployedPoliciesWithRegex() throws Exception {
+        checkRequest(POLICY_STATUS_ENDPOINT + "?regex=my.(1)name");
+        checkEmptyRegexRequest(POLICY_STATUS_ENDPOINT + "?regex=");
+        checkInvalidRegexRequest(POLICY_STATUS_ENDPOINT + "?regex=my-(name");
     }
 
     @Test
@@ -77,6 +86,16 @@ public class TestPolicyStatusControllerV1 extends CommonPapRestServer {
         checkRequest(POLICY_DEPLOYMENT_STATUS_ENDPOINT + "/my-group-name/my-name/1.2.3");
     }
 
+    @Test
+    public void testGetStatusOfPoliciesWithRegex() throws Exception {
+        checkRequest(POLICY_DEPLOYMENT_STATUS_ENDPOINT + "/my-group-name?regex=my-%3F%5Bmn%5Da.%7B1%7De");
+        checkRequest(POLICY_DEPLOYMENT_STATUS_ENDPOINT + "/my-group-name?regex=my.(1)name");
+        // my-?[mna.{1}e
+        checkInvalidRegexRequest(POLICY_DEPLOYMENT_STATUS_ENDPOINT + "/my-group-name?regex=my-%3F%5Bmna.%7B1%7De");
+        checkInvalidRegexRequest(POLICY_DEPLOYMENT_STATUS_ENDPOINT + "/my-group-name?regex=my.(1name");
+        checkEmptyRegexRequest(POLICY_DEPLOYMENT_STATUS_ENDPOINT + "/my-group-name?regex=");
+    }
+
     private void checkRequest(String uri) throws Exception {
         Invocation.Builder invocationBuilder = sendRequest(uri);
         Response rawresp = invocationBuilder.get();
@@ -85,4 +104,26 @@ public class TestPolicyStatusControllerV1 extends CommonPapRestServer {
         // verify it fails when no authorization info is included
         checkUnauthRequest(uri, req -> req.get());
     }
+
+    private void checkInvalidRegexRequest(String uri) throws Exception {
+        Invocation.Builder invocationBuilder = sendRequest(uri);
+        Response rawresp = invocationBuilder.get();
+        assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), rawresp.getStatus());
+        final String entity = rawresp.readEntity(String.class);
+        assertThat(entity).contains("error parsing regexp");
+
+        // verify it fails when no authorization info is included
+        checkUnauthRequest(uri, req -> req.get());
+    }
+
+    private void checkEmptyRegexRequest(String uri) throws Exception {
+        Invocation.Builder invocationBuilder = sendRequest(uri);
+        Response rawresp = invocationBuilder.get();
+        assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), rawresp.getStatus());
+        final String entity = rawresp.readEntity(String.class);
+        assertThat(entity).contains("empty string passed as a regex");
+
+        // verify it fails when no authorization info is included
+        checkUnauthRequest(uri, req -> req.get());
+    }
 }
index 81ed680..d3ff4ea 100644 (file)
@@ -4,6 +4,7 @@
  * ================================================================================
  * Copyright (C) 2021 AT&T Intellectual Property. All rights reserved.
  * Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
+ * Modifications Copyright (C) 2021 Nordix Foundation.
  * ================================================================================
  * 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,7 @@ import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.when;
 
 import java.util.ArrayList;
+import java.util.Collection;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
@@ -197,6 +199,37 @@ public class TestPolicyStatusProvider extends ProviderSuper {
         assertThat(status.getState()).isEqualTo(State.FAILURE);
     }
 
+    @Test
+    public void testGetPolicyStatusByRegexNoMatch() throws PfModelException {
+        buildPolicyStatusToReturn1();
+        final String pattern = "Hello";
+
+        final Collection<PolicyStatus> actual = prov.getByRegex(pattern);
+        assertThat(actual).isEmpty();
+    }
+
+    @Test
+    public void testGetPolicyStatusOneMatch() throws PfModelException {
+        buildPolicyStatusToReturn1();
+        final String pattern = "My(We|Po)[li]{0,3}c.A";
+
+        final Collection<PolicyStatus> actual = prov.getByRegex(pattern);
+        assertThat(actual).hasSize(1);
+
+        final String actualName = actual.iterator().next().getPolicy().getName();
+        assertThat(actualName).isEqualTo("MyPolicyA");
+    }
+
+    @Test
+    public void testGetPolicyStatusAllMatch() throws PfModelException {
+        buildPolicyStatusToReturn1();
+        final String pattern = "My(We|Po)[li]{0,3}c.{2}0*";
+
+        final Collection<PolicyStatus> actual = prov.getByRegex(pattern);
+
+        assertThat(actual).hasSize(3);
+    }
+
     private void buildPolicyStatusToReturn1() throws PfModelException {
 
         PdpPolicyStatusBuilder builder = PdpPolicyStatus.builder().pdpGroup(MY_GROUP).pdpType(MY_PDP_TYPE)