diff options
Diffstat (limited to 'tosca-controlloop/runtime')
8 files changed, 1444 insertions, 35 deletions
diff --git a/tosca-controlloop/runtime/src/main/java/org/onap/policy/clamp/controlloop/runtime/commissioning/CommissioningHandler.java b/tosca-controlloop/runtime/src/main/java/org/onap/policy/clamp/controlloop/runtime/commissioning/CommissioningHandler.java new file mode 100644 index 000000000..ab917b74e --- /dev/null +++ b/tosca-controlloop/runtime/src/main/java/org/onap/policy/clamp/controlloop/runtime/commissioning/CommissioningHandler.java @@ -0,0 +1,101 @@ +/*- + * ============LICENSE_START======================================================= + * 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. + * 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.clamp.controlloop.runtime.commissioning; + +import java.io.IOException; +import java.util.List; +import java.util.Set; +import javax.ws.rs.core.Response; +import lombok.Getter; +import org.onap.policy.clamp.controlloop.common.handler.ControlLoopHandler; +import org.onap.policy.clamp.controlloop.runtime.commissioning.rest.CommissioningController; +import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup; +import org.onap.policy.common.endpoints.event.comm.TopicSink; +import org.onap.policy.common.endpoints.listeners.MessageTypeDispatcher; +import org.onap.policy.common.utils.services.Registry; +import org.onap.policy.models.base.PfModelRuntimeException; + +/** + * This class handles commissioning of control loop definitions. + */ +public final class CommissioningHandler extends ControlLoopHandler { + + @Getter + private CommissioningProvider provider; + + /** + * Gets the CommissioningHandler. + * + * @return CommissioningHandler + */ + public static CommissioningHandler getInstance() { + return Registry.get(CommissioningHandler.class.getName()); + } + + /** + * Create a handler. + * + * @param controlLoopParameters the parameters for access to the database + */ + public CommissioningHandler(ClRuntimeParameterGroup controlLoopParameters) { + super(controlLoopParameters.getDatabaseProviderParameters()); + } + + @Override + public Set<Class<?>> getProviderClasses() { + return Set.of(CommissioningController.class); + } + + @Override + public void startAndRegisterListeners(MessageTypeDispatcher msgDispatcher) { + // No topic communication on this handler + } + + @Override + public void startAndRegisterPublishers(List<TopicSink> topicSinks) { + // No topic communication on this handler + } + + @Override + public void stopAndUnregisterPublishers() { + // No topic communication on this handler + } + + @Override + public void stopAndUnregisterListeners(MessageTypeDispatcher msgDispatcher) { + // No topic communication on this handler + } + + @Override + public void startProviders() { + provider = new CommissioningProvider(getDatabaseProviderParameters()); + } + + @Override + public void stopProviders() { + try { + provider.close(); + } catch (IOException e) { + throw new PfModelRuntimeException(Response.Status.INTERNAL_SERVER_ERROR, + "an error has occured while stopping commissioning providers", e); + } + } +} diff --git a/tosca-controlloop/runtime/src/main/java/org/onap/policy/clamp/controlloop/runtime/commissioning/rest/CommissioningController.java b/tosca-controlloop/runtime/src/main/java/org/onap/policy/clamp/controlloop/runtime/commissioning/rest/CommissioningController.java new file mode 100644 index 000000000..cd6c08e30 --- /dev/null +++ b/tosca-controlloop/runtime/src/main/java/org/onap/policy/clamp/controlloop/runtime/commissioning/rest/CommissioningController.java @@ -0,0 +1,351 @@ +/*- + * ============LICENSE_START======================================================= + * 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. + * 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.clamp.controlloop.runtime.commissioning.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.List; +import java.util.UUID; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Response; +import javax.ws.rs.core.Response.Status; +import org.onap.policy.clamp.controlloop.models.messages.rest.commissioning.CommissioningResponse; +import org.onap.policy.clamp.controlloop.runtime.commissioning.CommissioningHandler; +import org.onap.policy.clamp.controlloop.runtime.commissioning.CommissioningProvider; +import org.onap.policy.clamp.controlloop.runtime.main.rest.RestController; +import org.onap.policy.models.base.PfModelException; +import org.onap.policy.models.base.PfModelRuntimeException; +import org.onap.policy.models.errors.concepts.ErrorResponseInfo; +import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate; +import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * Class to provide REST end points for creating, deleting, querying commissioned control loops. + */ +public class CommissioningController extends RestController { + + private static final Logger LOGGER = LoggerFactory.getLogger(CommissioningController.class); + + private final CommissioningProvider provider; + + /** + * create Commissioning Controller. + */ + public CommissioningController() { + this.provider = CommissioningHandler.getInstance().getProvider(); + } + + /** + * Creates a control loop definition. + * + * @param requestId request ID used in ONAP logging + * @param body the body of control loop following TOSCA definition + * @return a response + */ + // @formatter:off + @POST + @Path("/commission") + @ApiOperation( + value = "Commissions control loop definitions", + notes = "Commissions control loop definitions, returning the commissioned control loop definition IDs", + response = CommissioningResponse.class, + tags = { + "Control Loop Commissioning 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 create( + @HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, + @ApiParam(value = "Entity Body of Control Loop", required = true) ToscaServiceTemplate body) { + + try { + CommissioningResponse response = provider.createControlLoopDefinitions(body); + return addLoggingHeaders(addVersionControlHeaders(Response.status(Status.OK)), requestId) + .entity(response).build(); + + } catch (PfModelRuntimeException | PfModelException e) { + LOGGER.warn("Commissioning of the control loops failed", e); + return createCommissioningErrorResponse(e, requestId); + } + + } + + /** + * Deletes a control loop definition. + * + * @param requestId request ID used in ONAP logging + * @param name the name of the control loop definition to delete + * @param version the version of the control loop definition to delete + * @return a response + */ + // @formatter:off + @DELETE + @Path("/commission") + @ApiOperation(value = "Delete a commissioned control loop", + notes = "Deletes a Commissioned Control Loop, returning optional error details", + response = CommissioningResponse.class, + tags = { + "Clamp Control Loop Commissioning 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 delete( + @HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, + @ApiParam(value = "Control Loop definition name", required = true) @QueryParam("name") String name, + @ApiParam(value = "Control Loop definition version", required = true) + @QueryParam("version") String version) { + + try { + CommissioningResponse response = provider.deleteControlLoopDefinition(name, version); + return addLoggingHeaders(addVersionControlHeaders(Response.status(Status.OK)), requestId) + .entity(response).build(); + + } catch (PfModelRuntimeException | PfModelException e) { + LOGGER.warn("Decommisssioning of control loop failed", e); + return createCommissioningErrorResponse(e, requestId); + } + + } + + /** + * Queries details of all or specific control loop definitions. + * + * @param requestId request ID used in ONAP logging + * @param name the name of the control loop definition to get, null for all definitions + * @param version the version of the control loop definition to get, null for all definitions + * @return the control loop definitions + */ + // @formatter:off + @GET + @Path("/commission") + @ApiOperation(value = "Query details of the requested commissioned control loop definitions", + notes = "Queries details of the requested commissioned control loop definitions, " + + "returning all control loop details", + response = ToscaNodeTemplate.class, + tags = { + "Clamp Control Loop Commissioning 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 query(@HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, + @ApiParam(value = "Control Loop definition name", required = true) + @QueryParam("name") String name, + @ApiParam(value = "Control Loop definition version", required = true) + @QueryParam("version") String version) { + + try { + List<ToscaNodeTemplate> response = provider.getControlLoopDefinitions(name, version); + return addLoggingHeaders(addVersionControlHeaders(Response.status(Status.OK)), requestId).entity(response) + .build(); + + } catch (PfModelRuntimeException | PfModelException e) { + LOGGER.warn("Get of control loop definitions failed", e); + return createCommissioningErrorResponse(e, requestId); + } + + } + + /** + * Queries the elements of a specific control loop. + * + * @param requestId request ID used in ONAP logging + * @param name the name of the control loop definition to get + * @param version the version of the control loop definition to get + * @return the control loop element definitions + */ + // @formatter:off + @GET + @Path("/commission/elements") + @ApiOperation(value = "Query details of the requested commissioned control loop element definitions", + notes = "Queries details of the requested commissioned control loop element definitions, " + + "returning all control loop elements' details", + response = ToscaNodeTemplate.class, + tags = { + "Clamp Control Loop Commissioning 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 queryElements(@HeaderParam(REQUEST_ID_NAME) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, + @ApiParam(value = "Control Loop definition name", required = true) + @QueryParam("name") String name, + @ApiParam(value = "Control Loop definition version", required = true) + @QueryParam("version") String version) throws Exception { + + try { + List<ToscaNodeTemplate> nodeTemplate = provider.getControlLoopDefinitions(name, version); + //Prevent ambiguous queries with multiple returns + if (nodeTemplate.size() > 1) { + throw new Exception(); + } + List<ToscaNodeTemplate> response = provider.getControlLoopElementDefinitions(nodeTemplate.get(0)); + return addLoggingHeaders(addVersionControlHeaders(Response.status(Status.OK)), requestId).entity(response) + .build(); + + } catch (PfModelRuntimeException | PfModelException e) { + LOGGER.warn("Get of control loop element definitions failed", e); + return createCommissioningErrorResponse(e, requestId); + } + + } + + private Response createCommissioningErrorResponse(ErrorResponseInfo e, UUID requestId) { + CommissioningResponse resp = new CommissioningResponse(); + resp.setErrorDetails(e.getErrorResponse().getErrorMessage()); + return addLoggingHeaders(addVersionControlHeaders(Response.status(e.getErrorResponse().getResponseCode())), + requestId).entity(resp).build(); + } + +} diff --git a/tosca-controlloop/runtime/src/main/java/org/onap/policy/clamp/controlloop/runtime/instantiation/InstantiationHandler.java b/tosca-controlloop/runtime/src/main/java/org/onap/policy/clamp/controlloop/runtime/instantiation/InstantiationHandler.java index c4b0955f9..fd5288fda 100644 --- a/tosca-controlloop/runtime/src/main/java/org/onap/policy/clamp/controlloop/runtime/instantiation/InstantiationHandler.java +++ b/tosca-controlloop/runtime/src/main/java/org/onap/policy/clamp/controlloop/runtime/instantiation/InstantiationHandler.java @@ -27,6 +27,7 @@ import java.util.Set; import javax.ws.rs.core.Response; import lombok.Getter; import org.onap.policy.clamp.controlloop.common.handler.ControlLoopHandler; +import org.onap.policy.clamp.controlloop.runtime.commissioning.rest.CommissioningController; import org.onap.policy.clamp.controlloop.runtime.instantiation.rest.InstantiationController; import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup; import org.onap.policy.common.endpoints.event.comm.TopicSink; @@ -66,11 +67,7 @@ public final class InstantiationHandler extends ControlLoopHandler { @Override public Set<Class<?>> getProviderClasses() { - Set<Class<?>> providerClasses = new HashSet<>(); - - providerClasses.add(InstantiationController.class); - - return providerClasses; + return Set.of(InstantiationController.class); } @Override diff --git a/tosca-controlloop/runtime/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/startstop/ClRuntimeActivator.java b/tosca-controlloop/runtime/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/startstop/ClRuntimeActivator.java index d3a5c5810..0078f6129 100644 --- a/tosca-controlloop/runtime/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/startstop/ClRuntimeActivator.java +++ b/tosca-controlloop/runtime/src/main/java/org/onap/policy/clamp/controlloop/runtime/main/startstop/ClRuntimeActivator.java @@ -20,11 +20,14 @@ package org.onap.policy.clamp.controlloop.runtime.main.startstop; +import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.atomic.AtomicReference; import javax.ws.rs.core.Response.Status; import org.onap.policy.clamp.controlloop.common.exception.ControlLoopRuntimeException; +import org.onap.policy.clamp.controlloop.common.handler.ControlLoopHandler; +import org.onap.policy.clamp.controlloop.runtime.commissioning.CommissioningHandler; import org.onap.policy.clamp.controlloop.runtime.instantiation.InstantiationHandler; import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup; import org.onap.policy.clamp.controlloop.runtime.main.rest.ControlLoopAafFilter; @@ -61,7 +64,6 @@ public class ClRuntimeActivator extends ServiceManagerContainer { * @param clRuntimeParameterGroup the parameters for the control loop runtime service */ public ClRuntimeActivator(final ClRuntimeParameterGroup clRuntimeParameterGroup) { - if (clRuntimeParameterGroup == null || !clRuntimeParameterGroup.isValid()) { throw new ControlLoopRuntimeException(Status.INTERNAL_SERVER_ERROR, "ParameterGroup not valid"); } @@ -81,53 +83,61 @@ public class ClRuntimeActivator extends ServiceManagerContainer { "topic message dispatcher failed to start", e); } - final AtomicReference<InstantiationHandler> instantiationHandler = new AtomicReference<>(); - final AtomicReference<RestServer> restServer = new AtomicReference<>(); + final AtomicReference<ControlLoopHandler> commissioningHandler = new AtomicReference<>(); + final AtomicReference<ControlLoopHandler> instantiationHandler = new AtomicReference<>(); + final AtomicReference<RestServer> restServer = new AtomicReference<>(); // @formatter:off addAction("Control loop runtime parameters", - () -> ParameterService.register(clRuntimeParameterGroup), - () -> ParameterService.deregister(clRuntimeParameterGroup.getName())); - + () -> ParameterService.register(clRuntimeParameterGroup), + () -> ParameterService.deregister(clRuntimeParameterGroup.getName())); addAction("Topic endpoint management", - () -> TopicEndpointManager.getManager().start(), - () -> TopicEndpointManager.getManager().shutdown()); - + () -> TopicEndpointManager.getManager().start(), + () -> TopicEndpointManager.getManager().shutdown()); + addAction("Commissioning Handler", + () -> commissioningHandler.set(new CommissioningHandler(clRuntimeParameterGroup)), + () -> commissioningHandler.get().close()); addAction("Instantiation Handler", - () -> instantiationHandler.set(new InstantiationHandler(clRuntimeParameterGroup)), - () -> instantiationHandler.get().close()); - - addAction("Providers", - () -> instantiationHandler.get().startProviders(), - () -> instantiationHandler.get().stopProviders()); + () -> instantiationHandler.set(new InstantiationHandler(clRuntimeParameterGroup)), + () -> instantiationHandler.get().close()); - addAction("Listeners", - () -> instantiationHandler.get().startAndRegisterListeners(msgDispatcher), - () -> instantiationHandler.get().stopAndUnregisterListeners(msgDispatcher)); - - addAction("Publishers", - () -> instantiationHandler.get().startAndRegisterPublishers(topicSinks), - () -> instantiationHandler.get().stopAndUnregisterPublishers()); + addHandlerActions("Commissioning", commissioningHandler); + addHandlerActions("Instantiation", instantiationHandler); addAction("Topic Message Dispatcher", this::registerMsgDispatcher, this::unregisterMsgDispatcher); clRuntimeParameterGroup.getRestServerParameters().setName(clRuntimeParameterGroup.getName()); addAction("REST server", - () -> { - Set<Class<?>> providerClasses = instantiationHandler.get().getProviderClasses(); + () -> { + Set<Class<?>> providerClasses = new HashSet<>(); + providerClasses.addAll(commissioningHandler.get().getProviderClasses()); + providerClasses.addAll(instantiationHandler.get().getProviderClasses()); - RestServer server = new RestServer(clRuntimeParameterGroup.getRestServerParameters(), + RestServer server = new RestServer(clRuntimeParameterGroup.getRestServerParameters(), ControlLoopAafFilter.class, providerClasses.toArray(new Class<?>[providerClasses.size()])); - - restServer.set(server); - restServer.get().start(); - }, - () -> restServer.get().stop()); + restServer.set(server); + restServer.get().start(); + }, + () -> restServer.get().stop()); // @formatter:on } + private void addHandlerActions(final String name, final AtomicReference<ControlLoopHandler> handler) { + addAction(name + " Providers", + () -> handler.get().startProviders(), + () -> handler.get().stopProviders()); + + addAction(name + " Listeners", + () -> handler.get().startAndRegisterListeners(msgDispatcher), + () -> handler.get().stopAndUnregisterListeners(msgDispatcher)); + + addAction(name + " Publishers", + () -> handler.get().startAndRegisterPublishers(topicSinks), + () -> handler.get().stopAndUnregisterPublishers()); + } + /** * Registers the dispatcher with the topic source(s). */ diff --git a/tosca-controlloop/runtime/src/main/java/org/onap/policy/clamp/controlloop/runtime/monitoring/MonitoringHandler.java b/tosca-controlloop/runtime/src/main/java/org/onap/policy/clamp/controlloop/runtime/monitoring/MonitoringHandler.java new file mode 100644 index 000000000..04f458e7d --- /dev/null +++ b/tosca-controlloop/runtime/src/main/java/org/onap/policy/clamp/controlloop/runtime/monitoring/MonitoringHandler.java @@ -0,0 +1,104 @@ +/*- + * ============LICENSE_START======================================================= + * 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. + * 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.clamp.controlloop.runtime.monitoring; + +import java.io.IOException; +import java.util.List; +import java.util.Set; +import javax.ws.rs.core.Response; +import lombok.Getter; +import org.onap.policy.clamp.controlloop.common.handler.ControlLoopHandler; +import org.onap.policy.clamp.controlloop.runtime.main.parameters.ClRuntimeParameterGroup; +import org.onap.policy.clamp.controlloop.runtime.monitoring.rest.MonitoringQueryController; +import org.onap.policy.common.endpoints.event.comm.TopicSink; +import org.onap.policy.common.endpoints.listeners.MessageTypeDispatcher; +import org.onap.policy.common.utils.services.Registry; +import org.onap.policy.models.base.PfModelRuntimeException; + +/** + * This class handles monitoring of control loop definitions, + * so only one object of this type should be built at a time. + * + * <p/> + * It is effectively a singleton that is started at system start. + */ +public class MonitoringHandler extends ControlLoopHandler { + + @Getter + private MonitoringProvider monitoringProvider; + + /** + * Gets the Monitoring Handler. + * + * @return MonitoringHandler + */ + public static MonitoringHandler getInstance() { + return Registry.get(MonitoringHandler.class.getName()); + } + + /** + * Create a handler. + * + * @param controlLoopParameters the parameters for access to the database + */ + public MonitoringHandler(ClRuntimeParameterGroup controlLoopParameters) { + super(controlLoopParameters.getDatabaseProviderParameters()); + } + + @Override + public Set<Class<?>> getProviderClasses() { + return Set.of(MonitoringQueryController.class); + } + + @Override + public void startAndRegisterListeners(MessageTypeDispatcher msgDispatcher) { + // No topic communication on this handler + } + + @Override + public void startAndRegisterPublishers(List<TopicSink> topicSinks) { + // No topic communication on this handler + } + + @Override + public void stopAndUnregisterPublishers() { + // No topic communication on this handler + } + + @Override + public void stopAndUnregisterListeners(MessageTypeDispatcher msgDispatcher) { + // No topic communication on this handler + } + + @Override + public void startProviders() { + monitoringProvider = new MonitoringProvider(getDatabaseProviderParameters()); + } + + @Override + public void stopProviders() { + try { + monitoringProvider.close(); + } catch (IOException e) { + throw new PfModelRuntimeException(Response.Status.INTERNAL_SERVER_ERROR, "Cannot stop provider", e); + } + } +} diff --git a/tosca-controlloop/runtime/src/main/java/org/onap/policy/clamp/controlloop/runtime/monitoring/MonitoringProvider.java b/tosca-controlloop/runtime/src/main/java/org/onap/policy/clamp/controlloop/runtime/monitoring/MonitoringProvider.java new file mode 100644 index 000000000..aeabce7a5 --- /dev/null +++ b/tosca-controlloop/runtime/src/main/java/org/onap/policy/clamp/controlloop/runtime/monitoring/MonitoringProvider.java @@ -0,0 +1,273 @@ +/*- + * ============LICENSE_START======================================================= + * 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. + * 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.clamp.controlloop.runtime.monitoring; + +import java.io.Closeable; +import java.io.IOException; +import java.time.Instant; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import lombok.NonNull; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ClElementStatistics; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ClElementStatisticsList; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoop; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ControlLoopElement; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantStatistics; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantStatisticsList; +import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ClElementStatisticsProvider; +import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ControlLoopProvider; +import org.onap.policy.clamp.controlloop.models.controlloop.persistence.provider.ParticipantStatisticsProvider; +import org.onap.policy.models.base.PfModelException; +import org.onap.policy.models.base.PfModelRuntimeException; +import org.onap.policy.models.provider.PolicyModelsProviderParameters; +import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifier; + +/** + * This class provides information about statistics data of CL elements and CL Participants in database to callers. + */ +public class MonitoringProvider implements Closeable { + + private static final String DESC_ORDER = "DESC"; + private final ParticipantStatisticsProvider participantStatisticsProvider; + private final ClElementStatisticsProvider clElementStatisticsProvider; + private final ControlLoopProvider controlLoopProvider; + + /** + * Create a Monitoring provider. + * + */ + public MonitoringProvider(PolicyModelsProviderParameters parameters) { + + try { + participantStatisticsProvider = new ParticipantStatisticsProvider(parameters); + clElementStatisticsProvider = new ClElementStatisticsProvider(parameters); + controlLoopProvider = new ControlLoopProvider(parameters); + } catch (PfModelException e) { + throw new PfModelRuntimeException(e); + } + } + + @Override + public void close() throws IOException { + controlLoopProvider.close(); + clElementStatisticsProvider.close(); + participantStatisticsProvider.close(); + } + + /** + * Create participant statistics. + * + * @param participantStatistics the participant statistics + * @return the result of create operation + * @throws PfModelException on creation errors + */ + public ParticipantStatisticsList createParticipantStatistics(List<ParticipantStatistics> participantStatistics) + throws PfModelException { + ParticipantStatisticsList participantStatisticsList = new ParticipantStatisticsList(); + participantStatisticsList.setStatisticsList(participantStatisticsProvider + .createParticipantStatistics(participantStatistics)); + + return participantStatisticsList; + } + + /** + * Create clElement statistics. + * + * @param clElementStatisticsList the clElement statistics + * @return the result of create operation + * @throws PfModelException on creation errors + */ + public ClElementStatisticsList createClElementStatistics(List<ClElementStatistics> clElementStatisticsList) + throws PfModelException { + ClElementStatisticsList elementStatisticsList = new ClElementStatisticsList(); + elementStatisticsList.setClElementStatistics(clElementStatisticsProvider + .createClElementStatistics(clElementStatisticsList)); + + return elementStatisticsList; + } + + /** + * Get participant statistics based on specific filters. + * + * @param name the name of the participant statistics to get, null to get all statistics + * @param version the version of the participant statistics to get, null to get all statistics + * @param recordCount number of records to be fetched. + * @param startTime start of the timestamp, from statistics to be filtered + * @param endTime end of the timestamp up to which statistics to be filtered + * @return the participant found + */ + public ParticipantStatisticsList fetchFilteredParticipantStatistics(@NonNull final String name, + final String version, int recordCount, + Instant startTime, Instant endTime) { + ParticipantStatisticsList participantStatisticsList = new ParticipantStatisticsList(); + + //Additional parameters can be added in filterMap for filtering data. + Map<String, Object> filterMap = null; + participantStatisticsList.setStatisticsList(participantStatisticsProvider.getFilteredParticipantStatistics( + name, version, startTime, endTime, filterMap, DESC_ORDER, recordCount)); + + return participantStatisticsList; + } + + /** + * Get all participant statistics records found for a specific control loop. * + * + * @param controlLoopName name of the control loop + * @param controlLoopVersion version of the control loop + * @return All the participant statistics found + * @throws PfModelException on errors getting participant statistics + */ + public ParticipantStatisticsList fetchParticipantStatsPerControlLoop(@NonNull final String controlLoopName, + @NonNull final String controlLoopVersion) + throws PfModelException { + ParticipantStatisticsList statisticsList = new ParticipantStatisticsList(); + List<ParticipantStatistics> participantStatistics = new ArrayList<>(); + try { + //Fetch all participantIds for a specific control loop + List<ToscaConceptIdentifier> participantIds = getAllParticipantIdsPerControlLoop(controlLoopName, + controlLoopVersion); + for (ToscaConceptIdentifier id: participantIds) { + participantStatistics.addAll(participantStatisticsProvider.getFilteredParticipantStatistics( + id.getName(), id.getVersion(), null, null, null, DESC_ORDER, 0)); + } + statisticsList.setStatisticsList(participantStatistics); + } catch (PfModelException e) { + throw new PfModelRuntimeException(e); + } + return statisticsList; + } + + + + /** + * Get clElement statistics based on specific filters. + * + * @param name the name of the clElement statistics to get, null to get all statistics + * @param version the version of the clElement statistics to get, null to get all statistics + * @param id UUID of the control loop element + * @param startTime start of the timestamp, from statistics to be filtered + * @param endTime end of the timestamp up to which statistics to be filtered + * @param recordCount number of records to be fetched. + * @return the participant found + * @throws PfModelException on errors getting control loop statistics + */ + public ClElementStatisticsList fetchFilteredClElementStatistics(@NonNull final String name, final String version, + final String id, Instant startTime, Instant endTime, + int recordCount) throws PfModelException { + ClElementStatisticsList clElementStatisticsList = new ClElementStatisticsList(); + Map<String, Object> filterMap = new HashMap<>(); + //Adding UUID in filter if present + if (id != null) { + filterMap.put("localName", id); + } + clElementStatisticsList.setClElementStatistics(clElementStatisticsProvider.getFilteredClElementStatistics( + name, version, startTime, endTime, filterMap, DESC_ORDER, recordCount)); + + return clElementStatisticsList; + } + + + /** + * Get clElement statistics per control loop. + * + * @param name the name of the control loop + * @param version the version of the control loop + * @return the clElement statistics found + * @throws PfModelException on errors getting control loop statistics + */ + public ClElementStatisticsList fetchClElementStatsPerControlLoop(@NonNull final String name, + @NonNull final String version) + throws PfModelException { + ClElementStatisticsList clElementStatisticsList = new ClElementStatisticsList(); + List<ClElementStatistics> clElementStats = new ArrayList<>(); + try { + List<ControlLoopElement> clElements = new ArrayList<>(); + //Fetch all control loop elements for the control loop + ControlLoop controlLoop = controlLoopProvider.getControlLoop(new ToscaConceptIdentifier(name, + version)); + clElements.addAll(controlLoop.getElements()); + + //Collect control loop element statistics for each cl element. + for (ControlLoopElement clElement : clElements) { + clElementStats.addAll(fetchFilteredClElementStatistics(clElement.getParticipantId().getName(), + clElement.getParticipantId().getVersion(), clElement.getId().toString(), null, + null, 0).getClElementStatistics()); + } + clElementStatisticsList.setClElementStatistics(clElementStats); + } catch (PfModelException e) { + throw new PfModelRuntimeException(e); + } + + return clElementStatisticsList; + } + + /** + * If required, REST end point can be defined for this method to fetch associated participant Ids + * for a control loop. + * + * @param name the name of the control loop + * @param version the version of the control loop + * @return List of participant Id + * @throws PfModelException on errors + */ + public List<ToscaConceptIdentifier> getAllParticipantIdsPerControlLoop(String name, String version) + throws PfModelException { + List<ToscaConceptIdentifier> participantIds = new ArrayList<>(); + ControlLoop controlLoop = controlLoopProvider.getControlLoop(new ToscaConceptIdentifier(name, version)); + if (controlLoop != null) { + for (ControlLoopElement clElement : controlLoop.getElements()) { + participantIds.add(clElement.getParticipantId()); + } + } + return participantIds; + } + + /** + * If required, REST end point can be defined for this method to fetch associated control loop element Ids + * for a control loop. + * + * @param name the name of the control loop + * @param version the version of the control loop + * @return Map of control loop Id and participant details + * @throws PfModelException on errors + */ + public Map<String, ToscaConceptIdentifier> getAllClElementsIdPerControlLoop(String name, String version) + throws PfModelException { + Map<String, ToscaConceptIdentifier> clElementId = new HashMap<>(); + ControlLoop controlLoop = controlLoopProvider.getControlLoop(new ToscaConceptIdentifier(name, version)); + for (ControlLoopElement clElement : controlLoop.getElements()) { + clElementId.put(clElement.getId().toString(), clElement.getParticipantId()); + } + return clElementId; + } + + + + public void updateClElementStatistics(List<ClElementStatistics> clElementStatistics) { + // TODO Auto-generated method stub + } + + public void updateParticipantStatistics(List<ParticipantStatistics> statisticsList) { + // TODO Auto-generated method stub + } +} diff --git a/tosca-controlloop/runtime/src/main/java/org/onap/policy/clamp/controlloop/runtime/monitoring/rest/MonitoringQueryController.java b/tosca-controlloop/runtime/src/main/java/org/onap/policy/clamp/controlloop/runtime/monitoring/rest/MonitoringQueryController.java new file mode 100644 index 000000000..2e19ffe3a --- /dev/null +++ b/tosca-controlloop/runtime/src/main/java/org/onap/policy/clamp/controlloop/runtime/monitoring/rest/MonitoringQueryController.java @@ -0,0 +1,371 @@ +/*- + * ============LICENSE_START======================================================= + * 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. + * 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.clamp.controlloop.runtime.monitoring.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.time.Instant; +import java.util.UUID; +import javax.ws.rs.DefaultValue; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.Path; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.Response; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ClElementStatisticsList; +import org.onap.policy.clamp.controlloop.models.controlloop.concepts.ParticipantStatisticsList; +import org.onap.policy.clamp.controlloop.runtime.main.rest.RestController; +import org.onap.policy.clamp.controlloop.runtime.monitoring.MonitoringHandler; +import org.onap.policy.clamp.controlloop.runtime.monitoring.MonitoringProvider; +import org.onap.policy.models.base.PfModelException; +import org.onap.policy.models.base.PfModelRuntimeException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** + * This class handles REST endpoints for CL Statistics monitoring. + */ +public class MonitoringQueryController extends RestController { + + private static final Logger LOGGER = LoggerFactory.getLogger(MonitoringQueryController.class); + private final MonitoringProvider provider; + + /** + * Create Monitoring Controller. + */ + public MonitoringQueryController() { + this.provider = MonitoringHandler.getInstance().getMonitoringProvider(); + } + + + /** + * Queries details of control loop participants statistics. + * + * @param requestId request ID used in ONAP logging + * @param name the name of the participant to get, null for all participants statistics + * @param recordCount the record count to be fetched + * @return the participant statistics + */ + // @formatter:off + @GET + @Path("/monitoring/participant") + @ApiOperation(value = "Query details of the requested participant stats", + notes = "Queries details of the requested participant stats, returning all participant stats", + response = ParticipantStatisticsList.class, + tags = { + "Clamp control loop Monitoring 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 queryParticipantStatistics(@HeaderParam(REQUEST_ID_NAME) + @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, + @ApiParam(value = "Control Loop participant name", required = true) + @QueryParam("name") final String name, + @ApiParam(value = "Control Loop participant version", required = true) + @QueryParam("version") final String version, + @ApiParam(value = "Record count", required = false) @DefaultValue("0") + @QueryParam("recordCount") final int recordCount, + @ApiParam(value = "start time", required = false) + @QueryParam("startTime") final String startTime, + @ApiParam(value = "end time", required = false) + @QueryParam("endTime") final String endTime) { + + try { + Instant startTimestamp = null; + Instant endTimestamp = null; + + if (startTime != null) { + startTimestamp = Instant.parse(startTime); + } + if (endTime != null) { + endTimestamp = Instant.parse(endTime); + } + ParticipantStatisticsList response = provider.fetchFilteredParticipantStatistics(name, version, recordCount, + startTimestamp, endTimestamp); + return addLoggingHeaders(addVersionControlHeaders(Response.status(Response.Status.OK)), requestId) + .entity(response) + .build(); + + } catch (PfModelRuntimeException e) { + LOGGER.warn("Monitoring of participants statistics failed", e); + return addLoggingHeaders(addVersionControlHeaders(Response.status(e.getErrorResponse().getResponseCode())), + requestId).build(); + } + + } + + /** + * Queries details of all participant statistics per control loop. + * + * @param requestId request ID used in ONAP logging + * @param name the name of the control loop + * @param version version of the control loop + * @return the control loop element statistics + */ + // @formatter:off + @GET + @Path("/monitoring/participants/controlloop") + @ApiOperation(value = "Query details of all the participant stats in a control loop", + notes = "Queries details of the participant stats, returning all participant stats", + response = ClElementStatisticsList.class, + tags = { + "Clamp control loop Monitoring 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 queryParticipantStatisticsPerControlLoop(@HeaderParam(REQUEST_ID_NAME) + @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, + @ApiParam(value = "Control Loop name", required = true) + @QueryParam("name") final String name, + @ApiParam(value = "Control Loop version", required = true) + @QueryParam("version") final String version) { + + try { + ParticipantStatisticsList response = provider.fetchParticipantStatsPerControlLoop(name, version); + return addLoggingHeaders(addVersionControlHeaders(Response.status(Response.Status.OK)), requestId) + .entity(response) + .build(); + + } catch (PfModelRuntimeException | PfModelException e) { + LOGGER.warn("Monitoring of Cl participant statistics failed", e); + return addLoggingHeaders(addVersionControlHeaders(Response.status(e.getErrorResponse().getResponseCode())), + requestId).build(); + } + + } + + + + /** + * Queries details of all control loop element statistics per control loop. + * + * @param requestId request ID used in ONAP logging + * @param name the name of the control loop + * @param version version of the control loop + * @return the control loop element statistics + */ + // @formatter:off + @GET + @Path("/monitoring/clelements/controlloop") + @ApiOperation(value = "Query details of the requested cl element stats in a control loop", + notes = "Queries details of the requested cl element stats, returning all clElement stats", + response = ClElementStatisticsList.class, + tags = { + "Clamp control loop Monitoring 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 queryElementStatisticsPerControlLoop(@HeaderParam(REQUEST_ID_NAME) + @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, + @ApiParam(value = "Control Loop name", required = true) + @QueryParam("name") final String name, + @ApiParam(value = "Control Loop version", required = true) + @QueryParam("version") final String version) { + + try { + ClElementStatisticsList response = provider.fetchClElementStatsPerControlLoop(name, version); + return addLoggingHeaders(addVersionControlHeaders(Response.status(Response.Status.OK)), requestId) + .entity(response) + .build(); + + } catch (PfModelRuntimeException | PfModelException e) { + LOGGER.warn("Monitoring of Cl Element statistics failed", e); + return addLoggingHeaders(addVersionControlHeaders(Response.status(e.getErrorResponse().getResponseCode())), + requestId).build(); + } + + } + + + + + /** + * Queries details of all control loop element statistics per control loop. + * + * @param requestId request ID used in ONAP logging + * @param name the name of the control loop + * @param version version of the control loop + * @param id Id of the control loop element + * @param recordCount the record count to be fetched + * @return the control loop element statistics + */ + // @formatter:off + @GET + @Path("/monitoring/clelement") + @ApiOperation(value = "Query details of the requested cl element stats", + notes = "Queries details of the requested cl element stats, returning all clElement stats", + response = ClElementStatisticsList.class, + tags = { + "Clamp control loop Monitoring 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 queryElementStatistics(@HeaderParam(REQUEST_ID_NAME) + @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId, + @ApiParam(value = "Participant name", required = true) + @QueryParam("name") final String name, + @ApiParam(value = "Participant version", required = true) + @QueryParam("version") final String version, + @ApiParam(value = "Record count", required = false) + @DefaultValue("0") @QueryParam("recordCount") final int recordCount, + @ApiParam(value = "Control Loop element id", required = false) + @QueryParam("id") final String id, + @ApiParam(value = "start time", required = false) + @QueryParam("startTime") final String startTime, + @ApiParam(value = "end time", required = false) + @QueryParam("endTime") final String endTime) { + + try { + Instant startTimestamp = null; + Instant endTimestamp = null; + + if (startTime != null) { + startTimestamp = Instant.parse(startTime); + } + if (endTime != null) { + endTimestamp = Instant.parse(endTime); + } + ClElementStatisticsList response = provider.fetchFilteredClElementStatistics(name, version, id, + startTimestamp, endTimestamp, recordCount); + return addLoggingHeaders(addVersionControlHeaders(Response.status(Response.Status.OK)), requestId) + .entity(response) + .build(); + + } catch (PfModelRuntimeException | PfModelException e) { + LOGGER.warn("Monitoring of Cl Element statistics failed", e); + return addLoggingHeaders(addVersionControlHeaders(Response.status(e.getErrorResponse().getResponseCode())), + requestId).build(); + } + + } + +} diff --git a/tosca-controlloop/runtime/src/test/java/org/onap/policy/clamp/controlloop/runtime/commissioning/rest/CommissioningControllerTest.java b/tosca-controlloop/runtime/src/test/java/org/onap/policy/clamp/controlloop/runtime/commissioning/rest/CommissioningControllerTest.java new file mode 100644 index 000000000..fa146635d --- /dev/null +++ b/tosca-controlloop/runtime/src/test/java/org/onap/policy/clamp/controlloop/runtime/commissioning/rest/CommissioningControllerTest.java @@ -0,0 +1,202 @@ +/*- + * ============LICENSE_START======================================================= + * 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. + * 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.clamp.controlloop.runtime.commissioning.rest; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; + +import java.util.List; +import javax.ws.rs.client.Entity; +import javax.ws.rs.client.Invocation; +import javax.ws.rs.core.Response; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; +import org.onap.policy.clamp.controlloop.models.messages.rest.commissioning.CommissioningResponse; +import org.onap.policy.clamp.controlloop.runtime.util.rest.CommonRestController; +import org.onap.policy.common.utils.coder.YamlJsonTranslator; +import org.onap.policy.common.utils.resources.ResourceUtils; +import org.onap.policy.models.provider.PolicyModelsProvider; +import org.onap.policy.models.provider.PolicyModelsProviderFactory; +import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate; + +public class CommissioningControllerTest extends CommonRestController { + + private static final String TOSCA_SERVICE_TEMPLATE_YAML = + "src/test/resources/servicetemplates/pmsh_multiple_cl_tosca.yaml"; + private static final YamlJsonTranslator yamlTranslator = new YamlJsonTranslator(); + private static final String COMMISSIONING_ENDPOINT = "commission"; + private static ToscaServiceTemplate serviceTemplate = new ToscaServiceTemplate(); + + /** + * starts Main and inserts a commissioning template. + * + * @throws Exception if an error occurs + */ + @BeforeClass + public static void setUpBeforeClass() throws Exception { + CommonRestController.setUpBeforeClass("CommissioningApi"); + + serviceTemplate = yamlTranslator.fromYaml(ResourceUtils.getResourceAsString(TOSCA_SERVICE_TEMPLATE_YAML), + ToscaServiceTemplate.class); + } + + @AfterClass + public static void teardownAfterClass() { + CommonRestController.teardownAfterClass(); + } + + @Test + public void testSwagger() throws Exception { + super.testSwagger(COMMISSIONING_ENDPOINT); + } + + @Test + public void testUnauthorizedCreate() throws Exception { + assertUnauthorizedPost(COMMISSIONING_ENDPOINT, Entity.json(serviceTemplate)); + } + + @Test + public void testUnauthorizedQuery() throws Exception { + assertUnauthorizedGet(COMMISSIONING_ENDPOINT); + } + + @Test + public void testUnauthorizedQueryElements() throws Exception { + assertUnauthorizedGet(COMMISSIONING_ENDPOINT + "/elements"); + } + + @Test + public void testUnauthorizedDelete() throws Exception { + assertUnauthorizedDelete(COMMISSIONING_ENDPOINT); + } + + @Test + public void testCreateBadRequest() throws Exception { + Invocation.Builder invocationBuilder = super.sendRequest(COMMISSIONING_ENDPOINT); + Response resp = invocationBuilder.post(Entity.json("NotToscaServiceTempalte")); + + assertEquals(Response.Status.BAD_REQUEST.getStatusCode(), resp.getStatus()); + CommissioningResponse commissioningResponse = resp.readEntity(CommissioningResponse.class); + assertNotNull(commissioningResponse.getErrorDetails()); + assertNull(commissioningResponse.getAffectedControlLoopDefinitions()); + } + + @Test + public void testCreate() throws Exception { + Invocation.Builder invocationBuilder = super.sendRequest(COMMISSIONING_ENDPOINT); + Response resp = invocationBuilder.post(Entity.json(serviceTemplate)); + assertEquals(Response.Status.OK.getStatusCode(), resp.getStatus()); + CommissioningResponse commissioningResponse = resp.readEntity(CommissioningResponse.class); + + assertNotNull(commissioningResponse); + assertNull(commissioningResponse.getErrorDetails()); + // Response should return the number of node templates present in the service template + assertThat(commissioningResponse.getAffectedControlLoopDefinitions()).hasSize(13); + for (String nodeTemplateName : serviceTemplate.getToscaTopologyTemplate().getNodeTemplates().keySet()) { + assertTrue(commissioningResponse.getAffectedControlLoopDefinitions().stream() + .anyMatch(ac -> ac.getName().equals(nodeTemplateName))); + } + } + + @Test + public void testQuery_NoResultWithThisName() throws Exception { + createEntryInDB(); + + Invocation.Builder invocationBuilder = super.sendRequest(COMMISSIONING_ENDPOINT + "?name=noResultWithThisName"); + Response rawresp = invocationBuilder.buildGet().invoke(); + assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus()); + List entityList = rawresp.readEntity(List.class); + assertThat(entityList).isEmpty(); + } + + @Test + public void testQuery() throws Exception { + createEntryInDB(); + + Invocation.Builder invocationBuilder = super.sendRequest(COMMISSIONING_ENDPOINT); + Response rawresp = invocationBuilder.buildGet().invoke(); + assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus()); + List entityList = rawresp.readEntity(List.class); + assertNotNull(entityList); + assertThat(entityList).hasSize(2); + } + + @Test + public void testQueryElementsBadRequest() throws Exception { + createEntryInDB(); + + //Call get elements with no info + Invocation.Builder invocationBuilder = super.sendRequest(COMMISSIONING_ENDPOINT + "/elements"); + Response resp = invocationBuilder.buildGet().invoke(); + assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), resp.getStatus()); + } + + @Test + public void testQueryElements() throws Exception { + createEntryInDB(); + + Invocation.Builder invocationBuilder = super.sendRequest(COMMISSIONING_ENDPOINT + "/elements" + + "?name=org.onap.domain.pmsh.PMSHControlLoopDefinition"); + Response rawresp = invocationBuilder.buildGet().invoke(); + assertEquals(Response.Status.OK.getStatusCode(), rawresp.getStatus()); + List entityList = rawresp.readEntity(List.class); + assertNotNull(entityList); + assertThat(entityList).hasSize(4); + } + + @Test + public void testDeleteBadRequest() throws Exception { + createEntryInDB(); + + Invocation.Builder invocationBuilder = super.sendRequest(COMMISSIONING_ENDPOINT); + //Call delete with no info + Response resp = invocationBuilder.delete(); + assertEquals(Response.Status.INTERNAL_SERVER_ERROR.getStatusCode(), resp.getStatus()); + } + + @Test + public void testDelete() throws Exception { + createEntryInDB(); + + Invocation.Builder invocationBuilder = super.sendRequest(COMMISSIONING_ENDPOINT + "?name=" + + serviceTemplate.getName() + "&version=" + serviceTemplate.getVersion()); + //Call delete with no info + Response resp = invocationBuilder.delete(); + assertEquals(Response.Status.OK.getStatusCode(), resp.getStatus()); + + try (PolicyModelsProvider modelsProvider = new PolicyModelsProviderFactory() + .createPolicyModelsProvider(CommonRestController.getParameters())) { + List<ToscaServiceTemplate> templatesInDB = modelsProvider.getServiceTemplateList(null, null); + assertThat(templatesInDB).isEmpty(); + } + } + + private synchronized void createEntryInDB() throws Exception { + try (PolicyModelsProvider modelsProvider = new PolicyModelsProviderFactory() + .createPolicyModelsProvider(CommonRestController.getParameters())) { + modelsProvider.createServiceTemplate(serviceTemplate); + } + } +} |