From 6ad41e3ccd398a2721f41ad61c80b7bb03f7d127 Mon Sep 17 00:00:00 2001 From: Ittay Stern Date: Mon, 31 Dec 2018 17:21:27 +0200 Subject: Merge from ECOMP's repository Main Features -------------- - Async-Instantiation jobs mechanism major update; still WIP (package `org.onap.vid.job`) - New features in View/Edit: Activate fabric configuration; show related networks; soft delete - Support AAI service-tree traversal (`AAIServiceTree`) - In-memory cache for SDC models and certain A&AI queries (`CacheProviderWithLoadingCache`) - Upgrade TOSCA Parser and add parsing options; fix malformed TOSCA models - Resolve Cloud-Owner values for MSO - Pass X-ONAP headers to MSO Infrastructure -------------- - Remove codehaus' jackson mapper; use soley fasterxml 2.9.7 - Surefire invokes both TestNG and JUnit tests - Support Kotlin source files - AaiController2 which handles errors in a "Spring manner" - Inline generated-sources and remove jsonschema2pojo Quality -------- - Cumulative bug fixes (A&AI API, UI timeouts, and many more) - Many Sonar issues cleaned-up - Some unused classes removed - Minor changes in vid-automation project, allowing some API verification to run Hard Merges ------------ - HTTP Clients (MSO, A&AI, WebConfig, OutgoingRequestHeadersTest) - Moved `package org.onap.vid.controllers` to `controller`, without plural -- just to keep semantic sync with ECOMP. Reference commit in ECOMP: 3d1141625 Issue-ID: VID-378 Change-Id: I9c8d1e74caa41815891d441fc0760bb5f29c5788 Signed-off-by: Ittay Stern --- .../OperationalEnvironmentController.java | 362 +++++++++++++++++++++ 1 file changed, 362 insertions(+) create mode 100644 vid-app-common/src/main/java/org/onap/vid/controller/OperationalEnvironmentController.java (limited to 'vid-app-common/src/main/java/org/onap/vid/controller/OperationalEnvironmentController.java') diff --git a/vid-app-common/src/main/java/org/onap/vid/controller/OperationalEnvironmentController.java b/vid-app-common/src/main/java/org/onap/vid/controller/OperationalEnvironmentController.java new file mode 100644 index 000000000..21aef6858 --- /dev/null +++ b/vid-app-common/src/main/java/org/onap/vid/controller/OperationalEnvironmentController.java @@ -0,0 +1,362 @@ +/*- + * ============LICENSE_START======================================================= + * VID + * ================================================================================ + * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved. + * Modifications Copyright (C) 2018 Nokia. All rights reserved. + * ================================================================================ + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ============LICENSE_END========================================================= + */ +package org.onap.vid.controller; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import com.google.common.base.MoreObjects; +import io.joshworks.restclient.http.HttpResponse; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.onap.portalsdk.core.logging.logic.EELFLoggerDelegate; +import org.onap.vid.changeManagement.RequestDetailsWrapper; +import org.onap.vid.model.ExceptionResponse; +import org.onap.vid.model.RequestReferencesContainer; +import org.onap.vid.mso.MsoBusinessLogic; +import org.onap.vid.mso.MsoInterface; +import org.onap.vid.mso.MsoResponseWrapper2; +import org.onap.vid.mso.model.OperationalEnvironmentActivateInfo; +import org.onap.vid.mso.model.OperationalEnvironmentDeactivateInfo; +import org.onap.vid.mso.rest.OperationalEnvironment.OperationEnvironmentRequestDetails; +import org.onap.vid.mso.rest.RequestDetails; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.MissingServletRequestParameterException; +import org.springframework.web.bind.annotation.*; + +import javax.servlet.http.HttpServletRequest; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import java.util.stream.Collectors; +import java.util.stream.Stream; + +import static org.onap.vid.utils.Logging.getMethodCallerName; +import static org.onap.vid.utils.Logging.getMethodName; + +@RestController +@RequestMapping("operationalEnvironment") +public class OperationalEnvironmentController extends VidRestrictedBaseController { + + private final MsoInterface restMso; + private final MsoBusinessLogic msoBusinessLogic; + + private static final Pattern RECOVERY_ACTION_MESSAGE_PATTERN = Pattern.compile("from String \"(.*)\": value not"); + + + @Autowired + public OperationalEnvironmentController(MsoBusinessLogic msoBusinessLogic, MsoInterface msoClientInterface) { + this.restMso = msoClientInterface; + this.msoBusinessLogic = msoBusinessLogic; + } + + @RequestMapping(value = "/create", method = RequestMethod.POST) + public MsoResponseWrapper2 createOperationalEnvironment(HttpServletRequest request, @RequestBody OperationalEnvironmentCreateBody operationalEnvironment) { + debugStart(operationalEnvironment); + String userId = ControllersUtils.extractUserId(request); + RequestDetailsWrapper requestDetailsWrapper = msoBusinessLogic.convertParametersToRequestDetails(operationalEnvironment, userId); + String path = msoBusinessLogic.getOperationalEnvironmentCreationPath(); + + HttpResponse msoResponse = restMso.post(path, requestDetailsWrapper, RequestReferencesContainer.class); + debugEnd(msoResponse); + return new MsoResponseWrapper2<>(msoResponse); + } + + @RequestMapping(value = "/activate", method = RequestMethod.POST) + public MsoResponseWrapper2 activate(HttpServletRequest request, + @RequestParam("operationalEnvironment") String operationalEnvironmentId, + @RequestBody OperationalEnvironmentActivateBody activateRequest) throws MissingServletRequestParameterException { + + verifyIsNotEmpty(operationalEnvironmentId, "operationalEnvironment"); + + //manifest is null in case of wrong manifest structure (deserialization failure of the manifest) + if (activateRequest.getManifest()==null || activateRequest.getManifest().getServiceModelList()==null) { + throw new BadManifestException("Manifest structure is wrong"); + } + + String userId = ControllersUtils.extractUserId(request); + + OperationalEnvironmentActivateInfo activateInfo = new OperationalEnvironmentActivateInfo(activateRequest, userId, operationalEnvironmentId); + debugStart(activateInfo); + + String path = msoBusinessLogic.getOperationalEnvironmentActivationPath(activateInfo); + RequestDetailsWrapper requestDetailsWrapper = msoBusinessLogic.createOperationalEnvironmentActivationRequestDetails(activateInfo); + + HttpResponse msoResponse = restMso.post(path, requestDetailsWrapper, RequestReferencesContainer.class); + + debugEnd(msoResponse); + return new MsoResponseWrapper2<>(msoResponse); + } + + @RequestMapping(value = "/deactivate", method = RequestMethod.POST) + public MsoResponseWrapper2 deactivate(HttpServletRequest request, + @RequestParam("operationalEnvironment") String operationalEnvironmentId, + @RequestBody Map deactivationRequest) throws MissingServletRequestParameterException { + + verifyIsNotEmpty(operationalEnvironmentId, "operationalEnvironment"); + + String userId = ControllersUtils.extractUserId(request); + + OperationalEnvironmentDeactivateInfo deactivateInfo = new OperationalEnvironmentDeactivateInfo(userId, operationalEnvironmentId); + debugStart(deactivateInfo); + + String path = msoBusinessLogic.getOperationalEnvironmentDeactivationPath(deactivateInfo); + RequestDetailsWrapper requestDetailsWrapper = msoBusinessLogic.createOperationalEnvironmentDeactivationRequestDetails(deactivateInfo); + + HttpResponse msoResponse = restMso.post(path, requestDetailsWrapper, RequestReferencesContainer.class); + + debugEnd(msoResponse); + return new MsoResponseWrapper2<>(msoResponse); + } + + @RequestMapping(value = "/requestStatus", method = RequestMethod.GET) + public MsoResponseWrapper2 status(HttpServletRequest request, @RequestParam("requestId") String requestId) throws MissingServletRequestParameterException { + + debugStart(requestId); + + verifyIsNotEmpty(requestId, "requestId"); + String path = msoBusinessLogic.getCloudResourcesRequestsStatusPath(requestId); + + HttpResponse msoResponse = restMso.get(path, HashMap.class); + + LOGGER.debug(EELFLoggerDelegate.debugLogger, "end {}() => {}", getMethodName(), msoResponse); + return new MsoResponseWrapper2<>(msoResponse); + } + + @ExceptionHandler({ + org.springframework.web.bind.MissingServletRequestParameterException.class, + BadManifestException.class + }) + @ResponseStatus(value = HttpStatus.BAD_REQUEST) + public ExceptionResponse clientDerivedExceptionAsBadRequest(Exception e) { + // same handler, different HTTP Code + return exceptionHandler(e); + } + + @ExceptionHandler({ + org.springframework.http.converter.HttpMessageNotReadableException.class, + }) + @ResponseStatus(value = HttpStatus.BAD_REQUEST) + public ExceptionResponse handlingHttpMessageNotReadableException(Exception e) { + //in case of wrong value in manifest for RecoveryAction the message contains the class name. + //The wrong value is in also part of this messages + //within the pattern of: String value '': value not + //so we use regex to find the wrong value + if (e.getMessage().contains(OperationalEnvironmentRecoveryAction.class.getName())) { + LOGGER.error(EELFLoggerDelegate.errorLogger, "{}: {}", getMethodName(), ExceptionUtils.getMessage(e), e); + String message = "Wrong value for RecoveryAction in manifest. Allowed options are: "+OperationalEnvironmentRecoveryAction.options; + + Matcher matcher = RECOVERY_ACTION_MESSAGE_PATTERN.matcher(e.getMessage()); + if (matcher.find()) { + String wrongValue = matcher.group(1); + message = message+". Wrong value is: "+wrongValue; + } + return new ExceptionResponse(new BadManifestException(message)); + } + return exceptionHandler(e); + } + + + public enum OperationalEnvironmentRecoveryAction { + abort, + retry, + skip; + + public static final String options = Stream.of(OperationalEnvironmentRecoveryAction.values()).map(OperationalEnvironmentRecoveryAction::name).collect(Collectors.joining(", ")); + } + + public static class ActivateServiceModel { + private String serviceModelVersionId; + private OperationalEnvironmentRecoveryAction recoveryAction; + + public ActivateServiceModel() { + } + + public ActivateServiceModel(String serviceModelVersionId, OperationalEnvironmentRecoveryAction recoveryAction) { + this.serviceModelVersionId = serviceModelVersionId; + this.recoveryAction = recoveryAction; + } + + public String getServiceModelVersionId() { + return serviceModelVersionId; + } + + public void setServiceModelVersionId(String serviceModelVersionId) { + this.serviceModelVersionId = serviceModelVersionId; + } + + public OperationalEnvironmentRecoveryAction getRecoveryAction() { + return recoveryAction; + } + + public void setRecoveryAction(OperationalEnvironmentRecoveryAction recoveryAction) { + this.recoveryAction = recoveryAction; + } + } + + @JsonIgnoreProperties(ignoreUnknown = true) + public static class OperationalEnvironmentManifest { + + + private List serviceModelList; + + public OperationalEnvironmentManifest() { + } + + public OperationalEnvironmentManifest(List serviceModelList) { + this.serviceModelList = serviceModelList; + } + + public List getServiceModelList() { + return serviceModelList; + } + + public void setServiceModelList(List serviceModelList) { + this.serviceModelList = serviceModelList; + } + } + + public static class OperationalEnvironmentActivateBody { + private final String relatedInstanceId; + private final String relatedInstanceName; + private final String workloadContext; + private final OperationalEnvironmentManifest manifest; + + public OperationalEnvironmentActivateBody(@JsonProperty(value = "relatedInstanceId", required = true) String relatedInstanceId, + @JsonProperty(value = "relatedInstanceName", required = true) String relatedInstanceName, + @JsonProperty(value = "workloadContext", required = true) String workloadContext, + @JsonProperty(value = "manifest", required = true) OperationalEnvironmentManifest manifest) { + this.relatedInstanceId = relatedInstanceId; + this.relatedInstanceName = relatedInstanceName; + this.workloadContext = workloadContext; + this.manifest = manifest; + } + + + public String getRelatedInstanceId() { + return relatedInstanceId; + } + + public String getRelatedInstanceName() { + return relatedInstanceName; + } + + public String getWorkloadContext() { + return workloadContext; + } + + public OperationalEnvironmentManifest getManifest() { + return manifest; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("relatedInstanceId", relatedInstanceId) + .add("relatedInstanceName", relatedInstanceName) + .add("workloadContext", workloadContext) + .add("manifest", manifest) + .toString(); + } + } + + public static class OperationalEnvironmentCreateBody { + private final String instanceName; + private final String ecompInstanceId; + private final String ecompInstanceName; + private final String operationalEnvironmentType; + private final String tenantContext; + private final String workloadContext; + + public OperationalEnvironmentCreateBody(@JsonProperty(value = "instanceName", required = true) String instanceName, + @JsonProperty(value = "ecompInstanceId", required = true) String ecompInstanceId, + @JsonProperty(value = "ecompInstanceName", required = true) String ecompInstanceName, + @JsonProperty(value = "operationalEnvironmentType", required = true) String operationalEnvironmentType, + @JsonProperty(value = "tenantContext", required = true) String tenantContext, + @JsonProperty(value = "workloadContext", required = true) String workloadContext) { + this.instanceName = instanceName; + this.ecompInstanceId = ecompInstanceId; + this.ecompInstanceName = ecompInstanceName; + this.operationalEnvironmentType = operationalEnvironmentType; + this.tenantContext = tenantContext; + this.workloadContext = workloadContext; + } + + public String getInstanceName() { + return instanceName; + } + + public String getEcompInstanceId() { + return ecompInstanceId; + } + + public String getEcompInstanceName() { + return ecompInstanceName; + } + + public String getOperationalEnvironmentType() { + return operationalEnvironmentType; + } + + public String getTenantContext() { + return tenantContext; + } + + public String getWorkloadContext() { + return workloadContext; + } + + @Override + public String toString() { + return MoreObjects.toStringHelper(this) + .add("instanceName", instanceName) + .add("ecompInstanceId", ecompInstanceId) + .add("ecompInstanceName", ecompInstanceName) + .add("operationalEnvironmentType", operationalEnvironmentType) + .add("tenantContext", tenantContext) + .add("workloadContext", workloadContext) + .toString(); + } + } + + private void debugEnd(HttpResponse msoResponse) { + LOGGER.debug(EELFLoggerDelegate.debugLogger, "end {}() => {}", getMethodCallerName(), msoResponse); + } + + private void debugStart(Object requestInfo) { + LOGGER.debug(EELFLoggerDelegate.debugLogger, "start {}({})", getMethodCallerName(), requestInfo); + } + + private void verifyIsNotEmpty(String fieldValue, String fieldName) throws MissingServletRequestParameterException { + if (StringUtils.isEmpty(fieldValue)) { + throw new MissingServletRequestParameterException(fieldName, "String"); + } + } + + public static class BadManifestException extends RuntimeException { + public BadManifestException(String message) { + super(message); + } + } + +} -- cgit 1.2.3-korg