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 * ================================================================================
22 package org.openecomp.sdc.be.components.impl;
24 import static java.util.stream.Collectors.toList;
25 import static org.openecomp.sdc.be.model.jsonjanusgraph.utils.ModelConverter.extractCapabilitiesFromGroups;
26 import static org.openecomp.sdc.be.model.jsonjanusgraph.utils.ModelConverter.extractCapabilityPropertiesFromGroups;
28 import fj.data.Either;
29 import java.util.ArrayList;
30 import java.util.Arrays;
31 import java.util.Collection;
32 import java.util.Collections;
33 import java.util.EnumMap;
34 import java.util.HashMap;
35 import java.util.List;
37 import java.util.Map.Entry;
38 import java.util.Optional;
40 import java.util.regex.Pattern;
41 import java.util.stream.Collectors;
42 import org.apache.commons.collections.CollectionUtils;
43 import org.apache.commons.collections.MapUtils;
44 import org.apache.commons.io.FilenameUtils;
45 import org.apache.commons.lang3.StringUtils;
46 import org.apache.commons.lang3.math.NumberUtils;
47 import org.apache.commons.lang3.tuple.ImmutablePair;
48 import org.openecomp.sdc.be.components.impl.exceptions.ByActionStatusComponentException;
49 import org.openecomp.sdc.be.components.impl.exceptions.ByResponseFormatComponentException;
50 import org.openecomp.sdc.be.components.impl.exceptions.ComponentException;
51 import org.openecomp.sdc.be.components.impl.lock.LockingTransactional;
52 import org.openecomp.sdc.be.components.impl.policy.PolicyTargetsUpdateHandler;
53 import org.openecomp.sdc.be.components.utils.Utils;
54 import org.openecomp.sdc.be.components.validation.AccessValidations;
55 import org.openecomp.sdc.be.components.validation.ComponentValidations;
56 import org.openecomp.sdc.be.config.BeEcompErrorManager;
57 import org.openecomp.sdc.be.config.BeEcompErrorManager.ErrorSeverity;
58 import org.openecomp.sdc.be.config.ConfigurationManager;
59 import org.openecomp.sdc.be.dao.api.ActionStatus;
60 import org.openecomp.sdc.be.dao.janusgraph.JanusGraphOperationStatus;
61 import org.openecomp.sdc.be.datatypes.elements.ArtifactDataDefinition;
62 import org.openecomp.sdc.be.datatypes.elements.GroupDataDefinition;
63 import org.openecomp.sdc.be.datatypes.elements.PolicyTargetType;
64 import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
65 import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
66 import org.openecomp.sdc.be.datatypes.enums.CreatedFrom;
67 import org.openecomp.sdc.be.datatypes.enums.PromoteVersionEnum;
68 import org.openecomp.sdc.be.info.ArtifactDefinitionInfo;
69 import org.openecomp.sdc.be.info.ArtifactTemplateInfo;
70 import org.openecomp.sdc.be.info.GroupDefinitionInfo;
71 import org.openecomp.sdc.be.model.ArtifactDefinition;
72 import org.openecomp.sdc.be.model.Component;
73 import org.openecomp.sdc.be.model.ComponentInstance;
74 import org.openecomp.sdc.be.model.ComponentParametersView;
75 import org.openecomp.sdc.be.model.DataTypeDefinition;
76 import org.openecomp.sdc.be.model.GroupDefinition;
77 import org.openecomp.sdc.be.model.GroupInstance;
78 import org.openecomp.sdc.be.model.GroupInstanceProperty;
79 import org.openecomp.sdc.be.model.GroupProperty;
80 import org.openecomp.sdc.be.model.GroupTypeDefinition;
81 import org.openecomp.sdc.be.model.PropertyDefinition;
82 import org.openecomp.sdc.be.model.PropertyDefinition.GroupInstancePropertyValueUpdateBehavior;
83 import org.openecomp.sdc.be.model.PropertyDefinition.PropertyNames;
84 import org.openecomp.sdc.be.model.Resource;
85 import org.openecomp.sdc.be.model.User;
86 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.ArtifactsOperations;
87 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.GroupsOperation;
88 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.InterfaceOperation;
89 import org.openecomp.sdc.be.model.jsonjanusgraph.operations.TopologyTemplateOperation;
90 import org.openecomp.sdc.be.model.operations.api.IElementOperation;
91 import org.openecomp.sdc.be.model.operations.api.IGroupInstanceOperation;
92 import org.openecomp.sdc.be.model.operations.api.IGroupOperation;
93 import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation;
94 import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus;
95 import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter;
96 import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation;
97 import org.openecomp.sdc.be.model.operations.impl.UniqueIdBuilder;
98 import org.openecomp.sdc.common.api.Constants;
99 import org.openecomp.sdc.common.log.elements.LoggerSupportability;
100 import org.openecomp.sdc.common.log.enums.LogLevel;
101 import org.openecomp.sdc.common.log.enums.LoggerSupportabilityActions;
102 import org.openecomp.sdc.common.log.enums.StatusCode;
103 import org.openecomp.sdc.common.log.wrappers.Logger;
104 import org.openecomp.sdc.common.util.ValidationUtils;
105 import org.openecomp.sdc.exception.ResponseFormat;
106 import org.springframework.beans.factory.annotation.Autowired;
108 @org.springframework.stereotype.Component("groupBusinessLogic")
109 public class GroupBusinessLogic extends BaseBusinessLogic {
111 public static final String GROUP_DELIMITER_REGEX = "\\.\\.";
112 public static final String INITIAL_VERSION = "0.0";
113 private static final String ADDING_GROUP = "AddingGroup";
114 private static final String CREATE_GROUP = "CreateGroup";
115 private static final String UPDATE_GROUP = "UpdateGroup";
116 private static final String GET_GROUP = "GetGroup";
117 private static final String DELETE_GROUP = "DeleteGroup";
118 private static final Logger log = Logger.getLogger(GroupBusinessLogic.class);
119 private static final LoggerSupportability loggerSupportability = LoggerSupportability.getLogger(GroupBusinessLogic.class.getName());
120 private final AccessValidations accessValidations;
121 private final PolicyTargetsUpdateHandler policyTargetsUpdateHandler;
122 @javax.annotation.Resource
123 private final GroupsOperation groupsOperation;
126 public GroupBusinessLogic(IElementOperation elementDao, IGroupOperation groupOperation, IGroupInstanceOperation groupInstanceOperation,
127 IGroupTypeOperation groupTypeOperation, InterfaceOperation interfaceOperation,
128 InterfaceLifecycleOperation interfaceLifecycleTypeOperation, AccessValidations accessValidations,
129 GroupsOperation groupsOperation, PolicyTargetsUpdateHandler policyTargetsUpdateHandler,
130 ArtifactsOperations artifactToscaOperation) {
131 super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation, interfaceOperation, interfaceLifecycleTypeOperation,
132 artifactToscaOperation);
133 this.accessValidations = accessValidations;
134 this.groupsOperation = groupsOperation;
135 this.policyTargetsUpdateHandler = policyTargetsUpdateHandler;
138 private static boolean groupExistsInComponent(String groupDefinitionName, Component component) {
139 boolean found = false;
140 List<GroupDefinition> groups = component.getGroups();
141 if (CollectionUtils.isNotEmpty(groups)) {
142 found = groups.stream()
143 .filter(p -> (p.getName().equalsIgnoreCase(groupDefinitionName)) || p.getInvariantName().equalsIgnoreCase(groupDefinitionName))
144 .findFirst().orElse(null) != null;
149 private String getComponentTypeForResponse(org.openecomp.sdc.be.model.Component component) {
150 String componentTypeForResponse = "SERVICE";
151 if (component instanceof Resource) {
152 componentTypeForResponse = ((Resource) component).getResourceType().name();
154 return componentTypeForResponse;
158 * Verify that the artifact members belongs to the component
164 private Either<Boolean, ResponseFormat> verifyArtifactsBelongsToComponent(Component component, List<String> artifacts, String context) {
165 if (CollectionUtils.isEmpty(artifacts)) {
166 return Either.left(true);
168 Map<String, ArtifactDefinition> deploymentArtifacts = component.getDeploymentArtifacts();
169 if (MapUtils.isEmpty(deploymentArtifacts)) {
170 BeEcompErrorManager.getInstance()
171 .logInvalidInputError(context, "No deployment artifact found under component " + component.getNormalizedName(), ErrorSeverity.INFO);
172 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
174 List<String> currentArtifacts = deploymentArtifacts.values().stream().map(ArtifactDefinition::getUniqueId).collect(toList());
175 log.debug("The deployment artifacts of component {} are {}", component.getNormalizedName(), deploymentArtifacts);
176 if (!currentArtifacts.containsAll(artifacts)) {
177 BeEcompErrorManager.getInstance()
178 .logInvalidInputError(context, "Not all artifacts belongs to component " + component.getNormalizedName(), ErrorSeverity.INFO);
179 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
181 return Either.left(true);
185 * verify that the members are component instances of the component
188 * @param groupMembers
189 * @param memberToscaTypes
192 private Either<Boolean, ResponseFormat> verifyComponentInstancesAreValidMembers(Component component, String groupName,
193 Map<String, String> groupMembers, List<String> memberToscaTypes) {
194 if (MapUtils.isEmpty(groupMembers)) {
195 return Either.left(true);
197 if (CollectionUtils.isEmpty(memberToscaTypes)) {
198 return Either.left(true);
200 List<ComponentInstance> componentInstances = component.getComponentInstances();
201 if (CollectionUtils.isNotEmpty(componentInstances)) {
202 Map<String, ComponentInstance> compInstUidToCompInstMap = componentInstances.stream()
203 .collect(Collectors.toMap(ComponentInstance::getUniqueId, p -> p));
204 Set<String> allCompInstances = compInstUidToCompInstMap.keySet();
205 for (Entry<String, String> groupMember : groupMembers.entrySet()) {
206 String compName = groupMember.getKey();
207 String compUid = groupMember.getValue();
208 if (!allCompInstances.contains(compUid)) {
210 * %1 - member name %2 - group name %3 - VF name %4 - component type [VF ]
212 String componentTypeForResponse = getComponentTypeForResponse(component);
213 BeEcompErrorManager.getInstance()
214 .logInvalidInputError(CREATE_GROUP, "Not all group members exists under the component", ErrorSeverity.INFO);
215 return Either.right(componentsUtils
216 .getResponseFormat(ActionStatus.GROUP_INVALID_COMPONENT_INSTANCE, compName, groupName, component.getNormalizedName(),
217 componentTypeForResponse));
221 return Either.left(true);
225 * Update GroupDefinition metadata
229 * @param componentType
230 * @param updatedGroup
231 * @param inTransaction
234 public Either<GroupDefinition, ResponseFormat> validateAndUpdateGroupMetadata(String componentId, User user, ComponentTypeEnum componentType,
235 GroupDefinition updatedGroup, boolean inTransaction,
236 boolean shouldLock) {
237 Either<GroupDefinition, ResponseFormat> result = null;
238 boolean failed = false;
240 // Validate user exist
241 validateUserExists(user.getUserId());
242 // Validate component exist
243 org.openecomp.sdc.be.model.Component component = validateComponentExists(componentId, componentType, null);
244 // validate we can work on component
245 validateCanWorkOnComponent(component, user.getUserId());
246 List<GroupDefinition> currentGroups = component.getGroups();
247 if (CollectionUtils.isEmpty(currentGroups)) {
248 log.error("Failed to update the metadata of group {} on component {}. The status is {}. ", updatedGroup.getName(),
249 component.getName(), ActionStatus.GROUP_IS_MISSING);
250 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_IS_MISSING, updatedGroup.getName(), component.getName(),
251 component.getComponentType().getValue()));
254 // Validate groups exists in the component
255 Optional<GroupDefinition> currentGroupOpt = currentGroups.stream().filter(g -> g.getUniqueId().equals(updatedGroup.getUniqueId()))
257 if (!currentGroupOpt.isPresent()) {
258 log.error("Failed to update the metadata of group {} on component {}. The status is {}. ", updatedGroup.getName(),
259 component.getName(), ActionStatus.GROUP_IS_MISSING);
260 result = Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_IS_MISSING, updatedGroup.getName(), component.getName(),
261 component.getComponentType().getValue()));
264 GroupDefinition currentGroup = currentGroupOpt.get();
266 lockComponent(componentId, component, "Update GroupDefinition Metadata");
268 // Validate group type is vfModule
269 if (currentGroup.getType().equals(Constants.GROUP_TOSCA_HEAT)) {
270 log.error("Failed to update the metadata of group {}. Group type is {} and cannot be updated", currentGroup.getName(),
271 currentGroup.getType());
272 ResponseFormat responseFormat = componentsUtils.getResponseFormat(ActionStatus.GROUP_TYPE_IS_INVALID, updatedGroup.getType());
273 result = Either.right(responseFormat);
276 result = updateGroupMetadata(component, currentGroup, updatedGroup);
278 } catch (ComponentException e) {
283 janusGraphDao.commit();
285 janusGraphDao.rollback();
288 graphLockOperation.unlockComponent(componentId, componentType.getNodeType());
293 private Either<GroupDefinition, ResponseFormat> updateGroupMetadata(Component component, GroupDefinition currentGroup,
294 GroupDefinition updatedGroup) {
295 String currentGroupName = currentGroup.getName();
296 Either<GroupDefinition, ResponseFormat> result = validateAndUpdateGroupMetadata(currentGroup, updatedGroup);
297 if (result.isRight()) {
298 log.debug("Failed to validate a metadata of the group {} on component {}. ", updatedGroup.getName(), component.getName());
300 if (result.isLeft()) {
301 result = updateGroup(component, currentGroup, currentGroupName);
306 private Either<GroupDefinition, ResponseFormat> updateGroup(Component component, GroupDefinition updatedGroup, String currentGroupName) {
307 Either<GroupDefinition, StorageOperationStatus> handleGroupRes;
308 Either<GroupDefinition, ResponseFormat> result = null;
309 handleGroupRes = groupsOperation.updateGroup(component, updatedGroup);
310 if (handleGroupRes.isRight()) {
311 log.debug("Failed to update a metadata of the group {} on component {}. ", updatedGroup.getName(), component.getName());
312 result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(handleGroupRes.right().value())));
314 if (result == null) {
315 result = Either.left(updatedGroup);
321 * Validate and update GroupDefinition metadata
323 * @param currentGroup
327 private Either<GroupDefinition, ResponseFormat> validateAndUpdateGroupMetadata(GroupDefinition currentGroup, GroupDefinition groupUpdate) {
328 // Check if to update, and update GroupDefinition name.
329 Either<Boolean, ResponseFormat> response = validateAndUpdateGroupName(currentGroup, groupUpdate);
330 if (response.isRight()) {
331 ResponseFormat errorResponse = response.right().value();
332 return Either.right(errorResponse);
334 // Do not allow to update GroupDefinition version directly.
335 String versionUpdated = groupUpdate.getVersion();
336 String versionCurrent = currentGroup.getVersion();
337 if (versionUpdated != null && !versionCurrent.equals(versionUpdated)) {
338 log.info("update Group: recived request to update version to {} the field is not updatable ignoring.", versionUpdated);
340 return Either.left(currentGroup);
344 * Validate and update GroupDefinition name
346 * @param currentGroup
350 private Either<Boolean, ResponseFormat> validateAndUpdateGroupName(GroupDefinition currentGroup, GroupDefinition groupUpdate) {
351 String nameUpdated = groupUpdate.getName();
352 String nameCurrent = currentGroup.getName();
353 if (!nameCurrent.equals(nameUpdated)) {
354 Either<Boolean, ResponseFormat> validatNameResponse = validateGroupName(currentGroup.getName(), groupUpdate.getName(), true);
355 if (validatNameResponse.isRight()) {
356 ResponseFormat errorRespons = validatNameResponse.right().value();
357 return Either.right(errorRespons);
359 currentGroup.setName(groupUpdate.getName());
361 return Either.left(true);
365 * Validate that group name to update is valid (same as current group name except for middle part). For example: Current group name:
366 * MyResource..MyDesc..Module-1 Group to update: MyResource..MyDesc2..Module-1 Verify that only the second part MyDesc was changed.
368 * @param currentGroupName
369 * @param groupUpdateName
372 private Either<Boolean, ResponseFormat> validateGroupName(String currentGroupName, String groupUpdateName, boolean isforceNameModification) {
374 // Check if the group name is in old format.
375 if (Pattern.compile(Constants.MODULE_OLD_NAME_PATTERN).matcher(groupUpdateName).matches()) {
376 log.error("Group name {} is in old format", groupUpdateName);
377 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_VF_MODULE_NAME, groupUpdateName));
379 // Check that name pats 1 and 3 did not changed (only the second
381 // part can be changed)
383 // But verify before that the current group format is the new one
384 if (!Pattern.compile(Constants.MODULE_OLD_NAME_PATTERN).matcher(currentGroupName).matches()) {
385 String[] split1 = currentGroupName.split(GROUP_DELIMITER_REGEX);
386 String currentResourceName = split1[0];
387 String currentCounter = split1[2];
388 String[] split2 = groupUpdateName.split(GROUP_DELIMITER_REGEX);
389 String groupUpdateResourceName = split2[0];
390 String groupUpdateCounter = split2[2];
391 if (!isforceNameModification) { //if not forced ,allow name prefix&suffix validation [no changes]
392 if (!currentResourceName.equals(groupUpdateResourceName)) {
393 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_VF_MODULE_NAME_MODIFICATION, currentResourceName));
395 if (!currentCounter.equals(groupUpdateCounter)) {
396 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_VF_MODULE_NAME_MODIFICATION, currentCounter));
400 return Either.left(true);
401 } catch (Exception e) {
402 log.error("Error valiadting group name", e);
403 return Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_CONTENT));
408 * associate artifacts to a given group
412 * @param componentType
413 * @param inTransaction
416 public Either<GroupDefinitionInfo, ResponseFormat> getGroupWithArtifactsById(ComponentTypeEnum componentType, String componentId, String groupId,
417 String userId, boolean inTransaction) {
418 Either<GroupDefinitionInfo, ResponseFormat> result = null;
419 // Validate user exist
420 validateUserExists(userId);
421 // Validate component exist
422 org.openecomp.sdc.be.model.Component component = null;
424 ComponentParametersView componentParametersView = new ComponentParametersView();
425 componentParametersView.disableAll();
426 componentParametersView.setIgnoreGroups(false);
427 componentParametersView.setIgnoreArtifacts(false);
428 componentParametersView.setIgnoreUsers(false);
429 component = validateComponentExists(componentId, componentType, componentParametersView);
430 Either<GroupDefinition, StorageOperationStatus> groupEither = findGroupOnComponent(component, groupId);
431 if (groupEither.isRight()) {
432 log.debug("Failed to find group {} under component {}", groupId, component.getUniqueId());
433 BeEcompErrorManager.getInstance()
434 .logInvalidInputError(GET_GROUP, "group " + groupId + " not found under component " + component.getUniqueId(),
436 String componentTypeForResponse = getComponentTypeForResponse(component);
437 result = Either.right(
438 componentsUtils.getResponseFormat(ActionStatus.GROUP_IS_MISSING, groupId, component.getSystemName(), componentTypeForResponse));
441 GroupDefinition group = groupEither.left().value();
442 List<GroupProperty> props = group.convertToGroupProperties();
443 Boolean isBase = isBaseProp(component, props);
444 List<ArtifactDefinitionInfo> artifacts = new ArrayList<>();
445 List<ArtifactDefinition> artifactsFromComponent = new ArrayList<>();
446 List<String> artifactsIds = group.getArtifacts();
447 Map<String, ArtifactDefinition> deploymentArtifacts = null;
448 if (MapUtils.isNotEmpty(component.getDeploymentArtifacts())) {
449 deploymentArtifacts = component.getDeploymentArtifacts().values().stream()
450 .collect(Collectors.toMap(ArtifactDataDefinition::getUniqueId, a -> a));
452 if (artifactsIds != null && !artifactsIds.isEmpty()) {
453 for (String id : artifactsIds) {
454 if (deploymentArtifacts == null || !deploymentArtifacts.containsKey(id)) {
455 log.debug("Failed to get artifact {} . Status is {} ", id, StorageOperationStatus.NOT_FOUND);
456 ResponseFormat responseFormat = componentsUtils
457 .getResponseFormat(componentsUtils.convertFromStorageResponse(StorageOperationStatus.NOT_FOUND));
458 result = Either.right(responseFormat);
461 artifactsFromComponent.add(deploymentArtifacts.get(id));
463 addArtifactsToList(artifacts, artifactsFromComponent);
465 GroupDefinitionInfo resultInfo = new GroupDefinitionInfo(group);
466 resultInfo.setIsBase(isBase);
467 if (!artifacts.isEmpty()) {
468 resultInfo.setArtifacts(artifacts);
470 result = Either.left(resultInfo);
473 closeTransaction(inTransaction, result);
477 private void addArtifactsToList(List<ArtifactDefinitionInfo> artifacts, List<ArtifactDefinition> artifactsFromComponent) {
478 artifactsFromComponent.forEach(a -> artifacts.add(new ArtifactDefinitionInfo(a)));
481 private Boolean isBaseProp(Component component, List<GroupProperty> props) {
482 Boolean isBase = null;
483 if (CollectionUtils.isNotEmpty(props)) {
484 Optional<GroupProperty> isBasePropOp = props.stream().filter(p -> p.getName().equals(Constants.IS_BASE)).findAny();
485 if (isBasePropOp.isPresent()) {
486 GroupProperty propIsBase = isBasePropOp.get();
487 isBase = Boolean.parseBoolean(propIsBase.getValue());
489 BeEcompErrorManager.getInstance()
490 .logInvalidInputError(GET_GROUP, "failed to find prop isBase " + component.getNormalizedName(), ErrorSeverity.INFO);
496 private Either<GroupDefinition, StorageOperationStatus> findGroupOnComponent(Component component, String groupId) {
497 Either<GroupDefinition, StorageOperationStatus> result = null;
498 if (CollectionUtils.isNotEmpty(component.getGroups())) {
499 Optional<GroupDefinition> foundGroup = component.getGroups().stream().filter(g -> g.getUniqueId().equals(groupId)).findFirst();
500 if (foundGroup.isPresent()) {
501 result = Either.left(foundGroup.get());
504 if (result == null) {
505 result = Either.right(StorageOperationStatus.NOT_FOUND);
510 public Either<Boolean, ResponseFormat> validateGenerateVfModuleGroupNames(List<ArtifactTemplateInfo> allGroups, String resourceSystemName,
511 int startGroupCounter) {
512 Either<Boolean, ResponseFormat> validateGenerateGroupNamesRes = Either.left(true);
513 Collections.sort(allGroups, ArtifactTemplateInfo::compareByGroupName);
514 for (ArtifactTemplateInfo group : allGroups) {
515 Either<String, ResponseFormat> validateGenerateGroupNameRes = validateGenerateVfModuleGroupName(resourceSystemName,
516 group.getDescription(), startGroupCounter++);
517 if (validateGenerateGroupNameRes.isRight()) {
518 validateGenerateGroupNamesRes = Either.right(validateGenerateGroupNameRes.right().value());
521 group.setGroupName(validateGenerateGroupNameRes.left().value());
523 return validateGenerateGroupNamesRes;
527 * Generate module name from resourceName, description and counter
529 * @param resourceSystemName
531 * @param groupCounter
534 private Either<String, ResponseFormat> validateGenerateVfModuleGroupName(String resourceSystemName, String description, int groupCounter) {
535 Either<String, ResponseFormat> validateGenerateGroupNameRes;
536 if (resourceSystemName != null && description != null && Pattern.compile(Constants.MODULE_DESC_PATTERN).matcher(description).matches()) {
537 final String fileName = description.replaceAll(GROUP_DELIMITER_REGEX, "\\.");
538 validateGenerateGroupNameRes = Either
539 .left(String.format(Constants.MODULE_NAME_FORMAT, resourceSystemName, FilenameUtils.removeExtension(fileName), groupCounter));
541 validateGenerateGroupNameRes = Either.right(componentsUtils.getResponseFormat(ActionStatus.INVALID_VF_MODULE_NAME));
543 return validateGenerateGroupNameRes;
546 Either<Map<String, GroupDefinition>, ResponseFormat> validateUpdateVfGroupNames(Map<String, GroupDefinition> groups, String resourceSystemName) {
547 Map<String, GroupDefinition> updatedNamesGroups = new HashMap<>();
548 Either<Map<String, GroupDefinition>, ResponseFormat> result = Either.left(updatedNamesGroups);
549 for (Entry<String, GroupDefinition> groupEntry : groups.entrySet()) {
550 GroupDefinition curGroup = groupEntry.getValue();
551 String groupType = curGroup.getType();
552 String groupName = groupEntry.getKey();
555 Either<String, ResponseFormat> newGroupNameRes;
556 if (groupType.equals(Constants.DEFAULT_GROUP_VF_MODULE) && !Pattern.compile(Constants.MODULE_NEW_NAME_PATTERN).matcher(groupName)
558 if (Pattern.compile(Constants.MODULE_OLD_NAME_PATTERN).matcher(groupEntry.getKey()).matches()) {
559 counter = Integer.parseInt(groupEntry.getKey().split(Constants.MODULE_NAME_DELIMITER)[1]);
560 description = curGroup.getDescription();
562 counter = getNextVfModuleNameCounter(updatedNamesGroups);
563 description = groupName;
565 newGroupNameRes = validateGenerateVfModuleGroupName(resourceSystemName, description, counter);
566 if (newGroupNameRes.isRight()) {
567 log.debug("Failed to generate new vf module group name. Status is {} ", newGroupNameRes.right().value());
568 loggerSupportability.log(LogLevel.INFO, LoggerSupportabilityActions.CREATE_RESOURCE_FROM_YAML.getName(), StatusCode.ERROR.name(),
569 "Failed to generate new vf module group name. Status is: " + newGroupNameRes.right().value());
570 result = Either.right(newGroupNameRes.right().value());
573 groupName = newGroupNameRes.left().value();
574 curGroup.setName(groupName);
576 updatedNamesGroups.put(groupName, curGroup);
581 public int getNextVfModuleNameCounter(Map<String, GroupDefinition> groups) {
583 if (groups != null && !groups.isEmpty()) {
584 counter = getNextVfModuleNameCounter(groups.values());
589 public int getNextVfModuleNameCounter(Collection<GroupDefinition> groups) {
591 if (groups != null && !groups.isEmpty()) {
592 List<Integer> counters = groups.stream().filter(
593 group -> Pattern.compile(Constants.MODULE_NEW_NAME_PATTERN).matcher(group.getName()).matches() || Pattern
594 .compile(Constants.MODULE_OLD_NAME_PATTERN).matcher(group.getName()).matches())
595 .map(group -> Integer.parseInt(group.getName().split(Constants.MODULE_NAME_DELIMITER)[1])).collect(toList());
596 counter = (counters == null || counters.isEmpty()) ? 0 : counters.stream().max(Integer::compare).get() + 1;
601 public Either<List<GroupDefinition>, ResponseFormat> validateUpdateVfGroupNamesOnGraph(List<GroupDefinition> groups, Component component) {
602 List<GroupDefinition> updatedGroups = new ArrayList<>();
603 for (GroupDefinition group : groups) {
604 String groupType = group.getType();
605 String oldGroupName = group.getName();
607 Either<String, ResponseFormat> newGroupNameRes;
609 if (groupType.equals(Constants.DEFAULT_GROUP_VF_MODULE) && Pattern.compile(Constants.MODULE_OLD_NAME_PATTERN).matcher(oldGroupName)
611 counter = Integer.parseInt(group.getName().split(Constants.MODULE_NAME_DELIMITER)[1]);
612 newGroupNameRes = validateGenerateVfModuleGroupName(component.getSystemName(), group.getDescription(), counter);
613 if (newGroupNameRes.isRight()) {
614 log.debug("Failed to generate new vf module group name. Status is {} ", newGroupNameRes.right().value());
617 newGroupName = newGroupNameRes.left().value();
618 group.setName(newGroupName);
620 updatedGroups.add(group);
622 return Either.left(updatedGroups);
625 public Either<GroupDefinitionInfo, ResponseFormat> getGroupInstWithArtifactsById(ComponentTypeEnum componentType, String componentId,
626 String componentInstanceId, String groupInstId, String userId,
627 boolean inTransaction) {
628 Either<GroupDefinitionInfo, ResponseFormat> result = null;
629 // Validate user exist
630 validateUserExists(userId);
631 // Validate component exist
632 org.openecomp.sdc.be.model.Component component;
634 ComponentParametersView componentParametersView = new ComponentParametersView();
635 componentParametersView.disableAll();
636 componentParametersView.setIgnoreUsers(false);
637 componentParametersView.setIgnoreComponentInstances(false);
638 componentParametersView.setIgnoreArtifacts(false);
639 component = validateComponentExists(componentId, componentType, componentParametersView);
640 Either<ImmutablePair<ComponentInstance, GroupInstance>, StorageOperationStatus> findComponentInstanceAndGroupInstanceRes = findComponentInstanceAndGroupInstanceOnComponent(
641 component, componentInstanceId, groupInstId);
642 if (findComponentInstanceAndGroupInstanceRes.isRight()) {
643 log.debug("Failed to get group {} . Status is {} ", groupInstId, findComponentInstanceAndGroupInstanceRes.right().value());
644 ResponseFormat responseFormat = componentsUtils
645 .getResponseFormat(componentsUtils.convertFromStorageResponse(findComponentInstanceAndGroupInstanceRes.right().value()));
646 result = Either.right(responseFormat);
649 GroupInstance group = findComponentInstanceAndGroupInstanceRes.left().value().getRight();
650 Boolean isBase = isBaseProperty(component, group);
651 List<ArtifactDefinitionInfo> artifacts = new ArrayList<>();
652 List<String> artifactsIds = group.getArtifacts();
653 if (artifactsIds != null && !artifactsIds.isEmpty()) {
654 List<ComponentInstance> instances = component.getComponentInstances();
655 if (instances != null) {
656 instances.stream().filter(i -> i.getUniqueId().equals(componentInstanceId)).findFirst()
657 .ifPresent(f -> getFirstComponentInstance(group, artifacts, artifactsIds, f));
660 GroupDefinitionInfo resultInfo = new GroupDefinitionInfo(group);
661 resultInfo.setIsBase(isBase);
662 if (!artifacts.isEmpty()) {
663 resultInfo.setArtifacts(artifacts);
665 result = Either.left(resultInfo);
668 closeTransaction(inTransaction, result);
672 private void getFirstComponentInstance(GroupInstance group, List<ArtifactDefinitionInfo> artifacts, List<String> artifactsIds,
673 ComponentInstance ci) {
674 Map<String, ArtifactDefinition> deploymentArtifacts = ci.getDeploymentArtifacts();
675 artifactsIds.forEach(id -> deploymentArtifacts.values().stream().filter(a -> a.getUniqueId().equals(id)).findFirst()
676 .ifPresent(g -> artifacts.add(new ArtifactDefinitionInfo(g))));
677 List<String> instArtifactsIds = group.getGroupInstanceArtifacts();
678 instArtifactsIds.forEach(id -> deploymentArtifacts.values().stream().filter(a -> a.getUniqueId().equals(id)).findFirst()
679 .ifPresent(g -> artifacts.add(new ArtifactDefinitionInfo(g))));
682 private Boolean isBaseProperty(Component component, GroupInstance group) {
683 Boolean isBase = null;
684 List<? extends GroupProperty> props = group.convertToGroupInstancesProperties();
685 if (props != null && !props.isEmpty()) {
686 Optional<? extends GroupProperty> isBasePropOp = props.stream().filter(p -> p.getName().equals(Constants.IS_BASE)).findAny();
687 if (isBasePropOp.isPresent()) {
688 GroupProperty propIsBase = isBasePropOp.get();
689 isBase = Boolean.parseBoolean(propIsBase.getValue());
691 BeEcompErrorManager.getInstance()
692 .logInvalidInputError(GET_GROUP, "failed to find prop isBase " + component.getNormalizedName(), ErrorSeverity.INFO);
698 private void closeTransaction(boolean inTransaction, Either<GroupDefinitionInfo, ResponseFormat> result) {
699 if (!inTransaction) {
700 if (result == null || result.isRight()) {
701 log.debug("Going to execute rollback on create group.");
702 janusGraphDao.rollback();
704 log.debug("Going to execute commit on create group.");
705 janusGraphDao.commit();
710 private Either<ImmutablePair<ComponentInstance, GroupInstance>, StorageOperationStatus> findComponentInstanceAndGroupInstanceOnComponent(
711 Component component, String componentInstanceId, String groupInstId) {
712 Either<ImmutablePair<ComponentInstance, GroupInstance>, StorageOperationStatus> result = null;
713 if (CollectionUtils.isNotEmpty(component.getComponentInstances())) {
714 Optional<GroupInstance> foundGroup;
715 Optional<ComponentInstance> foundComponent = component.getComponentInstances().stream()
716 .filter(ci -> ci.getUniqueId().equals(componentInstanceId)).findFirst();
717 if (foundComponent.isPresent() && CollectionUtils.isNotEmpty(foundComponent.get().getGroupInstances())) {
718 foundGroup = foundComponent.get().getGroupInstances().stream().filter(gi -> gi.getUniqueId().equals(groupInstId)).findFirst();
719 if (foundGroup.isPresent()) {
720 result = Either.left(new ImmutablePair<>(foundComponent.get(), foundGroup.get()));
724 if (result == null) {
725 result = Either.right(StorageOperationStatus.NOT_FOUND);
730 private Boolean validateMinMaxAndInitialCountPropertyLogic(Map<PropertyNames, String> newValues, Map<PropertyNames, String> currValues,
731 Map<PropertyNames, String> parentValues) {
732 for (Entry<PropertyNames, String> entry : newValues.entrySet()) {
733 PropertyNames currPropertyName = entry.getKey();
734 if (currPropertyName == PropertyNames.MIN_INSTANCES) {
735 String minValue = parentValues.get(PropertyNames.MIN_INSTANCES);
736 String maxValue = getMaxValue(newValues, currValues);
737 validateValueInRange(new ImmutablePair<>(currPropertyName, entry.getValue()),
738 new ImmutablePair<>(PropertyNames.MIN_INSTANCES, minValue), new ImmutablePair<>(PropertyNames.MAX_INSTANCES, maxValue));
739 } else if (currPropertyName == PropertyNames.INITIAL_COUNT) {
740 String minValue = newValues.containsKey(PropertyNames.MIN_INSTANCES) ? newValues.get(PropertyNames.MIN_INSTANCES)
741 : currValues.get(PropertyNames.MIN_INSTANCES);
742 String maxValue = newValues.containsKey(PropertyNames.MAX_INSTANCES) ? newValues.get(PropertyNames.MAX_INSTANCES)
743 : currValues.get(PropertyNames.MAX_INSTANCES);
744 validateValueInRange(new ImmutablePair<>(currPropertyName, entry.getValue()),
745 new ImmutablePair<>(PropertyNames.MIN_INSTANCES, minValue), new ImmutablePair<>(PropertyNames.MAX_INSTANCES, maxValue));
746 } else if (currPropertyName == PropertyNames.MAX_INSTANCES) {
747 String minValue = getMinValue(newValues, currValues);
748 String maxValue = parentValues.get(PropertyNames.MAX_INSTANCES);
749 validateValueInRange(new ImmutablePair<>(currPropertyName, entry.getValue()),
750 new ImmutablePair<>(PropertyNames.MIN_INSTANCES, minValue), new ImmutablePair<>(PropertyNames.MAX_INSTANCES, maxValue));
756 private String getMaxValue(Map<PropertyNames, String> newValues, Map<PropertyNames, String> currValues) {
757 return newValues.containsKey(PropertyNames.INITIAL_COUNT) ? newValues.get(PropertyNames.MAX_INSTANCES)
758 : currValues.get(PropertyNames.INITIAL_COUNT);
761 private String getMinValue(Map<PropertyNames, String> newValues, Map<PropertyNames, String> currValues) {
762 return newValues.containsKey(PropertyNames.INITIAL_COUNT) ? newValues.get(PropertyNames.MIN_INSTANCES)
763 : currValues.get(PropertyNames.INITIAL_COUNT);
766 private Boolean validateValueInRange(ImmutablePair<PropertyNames, String> newValue, ImmutablePair<PropertyNames, String> min,
767 ImmutablePair<PropertyNames, String> max) {
768 final String warnMessage = "Failed to validate {} as property value of {}. It must be not higher than {}, and not lower than {}.";
769 int newValueInt = parseIntValue(newValue.getValue(), newValue.getKey());
770 int minInt = parseIntValue(min.getValue(), min.getKey());
771 int maxInt = parseIntValue(max.getValue(), max.getKey());
772 if (newValueInt < 0 || minInt < 0 || maxInt < 0) {
773 throw new ByActionStatusComponentException(ActionStatus.INVALID_PROPERTY);
774 } else if (newValueInt < minInt || newValueInt > maxInt) {
775 log.debug(warnMessage, newValue.getValue(), newValue.getKey().getPropertyName(), min.getValue(), max.getValue());
776 throw new ByActionStatusComponentException(ActionStatus.INVALID_GROUP_MIN_MAX_INSTANCES_PROPERTY_VALUE,
777 newValue.getKey().getPropertyName(), maxInt == Integer.MAX_VALUE ? Constants.UNBOUNDED : max.getValue(), min.getValue());
782 private int parseIntValue(String value, PropertyNames propertyName) {
784 if (propertyName == PropertyNames.MAX_INSTANCES) {
785 result = convertIfUnboundMax(value);
786 } else if (NumberUtils.isNumber(value)) {
787 result = Integer.parseInt(value);
795 * validates received new property values and updates group instance in case of success
797 * @param oldGroupInstance
798 * @param newProperties
801 public Either<GroupInstance, ResponseFormat> validateAndUpdateGroupInstancePropertyValues(String componentId, String instanceId,
802 GroupInstance oldGroupInstance,
803 List<GroupInstanceProperty> newProperties) {
804 Either<GroupInstance, ResponseFormat> actionResult = null;
805 List<GroupInstanceProperty> validatedReducedNewProperties = validateReduceGroupInstancePropertiesBeforeUpdate(oldGroupInstance, newProperties);
806 Either<GroupInstance, StorageOperationStatus> updateGroupInstanceResult = groupsOperation
807 .updateGroupInstancePropertyValuesOnGraph(componentId, instanceId, oldGroupInstance, validatedReducedNewProperties);
808 if (updateGroupInstanceResult.isRight()) {
809 log.debug("Failed to update group instance {} property values. ", oldGroupInstance.getName());
810 actionResult = Either
811 .right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(updateGroupInstanceResult.right().value())));
813 if (actionResult == null) {
814 actionResult = Either.left(updateGroupInstanceResult.left().value());
819 private List<GroupInstanceProperty> validateReduceGroupInstancePropertiesBeforeUpdate(GroupInstance oldGroupInstance,
820 List<GroupInstanceProperty> newProperties) {
821 Boolean validationRes = null;
822 List<GroupInstanceProperty> actionResult = null;
823 Map<String, GroupInstanceProperty> existingProperties = oldGroupInstance.convertToGroupInstancesProperties().stream()
824 .collect(Collectors.toMap(PropertyDataDefinition::getName, p -> p));
825 Map<PropertyNames, String> newPropertyValues = new EnumMap<>(PropertyNames.class);
826 List<GroupInstanceProperty> reducedProperties = new ArrayList<>();
827 String currPropertyName;
829 for (GroupInstanceProperty currNewProperty : newProperties) {
830 currPropertyName = currNewProperty.getName();
831 validationRes = handleAndAddProperty(reducedProperties, newPropertyValues, currNewProperty, existingProperties.get(currPropertyName));
833 if (validationRes == null || validationRes) {
834 Map<PropertyNames, String> existingPropertyValues = new EnumMap<>(PropertyNames.class);
835 Map<PropertyNames, String> parentPropertyValues = new EnumMap<>(PropertyNames.class);
836 fillValuesAndParentValuesFromExistingProperties(existingProperties, existingPropertyValues, parentPropertyValues);
837 validationRes = validateMinMaxAndInitialCountPropertyLogic(newPropertyValues, existingPropertyValues, parentPropertyValues);
840 actionResult = reducedProperties;
842 } catch (Exception e) {
843 log.error("Exception occured during validation and reducing group instance properties. The message is {}", e.getMessage(), e);
844 throw new ByActionStatusComponentException(ActionStatus.GENERAL_ERROR);
849 private void fillValuesAndParentValuesFromExistingProperties(Map<String, GroupInstanceProperty> existingProperties,
850 Map<PropertyNames, String> propertyValues,
851 Map<PropertyNames, String> parentPropertyValues) {
852 PropertyNames[] allPropertyNames = PropertyNames.values();
853 for (PropertyNames name : allPropertyNames) {
854 if (isUpdatable(name)) {
855 propertyValues.put(name, String.valueOf(existingProperties.get(name.getPropertyName()).getValue()));
856 parentPropertyValues.put(name, String.valueOf(existingProperties.get(name.getPropertyName()).getParentValue()));
861 private Boolean handleAndAddProperty(List<GroupInstanceProperty> reducedProperties, Map<PropertyNames, String> newPropertyValues,
862 GroupInstanceProperty currNewProperty, GroupInstanceProperty currExistingProperty) {
863 Boolean validationRes = null;
864 String currPropertyName = currNewProperty.getName();
865 PropertyNames propertyName = PropertyNames.findName(currPropertyName);
867 if (currExistingProperty == null) {
868 log.warn("The value of property with the name {} cannot be updated. The property not found on group instance. ", currPropertyName);
869 } else if (isUpdatable(propertyName)) {
870 validationRes = validateAndUpdatePropertyValue(currNewProperty, currExistingProperty);
871 addPropertyUpdatedValues(reducedProperties, propertyName, newPropertyValues, currNewProperty, currExistingProperty);
873 validateImmutableProperty(currExistingProperty, currNewProperty);
875 if (validationRes == null) {
876 validationRes = true;
878 } catch (Exception e) {
879 log.error("Exception occured during handle and adding property. The message is {}", e.getMessage(), e);
881 return validationRes;
884 private boolean isUpdatable(PropertyNames updatablePropertyName) {
885 return updatablePropertyName != null
886 && updatablePropertyName.getUpdateBehavior().getLevelNumber() >= GroupInstancePropertyValueUpdateBehavior.UPDATABLE_ON_SERVICE_LEVEL
890 private void addPropertyUpdatedValues(List<GroupInstanceProperty> reducedProperties, PropertyNames propertyName,
891 Map<PropertyNames, String> newPropertyValues, GroupInstanceProperty newProperty,
892 GroupInstanceProperty existingProperty) {
893 String newValue = newProperty.getValue();
894 if (!newValue.equals(String.valueOf(existingProperty.getValue()))) {
895 newProperty.setValueUniqueUid(existingProperty.getValueUniqueUid());
896 reducedProperties.add(newProperty);
898 if (!isEmptyMinInitialCountValue(propertyName, newValue)) {
899 newPropertyValues.put(propertyName, newValue);
903 private boolean isEmptyMinInitialCountValue(PropertyNames propertyName, String newValue) {
904 boolean result = false;
905 if ((propertyName == PropertyNames.MIN_INSTANCES || propertyName == PropertyNames.INITIAL_COUNT) && !NumberUtils.isNumber(newValue)) {
911 private int convertIfUnboundMax(String value) {
913 if (!NumberUtils.isNumber(value)) {
914 result = Integer.MAX_VALUE;
916 result = Integer.parseInt(value);
921 private Boolean validateAndUpdatePropertyValue(GroupInstanceProperty newProperty, GroupInstanceProperty existingProperty) {
922 String parentValue = existingProperty.getParentValue();
923 newProperty.setParentValue(parentValue);
924 if (StringUtils.isEmpty(newProperty.getValue())) {
925 newProperty.setValue(parentValue);
927 if (StringUtils.isEmpty(existingProperty.getValue())) {
928 existingProperty.setValue(parentValue);
930 StorageOperationStatus status = groupOperation.validateAndUpdatePropertyValue(newProperty);
931 if (status != StorageOperationStatus.OK) {
932 log.debug("Failed to validate property value {} of property with name {}. Status is {}. ", newProperty.getValue(), newProperty.getName(),
934 throw new ByActionStatusComponentException(componentsUtils.convertFromStorageResponse(status));
939 private void validateImmutableProperty(GroupProperty oldProperty, GroupProperty newProperty) {
940 if (oldProperty.getValue() == null && newProperty.getValue() != null || oldProperty.getValue() != null && !oldProperty.getValue()
941 .equals(newProperty.getValue())) {
942 log.warn("The value of property with the name {} cannot be updated on service level. Going to ignore new property value {}. ",
943 oldProperty.getName(), newProperty.getValue());
947 @LockingTransactional
948 public GroupDefinition createGroup(String componentId, ComponentTypeEnum componentTypeEnum, String groupType, String userId) {
949 Component component = accessValidations.validateUserCanWorkOnComponent(componentId, componentTypeEnum, userId, CREATE_GROUP);
950 validateGroupTypePerComponent(groupType, component);
951 GroupTypeDefinition groupTypeDefinition = groupTypeOperation.getLatestGroupTypeByType(groupType, false).left()
952 .on(se -> onGroupTypeNotFound(component));
953 boolean hasExistingGroups = CollectionUtils.isNotEmpty(component.getGroups());
954 GroupDefinition groupDefinition = new GroupDefinition();
955 groupDefinition.setType(groupType);
956 //find next valid counter
958 if (hasExistingGroups) {
959 nextCounter = getNewGroupCounter(component);
961 String name = TopologyTemplateOperation.buildSubComponentName(component.getName(), groupType, nextCounter);
962 groupDefinition.setName(name);
963 groupDefinition.setDescription(groupTypeDefinition.getDescription());
964 groupDefinition.setInvariantName(name);
965 groupDefinition.setCreatedFrom(CreatedFrom.UI);
966 //Add default type properties
967 List<PropertyDefinition> groupTypeProperties = groupTypeDefinition.getProperties();
968 List<GroupProperty> properties = groupTypeProperties.stream().map(GroupProperty::new).collect(toList());
969 groupDefinition.convertFromGroupProperties(properties);
970 groupDefinition.convertCapabilityDefinitions(groupTypeDefinition.getCapabilities());
971 List<GroupDefinition> gdList;
972 if (toscaOperationFacade.canAddGroups(componentId)) {
973 gdList = addGroups(component, Arrays.asList(groupDefinition), false).left().on(this::onFailedGroupDBOperation);
975 //createGroups also creates an edge and vertex to store group data
976 gdList = createGroups(component, Arrays.asList(groupDefinition), false).left().on(this::onFailedGroupDBOperation);
978 return gdList.get(0);
981 private void validateGroupTypePerComponent(String groupType, Component component) {
982 String specificType = component.getComponentMetadataDefinition().getMetadataDataDefinition().getActualComponentType();
983 if (!component.isTopologyTemplate()) {
984 throw new ByActionStatusComponentException(ActionStatus.GROUP_TYPE_ILLEGAL_PER_COMPONENT, groupType, specificType);
986 Map<String, Set<String>> excludedGroupTypesMap = ConfigurationManager.getConfigurationManager().getConfiguration()
987 .getExcludedGroupTypesMapping();
988 if (MapUtils.isNotEmpty(excludedGroupTypesMap) && StringUtils.isNotEmpty(specificType)) {
989 Set<String> excludedGroupTypesPerComponent = excludedGroupTypesMap.get(specificType);
990 if (excludedGroupTypesPerComponent != null && excludedGroupTypesPerComponent.contains(groupType)) {
991 throw new ByActionStatusComponentException(ActionStatus.GROUP_TYPE_ILLEGAL_PER_COMPONENT, groupType, specificType);
996 private int getNewGroupCounter(Component component) {
997 List<String> existingNames = component.getGroups().stream().map(GroupDataDefinition::getInvariantName).collect(toList());
998 List<String> existingIds = component.getGroups().stream().map(GroupDataDefinition::getUniqueId).collect(toList());
999 existingIds.addAll(existingNames);
1000 return Utils.getNextCounter(existingIds);
1003 @LockingTransactional
1004 public GroupDefinition updateGroup(String componentId, ComponentTypeEnum componentTypeEnum, String groupId, String userId,
1005 GroupDefinition updatedGroup) {
1006 Component component = accessValidations.validateUserCanWorkOnComponent(componentId, componentTypeEnum, userId, UPDATE_GROUP);
1007 GroupDefinition existingGroup = findGroupOnComponent(component, groupId).left().on(se -> onGroupNotFoundInComponentError(component, groupId));
1008 String existingGroupName = existingGroup.getName();
1009 String updatedGroupName = updatedGroup.getName();
1010 assertNewNameIsValidAndUnique(existingGroupName, updatedGroupName, component);
1011 existingGroup.setName(updatedGroupName);
1012 return updateGroup(component, existingGroup, existingGroupName).left().on(this::onFailedUpdateGroupDBOperation);
1015 private void assertNewNameIsValidAndUnique(String currentGroupName, String updatedGroupName, Component component) {
1016 if (!ValidationUtils.validateResourceInstanceNameLength(updatedGroupName)) {
1017 throw new ByActionStatusComponentException(ActionStatus.EXCEEDS_LIMIT, "Group Name", ValidationUtils.RSI_NAME_MAX_LENGTH.toString());
1019 if (!ValidationUtils.validateResourceInstanceName(updatedGroupName)) {
1020 throw new ByActionStatusComponentException(ActionStatus.INVALID_VF_MODULE_NAME, updatedGroupName);
1022 if (!ComponentValidations.validateNameIsUniqueInComponent(currentGroupName, updatedGroupName, component)) {
1023 throw new ByActionStatusComponentException(ActionStatus.COMPONENT_NAME_ALREADY_EXIST, "Group", updatedGroupName);
1027 @LockingTransactional
1028 public GroupDefinition deleteGroup(String componentId, ComponentTypeEnum componentTypeEnum, String groupId, String userId) {
1029 Component component = accessValidations.validateUserCanWorkOnComponent(componentId, componentTypeEnum, userId, DELETE_GROUP);
1030 GroupDefinition groupDefinition = findGroupOnComponent(component, groupId).left()
1031 .on(se -> onGroupNotFoundInComponentError(component, groupId));
1032 List<GroupDefinition> gdList = deleteGroups(component, java.util.Arrays.asList(groupDefinition)).left().on(this::onFailedGroupDBOperation);
1033 updatePolicyTargetReferencingDeletedGroup(groupId, component);
1034 return gdList.get(0);
1037 private List<GroupDefinition> onFailedGroupDBOperation(ResponseFormat responseFormat) {
1038 janusGraphDao.rollback();
1039 throw new ByResponseFormatComponentException(responseFormat);
1042 private GroupDefinition onFailedUpdateGroupDBOperation(ResponseFormat responseFormat) {
1043 janusGraphDao.rollback();
1044 throw new ByResponseFormatComponentException(responseFormat);
1047 private GroupDefinition onGroupNotFoundInComponentError(Component component, String groupId) {
1048 throw new ByActionStatusComponentException(ActionStatus.GROUP_IS_MISSING, groupId, component.getSystemName(),
1049 getComponentTypeForResponse(component));
1052 private GroupTypeDefinition onGroupTypeNotFound(Component component) {
1053 throw new ByActionStatusComponentException(ActionStatus.GROUP_TYPE_IS_INVALID, component.getSystemName(),
1054 component.getComponentType().toString());
1057 private void updatePolicyTargetReferencingDeletedGroup(String groupId, Component component) {
1058 log.debug("#updatePolicyTargetReferencingDeletedGroup - removing all component {} policy targets referencing group {}",
1059 component.getUniqueId(), groupId);
1060 ActionStatus actionStatus = policyTargetsUpdateHandler.removePoliciesTargets(component, groupId, PolicyTargetType.GROUPS);
1061 if (ActionStatus.OK != actionStatus) {
1062 janusGraphDao.rollback();
1063 throw new ByActionStatusComponentException(actionStatus, groupId);
1067 public Either<List<GroupDefinition>, ResponseFormat> createGroups(Component component, final List<GroupDefinition> groupDefinitions,
1069 Map<String, GroupDataDefinition> groups = new HashMap<>();
1070 Either<List<GroupDefinition>, ResponseFormat> result = null;
1071 Either<List<GroupDefinition>, StorageOperationStatus> createGroupsResult = null;
1072 Either<Map<String, DataTypeDefinition>, JanusGraphOperationStatus> allDataTypes = dataTypeCache.getAll();
1073 if (allDataTypes.isRight()) {
1074 JanusGraphOperationStatus status = allDataTypes.right().value();
1075 BeEcompErrorManager.getInstance()
1076 .logInternalFlowError("AddPropertyToGroup", "Failed to add property to group. Status is " + status, ErrorSeverity.ERROR);
1077 return Either.right(componentsUtils
1078 .getResponseFormat(componentsUtils.convertFromStorageResponse(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status))));
1080 // handle groups and convert to tosca data
1081 if (groupDefinitions != null && !groupDefinitions.isEmpty()) {
1082 for (GroupDefinition groupDefinition : groupDefinitions) {
1083 Either<GroupDefinition, ResponseFormat> handleGroupRes = handleGroup(component, groupDefinition, allDataTypes.left().value());
1084 if (handleGroupRes.isRight()) {
1085 result = Either.right(handleGroupRes.right().value());
1088 GroupDefinition handledGroup = handleGroupRes.left().value();
1089 groups.put(handledGroup.getInvariantName(), new GroupDataDefinition(handledGroup));
1092 if (result == null) {
1093 createGroupsResult = groupsOperation.createGroups(component, groups);
1094 if (createGroupsResult.isRight()) {
1096 .right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(createGroupsResult.right().value())));
1099 if (result == null) {
1100 addCalculatedCapabilitiesWithPropertiesToComponent(component, groupDefinitions, fromCsar);
1102 if (result == null) {
1103 result = Either.left(groupDefinitions);
1105 component.setGroups(groupDefinitions);
1109 private void updateCalculatedCapabilitiesWithPropertiesOnComponent(Component component, final List<GroupDefinition> groupDefinitions,
1111 groupDefinitions.forEach(GroupDefinition::updateEmptyCapabilitiesOwnerFields);
1112 StorageOperationStatus status = groupsOperation
1113 .updateCalculatedCapabilitiesWithProperties(component.getUniqueId(), extractCapabilitiesFromGroups(groupDefinitions),
1114 extractCapabilityPropertiesFromGroups(groupDefinitions, fromCsar));
1115 if (status != StorageOperationStatus.OK) {
1117 "#updateCalculatedCapabilitiesWithPropertiesOnComponent - failed to update the groups' calculated capabilities with the properties on the component {}. ",
1118 component.getUniqueId());
1119 rollbackWithException(componentsUtils.convertFromStorageResponse(status));
1123 private void addCalculatedCapabilitiesWithPropertiesToComponent(Component component, final List<GroupDefinition> groupDefinitions,
1125 final List<GroupDefinition> nonNullGroupDefinitions = (groupDefinitions == null) ? Collections.emptyList() : groupDefinitions;
1126 nonNullGroupDefinitions.forEach(GroupDefinition::updateEmptyCapabilitiesOwnerFields);
1127 StorageOperationStatus status = groupsOperation
1128 .addCalculatedCapabilitiesWithProperties(component.getUniqueId(), extractCapabilitiesFromGroups(nonNullGroupDefinitions),
1129 extractCapabilityPropertiesFromGroups(nonNullGroupDefinitions, fromCsar));
1130 if (status != StorageOperationStatus.OK) {
1132 "#addCalculatedCapabilitiesWithPropertiesToComponent - failed to add the groups' calculated capabilities with the properties to the component {}. ",
1133 component.getUniqueId());
1134 rollbackWithException(componentsUtils.convertFromStorageResponse(status));
1138 private void deleteCalculatedCapabilitiesWithPropertiesFromComponent(Component component, final List<GroupDefinition> groupDefinitions) {
1139 StorageOperationStatus status = groupsOperation.deleteCalculatedCapabilitiesWithProperties(component.getUniqueId(), groupDefinitions);
1140 if (status != StorageOperationStatus.OK) {
1142 "#deleteCalculatedCapabilitiesWithPropertiesFromComponent - failed to remove the groups' calculated capabilities with the properties from the component {}. ",
1143 component.getUniqueId());
1144 rollbackWithException(componentsUtils.convertFromStorageResponse(status));
1148 public Either<List<GroupDefinition>, ResponseFormat> addGroups(Component component, final List<GroupDefinition> groupDefinitions,
1150 Either<List<GroupDefinition>, ResponseFormat> result = null;
1151 Either<List<GroupDefinition>, StorageOperationStatus> createGroupsResult = null;
1152 List<GroupDataDefinition> groups = new ArrayList<>();
1153 Either<Map<String, DataTypeDefinition>, JanusGraphOperationStatus> allDataTypes = dataTypeCache.getAll();
1154 if (allDataTypes.isRight()) {
1155 JanusGraphOperationStatus status = allDataTypes.right().value();
1156 BeEcompErrorManager.getInstance()
1157 .logInternalFlowError("AddPropertyToGroup", "Failed to add property to group. Status is " + status, ErrorSeverity.ERROR);
1158 return Either.right(componentsUtils
1159 .getResponseFormat(componentsUtils.convertFromStorageResponse(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(status))));
1161 // handle groups and convert to tosca data
1162 if (groupDefinitions != null && !groupDefinitions.isEmpty()) {
1163 for (GroupDefinition groupDefinition : groupDefinitions) {
1164 Either<GroupDefinition, ResponseFormat> handleGroupRes = handleGroup(component, groupDefinition, allDataTypes.left().value());
1165 if (handleGroupRes.isRight()) {
1166 result = Either.right(handleGroupRes.right().value());
1169 GroupDefinition handledGroup = handleGroupRes.left().value();
1170 groups.add(new GroupDataDefinition(handledGroup));
1173 if (result == null) {
1174 createGroupsResult = groupsOperation.addGroups(component, groups);
1175 if (createGroupsResult.isRight()) {
1177 .right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(createGroupsResult.right().value())));
1179 component.addGroups(createGroupsResult.left().value());
1181 if (result == null) {
1182 addCalculatedCapabilitiesWithPropertiesToComponent(component, groupDefinitions, fromCsar);
1184 if (result == null) {
1185 result = Either.left(groupDefinitions);
1190 public Either<List<GroupDefinition>, ResponseFormat> deleteGroups(Component component, List<GroupDefinition> groupDefinitions) {
1191 Either<List<GroupDefinition>, StorageOperationStatus> deleteGroupsResult;
1192 deleteGroupsResult = groupsOperation.deleteGroups(component, groupDefinitions.stream().map(GroupDataDefinition::new).collect(toList()));
1193 if (deleteGroupsResult.isRight()) {
1194 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(deleteGroupsResult.right().value())));
1196 deleteCalculatedCapabilitiesWithPropertiesFromComponent(component, groupDefinitions);
1198 if (component.getGroups() != null) {
1199 component.getGroups().removeAll(deleteGroupsResult.left().value());
1201 return Either.left(deleteGroupsResult.left().value());
1205 * Update specific group version
1207 * @param fromCsar TODO
1209 public Either<List<GroupDefinition>, ResponseFormat> updateGroups(Component component, List<GroupDefinition> groupDefinitions, boolean fromCsar) {
1210 Either<List<GroupDefinition>, ResponseFormat> result = null;
1211 Either<List<GroupDefinition>, StorageOperationStatus> createGroupsResult;
1212 createGroupsResult = groupsOperation
1213 .updateGroups(component, groupDefinitions.stream().map(GroupDataDefinition::new).collect(toList()), PromoteVersionEnum.MINOR);
1214 if (createGroupsResult.isRight()) {
1215 result = Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(createGroupsResult.right().value())));
1217 if (result == null) {
1218 updateCalculatedCapabilitiesWithPropertiesOnComponent(component, groupDefinitions, fromCsar);
1220 if (result == null) {
1221 result = Either.left(groupDefinitions);
1226 private Either<GroupDefinition, ResponseFormat> handleGroup(Component component, GroupDefinition groupDefinition,
1227 Map<String, DataTypeDefinition> allDAtaTypes) {
1228 log.trace("Going to create group {}", groupDefinition);
1229 loggerSupportability.log(LoggerSupportabilityActions.CREATE_GROUP_POLICY, component.getComponentMetadataForSupportLog(), StatusCode.STARTED,
1230 "Start to create group: {}", groupDefinition.getName() + " for component " + component.getName());
1231 // 3. verify group not already exist
1232 String groupDefinitionName = groupDefinition.getName();
1233 if (groupExistsInComponent(groupDefinitionName, component)) {
1234 String componentTypeForResponse = getComponentTypeForResponse(component);
1235 return Either.right(componentsUtils
1236 .getResponseFormat(ActionStatus.GROUP_ALREADY_EXIST, groupDefinitionName, component.getNormalizedName(), componentTypeForResponse));
1238 // 4. verify type of group exist
1239 String groupType = groupDefinition.getType();
1240 if (StringUtils.isEmpty(groupType)) {
1241 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_MISSING_GROUP_TYPE, groupDefinitionName));
1243 Either<GroupTypeDefinition, StorageOperationStatus> getGroupType = groupTypeOperation.getLatestGroupTypeByType(groupType, true);
1244 if (getGroupType.isRight()) {
1245 StorageOperationStatus status = getGroupType.right().value();
1246 if (status == StorageOperationStatus.NOT_FOUND) {
1247 loggerSupportability
1248 .log(LoggerSupportabilityActions.CREATE_GROUP_POLICY, component.getComponentMetadataForSupportLog(), StatusCode.ERROR,
1249 "group {} cannot be found", groupDefinition.getName());
1250 BeEcompErrorManager.getInstance()
1251 .logInvalidInputError(CREATE_GROUP, "group type " + groupType + " cannot be found", ErrorSeverity.INFO);
1252 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GROUP_TYPE_IS_INVALID, groupType));
1254 return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
1257 // 6. verify the component instances type are allowed according to
1259 // the member types in the group type
1260 GroupTypeDefinition groupTypeDefinition = getGroupType.left().value();
1261 Either<Boolean, ResponseFormat> areValidMembers = verifyComponentInstancesAreValidMembers(component, groupDefinitionName,
1262 groupDefinition.getMembers(), groupTypeDefinition.getMembers());
1263 if (areValidMembers.isRight()) {
1264 ResponseFormat responseFormat = areValidMembers.right().value();
1265 return Either.right(responseFormat);
1267 // 7. verify the artifacts belongs to the component
1268 Either<Boolean, ResponseFormat> areValidArtifacts = verifyArtifactsBelongsToComponent(component, groupDefinition.getArtifacts(),
1270 if (areValidArtifacts.isRight()) {
1271 ResponseFormat responseFormat = areValidArtifacts.right().value();
1272 return Either.right(responseFormat);
1274 List<PropertyDefinition> groupTypeProperties = groupTypeDefinition.getProperties();
1275 List<GroupProperty> properties = groupDefinition.convertToGroupProperties();
1276 List<GroupProperty> updatedGroupTypeProperties = new ArrayList<>();
1277 if (CollectionUtils.isNotEmpty(properties)) {
1278 if (CollectionUtils.isEmpty(groupTypeProperties)) {
1279 BeEcompErrorManager.getInstance().logInvalidInputError(ADDING_GROUP, "group type does not have properties", ErrorSeverity.INFO);
1280 loggerSupportability
1281 .log(LoggerSupportabilityActions.CREATE_GROUP_POLICY, component.getComponentMetadataForSupportLog(), StatusCode.ERROR,
1282 "group {} does not have properties ", groupDefinition.getName());
1283 return Either.right(componentsUtils.getResponseFormat(componentsUtils.convertFromStorageResponse(
1284 DaoStatusConverter.convertJanusGraphStatusToStorageStatus(JanusGraphOperationStatus.MATCH_NOT_FOUND))));
1286 Map<String, PropertyDefinition> groupTypePropertiesMap = groupTypeProperties.stream()
1287 .collect(Collectors.toMap(PropertyDefinition::getName, p -> p));
1288 Either<GroupProperty, JanusGraphOperationStatus> addPropertyResult;
1290 for (GroupProperty prop : properties) {
1291 addPropertyResult = handleProperty(prop, groupTypePropertiesMap.get(prop.getName()), i, allDAtaTypes, groupType);
1292 if (addPropertyResult.isRight()) {
1293 BeEcompErrorManager.getInstance().logInvalidInputError(ADDING_GROUP, "failed to validate property", ErrorSeverity.INFO);
1294 return Either.right(componentsUtils.getResponseFormat(componentsUtils
1295 .convertFromStorageResponse(DaoStatusConverter.convertJanusGraphStatusToStorageStatus(addPropertyResult.right().value()))));
1297 updatedGroupTypeProperties.add(addPropertyResult.left().value());
1301 if (groupDefinition.getUniqueId() == null) {
1302 String uid = UniqueIdBuilder.buildGroupingUid(component.getUniqueId(), groupDefinitionName);
1303 groupDefinition.setUniqueId(uid);
1305 groupDefinition.convertFromGroupProperties(updatedGroupTypeProperties);
1306 groupDefinition.setInvariantUUID(UniqueIdBuilder.buildInvariantUUID());
1307 groupDefinition.setGroupUUID(UniqueIdBuilder.generateUUID());
1308 groupDefinition.setVersion(INITIAL_VERSION);
1309 groupDefinition.setTypeUid(groupTypeDefinition.getUniqueId());
1310 loggerSupportability.log(LoggerSupportabilityActions.CREATE_GROUP_POLICY, component.getComponentMetadataForSupportLog(), StatusCode.COMPLETE,
1311 "group {} has been created ", groupDefinition.getName());
1312 return Either.left(groupDefinition);
1315 private Either<GroupProperty, JanusGraphOperationStatus> handleProperty(GroupProperty groupProperty, PropertyDefinition prop, Integer index,
1316 Map<String, DataTypeDefinition> allDataTypes, String groupType) {
1318 return Either.right(JanusGraphOperationStatus.ILLEGAL_ARGUMENT);
1320 String propertyType = prop.getType();
1321 String value = groupProperty.getValue();
1322 Either<String, JanusGraphOperationStatus> checkInnerType = propertyOperation.checkInnerType(prop);
1323 if (checkInnerType.isRight()) {
1324 JanusGraphOperationStatus status = checkInnerType.right().value();
1325 return Either.right(status);
1327 String innerType = checkInnerType.left().value();
1328 log.debug("Before validateAndUpdatePropertyValue");
1329 Either<Object, Boolean> isValid = propertyOperation.validateAndUpdatePropertyValue(propertyType, value, innerType, allDataTypes);
1330 log.debug("After validateAndUpdatePropertyValue. isValid = {}", isValid);
1331 String newValue = value;
1332 if (isValid.isRight()) {
1333 Boolean res = isValid.right().value();
1335 return Either.right(JanusGraphOperationStatus.ILLEGAL_ARGUMENT);
1338 Object object = isValid.left().value();
1339 if (object != null) {
1340 newValue = object.toString();
1344 shouldReconstructUniqueId(groupType) ? UniqueIdBuilder.buildGroupPropertyValueUid(prop.getUniqueId(), index) : prop.getUniqueId();
1345 groupProperty.setUniqueId(uniqueId);
1346 groupProperty.setValue(newValue);
1347 groupProperty.setType(prop.getType());
1348 groupProperty.setDefaultValue(prop.getDefaultValue());
1349 groupProperty.setDescription(prop.getDescription());
1350 groupProperty.setSchema(prop.getSchema());
1351 groupProperty.setPassword(prop.isPassword());
1352 groupProperty.setParentUniqueId(prop.getUniqueId());
1353 log.debug("Before adding property value to graph {}", groupProperty);
1354 return Either.left(groupProperty);
1356 // For old groups we want to leave indexing of property
1358 // For new groups we just need the types
1359 private boolean shouldReconstructUniqueId(String groupType) {
1360 return Constants.GROUP_TOSCA_HEAT.equals(groupType) || Constants.DEFAULT_GROUP_VF_MODULE.equals(groupType);