summaryrefslogtreecommitdiffstats
path: root/catalog-be/src/main
diff options
context:
space:
mode:
authorJvD_Ericsson <jeff.van.dam@est.tech>2023-03-23 11:52:27 +0000
committerJEFF VAN DAM <jeff.van.dam@est.tech>2023-03-31 10:28:19 +0000
commit3dff1c221e58de6a81cf6bbdfb84fdf97665e484 (patch)
treed670bd19a3721a59547f057e19109aa424191b88 /catalog-be/src/main
parent94176d70ee48b1703981cd8786c306f7c055e15d (diff)
Support to change substitution mapping node or version after service creation
Before changing check for service property usage in sub mapping node change Issue-ID: SDC-4439 Issue-ID: SDC-4430 Signed-off-by: JvD_Ericsson <jeff.van.dam@est.tech> Change-Id: Ia0f24c626ac836f0b4e7ffbe0004e7ab30089b25
Diffstat (limited to 'catalog-be/src/main')
-rw-r--r--catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml10
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentBusinessLogic.java13
-rw-r--r--catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogic.java175
-rw-r--r--catalog-be/src/main/resources/config/error-configuration.yaml8
4 files changed, 192 insertions, 14 deletions
diff --git a/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml b/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml
index ba2e58d6b8..05926151ba 100644
--- a/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml
+++ b/catalog-be/src/main/docker/backend/chef-repo/cookbooks/sdc-catalog-be/files/default/error-configuration.yaml
@@ -2877,4 +2877,12 @@ errors:
code: 400,
message: "Input name '%1' already exist.",
messageId: "SVC4016"
- } \ No newline at end of file
+ }
+
+ #---------SVC4017-----------------------------
+ # %1 - Map of component instance and properties
+ SUBSTITUTION_NODE_TYPE_PROPERTY_IN_USE: {
+ code: 409,
+ message: "Cannot change substitution node type as properties of the existing type are referenced by properties %1.",
+ messageId: "SVC4017"
+ }
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentBusinessLogic.java
index 1b28435dd8..28d105904b 100644
--- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentBusinessLogic.java
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentBusinessLogic.java
@@ -720,16 +720,21 @@ public abstract class ComponentBusinessLogic extends BaseBusinessLogic {
}
protected <T extends Component> Resource fetchAndSetDerivedFromGenericType(final T component, final String toscaType) {
+ final Resource genericTypeResource = fetchDerivedFromGenericType(component, toscaType);
+ component.setDerivedFromGenericInfo(genericTypeResource);
+ return genericTypeResource;
+ }
+
+ protected <T extends Component> Resource fetchDerivedFromGenericType(final T component, final String toscaType) {
final Either<Resource, ResponseFormat> genericTypeEither = this.genericTypeBusinessLogic.fetchDerivedFromGenericType(component, toscaType);
if (genericTypeEither.isRight()) {
- log.debug("Failed to fetch latest generic type for component {} of type", component.getName(), component.assetType());
+ log.debug("Failed to fetch latest generic type for component {} of type {}", component.getName(), component.assetType());
throw new ByActionStatusComponentException(ActionStatus.GENERIC_TYPE_NOT_FOUND, component.assetType());
}
- final Resource genericTypeResource = genericTypeEither.left().value();
- component.setDerivedFromGenericInfo(genericTypeResource);
- return genericTypeResource;
+ return genericTypeEither.left().value();
}
+
public Either<Map<String, List<IComponentInstanceConnectedElement>>, ResponseFormat> getFilteredComponentInstanceProperties(String componentId,
Map<FilterKeyEnum, List<String>> filters,
String userId) {
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogic.java
index 9b095cc062..a9014b4b21 100644
--- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogic.java
+++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ServiceBusinessLogic.java
@@ -19,6 +19,7 @@
* Modifications copyright (c) 2019 Nokia
* ================================================================================
*/
+
package org.openecomp.sdc.be.components.impl;
import static org.apache.commons.collections.CollectionUtils.isNotEmpty;
@@ -97,6 +98,10 @@ import org.openecomp.sdc.be.datatypes.elements.InterfaceDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.ListDataDefinition;
import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition;
import org.openecomp.sdc.be.datatypes.elements.OperationOutputDefinition;
+import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition;
+import org.openecomp.sdc.be.datatypes.elements.ToscaFunction;
+import org.openecomp.sdc.be.datatypes.elements.ToscaFunctionType;
+import org.openecomp.sdc.be.datatypes.elements.ToscaGetFunctionDataDefinition;
import org.openecomp.sdc.be.datatypes.enums.ComponentFieldsEnum;
import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum;
import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields;
@@ -189,7 +194,6 @@ public class ServiceBusinessLogic extends ComponentBusinessLogic {
private final ServiceInstantiationTypeValidator serviceInstantiationTypeValidator;
private final ServiceCategoryValidator serviceCategoryValidator;
private final ServiceValidator serviceValidator;
- private final PolicyBusinessLogic policyBusinessLogic;
private final GroupBusinessLogic groupBusinessLogic;
private ForwardingPathOperation forwardingPathOperation;
private AuditCassandraDao auditCassandraDao;
@@ -209,8 +213,7 @@ public class ServiceBusinessLogic extends ComponentBusinessLogic {
ComponentDescriptionValidator componentDescriptionValidator, ModelOperation modelOperation,
final ServiceRoleValidator serviceRoleValidator,
final ServiceInstantiationTypeValidator serviceInstantiationTypeValidator,
- final ServiceCategoryValidator serviceCategoryValidator, final ServiceValidator serviceValidator,
- final PolicyBusinessLogic policyBusinessLogic) {
+ final ServiceCategoryValidator serviceCategoryValidator, final ServiceValidator serviceValidator) {
super(elementDao, groupOperation, groupInstanceOperation, groupTypeOperation, groupBusinessLogic, interfaceOperation,
interfaceLifecycleTypeOperation, artifactsBusinessLogic, artifactToscaOperation, componentContactIdValidator, componentNameValidator,
componentTagsValidator, componentValidator, componentIconValidator, componentProjectCodeValidator, componentDescriptionValidator);
@@ -224,7 +227,6 @@ public class ServiceBusinessLogic extends ComponentBusinessLogic {
this.serviceInstantiationTypeValidator = serviceInstantiationTypeValidator;
this.serviceCategoryValidator = serviceCategoryValidator;
this.serviceValidator = serviceValidator;
- this.policyBusinessLogic = policyBusinessLogic;
this.groupBusinessLogic = groupBusinessLogic;
}
@@ -849,21 +851,42 @@ public class ServiceBusinessLogic extends ComponentBusinessLogic {
log.info("Restricted operation for user: {}, on service: {}", user.getUserId(), currentService.getCreatorUserId());
return Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION));
}
- Either<Service, ResponseFormat> validationRsponse = validateAndUpdateServiceMetadata(user, currentService, serviceUpdate);
- if (validationRsponse.isRight()) {
+ List<String> subNodePropsToBeRemoved = getSubstitutionNodePropertiesToBeRemoved(currentService, serviceUpdate);
+ List<PropertyDefinition> subNodePropsToBeAdded = getSubstitutionNodePropertiesToBeAdded(currentService, serviceUpdate);
+ boolean subNodeChanged = isSubstitutionNodeChanged(currentService, serviceUpdate);
+ Either<Service, ResponseFormat> validationResponse =
+ validateAndUpdateServiceMetadata(user, currentService, serviceUpdate, subNodeChanged, ListUtils.emptyIfNull(subNodePropsToBeRemoved));
+ if (validationResponse.isRight()) {
log.info("service update metadata: validations field.");
- return validationRsponse;
+ return validationResponse;
}
- Service serviceToUpdate = validationRsponse.left().value();
+ Service serviceToUpdate = validationResponse.left().value();
// lock resource
lockComponent(serviceId, currentService, "Update Service Metadata");
try {
+ if (subNodeChanged) {
+ if (!subNodePropsToBeRemoved.isEmpty()) {
+ removePropertiesFromService(currentService, subNodePropsToBeRemoved);
+ removeInputsFromService(currentService, subNodePropsToBeRemoved);
+ }
+ if (!subNodePropsToBeAdded.isEmpty()) {
+ addPropertiesToService(currentService, subNodePropsToBeAdded);
+ if (Constants.DEFAULT_MODEL_NAME.equals(currentService.getModel()) || currentService.getModel() == null) {
+ addInputsToService(currentService, subNodePropsToBeAdded);
+ }
+ }
+ }
return toscaOperationFacade.updateToscaElement(serviceToUpdate).right().map(rf -> {
janusGraphDao.rollback();
BeEcompErrorManager.getInstance().logBeSystemError("Update Service Metadata");
log.debug("failed to update sevice {}", serviceToUpdate.getUniqueId());
return (componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
}).left().bind(this::updateCatalogAndCommit);
+ } catch (ComponentException e) {
+ janusGraphDao.rollback();
+ BeEcompErrorManager.getInstance().logBeSystemError("Update Service Metadata");
+ log.debug("failed to update sevice {}", serviceToUpdate.getUniqueId());
+ return Either.right(componentsUtils.getResponseFormat(ActionStatus.GENERAL_ERROR));
} finally {
graphLockOperation.unlockComponent(serviceId, NodeTypeEnum.Service);
}
@@ -1034,9 +1057,18 @@ public class ServiceBusinessLogic extends ComponentBusinessLogic {
}
@VisibleForTesting
- Either<Service, ResponseFormat> validateAndUpdateServiceMetadata(User user, Service currentService, Service serviceUpdate) {
+ Either<Service, ResponseFormat> validateAndUpdateServiceMetadata(User user, Service currentService, Service serviceUpdate, boolean subNodeChanged,
+ List<String> subNodePropsToBeRemoved) {
try {
boolean hasBeenCertified = ValidationUtils.hasBeenCertified(currentService.getVersion());
+ if (subNodeChanged) {
+ if (!subNodePropsToBeRemoved.isEmpty()) {
+ areSubstitutionNodePropertiesInUse(currentService, subNodePropsToBeRemoved);
+ }
+ currentService.setDerivedFromGenericVersion(serviceUpdate.getDerivedFromGenericVersion());
+ currentService.setDerivedFromGenericType(serviceUpdate.getDerivedFromGenericType());
+ }
+
Either<Boolean, ResponseFormat> response = validateAndUpdateCategory(user, currentService, serviceUpdate, hasBeenCertified,
UPDATE_SERVICE_METADATA);
if (response.isRight()) {
@@ -1103,6 +1135,131 @@ public class ServiceBusinessLogic extends ComponentBusinessLogic {
}
}
+ private void addPropertiesToService(Service currentService, List<PropertyDefinition> subNodePropsToBeAdded) {
+ ListUtils.emptyIfNull(subNodePropsToBeAdded).forEach(prop -> {
+ Either<PropertyDefinition, StorageOperationStatus> addPropertyEither =
+ toscaOperationFacade.addPropertyToComponent(prop, currentService);
+ if (addPropertyEither.isRight()) {
+ throw new ByActionStatusComponentException(ActionStatus.GENERAL_ERROR);
+ }
+ });
+ }
+
+ private void addInputsToService(Service currentService, List<PropertyDefinition> subNodePropsToBeAdded) {
+ ListUtils.emptyIfNull(subNodePropsToBeAdded).forEach(prop -> {
+ InputDefinition inputDef = new InputDefinition(prop);
+ Either<InputDefinition, StorageOperationStatus> status =
+ toscaOperationFacade.addInputToComponent(prop.getName(), inputDef, currentService);
+ if (status.isRight()) {
+ throw new ByActionStatusComponentException(ActionStatus.GENERAL_ERROR);
+ }
+ });
+ }
+
+ private void removePropertiesFromService(Service currentService, List<String> subNodePropsToBeRemoved) {
+ List<PropertyDefinition> props = currentService.getProperties();
+ List<String> propsUniqueIdsToBeRemoved =
+ props.stream().filter(prop -> subNodePropsToBeRemoved.contains(prop.getName())).map(PropertyDefinition::getUniqueId)
+ .collect(Collectors.toList());
+ ListUtils.emptyIfNull(props).stream().filter(prop -> propsUniqueIdsToBeRemoved.contains(prop.getUniqueId())).forEach(prop -> {
+ StorageOperationStatus status = toscaOperationFacade.deletePropertyOfComponent(currentService, prop.getName());
+ if (status != StorageOperationStatus.OK) {
+ throw new ByActionStatusComponentException(ActionStatus.GENERAL_ERROR);
+ }
+ });
+ }
+
+ private void removeInputsFromService(Service currentService, List<String> subNodePropsToBeRemoved) {
+ List<PropertyDefinition> props = currentService.getProperties();
+ List<InputDefinition> inputs = currentService.getInputs();
+ List<String> propsUniqueIdsToBeRemoved =
+ props.stream().filter(prop -> subNodePropsToBeRemoved.contains(prop.getName())).map(PropertyDefinition::getUniqueId)
+ .collect(Collectors.toList());
+ ListUtils.emptyIfNull(inputs).stream().filter(input -> input.isMappedToComponentProperty() &&
+ (propsUniqueIdsToBeRemoved.contains(input.getPropertyId()) || subNodePropsToBeRemoved.contains(input.getName()))).forEach(input -> {
+ StorageOperationStatus status = toscaOperationFacade.deleteInputOfResource(currentService, input.getName());
+ if (status != StorageOperationStatus.OK) {
+ throw new ByActionStatusComponentException(ActionStatus.GENERAL_ERROR);
+ }
+ });
+ }
+
+ private void areSubstitutionNodePropertiesInUse(Service service, List<String> subNodePropsToBeRemoved) {
+ Map<String, List<ComponentInstanceProperty>> componentInstancesProps = service.getComponentInstancesProperties();
+ List<String> propsUniqueIdsToBeRemoved =
+ ListUtils.emptyIfNull(service.getProperties()).stream().filter(prop -> subNodePropsToBeRemoved.contains(prop.getName()))
+ .map(PropertyDefinition::getUniqueId)
+ .collect(Collectors.toList());
+ List<String> inputsUniqueIdsToBeRemoved = ListUtils.emptyIfNull(service.getInputs()).stream()
+ .filter(input -> propsUniqueIdsToBeRemoved.contains(input.getPropertyId()) || subNodePropsToBeRemoved.contains(input.getName()))
+ .map(PropertyDefinition::getUniqueId)
+ .collect(Collectors.toList());
+ Map<String, List<String>> inUse = new HashMap<>();
+ if (componentInstancesProps != null && !componentInstancesProps.isEmpty()) {
+ componentInstancesProps.forEach((compInstanceId, listOfProps) -> {
+ List<String> propsInUse = new ArrayList<>();
+ listOfProps.stream()
+ .filter(PropertyDataDefinition::isToscaFunction)
+ .filter(compProp -> ToscaFunctionType.isGetFunction(compProp.getToscaFunction().getType()))
+ .forEach(compProp -> {
+ ToscaFunction toscaFunction = compProp.getToscaFunction();
+ ToscaGetFunctionDataDefinition toscaGetFunction = (ToscaGetFunctionDataDefinition) toscaFunction;
+ String propName = toscaGetFunction.getPropertyName();
+ String propUniqueId = toscaGetFunction.getPropertyUniqueId();
+ if (inputsUniqueIdsToBeRemoved.contains(propUniqueId) || propsUniqueIdsToBeRemoved.contains(propUniqueId) ||
+ subNodePropsToBeRemoved.contains(propName)) {
+ propsInUse.add(compProp.getName());
+ }
+ });
+ if (!propsInUse.isEmpty()) {
+ Optional<ComponentInstance> componentInstance = service.getComponentInstanceById(compInstanceId);
+ componentInstance.ifPresent(instance -> inUse.put(instance.getName(), propsInUse));
+ }
+
+ });
+ }
+ if (!inUse.isEmpty()) {
+ String propsInUse = inUse.entrySet().stream().map(entry -> {
+ String properties = entry.getValue().stream().map(Object::toString).collect(Collectors.joining(", "));
+ return properties + " on " + entry.getKey();
+ }).collect(Collectors.joining(", properties "));
+ throw new ByActionStatusComponentException(ActionStatus.SUBSTITUTION_NODE_TYPE_PROPERTY_IN_USE, propsInUse);
+ }
+ }
+
+
+ private boolean isSubstitutionNodeChanged(Service currentService, Service updatedService) {
+ String currentServiceType = currentService.getDerivedFromGenericType();
+ String updatedServiceType = updatedService.getDerivedFromGenericType();
+ String currentServiceVersion = currentService.getDerivedFromGenericVersion();
+ String updatedServiceVersion = updatedService.getDerivedFromGenericVersion();
+ return !(StringUtils.equals(currentServiceType, updatedServiceType) && StringUtils.equals(currentServiceVersion, updatedServiceVersion));
+ }
+
+ private List<String> getSubstitutionNodePropertiesToBeRemoved(Service currentService, Service serviceUpdate) {
+ List<PropertyDefinition> currentProps = ListUtils.emptyIfNull(fetchDerivedFromGenericType(currentService, null).getProperties());
+ List<PropertyDefinition> updatedProps = ListUtils.emptyIfNull(fetchDerivedFromGenericType(serviceUpdate, null).getProperties());
+ if (!StringUtils.equals(currentService.getDerivedFromGenericType(), serviceUpdate.getDerivedFromGenericType())) {
+ return currentProps.stream().map(PropertyDefinition::getName).collect(Collectors.toList());
+ }
+ List<String> updatedPropNames = updatedProps.stream().map(PropertyDefinition::getName).collect(Collectors.toList());
+ List<String> propNamesToBeRemoved = currentProps.stream().map(PropertyDefinition::getName).collect(Collectors.toList());
+ propNamesToBeRemoved.removeIf(updatedPropNames::contains);
+ return propNamesToBeRemoved;
+ }
+
+ private List<PropertyDefinition> getSubstitutionNodePropertiesToBeAdded(Service currentService, Service serviceUpdate) {
+ List<PropertyDefinition> currentProps = ListUtils.emptyIfNull(fetchDerivedFromGenericType(currentService, null).getProperties());
+ List<PropertyDefinition> updatedProps = ListUtils.emptyIfNull(fetchDerivedFromGenericType(serviceUpdate, null).getProperties());
+ if (!StringUtils.equals(currentService.getDerivedFromGenericType(), serviceUpdate.getDerivedFromGenericType())) {
+ return updatedProps;
+ }
+ Set<String> currentPropNames = currentProps.stream().map(PropertyDefinition::getName).collect(Collectors.toSet());
+ updatedProps.removeIf(prop -> currentPropNames.contains(prop.getName()));
+ return updatedProps;
+ }
+
+
private void verifyValuesAreIdentical(Object updatedValue, Object originalValue, String fieldName) {
if (updatedValue != null && !updatedValue.equals(originalValue)) {
log.info("update service: received request to update {} to {} the field is not updatable ignoring.", fieldName, updatedValue);
diff --git a/catalog-be/src/main/resources/config/error-configuration.yaml b/catalog-be/src/main/resources/config/error-configuration.yaml
index 56dd54c5e4..a4b56d530c 100644
--- a/catalog-be/src/main/resources/config/error-configuration.yaml
+++ b/catalog-be/src/main/resources/config/error-configuration.yaml
@@ -2869,4 +2869,12 @@ errors:
code: 400,
message: "Cannot change this properties constraints as the resource is an instance.",
messageId: "SVC4015"
+ }
+
+ #---------SVC4017-----------------------------
+ # %1 - Map of component instance and properties
+ SUBSTITUTION_NODE_TYPE_PROPERTY_IN_USE: {
+ code: 409,
+ message: "Cannot change substitution node type as properties of the existing type are referenced by properties %1.",
+ messageId: "SVC4017"
} \ No newline at end of file