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