SLAs for async methods
[policy/pap.git] / main / src / main / java / org / onap / policy / pap / main / rest / PdpGroupDeleteControllerV1.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-2022 Nordix Foundation.
7  * Modifications Copyright (C) 2021 Bell Canada. All rights reserved.
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.PdpGroupDeleteResponse;
43 import org.onap.policy.models.pap.concepts.PdpGroupDeployResponse;
44 import org.onap.policy.models.pdp.concepts.PdpPolicyStatus;
45 import org.onap.policy.models.tosca.authorative.concepts.ToscaConceptIdentifierOptVersion;
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.DeleteMapping;
51 import org.springframework.web.bind.annotation.PathVariable;
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 delete a PDP group.
58  */
59 @RestController
60 @RequestMapping(path = "/policy/pap/v1")
61 @RequiredArgsConstructor
62 public class PdpGroupDeleteControllerV1 extends PapRestControllerV1 {
63     private static final Logger logger = LoggerFactory.getLogger(PdpGroupDeleteControllerV1.class);
64
65     private final PdpGroupDeleteProvider provider;
66     private Timer undeploySuccessTimer;
67     private Timer undeployFailureTimer;
68
69
70     @Autowired
71     public PdpGroupDeleteControllerV1(PdpGroupDeleteProvider provider, MeterRegistry meterRegistry) {
72         this.provider = provider;
73         initMetrics(meterRegistry);
74     }
75
76     /**
77      * Initializes the metrics for delete operation.
78      *
79      * @param meterRegistry spring bean for MeterRegistry to add the new metric
80      */
81     public void initMetrics(MeterRegistry meterRegistry) {
82         String metricName = String.join(".", "pap", "policy", "deployments");
83         String description = "Timer for HTTP request to deploy/undeploy a policy";
84         undeploySuccessTimer = Timer.builder(metricName).description(description)
85             .tags(PrometheusUtils.OPERATION_METRIC_LABEL, PrometheusUtils.UNDEPLOY_OPERATION,
86                 PrometheusUtils.STATUS_METRIC_LABEL, PdpPolicyStatus.State.SUCCESS.name())
87             .register(meterRegistry);
88         undeployFailureTimer = Timer.builder(metricName).description(description)
89             .tags(PrometheusUtils.OPERATION_METRIC_LABEL, PrometheusUtils.UNDEPLOY_OPERATION,
90                 PrometheusUtils.STATUS_METRIC_LABEL, PdpPolicyStatus.State.FAILURE.name())
91             .register(meterRegistry);
92     }
93
94     /**
95      * Deletes a PDP group.
96      *
97      * @param requestId request ID used in ONAP logging
98      * @param groupName name of the PDP group to be deleted
99      * @return a response
100      */
101     // @formatter:off
102     @DeleteMapping("pdps/groups/{name}")
103     @ApiOperation(value = "Delete PDP Group",
104         notes = "Deletes a PDP Group, returning optional error details",
105         response = PdpGroupDeleteResponse.class,
106         tags = {"PdpGroup Delete"},
107         authorizations = @Authorization(value = AUTHORIZATION_TYPE),
108         responseHeaders = {
109             @ResponseHeader(name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
110                             response = String.class),
111             @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
112                             response = String.class),
113             @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
114                             response = String.class),
115             @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
116                             response = UUID.class)},
117         extensions = {
118             @Extension(name = EXTENSION_NAME,
119                 properties = {
120                     @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
121                     @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
122                 })
123             })
124     @ApiResponses(value = {
125         @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
126         @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
127         @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
128     })
129     // @formatter:on
130     public ResponseEntity<PdpGroupDeleteResponse> deleteGroup(
131         @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) @RequestHeader(
132             required = false,
133             value = REQUEST_ID_NAME) final UUID requestId,
134         @ApiParam(value = "PDP Group Name") @PathVariable("name") String groupName) {
135         return doOperation(requestId, () -> provider.deleteGroup(groupName));
136     }
137
138     /**
139      * Undeploys the latest version of a policy from the PDPs.
140      *
141      * @param requestId request ID used in ONAP logging
142      * @param policyName name of the PDP Policy to be deleted
143      * @return a response
144      */
145     // @formatter:off
146     @DeleteMapping("pdps/policies/{name}")
147     @ApiOperation(value = "Undeploy a PDP Policy from PDPs",
148         notes = "Undeploys the latest version of a policy from the PDPs, returning optional error details",
149         response = PdpGroupDeployResponse.class,
150         tags = {"PdpGroup Delete"},
151         authorizations = @Authorization(value = AUTHORIZATION_TYPE),
152         responseHeaders = {
153             @ResponseHeader(name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
154                             response = String.class),
155             @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
156                             response = String.class),
157             @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
158                             response = String.class),
159             @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
160                             response = UUID.class)},
161         extensions = {
162             @Extension(name = EXTENSION_NAME,
163                 properties = {
164                     @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
165                     @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
166                 })
167             })
168     @ApiResponses(value = {
169         @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
170         @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
171         @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
172     })
173     // @formatter:on
174     public ResponseEntity<PdpGroupDeployResponse> deletePolicy(
175         @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) @RequestHeader(
176             required = false,
177             value = REQUEST_ID_NAME) final UUID requestId,
178         @ApiParam(value = "PDP Policy Name") @PathVariable("name") String policyName) {
179
180         return doUndeployOperation(requestId,
181             () -> provider.undeploy(new ToscaConceptIdentifierOptVersion(policyName, null), getPrincipal()));
182     }
183
184     /**
185      * Undeploys a specific version of a policy from the PDPs.
186      *
187      * @param requestId request ID used in ONAP logging
188      * @param policyName name of the PDP Policy to be deleted
189      * @param version version to be deleted
190      * @return a response
191      */
192     // @formatter:off
193     @DeleteMapping("pdps/policies/{name}/versions/{version}")
194     @ApiOperation(value = "Undeploy version of a PDP Policy from PDPs",
195         notes = "Undeploys a specific version of a policy from the PDPs, returning optional error details",
196         response = PdpGroupDeployResponse.class,
197         tags = {"PdpGroup Delete"},
198         authorizations = @Authorization(value = AUTHORIZATION_TYPE),
199         responseHeaders = {
200             @ResponseHeader(name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
201                             response = String.class),
202             @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
203                             response = String.class),
204             @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
205                             response = String.class),
206             @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
207                             response = UUID.class)},
208         extensions = {
209             @Extension(name = EXTENSION_NAME,
210                 properties = {
211                     @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
212                     @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
213                 })
214             })
215     @ApiResponses(value = {
216         @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
217         @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
218         @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
219     })
220     // @formatter:on
221     public ResponseEntity<PdpGroupDeployResponse> deletePolicyVersion(
222         @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) @RequestHeader(
223             required = false,
224             value = REQUEST_ID_NAME) final UUID requestId,
225         @ApiParam(value = "PDP Policy Name") @PathVariable("name") String policyName,
226         @ApiParam(value = "PDP Policy Version") @PathVariable("version") String version) {
227
228         return doUndeployOperation(requestId,
229             () -> provider.undeploy(new ToscaConceptIdentifierOptVersion(policyName, version), getPrincipal()));
230     }
231
232     /**
233      * Invokes an operation.
234      *
235      * @param requestId request ID
236      * @param runnable operation to invoke
237      * @return a {@link PdpGroupDeleteResponse} response entity
238      */
239     private ResponseEntity<PdpGroupDeleteResponse> doOperation(UUID requestId, RunnableWithPfEx runnable) {
240         try {
241             runnable.run();
242             return addLoggingHeaders(addVersionControlHeaders(ResponseEntity.ok()), requestId)
243                 .body(new PdpGroupDeleteResponse());
244
245         } catch (PfModelException | PfModelRuntimeException e) {
246             logger.warn("delete group failed", e);
247             var resp = new PdpGroupDeleteResponse();
248             resp.setErrorDetails(e.getErrorResponse().getErrorMessage());
249             return addLoggingHeaders(
250                 addVersionControlHeaders(ResponseEntity.status(e.getErrorResponse().getResponseCode().getStatusCode())),
251                 requestId).body(resp);
252         }
253     }
254
255     /**
256      * Invokes the undeployment operation.
257      *
258      * @param requestId request ID
259      * @param runnable operation to invoke
260      * @return a {@link PdpGroupDeployResponse} response entity
261      */
262     private ResponseEntity<PdpGroupDeployResponse> doUndeployOperation(UUID requestId, RunnableWithPfEx runnable) {
263         Instant start = Instant.now();
264         try {
265             runnable.run();
266             undeploySuccessTimer.record(Duration.between(start, Instant.now()));
267             return addLoggingHeaders(addVersionControlHeaders(ResponseEntity.accepted()), requestId)
268                 .body(new PdpGroupDeployResponse(PdpGroupDeployControllerV1.DEPLOYMENT_RESPONSE_MSG,
269                     PdpGroupDeployControllerV1.POLICY_STATUS_URI));
270
271         } catch (PfModelException | PfModelRuntimeException e) {
272             logger.warn("undeploy policy failed", e);
273             var resp = new PdpGroupDeployResponse();
274             resp.setErrorDetails(e.getErrorResponse().getErrorMessage());
275             undeployFailureTimer.record(Duration.between(start, Instant.now()));
276             return addLoggingHeaders(
277                 addVersionControlHeaders(ResponseEntity.status(e.getErrorResponse().getResponseCode().getStatusCode())),
278                 requestId).body(resp);
279         }
280     }
281 }