44bdc813b4124ba3af01e63a8e43c99fe59cc766
[vid.git] / vid-app-common / src / main / java / org / onap / vid / controller / OperationalEnvironmentController.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * VID
4  * ================================================================================
5  * Copyright (C) 2017 - 2019 AT&T Intellectual Property. All rights reserved.
6  * Modifications Copyright (C) 2018 - 2019 Nokia. All rights reserved.
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  * 
12  *      http://www.apache.org/licenses/LICENSE-2.0
13  * 
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  */
21 package org.onap.vid.controller;
22
23 import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
24 import com.fasterxml.jackson.annotation.JsonProperty;
25 import com.google.common.base.MoreObjects;
26 import io.joshworks.restclient.http.HttpResponse;
27 import org.apache.commons.lang3.StringUtils;
28 import org.apache.commons.lang3.exception.ExceptionUtils;
29 import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate;
30 import org.onap.vid.changeManagement.RequestDetailsWrapper;
31 import org.onap.vid.model.ExceptionResponse;
32 import org.onap.vid.model.RequestReferencesContainer;
33 import org.onap.vid.mso.MsoBusinessLogic;
34 import org.onap.vid.mso.MsoInterface;
35 import org.onap.vid.mso.MsoResponseWrapper2;
36 import org.onap.vid.mso.MsoUtil;
37 import org.onap.vid.mso.model.OperationalEnvironmentActivateInfo;
38 import org.onap.vid.mso.model.OperationalEnvironmentDeactivateInfo;
39 import org.onap.vid.mso.rest.OperationalEnvironment.OperationEnvironmentRequestDetails;
40 import org.onap.vid.mso.rest.RequestDetails;
41 import org.onap.vid.utils.SystemPropertiesWrapper;
42 import org.springframework.beans.factory.annotation.Autowired;
43 import org.springframework.http.HttpStatus;
44 import org.springframework.web.bind.MissingServletRequestParameterException;
45 import org.springframework.web.bind.annotation.*;
46
47 import javax.servlet.http.HttpServletRequest;
48 import java.util.HashMap;
49 import java.util.List;
50 import java.util.Map;
51 import java.util.regex.Matcher;
52 import java.util.regex.Pattern;
53 import java.util.stream.Collectors;
54 import java.util.stream.Stream;
55
56 import static org.onap.vid.utils.Logging.getMethodCallerName;
57 import static org.onap.vid.utils.Logging.getMethodName;
58
59 @RestController
60 @RequestMapping("operationalEnvironment")
61 public class OperationalEnvironmentController extends VidRestrictedBaseController {
62
63     private final MsoInterface restMso;
64     private final MsoBusinessLogic msoBusinessLogic;
65     private final SystemPropertiesWrapper systemPropertiesWrapper;
66
67     private static final Pattern RECOVERY_ACTION_MESSAGE_PATTERN = Pattern.compile("from String \"(.*)\": value not");
68
69
70     @Autowired
71     public OperationalEnvironmentController(MsoBusinessLogic msoBusinessLogic, MsoInterface msoClientInterface, SystemPropertiesWrapper systemPropertiesWrapper) {
72         this.restMso = msoClientInterface;
73         this.msoBusinessLogic = msoBusinessLogic;
74         this.systemPropertiesWrapper = systemPropertiesWrapper;
75     }
76
77     @RequestMapping(value = "/create", method = RequestMethod.POST)
78     public MsoResponseWrapper2 createOperationalEnvironment(HttpServletRequest request, @RequestBody OperationalEnvironmentCreateBody operationalEnvironment) {
79         debugStart(operationalEnvironment);
80         String userId = new ControllersUtils(systemPropertiesWrapper).extractUserId(request);
81         RequestDetailsWrapper<OperationEnvironmentRequestDetails> requestDetailsWrapper = msoBusinessLogic.convertParametersToRequestDetails(operationalEnvironment, userId);
82         String path = msoBusinessLogic.getOperationalEnvironmentCreationPath();
83
84         return MsoUtil.wrapResponse2(restMso.post(path, requestDetailsWrapper, String.class), RequestReferencesContainer.class);
85     }
86
87     @RequestMapping(value = "/activate", method = RequestMethod.POST)
88     public MsoResponseWrapper2 activate(HttpServletRequest request,
89                                         @RequestParam("operationalEnvironment") String operationalEnvironmentId,
90                                         @RequestBody OperationalEnvironmentActivateBody activateRequest) throws MissingServletRequestParameterException {
91
92         verifyIsNotEmpty(operationalEnvironmentId, "operationalEnvironment");
93
94         //manifest is null in case of wrong manifest structure (deserialization failure of the manifest)
95         if (activateRequest.getManifest()==null || activateRequest.getManifest().getServiceModelList()==null) {
96             throw new BadManifestException("Manifest structure is wrong");
97         }
98
99         String userId = new ControllersUtils(systemPropertiesWrapper).extractUserId(request);
100
101         OperationalEnvironmentActivateInfo activateInfo = new OperationalEnvironmentActivateInfo(activateRequest, userId, operationalEnvironmentId);
102         debugStart(activateInfo);
103
104         String path = msoBusinessLogic.getOperationalEnvironmentActivationPath(activateInfo);
105         RequestDetailsWrapper<RequestDetails> requestDetailsWrapper = msoBusinessLogic.createOperationalEnvironmentActivationRequestDetails(activateInfo);
106
107         return MsoUtil.wrapResponse2(restMso.post(path, requestDetailsWrapper, String.class), RequestReferencesContainer.class);
108     }
109
110     @RequestMapping(value = "/deactivate", method = RequestMethod.POST)
111     public MsoResponseWrapper2 deactivate(HttpServletRequest request,
112                                           @RequestParam("operationalEnvironment") String operationalEnvironmentId,
113                                           @RequestBody Map deactivationRequest) throws MissingServletRequestParameterException {
114
115         verifyIsNotEmpty(operationalEnvironmentId, "operationalEnvironment");
116
117         String userId = new ControllersUtils(systemPropertiesWrapper).extractUserId(request);
118
119         OperationalEnvironmentDeactivateInfo deactivateInfo = new OperationalEnvironmentDeactivateInfo(userId, operationalEnvironmentId);
120         debugStart(deactivateInfo);
121
122         String path = msoBusinessLogic.getOperationalEnvironmentDeactivationPath(deactivateInfo);
123         RequestDetailsWrapper<RequestDetails> requestDetailsWrapper =  msoBusinessLogic.createOperationalEnvironmentDeactivationRequestDetails(deactivateInfo);
124
125         return MsoUtil.wrapResponse2(restMso.post(path, requestDetailsWrapper, String.class), RequestReferencesContainer.class);
126     }
127
128     @RequestMapping(value = "/requestStatus", method = RequestMethod.GET)
129     public MsoResponseWrapper2 status(HttpServletRequest request, @RequestParam("requestId") String requestId) throws MissingServletRequestParameterException {
130
131         debugStart(requestId);
132
133         verifyIsNotEmpty(requestId, "requestId");
134         String path = msoBusinessLogic.getCloudResourcesRequestsStatusPath(requestId);
135
136         return MsoUtil.wrapResponse2(restMso.get(path, String.class), HashMap.class);
137     }
138
139     @ExceptionHandler({
140             org.springframework.web.bind.MissingServletRequestParameterException.class,
141             BadManifestException.class
142     })
143     @ResponseStatus(value = HttpStatus.BAD_REQUEST)
144     public ExceptionResponse clientDerivedExceptionAsBadRequest(Exception e) {
145         // same handler, different HTTP Code
146         return exceptionHandler(e);
147     }
148
149     @ExceptionHandler({
150             org.springframework.http.converter.HttpMessageNotReadableException.class,
151     })
152     @ResponseStatus(value = HttpStatus.BAD_REQUEST)
153     public ExceptionResponse handlingHttpMessageNotReadableException(Exception e) {
154         //in case of wrong value in manifest for RecoveryAction the message contains the class name.
155         //The wrong value is in also part of this messages
156         //within the pattern of: String value '<WRONG_VALUE>': value not
157         //so we use regex to find the wrong value
158         if (e.getMessage().contains(OperationalEnvironmentRecoveryAction.class.getName())) {
159             LOGGER.error(EELFLoggerDelegate.errorLogger, "{}: {}", getMethodName(), ExceptionUtils.getMessage(e), e);
160             String message = "Wrong value for RecoveryAction in manifest. Allowed options are: "+OperationalEnvironmentRecoveryAction.options;
161
162             Matcher matcher = RECOVERY_ACTION_MESSAGE_PATTERN.matcher(e.getMessage());
163             if (matcher.find()) {
164                 String wrongValue = matcher.group(1);
165                 message = message+". Wrong value is: "+wrongValue;
166             }
167             return new ExceptionResponse(new BadManifestException(message));
168         }
169         return exceptionHandler(e);
170     }
171
172
173     public enum OperationalEnvironmentRecoveryAction {
174         abort,
175         retry,
176         skip;
177
178         public static final String options = Stream.of(OperationalEnvironmentRecoveryAction.values()).map(OperationalEnvironmentRecoveryAction::name).collect(Collectors.joining(", "));
179     }
180
181     public static class ActivateServiceModel {
182         private String serviceModelVersionId;
183         private OperationalEnvironmentRecoveryAction recoveryAction;
184
185         public ActivateServiceModel() {
186         }
187
188         public ActivateServiceModel(String serviceModelVersionId, OperationalEnvironmentRecoveryAction recoveryAction) {
189             this.serviceModelVersionId = serviceModelVersionId;
190             this.recoveryAction = recoveryAction;
191         }
192
193         public String getServiceModelVersionId() {
194             return serviceModelVersionId;
195         }
196
197         public void setServiceModelVersionId(String serviceModelVersionId) {
198             this.serviceModelVersionId = serviceModelVersionId;
199         }
200
201         public OperationalEnvironmentRecoveryAction getRecoveryAction() {
202             return recoveryAction;
203         }
204
205         public void setRecoveryAction(OperationalEnvironmentRecoveryAction recoveryAction) {
206             this.recoveryAction = recoveryAction;
207         }
208     }
209
210     @JsonIgnoreProperties(ignoreUnknown = true)
211     public static class OperationalEnvironmentManifest {
212
213
214         private List<ActivateServiceModel> serviceModelList;
215
216         public OperationalEnvironmentManifest() {
217         }
218
219         public OperationalEnvironmentManifest(List<ActivateServiceModel> serviceModelList) {
220             this.serviceModelList = serviceModelList;
221         }
222
223         public List<ActivateServiceModel> getServiceModelList() {
224             return serviceModelList;
225         }
226
227         public void setServiceModelList(List<ActivateServiceModel> serviceModelList) {
228             this.serviceModelList = serviceModelList;
229         }
230     }
231
232     public static class OperationalEnvironmentActivateBody {
233         private final String relatedInstanceId;
234         private final String relatedInstanceName;
235         private final String workloadContext;
236         private final OperationalEnvironmentManifest manifest;
237
238         public OperationalEnvironmentActivateBody(@JsonProperty(value = "relatedInstanceId", required = true) String relatedInstanceId,
239                                                   @JsonProperty(value = "relatedInstanceName", required = true) String relatedInstanceName,
240                                                   @JsonProperty(value = "workloadContext", required = true) String workloadContext,
241                                                   @JsonProperty(value = "manifest", required = true) OperationalEnvironmentManifest manifest) {
242             this.relatedInstanceId = relatedInstanceId;
243             this.relatedInstanceName = relatedInstanceName;
244             this.workloadContext = workloadContext;
245             this.manifest = manifest;
246         }
247
248
249         public String getRelatedInstanceId() {
250             return relatedInstanceId;
251         }
252
253         public String getRelatedInstanceName() {
254             return relatedInstanceName;
255         }
256
257         public String getWorkloadContext() {
258             return workloadContext;
259         }
260
261         public OperationalEnvironmentManifest getManifest() {
262             return manifest;
263         }
264
265         @Override
266         public String toString() {
267             return MoreObjects.toStringHelper(this)
268                     .add("relatedInstanceId", relatedInstanceId)
269                     .add("relatedInstanceName", relatedInstanceName)
270                     .add("workloadContext", workloadContext)
271                     .add("manifest", manifest)
272                     .toString();
273         }
274     }
275
276     public static class OperationalEnvironmentCreateBody {
277         private final String instanceName;
278         private final String ecompInstanceId;
279         private final String ecompInstanceName;
280         private final String operationalEnvironmentType;
281         private final String tenantContext;
282         private final String workloadContext;
283
284         public OperationalEnvironmentCreateBody(@JsonProperty(value = "instanceName", required = true) String instanceName,
285                                                 @JsonProperty(value = "ecompInstanceId", required = true) String ecompInstanceId,
286                                                 @JsonProperty(value = "ecompInstanceName", required = true) String ecompInstanceName,
287                                                 @JsonProperty(value = "operationalEnvironmentType", required = true) String operationalEnvironmentType,
288                                                 @JsonProperty(value = "tenantContext", required = true) String tenantContext,
289                                                 @JsonProperty(value = "workloadContext", required = true) String workloadContext) {
290             this.instanceName = instanceName;
291             this.ecompInstanceId = ecompInstanceId;
292             this.ecompInstanceName = ecompInstanceName;
293             this.operationalEnvironmentType = operationalEnvironmentType;
294             this.tenantContext = tenantContext;
295             this.workloadContext = workloadContext;
296         }
297
298         public String getInstanceName() {
299             return instanceName;
300         }
301
302         public String getEcompInstanceId() {
303             return ecompInstanceId;
304         }
305
306         public String getEcompInstanceName() {
307             return ecompInstanceName;
308         }
309
310         public String getOperationalEnvironmentType() {
311             return operationalEnvironmentType;
312         }
313
314         public String getTenantContext() {
315             return tenantContext;
316         }
317
318         public String getWorkloadContext() {
319             return workloadContext;
320         }
321
322         @Override
323         public String toString() {
324             return MoreObjects.toStringHelper(this)
325                     .add("instanceName", instanceName)
326                     .add("ecompInstanceId", ecompInstanceId)
327                     .add("ecompInstanceName", ecompInstanceName)
328                     .add("operationalEnvironmentType", operationalEnvironmentType)
329                     .add("tenantContext", tenantContext)
330                     .add("workloadContext", workloadContext)
331                     .toString();
332         }
333     }
334
335     private void debugEnd(HttpResponse<RequestReferencesContainer> msoResponse) {
336         LOGGER.debug(EELFLoggerDelegate.debugLogger, "end {}() => {}", getMethodCallerName(), msoResponse);
337     }
338
339     private void debugStart(Object requestInfo) {
340         LOGGER.debug(EELFLoggerDelegate.debugLogger, "start {}({})", getMethodCallerName(), requestInfo);
341     }
342
343     private void verifyIsNotEmpty(String fieldValue, String fieldName) throws MissingServletRequestParameterException {
344         if (StringUtils.isEmpty(fieldValue)) {
345             throw new MissingServletRequestParameterException(fieldName, "String");
346         }
347     }
348
349     public static class BadManifestException extends RuntimeException {
350         public BadManifestException(String message) {
351             super(message);
352         }
353     }
354
355 }