re base code
[sdc.git] / catalog-be / src / main / java / org / openecomp / sdc / be / components / upgrade / UpgradeBusinessLogic.java
1 package org.openecomp.sdc.be.components.upgrade;
2
3 import fj.data.Either;
4 import org.openecomp.sdc.be.components.impl.ComponentInstanceBusinessLogic;
5 import org.openecomp.sdc.be.components.lifecycle.LifecycleBusinessLogic;
6 import org.openecomp.sdc.be.components.lifecycle.LifecycleChangeInfoWithAction;
7 import org.openecomp.sdc.be.components.validation.UserValidations;
8 import org.openecomp.sdc.be.dao.api.ActionStatus;
9 import org.openecomp.sdc.be.dao.jsongraph.TitanDao;
10 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
11 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
12 import org.openecomp.sdc.be.impl.ComponentsUtils;
13 import org.openecomp.sdc.be.model.*;
14 import org.openecomp.sdc.be.model.jsontitan.operations.ToscaOperationFacade;
15 import org.openecomp.sdc.be.model.jsontitan.operations.UpgradeOperation;
16 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
17 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
18 import org.openecomp.sdc.be.user.Role;
19 import org.openecomp.sdc.common.log.wrappers.Logger;
20 import org.openecomp.sdc.exception.ResponseFormat;
21
22 import java.util.*;
23 import java.util.stream.Collectors;
24
25 @org.springframework.stereotype.Component("upgradeBusinessLogic")
26 public class UpgradeBusinessLogic {
27
28     private final LifecycleBusinessLogic lifecycleBusinessLogic;
29     private final ComponentInstanceBusinessLogic componentInstanceBusinessLogic;
30     private final UserValidations userValidations;
31     private final ToscaOperationFacade toscaOperationFacade;
32     private final ComponentsUtils componentsUtils;
33     private final UpgradeOperation upgradeOperation;
34     private final TitanDao titanDao;
35     private LifecycleChangeInfoWithAction changeInfo = new LifecycleChangeInfoWithAction("automated upgrade");
36
37     private static final List<String> UUID_PROPS_NAMES = Arrays.asList("depending_service_uuid", "providing_service_uuid");
38     private static final List<String> INV_UUID_PROPS_NAMES = Arrays.asList("depending_service_invariant_uuid", "providing_service_invariant_uuid");
39     private static final List<String> NAME_PROPS_NAMES = Arrays.asList("depending_service_name", "providing_service_name");
40
41     private static final Logger LOGGER = Logger.getLogger(UpgradeBusinessLogic.class);
42
43     public UpgradeBusinessLogic(LifecycleBusinessLogic lifecycleBusinessLogic, ComponentInstanceBusinessLogic componentInstanceBusinessLogic, UserValidations userValidations, ToscaOperationFacade toscaOperationFacade, ComponentsUtils componentsUtils,
44                                 UpgradeOperation upgradeOperation, TitanDao titanDao) {
45         this.lifecycleBusinessLogic = lifecycleBusinessLogic;
46         this.componentInstanceBusinessLogic = componentInstanceBusinessLogic;
47         this.userValidations = userValidations;
48         this.toscaOperationFacade = toscaOperationFacade;
49         this.componentsUtils = componentsUtils;
50         this.upgradeOperation = upgradeOperation;
51         this.titanDao = titanDao;
52     }
53
54
55     /**
56      * 
57      * @param componentId
58      * @param userId
59      * @return
60      */
61     public UpgradeStatus automatedUpgrade(String componentId, List<UpgradeRequest> upgradeRequest, String userId) {
62         UpgradeStatus status = new UpgradeStatus();
63         User user = userValidations.validateUserExists(userId, "automated upgrade", false);
64
65         Either<Component, StorageOperationStatus> storageStatus = toscaOperationFacade.getToscaFullElement(componentId);
66         if (storageStatus.isRight()) {
67             status.setError(componentsUtils.getResponseFormatByResource(componentsUtils.convertFromStorageResponse(storageStatus.right().value()), componentId));
68             return status;
69         }
70         Component component = storageStatus.left().value();
71         if (!component.isHighestVersion() || component.getLifecycleState() != LifecycleStateEnum.CERTIFIED) {
72             LOGGER.debug("automated Upgrade failed - target is not higest certified component {} state {} version {} ", component.getName(), component.getLifecycleState(), component.getVersion());
73             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_IS_NOT_HIHGEST_CERTIFIED, component.getName());
74             status.setError(responseFormat);
75             componentsUtils.auditComponentAdmin(responseFormat, user, component, getAuditTypeByComponent(component), component.getComponentType());
76
77             return status;
78         }
79         if ( component.isArchived() ){
80             LOGGER.debug("automated Upgrade failed - target is archived component {}  version {} ", component.getName(), component.getVersion());
81             ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.COMPONENT_IS_ARCHIVED, component.getName());
82             status.setError(responseFormat);
83             componentsUtils.auditComponentAdmin(responseFormat, user, component, getAuditTypeByComponent(component), component.getComponentType());
84
85             return status;
86         }
87         switch (component.getComponentType()) {
88         case RESOURCE:
89             hadnleUpgradeVFInService(component, upgradeRequest, user, status);
90             break;
91         case SERVICE:
92             hadnleUpgradeService(component, upgradeRequest, user, status);
93             break;
94         default:
95             LOGGER.debug("automated Upgrade failed - Not supported type {} for component {} ", component.getComponentType(), component.getName());
96             status.setError(componentsUtils.getResponseFormat(ActionStatus.UNSUPPORTED_ERROR));
97         }
98         return status;
99     }
100
101     /**
102      * 
103      * @param componentId
104      * @param userId
105      * @return
106      */
107     public Either<List<ComponentDependency>, ResponseFormat> getComponentDependencies(String componentId, String userId) {
108
109         User user = userValidations.validateUserExists(userId, "get Component Dependencies for automated upgrade", false);
110         try {
111             return upgradeOperation.getComponentDependencies(componentId)
112                     .right()
113                     .map(rf -> componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(rf)));
114         } finally {
115             // all operation were read only. no commit needed
116             titanDao.rollback();
117         }
118
119     }
120
121     private UpgradeStatus hadnleUpgradeVFInService(Component component, List<UpgradeRequest> componentUids, User user, UpgradeStatus upgradeStatus) {
122         Resource vfResource = (Resource) component;
123         if (vfResource.getResourceType() != ResourceTypeEnum.VF) {
124             LOGGER.debug("automated Upgrade failed - target is not VF resource {} {} ", vfResource.getName(), vfResource.getResourceType());
125             upgradeStatus.setStatus(ActionStatus.GENERAL_ERROR);
126             componentsUtils.auditComponentAdmin(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR), user, component, getAuditTypeByComponent(component), component.getComponentType());
127             return upgradeStatus;
128         }
129         componentUids.forEach(request -> upgradeInSingleService(request, vfResource, user, upgradeStatus));
130         upgradeStatus.setStatus(ActionStatus.OK);
131         componentsUtils.auditComponentAdmin(componentsUtils.getResponseFormat(ActionStatus.OK), user, component, AuditingActionEnum.VF_UPGRADE_SERVICES, component.getComponentType());
132
133         return upgradeStatus;
134     }
135
136     private UpgradeStatus hadnleUpgradeService(Component component, List<UpgradeRequest> upgradeRequest, User user, UpgradeStatus upgradeStatus) {
137         if ( Role.TESTER.name().equals(user.getRole()) ){
138             user.setRole(Role.DESIGNER.name());
139             LOGGER.debug("Change temporary for update service reference user role from TESTER to DESINGER");
140         }
141         Service service = (Service) component;
142         upgradeRequest.forEach(request -> upgradeSingleService(request, service, user, upgradeStatus));
143         upgradeStatus.setStatus(ActionStatus.OK);
144         componentsUtils.auditComponentAdmin(componentsUtils.getResponseFormat(ActionStatus.OK), user, component, AuditingActionEnum.UPDATE_SERVICE_REFERENCE, component.getComponentType());
145        return upgradeStatus;
146     }
147
148     private ActionStatus upgradeSingleService(UpgradeRequest request, Service service, User user, UpgradeStatus upgradeStatus) {
149         if (request.getResourceId() == null) {
150             // upgrade proxy version
151             return upgradeInSingleService(request, service, user, upgradeStatus);
152         } else {
153             // upgrade allotted resource -> service
154             return upgradeChainResourceService(request, service, user, upgradeStatus);
155         }
156     }
157
158     private ActionStatus upgradeInSingleService(UpgradeRequest request, Component newVersionComponent, User user, UpgradeStatus upgradeStatus) {
159         String serviceId = request.getServiceId();
160         return toscaOperationFacade.getToscaFullElement(serviceId)
161                 .either(l -> handleService(l, newVersionComponent, user, upgradeStatus), err -> {
162             LOGGER.debug("Failed to fetch service by id {} error {}", serviceId, err);
163             ActionStatus errS = componentsUtils.convertFromStorageResponse(err);
164             upgradeStatus.addServiceStatus(serviceId, errS);
165             return errS;
166         });
167     }
168
169     private ActionStatus upgradeChainResourceService(UpgradeRequest request, Service service, User user, UpgradeStatus upgradeStatus) {
170         Component resource;
171         Either<? extends Component, ActionStatus> upgradeAllottedResource = upgradeAllottedResource(request, user, upgradeStatus, service);
172         if (upgradeAllottedResource.isRight()) {
173             return upgradeAllottedResource.right().value();
174         }
175
176         resource = upgradeAllottedResource.left().value();
177         // update VF instance in service
178
179         Either<Component, StorageOperationStatus> serviceContainer = toscaOperationFacade.getToscaFullElement(request.getServiceId());
180         if (serviceContainer.isRight()) {
181             LOGGER.debug("Failed to fetch resource by id {} error {}", request.getServiceId(), serviceContainer.right().value());
182             ActionStatus errS = componentsUtils.convertFromStorageResponse(serviceContainer.right().value());
183             upgradeStatus.addServiceStatus(request.getServiceId(), errS);
184             return errS;
185         }
186         return handleService(serviceContainer.left().value(), resource, user, upgradeStatus);
187
188     }
189
190     private Either<? extends Component, ActionStatus> upgradeAllottedResource(UpgradeRequest request, User user, UpgradeStatus upgradeStatus, Service service) {
191         return getElement(request.getResourceId(), upgradeStatus, request)
192                 .left()
193                 .bind(l -> upgradeStateAlloted(request, user, upgradeStatus, service, l));
194     }
195
196     private Either<Component, ActionStatus> getElement(String id, UpgradeStatus upgradeStatus, UpgradeRequest request) {
197         return toscaOperationFacade.getToscaElement(id)
198                 .right()
199                 .map(err -> {
200             ActionStatus errS = componentsUtils.convertFromStorageResponse(err);
201             upgradeStatus.addServiceStatus(request.getServiceId(), errS);
202             return errS;
203         });
204     }
205
206     private Either<? extends Component, ActionStatus> upgradeStateAlloted(UpgradeRequest request, User user, UpgradeStatus upgradeStatus, Service service, Component resource) {
207         if (resource.getLifecycleState() == LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT) {
208             LOGGER.debug("Automated upgrade failedd. Alloted vf {} is in state NOT_CERTIFIED_CHECKOUT", request.getResourceId());
209             upgradeStatus.addServiceStatus(request.getServiceId(), ActionStatus.RESOURCE_LIFECYCLE_STATE_NOT_VALID);
210             return Either.right(ActionStatus.RESOURCE_LIFECYCLE_STATE_NOT_VALID);
211         }
212         // check out VF
213         // update properties-reference to service in VF on VFCI
214         return changeComponentState(resource, LifeCycleTransitionEnum.CHECKOUT, user,  upgradeStatus, request.getServiceId())
215                 .left()
216                 .bind(l -> updateAllottedPropsAndCertify(request, user, upgradeStatus, service, l));
217     }
218
219     private Either<? extends Component, ActionStatus> updateAllottedPropsAndCertify(UpgradeRequest request, User user, UpgradeStatus upgradeStatus, Service service, Component resource) {
220         Either<? extends Component, ActionStatus> result = null;
221         try {
222             List<String> instanceIds = upgradeOperation.getInstanceIdFromAllottedEdge(resource.getUniqueId(), service.getInvariantUUID());
223             if (instanceIds != null) {
224                 Map<String, List<ComponentInstanceProperty>> componentInstancesProperties = resource.getComponentInstancesProperties();
225                 Map<String, List<ComponentInstanceProperty>> propertiesToUpdate = new HashMap<>();
226
227                 instanceIds.forEach(id -> findPropertiesToUpdate(id, componentInstancesProperties, propertiesToUpdate, service));
228
229                 Either<Map<String, List<ComponentInstanceProperty>>, StorageOperationStatus> updatePropsResult = toscaOperationFacade.updateComponentInstancePropsToComponent(propertiesToUpdate, resource.getUniqueId());
230                 if (updatePropsResult.isRight()) {
231                     LOGGER.debug("Failed to update properties in  Allotted resource {} {}, Error {}. ", resource.getName(), resource.getUniqueId(), updatePropsResult.right().value());
232
233                     result = Either.right(ActionStatus.GENERAL_ERROR);
234                     return result;
235                 }
236
237                 // certify VF
238                 result =  changeComponentState(resource, LifeCycleTransitionEnum.CERTIFY, user,  upgradeStatus, request.getServiceId());
239             } else {
240                 // nothing to update
241                 LOGGER.debug("No Instances to update in allotted resource {} ", resource.getName());
242                 result = Either.right(ActionStatus.NO_INSTANCES_TO_UPGRADE);
243             }
244             return result;
245         } finally  {
246             if ( result.isRight() ){
247                 // undo checkout resource in case of failure
248                 LOGGER.debug("Failed to update Allotted resource {} {}, Error {}. UNDOCHEKOUT our resource", resource.getName(), resource.getUniqueId(), result.right().value());
249                        
250                 upgradeStatus.addServiceStatus(request.getServiceId(), ActionStatus.GENERAL_ERROR);
251             }
252         }
253     }
254
255     private void undocheckoutComponent(User user, Component resource) {
256         Either<? extends Component, ResponseFormat> changeComponentState = lifecycleBusinessLogic.changeComponentState(resource.getComponentType(), resource.getUniqueId(), user, LifeCycleTransitionEnum.UNDO_CHECKOUT, changeInfo, false, true);
257         if (changeComponentState.isRight()) {
258             LOGGER.debug("Failed to UNDOCHECKOUT Service {} {}, Error {}", resource.getName(), resource.getUniqueId(), changeComponentState.right().value());
259         }
260     }
261
262     private void findPropertiesToUpdate(String id, Map<String, List<ComponentInstanceProperty>> componentInstancesProperties, Map<String, List<ComponentInstanceProperty>> propertiesToUpdate, Service service) {
263         List<ComponentInstanceProperty> list = componentInstancesProperties.get(id);
264         List<ComponentInstanceProperty> propsPerInstance = new ArrayList<>();
265         list.forEach(p -> {
266             if (UUID_PROPS_NAMES.contains(p.getName())) {
267                 p.setValue(service.getUUID());
268                 propsPerInstance.add(p);
269             }
270             if (INV_UUID_PROPS_NAMES.contains(p.getName())) {
271                 p.setValue(service.getInvariantUUID());
272                 propsPerInstance.add(p);
273             }
274             if (NAME_PROPS_NAMES.contains(p.getName())) {
275                 p.setValue(service.getName());
276                 propsPerInstance.add(p);
277             }
278         });
279         propertiesToUpdate.put(id, propsPerInstance);
280     }
281
282     private ActionStatus handleService(Component component, Component newVersionComponent, User user, UpgradeStatus upgradeStatus) {
283         if (component.getComponentType() != ComponentTypeEnum.SERVICE) {
284             LOGGER.debug("component with id  {} and name {} isn't SERVICE.  type{} ", component.getName(), component.getUniqueId(), component.getComponentType());
285             upgradeStatus.addServiceStatus(component, ActionStatus.GENERAL_ERROR);
286             return ActionStatus.GENERAL_ERROR;
287         }
288         
289         Service service = (Service) component;
290         if (component.getLifecycleState() != LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT) {
291             LOGGER.debug("Service {} {} is not in CHECKOUT state . Try to checkout it", component.getName(), component.getUniqueId());
292             Either<? extends Component, ActionStatus> changeComponentState = changeComponentState(component, LifeCycleTransitionEnum.CHECKOUT, user,  upgradeStatus, null);
293             if ( changeComponentState.isRight() ){
294                 return changeComponentState.right().value();
295             }
296             service = (Service) changeComponentState.left().value();
297             //need to fetch service again with capability properties
298             Either<Component, StorageOperationStatus> toscaFullElement = toscaOperationFacade.getToscaFullElement(service.getUniqueId());
299             if ( toscaFullElement.isRight() ){
300                 return componentsUtils.convertFromStorageResponse(toscaFullElement.right().value());
301             }
302             service = (Service) toscaFullElement.left().value();
303         }else{
304             LOGGER.debug("Service {} {} is  in CHECKOUT state . Restricted update operation", component.getName(), component.getUniqueId());
305             upgradeStatus.addServiceStatus(component, ActionStatus.COMPONENT_IN_CHECKOUT_STATE);
306             return ActionStatus.COMPONENT_IN_CHECKOUT_STATE;          
307         }
308         ActionStatus status = ActionStatus.GENERAL_ERROR;
309         try {
310             status = handleInstances(newVersionComponent, user, upgradeStatus, service);
311         } finally {
312             if (status != ActionStatus.OK) {
313                 LOGGER.debug("Failed to upgrade instance for service {} status {}. Undocheckout service", service.getName(), status);
314                 undocheckoutComponent(user, service);
315
316                 upgradeStatus.addServiceStatus(component, status);
317             }
318         }
319         return status;
320     }
321     
322     private Either<? extends Component,ActionStatus> changeComponentState(Component component, LifeCycleTransitionEnum nextState, User user, UpgradeStatus upgradeStatus, String idForStatus){
323         if ( component.isArchived() ){
324             LOGGER.debug("Component  {} from type {} id {} is archived, Error {}", nextState, component.getName(), component.getComponentType(), component.getUniqueId());
325             setUpgradeStatus(component, upgradeStatus, idForStatus);
326             return Either.right(ActionStatus.COMPONENT_IS_ARCHIVED);
327         }
328         return lifecycleBusinessLogic.changeComponentState(component.getComponentType(), component.getUniqueId(), user, nextState, changeInfo, false, true)
329                 .right()
330                 .map(err-> {
331                     LOGGER.debug("Failed to {} Component  {} from type {} id {}, Error {}", nextState, component.getName(), component.getComponentType(), component.getUniqueId(), err);
332                     setUpgradeStatus(component, upgradeStatus, idForStatus);
333                     return ActionStatus.GENERAL_ERROR;
334                          
335                 });
336     }
337
338
339     private void setUpgradeStatus(Component component, UpgradeStatus upgradeStatus, String idForStatus) {
340         if ( idForStatus == null ){ 
341             upgradeStatus.addServiceStatus(component, ActionStatus.GENERAL_ERROR);
342         }else{
343             upgradeStatus.addServiceStatus(idForStatus, ActionStatus.GENERAL_ERROR);
344         }
345     }
346
347     private ActionStatus handleInstances(Component newVersionComponent, User user, UpgradeStatus upgradeStatus, Service service) {
348         List<ComponentInstance> componentInstances = service.getComponentInstances();
349         if (componentInstances != null) {
350             List<ComponentInstance> instanceToChange = componentInstances
351                     .stream()
352                     .filter(ci -> matchInstance(ci, newVersionComponent))
353                     .collect(Collectors.toList());
354             if (instanceToChange != null && !instanceToChange.isEmpty()) {
355                 return changeInstances(newVersionComponent, user, upgradeStatus, service, instanceToChange);
356             } else {
357                 LOGGER.debug("No instances for change version");
358                 return ActionStatus.NO_INSTANCES_TO_UPGRADE;
359             }
360         }
361         return ActionStatus.OK;
362     }
363
364     private ActionStatus changeInstances(Component newVersionComponent, User user, UpgradeStatus upgradeStatus, Service service, List<ComponentInstance> instanceToChange) {
365         Component serviceToUpgrade = service;
366         for (ComponentInstance ci : instanceToChange) {
367             Either<Component, ActionStatus> fetchService = fetchService(service.getUniqueId(),service.getName());
368             if ( fetchService.isRight()){
369                 upgradeStatus.addServiceStatus(service, fetchService.right().value());
370                 return fetchService.right().value();
371             }
372             serviceToUpgrade = fetchService.left().value();
373             ActionStatus status = changeVersionOfInstance(serviceToUpgrade, ci, newVersionComponent, user);
374             if (status != ActionStatus.OK) {
375                 LOGGER.debug("Failed to change for instance {} version in service {}", ci.getName(), service.getName());
376                 upgradeStatus.addServiceStatus(service, status);
377                 return status;
378             }
379         }
380         Either<Component, ActionStatus> fetchService = fetchService(service.getUniqueId(),service.getName());
381         if ( fetchService.isRight()){
382             upgradeStatus.addServiceStatus(service, fetchService.right().value());
383             return fetchService.right().value();
384         }
385         serviceToUpgrade = fetchService.left().value();
386         
387         Either<? extends Component, ActionStatus> changeComponentState = changeComponentState(serviceToUpgrade, LifeCycleTransitionEnum.CHECKIN, user,  upgradeStatus, null);
388         if ( changeComponentState.isRight() ){
389             return changeComponentState.right().value();
390         }
391         upgradeStatus.addServiceStatus(serviceToUpgrade, ActionStatus.OK);
392         return ActionStatus.OK;
393     }
394
395
396     private Either<Component, ActionStatus> fetchService(String uniqueId, String name) {
397         return toscaOperationFacade.getToscaFullElement(uniqueId)
398                 .right()
399                 .map(r->{
400                     LOGGER.debug("Failed to fetch service {} id {} error {}", name, uniqueId, r);
401                     return ActionStatus.GENERAL_ERROR;
402                 });
403     }
404
405     private ActionStatus changeVersionOfInstance(Component service, ComponentInstance ci, Component newVersionComponent, User user) {
406         LOGGER.debug("In Service {} change instance version {} to version {}", service.getName(), ci.getName(), newVersionComponent.getVersion());
407         ComponentInstance newComponentInstance = new ComponentInstance();
408         newComponentInstance.setComponentUid(newVersionComponent.getUniqueId());
409         Either<ComponentInstance, ResponseFormat> changeInstanceVersion = componentInstanceBusinessLogic.changeInstanceVersion(service, ci, newComponentInstance, user, service.getComponentType());
410         if (changeInstanceVersion.isLeft()) {
411             return ActionStatus.OK;
412         } else {
413             return ActionStatus.GENERAL_ERROR;
414         }
415     }
416
417     private boolean matchInstance(ComponentInstance ci, Component newVersionComponent) {
418         Either<Component, StorageOperationStatus> toscaElement;
419         ComponentParametersView filters = new ComponentParametersView(true);
420         if (newVersionComponent.getComponentType() == ComponentTypeEnum.SERVICE) {
421             if (ci.getIsProxy()) {
422                 toscaElement = toscaOperationFacade.getToscaElement(ci.getSourceModelUid(), filters);
423             } else {
424                 return false;
425             }
426         } else {
427             toscaElement = toscaOperationFacade.getToscaElement(ci.getComponentUid(), filters);
428         }
429         if (toscaElement.isLeft()) {
430             Component origin = toscaElement.left().value();
431             if (newVersionComponent.getInvariantUUID().equals(origin.getInvariantUUID()) && !newVersionComponent.getVersion().equals(origin.getVersion())) {
432                 // only for same invariant UUID (same component) but different versions
433                 return true;
434             }
435         }
436         return false;
437     }
438     private AuditingActionEnum getAuditTypeByComponent(Component component){
439         if ( ComponentTypeEnum.RESOURCE == component.getComponentType()){
440             return AuditingActionEnum.VF_UPGRADE_SERVICES;
441         }
442         return AuditingActionEnum.UPDATE_SERVICE_REFERENCE;
443     }
444
445 }