consolidate Policy Health Check into PAP 93/99193/5
authorHengye <yehui.wang@est.tech>
Wed, 27 Nov 2019 05:43:42 +0000 (13:43 +0800)
committerHengye <yehui.wang@est.tech>
Wed, 11 Dec 2019 03:30:28 +0000 (11:30 +0800)
Issue-ID: POLICY-1689
Change-Id: I3b84094e217c8cda115efdbf3444e92f08013a7c
Signed-off-by: Hengye <yehui.wang@est.tech>
13 files changed:
main/src/main/java/org/onap/policy/pap/main/PapConstants.java
main/src/main/java/org/onap/policy/pap/main/parameters/PapParameterGroup.java
main/src/main/java/org/onap/policy/pap/main/rest/HealthCheckProvider.java
main/src/main/java/org/onap/policy/pap/main/rest/PolicyComponentsHealthCheckControllerV1.java [new file with mode: 0644]
main/src/main/java/org/onap/policy/pap/main/rest/PolicyComponentsHealthCheckProvider.java [new file with mode: 0644]
main/src/main/java/org/onap/policy/pap/main/startstop/PapActivator.java
main/src/test/java/org/onap/policy/pap/main/rest/CommonPapRestServer.java
main/src/test/java/org/onap/policy/pap/main/rest/TestPolicyComponentsHealthCheckControllerV1.java [new file with mode: 0644]
main/src/test/resources/e2e/PapConfigParameters.json
main/src/test/resources/parameters/MinimumParameters.json
main/src/test/resources/parameters/PapConfigParameters.json
main/src/test/resources/parameters/PapConfigParametersStd.json
packages/policy-pap-tarball/src/main/resources/etc/defaultConfig.json

index b8b199e..2acf3e7 100644 (file)
@@ -38,6 +38,12 @@ public class PapConstants {
     public static final String TOPIC_POLICY_PDP_PAP = "POLICY-PDP-PAP";
     public static final String TOPIC_POLICY_NOTIFICATION = "POLICY-NOTIFICATION";
 
+    // policy components names
+    public static final String POLICY_API = "api";
+    public static final String POLICY_DISTRIBUTION = "distribution";
+    public static final String POLICY_PAP = "pap";
+    public static final String POLICY_PDPS = "pdps";
+
     private PapConstants() {
         super();
     }
index ed1b4ad..9a50cf0 100644 (file)
@@ -21,7 +21,9 @@
 
 package org.onap.policy.pap.main.parameters;
 
+import java.util.List;
 import lombok.Getter;
+import org.onap.policy.common.endpoints.event.comm.bus.internal.BusTopicParams;
 import org.onap.policy.common.endpoints.parameters.RestServerParameters;
 import org.onap.policy.common.endpoints.parameters.TopicParameterGroup;
 import org.onap.policy.common.parameters.ParameterGroupImpl;
@@ -42,6 +44,8 @@ public class PapParameterGroup extends ParameterGroupImpl {
     private PdpParameters pdpParameters;
     private PolicyModelsProviderParameters databaseProviderParameters;
     private TopicParameterGroup topicParameterGroup;
+    // API, Distribution Health Check restClient parameters.
+    private List<BusTopicParams> healthCheckRestClientParameters;
 
     /**
      * Create the pap parameter group.
index b585b9d..9d3ad81 100644 (file)
@@ -22,6 +22,7 @@
 package org.onap.policy.pap.main.rest;
 
 import org.onap.policy.common.endpoints.report.HealthCheckReport;
+import org.onap.policy.common.utils.network.NetworkUtil;
 import org.onap.policy.common.utils.services.Registry;
 import org.onap.policy.pap.main.PapConstants;
 import org.onap.policy.pap.main.startstop.PapActivator;
@@ -35,7 +36,7 @@ public class HealthCheckProvider {
 
     private static final String NOT_ALIVE = "not alive";
     private static final String ALIVE = "alive";
-    private static final String URL = "self";
+    private static final String URL = NetworkUtil.getHostname();
     private static final String NAME = "Policy PAP";
 
     /**
diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/PolicyComponentsHealthCheckControllerV1.java b/main/src/main/java/org/onap/policy/pap/main/rest/PolicyComponentsHealthCheckControllerV1.java
new file mode 100644 (file)
index 0000000..8abc09c
--- /dev/null
@@ -0,0 +1,88 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.pap.main.rest;
+
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+import io.swagger.annotations.ApiResponse;
+import io.swagger.annotations.ApiResponses;
+import io.swagger.annotations.Authorization;
+import io.swagger.annotations.Extension;
+import io.swagger.annotations.ExtensionProperty;
+import io.swagger.annotations.ResponseHeader;
+import java.util.Map;
+import java.util.UUID;
+import javax.ws.rs.GET;
+import javax.ws.rs.HeaderParam;
+import javax.ws.rs.Path;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import org.apache.commons.lang3.tuple.Pair;
+
+/**
+ * Class to provide REST end point for PAP component to fetch all policy components, including PAP,
+ * API, Distribution, and PDPs
+ *
+ * @author Yehui Wang (yehui.wang@est.tech)
+ */
+public class PolicyComponentsHealthCheckControllerV1 extends PapRestControllerV1 {
+
+    /**
+     * Returns health status of all Policy components, including PAP, API, Distribution, and PDPs.
+     * Note: a new provider {@link PolicyComponentsHealthCheckProvider} must be created for each
+     * request.
+     *
+     * @param requestId request ID used in ONAP logging
+     * @return a response
+     */
+    // @formatter:off
+    @GET
+    @Path("components/healthcheck")
+    @ApiOperation(value = "Returns health status of all policy components, including PAP, API, Distribution, and PDPs",
+        notes = "Queries health status of all policy components, returning all policy components health status",
+        response = Map.class,
+        tags = {"Policy Administration (PAP) API"},
+        authorizations = @Authorization(value = AUTHORIZATION_TYPE),
+        responseHeaders = {
+            @ResponseHeader(name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
+                            response = String.class),
+            @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
+                            response = String.class),
+            @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
+                            response = String.class),
+            @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
+                            response = UUID.class)},
+        extensions = {@Extension(name = EXTENSION_NAME,
+            properties = {@ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
+                @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)})})
+    @ApiResponses(value = {@ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
+                    @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
+                    @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)})
+    // @formatter:on
+
+    public Response policyComponentsHealthCheck(
+            @HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) final UUID requestId) {
+        final Pair<Status, Map<String, Object>> pair =
+                new PolicyComponentsHealthCheckProvider().fetchPolicyComponentsHealthStatus();
+        return addLoggingHeaders(addVersionControlHeaders(Response.status(pair.getLeft())), requestId)
+                .entity(pair.getRight()).build();
+    }
+}
diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/PolicyComponentsHealthCheckProvider.java b/main/src/main/java/org/onap/policy/pap/main/rest/PolicyComponentsHealthCheckProvider.java
new file mode 100644 (file)
index 0000000..ddcab77
--- /dev/null
@@ -0,0 +1,174 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.pap.main.rest;
+
+import java.net.HttpURLConnection;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.ws.rs.core.Response;
+import javax.ws.rs.core.Response.Status;
+import org.apache.commons.lang3.tuple.Pair;
+import org.onap.policy.common.endpoints.event.comm.bus.internal.BusTopicParams;
+import org.onap.policy.common.endpoints.http.client.HttpClient;
+import org.onap.policy.common.endpoints.http.client.HttpClientConfigException;
+import org.onap.policy.common.endpoints.http.client.HttpClientFactory;
+import org.onap.policy.common.endpoints.http.client.HttpClientFactoryInstance;
+import org.onap.policy.common.endpoints.parameters.RestServerParameters;
+import org.onap.policy.common.endpoints.report.HealthCheckReport;
+import org.onap.policy.common.parameters.ParameterService;
+import org.onap.policy.common.utils.services.Registry;
+import org.onap.policy.models.base.PfModelException;
+import org.onap.policy.models.pdp.concepts.Pdp;
+import org.onap.policy.models.pdp.concepts.PdpGroup;
+import org.onap.policy.models.pdp.concepts.PdpSubGroup;
+import org.onap.policy.models.pdp.enums.PdpHealthStatus;
+import org.onap.policy.models.provider.PolicyModelsProvider;
+import org.onap.policy.pap.main.PapConstants;
+import org.onap.policy.pap.main.PolicyModelsProviderFactoryWrapper;
+import org.onap.policy.pap.main.parameters.PapParameterGroup;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Provider for PAP to fetch health status of all Policy components, including PAP, API,
+ * Distribution, and PDPs. Note: a new provider {@link PolicyComponentsHealthCheckProvider} must be
+ * created for each request.
+ *
+ * @author Yehui Wang (yehui.wang@est.tech)
+ */
+public class PolicyComponentsHealthCheckProvider {
+
+    private static final Logger LOGGER = LoggerFactory.getLogger(PolicyComponentsHealthCheckProvider.class);
+    private static final String PAP_GROUP_PARAMS_NAME = "PapGroup";
+    private static final String HEALTH_STATUS = "healthy";
+    private static final Pattern IP_REPLACEMENT_PATTERN = Pattern.compile("//(\\S+):");
+    private static final String POLICY_PAP_HEALTHCHECK_URI = "/policy/pap/v1/healthcheck";
+    private PapParameterGroup papParameterGroup = ParameterService.get(PAP_GROUP_PARAMS_NAME);
+    private boolean isHealthy = true;
+    private Map<String, Object> result = new HashMap<>();
+
+    /**
+     * Returns health status of all Policy components.
+     *
+     * @return a pair containing the status and the response
+     * @throws PfModelException in case of errors
+     */
+    public Pair<Status, Map<String, Object>> fetchPolicyComponentsHealthStatus() {
+        getHttpClients(papParameterGroup.getHealthCheckRestClientParameters()).parallelStream()
+                .forEach(this::fetchPolicyComponentHealthStatus);
+        HealthCheckReport papReport = new HealthCheckProvider().performHealthCheck();
+        RestServerParameters restServerParameters = papParameterGroup.getRestServerParameters();
+        papReport.setUrl((restServerParameters.isHttps() ? "https://" : "http://") + papReport.getUrl() + ":"
+                + restServerParameters.getPort() + POLICY_PAP_HEALTHCHECK_URI);
+        result.put(PapConstants.POLICY_PAP, papReport);
+        try {
+            Map<String, List<Pdp>> pdpListWithType = fetchPdpsHealthStatus();
+            if (isHealthy && (pdpListWithType.isEmpty() || pdpListWithType.values().stream().flatMap(List::stream)
+                    .anyMatch(pdp -> !PdpHealthStatus.HEALTHY.equals(pdp.getHealthy())))) {
+                isHealthy = false;
+            }
+            result.put(PapConstants.POLICY_PDPS, pdpListWithType);
+        } catch (final PfModelException exp) {
+            result.put(PapConstants.POLICY_PDPS, exp.getErrorResponse());
+            isHealthy = false;
+        }
+        result.put(HEALTH_STATUS, isHealthy);
+        LOGGER.debug("Policy Components HealthCheck Response - {}", result);
+        return Pair.of(Response.Status.OK, result);
+    }
+
+    private Map<String, List<Pdp>> fetchPdpsHealthStatus() throws PfModelException {
+        Map<String, List<Pdp>> pdpListWithType = new HashMap<>();
+        final PolicyModelsProviderFactoryWrapper modelProviderWrapper =
+                Registry.get(PapConstants.REG_PAP_DAO_FACTORY, PolicyModelsProviderFactoryWrapper.class);
+        try (PolicyModelsProvider databaseProvider = modelProviderWrapper.create()) {
+            final List<PdpGroup> groups = databaseProvider.getPdpGroups(null);
+            for (final PdpGroup group : groups) {
+                for (final PdpSubGroup subGroup : group.getPdpSubgroups()) {
+                    List<Pdp> pdpList = new ArrayList<>(subGroup.getPdpInstances());
+                    pdpListWithType.computeIfAbsent(subGroup.getPdpType(), k -> new ArrayList<>()).addAll(pdpList);
+                }
+            }
+        }
+        return pdpListWithType;
+    }
+
+    private List<HttpClient> getHttpClients(List<BusTopicParams> restClientParameters) {
+        HttpClientFactory clientFactory = HttpClientFactoryInstance.getClientFactory();
+        for (BusTopicParams params : restClientParameters) {
+            try {
+                params.setManaged(true);
+                clientFactory.build(params);
+            } catch (HttpClientConfigException e) {
+                LOGGER.warn("{} httpClient creation error", params.getClientName());
+                String url = (params.isUseHttps() ? "https://" : "http://") + params.getHostname() + ":"
+                        + params.getPort() + "/" + params.getBasePath();
+                storeUnHealthCheckReport(params.getClientName(), url, HttpURLConnection.HTTP_BAD_REQUEST,
+                        e.getMessage());
+            }
+        }
+        return clientFactory.inventory();
+    }
+
+    private void fetchPolicyComponentHealthStatus(HttpClient httpClient) {
+        try {
+            Response resp = httpClient.get();
+            if (resp.getStatus() != HttpURLConnection.HTTP_OK) {
+                isHealthy = false;
+                result.put(httpClient.getName(),
+                        replaceIpWithHostname(resp.readEntity(HealthCheckReport.class), httpClient.getBaseUrl()));
+            } else {
+                result.put(httpClient.getName(),
+                        replaceIpWithHostname(resp.readEntity(HealthCheckReport.class), httpClient.getBaseUrl()));
+            }
+        } catch (RuntimeException e) {
+            LOGGER.warn("{} connection error", httpClient.getName());
+            storeUnHealthCheckReport(httpClient.getName(), httpClient.getBaseUrl(),
+                    HttpURLConnection.HTTP_INTERNAL_ERROR, e.getMessage());
+        }
+    }
+
+
+    private void storeUnHealthCheckReport(String name, String url, int code, String message) {
+        HealthCheckReport report = new HealthCheckReport();
+        report.setName(name);
+        report.setUrl(url);
+        report.setHealthy(false);
+        isHealthy = false;
+        report.setCode(code);
+        report.setMessage(message);
+        result.put(name, report);
+    }
+
+    private HealthCheckReport replaceIpWithHostname(HealthCheckReport report, String baseUrl) {
+        Matcher matcher = IP_REPLACEMENT_PATTERN.matcher(baseUrl);
+        String ip = "";
+        if (matcher.find()) {
+            ip = matcher.group(1);
+            report.setUrl(baseUrl.replace(ip, report.getUrl()));
+        }
+        return report;
+    }
+}
index 1721cb0..83b9151 100644 (file)
@@ -56,6 +56,7 @@ import org.onap.policy.pap.main.rest.PdpGroupDeployControllerV1;
 import org.onap.policy.pap.main.rest.PdpGroupHealthCheckControllerV1;
 import org.onap.policy.pap.main.rest.PdpGroupQueryControllerV1;
 import org.onap.policy.pap.main.rest.PdpGroupStateChangeControllerV1;
+import org.onap.policy.pap.main.rest.PolicyComponentsHealthCheckControllerV1;
 import org.onap.policy.pap.main.rest.PolicyStatusControllerV1;
 import org.onap.policy.pap.main.rest.PolicyUndeployerImpl;
 import org.onap.policy.pap.main.rest.StatisticsRestControllerV1;
@@ -246,7 +247,8 @@ public class PapActivator extends ServiceManagerContainer {
                                 PdpGroupStateChangeControllerV1.class,
                                 PdpGroupQueryControllerV1.class,
                                 PdpGroupHealthCheckControllerV1.class,
-                                PolicyStatusControllerV1.class);
+                                PolicyStatusControllerV1.class,
+                                PolicyComponentsHealthCheckControllerV1.class);
                 restServer.set(server);
                 restServer.get().start();
             },
index 8660d00..3823365 100644 (file)
@@ -72,7 +72,7 @@ public class CommonPapRestServer {
 
     public static final String NOT_ALIVE = "not alive";
     public static final String ALIVE = "alive";
-    public static final String SELF = "self";
+    public static final String SELF = NetworkUtil.getHostname();
     public static final String NAME = "Policy PAP";
     public static final String ENDPOINT_PREFIX = "policy/pap/v1/";
 
diff --git a/main/src/test/java/org/onap/policy/pap/main/rest/TestPolicyComponentsHealthCheckControllerV1.java b/main/src/test/java/org/onap/policy/pap/main/rest/TestPolicyComponentsHealthCheckControllerV1.java
new file mode 100644 (file)
index 0000000..f73178b
--- /dev/null
@@ -0,0 +1,38 @@
+/*-
+ * ============LICENSE_START=======================================================
+ *  Copyright (C) 2019 Nordix Foundation.
+ * ================================================================================
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ * ============LICENSE_END=========================================================
+ */
+
+package org.onap.policy.pap.main.rest;
+
+import org.junit.Test;
+
+/**
+ * Class to perform unit test of {@link PolicyComponentsHealthCheckControllerV1}.
+ *
+ * @author Yehui Wang (yehui.wang@est.tech)
+ */
+public class TestPolicyComponentsHealthCheckControllerV1 extends CommonPapRestServer {
+
+    private static final String ENDPOINT = "components/healthcheck";
+
+    @Test
+    public void testSwagger() throws Exception {
+        super.testSwagger(ENDPOINT);
+    }
+}
index 17507bd..610ded8 100644 (file)
             "servers" : [ "message-router" ],
             "topicCommInfrastructure" : "noop"
         }]
-    }
+    },
+    "healthCheckRestClientParameters":[{
+        "clientName": "api",
+        "hostname": "policy-api",
+        "port": 6969,
+        "userName": "healthcheck",
+        "password": "zb!XztG34",
+        "useHttps": true,
+        "basePath": "policy/api/v1/healthcheck"
+    },
+    {
+        "clientName": "distribution",
+        "hostname": "policy-distribution",
+        "port": 6969,
+        "userName": "healthcheck",
+        "password": "zb!XztG34",
+        "useHttps": true,
+        "basePath": "healthcheck"
+    }]
 }
index 6b21b4d..69492e9 100644 (file)
             "servers" : [ "message-router" ],
             "topicCommInfrastructure" : "dmaap"
         }]
-    }
+    },
+    "healthCheckRestClientParameters":[{
+        "clientName": "api",
+        "hostname": "policy-api",
+        "port": 6969,
+        "userName": "healthcheck",
+        "password": "zb!XztG34",
+        "useHttps": true,
+        "basePath": "policy/api/v1/healthcheck"
+    },
+    {
+        "clientName": "distribution",
+        "hostname": "policy-distribution",
+        "port": 6969,
+        "userName": "healthcheck",
+        "password": "zb!XztG34",
+        "useHttps": true,
+        "basePath": "healthcheck"
+    }]
 }
index 1131502..111a635 100644 (file)
             "servers" : [ "message-router" ],
             "topicCommInfrastructure" : "noop"
         }]
-    }
+    },
+    "healthCheckRestClientParameters":[{
+        "clientName": "api",
+        "hostname": "policy-api",
+        "port": 6969,
+        "userName": "healthcheck",
+        "password": "zb!XztG34",
+        "useHttps": true,
+        "basePath": "policy/api/v1/healthcheck"
+    },
+    {
+        "clientName": "distribution",
+        "hostname": "policy-distribution",
+        "port": 6969,
+        "userName": "healthcheck",
+        "password": "zb!XztG34",
+        "useHttps": true,
+        "basePath": "healthcheck"
+    }]
 }
index 828c1a4..47925df 100644 (file)
             "servers" : [ "message-router" ],
             "topicCommInfrastructure" : "noop"
         }]
-    }
+    },
+    "healthCheckRestClientParameters":[{
+        "clientName": "api",
+        "hostname": "policy-api",
+        "port": 6969,
+        "userName": "healthcheck",
+        "password": "zb!XztG34",
+        "useHttps": true,
+        "basePath": "policy/api/v1/healthcheck"
+    },
+    {
+        "clientName": "distribution",
+        "hostname": "policy-distribution",
+        "port": 6969,
+        "userName": "healthcheck",
+        "password": "zb!XztG34",
+        "useHttps": true,
+        "basePath": "healthcheck"
+    }]
 }
index 995a3ce..173b201 100644 (file)
             "servers" : [ "message-router" ],
             "topicCommInfrastructure" : "dmaap"
         }]
-    }
+    },
+    "healthCheckRestClientParameters":[{
+        "clientName": "api",
+        "hostname": "policy-api",
+        "port": 6969,
+        "userName": "healthcheck",
+        "password": "zb!XztG34",
+        "useHttps": true,
+        "basePath": "policy/api/v1/healthcheck"
+    },
+    {
+        "clientName": "distribution",
+        "hostname": "policy-distribution",
+        "port": 6969,
+        "userName": "healthcheck",
+        "password": "zb!XztG34",
+        "useHttps": true,
+        "basePath": "healthcheck"
+    }]
 }