diff options
author | 2020-02-25 09:15:58 +0800 | |
---|---|---|
committer | 2020-03-03 09:26:05 +0800 | |
commit | 7fa12fdd8d4428a8b21ad143943858a1ca2e0e27 (patch) | |
tree | 770f902b866e426776a5b450c431ae1799c48a7f /gui-pdp-monitoring/src/main/java | |
parent | fd7eb2d478674ae0922abee899d784441c7f3487 (diff) |
Create PDP Monitoring GUI Model
Monitorning GUI to monitor PDPs Statistics, including
Web and Rest Server by embeded jetty.
Issue-ID: POLICY-2311
Signed-off-by: Hengye <yehui.wang@est.tech>
Change-Id: I9bd0d50eaa7ae4dbd07d17389da2cf107e854c61
Diffstat (limited to 'gui-pdp-monitoring/src/main/java')
9 files changed, 912 insertions, 0 deletions
diff --git a/gui-pdp-monitoring/src/main/java/org/onap/policy/gui/pdp/monitoring/PdpMonitoringMain.java b/gui-pdp-monitoring/src/main/java/org/onap/policy/gui/pdp/monitoring/PdpMonitoringMain.java new file mode 100644 index 0000000..34b2901 --- /dev/null +++ b/gui-pdp-monitoring/src/main/java/org/onap/policy/gui/pdp/monitoring/PdpMonitoringMain.java @@ -0,0 +1,170 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 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.gui.pdp.monitoring; + +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import lombok.Getter; +import lombok.ToString; +import org.onap.policy.common.parameters.ValidationResult; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The main class for Pdp Statistics Monitoring. + * + * @author Yehui Wang (yehui.wang@est.tech) + */ +@ToString +public class PdpMonitoringMain { + // Logger for this class + private static final Logger LOGGER = LoggerFactory.getLogger(PdpMonitoringMain.class); + + // Recurring string constants + private static final String PDP_MONITORING_PREFIX = "Pdp Monitoring GUI ("; + + // Services state + public enum ServicesState { + STOPPED, READY, INITIALIZING, RUNNING + } + + @Getter + private ServicesState state = ServicesState.STOPPED; + + // The parameters for the Server + private PdpMonitoringServerParameters parameters = null; + + // The Pdp Monitoring services this class is running + private PdpMonitoringServer pdpMonitoringServer = null; + + private CountDownLatch countDownLatch = new CountDownLatch(1); + + /** + * Constructor, kicks off the GUI service. + * + * @param args The command line arguments for the RESTful service + */ + public PdpMonitoringMain(final String[] args) { + + // Server parameter parsing + final PdpMonitoringServerParameterParser parser = new PdpMonitoringServerParameterParser(); + + try { + // Get and check the parameters + parameters = parser.parse(args); + } catch (final PdpMonitoringServerParameterException e) { + throw new PdpMonitoringServerParameterException(PDP_MONITORING_PREFIX + this + ") parameter error, " + + e.getMessage() + '\n' + parser.getHelp(PdpMonitoringMain.class.getName()), e); + } + + if (parameters.isHelpSet()) { + throw new PdpMonitoringServerParameterException(parser.getHelp(PdpMonitoringMain.class.getName())); + } + + // Validate the parameters + final ValidationResult validationResult = parameters.validate(); + if (!validationResult.isValid()) { + throw new PdpMonitoringServerParameterException( + PDP_MONITORING_PREFIX + this + ") parameters invalid, " + validationResult.getResult() + '\n' + + parser.getHelp(PdpMonitoringMain.class.getName())); + } + + state = ServicesState.READY; + } + + /** + * Initialize the rest service. + */ + public void init() { + LOGGER.info(PDP_MONITORING_PREFIX + "{}) starting at {} . . .", this, parameters.getBaseUri()); + + try { + state = ServicesState.INITIALIZING; + + // Start the Pdp Monitoring service + pdpMonitoringServer = new PdpMonitoringServer(parameters); + + // Add a shutdown hook to shut down the servlet services when the process is exiting + Runtime.getRuntime().addShutdownHook(new Thread(new PdpServicesShutdownHook())); + + state = ServicesState.RUNNING; + + if (parameters.getTimeToLive() == PdpMonitoringServerParameters.INFINITY_TIME_TO_LIVE) { + LOGGER.info(PDP_MONITORING_PREFIX + "{}) starting at {} . . .", this, parameters.getTimeToLive()); + } else { + LOGGER.info(PDP_MONITORING_PREFIX + "{}) started", this); + } + + // Find out how long is left to wait + long timeRemaining = parameters.getTimeToLive(); + if (timeRemaining >= 0) { + countDownLatch.await(timeRemaining, TimeUnit.SECONDS); + } else { + countDownLatch.await(); + } + } catch (final Exception e) { + LOGGER.warn(this + " failed with error", e); + } finally { + shutdown(); + } + + } + + /** + * Explicitly shut down the services. + */ + public void shutdown() { + if (pdpMonitoringServer != null) { + LOGGER.info(PDP_MONITORING_PREFIX + "{}) shutting down", this); + pdpMonitoringServer.shutdown(parameters.getPort(), parameters.getDefaultRestPort()); + } + countDownLatch.countDown(); + state = ServicesState.STOPPED; + LOGGER.info(PDP_MONITORING_PREFIX + "{}) shutting down", this); + } + + /** + * This class is a shutdown hook for the Pdp services command. + */ + private class PdpServicesShutdownHook implements Runnable { + /** + * {@inheritDoc}. + */ + @Override + public void run() { + shutdown(); + } + } + + /** + * Main method, main entry point for command. + * + * @param args The command line arguments for the GUI + */ + public static void main(final String[] args) { + try { + final PdpMonitoringMain main = new PdpMonitoringMain(args); + main.init(); + } catch (final Exception e) { + LOGGER.error("start failed", e); + } + } +} diff --git a/gui-pdp-monitoring/src/main/java/org/onap/policy/gui/pdp/monitoring/PdpMonitoringServer.java b/gui-pdp-monitoring/src/main/java/org/onap/policy/gui/pdp/monitoring/PdpMonitoringServer.java new file mode 100644 index 0000000..97d2deb --- /dev/null +++ b/gui-pdp-monitoring/src/main/java/org/onap/policy/gui/pdp/monitoring/PdpMonitoringServer.java @@ -0,0 +1,92 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 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.gui.pdp.monitoring; + +import lombok.NonNull; +import org.eclipse.jetty.servlets.CrossOriginFilter; +import org.onap.policy.common.endpoints.http.server.HttpServletServer; +import org.onap.policy.common.endpoints.http.server.HttpServletServerFactoryInstance; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class is used to launch the services. It creates a Jetty embedded web server and runs the + * services. + * + * @author Yehui Wang (yehui.wang@est.tech) + */ +public class PdpMonitoringServer { + // Logger for this class + private static final Logger LOGGER = LoggerFactory.getLogger(PdpMonitoringServer.class); + + // The HTTP server exposing JAX-RS resources defined in this application. + private HttpServletServer jerseyServer; + + // The HTTP server exposing static resources defined in this application. + private HttpServletServer staticResourceServer; + + /** + * Starts the HTTP server for the Pdp statistics monitoring on the default base URI and with the + * default REST packages. + */ + public PdpMonitoringServer() { + this(new PdpMonitoringServerParameters()); + } + + /** + * Starts the HTTP server for the Pdp statistics monitoring GUI. + * + * @param parameters The Pdp parameters to use to start the server. + * @return + */ + public PdpMonitoringServer(@NonNull final PdpMonitoringServerParameters parameters) { + + LOGGER.debug("Pdp Monitoring starting . . ."); + + jerseyServer = HttpServletServerFactoryInstance.getServerFactory().build("PDP Monitoring Rest Server", false, + parameters.getServerHost(), parameters.getDefaultRestPort(), parameters.getContextPath(), false, true); + jerseyServer.addServletPackage(parameters.getDefaultRestPath(), parameters.getRestPackage()); + jerseyServer.addFilterClass(parameters.getDefaultRestPath(), CrossOriginFilter.class.getName()); + jerseyServer.start(); + + staticResourceServer = HttpServletServerFactoryInstance.getServerFactory().buildStaticResourceServer( + "PDP Monitoring Html Server", false, parameters.getServerHost(), parameters.getPort(), + parameters.getContextPath(), true); + staticResourceServer.addServletResource(null, + PdpMonitoringServer.class.getClassLoader().getResource("webapp").toExternalForm()); + staticResourceServer.start(); + + LOGGER.debug("Pdp Monitoring started"); + } + + /** + * Shut down the web server. + * + * @param htmlPort port number of static resource server + * @param restPort port number of jersey server + */ + public void shutdown(int htmlPort, int restPort) { + LOGGER.debug("Pdp Monitoring . . ."); + HttpServletServerFactoryInstance.getServerFactory().destroy(htmlPort); + HttpServletServerFactoryInstance.getServerFactory().destroy(restPort); + LOGGER.debug("Pdp Monitoring shut down"); + } +} diff --git a/gui-pdp-monitoring/src/main/java/org/onap/policy/gui/pdp/monitoring/PdpMonitoringServerParameterException.java b/gui-pdp-monitoring/src/main/java/org/onap/policy/gui/pdp/monitoring/PdpMonitoringServerParameterException.java new file mode 100644 index 0000000..8977d33 --- /dev/null +++ b/gui-pdp-monitoring/src/main/java/org/onap/policy/gui/pdp/monitoring/PdpMonitoringServerParameterException.java @@ -0,0 +1,47 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 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.gui.pdp.monitoring; + +/** + * A run time exception used to report parsing and parameter input errors. + */ +public class PdpMonitoringServerParameterException extends IllegalArgumentException { + private static final long serialVersionUID = 6520231162404452427L; + + /** + * Create an PdpMonitoringServerParameterException with a message. + * + * @param message the message + */ + public PdpMonitoringServerParameterException(final String message) { + super(message); + } + + /** + * Create an PdpMonitoringServerParameterException with a message and an exception. + * + * @param message the message + * @param throwable The exception that caused the exception + */ + public PdpMonitoringServerParameterException(final String message, final Throwable throwable) { + super(message, throwable); + } +} diff --git a/gui-pdp-monitoring/src/main/java/org/onap/policy/gui/pdp/monitoring/PdpMonitoringServerParameterParser.java b/gui-pdp-monitoring/src/main/java/org/onap/policy/gui/pdp/monitoring/PdpMonitoringServerParameterParser.java new file mode 100644 index 0000000..5d9d290 --- /dev/null +++ b/gui-pdp-monitoring/src/main/java/org/onap/policy/gui/pdp/monitoring/PdpMonitoringServerParameterParser.java @@ -0,0 +1,113 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 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.gui.pdp.monitoring; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Arrays; +import org.apache.commons.cli.CommandLine; +import org.apache.commons.cli.DefaultParser; +import org.apache.commons.cli.HelpFormatter; +import org.apache.commons.cli.Option; +import org.apache.commons.cli.Options; +import org.apache.commons.cli.ParseException; + +/** + * This class reads and handles command line parameters to the Pdp Statistics services. + * + * @author Yehui Wang (yehui.wang@est.tech) + */ +public class PdpMonitoringServerParameterParser { + // Apache Commons CLI options + private final Options options; + + /** + * Construct the options for the Pdp monitoring services. + */ + public PdpMonitoringServerParameterParser() { + options = new Options(); + options.addOption("h", "help", false, "outputs the usage of this command"); + options.addOption(Option.builder("p").longOpt("port").desc("port to use for the Pdp Services REST calls") + .hasArg().argName("PORT").required(false).type(Number.class).build()); + options.addOption(Option.builder("t").longOpt("time-to-live") + .desc("the amount of time in seconds that the server will run for before terminating").hasArg() + .argName("TIME_TO_LIVE").required(false).type(Number.class).build()); + } + + /** + * Parse the command line options. + * + * @param args the arguments + * @return parsed parameters + */ + public PdpMonitoringServerParameters parse(final String[] args) { + CommandLine commandLine = null; + try { + commandLine = new DefaultParser().parse(options, args); + } catch (final ParseException e) { + throw new PdpMonitoringServerParameterException("invalid command line arguments specified", e); + } + + final PdpMonitoringServerParameters parameters = new PdpMonitoringServerParameters(); + final String[] remainingArgs = commandLine.getArgs(); + + if (commandLine.getArgs().length > 0) { + throw new PdpMonitoringServerParameterException( + "too many command line arguments specified : " + Arrays.toString(remainingArgs)); + } + + if (commandLine.hasOption('h')) { + parameters.setHelpSet(true); + } + try { + if (commandLine.hasOption('p')) { + parameters.setPort(((Number) commandLine.getParsedOptionValue("port")).intValue()); + } + } catch (final ParseException e) { + throw new PdpMonitoringServerParameterException("error parsing argument \"port\"", e); + } + try { + if (commandLine.hasOption('t')) { + parameters.setTimeToLive(((Number) commandLine.getParsedOptionValue("time-to-live")).longValue()); + } + } catch (final ParseException e) { + throw new PdpMonitoringServerParameterException("error parsing argument \"time-to-live\"", e); + } + + return parameters; + } + + /** + * Get help information. + * + * @param mainClassName the main class name for the help output + * @return help string + */ + public String getHelp(final String mainClassName) { + final StringWriter stringWriter = new StringWriter(); + final PrintWriter stringPrintWriter = new PrintWriter(stringWriter); + + final HelpFormatter helpFormatter = new HelpFormatter(); + helpFormatter.printHelp(stringPrintWriter, 120, mainClassName + " [options...] ", "", options, 0, 0, ""); + + return stringWriter.toString(); + } +} diff --git a/gui-pdp-monitoring/src/main/java/org/onap/policy/gui/pdp/monitoring/PdpMonitoringServerParameters.java b/gui-pdp-monitoring/src/main/java/org/onap/policy/gui/pdp/monitoring/PdpMonitoringServerParameters.java new file mode 100644 index 0000000..614d47d --- /dev/null +++ b/gui-pdp-monitoring/src/main/java/org/onap/policy/gui/pdp/monitoring/PdpMonitoringServerParameters.java @@ -0,0 +1,95 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 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.gui.pdp.monitoring; + +import java.net.URI; +import lombok.Getter; +import lombok.Setter; +import lombok.ToString; +import org.onap.policy.common.parameters.BeanValidator; +import org.onap.policy.common.parameters.ValidationResult; +import org.onap.policy.common.parameters.annotations.Max; +import org.onap.policy.common.parameters.annotations.Min; + +/** + * This class reads and handles command line parameters to the Pdp Monitoring services. + * + * @author Yehui Wang (yehui.wang@est.tech) + */ +@ToString +@Getter +@Setter +public class PdpMonitoringServerParameters { + public static final int DEFAULT_PORT = 18999; + public static final int INFINITY_TIME_TO_LIVE = -1; + + // Base URI the HTTP server will listen on + private static final String DEFAULT_SERVER_URI_ROOT = "http://0.0.0.0:"; + private static final String DEFAULT_REST_PATH = "/papservices/*"; + private static final String DEFAULT_CONTEXT_PATH = "/"; + private static final String SERVER_HOST = "0.0.0.0"; + private static final int DEFAULT_REST_PORT = 17999; + // Package that will field REST requests + private static final String DEFAULT_REST_PACKAGE = "org.onap.policy.gui.pdp.monitoring.rest"; + + // The services parameters + private boolean helpSet = false; + + @Min(1024) + @Max(65534) + private int port = DEFAULT_PORT; + + @Min(-1) + private long timeToLive = INFINITY_TIME_TO_LIVE; + + /** + * Validate the parameters. + * + * @return the result of the validation + */ + public ValidationResult validate() { + return new BeanValidator().validateTop(PdpMonitoringServerParameters.class.getSimpleName(), this); + } + + public URI getBaseUri() { + return URI.create(DEFAULT_SERVER_URI_ROOT + port + DEFAULT_REST_PATH); + } + + public String getRestPackage() { + return DEFAULT_REST_PACKAGE; + } + + public String getContextPath() { + return DEFAULT_CONTEXT_PATH; + } + + public String getServerHost() { + return SERVER_HOST; + } + + public String getDefaultRestPath() { + return DEFAULT_REST_PATH; + } + + public int getDefaultRestPort() { + return DEFAULT_REST_PORT; + } +} diff --git a/gui-pdp-monitoring/src/main/java/org/onap/policy/gui/pdp/monitoring/package-info.java b/gui-pdp-monitoring/src/main/java/org/onap/policy/gui/pdp/monitoring/package-info.java new file mode 100644 index 0000000..d1595b8 --- /dev/null +++ b/gui-pdp-monitoring/src/main/java/org/onap/policy/gui/pdp/monitoring/package-info.java @@ -0,0 +1,27 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 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========================================================= + */ + +/** + * Implements the PDP monitoring GUI. + * + * @author Yehui Wang (yehui.wang@est.tech) + */ + +package org.onap.policy.gui.pdp.monitoring; diff --git a/gui-pdp-monitoring/src/main/java/org/onap/policy/gui/pdp/monitoring/rest/EngineStatus.java b/gui-pdp-monitoring/src/main/java/org/onap/policy/gui/pdp/monitoring/rest/EngineStatus.java new file mode 100644 index 0000000..5d2d38a --- /dev/null +++ b/gui-pdp-monitoring/src/main/java/org/onap/policy/gui/pdp/monitoring/rest/EngineStatus.java @@ -0,0 +1,43 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 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.gui.pdp.monitoring.rest; + +import lombok.Setter; + + +/** + * A POJO class to record engine worker status. + * + * @author Yehui Wang (yehui.wang@est.tech) + * + */ +@Setter +@SuppressWarnings("unused") +class EngineStatus { + private String timestamp; + private String id; + private String status; + private String lastMessage; + private long upTime; + private long policyExecutions; + private String lastPolicyDuration; + private String averagePolicyDuration; +} diff --git a/gui-pdp-monitoring/src/main/java/org/onap/policy/gui/pdp/monitoring/rest/PdpMonitoringRestResource.java b/gui-pdp-monitoring/src/main/java/org/onap/policy/gui/pdp/monitoring/rest/PdpMonitoringRestResource.java new file mode 100644 index 0000000..921c68c --- /dev/null +++ b/gui-pdp-monitoring/src/main/java/org/onap/policy/gui/pdp/monitoring/rest/PdpMonitoringRestResource.java @@ -0,0 +1,277 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 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.gui.pdp.monitoring.rest; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import javax.ws.rs.Consumes; +import javax.ws.rs.GET; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; +import lombok.EqualsAndHashCode; +import lombok.Getter; +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.HttpClientFactoryInstance; +import org.onap.policy.common.utils.coder.CoderException; +import org.onap.policy.common.utils.coder.StandardCoder; +import org.onap.policy.models.pdp.concepts.Pdp; +import org.onap.policy.models.pdp.concepts.PdpEngineWorkerStatistics; +import org.onap.policy.models.pdp.concepts.PdpGroups; +import org.onap.policy.models.pdp.concepts.PdpStatistics; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * The class represents the root resource exposed at the base URL<br> + * The url to access this resource would be in the form {@code <baseURL>/rest/....} <br> + * For example: a GET request to the following URL + * {@code http://localhost:18989/papservices/rest/?hostName=localhost&port=12345} + * + * <b>Note:</b> An allocated {@code hostName} and {@code port} query parameter must be included in + * all requests. Datasets for different {@code hostName} are completely isolated from one another. + * + * @author Yehui Wang (yehui.wang@est.tech) + */ +@Path("monitoring/") +@Produces({MediaType.APPLICATION_JSON}) +@Consumes({MediaType.APPLICATION_JSON}) +public class PdpMonitoringRestResource { + // Get a reference to the logger + private static final Logger LOGGER = LoggerFactory.getLogger(PdpMonitoringRestResource.class); + // Set up a map separated by host and engine for the data + private static final Map<String, HashMap<String, List<Counter>>> cache = new HashMap<>(); + + // Set the maximum number of stored data entries to be stored for each engine + private static final int MAX_CACHED_ENTITIES = 50; + + private static Gson gson = new Gson(); + + /** + * Query Pdps. + * + * @param useHttps use Http or not + * @param hostname hostname the host name of the engine service to connect to. + * @param port port the port number of the engine service to connect to. + * @param username user name + * @param password password + * @return a Response object containing Pdps in JSON + * @throws HttpClientConfigException exception + */ + @GET + public Response getPdps(@QueryParam("useHttps") final String useHttps, + @QueryParam("hostname") final String hostname, @QueryParam("port") final int port, + @QueryParam("username") final String username, @QueryParam("password") final String password) + throws HttpClientConfigException { + + return Response + .ok(getHttpClient(useHttps, hostname, port, username, password, "policy/pap/v1/pdps").get().getEntity(), + MediaType.APPLICATION_JSON) + .build(); + } + + /** + * Query Pdp statistics. + * + * @param useHttps use Http or not + * @param hostname the host name of the engine service to connect to. + * @param port the port number of the engine service to connect to. + * @param username user name + * @param password password + * @param id PdpGroupName/PdpSubGroup/PdpIntanceID + * @return a Response object containing the Pdp status and context data in JSON + * @throws HttpClientConfigException exception + * @throws CoderException Coder exception + */ + @GET + @Path("statistics/") + public Response getStatistics(@QueryParam("useHttps") final String useHttps, + @QueryParam("hostname") final String hostname, @QueryParam("port") final int port, + @QueryParam("username") final String username, @QueryParam("password") final String password, + @QueryParam("id") final String id) throws HttpClientConfigException, CoderException { + + PdpGroups pdpGroups = getHttpClient(useHttps, hostname, port, username, password, "policy/pap/v1/pdps").get() + .readEntity(PdpGroups.class); + String groupName; + String subGroup; + String instanceId; + String[] idArray = id.split("/"); + if (idArray.length == 3) { + groupName = idArray[0]; + subGroup = idArray[1]; + instanceId = idArray[2]; + } else { + throw new IllegalArgumentException("Cannot parse groupName, subGroup and instanceId from " + id); + } + + Pdp pdp = pdpGroups.getGroups().stream().filter(group -> group.getName().equals(groupName)) + .flatMap(group -> group.getPdpSubgroups().stream().filter(sub -> sub.getPdpType().equals(subGroup))) + .flatMap(sub -> sub.getPdpInstances().stream() + .filter(instance -> instance.getInstanceId().equals(instanceId))) + .filter(Objects::nonNull).findFirst().orElseThrow(); + + final StatisticsResponse responseObject = new StatisticsResponse(); + + // Engine Service data + responseObject.setEngineId(pdp.getInstanceId()); + responseObject.setServer(hostname); + responseObject.setPort(Integer.toString(port)); + responseObject.setHealthStatus(pdp.getHealthy().name()); + responseObject.setPdpState(pdp.getPdpState().name()); + + String statisticsEntity = getHttpClient(useHttps, hostname, port, username, password, + "policy/pap/v1/pdps/statistics/" + id + "?recordCount=1").get().readEntity(String.class); + Map<String, Map<String, List<PdpStatistics>>> pdpStats = gson.fromJson(statisticsEntity, + new TypeToken<Map<String, Map<String, List<PdpStatistics>>>>() {}.getType()); + + final List<EngineStatus> engineStatusList = new ArrayList<>(); + + if (!pdpStats.isEmpty()) { + PdpStatistics pdpStatistics = pdpStats.get(groupName).get(subGroup).get(0); + responseObject.setTimeStamp(pdpStatistics.getTimeStamp().toString()); + responseObject.setPolicyDeployCount(pdpStatistics.getPolicyDeployCount()); + responseObject.setPolicyDeploySuccessCount(pdpStatistics.getPolicyDeploySuccessCount()); + responseObject.setPolicyDeployFailCount(pdpStatistics.getPolicyDeployFailCount()); + responseObject.setPolicyExecutedCount(pdpStatistics.getPolicyExecutedCount()); + responseObject.setPolicyExecutedSuccessCount(pdpStatistics.getPolicyExecutedSuccessCount()); + responseObject.setPolicyExecutedFailCount(pdpStatistics.getPolicyExecutedFailCount()); + + // Engine Status data + for (final PdpEngineWorkerStatistics engineStats : pdpStatistics.getEngineStats()) { + try { + final EngineStatus engineStatusObject = new EngineStatus(); + engineStatusObject.setTimestamp(pdpStatistics.getTimeStamp().toString()); + engineStatusObject.setId(engineStats.getEngineId()); + engineStatusObject.setStatus(engineStats.getEngineWorkerState().name()); + engineStatusObject.setLastMessage(new Date(engineStats.getEngineTimeStamp()).toString()); + engineStatusObject.setUpTime(engineStats.getUpTime()); + engineStatusObject.setPolicyExecutions(engineStats.getEventCount()); + engineStatusObject.setLastPolicyDuration(gson.toJson( + getValuesFromCache(id, engineStats.getEngineId() + "_last_policy_duration", + pdpStatistics.getTimeStamp().getTime(), engineStats.getLastExecutionTime()), + List.class)); + engineStatusObject.setAveragePolicyDuration( + gson.toJson(getValuesFromCache(id, engineStats.getEngineId() + "_average_policy_duration", + pdpStatistics.getTimeStamp().getTime(), + (long) engineStats.getAverageExecutionTime()), List.class)); + engineStatusList.add(engineStatusObject); + } catch (final RuntimeException e) { + LOGGER.warn("Error getting status of engine with ID " + engineStats.getEngineId() + "<br>", e); + } + } + } else { + responseObject.setTimeStamp("N/A"); + responseObject.setPolicyDeployCount("N/A"); + responseObject.setPolicyDeploySuccessCount("N/A"); + responseObject.setPolicyDeployFailCount("N/A"); + responseObject.setPolicyExecutedCount("N/A"); + responseObject.setPolicyExecutedSuccessCount("N/A"); + responseObject.setPolicyExecutedFailCount("N/A"); + } + + responseObject.setStatus(engineStatusList); + return Response.ok(new StandardCoder().encode(responseObject), MediaType.APPLICATION_JSON).build(); + } + + private HttpClient getHttpClient(String useHttps, String hostname, int port, String username, String password, + String basePath) throws HttpClientConfigException { + BusTopicParams busParams = new BusTopicParams(); + busParams.setClientName("pdp-monitoring"); + busParams.setHostname(hostname); + busParams.setManaged(false); + busParams.setPassword(password); + busParams.setPort(port); + busParams.setUseHttps(useHttps.equals("https")); + busParams.setUserName(username); + busParams.setBasePath(basePath); + return HttpClientFactoryInstance.getClientFactory().build(busParams); + } + + /** + * This method takes in the latest data entry for an engine, adds it to an existing data set and + * returns the full map for that host and engine. + * + * @param uri the pdp uri + * @param id the engines id + * @param timestamp the timestamp of the latest data entry + * @param latestValue the value of the latest data entry + * @return a list of {@code Counter} objects for that engine + */ + private synchronized List<Counter> getValuesFromCache(final String uri, final String id, final long timestamp, + final long latestValue) { + + Map<String, List<Counter>> engineStatus = cache.computeIfAbsent(uri, k -> new HashMap<>()); + + List<Counter> valueList = engineStatus.computeIfAbsent(id, k -> new SlidingWindowList<>(MAX_CACHED_ENTITIES)); + + valueList.add(new Counter(timestamp, latestValue)); + + return valueList; + } + + /** + * A list of values that uses a FIFO sliding window of a fixed size. + */ + @EqualsAndHashCode(callSuper = true) + public class SlidingWindowList<V> extends LinkedList<V> { + private static final long serialVersionUID = -7187277916025957447L; + + private final int maxEntries; + + public SlidingWindowList(final int maxEntries) { + this.maxEntries = maxEntries; + } + + @Override + public boolean add(final V elm) { + if (this.size() > (maxEntries - 1)) { + this.removeFirst(); + } + return super.add(elm); + } + } + + /** + * A class used to storing a single data entry for an engine. + */ + @Getter + public class Counter { + private final long timestamp; + private final long value; + + public Counter(final long timestamp, final long value) { + this.timestamp = timestamp; + this.value = value; + } + } + +} diff --git a/gui-pdp-monitoring/src/main/java/org/onap/policy/gui/pdp/monitoring/rest/StatisticsResponse.java b/gui-pdp-monitoring/src/main/java/org/onap/policy/gui/pdp/monitoring/rest/StatisticsResponse.java new file mode 100644 index 0000000..ada722f --- /dev/null +++ b/gui-pdp-monitoring/src/main/java/org/onap/policy/gui/pdp/monitoring/rest/StatisticsResponse.java @@ -0,0 +1,48 @@ +/*- + * ============LICENSE_START======================================================= + * Copyright (C) 2020 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.gui.pdp.monitoring.rest; + +import java.util.List; +import lombok.Setter; + +/** + * A POJO class to record Pdp statistics. + * + * @author Yehui Wang (yehui.wang@est.tech) + * + */ +@Setter +@SuppressWarnings("unused") +class StatisticsResponse { + private String engineId; + private String server; + private String port; + private String healthStatus; + private String pdpState; + private String timeStamp; + private Object policyDeployCount; + private Object policyDeploySuccessCount; + private Object policyDeployFailCount; + private Object policyExecutedCount; + private Object policyExecutedSuccessCount; + private Object policyExecutedFailCount; + private List<EngineStatus> status; +} |