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