From be8c2967de20d71203f07049d4071c7521d27026 Mon Sep 17 00:00:00 2001 From: "arkadiusz.adamski" Date: Tue, 13 Apr 2021 11:23:28 +0100 Subject: Query deployed policies by regex - Query deployed policies by regex on the name, for a given policy type Issue-ID: POLICY-2535 Signed-off-by: arkadiusz.adamski Change-Id: Ia2be683d044b22e4104ae14e2ce301882091c8ea --- .../pap/main/rest/PolicyStatusControllerV1.java | 68 +++++++++++++++++----- .../policy/pap/main/rest/PolicyStatusProvider.java | 59 ++++++++++++++++++- .../main/rest/TestPolicyStatusControllerV1.java | 43 +++++++++++++- .../pap/main/rest/TestPolicyStatusProvider.java | 33 +++++++++++ 4 files changed, 187 insertions(+), 16 deletions(-) diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/PolicyStatusControllerV1.java b/main/src/main/java/org/onap/policy/pap/main/rest/PolicyStatusControllerV1.java index 055e129e..d6388a51 100644 --- a/main/src/main/java/org/onap/policy/pap/main/rest/PolicyStatusControllerV1.java +++ b/main/src/main/java/org/onap/policy/pap/main/rest/PolicyStatusControllerV1.java @@ -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 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 result = provider.getPolicyStatus(pdpGroupName); - if (result.isEmpty()) { - return makeNotFoundResponse(requestId); - + final Collection 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(); + } + } } diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/PolicyStatusProvider.java b/main/src/main/java/org/onap/policy/pap/main/rest/PolicyStatusProvider.java index 8c969782..17651875 100644 --- a/main/src/main/java/org/onap/policy/pap/main/rest/PolicyStatusProvider.java +++ b/main/src/main/java/org/onap/policy/pap/main/rest/PolicyStatusProvider.java @@ -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. @@ -21,7 +22,10 @@ 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 getByRegex(String patternString) throws PfModelException { + // try to make pattern out of regex + final Pattern pattern = Pattern.compile(patternString); + // get all the statuses + final List policyStatuses; + try (PolicyModelsProvider dao = daoFactory.create()) { + policyStatuses = dao.getAllPolicyStatus(); + } + // filter out statuses with the wrong name + final Collection 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 getPolicyStatusByRegex(String pdpGroupName, String patternString) + throws PfModelException { + final Pattern pattern = Pattern.compile(patternString); + // get all the statuses + final Collection policyStatuses = getPolicyStatus(pdpGroupName); + // filter out statuses with the wrong name + return filterWithPattern(pattern, policyStatuses); + } + + private Collection filterWithPattern(Pattern pattern, Collection 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()); + } } diff --git a/main/src/test/java/org/onap/policy/pap/main/rest/TestPolicyStatusControllerV1.java b/main/src/test/java/org/onap/policy/pap/main/rest/TestPolicyStatusControllerV1.java index 1d0c7aa7..fc86fef1 100644 --- a/main/src/test/java/org/onap/policy/pap/main/rest/TestPolicyStatusControllerV1.java +++ b/main/src/test/java/org/onap/policy/pap/main/rest/TestPolicyStatusControllerV1.java @@ -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()); + } } diff --git a/main/src/test/java/org/onap/policy/pap/main/rest/TestPolicyStatusProvider.java b/main/src/test/java/org/onap/policy/pap/main/rest/TestPolicyStatusProvider.java index 81ed6805..d3ff4ea6 100644 --- a/main/src/test/java/org/onap/policy/pap/main/rest/TestPolicyStatusProvider.java +++ b/main/src/test/java/org/onap/policy/pap/main/rest/TestPolicyStatusProvider.java @@ -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 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 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 actual = prov.getByRegex(pattern); + + assertThat(actual).hasSize(3); + } + private void buildPolicyStatusToReturn1() throws PfModelException { PdpPolicyStatusBuilder builder = PdpPolicyStatus.builder().pdpGroup(MY_GROUP).pdpType(MY_PDP_TYPE) -- cgit 1.2.3-korg