2 * ============LICENSE_START=======================================================
3 * Copyright (C) 2021 Nordix Foundation.
4 * ================================================================================
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
17 * SPDX-License-Identifier: Apache-2.0
18 * ============LICENSE_END=========================================================
21 package org.onap.policy.clamp.controlloop.runtime.main.rest;
23 import com.fasterxml.jackson.core.JsonProcessingException;
24 import com.fasterxml.jackson.databind.ObjectMapper;
25 import com.fasterxml.jackson.databind.PropertyNamingStrategies;
26 import io.swagger.annotations.ApiOperation;
27 import io.swagger.annotations.ApiParam;
28 import io.swagger.annotations.ApiResponse;
29 import io.swagger.annotations.ApiResponses;
30 import io.swagger.annotations.Authorization;
31 import io.swagger.annotations.Extension;
32 import io.swagger.annotations.ExtensionProperty;
33 import io.swagger.annotations.ResponseHeader;
34 import java.util.List;
35 import java.util.UUID;
36 import javax.ws.rs.core.Response.Status;
37 import org.onap.policy.clamp.controlloop.models.messages.rest.commissioning.CommissioningResponse;
38 import org.onap.policy.clamp.controlloop.runtime.commissioning.CommissioningProvider;
39 import org.onap.policy.clamp.controlloop.runtime.main.web.AbstractRestController;
40 import org.onap.policy.models.base.PfModelException;
41 import org.onap.policy.models.base.PfModelRuntimeException;
42 import org.onap.policy.models.tosca.authorative.concepts.ToscaNodeTemplate;
43 import org.onap.policy.models.tosca.authorative.concepts.ToscaServiceTemplate;
44 import org.slf4j.Logger;
45 import org.slf4j.LoggerFactory;
46 import org.springframework.http.HttpStatus;
47 import org.springframework.http.MediaType;
48 import org.springframework.http.ResponseEntity;
49 import org.springframework.web.bind.annotation.DeleteMapping;
50 import org.springframework.web.bind.annotation.GetMapping;
51 import org.springframework.web.bind.annotation.PostMapping;
52 import org.springframework.web.bind.annotation.RequestBody;
53 import org.springframework.web.bind.annotation.RequestHeader;
54 import org.springframework.web.bind.annotation.RequestParam;
55 import org.springframework.web.bind.annotation.RestController;
58 * Class to provide REST end points for creating, deleting, querying commissioned control loops.
61 public class CommissioningController extends AbstractRestController {
63 private static final Logger LOGGER = LoggerFactory.getLogger(CommissioningController.class);
65 private static final String TAGS = "Clamp Control Loop Commissioning API";
67 private final CommissioningProvider provider;
70 * Create Commissioning Controller.
72 * @param provider the CommissioningProvider
74 public CommissioningController(CommissioningProvider provider) {
75 this.provider = provider;
79 * Creates a control loop definition.
81 * @param requestId request ID used in ONAP logging
82 * @param body the body of control loop following TOSCA definition
86 @PostMapping(value = "/commission",
87 consumes = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML},
88 produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
90 value = "Commissions control loop definitions",
91 notes = "Commissions control loop definitions, returning the commissioned control loop definition IDs",
92 response = CommissioningResponse.class,
94 authorizations = @Authorization(value = AUTHORIZATION_TYPE),
97 name = VERSION_MINOR_NAME,
98 description = VERSION_MINOR_DESCRIPTION,
99 response = String.class),
101 name = VERSION_PATCH_NAME,
102 description = VERSION_PATCH_DESCRIPTION,
103 response = String.class),
105 name = VERSION_LATEST_NAME,
106 description = VERSION_LATEST_DESCRIPTION,
107 response = String.class),
109 name = REQUEST_ID_NAME,
110 description = REQUEST_ID_HDR_DESCRIPTION,
111 response = UUID.class)
116 name = EXTENSION_NAME,
118 @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
119 @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
126 @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
127 @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
128 @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
132 public ResponseEntity<CommissioningResponse> create(
134 name = REQUEST_ID_NAME,
135 required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
136 @ApiParam(value = "Entity Body of Control Loop", required = true) @RequestBody ToscaServiceTemplate body) {
138 return ResponseEntity.ok().body(provider.createControlLoopDefinitions(body));
140 } catch (PfModelRuntimeException | PfModelException e) {
141 LOGGER.warn("Commissioning of the control loops failed", e);
142 var resp = new CommissioningResponse();
143 resp.setErrorDetails(e.getErrorResponse().getErrorMessage());
144 return ResponseEntity.status(e.getErrorResponse().getResponseCode().getStatusCode()).body(resp);
150 * Deletes a control loop definition.
152 * @param requestId request ID used in ONAP logging
153 * @param name the name of the control loop definition to delete
154 * @param version the version of the control loop definition to delete
158 @DeleteMapping(value = "/commission",
159 produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
160 @ApiOperation(value = "Delete a commissioned control loop",
161 notes = "Deletes a Commissioned Control Loop, returning optional error details",
162 response = CommissioningResponse.class,
164 authorizations = @Authorization(value = AUTHORIZATION_TYPE),
167 name = VERSION_MINOR_NAME,
168 description = VERSION_MINOR_DESCRIPTION,
169 response = String.class),
171 name = VERSION_PATCH_NAME,
172 description = VERSION_PATCH_DESCRIPTION,
173 response = String.class),
175 name = VERSION_LATEST_NAME,
176 description = VERSION_LATEST_DESCRIPTION,
177 response = String.class),
179 name = REQUEST_ID_NAME,
180 description = REQUEST_ID_HDR_DESCRIPTION,
181 response = UUID.class)},
185 name = EXTENSION_NAME,
187 @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
188 @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
195 @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
196 @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
197 @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
201 public ResponseEntity<CommissioningResponse> delete(
203 name = REQUEST_ID_NAME,
204 required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
205 @ApiParam(value = "Control Loop definition name", required = true) @RequestParam(
206 value = "name") String name,
208 value = "Control Loop definition version",
209 required = true) @RequestParam("version") String version) {
212 return ResponseEntity.ok().body(provider.deleteControlLoopDefinition(name, version));
214 } catch (PfModelRuntimeException | PfModelException e) {
215 LOGGER.warn("Decommisssioning of control loop failed", e);
216 var resp = new CommissioningResponse();
217 resp.setErrorDetails(e.getErrorResponse().getErrorMessage());
218 return ResponseEntity.status(e.getErrorResponse().getResponseCode().getStatusCode()).body(resp);
224 * Queries details of all or specific control loop definitions.
226 * @param requestId request ID used in ONAP logging
227 * @param name the name of the control loop definition to get, null for all definitions
228 * @param version the version of the control loop definition to get, null for all definitions
229 * @return the control loop definitions
232 @GetMapping(value = "/commission",
233 produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
234 @ApiOperation(value = "Query details of the requested commissioned control loop definitions",
235 notes = "Queries details of the requested commissioned control loop definitions, "
236 + "returning all control loop details",
237 response = ToscaNodeTemplate.class,
239 authorizations = @Authorization(value = AUTHORIZATION_TYPE),
242 name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
243 response = String.class),
244 @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
245 response = String.class),
246 @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
247 response = String.class),
248 @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
249 response = UUID.class)},
253 name = EXTENSION_NAME,
255 @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
256 @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
263 @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
264 @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
265 @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
269 public ResponseEntity<?> query(
271 name = REQUEST_ID_NAME,
272 required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
273 @ApiParam(value = "Control Loop definition name", required = false) @RequestParam(
275 required = false) String name,
276 @ApiParam(value = "Control Loop definition version", required = false) @RequestParam(
278 required = false) String version) {
281 return ResponseEntity.ok().body(provider.getControlLoopDefinitions(name, version));
283 } catch (PfModelRuntimeException | PfModelException e) {
284 LOGGER.warn("Get of control loop definitions failed", e);
285 var resp = new CommissioningResponse();
286 resp.setErrorDetails(e.getErrorResponse().getErrorMessage());
287 return ResponseEntity.status(e.getErrorResponse().getResponseCode().getStatusCode()).body(resp);
293 * Retrieves the Tosca Service Template.
295 * @param requestId request ID used in ONAP logging
296 * @param name the name of the tosca service template to retrieve
297 * @param version the version of the tosca service template to get
298 * @return the specified tosca service template
301 @GetMapping(value = "/commission/toscaservicetemplate",
302 produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
303 @ApiOperation(value = "Query details of the requested tosca service templates",
304 notes = "Queries details of the requested commissioned tosca service template, "
305 + "returning all tosca service template details",
306 response = ToscaServiceTemplate.class,
308 authorizations = @Authorization(value = AUTHORIZATION_TYPE),
311 name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
312 response = String.class),
313 @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
314 response = String.class),
315 @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
316 response = String.class),
317 @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
318 response = UUID.class)},
322 name = EXTENSION_NAME,
324 @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
325 @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
332 @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
333 @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
334 @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
338 public ResponseEntity<?> queryToscaServiceTemplate(
340 name = REQUEST_ID_NAME,
341 required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
342 @ApiParam(value = "Tosca service template name", required = false) @RequestParam(
344 required = false) String name,
345 @ApiParam(value = "Tosca service template version", required = true) @RequestParam(
347 required = false) String version) {
350 var mapper = new ObjectMapper();
351 mapper.setPropertyNamingStrategy(PropertyNamingStrategies.SNAKE_CASE);
352 var response = mapper.writerWithDefaultPrettyPrinter()
353 .writeValueAsString(provider.getToscaServiceTemplateReduced(name, version));
355 return ResponseEntity.ok().body(response);
357 } catch (PfModelRuntimeException | PfModelException e) {
358 LOGGER.warn("Get of tosca service template failed", e);
359 var resp = new CommissioningResponse();
360 resp.setErrorDetails(e.getErrorResponse().getErrorMessage());
361 return ResponseEntity.status(e.getErrorResponse().getResponseCode().getStatusCode()).body(resp);
362 } catch (JsonProcessingException e) {
363 LOGGER.warn("Get of tosca service template failed", e);
364 var resp = new CommissioningResponse();
365 resp.setErrorDetails(e.getMessage());
366 return ResponseEntity.status(Status.BAD_REQUEST.getStatusCode()).body(resp);
371 * Retrieves the Json Schema for the specified Tosca Service Template.
373 * @param requestId request ID used in ONAP logging
374 * @param section section of the tosca service template to get schema for
375 * @return the specified tosca service template or section Json Schema
378 @GetMapping(value = "/commission/toscaServiceTemplateSchema",
379 produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
380 @ApiOperation(value = "Query details of the requested tosca service template json schema",
381 notes = "Queries details of the requested commissioned tosca service template json schema, "
382 + "returning all tosca service template json schema details",
383 response = ToscaServiceTemplate.class,
385 authorizations = @Authorization(value = AUTHORIZATION_TYPE),
388 name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
389 response = String.class),
390 @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
391 response = String.class),
392 @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
393 response = String.class),
394 @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
395 response = UUID.class)},
399 name = EXTENSION_NAME,
401 @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
402 @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
409 @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
410 @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
411 @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
415 public ResponseEntity<?> queryToscaServiceTemplateJsonSchema(
417 name = REQUEST_ID_NAME,
418 required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
419 @ApiParam(value = "Section of Template schema is desired for", required = false) @RequestParam(
421 required = false, defaultValue = "all") String section) {
423 return ResponseEntity.ok().body(provider.getToscaServiceTemplateSchema(section));
425 } catch (PfModelRuntimeException | PfModelException e) {
426 LOGGER.warn("Get of tosca service template json schema failed", e);
427 var resp = new CommissioningResponse();
428 resp.setErrorDetails(e.getErrorResponse().getErrorMessage());
429 return ResponseEntity.status(e.getErrorResponse().getResponseCode().getStatusCode()).body(resp);
430 } catch (JsonProcessingException e) {
431 LOGGER.warn("Get of tosca service template json schema failed", e);
432 var resp = new CommissioningResponse();
433 resp.setErrorDetails(e.getMessage());
434 return ResponseEntity.status(Status.BAD_REQUEST.getStatusCode()).body(resp);
439 * Retrieves the Common or Instance Properties for the specified Tosca Service Template.
441 * @param requestId request ID used in ONAP logging
442 * @param common a flag, true to get common properties, false to get instance properties
443 * @param name the name of the tosca service template to retrieve
444 * @param version the version of the tosca service template to get
445 * @return the specified tosca service template or section Json Schema
448 @GetMapping(value = "/commission/getCommonOrInstanceProperties",
449 produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
450 @ApiOperation(value = "Query details of the requested tosca service template common or instance properties",
451 notes = "Queries details of the requested commissioned tosca service template json common"
452 + "or instance properties, returning all tosca service template common or instance property details",
453 response = ToscaServiceTemplate.class,
454 tags = {"Clamp Control Loop Commissioning API"},
455 authorizations = @Authorization(value = AUTHORIZATION_TYPE),
458 name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
459 response = String.class),
460 @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
461 response = String.class),
462 @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
463 response = String.class),
464 @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
465 response = UUID.class)},
469 name = EXTENSION_NAME,
471 @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
472 @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
479 @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
480 @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
481 @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
485 public ResponseEntity<?> queryToscaServiceCommonOrInstanceProperties(
487 name = REQUEST_ID_NAME,
488 required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
489 @ApiParam(value = "Flag, true for common properties, false for instance", required = false) @RequestParam(
491 defaultValue = "false",
492 required = false) boolean common,
493 @ApiParam(value = "Tosca service template name", required = false) @RequestParam(
495 required = false) String name,
496 @ApiParam(value = "Tosca service template version", required = true) @RequestParam(
498 required = false) String version) {
500 return ResponseEntity.ok().body(provider.getNodeTemplatesWithCommonOrInstanceProperties(
501 common, name, version));
503 } catch (PfModelRuntimeException | PfModelException e) {
504 LOGGER.warn("Get of common or instance properties failed", e);
505 var resp = new CommissioningResponse();
506 resp.setErrorDetails(e.getErrorResponse().getErrorMessage());
507 return ResponseEntity.status(e.getErrorResponse().getResponseCode().getStatusCode()).body(resp);
512 * Queries the elements of a specific control loop.
514 * @param requestId request ID used in ONAP logging
515 * @param name the name of the control loop definition to get
516 * @param version the version of the control loop definition to get
517 * @return the control loop element definitions
520 @GetMapping(value = "/commission/elements",
521 produces = {MediaType.APPLICATION_JSON_VALUE, APPLICATION_YAML})
522 @ApiOperation(value = "Query details of the requested commissioned control loop element definitions",
523 notes = "Queries details of the requested commissioned control loop element definitions, "
524 + "returning all control loop elements' details",
525 response = ToscaNodeTemplate.class,
527 authorizations = @Authorization(value = AUTHORIZATION_TYPE),
530 name = VERSION_MINOR_NAME, description = VERSION_MINOR_DESCRIPTION,
531 response = String.class),
532 @ResponseHeader(name = VERSION_PATCH_NAME, description = VERSION_PATCH_DESCRIPTION,
533 response = String.class),
534 @ResponseHeader(name = VERSION_LATEST_NAME, description = VERSION_LATEST_DESCRIPTION,
535 response = String.class),
536 @ResponseHeader(name = REQUEST_ID_NAME, description = REQUEST_ID_HDR_DESCRIPTION,
537 response = UUID.class)},
541 name = EXTENSION_NAME,
543 @ExtensionProperty(name = API_VERSION_NAME, value = API_VERSION),
544 @ExtensionProperty(name = LAST_MOD_NAME, value = LAST_MOD_RELEASE)
551 @ApiResponse(code = AUTHENTICATION_ERROR_CODE, message = AUTHENTICATION_ERROR_MESSAGE),
552 @ApiResponse(code = AUTHORIZATION_ERROR_CODE, message = AUTHORIZATION_ERROR_MESSAGE),
553 @ApiResponse(code = SERVER_ERROR_CODE, message = SERVER_ERROR_MESSAGE)
557 public ResponseEntity<?> queryElements(
559 name = REQUEST_ID_NAME,
560 required = false) @ApiParam(REQUEST_ID_PARAM_DESCRIPTION) UUID requestId,
561 @ApiParam(value = "Control Loop definition name", required = false) @RequestParam(
563 required = false) String name,
564 @ApiParam(value = "Control Loop definition version", required = true) @RequestParam(
566 required = false) String version) {
569 List<ToscaNodeTemplate> nodeTemplate = provider.getControlLoopDefinitions(name, version);
570 // Prevent ambiguous queries with multiple returns
571 if (nodeTemplate.size() > 1) {
572 var resp = new CommissioningResponse();
573 resp.setErrorDetails("Multiple ControlLoops are not supported");
574 return ResponseEntity.status(HttpStatus.NOT_ACCEPTABLE).body(resp);
577 List<ToscaNodeTemplate> response = provider.getControlLoopElementDefinitions(nodeTemplate.get(0));
578 return ResponseEntity.ok().body(response);
580 } catch (PfModelRuntimeException | PfModelException e) {
581 LOGGER.warn("Get of control loop element definitions failed", e);
582 var resp = new CommissioningResponse();
583 resp.setErrorDetails(e.getErrorResponse().getErrorMessage());
584 return ResponseEntity.status(e.getErrorResponse().getResponseCode().getStatusCode()).body(resp);