diff options
13 files changed, 411 insertions, 8 deletions
diff --git a/main/src/main/java/org/onap/policy/pap/main/PapConstants.java b/main/src/main/java/org/onap/policy/pap/main/PapConstants.java index b8b199e6..2acf3e72 100644 --- a/main/src/main/java/org/onap/policy/pap/main/PapConstants.java +++ b/main/src/main/java/org/onap/policy/pap/main/PapConstants.java @@ -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(); } diff --git a/main/src/main/java/org/onap/policy/pap/main/parameters/PapParameterGroup.java b/main/src/main/java/org/onap/policy/pap/main/parameters/PapParameterGroup.java index ed1b4adc..9a50cf0f 100644 --- a/main/src/main/java/org/onap/policy/pap/main/parameters/PapParameterGroup.java +++ b/main/src/main/java/org/onap/policy/pap/main/parameters/PapParameterGroup.java @@ -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. diff --git a/main/src/main/java/org/onap/policy/pap/main/rest/HealthCheckProvider.java b/main/src/main/java/org/onap/policy/pap/main/rest/HealthCheckProvider.java index b585b9d2..9d3ad816 100644 --- a/main/src/main/java/org/onap/policy/pap/main/rest/HealthCheckProvider.java +++ b/main/src/main/java/org/onap/policy/pap/main/rest/HealthCheckProvider.java @@ -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 index 00000000..8abc09cd --- /dev/null +++ b/main/src/main/java/org/onap/policy/pap/main/rest/PolicyComponentsHealthCheckControllerV1.java @@ -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 index 00000000..ddcab778 --- /dev/null +++ b/main/src/main/java/org/onap/policy/pap/main/rest/PolicyComponentsHealthCheckProvider.java @@ -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; + } +} diff --git a/main/src/main/java/org/onap/policy/pap/main/startstop/PapActivator.java b/main/src/main/java/org/onap/policy/pap/main/startstop/PapActivator.java index 1721cb0d..83b9151c 100644 --- a/main/src/main/java/org/onap/policy/pap/main/startstop/PapActivator.java +++ b/main/src/main/java/org/onap/policy/pap/main/startstop/PapActivator.java @@ -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(); }, diff --git a/main/src/test/java/org/onap/policy/pap/main/rest/CommonPapRestServer.java b/main/src/test/java/org/onap/policy/pap/main/rest/CommonPapRestServer.java index 8660d005..3823365b 100644 --- a/main/src/test/java/org/onap/policy/pap/main/rest/CommonPapRestServer.java +++ b/main/src/test/java/org/onap/policy/pap/main/rest/CommonPapRestServer.java @@ -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 index 00000000..f73178b7 --- /dev/null +++ b/main/src/test/java/org/onap/policy/pap/main/rest/TestPolicyComponentsHealthCheckControllerV1.java @@ -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); + } +} diff --git a/main/src/test/resources/e2e/PapConfigParameters.json b/main/src/test/resources/e2e/PapConfigParameters.json index 17507bdb..610ded8c 100644 --- a/main/src/test/resources/e2e/PapConfigParameters.json +++ b/main/src/test/resources/e2e/PapConfigParameters.json @@ -42,5 +42,23 @@ "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" + }] } diff --git a/main/src/test/resources/parameters/MinimumParameters.json b/main/src/test/resources/parameters/MinimumParameters.json index 6b21b4dc..69492e9b 100644 --- a/main/src/test/resources/parameters/MinimumParameters.json +++ b/main/src/test/resources/parameters/MinimumParameters.json @@ -37,5 +37,23 @@ "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" + }] } diff --git a/main/src/test/resources/parameters/PapConfigParameters.json b/main/src/test/resources/parameters/PapConfigParameters.json index 11315029..111a6352 100644 --- a/main/src/test/resources/parameters/PapConfigParameters.json +++ b/main/src/test/resources/parameters/PapConfigParameters.json @@ -42,5 +42,23 @@ "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" + }] } diff --git a/main/src/test/resources/parameters/PapConfigParametersStd.json b/main/src/test/resources/parameters/PapConfigParametersStd.json index 828c1a44..47925dff 100644 --- a/main/src/test/resources/parameters/PapConfigParametersStd.json +++ b/main/src/test/resources/parameters/PapConfigParametersStd.json @@ -42,5 +42,23 @@ "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" + }] } diff --git a/packages/policy-pap-tarball/src/main/resources/etc/defaultConfig.json b/packages/policy-pap-tarball/src/main/resources/etc/defaultConfig.json index 995a3cec..173b2017 100644 --- a/packages/policy-pap-tarball/src/main/resources/etc/defaultConfig.json +++ b/packages/policy-pap-tarball/src/main/resources/etc/defaultConfig.json @@ -44,5 +44,23 @@ "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" + }] } |