2 * ============LICENSE_START=======================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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 * Modifications copyright (c) 2019 Nokia
20 * ================================================================================
23 package org.openecomp.sdc.be.components.impl;
25 import fj.data.Either;
26 import org.apache.commons.collections.CollectionUtils;
27 import org.apache.commons.collections.MapUtils;
28 import org.apache.commons.io.FilenameUtils;
29 import org.apache.commons.lang.StringUtils;
30 import org.apache.commons.lang3.math.NumberUtils;
31 import org.apache.commons.lang3.tuple.ImmutablePair;
32 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
33 import org.openecomp.sdc.be.components.impl.exceptions.ByResponseFormatComponentException;
34 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
35 import org.openecomp.sdc.be.components.impl.lock.LockingTransactional;
36 import org.openecomp.sdc.be.components.impl.policy.PolicyTargetsUpdateHandler;
37 import org.openecomp.sdc.be.components.utils.Utils;
38 import org.openecomp.sdc.be.components.validation.AccessValidations;
39 import org.openecomp.sdc.be.components.validation.ComponentValidations;
40 import org.openecomp.sdc.be.config.BeEcompErrorManager;
41 import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity;
42 import org.openecomp.sdc.be.config.ConfigurationManager;
43 import org.openecomp.sdc.be.dao.api.ActionStatus;
44 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
45 import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition;
46 import org.openecomp.sdc.be.datatypes.elements.GroupDataDefinition;
47 import org.openecomp.sdc.be.datatypes.elements.PolicyTargetType;
48 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
49 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
50 import org.openecomp.sdc.be.datatypes.enums.CreatedFrom;
51 import org.openecomp.sdc.be.datatypes.enums.PromoteVersionEnum;
52 import org.openecomp.sdc.be.info.ArtifactDefinitionInfo;
53 import org.openecomp.sdc.be.info.ArtifactTemplateInfo;
54 import org.openecomp.sdc.be.info.GroupDefinitionInfo;
55 import org.openecomp.sdc.be.model.ArtifactDefinition;
56 import org.openecomp.sdc.be.model.Component;
57 import org.openecomp.sdc.be.model.ComponentInstance;
58 import org.openecomp.sdc.be.model.ComponentParametersView;
59 import org.openecomp.sdc.be.model.DataTypeDefinition;
60 import org.openecomp.sdc.be.model.GroupDefinition;
61 import org.openecomp.sdc.be.model.GroupInstance;
62 import org.openecomp.sdc.be.model.GroupInstanceProperty;
63 import org.openecomp.sdc.be.model.GroupProperty;
64 import org.openecomp.sdc.be.model.GroupTypeDefinition;
65 import org.openecomp.sdc.be.model.PropertyDefinition;
66 import org.openecomp.sdc.be.model.PropertyDefinition.GroupInstancePropertyValueUpdateBehavior;
67 import org.openecomp.sdc.be.model.PropertyDefinition.PropertyNames;
68 import org.openecomp.sdc.be.model.Resource;
69 import org.openecomp.sdc.be.model.User;
70 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations;
71 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.GroupsOperation;
72 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation;
73 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.TopologyTemplateOperation;
74 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
75 import org.openecomp.sdc.be.model.operations.api.IGroupInstanceOperation;
76 import org.openecomp.sdc.be.model.operations.api.IGroupOperation;
77 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
78 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
79 import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter;
80 import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
81 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
82 import org.openecomp.sdc.common.api.Constants;
83 import org.openecomp.sdc.common.log.elements.LoggerSupportability;
84 import org.openecomp.sdc.common.log.enums.LogLevel;
85 import org.openecomp.sdc.common.log.enums.LoggerSupportabilityActions;
86 import org.openecomp.sdc.common.log.enums.StatusCode;
87 import org.openecomp.sdc.common.log.wrappers.Logger;
88 import org.openecomp.sdc.common.util.ValidationUtils;
89 import org.openecomp.sdc.exception.ResponseFormat;
90 import org.springframework.beans.factory.annotation.Autowired;
92 import java.util.ArrayList;
93 import java.util.Arrays;
94 import java.util.Collection;
95 import java.util.Collections;
96 import java.util.EnumMap;
97 import java.util.HashMap;
98 import java.util.List;
100 import java.util.Map.Entry;
101 import java.util.Optional;
102 import java.util.Set;
103 import java.util.regex.Pattern;
104 import java.util.stream.Collectors;
106 import static java.util.stream.Collectors.toList;
107 import static org.openecomp.sdc.be.model.jsonjanusgraph.utils.ModelConverter.extractCapabilitiesFromGroups;
108 import static org.openecomp.sdc.be.model.jsonjanusgraph.utils.ModelConverter.extractCapabilityPropertiesFromGroups;
110 @org.springframework.stereotype.Component("groupBusinessLogic")
111 public class GroupBusinessLogic extends BaseBusinessLogic {
113 public static final String GROUP_DELIMITER_REGEX = "\\.\\.";
115 public static final String INITIAL_VERSION = "0.0";
117 private static final String ADDING_GROUP = "AddingGroup";
119 private static final String CREATE_GROUP = "CreateGroup";
121 private static final String UPDATE_GROUP = "UpdateGroup";
123 private static final String GET_GROUP = "GetGroup";
125 private static final String DELETE_GROUP = "DeleteGroup";
127 private static final Logger log = Logger.getLogger(GroupBusinessLogic.class);
129 private static final LoggerSupportability loggerSupportability = LoggerSupportability.getLogger(GroupBusinessLogic.class.getName());
131 private final AccessValidations accessValidations;
132 private final PolicyTargetsUpdateHandler policyTargetsUpdateHandler;
134 @javax.annotation.Resource
135 private final GroupsOperation groupsOperation;
139 public GroupBusinessLogic(IElementOperation elementDao,
140 IGroupOperation groupOperation,
141 IGroupInstanceOperation groupInstanceOperation,
142 IGroupTypeOperation groupTypeOperation,
143 InterfaceOperation interfaceOperation,
144 InterfaceLifecycleOperation interfaceLifecycleTypeOperation, AccessValidations accessValidations,
145 GroupsOperation groupsOperation, PolicyTargetsUpdateHandler policyTargetsUpdateHandler,
146 ArtifactsOperations artifactToscaOperation) {
147 super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation,
148 interfaceOperation, interfaceLifecycleTypeOperation, artifactToscaOperation);
149 this.accessValidations = accessValidations;
150 this.groupsOperation = groupsOperation;
151 this.policyTargetsUpdateHandler = policyTargetsUpdateHandler;
154 private String getComponentTypeForResponse(org.openecomp.sdc.be.model.Component component) {
155 String componentTypeForResponse = "SERVICE";
156 if (component instanceof Resource) {
157 componentTypeForResponse = ((Resource) component).getResourceType().name();
159 return componentTypeForResponse;
163 * Verify that the artifact members belongs to the component
169 private Either<Boolean, ResponseFormat> verifyArtifactsBelongsToComponent(Component component, List<String> artifacts, String context) {
171 if (CollectionUtils.isEmpty(artifacts)) {
172 return Either.left(true);
175 Map<String, ArtifactDefinition> deploymentArtifacts = component.getDeploymentArtifacts();
176 if (MapUtils.isEmpty(deploymentArtifacts)) {
177 BeEcompErrorManager.getInstance().logInvalidInputError(context, "No deployment artifact found under component " + component.getNormalizedName(), ErrorSeverity.INFO);
178 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
181 List<String> currentArtifacts = deploymentArtifacts.values().stream().map(ArtifactDefinition::getUniqueId).collect(toList());
182 log.debug("The deployment artifacts of component {} are {}", component.getNormalizedName(), deploymentArtifacts);
183 if (!currentArtifacts.containsAll(artifacts)) {
184 BeEcompErrorManager.getInstance().logInvalidInputError(context, "Not all artifacts belongs to component " + component.getNormalizedName(), ErrorSeverity.INFO);
185 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
188 return Either.left(true);
193 * verify that the members are component instances of the component
196 * @param groupMembers
197 * @param memberToscaTypes
200 private Either<Boolean, ResponseFormat> verifyComponentInstancesAreValidMembers(Component component, String groupName, Map<String, String> groupMembers, List<String> memberToscaTypes) {
202 if (MapUtils.isEmpty(groupMembers)) {
203 return Either.left(true);
206 if (CollectionUtils.isEmpty(memberToscaTypes)) {
207 return Either.left(true);
210 List<ComponentInstance> componentInstances = component.getComponentInstances();
211 if (CollectionUtils.isNotEmpty(componentInstances)) {
212 Map<String, ComponentInstance> compInstUidToCompInstMap = componentInstances.stream().collect(Collectors.toMap(ComponentInstance::getUniqueId, p -> p));
214 Set<String> allCompInstances = compInstUidToCompInstMap.keySet();
216 for (Entry<String, String> groupMember : groupMembers.entrySet()) {
217 String compName = groupMember.getKey();
218 String compUid = groupMember.getValue();
220 if (!allCompInstances.contains(compUid)) {
222 * %1 - member name %2 - group name %3 - VF name %4 - component type [VF ]
224 String componentTypeForResponse = getComponentTypeForResponse(component);
226 BeEcompErrorManager.getInstance().logInvalidInputError(CREATE_GROUP, "Not all group members exists under the component", ErrorSeverity.INFO);
227 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_INVALID_COMPONENT_INSTANCE, compName, groupName, component.getNormalizedName(), componentTypeForResponse));
232 return Either.left(true);
238 * Update GroupDefinition metadata
242 * @param componentType
243 * @param updatedGroup
244 * @param inTransaction
247 public Either<GroupDefinition, ResponseFormat> validateAndUpdateGroupMetadata(String componentId, User user, ComponentTypeEnum componentType, GroupDefinition updatedGroup, boolean inTransaction , boolean shouldLock) {
249 Either<GroupDefinition, ResponseFormat> result = null;
250 boolean failed = false;
252 // Validate user exist
253 validateUserExists(user.getUserId());
254 // Validate component exist
255 org.openecomp.sdc.be.model.Component component = validateComponentExists(componentId, componentType, null);
256 // validate we can work on component
257 validateCanWorkOnComponent(component, user.getUserId());
258 List<GroupDefinition> currentGroups = component.getGroups();
259 if (CollectionUtils.isEmpty(currentGroups)) {
260 log.error("Failed to update the metadata of group {} on component {}. The status is {}. ", updatedGroup.getName(), component.getName(), ActionStatus.GROUP_IS_MISSING);
261 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_IS_MISSING, updatedGroup.getName(), component.getName(), component.getComponentType().getValue()));
264 // Validate groups exists in the component
265 Optional<GroupDefinition> currentGroupOpt = currentGroups.stream().filter(g -> g.getUniqueId().equals(updatedGroup.getUniqueId())).findAny();
266 if (!currentGroupOpt.isPresent()) {
267 log.error("Failed to update the metadata of group {} on component {}. The status is {}. ", updatedGroup.getName(), component.getName(), ActionStatus.GROUP_IS_MISSING);
268 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_IS_MISSING, updatedGroup.getName(), component.getName(), component.getComponentType().getValue()));
271 GroupDefinition currentGroup = currentGroupOpt.get();
273 lockComponent(componentId, component, "Update GroupDefinition Metadata");
275 // Validate group type is vfModule
276 if (currentGroup.getType().equals(Constants.GROUP_TOSCA_HEAT)) {
277 log.error("Failed to update the metadata of group {}. Group type is {} and cannot be updated", currentGroup.getName(), currentGroup.getType());
278 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.GROUP_TYPE_IS_INVALID, updatedGroup.getType());
279 result = Either.right(responseFormat);
282 result = updateGroupMetadata(component, currentGroup, updatedGroup);
285 }catch (ComponentException e){
290 janusGraphDao.commit();
292 janusGraphDao.rollback();
295 graphLockOperation.unlockComponent(componentId, componentType.getNodeType());
300 private Either<GroupDefinition, ResponseFormat> updateGroupMetadata(Component component, GroupDefinition currentGroup, GroupDefinition updatedGroup) {
301 String currentGroupName = currentGroup.getName();
302 Either<GroupDefinition, ResponseFormat> result = validateAndUpdateGroupMetadata(currentGroup, updatedGroup);
304 if (result.isRight()) {
305 log.debug("Failed to validate a metadata of the group {} on component {}. ", updatedGroup.getName(), component.getName());
307 if (result.isLeft()) {
308 result = updateGroup(component, currentGroup, currentGroupName);
313 private Either<GroupDefinition, ResponseFormat> updateGroup(Component component, GroupDefinition updatedGroup, String currentGroupName) {
314 Either<GroupDefinition, StorageOperationStatus> handleGroupRes;
315 Either<GroupDefinition, ResponseFormat> result = null;
316 handleGroupRes = groupsOperation.updateGroup(component, updatedGroup);
317 if (handleGroupRes.isRight()) {
318 log.debug("Failed to update a metadata of the group {} on component {}. ", updatedGroup.getName(), component.getName());
319 result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(handleGroupRes.right().value())));
321 if (result == null) {
322 result = Either.left(updatedGroup);
328 * Validate and update GroupDefinition metadata
330 * @param currentGroup
334 private Either<GroupDefinition, ResponseFormat> validateAndUpdateGroupMetadata(GroupDefinition currentGroup, GroupDefinition groupUpdate) {
335 // Check if to update, and update GroupDefinition name.
336 Either<Boolean, ResponseFormat> response = validateAndUpdateGroupName(currentGroup, groupUpdate);
337 if (response.isRight()) {
338 ResponseFormat errorResponse = response.right().value();
339 return Either.right(errorResponse);
342 // Do not allow to update GroupDefinition version directly.
343 String versionUpdated = groupUpdate.getVersion();
344 String versionCurrent = currentGroup.getVersion();
345 if (versionUpdated != null && !versionCurrent.equals(versionUpdated)) {
346 log.info("update Group: recived request to update version to {} the field is not updatable ignoring.", versionUpdated);
349 return Either.left(currentGroup);
353 * Validate and update GroupDefinition name
355 * @param currentGroup
359 private Either<Boolean, ResponseFormat> validateAndUpdateGroupName(GroupDefinition currentGroup, GroupDefinition groupUpdate) {
360 String nameUpdated = groupUpdate.getName();
361 String nameCurrent = currentGroup.getName();
362 if (!nameCurrent.equals(nameUpdated)) {
363 Either<Boolean, ResponseFormat> validatNameResponse = validateGroupName(currentGroup.getName(), groupUpdate.getName() ,true);
364 if (validatNameResponse.isRight()) {
365 ResponseFormat errorRespons = validatNameResponse.right().value();
366 return Either.right(errorRespons);
368 currentGroup.setName(groupUpdate.getName());
370 return Either.left(true);
374 * Validate that group name to update is valid (same as current group name except for middle part). For example: Current group name: MyResource..MyDesc..Module-1 Group to update: MyResource..MyDesc2..Module-1 Verify that only the second part
375 * MyDesc was changed.
377 * @param currentGroupName
378 * @param groupUpdateName
381 private Either<Boolean, ResponseFormat> validateGroupName(String currentGroupName, String groupUpdateName , boolean isforceNameModification) {
383 // Check if the group name is in old format.
384 if (Pattern.compile(Constants.MODULE_OLD_NAME_PATTERN).matcher(groupUpdateName).matches()) {
385 log.error("Group name {} is in old format", groupUpdateName);
386 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_VF_MODULE_NAME, groupUpdateName));
389 // Check that name pats 1 and 3 did not changed (only the second
390 // part can be changed)
391 // But verify before that the current group format is the new one
392 if (!Pattern.compile(Constants.MODULE_OLD_NAME_PATTERN).matcher(currentGroupName).matches()) {
393 String[] split1 = currentGroupName.split(GROUP_DELIMITER_REGEX);
394 String currentResourceName = split1[0];
395 String currentCounter = split1[2];
397 String[] split2 = groupUpdateName.split(GROUP_DELIMITER_REGEX);
398 String groupUpdateResourceName = split2[0];
399 String groupUpdateCounter = split2[2];
400 if (!isforceNameModification){ //if not forced ,allow name prefix&suffix validation [no changes]
401 if (!currentResourceName.equals(groupUpdateResourceName)) {
402 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_VF_MODULE_NAME_MODIFICATION, currentResourceName));
405 if (!currentCounter.equals(groupUpdateCounter)) {
406 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_VF_MODULE_NAME_MODIFICATION, currentCounter));
412 return Either.left(true);
413 } catch (Exception e) {
414 log.error("Error valiadting group name", e);
415 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
421 * associate artifacts to a given group
425 * @param componentType
426 * @param inTransaction
429 public Either<GroupDefinitionInfo, ResponseFormat> getGroupWithArtifactsById(ComponentTypeEnum componentType, String componentId, String groupId, String userId, boolean inTransaction) {
431 Either<GroupDefinitionInfo, ResponseFormat> result = null;
433 // Validate user exist
434 validateUserExists(userId);
435 // Validate component exist
436 org.openecomp.sdc.be.model.Component component = null;
439 ComponentParametersView componentParametersView = new ComponentParametersView();
440 componentParametersView.disableAll();
441 componentParametersView.setIgnoreGroups(false);
442 componentParametersView.setIgnoreArtifacts(false);
443 componentParametersView.setIgnoreUsers(false);
445 component = validateComponentExists(componentId, componentType, componentParametersView);
447 Either<GroupDefinition, StorageOperationStatus> groupEither = findGroupOnComponent(component, groupId);
449 if (groupEither.isRight()) {
450 log.debug("Failed to find group {} under component {}", groupId, component.getUniqueId());
451 BeEcompErrorManager.getInstance().logInvalidInputError(GET_GROUP, "group " + groupId + " not found under component " + component.getUniqueId(), ErrorSeverity.INFO);
452 String componentTypeForResponse = getComponentTypeForResponse(component);
453 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_IS_MISSING, groupId, component.getSystemName(), componentTypeForResponse));
456 GroupDefinition group = groupEither.left().value();
458 List<GroupProperty> props = group.convertToGroupProperties();
459 Boolean isBase = isBaseProp(component, props);
461 List<ArtifactDefinitionInfo> artifacts = new ArrayList<>();
462 List<ArtifactDefinition> artifactsFromComponent = new ArrayList<>();
463 List<String> artifactsIds = group.getArtifacts();
465 Map<String, ArtifactDefinition> deploymentArtifacts = null;
466 if (MapUtils.isNotEmpty(component.getDeploymentArtifacts())) {
467 deploymentArtifacts = component.getDeploymentArtifacts().values().stream().collect(Collectors.toMap(ArtifactDataDefinition::getUniqueId, a -> a));
470 if (artifactsIds != null && !artifactsIds.isEmpty()) {
471 for (String id : artifactsIds) {
472 if (deploymentArtifacts == null || !deploymentArtifacts.containsKey(id)) {
473 log.debug("Failed to get artifact {} . Status is {} ", id, StorageOperationStatus.NOT_FOUND);
474 ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(StorageOperationStatus.NOT_FOUND));
475 result = Either.right(responseFormat);
478 artifactsFromComponent.add(deploymentArtifacts.get(id));
480 addArtifactsToList(artifacts, artifactsFromComponent);
483 GroupDefinitionInfo resultInfo = new GroupDefinitionInfo(group);
484 resultInfo.setIsBase(isBase);
485 if (!artifacts.isEmpty()) {
486 resultInfo.setArtifacts(artifacts);
488 result = Either.left(resultInfo);
493 closeTransaction(inTransaction, result);
498 private void addArtifactsToList(List<ArtifactDefinitionInfo> artifacts, List<ArtifactDefinition> artifactsFromComponent) {
499 artifactsFromComponent.forEach(a-> artifacts.add(new ArtifactDefinitionInfo(a)));
502 private Boolean isBaseProp(Component component, List<GroupProperty> props) {
503 Boolean isBase = null;
504 if (CollectionUtils.isNotEmpty(props)) {
505 Optional<GroupProperty> isBasePropOp = props.stream().filter(p -> p.getName().equals(Constants.IS_BASE)).findAny();
506 if (isBasePropOp.isPresent()) {
507 GroupProperty propIsBase = isBasePropOp.get();
508 isBase = Boolean.parseBoolean(propIsBase.getValue());
511 BeEcompErrorManager.getInstance().logInvalidInputError(GET_GROUP, "failed to find prop isBase " + component.getNormalizedName(), ErrorSeverity.INFO);
517 private Either<GroupDefinition, StorageOperationStatus> findGroupOnComponent(Component component, String groupId) {
519 Either<GroupDefinition, StorageOperationStatus> result = null;
520 if (CollectionUtils.isNotEmpty(component.getGroups())) {
521 Optional<GroupDefinition> foundGroup = component.getGroups().stream().filter(g -> g.getUniqueId().equals(groupId)).findFirst();
522 if (foundGroup.isPresent()) {
523 result = Either.left(foundGroup.get());
526 if (result == null) {
527 result = Either.right(StorageOperationStatus.NOT_FOUND);
532 public Either<Boolean, ResponseFormat> validateGenerateVfModuleGroupNames(List<ArtifactTemplateInfo> allGroups, String resourceSystemName, int startGroupCounter) {
533 Either<Boolean, ResponseFormat> validateGenerateGroupNamesRes = Either.left(true);
534 Collections.sort(allGroups, ArtifactTemplateInfo::compareByGroupName);
535 for (ArtifactTemplateInfo group : allGroups) {
536 Either<String, ResponseFormat> validateGenerateGroupNameRes = validateGenerateVfModuleGroupName(resourceSystemName, group.getDescription(), startGroupCounter++);
537 if (validateGenerateGroupNameRes.isRight()) {
538 validateGenerateGroupNamesRes = Either.right(validateGenerateGroupNameRes.right().value());
541 group.setGroupName(validateGenerateGroupNameRes.left().value());
543 return validateGenerateGroupNamesRes;
547 * Generate module name from resourceName, description and counter
549 * @param resourceSystemName
551 * @param groupCounter
554 private Either<String, ResponseFormat> validateGenerateVfModuleGroupName(String resourceSystemName, String description, int groupCounter) {
555 Either<String, ResponseFormat> validateGenerateGroupNameRes;
556 if (resourceSystemName != null && description != null && Pattern.compile(Constants.MODULE_DESC_PATTERN).matcher(description).matches()) {
557 final String fileName = description.replaceAll(GROUP_DELIMITER_REGEX, "\\.");
558 validateGenerateGroupNameRes = Either.left(String.format(Constants.MODULE_NAME_FORMAT, resourceSystemName, FilenameUtils.removeExtension(fileName), groupCounter));
560 validateGenerateGroupNameRes = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_VF_MODULE_NAME));
562 return validateGenerateGroupNameRes;
565 Either<Map<String, GroupDefinition>, ResponseFormat> validateUpdateVfGroupNames(Map<String, GroupDefinition> groups, String resourceSystemName) {
567 Map<String, GroupDefinition> updatedNamesGroups = new HashMap<>();
568 Either<Map<String, GroupDefinition>, ResponseFormat> result = Either.left(updatedNamesGroups);
569 for (Entry<String, GroupDefinition> groupEntry : groups.entrySet()) {
570 GroupDefinition curGroup = groupEntry.getValue();
571 String groupType = curGroup.getType();
572 String groupName = groupEntry.getKey();
575 Either<String, ResponseFormat> newGroupNameRes;
576 if (groupType.equals(Constants.DEFAULT_GROUP_VF_MODULE) && !Pattern.compile(Constants.MODULE_NEW_NAME_PATTERN).matcher(groupName).matches()) {
578 if (Pattern.compile(Constants.MODULE_OLD_NAME_PATTERN).matcher(groupEntry.getKey()).matches()) {
579 counter = Integer.parseInt(groupEntry.getKey().split(Constants.MODULE_NAME_DELIMITER)[1]);
580 description = curGroup.getDescription();
582 counter = getNextVfModuleNameCounter(updatedNamesGroups);
583 description = groupName;
585 newGroupNameRes = validateGenerateVfModuleGroupName(resourceSystemName, description, counter);
586 if (newGroupNameRes.isRight()) {
587 log.debug("Failed to generate new vf module group name. Status is {} ", newGroupNameRes.right().value());
588 loggerSupportability.log(LogLevel.INFO,LoggerSupportabilityActions.CREATE_RESOURCE_FROM_YAML.getName(),StatusCode.ERROR.name(),"Failed to generate new vf module group name. Status is: "+newGroupNameRes.right().value());
589 result = Either.right(newGroupNameRes.right().value());
592 groupName = newGroupNameRes.left().value();
593 curGroup.setName(groupName);
595 updatedNamesGroups.put(groupName, curGroup);
600 public int getNextVfModuleNameCounter(Map<String, GroupDefinition> groups) {
602 if (groups != null && !groups.isEmpty()) {
603 counter = getNextVfModuleNameCounter(groups.values());
608 public int getNextVfModuleNameCounter(Collection<GroupDefinition> groups) {
610 if (groups != null && !groups.isEmpty()) {
611 List<Integer> counters = groups.stream().filter(group -> Pattern.compile(Constants.MODULE_NEW_NAME_PATTERN).matcher(group.getName()).matches() || Pattern.compile(Constants.MODULE_OLD_NAME_PATTERN).matcher(group.getName()).matches())
612 .map(group -> Integer.parseInt(group.getName().split(Constants.MODULE_NAME_DELIMITER)[1])).collect(toList());
613 counter = (counters == null || counters.isEmpty()) ? 0 : counters.stream().max(Integer::compare).get() + 1;
618 public Either<List<GroupDefinition>, ResponseFormat> validateUpdateVfGroupNamesOnGraph(List<GroupDefinition> groups, Component component) {
619 List<GroupDefinition> updatedGroups = new ArrayList<>();
621 for (GroupDefinition group : groups) {
622 String groupType = group.getType();
623 String oldGroupName = group.getName();
625 Either<String, ResponseFormat> newGroupNameRes;
627 if (groupType.equals(Constants.DEFAULT_GROUP_VF_MODULE) && Pattern.compile(Constants.MODULE_OLD_NAME_PATTERN).matcher(oldGroupName).matches()) {
628 counter = Integer.parseInt(group.getName().split(Constants.MODULE_NAME_DELIMITER)[1]);
629 newGroupNameRes = validateGenerateVfModuleGroupName(component.getSystemName(), group.getDescription(), counter);
630 if (newGroupNameRes.isRight()) {
631 log.debug("Failed to generate new vf module group name. Status is {} ", newGroupNameRes.right().value());
634 newGroupName = newGroupNameRes.left().value();
635 group.setName(newGroupName);
638 updatedGroups.add(group);
642 return Either.left(updatedGroups);
646 public Either<GroupDefinitionInfo, ResponseFormat> getGroupInstWithArtifactsById(ComponentTypeEnum componentType, String componentId, String componentInstanceId, String groupInstId, String userId, boolean inTransaction) {
647 Either<GroupDefinitionInfo, ResponseFormat> result = null;
649 // Validate user exist
650 validateUserExists(userId);
651 // Validate component exist
652 org.openecomp.sdc.be.model.Component component;
655 ComponentParametersView componentParametersView = new ComponentParametersView();
656 componentParametersView.disableAll();
657 componentParametersView.setIgnoreUsers(false);
658 componentParametersView.setIgnoreComponentInstances(false);
659 componentParametersView.setIgnoreArtifacts(false);
661 component = validateComponentExists(componentId, componentType, componentParametersView);
662 Either<ImmutablePair<ComponentInstance, GroupInstance>, StorageOperationStatus> findComponentInstanceAndGroupInstanceRes = findComponentInstanceAndGroupInstanceOnComponent(component, componentInstanceId, groupInstId);
664 if (findComponentInstanceAndGroupInstanceRes.isRight()) {
665 log.debug("Failed to get group {} . Status is {} ", groupInstId, findComponentInstanceAndGroupInstanceRes.right().value());
666 ResponseFormat responseFormat = componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(findComponentInstanceAndGroupInstanceRes.right().value()));
667 result = Either.right(responseFormat);
671 GroupInstance group = findComponentInstanceAndGroupInstanceRes.left().value().getRight();
673 Boolean isBase = isBaseProperty(component, group);
675 List<ArtifactDefinitionInfo> artifacts = new ArrayList<>();
676 List<String> artifactsIds = group.getArtifacts();
677 if (artifactsIds != null && !artifactsIds.isEmpty()) {
679 List<ComponentInstance> instances = component.getComponentInstances();
680 if (instances != null) {
681 instances.stream().filter(i -> i.getUniqueId().equals(componentInstanceId))
683 .ifPresent(f->getFirstComponentInstance(group, artifacts, artifactsIds, f));
686 GroupDefinitionInfo resultInfo = new GroupDefinitionInfo(group);
687 resultInfo.setIsBase(isBase);
688 if (!artifacts.isEmpty()) {
689 resultInfo.setArtifacts(artifacts);
691 result = Either.left(resultInfo);
696 closeTransaction(inTransaction, result);
700 private void getFirstComponentInstance(GroupInstance group, List<ArtifactDefinitionInfo> artifacts, List<String> artifactsIds, ComponentInstance ci) {
701 Map<String, ArtifactDefinition> deploymentArtifacts = ci.getDeploymentArtifacts();
702 artifactsIds.forEach(id -> deploymentArtifacts.values().stream()
703 .filter(a -> a.getUniqueId().equals(id))
705 .ifPresent(g -> artifacts.add(new ArtifactDefinitionInfo(g))));
707 List<String> instArtifactsIds = group.getGroupInstanceArtifacts();
708 instArtifactsIds.forEach(id -> deploymentArtifacts.values()
710 .filter(a -> a.getUniqueId().equals(id))
712 .ifPresent(g -> artifacts.add(new ArtifactDefinitionInfo(g))));
715 private Boolean isBaseProperty(Component component, GroupInstance group) {
717 Boolean isBase = null;
718 List<? extends GroupProperty> props = group.convertToGroupInstancesProperties();
719 if (props != null && !props.isEmpty()) {
720 Optional<? extends GroupProperty> isBasePropOp = props.stream().filter(p -> p.getName().equals(Constants.IS_BASE)).findAny();
721 if (isBasePropOp.isPresent()) {
722 GroupProperty propIsBase = isBasePropOp.get();
723 isBase = Boolean.parseBoolean(propIsBase.getValue());
726 BeEcompErrorManager.getInstance().logInvalidInputError(GET_GROUP, "failed to find prop isBase " + component.getNormalizedName(), ErrorSeverity.INFO);
732 private void closeTransaction(boolean inTransaction, Either<GroupDefinitionInfo, ResponseFormat> result) {
733 if (!inTransaction) {
734 if (result == null || result.isRight()) {
735 log.debug("Going to execute rollback on create group.");
736 janusGraphDao.rollback();
738 log.debug("Going to execute commit on create group.");
739 janusGraphDao.commit();
744 private Either<ImmutablePair<ComponentInstance, GroupInstance>, StorageOperationStatus> findComponentInstanceAndGroupInstanceOnComponent(Component component, String componentInstanceId, String groupInstId) {
746 Either<ImmutablePair<ComponentInstance, GroupInstance>, StorageOperationStatus> result = null;
747 if (CollectionUtils.isNotEmpty(component.getComponentInstances())) {
748 Optional<GroupInstance> foundGroup;
749 Optional<ComponentInstance> foundComponent = component.getComponentInstances().stream().filter(ci -> ci.getUniqueId().equals(componentInstanceId)).findFirst();
750 if (foundComponent.isPresent() && CollectionUtils.isNotEmpty(foundComponent.get().getGroupInstances())) {
751 foundGroup = foundComponent.get().getGroupInstances().stream().filter(gi -> gi.getUniqueId().equals(groupInstId)).findFirst();
752 if (foundGroup.isPresent()) {
753 result = Either.left(new ImmutablePair<>(foundComponent.get(), foundGroup.get()));
757 if (result == null) {
758 result = Either.right(StorageOperationStatus.NOT_FOUND);
763 private Boolean validateMinMaxAndInitialCountPropertyLogic(Map<PropertyNames, String> newValues, Map<PropertyNames, String> currValues, Map<PropertyNames, String> parentValues) {
765 for (Entry<PropertyNames, String> entry : newValues.entrySet()) {
766 PropertyNames currPropertyName = entry.getKey();
767 if (currPropertyName == PropertyNames.MIN_INSTANCES) {
768 String minValue = parentValues.get(PropertyNames.MIN_INSTANCES);
769 String maxValue = getMaxValue(newValues, currValues);
770 validateValueInRange(new ImmutablePair<>(currPropertyName, entry.getValue()), new ImmutablePair<>(PropertyNames.MIN_INSTANCES, minValue),
771 new ImmutablePair<>(PropertyNames.MAX_INSTANCES, maxValue));
772 } else if (currPropertyName == PropertyNames.INITIAL_COUNT) {
773 String minValue = newValues.containsKey(PropertyNames.MIN_INSTANCES) ? newValues.get(PropertyNames.MIN_INSTANCES) : currValues.get(PropertyNames.MIN_INSTANCES);
774 String maxValue = newValues.containsKey(PropertyNames.MAX_INSTANCES) ? newValues.get(PropertyNames.MAX_INSTANCES) : currValues.get(PropertyNames.MAX_INSTANCES);
775 validateValueInRange(new ImmutablePair<>(currPropertyName, entry.getValue()), new ImmutablePair<>(PropertyNames.MIN_INSTANCES, minValue),
776 new ImmutablePair<>(PropertyNames.MAX_INSTANCES, maxValue));
777 } else if (currPropertyName == PropertyNames.MAX_INSTANCES) {
778 String minValue = getMinValue(newValues, currValues);
779 String maxValue = parentValues.get(PropertyNames.MAX_INSTANCES);
780 validateValueInRange(new ImmutablePair<>(currPropertyName, entry.getValue()), new ImmutablePair<>(PropertyNames.MIN_INSTANCES, minValue),
781 new ImmutablePair<>(PropertyNames.MAX_INSTANCES, maxValue));
787 private String getMaxValue(Map<PropertyNames, String> newValues, Map<PropertyNames, String> currValues) {
788 return newValues.containsKey(PropertyNames.INITIAL_COUNT) ? newValues.get(PropertyNames.MAX_INSTANCES) : currValues.get(PropertyNames.INITIAL_COUNT);
791 private String getMinValue(Map<PropertyNames, String> newValues, Map<PropertyNames, String> currValues) {
792 return newValues.containsKey(PropertyNames.INITIAL_COUNT) ? newValues.get(PropertyNames.MIN_INSTANCES) : currValues.get(PropertyNames.INITIAL_COUNT);
795 private Boolean validateValueInRange(ImmutablePair<PropertyNames, String> newValue, ImmutablePair<PropertyNames, String> min, ImmutablePair<PropertyNames, String> max) {
796 final String warnMessage = "Failed to validate {} as property value of {}. It must be not higher than {}, and not lower than {}.";
797 int newValueInt = parseIntValue(newValue.getValue(), newValue.getKey());
798 int minInt = parseIntValue(min.getValue(), min.getKey());
799 int maxInt = parseIntValue(max.getValue(), max.getKey());
800 if (newValueInt < 0 || minInt < 0 || maxInt < 0) {
801 throw new ByActionStatusComponentException(ActionStatus.INVALID_PROPERTY);
802 } else if (newValueInt < minInt || newValueInt > maxInt) {
803 log.debug(warnMessage, newValue.getValue(), newValue.getKey().getPropertyName(), min.getValue(), max.getValue());
804 throw new ByActionStatusComponentException(ActionStatus.INVALID_GROUP_MIN_MAX_INSTANCES_PROPERTY_VALUE, newValue.getKey().getPropertyName(),
805 maxInt == Integer.MAX_VALUE ? Constants.UNBOUNDED : max.getValue(), min.getValue());
810 private int parseIntValue(String value, PropertyNames propertyName) {
812 if (propertyName == PropertyNames.MAX_INSTANCES) {
813 result = convertIfUnboundMax(value);
814 } else if (NumberUtils.isNumber(value)) {
815 result = Integer.parseInt(value);
823 * validates received new property values and updates group instance in case of success
825 * @param oldGroupInstance
826 * @param newProperties
829 public Either<GroupInstance, ResponseFormat> validateAndUpdateGroupInstancePropertyValues(String componentId, String instanceId, GroupInstance oldGroupInstance, List<GroupInstanceProperty> newProperties) {
831 Either<GroupInstance, ResponseFormat> actionResult = null;
832 Either<GroupInstance, StorageOperationStatus> updateGroupInstanceResult = null;
833 List<GroupInstanceProperty> validateRes = validateReduceGroupInstancePropertiesBeforeUpdate(oldGroupInstance, newProperties);
834 if (actionResult == null) {
835 List<GroupInstanceProperty> validatedReducedNewProperties = validateRes;
836 updateGroupInstanceResult = groupsOperation.updateGroupInstancePropertyValuesOnGraph(componentId, instanceId, oldGroupInstance, validatedReducedNewProperties);
837 if (updateGroupInstanceResult.isRight()) {
838 log.debug("Failed to update group instance {} property values. ", oldGroupInstance.getName());
839 actionResult = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(updateGroupInstanceResult.right().value())));
842 if (actionResult == null) {
843 actionResult = Either.left(updateGroupInstanceResult.left().value());
848 private List<GroupInstanceProperty> validateReduceGroupInstancePropertiesBeforeUpdate(GroupInstance oldGroupInstance, List<GroupInstanceProperty> newProperties) {
850 Boolean validationRes = null;
851 List<GroupInstanceProperty> actionResult = null;
852 Map<String, GroupInstanceProperty> existingProperties = oldGroupInstance.convertToGroupInstancesProperties().stream().collect(Collectors.toMap(PropertyDataDefinition::getName, p -> p));
853 Map<PropertyNames, String> newPropertyValues = new EnumMap<>(PropertyNames.class);
854 List<GroupInstanceProperty> reducedProperties = new ArrayList<>();
855 String currPropertyName;
857 for (GroupInstanceProperty currNewProperty : newProperties) {
858 currPropertyName = currNewProperty.getName();
859 validationRes = handleAndAddProperty(reducedProperties, newPropertyValues, currNewProperty, existingProperties.get(currPropertyName));
861 if (validationRes == null || validationRes) {
862 Map<PropertyNames, String> existingPropertyValues = new EnumMap<>(PropertyNames.class);
863 Map<PropertyNames, String> parentPropertyValues = new EnumMap<>(PropertyNames.class);
864 fillValuesAndParentValuesFromExistingProperties(existingProperties, existingPropertyValues, parentPropertyValues);
865 validationRes = validateMinMaxAndInitialCountPropertyLogic(newPropertyValues, existingPropertyValues, parentPropertyValues);
868 actionResult = reducedProperties;
870 } catch (Exception e) {
871 log.error("Exception occured during validation and reducing group instance properties. The message is {}", e.getMessage(), e);
872 throw new ByActionStatusComponentException(ActionStatus.GENERAL_ERROR);
877 private void fillValuesAndParentValuesFromExistingProperties(Map<String, GroupInstanceProperty> existingProperties, Map<PropertyNames, String> propertyValues, Map<PropertyNames, String> parentPropertyValues) {
878 PropertyNames[] allPropertyNames = PropertyNames.values();
879 for (PropertyNames name : allPropertyNames) {
880 if (isUpdatable(name)) {
881 propertyValues.put(name, String.valueOf(existingProperties.get(name.getPropertyName()).getValue()));
882 parentPropertyValues.put(name, String.valueOf(existingProperties.get(name.getPropertyName()).getParentValue()));
887 private Boolean handleAndAddProperty(List<GroupInstanceProperty> reducedProperties, Map<PropertyNames, String> newPropertyValues, GroupInstanceProperty currNewProperty, GroupInstanceProperty currExistingProperty) {
889 Boolean validationRes = null;
890 String currPropertyName = currNewProperty.getName();
891 PropertyNames propertyName = PropertyNames.findName(currPropertyName);
893 if (currExistingProperty == null) {
894 log.warn("The value of property with the name {} cannot be updated. The property not found on group instance. ", currPropertyName);
895 } else if (isUpdatable(propertyName)) {
896 validationRes = validateAndUpdatePropertyValue(currNewProperty, currExistingProperty);
897 addPropertyUpdatedValues(reducedProperties, propertyName, newPropertyValues, currNewProperty, currExistingProperty);
899 validateImmutableProperty(currExistingProperty, currNewProperty);
901 if (validationRes == null) {
902 validationRes = true;
904 } catch (Exception e) {
905 log.error("Exception occured during handle and adding property. The message is {}", e.getMessage(), e);
907 return validationRes;
910 private boolean isUpdatable(PropertyNames updatablePropertyName) {
911 return updatablePropertyName != null && updatablePropertyName.getUpdateBehavior().getLevelNumber() >= GroupInstancePropertyValueUpdateBehavior.UPDATABLE_ON_SERVICE_LEVEL.getLevelNumber();
914 private void addPropertyUpdatedValues(List<GroupInstanceProperty> reducedProperties, PropertyNames propertyName, Map<PropertyNames, String> newPropertyValues, GroupInstanceProperty newProperty, GroupInstanceProperty existingProperty) {
916 String newValue = newProperty.getValue();
917 if (!newValue.equals(String.valueOf(existingProperty.getValue()))) {
918 newProperty.setValueUniqueUid(existingProperty.getValueUniqueUid());
919 reducedProperties.add(newProperty);
921 if (!isEmptyMinInitialCountValue(propertyName, newValue)) {
922 newPropertyValues.put(propertyName, newValue);
926 private boolean isEmptyMinInitialCountValue(PropertyNames propertyName, String newValue) {
927 boolean result = false;
928 if ((propertyName == PropertyNames.MIN_INSTANCES || propertyName == PropertyNames.INITIAL_COUNT) && !NumberUtils.isNumber(newValue)) {
934 private int convertIfUnboundMax(String value) {
937 if (!NumberUtils.isNumber(value)) {
938 result = Integer.MAX_VALUE;
940 result = Integer.parseInt(value);
945 private Boolean validateAndUpdatePropertyValue(GroupInstanceProperty newProperty, GroupInstanceProperty existingProperty) {
947 String parentValue = existingProperty.getParentValue();
949 newProperty.setParentValue(parentValue);
950 if (StringUtils.isEmpty(newProperty.getValue())) {
951 newProperty.setValue(parentValue);
953 if (StringUtils.isEmpty(existingProperty.getValue())) {
954 existingProperty.setValue(parentValue);
956 StorageOperationStatus status = groupOperation.validateAndUpdatePropertyValue(newProperty);
957 if (status != StorageOperationStatus.OK) {
958 log.debug("Failed to validate property value {} of property with name {}. Status is {}. ", newProperty.getValue(), newProperty.getName(), status);
959 throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(status));
964 private void validateImmutableProperty(GroupProperty oldProperty, GroupProperty newProperty) {
965 if (oldProperty.getValue() == null && newProperty.getValue() != null || oldProperty.getValue() != null && !oldProperty.getValue().equals(newProperty.getValue())) {
966 log.warn("The value of property with the name {} cannot be updated on service level. Going to ignore new property value {}. ", oldProperty.getName(), newProperty.getValue());
970 @LockingTransactional
971 public GroupDefinition createGroup(String componentId, ComponentTypeEnum componentTypeEnum, String groupType,
974 Component component = accessValidations.validateUserCanWorkOnComponent(componentId, componentTypeEnum, userId, CREATE_GROUP);
976 validateGroupTypePerComponent(groupType, component);
978 GroupTypeDefinition groupTypeDefinition = groupTypeOperation.getLatestGroupTypeByType(groupType, false)
980 .on(se -> onGroupTypeNotFound(component));
982 boolean hasExistingGroups = CollectionUtils.isNotEmpty(component.getGroups());
983 GroupDefinition groupDefinition = new GroupDefinition();
984 groupDefinition.setType(groupType);
986 //find next valid counter
988 if (hasExistingGroups) {
989 nextCounter = getNewGroupCounter(component);
991 String name = TopologyTemplateOperation.buildSubComponentName(component.getName(), groupType, nextCounter);
992 groupDefinition.setName(name);
993 groupDefinition.setDescription(groupTypeDefinition.getDescription());
994 groupDefinition.setInvariantName(name);
995 groupDefinition.setCreatedFrom(CreatedFrom.UI);
997 //Add default type properties
998 List<PropertyDefinition> groupTypeProperties = groupTypeDefinition.getProperties();
999 List<GroupProperty> properties = groupTypeProperties.stream()
1000 .map(GroupProperty::new)
1002 groupDefinition.convertFromGroupProperties(properties);
1004 groupDefinition.convertCapabilityDefinitions(groupTypeDefinition.getCapabilities());
1006 List<GroupDefinition> gdList;
1007 if (toscaOperationFacade.canAddGroups(componentId)) {
1008 gdList = addGroups(component, Arrays.asList(groupDefinition), false)
1010 .on(this::onFailedGroupDBOperation);
1012 //createGroups also creates an edge and vertex to store group data
1013 gdList = createGroups(component, Arrays.asList(groupDefinition), false)
1015 .on(this::onFailedGroupDBOperation);
1017 return gdList.get(0);
1020 private void validateGroupTypePerComponent(String groupType, Component component) {
1021 String specificType = component.getComponentMetadataDefinition().getMetadataDataDefinition().getActualComponentType();
1022 if (!component.isTopologyTemplate()) {
1023 throw new ByActionStatusComponentException(ActionStatus.GROUP_TYPE_ILLEGAL_PER_COMPONENT, groupType,
1026 Map<String, Set<String>> excludedGroupTypesMap = ConfigurationManager.getConfigurationManager().getConfiguration()
1027 .getExcludedGroupTypesMapping();
1029 if (MapUtils.isNotEmpty(excludedGroupTypesMap) && StringUtils.isNotEmpty(specificType)) {
1030 Set<String> excludedGroupTypesPerComponent = excludedGroupTypesMap.get(specificType);
1031 if (excludedGroupTypesPerComponent!=null && excludedGroupTypesPerComponent.contains(groupType)) {
1032 throw new ByActionStatusComponentException(ActionStatus.GROUP_TYPE_ILLEGAL_PER_COMPONENT, groupType, specificType);
1037 private int getNewGroupCounter(Component component) {
1038 List<String> existingNames = component.getGroups()
1040 .map(GroupDataDefinition::getInvariantName)
1042 List<String> existingIds = component.getGroups()
1044 .map(GroupDataDefinition::getUniqueId)
1046 existingIds.addAll(existingNames);
1048 return Utils.getNextCounter(existingIds);
1051 @LockingTransactional
1052 public GroupDefinition updateGroup(String componentId, ComponentTypeEnum componentTypeEnum, String groupId,
1053 String userId, GroupDefinition updatedGroup) {
1054 Component component = accessValidations.validateUserCanWorkOnComponent(componentId, componentTypeEnum, userId, UPDATE_GROUP);
1056 GroupDefinition existingGroup = findGroupOnComponent(component, groupId)
1058 .on(se -> onGroupNotFoundInComponentError(component, groupId));
1060 String existingGroupName = existingGroup.getName();
1061 String updatedGroupName = updatedGroup.getName();
1062 assertNewNameIsValidAndUnique(existingGroupName, updatedGroupName, component);
1063 existingGroup.setName(updatedGroupName);
1065 return updateGroup(component, existingGroup, existingGroupName)
1067 .on(this::onFailedUpdateGroupDBOperation);
1070 private void assertNewNameIsValidAndUnique(String currentGroupName, String updatedGroupName, Component component) {
1071 if (!ValidationUtils.validateResourceInstanceNameLength(updatedGroupName)) {
1072 throw new ByActionStatusComponentException(ActionStatus.EXCEEDS_LIMIT, "Group Name", ValidationUtils.RSI_NAME_MAX_LENGTH.toString());
1074 if (!ValidationUtils.validateResourceInstanceName(updatedGroupName)) {
1075 throw new ByActionStatusComponentException(ActionStatus.INVALID_VF_MODULE_NAME, updatedGroupName);
1077 if (!ComponentValidations.validateNameIsUniqueInComponent(currentGroupName, updatedGroupName, component)) {
1078 throw new ByActionStatusComponentException(ActionStatus.COMPONENT_NAME_ALREADY_EXIST, "Group", updatedGroupName);
1082 @LockingTransactional
1083 public GroupDefinition deleteGroup(String componentId, ComponentTypeEnum componentTypeEnum, String groupId,
1085 Component component = accessValidations.validateUserCanWorkOnComponent(componentId, componentTypeEnum, userId, DELETE_GROUP);
1087 GroupDefinition groupDefinition = findGroupOnComponent(component, groupId)
1089 .on(se -> onGroupNotFoundInComponentError(component, groupId));
1091 List<GroupDefinition> gdList = deleteGroups(component, java.util.Arrays.asList(groupDefinition))
1093 .on(this::onFailedGroupDBOperation);
1095 updatePolicyTargetReferencingDeletedGroup(groupId, component);
1096 return gdList.get(0);
1099 private List<GroupDefinition> onFailedGroupDBOperation(ResponseFormat responseFormat) {
1100 janusGraphDao.rollback();
1101 throw new ByResponseFormatComponentException(responseFormat);
1104 private GroupDefinition onFailedUpdateGroupDBOperation(ResponseFormat responseFormat) {
1105 janusGraphDao.rollback();
1106 throw new ByResponseFormatComponentException(responseFormat);
1109 private GroupDefinition onGroupNotFoundInComponentError(Component component, String groupId) {
1110 throw new ByActionStatusComponentException(ActionStatus.GROUP_IS_MISSING, groupId,
1111 component.getSystemName(), getComponentTypeForResponse(component));
1114 private GroupTypeDefinition onGroupTypeNotFound(Component component) {
1115 throw new ByActionStatusComponentException(ActionStatus.GROUP_TYPE_IS_INVALID, component.getSystemName(),
1116 component.getComponentType().toString());
1119 private void updatePolicyTargetReferencingDeletedGroup(String groupId, Component component) {
1120 log.debug("#updatePolicyTargetReferencingDeletedGroup - removing all component {} policy targets referencing group {}", component.getUniqueId(), groupId);
1121 ActionStatus actionStatus = policyTargetsUpdateHandler.removePoliciesTargets(component, groupId, PolicyTargetType.GROUPS);
1122 if (ActionStatus.OK != actionStatus) {
1123 janusGraphDao.rollback();
1124 throw new ByActionStatusComponentException(actionStatus, groupId);
1129 public Either<List<GroupDefinition>, ResponseFormat> createGroups(Component component, final List<GroupDefinition> groupDefinitions, boolean fromCsar) {
1131 Map<String, GroupDataDefinition> groups = new HashMap<>();
1132 Either<List<GroupDefinition>, ResponseFormat> result = null;
1133 Either<List<GroupDefinition>, StorageOperationStatus> createGroupsResult = null;
1134 Either<Map<String, DataTypeDefinition>, JanusGraphOperationStatus> allDataTypes = dataTypeCache.getAll();
1135 if (allDataTypes.isRight()) {
1136 JanusGraphOperationStatus status = allDataTypes.right().value();
1137 BeEcompErrorManager.getInstance().logInternalFlowError("AddPropertyToGroup", "Failed to add property to group. Status is " + status, ErrorSeverity.ERROR);
1138 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status))));
1142 // handle groups and convert to tosca data
1143 if (groupDefinitions != null && !groupDefinitions.isEmpty()) {
1144 for (GroupDefinition groupDefinition : groupDefinitions) {
1145 Either<GroupDefinition, ResponseFormat> handleGroupRes = handleGroup(component, groupDefinition, allDataTypes.left().value());
1146 if (handleGroupRes.isRight()) {
1147 result = Either.right(handleGroupRes.right().value());
1150 GroupDefinition handledGroup = handleGroupRes.left().value();
1151 groups.put(handledGroup.getInvariantName(), new GroupDataDefinition(handledGroup));
1155 if (result == null) {
1156 createGroupsResult = groupsOperation.createGroups(component, groups);
1157 if (createGroupsResult.isRight()) {
1158 result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(createGroupsResult.right().value())));
1161 if (result == null) {
1162 addCalculatedCapabilitiesWithPropertiesToComponent(component, groupDefinitions, fromCsar);
1164 if (result == null) {
1165 result = Either.left(groupDefinitions);
1167 component.setGroups(groupDefinitions);
1171 private void updateCalculatedCapabilitiesWithPropertiesOnComponent(Component component, final List<GroupDefinition> groupDefinitions, boolean fromCsar) {
1172 groupDefinitions.forEach(GroupDefinition::updateEmptyCapabilitiesOwnerFields);
1173 StorageOperationStatus status = groupsOperation.updateCalculatedCapabilitiesWithProperties(component.getUniqueId(),
1174 extractCapabilitiesFromGroups(groupDefinitions), extractCapabilityPropertiesFromGroups(groupDefinitions, fromCsar));
1175 if(status != StorageOperationStatus.OK){
1176 log.error("#updateCalculatedCapabilitiesWithPropertiesOnComponent - failed to update the groups' calculated capabilities with the properties on the component {}. ", component.getUniqueId());
1177 rollbackWithException(componentsUtils.convertFromStorageResponse(status));
1181 private void addCalculatedCapabilitiesWithPropertiesToComponent(Component component,
1182 final List<GroupDefinition> groupDefinitions, boolean fromCsar) {
1183 final List<GroupDefinition> nonNullGroupDefinitions =
1184 (groupDefinitions == null) ? Collections.emptyList() : groupDefinitions;
1186 nonNullGroupDefinitions.forEach(GroupDefinition::updateEmptyCapabilitiesOwnerFields);
1187 StorageOperationStatus status = groupsOperation.addCalculatedCapabilitiesWithProperties(
1188 component.getUniqueId(),
1189 extractCapabilitiesFromGroups(nonNullGroupDefinitions),
1190 extractCapabilityPropertiesFromGroups(nonNullGroupDefinitions, fromCsar));
1191 if (status != StorageOperationStatus.OK) {
1193 "#addCalculatedCapabilitiesWithPropertiesToComponent - failed to add the groups' calculated capabilities with the properties to the component {}. ",
1194 component.getUniqueId());
1195 rollbackWithException(componentsUtils.convertFromStorageResponse(status));
1199 private void deleteCalculatedCapabilitiesWithPropertiesFromComponent(Component component, final List<GroupDefinition> groupDefinitions) {
1200 StorageOperationStatus status = groupsOperation.deleteCalculatedCapabilitiesWithProperties(component.getUniqueId(), groupDefinitions);
1201 if(status != StorageOperationStatus.OK){
1202 log.error("#deleteCalculatedCapabilitiesWithPropertiesFromComponent - failed to remove the groups' calculated capabilities with the properties from the component {}. ", component.getUniqueId());
1203 rollbackWithException(componentsUtils.convertFromStorageResponse(status));
1207 public Either<List<GroupDefinition>, ResponseFormat> addGroups(Component component, final List<GroupDefinition> groupDefinitions, boolean fromCsar) {
1209 Either<List<GroupDefinition>, ResponseFormat> result = null;
1210 Either<List<GroupDefinition>, StorageOperationStatus> createGroupsResult = null;
1211 List<GroupDataDefinition> groups = new ArrayList<>();
1213 Either<Map<String, DataTypeDefinition>, JanusGraphOperationStatus> allDataTypes = dataTypeCache.getAll();
1214 if (allDataTypes.isRight()) {
1215 JanusGraphOperationStatus status = allDataTypes.right().value();
1216 BeEcompErrorManager.getInstance().logInternalFlowError("AddPropertyToGroup", "Failed to add property to group. Status is " + status, ErrorSeverity.ERROR);
1217 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status))));
1221 // handle groups and convert to tosca data
1222 if (groupDefinitions != null && !groupDefinitions.isEmpty()) {
1223 for (GroupDefinition groupDefinition : groupDefinitions) {
1224 Either<GroupDefinition, ResponseFormat> handleGroupRes = handleGroup(component, groupDefinition, allDataTypes.left().value());
1225 if (handleGroupRes.isRight()) {
1226 result = Either.right(handleGroupRes.right().value());
1229 GroupDefinition handledGroup = handleGroupRes.left().value();
1230 groups.add(new GroupDataDefinition(handledGroup));
1233 if (result == null) {
1234 createGroupsResult = groupsOperation.addGroups(component, groups);
1235 if (createGroupsResult.isRight()) {
1236 result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(createGroupsResult.right().value())));
1238 component.addGroups(createGroupsResult.left().value());
1240 if (result == null) {
1241 addCalculatedCapabilitiesWithPropertiesToComponent(component, groupDefinitions, fromCsar);
1243 if (result == null) {
1244 result = Either.left(groupDefinitions);
1249 public Either<List<GroupDefinition>, ResponseFormat> deleteGroups(Component component, List<GroupDefinition> groupDefinitions) {
1251 Either<List<GroupDefinition>, StorageOperationStatus> deleteGroupsResult;
1253 deleteGroupsResult = groupsOperation.deleteGroups(component, groupDefinitions.stream().map(GroupDataDefinition::new).collect(toList()));
1254 if (deleteGroupsResult.isRight()) {
1255 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(deleteGroupsResult.right().value())));
1257 deleteCalculatedCapabilitiesWithPropertiesFromComponent(component, groupDefinitions);
1259 if (component.getGroups()!=null) {
1260 component.getGroups().removeAll(deleteGroupsResult.left().value());
1262 return Either.left(deleteGroupsResult.left().value());
1266 * Update specific group version
1267 * @param fromCsar TODO
1270 public Either<List<GroupDefinition>, ResponseFormat> updateGroups(Component component, List<GroupDefinition> groupDefinitions, boolean fromCsar) {
1272 Either<List<GroupDefinition>, ResponseFormat> result = null;
1273 Either<List<GroupDefinition>, StorageOperationStatus> createGroupsResult;
1275 createGroupsResult = groupsOperation.updateGroups(component, groupDefinitions.stream().map(GroupDataDefinition::new).collect(toList()), PromoteVersionEnum.MINOR);
1276 if (createGroupsResult.isRight()) {
1277 result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(createGroupsResult.right().value())));
1279 if (result == null) {
1280 updateCalculatedCapabilitiesWithPropertiesOnComponent(component, groupDefinitions, fromCsar);
1282 if (result == null) {
1283 result = Either.left(groupDefinitions);
1288 private Either<GroupDefinition, ResponseFormat> handleGroup(Component component, GroupDefinition groupDefinition, Map<String, DataTypeDefinition> allDAtaTypes) {
1290 log.trace("Going to create group {}", groupDefinition);
1291 loggerSupportability.log(LoggerSupportabilityActions.CREATE_GROUP_POLICY,component.getComponentMetadataForSupportLog(),StatusCode.STARTED,"Start to create group: {}",groupDefinition.getName()+ " for component " + component.getName());
1292 // 3. verify group not already exist
1293 String groupDefinitionName = groupDefinition.getName();
1294 if (groupExistsInComponent(groupDefinitionName, component)) {
1295 String componentTypeForResponse = getComponentTypeForResponse(component);
1296 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_ALREADY_EXIST, groupDefinitionName, component.getNormalizedName(), componentTypeForResponse));
1298 // 4. verify type of group exist
1299 String groupType = groupDefinition.getType();
1300 if (StringUtils.isEmpty(groupType)) {
1301 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_MISSING_GROUP_TYPE, groupDefinitionName));
1303 Either<GroupTypeDefinition, StorageOperationStatus> getGroupType = groupTypeOperation.getLatestGroupTypeByType(groupType, true);
1304 if (getGroupType.isRight()) {
1305 StorageOperationStatus status = getGroupType.right().value();
1306 if (status == StorageOperationStatus.NOT_FOUND) {
1307 loggerSupportability.log(LoggerSupportabilityActions.CREATE_GROUP_POLICY,component.getComponentMetadataForSupportLog(), StatusCode.ERROR,"group {} cannot be found",groupDefinition.getName());
1308 BeEcompErrorManager.getInstance().logInvalidInputError(CREATE_GROUP, "group type " + groupType + " cannot be found", ErrorSeverity.INFO);
1309 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_TYPE_IS_INVALID, groupType));
1311 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
1314 // 6. verify the component instances type are allowed according to
1315 // the member types in the group type
1316 GroupTypeDefinition groupTypeDefinition = getGroupType.left().value();
1318 Either<Boolean, ResponseFormat> areValidMembers = verifyComponentInstancesAreValidMembers(component, groupDefinitionName, groupDefinition.getMembers(), groupTypeDefinition.getMembers());
1320 if (areValidMembers.isRight()) {
1321 ResponseFormat responseFormat = areValidMembers.right().value();
1322 return Either.right(responseFormat);
1324 // 7. verify the artifacts belongs to the component
1325 Either<Boolean, ResponseFormat> areValidArtifacts = verifyArtifactsBelongsToComponent(component, groupDefinition.getArtifacts(), CREATE_GROUP);
1326 if (areValidArtifacts.isRight()) {
1327 ResponseFormat responseFormat = areValidArtifacts.right().value();
1328 return Either.right(responseFormat);
1330 List<PropertyDefinition> groupTypeProperties = groupTypeDefinition.getProperties();
1332 List<GroupProperty> properties = groupDefinition.convertToGroupProperties();
1333 List<GroupProperty> updatedGroupTypeProperties = new ArrayList<>();
1334 if (CollectionUtils.isNotEmpty(properties)) {
1335 if (CollectionUtils.isEmpty(groupTypeProperties)) {
1336 BeEcompErrorManager.getInstance().logInvalidInputError(ADDING_GROUP, "group type does not have properties", ErrorSeverity.INFO);
1337 loggerSupportability.log(LoggerSupportabilityActions.CREATE_GROUP_POLICY,component.getComponentMetadataForSupportLog(), StatusCode.ERROR,"group {} does not have properties ",groupDefinition.getName());
1338 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(JanusGraphOperationStatus.MATCH_NOT_FOUND))));
1341 Map<String, PropertyDefinition> groupTypePropertiesMap = groupTypeProperties.stream().collect(Collectors.toMap(PropertyDefinition::getName, p -> p));
1343 Either<GroupProperty, JanusGraphOperationStatus> addPropertyResult;
1345 for (GroupProperty prop : properties) {
1346 addPropertyResult = handleProperty(prop, groupTypePropertiesMap.get(prop.getName()), i, allDAtaTypes, groupType);
1347 if (addPropertyResult.isRight()) {
1348 BeEcompErrorManager.getInstance().logInvalidInputError(ADDING_GROUP, "failed to validate property", ErrorSeverity.INFO);
1349 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(addPropertyResult.right().value()))));
1351 updatedGroupTypeProperties.add(addPropertyResult.left().value());
1357 if (groupDefinition.getUniqueId() == null) {
1358 String uid = UniqueIdBuilder.buildGroupingUid(component.getUniqueId(), groupDefinitionName);
1359 groupDefinition.setUniqueId(uid);
1361 groupDefinition.convertFromGroupProperties(updatedGroupTypeProperties);
1362 groupDefinition.setInvariantUUID(UniqueIdBuilder.buildInvariantUUID());
1363 groupDefinition.setGroupUUID(UniqueIdBuilder.generateUUID());
1364 groupDefinition.setVersion(INITIAL_VERSION);
1365 groupDefinition.setTypeUid(groupTypeDefinition.getUniqueId());
1366 loggerSupportability.log(LoggerSupportabilityActions.CREATE_GROUP_POLICY,component.getComponentMetadataForSupportLog(), StatusCode.COMPLETE,"group {} has been created ",groupDefinition.getName());
1367 return Either.left(groupDefinition);
1370 private static boolean groupExistsInComponent(String groupDefinitionName, Component component) {
1371 boolean found = false;
1372 List<GroupDefinition> groups = component.getGroups();
1373 if (CollectionUtils.isNotEmpty(groups)) {
1374 found = groups.stream().filter(p -> (p.getName().equalsIgnoreCase(groupDefinitionName))
1375 || p.getInvariantName().equalsIgnoreCase(groupDefinitionName))
1376 .findFirst().orElse(null) != null;
1381 private Either<GroupProperty, JanusGraphOperationStatus> handleProperty(GroupProperty groupProperty, PropertyDefinition prop, Integer index, Map<String, DataTypeDefinition> allDataTypes, String groupType) {
1384 return Either.right(JanusGraphOperationStatus.ILLEGAL_ARGUMENT);
1387 String propertyType = prop.getType();
1388 String value = groupProperty.getValue();
1390 Either<String, JanusGraphOperationStatus> checkInnerType = propertyOperation.checkInnerType(prop);
1391 if (checkInnerType.isRight()) {
1392 JanusGraphOperationStatus status = checkInnerType.right().value();
1393 return Either.right(status);
1396 String innerType = checkInnerType.left().value();
1398 log.debug("Before validateAndUpdatePropertyValue");
1399 Either<Object, Boolean> isValid = propertyOperation.validateAndUpdatePropertyValue(propertyType, value, innerType, allDataTypes);
1400 log.debug("After validateAndUpdatePropertyValue. isValid = {}", isValid);
1402 String newValue = value;
1403 if (isValid.isRight()) {
1404 Boolean res = isValid.right().value();
1406 return Either.right(JanusGraphOperationStatus.ILLEGAL_ARGUMENT);
1409 Object object = isValid.left().value();
1410 if (object != null) {
1411 newValue = object.toString();
1415 String uniqueId = shouldReconstructUniqueId(groupType) ? UniqueIdBuilder.buildGroupPropertyValueUid(prop.getUniqueId(), index)
1416 : prop.getUniqueId();
1418 groupProperty.setUniqueId(uniqueId);
1419 groupProperty.setValue(newValue);
1420 groupProperty.setType(prop.getType());
1421 groupProperty.setDefaultValue(prop.getDefaultValue());
1422 groupProperty.setDescription(prop.getDescription());
1423 groupProperty.setSchema(prop.getSchema());
1424 groupProperty.setPassword(prop.isPassword());
1425 groupProperty.setParentUniqueId(prop.getUniqueId());
1427 log.debug("Before adding property value to graph {}", groupProperty);
1429 return Either.left(groupProperty);
1432 // For old groups we want to leave indexing of property
1433 // For new groups we just need the types
1434 private boolean shouldReconstructUniqueId(String groupType) {
1435 return Constants.GROUP_TOSCA_HEAT.equals(groupType) || Constants.DEFAULT_GROUP_VF_MODULE.equals(groupType);