SLAs for async methods
[policy/pap.git] / main / src / main / java / org / onap / policy / pap / main / rest / PdpGroupDeployControllerV1.java
1 /*
2  * ============LICENSE_START=======================================================
3  * ONAP PAP
4  * ================================================================================
5  * Copyright (C) 2019, 2021 AT&T Intellectual Property. All rights reserved.
6  * Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
7  * Modifications Copyright (C) 2022 Nordix Foundation.
8  * ================================================================================
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  *      http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  * ============LICENSE_END=========================================================
21  */
22
23 package org.onap.policy.pap.main.rest;
24
25 import io.micrometer.core.instrument.MeterRegistry;
26 import io.micrometer.core.instrument.Timer;
27 import io.swagger.annotations.ApiOperation;
28 import io.swagger.annotations.ApiParam;
29 import io.swagger.annotations.ApiResponse;
30 import io.swagger.annotations.ApiResponses;
31 import io.swagger.annotations.Authorization;
32 import io.swagger.annotations.Extension;
33 import io.swagger.annotations.ExtensionProperty;
34 import io.swagger.annotations.ResponseHeader;
35 import java.time.Duration;
36 import java.time.Instant;
37 import java.util.UUID;
38 import lombok.RequiredArgsConstructor;
39 import org.onap.policy.common.utils.resources.PrometheusUtils;
40 import org.onap.policy.models.base.PfModelException;
41 import org.onap.policy.models.base.PfModelRuntimeException;
42 import org.onap.policy.models.pap.concepts.PdpDeployPolicies;
43 import org.onap.policy.models.pap.concepts.PdpGroupDeployResponse;
44 import org.onap.policy.models.pdp.concepts.DeploymentGroups;
45 import org.onap.policy.models.pdp.concepts.PdpPolicyStatus;
46 import org.slf4j.Logger;
47 import org.slf4j.LoggerFactory;
48 import org.springframework.beans.factory.annotation.Autowired;
49 import org.springframework.http.ResponseEntity;
50 import org.springframework.web.bind.annotation.PostMapping;
51 import org.springframework.web.bind.annotation.RequestBody;
52 import org.springframework.web.bind.annotation.RequestHeader;
53 import org.springframework.web.bind.annotation.RequestMapping;
54 import org.springframework.web.bind.annotation.RestController;
55
56 /**
57  * Class to provide REST end points for PAP component to deploy a PDP group.
58  */
59 @RestController
60 @RequestMapping(path = "/policy/pap/v1")
61 @RequiredArgsConstructor
62 public class PdpGroupDeployControllerV1 extends PapRestControllerV1 {
63     public static final String POLICY_STATUS_URI = "/policy/pap/v1/policies/status";
64
65     public static final String DEPLOYMENT_RESPONSE_MSG = "Use the policy status url to fetch the latest status. "
66             + "Kindly note that when a policy is successfully undeployed,"
67             + " it will no longer appear in policy status response.";
68
69     private static final Logger logger = LoggerFactory.getLogger(PdpGroupDeployControllerV1.class);
70
71     private final PdpGroupDeployProvider provider;
72     private Timer deploySuccessTimer;
73     private Timer deployFailureTimer;
74
75
76     @Autowired
77     public PdpGroupDeployControllerV1(PdpGroupDeployProvider provider, MeterRegistry meterRegistry) {
78         this.provider = provider;
79         initMetrics(meterRegistry);
80     }
81
82     /**
83      * Initializes the metrics for delete operation.
84      *
85      * @param meterRegistry spring bean for MeterRegistry to add the new metric
86      */
87     public void initMetrics(MeterRegistry meterRegistry) {
88         String metricName = String.join(".", "pap", "policy", "deployments");
89         String description = "Timer for HTTP request to deploy/undeploy a policy";
90         deploySuccessTimer = Timer.builder(metricName).description(description)
91             .tags(PrometheusUtils.OPERATION_METRIC_LABEL, PrometheusUtils.DEPLOY_OPERATION,
92                 PrometheusUtils.STATUS_METRIC_LABEL, PdpPolicyStatus.State.SUCCESS.name())
93             .register(meterRegistry);
94         deployFailureTimer = Timer.builder(metricName).description(description)
95             .tags(PrometheusUtils.OPERATION_METRIC_LABEL, PrometheusUtils.DEPLOY_OPERATION,
96                 PrometheusUtils.STATUS_METRIC_LABEL, PdpPolicyStatus.State.FAILURE.name())
97             .register(meterRegistry);
98     }
99
100     /**
101      * Updates policy deployments within specific PDP groups.
102      *
103      * @param requestId request ID used in ONAP logging
104      * @param groups PDP group configuration
105      * @return a response
106      */
107     // @formatter:off
108     @PostMapping("pdps/deployments/batch")
109     @ApiOperation(value = "Updates policy deployments within specific PDP groups",
110         notes = "Updates policy deployments within specific PDP groups, returning optional error details",
111         response = PdpGroupDeployResponse.class,
112         tags = {"Deployments Update"},
113         authorizations = @Authorization(value = AUTHORIZATION_TYPE),
114         responseHeaders = {
115             @ResponseHeader(name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
116                             response = String.class),
117             @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
118                             response = String.class),
119             @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
120                             response = String.class),
121             @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
122                             response = UUID.class)},
123         extensions = {
124             @Extension(name = EXTENSION_NAME,
125                 properties = {
126                     @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
127                     @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
128                 })
129             })
130     @ApiResponses(value = {
131         @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
132         @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
133         @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
134     })
135     // @formatter:on
136     public ResponseEntity<PdpGroupDeployResponse> updateGroupPolicies(
137         @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) @RequestHeader(
138             required = false,
139             value = REQUEST_ID_NAME) final UUID requestId,
140         @ApiParam(value = "List of PDP Group Deployments", required = true) @RequestBody DeploymentGroups groups) {
141         return doOperation(requestId, "update policy deployments failed",
142             () -> provider.updateGroupPolicies(groups, getPrincipal()));
143     }
144
145     /**
146      * Deploys or updates PDP policies.
147      *
148      * @param requestId request ID used in ONAP logging
149      * @param policies PDP policies
150      * @return a response
151      */
152     // @formatter:off
153     @PostMapping("pdps/policies")
154     @ApiOperation(value = "Deploy or update PDP Policies",
155         notes = "Deploys or updates PDP Policies, returning optional error details",
156         response = PdpGroupDeployResponse.class,
157         tags = {"Deployments Update"},
158         authorizations = @Authorization(value = AUTHORIZATION_TYPE),
159         responseHeaders = {
160             @ResponseHeader(name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
161                             response = String.class),
162             @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
163                             response = String.class),
164             @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
165                             response = String.class),
166             @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
167                             response = UUID.class)},
168         extensions = {
169             @Extension(name = EXTENSION_NAME,
170                 properties = {
171                     @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
172                     @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
173                 })
174             })
175     @ApiResponses(value = {
176         @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
177         @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
178         @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
179     })
180     // @formatter:on
181     public ResponseEntity<PdpGroupDeployResponse> deployPolicies(
182         @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) @RequestHeader(
183             required = false,
184             value = REQUEST_ID_NAME) final UUID requestId,
185         @ApiParam(value = "PDP Policies; only the name is required") @RequestBody PdpDeployPolicies policies) {
186         return doOperation(requestId, "deploy policies failed",
187             () -> provider.deployPolicies(policies, getPrincipal()));
188     }
189
190     /**
191      * Invokes an operation.
192      *
193      * @param requestId request ID
194      * @param errmsg error message to log if the operation throws an exception
195      * @param runnable operation to invoke
196      * @return a {@link PdpGroupDeployResponse} response entity
197      */
198     private ResponseEntity<PdpGroupDeployResponse> doOperation(UUID requestId, String errmsg,
199         RunnableWithPfEx runnable) {
200         Instant start = Instant.now();
201         try {
202             runnable.run();
203             deploySuccessTimer.record(Duration.between(start, Instant.now()));
204             return addLoggingHeaders(addVersionControlHeaders(ResponseEntity.accepted()), requestId)
205                 .body(new PdpGroupDeployResponse(DEPLOYMENT_RESPONSE_MSG, POLICY_STATUS_URI));
206
207         } catch (PfModelException | PfModelRuntimeException e) {
208             logger.warn(errmsg, e);
209             var resp = new PdpGroupDeployResponse();
210             resp.setErrorDetails(e.getErrorResponse().getErrorMessage());
211             deployFailureTimer.record(Duration.between(start, Instant.now()));
212             return addLoggingHeaders(
213                 addVersionControlHeaders(ResponseEntity.status(e.getErrorResponse().getResponseCode().getStatusCode())),
214                 requestId).body(resp);
215         }
216     }
217
218 }