69a9cbdb242f9f2b8d21a275143d55931c6cab94
[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
21 package org.openecomp.sdc.be.components.lifecycle;
22
23 import java.util.ArrayList;
24 import java.util.Arrays;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28 import java.util.Map.Entry;
29 import java.util.Optional;
30 import java.util.Set;
31
32 import org.openecomp.sdc.be.components.distribution.engine.ServiceDistributionArtifactsBuilder;
33 import org.openecomp.sdc.be.components.impl.ComponentBusinessLogic;
34 import org.openecomp.sdc.be.components.impl.ServiceBusinessLogic;
35 import org.openecomp.sdc.be.dao.api.ActionStatus;
36 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
37 import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum;
38 import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum;
39 import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum;
40 import org.openecomp.sdc.be.impl.ComponentsUtils;
41 import org.openecomp.sdc.be.model.ArtifactDefinition;
42 import org.openecomp.sdc.be.model.CapabilityDefinition;
43 import org.openecomp.sdc.be.model.Component;
44 import org.openecomp.sdc.be.model.ComponentInstance;
45 import org.openecomp.sdc.be.model.LifeCycleTransitionEnum;
46 import org.openecomp.sdc.be.model.LifecycleStateEnum;
47 import org.openecomp.sdc.be.model.Operation;
48 import org.openecomp.sdc.be.model.RequirementAndRelationshipPair;
49 import org.openecomp.sdc.be.model.RequirementCapabilityRelDef;
50 import org.openecomp.sdc.be.model.Resource;
51 import org.openecomp.sdc.be.model.Service;
52 import org.openecomp.sdc.be.model.User;
53 import org.openecomp.sdc.be.model.operations.api.ILifecycleOperation;
54 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
55 import org.openecomp.sdc.be.model.operations.impl.CapabilityOperation;
56 import org.openecomp.sdc.be.model.operations.impl.ResourceOperation;
57 import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum;
58 import org.openecomp.sdc.be.tosca.ToscaExportHandler;
59 import org.openecomp.sdc.be.user.Role;
60 import org.openecomp.sdc.common.util.ValidationUtils;
61 import org.openecomp.sdc.exception.ResponseFormat;
62 import org.slf4j.Logger;
63 import org.slf4j.LoggerFactory;
64
65 import fj.data.Either;
66
67 public class CertificationRequestTransition extends LifeCycleTransition {
68
69         private static Logger log = LoggerFactory.getLogger(CertificationRequestTransition.class.getName());
70
71         private ServiceDistributionArtifactsBuilder serviceDistributionArtifactsBuilder;
72         private ResourceOperation resourceOperation;
73         private CapabilityOperation capabilityOperation;
74         private ServiceBusinessLogic serviceBusinessLogic;
75         private ToscaExportHandler toscaExportUtils;
76
77         public CertificationRequestTransition(ComponentsUtils componentUtils, ILifecycleOperation lifecycleOperation, ServiceDistributionArtifactsBuilder serviceDistributionArtifactsBuilder, ServiceBusinessLogic serviceBusinessLogic,
78                         CapabilityOperation capabilityOperation, ToscaExportHandler toscaExportUtils) {
79                 super(componentUtils, lifecycleOperation);
80
81                 // authorized roles
82                 Role[] resourceServiceCheckoutRoles = { Role.ADMIN, Role.DESIGNER };
83                 // Role[] productCheckoutRoles = {Role.ADMIN, Role.PRODUCT_MANAGER,
84                 // Role.PRODUCT_STRATEGIST};
85                 addAuthorizedRoles(ComponentTypeEnum.RESOURCE, Arrays.asList(resourceServiceCheckoutRoles));
86                 addAuthorizedRoles(ComponentTypeEnum.SERVICE, Arrays.asList(resourceServiceCheckoutRoles));
87                 // TODO to be later defined for product
88                 // addAuthorizedRoles(ComponentTypeEnum.PRODUCT,
89                 // Arrays.asList(productCheckoutRoles));
90
91                 this.serviceDistributionArtifactsBuilder = serviceDistributionArtifactsBuilder;
92                 if (lifeCycleOperation != null)
93                         this.resourceOperation = lifeCycleOperation.getResourceOperation();
94                 this.serviceBusinessLogic = serviceBusinessLogic;
95                 this.capabilityOperation = capabilityOperation;
96                 this.toscaExportUtils = toscaExportUtils;
97         }
98
99         @Override
100         public LifeCycleTransitionEnum getName() {
101                 return LifeCycleTransitionEnum.CERTIFICATION_REQUEST;
102         }
103
104         @Override
105         public AuditingActionEnum getAuditingAction() {
106                 return AuditingActionEnum.CERTIFICATION_REQUEST_RESOURCE;
107         }
108
109         protected Either<Boolean, ResponseFormat> validateAllResourceInstanceCertified(Component component) {
110                 Either<Boolean, ResponseFormat> eitherResult = Either.left(true);
111
112                 List<ComponentInstance> resourceInstance = component.getComponentInstances();
113                 if (resourceInstance != null) {
114                         Optional<ComponentInstance> nonCertifiedRIOptional = resourceInstance.stream().filter(p -> !ValidationUtils.validateCertifiedVersion(p.getComponentVersion())).findAny();
115                         // Uncertified Resource Found
116                         if (nonCertifiedRIOptional.isPresent()) {
117                                 ComponentInstance nonCertifiedRI = nonCertifiedRIOptional.get();
118                                 ResponseFormat resFormat = getRelevantResponseFormatUncertifiedRI(nonCertifiedRI, component.getComponentType());
119                                 eitherResult = Either.right(resFormat);
120                         }
121                 }
122                 return eitherResult;
123         }
124
125         private ResponseFormat getRelevantResponseFormatUncertifiedRI(ComponentInstance nonCertifiedRI, ComponentTypeEnum componentType) {
126
127                 ResponseFormat responseFormat;
128                 Either<Resource, StorageOperationStatus> eitherResource = resourceOperation.getResource(nonCertifiedRI.getComponentUid());
129                 if (eitherResource.isRight()) {
130
131                         responseFormat = componentUtils.getResponseFormat(ActionStatus.GENERAL_ERROR);
132
133                 } else {
134                         ActionStatus actionStatus;
135                         Resource resource = eitherResource.left().value();
136                         Either<List<Resource>, StorageOperationStatus> status = resourceOperation.findLastCertifiedResourceByUUID(resource);
137
138                         if (ValidationUtils.validateMinorVersion(nonCertifiedRI.getComponentVersion())) {
139                                 if (status.isRight() || status.left().value() == null || status.left().value().isEmpty()) {
140                                         actionStatus = ActionStatus.VALIDATED_RESOURCE_NOT_FOUND;
141                                 } else {
142                                         actionStatus = ActionStatus.FOUND_ALREADY_VALIDATED_RESOURCE;
143                                 }
144                         } else {
145                                 if (status.isRight() || status.left().value() == null || status.left().value().isEmpty())
146                                         actionStatus = ActionStatus.FOUND_LIST_VALIDATED_RESOURCES;
147                                 else {
148                                         actionStatus = ActionStatus.FOUND_ALREADY_VALIDATED_RESOURCE;
149                                 }
150
151                         }
152                         String compType = (componentType == ComponentTypeEnum.RESOURCE) ? "VF" : "service";
153                         responseFormat = componentUtils.getResponseFormat(actionStatus, compType, resource.getName());
154                 }
155                 return responseFormat;
156         }
157
158         private Either<ActionStatus, Map<String, ArtifactDefinition>> validateMandatoryArtifactsSupplied(Map<String, ArtifactDefinition> artifacts) {
159
160                 if (artifacts == null || true == artifacts.isEmpty()) {
161                         return Either.left(ActionStatus.OK);
162                 }
163
164                 Map<String, ArtifactDefinition> invalidArtifacts = new HashMap<String, ArtifactDefinition>();
165                 for (Entry<String, ArtifactDefinition> artifact : artifacts.entrySet()) {
166
167                         ArtifactDefinition artifactDefinition = artifact.getValue();
168                         if (true == artifactDefinition.getMandatory()) {
169                                 String artifactEsId = artifactDefinition.getEsId();
170                                 if (artifactEsId == null || true == artifactEsId.isEmpty()) {
171                                         invalidArtifacts.put(artifact.getKey(), artifactDefinition);
172                                 }
173                         }
174                 }
175
176                 if (true == invalidArtifacts.isEmpty()) {
177                         return Either.left(ActionStatus.OK);
178                 } else {
179                         return Either.right(invalidArtifacts);
180                 }
181         }
182
183         @Override
184         public Either<? extends Component, ResponseFormat> changeState(ComponentTypeEnum componentType, Component component, ComponentBusinessLogic componentBl, User modifier, User owner, boolean shouldLock, boolean inTransaction) {
185
186                 log.debug("start performing certification request for resource {}", component.getUniqueId());
187
188                 // Either<ActionStatus, Map<String, ArtifactDefinition>>
189                 // validateMandatoryArtifacts =
190                 // validateMandatoryArtifactsSupplied(component.getArtifacts());
191                 // log.debug("After checking mandatory artifacts were populated. Result
192                 // is " + validateMandatoryArtifacts);
193                 // if (validateMandatoryArtifacts.isRight()) {
194                 // ResponseFormat responseFormat = componentUtils
195                 // .getResponseFormatByMissingArtifacts(
196                 // componentType,
197                 // validateMandatoryArtifacts.right().value());
198                 // return Either.right(responseFormat);
199                 // }
200                 ActionStatus actionStatus = null;
201                 ResponseFormat responseFormat = null;
202
203                 if (componentType == ComponentTypeEnum.SERVICE || (componentType == ComponentTypeEnum.RESOURCE && ((Resource) component).getResourceType() == ResourceTypeEnum.VF)) {
204
205                         Either<Boolean, ResponseFormat> statusCert = validateAllResourceInstanceCertified(component);
206                         if (statusCert.isRight()) {
207                                 return Either.right(statusCert.right().value());
208                         }
209
210                         statusCert = validateConfiguredAtomicReqCapSatisfied(component);
211                         if (statusCert.isRight()) {
212                                 return Either.right(statusCert.right().value());
213                         }
214                 }
215                 if (componentType == ComponentTypeEnum.SERVICE) {
216                         Either<Boolean, StorageOperationStatus> status = validateDeloymentArtifactSupplied((Service) component);
217                         if (status.isRight()) {
218                                 StorageOperationStatus operationStatus = status.right().value();
219                                 actionStatus = componentUtils.convertFromStorageResponse(operationStatus);
220                         } else {
221                                 Boolean isDeploymentArtifactExists = status.left().value();
222                                 if (isDeploymentArtifactExists == null || isDeploymentArtifactExists.booleanValue() == false) {
223                                         actionStatus = ActionStatus.SERVICE_DEPLOYMENT_ARTIFACT_NOT_FOUND;
224                                 } else {
225                                         Either<Service, ResponseFormat> generateHeatEnvResult = serviceBusinessLogic.generateHeatEnvArtifacts((Service) component, modifier, shouldLock);
226                                         if (generateHeatEnvResult.isRight()) {
227                                                 return Either.right(generateHeatEnvResult.right().value());
228                                         }
229                                         Either<Service, ResponseFormat> generateVfModuleResult = serviceBusinessLogic.generateVfModuleArtifacts((Service) component, modifier, shouldLock);
230                                         if (generateVfModuleResult.isRight()) {
231                                                 return Either.right(generateVfModuleResult.right().value());
232                                         }
233                                 }
234                         }
235
236                         if (actionStatus != null) {
237                                 responseFormat = componentUtils.getResponseFormatByComponent(actionStatus, component, componentType);
238                                 return Either.right(responseFormat);
239                         }
240
241                 }
242
243                 Either<Either<ArtifactDefinition, Operation>, ResponseFormat> eitherPopulated = componentBl.populateToscaArtifacts(component, modifier, true, inTransaction, shouldLock);
244                 if (eitherPopulated != null && eitherPopulated.isRight()) {
245                         return Either.right(eitherPopulated.right().value());
246                 }
247
248                 NodeTypeEnum nodeType = (componentType.equals(ComponentTypeEnum.SERVICE)) ? NodeTypeEnum.Service : NodeTypeEnum.Resource;
249                 Either<? extends Component, StorageOperationStatus> certificationRequestResult = lifeCycleOperation.requestCertificationComponent(nodeType, component, modifier, owner, inTransaction);
250                 if (certificationRequestResult.isRight()) {
251                         log.debug("checkout failed on graph");
252                         StorageOperationStatus response = certificationRequestResult.right().value();
253                         actionStatus = componentUtils.convertFromStorageResponse(response);
254
255                         if (response.equals(StorageOperationStatus.ENTITY_ALREADY_EXISTS)) {
256                                 actionStatus = ActionStatus.COMPONENT_VERSION_ALREADY_EXIST;
257                         }
258                         responseFormat = componentUtils.getResponseFormatByComponent(actionStatus, component, componentType);
259                         return Either.right(responseFormat);
260                 }
261
262                 return Either.left(certificationRequestResult.left().value());
263         }
264
265         private Either<Boolean, ResponseFormat> validateConfiguredAtomicReqCapSatisfied(Component component) {
266                 log.debug("Submit for testing validation - Start validating configured req/cap satisfied for inner atomic instances, component id:{}", component.getUniqueId());
267                 List<ComponentInstance> componentInstances = component.getComponentInstances();
268                 if (componentInstances != null) {
269                         // Prepare relationships data structures
270                         // Better make it list than set in case we need to count req/cap
271                         // occurrences in the future
272                         Map<String, List<String>> reqName2Ids = new HashMap<>();
273                         Map<String, List<String>> capName2Ids = new HashMap<>();
274                         parseRelationsForReqCapVerification(component, reqName2Ids, capName2Ids);
275                         Map<String, Set<String>> requirementsToFulfillBeforeCert = configurationManager.getConfiguration().getRequirementsToFulfillBeforeCert();
276                         Map<String, Set<String>> capabilitiesToConsumeBeforeCert = configurationManager.getConfiguration().getCapabilitiesToConsumeBeforeCert();
277                         for (ComponentInstance compInst : componentInstances) {
278                                 String compInstId = compInst.getUniqueId();
279                                 OriginTypeEnum originType = compInst.getOriginType();
280                                 if (originType == null) {
281                                         log.error("Origin type is not set for component instance {} - it shouldn't happen. Skipping this component instance...", compInst.getUniqueId());
282                                         continue;
283                                 }
284                                 String compInstType = originType.getValue();
285                                 // Validating configured requirements fulfilled
286                                 if (null != requirementsToFulfillBeforeCert) {
287                                         Set<String> reqToFulfillForType = requirementsToFulfillBeforeCert.get(compInstType);
288                                         if (reqToFulfillForType != null) {
289                                                 for (String reqNameToFulfill : reqToFulfillForType) {
290                                                         List<String> reqNameList = reqName2Ids.get(reqNameToFulfill);
291                                                         if (reqNameList == null || !reqNameList.contains(compInstId)) {
292                                                                 log.debug("Requirement {} wasn't fulfilled for component instance {} of type {}", reqNameToFulfill, compInstId, compInstType);
293                                                                 ComponentTypeEnum componentType = component.getComponentType();
294                                                                 String compParam = (componentType == ComponentTypeEnum.RESOURCE) ? "VF" : componentType.getValue().toLowerCase();
295                                                                 ResponseFormat responseFormat = componentUtils.getResponseFormat(ActionStatus.REQ_CAP_NOT_SATISFIED_BEFORE_CERTIFICATION, component.getName(), compParam, originType.getDisplayValue(), compInst.getName(), "requirement",
296                                                                                 reqNameToFulfill, "fulfilled");
297                                                                 return Either.right(responseFormat);
298                                                         }
299                                                 }
300                                         }
301                                 }
302                                 // Validating configured capabilities consumed
303                                 if (null != capabilitiesToConsumeBeforeCert) {
304                                         Set<String> capToConsumeForType = capabilitiesToConsumeBeforeCert.get(compInstType);
305                                         if (capToConsumeForType != null) {
306                                                 for (String capNameToConsume : capToConsumeForType) {
307                                                         List<String> capNameList = capName2Ids.get(capNameToConsume);
308                                                         if (capNameList == null || !capNameList.contains(compInstId)) {
309                                                                 log.debug("Capability {} wasn't consumed for component instance {} of type {}", capNameToConsume, compInstId, compInstType);
310                                                                 ComponentTypeEnum componentType = component.getComponentType();
311                                                                 String compParam = (componentType == ComponentTypeEnum.RESOURCE) ? "VF" : componentType.getValue().toLowerCase();
312                                                                 ResponseFormat responseFormat = componentUtils.getResponseFormat(ActionStatus.REQ_CAP_NOT_SATISFIED_BEFORE_CERTIFICATION, component.getName(), compParam, originType.getDisplayValue(), compInst.getName(), "capability",
313                                                                                 capNameToConsume, "consumed");
314                                                                 return Either.right(responseFormat);
315                                                         }
316                                                 }
317                                         }
318                                 }
319                         }
320                 }
321                 log.debug("Submit for testing validation - validating configured req/cap satisfied for inner atomic instances finished successfully, component id:{}", component.getUniqueId());
322                 return Either.left(true);
323         }
324
325         private Either<Boolean, ResponseFormat> parseRelationsForReqCapVerification(Component component, Map<String, List<String>> reqName2Ids, Map<String, List<String>> capName2Ids) {
326                 log.debug("Submit for testing validation - Preparing relations for inner atomic instances validation");
327                 List<RequirementCapabilityRelDef> componentInstancesRelations = component.getComponentInstancesRelations();
328                 if (componentInstancesRelations != null) {
329                         for (RequirementCapabilityRelDef reqCapRelDef : componentInstancesRelations) {
330                                 List<RequirementAndRelationshipPair> relationships = reqCapRelDef.getRelationships();
331                                 if (relationships != null) {
332                                         for (RequirementAndRelationshipPair reqRelPair : relationships) {
333                                                 String capUniqueId = reqRelPair.getCapabilityUid();
334                                                 Either<CapabilityDefinition, StorageOperationStatus> capability = capabilityOperation.getCapability(capUniqueId);
335                                                 if (capability.isRight()) {
336                                                         log.error("Couldn't fetch capability by id {}", capUniqueId);
337                                                         return Either.right(componentUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
338                                                 }
339                                                 String reqCapType = capability.left().value().getType();
340                                                 String capabilityOwnerId = reqRelPair.getCapabilityOwnerId();
341                                                 String requirementOwnerId = reqRelPair.getRequirementOwnerId();
342                                                 // Update req
343                                                 List<String> reqIds = reqName2Ids.get(reqCapType);
344                                                 if (reqIds == null) {
345                                                         reqIds = new ArrayList<>();
346                                                         reqName2Ids.put(reqCapType, reqIds);
347                                                 }
348                                                 reqIds.add(requirementOwnerId);
349                                                 // Update cap
350                                                 List<String> capIds = capName2Ids.get(reqCapType);
351                                                 if (capIds == null) {
352                                                         capIds = new ArrayList<>();
353                                                         capName2Ids.put(reqCapType, capIds);
354                                                 }
355                                                 capIds.add(capabilityOwnerId);
356                                         }
357                                 }
358                         }
359                         log.debug("Parsed req for validation: {}, parsed cap for validation: {}", reqName2Ids, capName2Ids);
360                 } else {
361                         log.debug("There are no relations found for component {}", component.getUniqueId());
362                 }
363                 return Either.left(true);
364         }
365
366         @Override
367         public Either<Boolean, ResponseFormat> validateBeforeTransition(Component component, ComponentTypeEnum componentType, User modifier, User owner, LifecycleStateEnum oldState, LifecycleChangeInfoWithAction lifecycleChangeInfo) {
368                 String componentName = component.getComponentMetadataDefinition().getMetadataDataDefinition().getName();
369                 log.debug("validate before certification request. resource name={}, oldState={}, owner userId={}", componentName, oldState, owner.getUserId());
370
371                 // validate user
372                 Either<Boolean, ResponseFormat> userValidationResponse = userRoleValidation(modifier, componentType, lifecycleChangeInfo);
373                 if (userValidationResponse.isRight()) {
374                         return userValidationResponse;
375                 }
376
377                 // case of "atomic" checkin and certification request - modifier must be
378                 // the owner
379                 if (oldState.equals(LifecycleStateEnum.NOT_CERTIFIED_CHECKOUT) && !modifier.equals(owner) && !modifier.getRole().equals(Role.ADMIN.name())) {
380                         ResponseFormat error = componentUtils.getResponseFormat(ActionStatus.COMPONENT_CHECKOUT_BY_ANOTHER_USER, componentName, componentType.name().toLowerCase(), owner.getFirstName(), owner.getLastName(), owner.getUserId());
381                         return Either.right(error);
382                 }
383
384                 // other states
385                 if (oldState.equals(LifecycleStateEnum.CERTIFIED)) {
386                         ResponseFormat error = componentUtils.getResponseFormat(ActionStatus.COMPONENT_ALREADY_CERTIFIED, componentName, componentType.name().toLowerCase(), owner.getFirstName(), owner.getLastName(), owner.getUserId());
387                         return Either.right(error);
388                 }
389                 if (oldState.equals(LifecycleStateEnum.CERTIFICATION_IN_PROGRESS)) {
390                         ResponseFormat error = componentUtils.getResponseFormat(ActionStatus.COMPONENT_IN_CERT_IN_PROGRESS_STATE, componentName, componentType.name().toLowerCase(), owner.getFirstName(), owner.getLastName(), owner.getUserId());
391                         return Either.right(error);
392                 }
393                 if (oldState.equals(LifecycleStateEnum.READY_FOR_CERTIFICATION)) {
394                         ResponseFormat error = componentUtils.getResponseFormat(ActionStatus.COMPONENT_SENT_FOR_CERTIFICATION, componentName, componentType.name().toLowerCase(), owner.getFirstName(), owner.getLastName(), owner.getUserId());
395                         return Either.right(error);
396                 }
397
398                 return Either.left(true);
399         }
400
401         private Either<Boolean, StorageOperationStatus> validateDeloymentArtifactSupplied(Service service) {
402
403                 Either<Boolean, StorageOperationStatus> serviceContainsDeploymentArtifacts = this.serviceDistributionArtifactsBuilder.isServiceContainsDeploymentArtifacts(service);
404
405                 return serviceContainsDeploymentArtifacts;
406
407         }
408
409 }