757c789d5cb76b0800a46f9fbf35c14c8255bce2
[sdc.git] /
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20 package org.openecomp.sdc.be.components.lifecycle;
21
22 import fj.data.Either;
23 import java.util.Arrays;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.Optional;
27 import org.openecomp.sdc.be.components.impl.ComponentBusinessLogic;
28 import org.openecomp.sdc.be.components.impl.ServiceBusinessLogic;
29 import org.openecomp.sdc.be.components.impl.exceptions.ByResponseFormatComponentException;
30 import org.openecomp.sdc.be.config.BeEcompErrorManager;
31 import org.openecomp.sdc.be.dao.api.ActionStatus;
32 import org.openecomp.sdc.be.dao.jsongraph.JanusGraphDao;
33 import org.openecomp.sdc.be.datatypes.elements.ComponentInstanceDataDefinition;
34 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
35 import org.openecomp.sdc.be.impl.ComponentsUtils;
36 import org.openecomp.sdc.be.model.Component;
37 import org.openecomp.sdc.be.model.ComponentInstance;
38 import org.openecomp.sdc.be.model.ComponentInstanceProperty;
39 import org.openecomp.sdc.be.model.LifeCycleTransitionEnum;
40 import org.openecomp.sdc.be.model.LifecycleStateEnum;
41 import org.openecomp.sdc.be.model.Resource;
42 import org.openecomp.sdc.be.model.Service;
43 import org.openecomp.sdc.be.model.User;
44 import org.openecomp.sdc.be.model.category.CategoryDefinition;
45 import org.openecomp.sdc.be.model.jsonjanusgraph.datamodel.ToscaElement;
46 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.NodeTemplateOperation;
47 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaElementLifecycleOperation;
48 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ToscaOperationFacade;
49 import org.openecomp.sdc.be.model.jsonjanusgraph.utils.ModelConverter;
50 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
51 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
52 import org.openecomp.sdc.be.tosca.ToscaUtils;
53 import org.openecomp.sdc.be.user.Role;
54 import org.openecomp.sdc.common.log.wrappers.Logger;
55 import org.openecomp.sdc.common.util.ValidationUtils;
56 import org.openecomp.sdc.exception.ResponseFormat;
57
58 public class CertificationChangeTransition extends LifeCycleTransition {
59
60     private static final String ALLOTTED_CATEGORY = "Allotted Resource";
61     private static final String DEPENDING_SRV_NAME = "depending_service_name";
62     private static final String PROVIDING_SRV_NAME = "providing_service_name";
63     private static final String PROVIDING_SRV_UUID = "providing_service_uuid";
64     private static final String DEPENDING_SRV_UUID = "depending_service_uuid";
65     private static final Logger log = Logger.getLogger(CertificationChangeTransition.class);
66     private LifecycleStateEnum nextState;
67     private LifeCycleTransitionEnum name;
68     private AuditingActionEnum auditingAction;
69     private NodeTemplateOperation nodeTemplateOperation;
70     private ServiceBusinessLogic serviceBusinessLogic;
71
72     public CertificationChangeTransition(ServiceBusinessLogic serviceBusinessLogic, LifeCycleTransitionEnum name, ComponentsUtils componentUtils,
73                                          ToscaElementLifecycleOperation lifecycleOperation, ToscaOperationFacade toscaOperationFacade,
74                                          JanusGraphDao janusGraphDao) {
75         super(componentUtils, lifecycleOperation, toscaOperationFacade, janusGraphDao);
76         this.name = name;
77         this.serviceBusinessLogic = serviceBusinessLogic;
78         // authorized roles
79         Role[] certificationChangeRoles = {Role.ADMIN, Role.DESIGNER};
80         Role[] resourceRoles = {Role.ADMIN, Role.DESIGNER};
81         addAuthorizedRoles(ComponentTypeEnum.RESOURCE, Arrays.asList(resourceRoles));
82         addAuthorizedRoles(ComponentTypeEnum.SERVICE, Arrays.asList(certificationChangeRoles));
83         this.auditingAction = AuditingActionEnum.CERTIFICATION_SUCCESS_RESOURCE;
84         this.nextState = LifecycleStateEnum.CERTIFIED;
85     }
86
87     @Override
88     public LifeCycleTransitionEnum getName() {
89         return name;
90     }
91
92     @Override
93     public AuditingActionEnum getAuditingAction() {
94         return auditingAction;
95     }
96
97     public NodeTemplateOperation getNodeTemplateOperation() {
98         return nodeTemplateOperation;
99     }
100
101     public void setNodeTemplateOperation(NodeTemplateOperation nodeTemplateOperation) {
102         this.nodeTemplateOperation = nodeTemplateOperation;
103     }
104
105     private ResponseFormat formatCertificationError(Component component, StorageOperationStatus response, ComponentTypeEnum componentType) {
106         BeEcompErrorManager.getInstance().logBeDaoSystemError("Change LifecycleState - Certify failed on graph");
107         log.debug("certification change failed on graph");
108         return componentUtils.getResponseFormatByComponent(componentUtils.convertFromStorageResponse(response), component, componentType);
109     }
110
111     @Override
112     public Either<Boolean, ResponseFormat> validateBeforeTransition(Component component, ComponentTypeEnum componentType, User modifier, User owner,
113                                                                     LifecycleStateEnum oldState, LifecycleChangeInfoWithAction lifecycleChangeInfo) {
114         String componentName = component.getComponentMetadataDefinition().getMetadataDataDefinition().getName();
115         log.info("validate before certification change. resource name={}, oldState={}, owner userId={}", componentName, oldState, owner.getUserId());
116         // validate user
117         Either<Boolean, ResponseFormat> userValidationResponse = userRoleValidation(modifier, component, componentType, lifecycleChangeInfo);
118         if (userValidationResponse.isRight()) {
119             log.debug("userRoleValidation failed");
120             return userValidationResponse;
121         }
122         if (oldState != LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT && oldState != LifecycleStateEnum.NOT_CERTIFIED_CHECKIN) {
123             log.debug("Valid states for certification are NOT_CERTIFIED_CHECKIN and NOT_CERTIFIED_CHECKOUT. {} is invalid state", oldState);
124             ResponseFormat error = componentUtils
125                 .getResponseFormat(ActionStatus.ILLEGAL_COMPONENT_STATE, componentName, componentType.name().toLowerCase(), oldState.name());
126             return Either.right(error);
127         }
128         return Either.left(true);
129     }
130
131     @Override
132     public <T extends Component> Either<T, ResponseFormat> changeState(ComponentTypeEnum componentType, Component component,
133                                                                        ComponentBusinessLogic componentBl, User modifier, User owner,
134                                                                        boolean shouldLock, boolean inTransaction) {
135         log.info("start performing certification change for resource {}", component.getUniqueId());
136         Either<T, ResponseFormat> result = null;
137         try {
138             handleValidationsAndArtifactsGenerationBeforeCertifying(componentType, component, componentBl, modifier, shouldLock, inTransaction);
139             Either<ToscaElement, StorageOperationStatus> certificationChangeResult = lifeCycleOperation
140                 .certifyToscaElement(component.getUniqueId(), modifier.getUserId(), owner.getUserId());
141             if (certificationChangeResult.isRight()) {
142                 ResponseFormat responseFormat = formatCertificationError(component, certificationChangeResult.right().value(), componentType);
143                 result = Either.right(responseFormat);
144                 return result;
145             }
146             ToscaElement certificationResult = certificationChangeResult.left().value();
147             T componentAfterCertification = ModelConverter.convertFromToscaElement(certificationResult);
148             if (result == null || result.isLeft()) {
149                 //update edges for allotted resource 
150                 StorageOperationStatus status = handleConnectionsForAllotted(componentAfterCertification);
151                 if (status != StorageOperationStatus.OK) {
152                     ResponseFormat responseFormat = formatCertificationError(componentAfterCertification, status, componentType);
153                     result = Either.right(responseFormat);
154                 }
155             }
156             updateCalculatedCapabilitiesRequirements(componentAfterCertification);
157             updateCapReqPropertiesOwnerId(componentAfterCertification);
158             result = Either.left(componentAfterCertification);
159             return result;
160         } finally {
161             if (result == null || result.isRight()) {
162                 BeEcompErrorManager.getInstance().logBeDaoSystemError("Change LifecycleState");
163                 if (!inTransaction) {
164                     log.debug("operation failed. do rollback");
165                     janusGraphDao.rollback();
166                 }
167             } else {
168                 if (!inTransaction) {
169                     log.debug("operation success. do commit");
170                     janusGraphDao.commit();
171                 }
172             }
173         }
174     }
175
176     private void updateCapReqPropertiesOwnerId(Component component) {
177         if (component.isTopologyTemplate() && ToscaUtils.isNotComplexVfc(component)) {
178             toscaOperationFacade.updateCapReqPropertiesOwnerId(component.getUniqueId());
179         }
180     }
181
182     Either<Boolean, ResponseFormat> validateAllResourceInstanceCertified(Component component) {
183         Either<Boolean, ResponseFormat> eitherResult = Either.left(true);
184         if (component.isVspArchived()) {
185             return Either.right(
186                 componentUtils.getResponseFormat(ActionStatus.ARCHIVED_ORIGINS_FOUND, component.getComponentType().name(), component.getName()));
187         }
188         List<ComponentInstance> resourceInstance = component.getComponentInstances();
189         if (resourceInstance != null) {
190             //Filter components instances with archived origins
191             Optional<ComponentInstance> archivedRIOptional = resourceInstance.stream().filter(ComponentInstanceDataDefinition::isOriginArchived)
192                 .findAny();
193             //RIs with archived origins found, return relevant error
194             if (archivedRIOptional.isPresent()) {
195                 return Either.right(
196                     componentUtils.getResponseFormat(ActionStatus.ARCHIVED_ORIGINS_FOUND, component.getComponentType().name(), component.getName()));
197             }
198             //Continue with searching for non certified RIs
199             Optional<ComponentInstance> nonCertifiedRIOptional = resourceInstance.stream()
200                 .filter(p -> !ValidationUtils.validateCertifiedVersion(p.getComponentVersion())).findAny();
201             // Uncertified Resource Found
202             if (nonCertifiedRIOptional.isPresent()) {
203                 ComponentInstance nonCertifiedRI = nonCertifiedRIOptional.get();
204                 ResponseFormat resFormat = getRelevantResponseFormatUncertifiedRI(nonCertifiedRI, component.getComponentType());
205                 eitherResult = Either.right(resFormat);
206             }
207         }
208         return eitherResult;
209     }
210
211     private ResponseFormat getRelevantResponseFormatUncertifiedRI(ComponentInstance nonCertifiedRI, ComponentTypeEnum componentType) {
212         Either<Resource, StorageOperationStatus> eitherResource = toscaOperationFacade.getToscaElement(nonCertifiedRI.getComponentUid());
213         if (eitherResource.isRight()) {
214             return componentUtils.getResponseFormat(ActionStatus.GENERAL_ERROR);
215         }
216         ActionStatus actionStatus;
217         Resource resource = eitherResource.left().value();
218         Either<Resource, StorageOperationStatus> status = toscaOperationFacade.findLastCertifiedToscaElementByUUID(resource);
219         if (ValidationUtils.validateMinorVersion(nonCertifiedRI.getComponentVersion())) {
220             if (status.isRight() || status.left().value() == null) {
221                 actionStatus = ActionStatus.VALIDATED_RESOURCE_NOT_FOUND;
222             } else {
223                 actionStatus = ActionStatus.FOUND_ALREADY_VALIDATED_RESOURCE;
224             }
225         } else {
226             if (status.isRight() || status.left().value() == null) {
227                 actionStatus = ActionStatus.FOUND_LIST_VALIDATED_RESOURCES;
228             } else {
229                 actionStatus = ActionStatus.FOUND_ALREADY_VALIDATED_RESOURCE;
230             }
231         }
232         return componentUtils.getResponseFormat(actionStatus, componentType == ComponentTypeEnum.RESOURCE ? "VF" : "service", resource.getName());
233     }
234
235     private void handleValidationsAndArtifactsGenerationBeforeCertifying(ComponentTypeEnum componentType, Component component,
236                                                                          ComponentBusinessLogic componentBl, User modifier, boolean shouldLock,
237                                                                          boolean inTransaction) {
238         if (component.isTopologyTemplate()) {
239             Either<Boolean, ResponseFormat> statusCert = validateAllResourceInstanceCertified(component);
240             if (statusCert.isRight()) {
241                 throw new ByResponseFormatComponentException(statusCert.right().value());
242             }
243         }
244         if (componentType == ComponentTypeEnum.SERVICE) {
245             Either<Service, ResponseFormat> generateHeatEnvResult = serviceBusinessLogic
246                 .generateHeatEnvArtifacts((Service) component, modifier, shouldLock, inTransaction);
247             if (generateHeatEnvResult.isRight()) {
248                 throw new ByResponseFormatComponentException(generateHeatEnvResult.right().value());
249             }
250             Either<Service, ResponseFormat> generateVfModuleResult = serviceBusinessLogic
251                 .generateVfModuleArtifacts(generateHeatEnvResult.left().value(), modifier, shouldLock, inTransaction);
252             if (generateVfModuleResult.isRight()) {
253                 throw new ByResponseFormatComponentException(generateVfModuleResult.right().value());
254             }
255             component = generateVfModuleResult.left().value();
256         }
257         componentBl.populateToscaArtifacts(component, modifier, true, inTransaction, shouldLock);
258     }
259
260     private void updateCalculatedCapabilitiesRequirements(Component certifiedComponent) {
261         if (certifiedComponent.getComponentType() == ComponentTypeEnum.SERVICE) {
262             toscaOperationFacade.updateNamesOfCalculatedCapabilitiesRequirements(certifiedComponent.getUniqueId());
263         }
264     }
265
266     private StorageOperationStatus handleConnectionsForAllotted(Component component) {
267         StorageOperationStatus status = StorageOperationStatus.OK;
268         if (component.getComponentType() == ComponentTypeEnum.RESOURCE && component.isTopologyTemplate()) {
269             List<CategoryDefinition> categories = component.getCategories();
270             Optional<CategoryDefinition> findFirst = categories.stream().filter(c -> c.getName().equals(ALLOTTED_CATEGORY)).findFirst();
271             if (findFirst.isPresent()) {
272                 findInstanceByAllottedProperties(component);
273             } else {
274                 log.debug("Component isn't from allotted category.");
275             }
276         }
277         return status;
278     }
279
280     private void findInstanceByAllottedProperties(Component component) {
281         log.debug("Component is from alloted category. Remove all previous ALLOTTED_OF connections for all instances");
282         nodeTemplateOperation.removeAllAllotedEdges(component.getUniqueId());
283         Map<String, List<ComponentInstanceProperty>> componentInstancesProperties = component.getComponentInstancesProperties();
284         if (componentInstancesProperties != null) {
285             componentInstancesProperties.entrySet().forEach(e -> {
286                 List<ComponentInstanceProperty> props = e.getValue();
287                 Optional<ComponentInstanceProperty> findProp = props.stream()
288                     .filter(p -> p.getName().equals(DEPENDING_SRV_NAME) || p.getName().equals(PROVIDING_SRV_NAME)).findFirst();
289                 if (findProp.isPresent()) {
290                     log.debug("Find specific properties [{} or {}]on instance {} ", DEPENDING_SRV_NAME, PROVIDING_SRV_NAME, e.getKey());
291                     handleAllotedInstance(component.getUniqueId(), e.getKey(), e.getValue());
292                 } else {
293                     log.debug("Not defined specific properties [{} or {}]on instance {} ", DEPENDING_SRV_NAME, PROVIDING_SRV_NAME, e.getKey());
294                 }
295             });
296         }
297     }
298
299     private StorageOperationStatus handleAllotedInstance(String componentId, String instanceId, List<ComponentInstanceProperty> props) {
300         ComponentInstanceProperty serviceUUIDProp = props.stream()
301             .filter(p -> p.getName().equals(PROVIDING_SRV_UUID) || p.getName().equals(DEPENDING_SRV_UUID)).findFirst().get();
302         if (serviceUUIDProp.getValue() != null && !serviceUUIDProp.getValue().contains("get_input")) {
303             log.debug("Handle Allotted edge on instance {} for service UUID {} ", instanceId, serviceUUIDProp.getValue());
304             return nodeTemplateOperation.createAllottedOfEdge(componentId, instanceId, serviceUUIDProp.getValue());
305         } else {
306             log.debug("An incorrectly defined service UUID for Allotted instance {} . Skip instance", instanceId, serviceUUIDProp.getValue());
307             return StorageOperationStatus.OK;
308         }
309     }
310 }