diff options
Diffstat (limited to 'catalog-be/src')
15 files changed, 1581 insertions, 167 deletions
diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/BaseBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/BaseBusinessLogic.java index 8ee1864862..65f1e4981a 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/BaseBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/BaseBusinessLogic.java @@ -21,7 +21,17 @@ package org.openecomp.sdc.be.components.impl; import com.google.gson.JsonElement; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.function.Function; + import fj.data.Either; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.openecomp.sdc.be.components.impl.exceptions.ComponentException; import org.openecomp.sdc.be.components.validation.UserValidations; @@ -37,19 +47,33 @@ import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; import org.openecomp.sdc.be.impl.ComponentsUtils; -import org.openecomp.sdc.be.model.*; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentParametersView; +import org.openecomp.sdc.be.model.DataTypeDefinition; +import org.openecomp.sdc.be.model.IComplexDefaultValue; +import org.openecomp.sdc.be.model.IPropertyInputCommon; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.PropertyConstraint; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.User; import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache; import org.openecomp.sdc.be.model.jsontitan.operations.ArtifactsOperations; import org.openecomp.sdc.be.model.jsontitan.operations.InterfaceOperation; import org.openecomp.sdc.be.model.jsontitan.operations.ToscaOperationFacade; import org.openecomp.sdc.be.model.operations.StorageException; -import org.openecomp.sdc.be.model.operations.api.*; +import org.openecomp.sdc.be.model.operations.api.IElementOperation; +import org.openecomp.sdc.be.model.operations.api.IGraphLockOperation; +import org.openecomp.sdc.be.model.operations.api.IGroupInstanceOperation; +import org.openecomp.sdc.be.model.operations.api.IGroupOperation; +import org.openecomp.sdc.be.model.operations.api.IGroupTypeOperation; +import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter; import org.openecomp.sdc.be.model.operations.impl.InterfaceLifecycleOperation; import org.openecomp.sdc.be.model.operations.impl.PolicyTypeOperation; import org.openecomp.sdc.be.model.operations.impl.PropertyOperation; import org.openecomp.sdc.be.model.operations.utils.ComponentValidationUtils; import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; +import org.openecomp.sdc.be.model.tosca.ToscaType; import org.openecomp.sdc.be.model.tosca.converters.PropertyValueConverter; import org.openecomp.sdc.be.model.tosca.validators.DataTypeValidatorConverter; import org.openecomp.sdc.be.model.tosca.validators.PropertyTypeValidator; @@ -61,11 +85,6 @@ import org.openecomp.sdc.common.log.wrappers.Logger; import org.openecomp.sdc.exception.ResponseFormat; import org.springframework.beans.factory.annotation.Autowired; -import java.util.Arrays; -import java.util.List; -import java.util.Map; -import java.util.function.Function; - public abstract class BaseBusinessLogic { private static final String FAILED_TO_LOCK_COMPONENT_ERROR = "Failed to lock component {} error - {}"; @@ -374,7 +393,6 @@ public abstract class BaseBusinessLogic { ComponentTypeEnum getComponentTypeByParentComponentType(ComponentTypeEnum parentComponentType) { switch (parentComponentType) { case SERVICE: - return ComponentTypeEnum.RESOURCE; case RESOURCE: return ComponentTypeEnum.RESOURCE; case PRODUCT: @@ -666,8 +684,63 @@ public abstract class BaseBusinessLogic { return jsonElement.toString(); } - protected void rollbackWithException(ActionStatus actionStatus, String... params) { + void rollbackWithException(ActionStatus actionStatus, String... params) { titanDao.rollback(); throw new ComponentException(actionStatus, params); } + + public <T extends PropertyDataDefinition> List<PropertyConstraint> setInputConstraint(T inputDefinition) { + if (StringUtils.isNotBlank(inputDefinition.getParentPropertyType()) + && StringUtils.isNotBlank(inputDefinition.getSubPropertyInputPath())) { + return setConstraint(inputDefinition); + } + + return Collections.emptyList(); + } + + private <T extends PropertyDataDefinition> List<PropertyConstraint> setConstraint(T inputDefinition) { + List<PropertyConstraint> constraints = new ArrayList<>(); + String[] inputPathArr = inputDefinition.getSubPropertyInputPath().split("#"); + if (inputPathArr.length > 1) { + inputPathArr = ArrayUtils.remove(inputPathArr, 0); + } + + Map<String, DataTypeDefinition> dataTypeDefinitionMap = + applicationDataTypeCache.getAll().left().value(); + + String propertyType = inputDefinition.getParentPropertyType(); + + for (String anInputPathArr : inputPathArr) { + if (ToscaType.isPrimitiveType(propertyType)) { + constraints.addAll( + dataTypeDefinitionMap.get(propertyType).getConstraints()); + } else if (!ToscaType.isCollectionType(propertyType)) { + propertyType = setConstraintForComplexType(dataTypeDefinitionMap, propertyType, anInputPathArr, + constraints); + } + } + + return constraints; + } + + private String setConstraintForComplexType(Map<String, DataTypeDefinition> dataTypeDefinitionMap, + String propertyType, + String anInputPathArr, + List<PropertyConstraint> constraints) { + String type = null; + List<PropertyDefinition> propertyDefinitions = + dataTypeDefinitionMap.get(propertyType).getProperties(); + for (PropertyDefinition propertyDefinition : propertyDefinitions) { + if (propertyDefinition.getName().equals(anInputPathArr)) { + if (ToscaType.isPrimitiveType(propertyDefinition.getType())) { + constraints.addAll(propertyDefinition.getConstraints()); + } else { + type = propertyDefinition.getType(); + } + break; + } + } + + return type; + } } 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 6b17d1c8e9..acf28c2455 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 @@ -20,6 +20,13 @@ package org.openecomp.sdc.be.components.impl; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.stream.Collectors; + import fj.data.Either; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; @@ -34,9 +41,28 @@ import org.openecomp.sdc.be.dao.utils.MapUtil; import org.openecomp.sdc.be.datamodel.api.HighestFilterEnum; import org.openecomp.sdc.be.datatypes.components.ServiceMetadataDataDefinition; import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; -import org.openecomp.sdc.be.datatypes.enums.*; +import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.FilterKeyEnum; +import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum; +import org.openecomp.sdc.be.datatypes.enums.ResourceTypeEnum; import org.openecomp.sdc.be.datatypes.tosca.ToscaDataDefinition; -import org.openecomp.sdc.be.model.*; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.CapReqDef; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.ComponentInstanceInput; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; +import org.openecomp.sdc.be.model.ComponentParametersView; +import org.openecomp.sdc.be.model.DataTypeDefinition; +import org.openecomp.sdc.be.model.GroupDefinition; +import org.openecomp.sdc.be.model.IComponentInstanceConnectedElement; +import org.openecomp.sdc.be.model.InputDefinition; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Operation; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.User; import org.openecomp.sdc.be.model.cache.ComponentCache; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; @@ -54,13 +80,6 @@ import org.openecomp.sdc.common.util.ValidationUtils; import org.openecomp.sdc.exception.ResponseFormat; import org.springframework.beans.factory.annotation.Autowired; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.stream.Collectors; - public abstract class ComponentBusinessLogic extends BaseBusinessLogic { @Autowired @@ -72,6 +91,9 @@ public abstract class ComponentBusinessLogic extends BaseBusinessLogic { @Autowired private GenericTypeBusinessLogic genericTypeBusinessLogic; + @Autowired + private ComponentInstanceBusinessLogic componentInstanceBusinessLogic; + public void setGenericTypeBusinessLogic(GenericTypeBusinessLogic genericTypeBusinessLogic) { this.genericTypeBusinessLogic = genericTypeBusinessLogic; } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java index 1eb50e846a..0c6735f8c1 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ComponentInstanceBusinessLogic.java @@ -20,7 +20,26 @@ package org.openecomp.sdc.be.components.impl; +import static org.openecomp.sdc.be.components.property.GetInputUtils.isGetInputValueForInput; + import com.google.common.collect.Sets; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; +import java.util.function.BiConsumer; +import java.util.stream.Collectors; + import fj.data.Either; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; @@ -38,41 +57,43 @@ import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum; import org.openecomp.sdc.be.dao.neo4j.GraphPropertiesDictionary; import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; +import org.openecomp.sdc.be.datamodel.utils.PropertyValueConstraintValidationUtil; import org.openecomp.sdc.be.datatypes.elements.CINodeFilterDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.CapabilityDataDefinition; import org.openecomp.sdc.be.datatypes.elements.ForwardingPathDataDefinition; import org.openecomp.sdc.be.datatypes.elements.GetInputValueDataDefinition; import org.openecomp.sdc.be.datatypes.elements.GroupDataDefinition; +import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; import org.openecomp.sdc.be.datatypes.elements.RequirementDataDefinition; -import org.openecomp.sdc.be.datatypes.elements.CapabilityDataDefinition; import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition; -import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum; import org.openecomp.sdc.be.impl.ForwardingPathUtils; import org.openecomp.sdc.be.impl.ServiceFilterUtils; import org.openecomp.sdc.be.info.CreateAndAssotiateInfo; -import org.openecomp.sdc.be.model.Component; -import org.openecomp.sdc.be.model.ComponentParametersView; +import org.openecomp.sdc.be.model.ArtifactDefinition; import org.openecomp.sdc.be.model.CapabilityDefinition; -import org.openecomp.sdc.be.model.InterfaceDefinition; -import org.openecomp.sdc.be.model.RequirementDefinition; -import org.openecomp.sdc.be.model.Resource; -import org.openecomp.sdc.be.model.Service; -import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.ComponentInstanceInput; import org.openecomp.sdc.be.model.ComponentInstancePropInput; -import org.openecomp.sdc.be.model.LifecycleStateEnum; -import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; +import org.openecomp.sdc.be.model.ComponentParametersView; import org.openecomp.sdc.be.model.DataTypeDefinition; -import org.openecomp.sdc.be.model.PropertyDefinition; import org.openecomp.sdc.be.model.GroupDefinition; import org.openecomp.sdc.be.model.InputDefinition; +import org.openecomp.sdc.be.model.InterfaceDefinition; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.PropertyDefinition.PropertyNames; import org.openecomp.sdc.be.model.RelationshipInfo; import org.openecomp.sdc.be.model.RequirementCapabilityRelDef; -import org.openecomp.sdc.be.model.ComponentInstance; -import org.openecomp.sdc.be.model.ComponentInstanceInput; -import org.openecomp.sdc.be.model.ComponentInstanceProperty; -import org.openecomp.sdc.be.model.PropertyDefinition.PropertyNames; +import org.openecomp.sdc.be.model.RequirementDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache; import org.openecomp.sdc.be.model.jsontitan.operations.ForwardingPathOperation; import org.openecomp.sdc.be.model.jsontitan.operations.NodeFilterOperation; import org.openecomp.sdc.be.model.jsontitan.operations.ToscaOperationFacade; @@ -95,24 +116,6 @@ import org.openecomp.sdc.common.util.ValidationUtils; import org.openecomp.sdc.exception.ResponseFormat; import org.springframework.beans.factory.annotation.Autowired; -import java.util.Arrays; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Objects; -import java.util.Optional; -import java.util.Set; -import java.util.UUID; -import java.util.function.BiConsumer; -import java.util.stream.Collectors; - -import static org.openecomp.sdc.be.components.property.GetInputUtils.isGetInputValueForInput; - @org.springframework.stereotype.Component public class ComponentInstanceBusinessLogic extends BaseBusinessLogic { @@ -131,6 +134,9 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic { public static final String FAILED_TO_COPY_COMP_INSTANCE_TO_CANVAS = "Failed to copy the component instance to the canvas"; public static final String COPY_COMPONENT_INSTANCE_OK = "Copy component instance OK"; + @Autowired + private ApplicationDataTypeCache applicationDataTypeCache; + @Autowired private IComponentInstanceOperation componentInstanceOperation; @@ -1673,6 +1679,17 @@ public class ComponentInstanceBusinessLogic extends BaseBusinessLogic { resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESTRICTED_OPERATION)); return resultOp; } + + //Validate value and Constraint of property + Either<Boolean, ResponseFormat> constraintValidatorResponse = + PropertyValueConstraintValidationUtil.getInstance(). + validatePropertyConstraints(properties, applicationDataTypeCache); + if (constraintValidatorResponse.isRight()) { + log.error("Failed validation value and constraint of property: {}", + constraintValidatorResponse.right().value()); + return Either.right(constraintValidatorResponse.right().value()); + } + Either<ComponentInstance, StorageOperationStatus> resourceInstanceStatus = getResourceInstanceById(containerComponent, resourceInstanceId); if (resourceInstanceStatus.isRight()) { resultOp = Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_INSTANCE_NOT_FOUND_ON_SERVICE, resourceInstanceId, componentId)); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java index 357eb14ed0..f3b1b14652 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InputsBusinessLogic.java @@ -24,15 +24,20 @@ import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Map; +import java.util.Objects; import java.util.Optional; import java.util.stream.Collectors; import fj.data.Either; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.ListUtils; +import org.apache.commons.collections4.MapUtils; import org.openecomp.sdc.be.components.property.PropertyDeclarationOrchestrator; import org.openecomp.sdc.be.components.validation.ComponentValidations; import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; import org.openecomp.sdc.be.dao.utils.MapUtil; +import org.openecomp.sdc.be.datamodel.utils.PropertyValueConstraintValidationUtil; import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; import org.openecomp.sdc.be.datatypes.elements.SchemaDefinition; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; @@ -44,12 +49,15 @@ import org.openecomp.sdc.be.model.ComponentInstanceProperty; import org.openecomp.sdc.be.model.ComponentParametersView; import org.openecomp.sdc.be.model.DataTypeDefinition; import org.openecomp.sdc.be.model.InputDefinition; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache; import org.openecomp.sdc.be.model.operations.api.StorageOperationStatus; import org.openecomp.sdc.be.model.operations.impl.DaoStatusConverter; import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; import org.openecomp.sdc.be.model.tosca.converters.PropertyValueConverter; import org.openecomp.sdc.common.log.wrappers.Logger; import org.openecomp.sdc.exception.ResponseFormat; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import javax.inject.Inject; @@ -71,7 +79,6 @@ public class InputsBusinessLogic extends BaseBusinessLogic { private PropertyDeclarationOrchestrator propertyDeclarationOrchestrator; @Inject private ComponentInstanceBusinessLogic componentInstanceBusinessLogic; - /** * associate inputs to a given component with paging * @@ -124,7 +131,13 @@ public class InputsBusinessLogic extends BaseBusinessLogic { log.debug("Failed to found component instance inputs {}, error: {}", componentInstanceId, actionStatus); return Either.right(componentsUtils.getResponseFormat(actionStatus)); } - Map<String, List<ComponentInstanceInput>> ciInputs = Optional.ofNullable(component.getComponentInstancesInputs()).orElse(Collections.emptyMap()); + Map<String, List<ComponentInstanceInput>> ciInputs = + Optional.ofNullable(component.getComponentInstancesInputs()).orElse(Collections.emptyMap()); + + // Set Constraints on Input + MapUtils.emptyIfNull(ciInputs).values() + .forEach(inputs -> ListUtils.emptyIfNull(inputs) + .forEach(input -> input.setConstraints(setInputConstraint(input)))); return Either.left(ciInputs.getOrDefault(componentInstanceId, Collections.emptyList())); } @@ -140,7 +153,7 @@ public class InputsBusinessLogic extends BaseBusinessLogic { public Either<List<ComponentInstanceProperty>, ResponseFormat> getComponentInstancePropertiesByInputId(String userId, String componentId, String instanceId, String inputId) { validateUserExists(userId, GET_PROPERTIES_BY_INPUT, false); String parentId = componentId; - org.openecomp.sdc.be.model.Component component = null; + org.openecomp.sdc.be.model.Component component; ComponentParametersView filters = new ComponentParametersView(); filters.disableAll(); filters.setIgnoreComponentInstances(false); @@ -246,6 +259,9 @@ public class InputsBusinessLogic extends BaseBusinessLogic { componentParametersView.disableAll(); componentParametersView.setIgnoreInputs(false); componentParametersView.setIgnoreUsers(false); + componentParametersView.setIgnoreProperties(false); + componentParametersView.setIgnoreComponentInstancesProperties(false); + componentParametersView.setIgnoreComponentInstances(false); Either<? extends org.openecomp.sdc.be.model.Component, ResponseFormat> validateComponent = validateComponentExists(componentId, componentType, componentParametersView); @@ -269,6 +285,14 @@ public class InputsBusinessLogic extends BaseBusinessLogic { return result; } + //Validate value and Constraint of input + Either<Boolean, ResponseFormat> constraintValidatorResponse = validateInputValueConstraint(component, inputs); + if (constraintValidatorResponse.isRight()) { + log.error("Failed validation value and constraint of property: {}", + constraintValidatorResponse.right().value()); + return Either.right(constraintValidatorResponse.right().value()); + } + Either<Map<String, DataTypeDefinition>, ResponseFormat> allDataTypes = getAllDataTypes(applicationDataTypeCache); if (allDataTypes.isRight()) { result = Either.right(allDataTypes.right().value()); @@ -321,6 +345,29 @@ public class InputsBusinessLogic extends BaseBusinessLogic { } } + private Either<Boolean, ResponseFormat> validateInputValueConstraint( + org.openecomp.sdc.be.model.Component component, List<InputDefinition> inputs) { + PropertyValueConstraintValidationUtil propertyValueConstraintValidationUtil = + PropertyValueConstraintValidationUtil.getInstance(); + List<InputDefinition> inputDefinitions = new ArrayList<>(); + for (InputDefinition inputDefinition : inputs) { + InputDefinition inputDef = new InputDefinition(); + inputDefinition.setDefaultValue(inputDefinition.getDefaultValue()); + inputDefinition.setInputPath(inputDefinition.getSubPropertyInputPath()); + inputDefinition.setType(inputDefinition.getType()); + if (Objects.nonNull(inputDefinition.getParentPropertyType())) { + ComponentInstanceProperty propertyDefinition = new ComponentInstanceProperty(); + propertyDefinition.setType(inputDefinition.getParentPropertyType()); + + inputDefinition.setProperties(Collections.singletonList(propertyDefinition)); + } + + inputDefinitions.add(inputDef); + } + + return propertyValueConstraintValidationUtil.validatePropertyConstraints(inputDefinitions, applicationDataTypeCache); + } + public Either<List<ComponentInstanceInput>, ResponseFormat> getInputsForComponentInput(String userId, String componentId, String inputId) { validateUserExists(userId, GET_PROPERTIES_BY_INPUT, false); org.openecomp.sdc.be.model.Component component = null; @@ -396,7 +443,7 @@ public class InputsBusinessLogic extends BaseBusinessLogic { .left() .bind(inputsToCreate -> prepareInputsForCreation(userId, componentId, inputsToCreate)) .right() - .map(err -> componentsUtils.getResponseFormat(err)); + .map(componentsUtils::getResponseFormat); return result; @@ -422,6 +469,9 @@ public class InputsBusinessLogic extends BaseBusinessLogic { private Either<List<InputDefinition>, StorageOperationStatus> prepareInputsForCreation(String userId, String cmptId, List<InputDefinition> inputsToCreate) { Map<String, InputDefinition> inputsToPersist = MapUtil.toMap(inputsToCreate, InputDefinition::getName); assignOwnerIdToInputs(userId, inputsToPersist); + inputsToPersist.values() + .forEach(input -> input.setConstraints(componentInstanceBusinessLogic.setInputConstraint(input))); + return toscaOperationFacade.addInputsToComponent(inputsToPersist, cmptId) .left() .map(persistedInputs -> inputsToCreate); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InterfaceOperationBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InterfaceOperationBusinessLogic.java index 7f19e824e5..de2839f653 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InterfaceOperationBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/InterfaceOperationBusinessLogic.java @@ -450,6 +450,8 @@ public class InterfaceOperationBusinessLogic extends BaseBusinessLogic { operationInput.setToscaDefaultValue(getInputToscaDefaultValue(operationInput, component)); operationInput.setValue(componentInput.getValue()); operationInput.setSchema(componentInput.getSchema()); + operationInput.setParentPropertyType(componentInput.getParentPropertyType()); + operationInput.setSubPropertyInputPath(componentInput.getSubPropertyInputPath()); } //Set the tosca default value for inputs mapped to component inputs as well as other outputs operationInput.setToscaDefaultValue(getInputToscaDefaultValue(operationInput, component)); @@ -460,6 +462,7 @@ public class InterfaceOperationBusinessLogic extends BaseBusinessLogic { Map<String, List<String>> defaultInputValue; if (isOperationInputMappedToComponentInput(input, component.getInputs())) { String propertyName = input.getInputId().substring(input.getInputId().indexOf('.') + 1); + setParentPropertyTypeAndInputPath(input, component); defaultInputValue = createMappedInputPropertyDefaultValue(propertyName); } else { //Currently inputs can only be mapped to a declared input or an other operation outputs @@ -468,6 +471,24 @@ public class InterfaceOperationBusinessLogic extends BaseBusinessLogic { return new Gson().toJson(defaultInputValue); } + private void setParentPropertyTypeAndInputPath(OperationInputDefinition input, + org.openecomp.sdc.be.model.Component component) { + if (CollectionUtils.isEmpty(component.getInputs())) { + return; + } + + component.getInputs() + .stream() + .filter(inp -> inp.getUniqueId().equals( + input.getInputId().substring(0, input.getInputId().lastIndexOf('.')))) + .forEach(inp -> { + input.setParentPropertyType(inp.getParentPropertyType()); + if (Objects.nonNull(input.getName())) { + input.setSubPropertyInputPath(input.getName().replaceAll("\\.", "#")); + } + }); + } + private void addOperationToInterface(InterfaceDefinition interfaceDefinition, Operation interfaceOperation) { interfaceOperation.setUniqueId(UUID.randomUUID().toString()); interfaceOperation.setImplementation(createArtifactDefinition(UUID.randomUUID().toString())); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceBusinessLogic.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceBusinessLogic.java index 92d26a4eb8..53ed2a4306 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceBusinessLogic.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/impl/ResourceBusinessLogic.java @@ -8,7 +8,7 @@ * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * - * http://www.apache.org/licenses/LICENSE-2.0 + * http://www.apache.org/licenses/LICENSE-2.0getUiComponentDataTransferByComponentId * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, @@ -21,10 +21,37 @@ package org.openecomp.sdc.be.components.impl; +import static java.util.stream.Collectors.joining; +import static java.util.stream.Collectors.toList; +import static java.util.stream.Collectors.toMap; +import static java.util.stream.Collectors.toSet; +import static org.apache.commons.collections.CollectionUtils.isNotEmpty; +import static org.apache.commons.collections.MapUtils.isEmpty; +import static org.apache.commons.collections.MapUtils.isNotEmpty; +import static org.openecomp.sdc.be.components.impl.ImportUtils.findFirstToscaStringElement; +import static org.openecomp.sdc.be.components.impl.ImportUtils.getPropertyJsonStringValue; +import static org.openecomp.sdc.be.tosca.CsarUtils.VF_NODE_TYPE_ARTIFACTS_PATH_PATTERN; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.ListIterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; +import java.util.Set; +import java.util.function.Function; +import java.util.regex.Pattern; + import fj.data.Either; import org.apache.commons.codec.binary.Base64; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; +import org.apache.commons.collections4.ListUtils; import org.apache.commons.lang.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.openecomp.sdc.be.components.csar.CsarArtifactsAndGroupsBusinessLogic; @@ -53,6 +80,7 @@ import org.openecomp.sdc.be.datatypes.elements.CapabilityDataDefinition; import org.openecomp.sdc.be.datatypes.elements.GetInputValueDataDefinition; import org.openecomp.sdc.be.datatypes.elements.PropertyDataDefinition; import org.openecomp.sdc.be.datatypes.elements.RequirementDataDefinition; +import org.openecomp.sdc.be.datatypes.enums.ComponentFieldsEnum; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.datatypes.enums.CreatedFrom; import org.openecomp.sdc.be.datatypes.enums.NodeTypeEnum; @@ -130,31 +158,6 @@ import org.yaml.snakeyaml.DumperOptions; import org.yaml.snakeyaml.Yaml; import javax.servlet.ServletContext; -import java.util.ArrayList; -import java.util.Collection; -import java.util.EnumMap; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.ListIterator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Optional; -import java.util.Set; -import java.util.function.Function; -import java.util.regex.Pattern; - -import static java.util.stream.Collectors.joining; -import static java.util.stream.Collectors.toList; -import static java.util.stream.Collectors.toMap; -import static java.util.stream.Collectors.toSet; -import static org.apache.commons.collections.CollectionUtils.isNotEmpty; -import static org.apache.commons.collections.MapUtils.isEmpty; -import static org.apache.commons.collections.MapUtils.isNotEmpty; -import static org.openecomp.sdc.be.components.impl.ImportUtils.findFirstToscaStringElement; -import static org.openecomp.sdc.be.components.impl.ImportUtils.getPropertyJsonStringValue; -import static org.openecomp.sdc.be.tosca.CsarUtils.VF_NODE_TYPE_ARTIFACTS_PATH_PATTERN; @org.springframework.stereotype.Component("resourceBusinessLogic") public class ResourceBusinessLogic extends ComponentBusinessLogic { @@ -5207,28 +5210,36 @@ public class ResourceBusinessLogic extends ComponentBusinessLogic { } @Override - public Either<UiComponentDataTransfer, ResponseFormat> getUiComponentDataTransferByComponentId(String resourceId, List<String> dataParamsToReturn) { - - ComponentParametersView paramsToRetuen = new ComponentParametersView(dataParamsToReturn); - Either<Resource, StorageOperationStatus> resourceResultEither = toscaOperationFacade.getToscaElement(resourceId, - paramsToRetuen); - - if (resourceResultEither.isRight()) { - if (resourceResultEither.right().value().equals(StorageOperationStatus.NOT_FOUND)) { - log.debug("Failed to found resource with id {} ", resourceId); - Either.right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, resourceId)); - } - - log.debug("failed to get resource by id {} with filters {}", resourceId, dataParamsToReturn); - return Either.right(componentsUtils.getResponseFormatByResource( - componentsUtils.convertFromStorageResponse(resourceResultEither.right().value()), "")); - } - - Resource resource = resourceResultEither.left().value(); - UiComponentDataTransfer dataTransfer = uiComponentDataConverter.getUiDataTransferFromResourceByParams(resource, - dataParamsToReturn); - return Either.left(dataTransfer); - } + public Either<UiComponentDataTransfer, ResponseFormat> getUiComponentDataTransferByComponentId(String resourceId, + List<String> dataParamsToReturn) { + + ComponentParametersView paramsToRetuen = new ComponentParametersView(dataParamsToReturn); + Either<Resource, StorageOperationStatus> resourceResultEither = + toscaOperationFacade.getToscaElement(resourceId, + paramsToRetuen); + + if (resourceResultEither.isRight()) { + if (resourceResultEither.right().value().equals(StorageOperationStatus.NOT_FOUND)) { + log.debug("Failed to found resource with id {} ", resourceId); + Either + .right(componentsUtils.getResponseFormat(ActionStatus.RESOURCE_NOT_FOUND, resourceId)); + } + + log.debug("failed to get resource by id {} with filters {}", resourceId, dataParamsToReturn); + return Either.right(componentsUtils.getResponseFormatByResource( + componentsUtils.convertFromStorageResponse(resourceResultEither.right().value()), "")); + } + + Resource resource = resourceResultEither.left().value(); + if (dataParamsToReturn.contains(ComponentFieldsEnum.INPUTS.getValue())) { + ListUtils.emptyIfNull(resource.getInputs()) + .forEach(input -> input.setConstraints(setInputConstraint(input))); + } + + UiComponentDataTransfer dataTransfer = uiComponentDataConverter.getUiDataTransferFromResourceByParams(resource, + dataParamsToReturn); + return Either.left(dataTransfer); + } @Override public Either<Component, ActionStatus> shouldUpgradeToLatestDerived(Component clonedComponent) { 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 ba3b8dfc45..364b007ce3 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 @@ -20,13 +20,39 @@ package org.openecomp.sdc.be.components.impl; +import static org.apache.commons.collections.CollectionUtils.isEmpty; +import static org.apache.commons.collections.CollectionUtils.isNotEmpty; +import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.getOperationOutputName; +import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.isOperationInputMappedToOtherOperationOutput; +import static org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum.UPDATE_SERVICE_METADATA; +import static org.openecomp.sdc.be.tosca.utils.InterfacesOperationsToscaUtil.SELF; +import static org.openecomp.sdc.be.types.ServiceConsumptionSource.SERVICE_INPUT; +import static org.openecomp.sdc.be.types.ServiceConsumptionSource.STATIC; + import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Strings; import com.google.gson.Gson; import com.google.gson.GsonBuilder; + +import java.nio.charset.StandardCharsets; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Optional; +import java.util.Set; +import java.util.concurrent.Callable; +import java.util.function.Function; +import java.util.stream.Collectors; + import fj.data.Either; import org.apache.commons.collections.CollectionUtils; import org.apache.commons.collections.MapUtils; +import org.apache.commons.collections4.ListUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.ImmutablePair; import org.openecomp.sdc.be.components.distribution.engine.IDistributionEngine; @@ -46,6 +72,7 @@ import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.dao.cassandra.AuditCassandraDao; import org.openecomp.sdc.be.dao.jsongraph.types.JsonParseFlagEnum; import org.openecomp.sdc.be.datamodel.ServiceRelations; +import org.openecomp.sdc.be.datamodel.utils.PropertyValueConstraintValidationUtil; import org.openecomp.sdc.be.datamodel.utils.UiComponentDataConverter; import org.openecomp.sdc.be.datatypes.elements.CINodeFilterDataDefinition; import org.openecomp.sdc.be.datatypes.elements.ForwardingPathDataDefinition; @@ -54,6 +81,7 @@ 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.RequirementNodeFilterPropertyDataDefinition; +import org.openecomp.sdc.be.datatypes.enums.ComponentFieldsEnum; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.datatypes.enums.InstantiationTypes; import org.openecomp.sdc.be.datatypes.enums.JsonPresentationFields; @@ -62,7 +90,24 @@ import org.openecomp.sdc.be.datatypes.enums.OriginTypeEnum; import org.openecomp.sdc.be.externalapi.servlet.representation.ServiceDistributionReqInfo; import org.openecomp.sdc.be.impl.ForwardingPathUtils; import org.openecomp.sdc.be.impl.WebAppContextWrapper; -import org.openecomp.sdc.be.model.*; +import org.openecomp.sdc.be.model.ArtifactDefinition; +import org.openecomp.sdc.be.model.Component; +import org.openecomp.sdc.be.model.ComponentInstance; +import org.openecomp.sdc.be.model.ComponentInstanceInterface; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; +import org.openecomp.sdc.be.model.ComponentParametersView; +import org.openecomp.sdc.be.model.DistributionStatusEnum; +import org.openecomp.sdc.be.model.DistributionTransitionEnum; +import org.openecomp.sdc.be.model.GroupInstance; +import org.openecomp.sdc.be.model.GroupInstanceProperty; +import org.openecomp.sdc.be.model.InputDefinition; +import org.openecomp.sdc.be.model.InterfaceDefinition; +import org.openecomp.sdc.be.model.LifecycleStateEnum; +import org.openecomp.sdc.be.model.Operation; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.Resource; +import org.openecomp.sdc.be.model.Service; +import org.openecomp.sdc.be.model.User; import org.openecomp.sdc.be.model.category.CategoryDefinition; import org.openecomp.sdc.be.model.jsontitan.operations.ForwardingPathOperation; import org.openecomp.sdc.be.model.jsontitan.operations.NodeFilterOperation; @@ -77,7 +122,11 @@ import org.openecomp.sdc.be.model.tosca.ToscaPropertyType; import org.openecomp.sdc.be.model.tosca.validators.PropertyTypeValidator; import org.openecomp.sdc.be.resources.data.ComponentInstanceData; import org.openecomp.sdc.be.resources.data.ComponentMetadataData; -import org.openecomp.sdc.be.resources.data.auditing.*; +import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; +import org.openecomp.sdc.be.resources.data.auditing.AuditingGenericEvent; +import org.openecomp.sdc.be.resources.data.auditing.DistributionDeployEvent; +import org.openecomp.sdc.be.resources.data.auditing.DistributionNotificationEvent; +import org.openecomp.sdc.be.resources.data.auditing.ResourceAdminEvent; import org.openecomp.sdc.be.resources.data.auditing.model.ResourceCommonInfo; import org.openecomp.sdc.be.resources.data.auditing.model.ResourceVersionInfo; import org.openecomp.sdc.be.types.ServiceConsumptionData; @@ -100,20 +149,6 @@ import org.springframework.web.context.WebApplicationContext; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; -import java.nio.charset.StandardCharsets; -import java.util.*; -import java.util.concurrent.Callable; -import java.util.function.Function; -import java.util.stream.Collectors; - -import static org.apache.commons.collections.CollectionUtils.isEmpty; -import static org.apache.commons.collections.CollectionUtils.isNotEmpty; -import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.getOperationOutputName; -import static org.openecomp.sdc.be.components.utils.InterfaceOperationUtils.isOperationInputMappedToOtherOperationOutput; -import static org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum.UPDATE_SERVICE_METADATA; -import static org.openecomp.sdc.be.tosca.utils.InterfacesOperationsToscaUtil.SELF; -import static org.openecomp.sdc.be.types.ServiceConsumptionSource.SERVICE_INPUT; -import static org.openecomp.sdc.be.types.ServiceConsumptionSource.STATIC; @org.springframework.stereotype.Component("serviceBusinessLogic") public class ServiceBusinessLogic extends ComponentBusinessLogic { @@ -365,7 +400,6 @@ public class ServiceBusinessLogic extends ComponentBusinessLogic { } OperationInputDefinition operationInputDefinition = inputCandidate.get(); - // add data to operation if(Objects.nonNull(serviceConsumptionData.getValue())) { @@ -441,6 +475,14 @@ public class ServiceBusinessLogic extends ComponentBusinessLogic { ServiceConsumptionSource sourceValue = ServiceConsumptionSource.getSourceValue(source); if(STATIC.equals(sourceValue)) { + // Validate constraint on input value + /*Either<Boolean, ResponseFormat> constraintValidationResult = + validateOperationInputConstraint(operationInputDefinition, serviceConsumptionData); + + if (constraintValidationResult.isRight()) { + return Either.right(constraintValidationResult.right().value()); + }*/ + return handleConsumptionStaticValue(consumptionValue, type, operation, operationInputDefinition); } @@ -612,12 +654,37 @@ public class ServiceBusinessLogic extends ComponentBusinessLogic { return Either.right(componentsUtils.getResponseFormat( ActionStatus.INVALID_CONSUMPTION_TYPE, type)); } + + //Validate Constraint and Value + Either<Boolean, ResponseFormat> constraintValidationResponse = + validateOperationInputConstraint(operationInputDefinition, value, type); + if(constraintValidationResponse.isRight()) { + return Either.right(constraintValidationResponse.right().value()); + } + addStaticValueToInputOperation(value, operation, operationInputDefinition); return Either.left(operation); } - private void addStaticValueToInputOperation(String value, Operation operation, + private Either<Boolean, ResponseFormat> validateOperationInputConstraint( + OperationInputDefinition operationInputDefinition, String value, String type) { + ComponentInstanceProperty propertyDefinition = new ComponentInstanceProperty(); + propertyDefinition.setType(operationInputDefinition.getParentPropertyType()); + + InputDefinition inputDefinition = new InputDefinition(); + inputDefinition.setDefaultValue(value); + inputDefinition.setInputPath(operationInputDefinition.getSubPropertyInputPath()); + inputDefinition.setType(type); + if (Objects.nonNull(operationInputDefinition.getParentPropertyType())) { + inputDefinition.setProperties(Collections.singletonList(propertyDefinition)); + } + + return PropertyValueConstraintValidationUtil.getInstance() + .validatePropertyConstraints(Collections.singletonList(inputDefinition), applicationDataTypeCache); + } + + private void addStaticValueToInputOperation(String value, Operation operation, OperationInputDefinition operationInputDefinition) { operation.getInputs().delete(operationInputDefinition); operationInputDefinition.setSource(STATIC.getSource()); @@ -2571,6 +2638,11 @@ public class ServiceBusinessLogic extends ComponentBusinessLogic { } Service service = serviceResultEither.left().value(); + if (dataParamsToReturn.contains(ComponentFieldsEnum.INPUTS.getValue())) { + ListUtils.emptyIfNull(service.getInputs()) + .forEach(input -> input.setConstraints(setInputConstraint(input))); + } + UiComponentDataTransfer dataTransfer = uiComponentDataConverter.getUiDataTransferFromServiceByParams(service, dataParamsToReturn); return Either.left(dataTransfer); } diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/DefaultPropertyDeclarator.java b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/DefaultPropertyDeclarator.java index bd7a58c48a..0f76210a1a 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/DefaultPropertyDeclarator.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/components/property/DefaultPropertyDeclarator.java @@ -156,6 +156,14 @@ public abstract class DefaultPropertyDeclarator<PROPERTYOWNER extends Properties input.setInputPath(propertiesName); input.setInstanceUniqueId(propertiesOwner.getUniqueId()); input.setPropertyId(propInput.getUniqueId()); + if (Objects.isNull(input.getSubPropertyInputPath()) + || (Objects.nonNull(propertiesName) + && input.getSubPropertyInputPath().substring(input.getSubPropertyInputPath().lastIndexOf('#')) + .equals(propertiesName.substring(propertiesName.lastIndexOf('#'))))) { + input.setParentPropertyType(propInput.getType()); + input.setSubPropertyInputPath(propertiesName); + } + changePropertyValueToGetInputValue(inputName, parsedPropNames, input, prop, complexProperty); if(prop instanceof IComponentInstanceConnectedElement) { @@ -169,7 +177,7 @@ public abstract class DefaultPropertyDeclarator<PROPERTYOWNER extends Properties private void changePropertyValueToGetInputValue(String inputName, String[] parsedPropNames, InputDefinition input, PropertyDataDefinition prop, boolean complexProperty) { JSONObject jobject = new JSONObject(); - String value = (String) prop.getValue(); + String value = prop.getValue(); if(value == null || value.isEmpty()){ if(complexProperty){ @@ -185,7 +193,6 @@ public abstract class DefaultPropertyDeclarator<PROPERTYOWNER extends Properties }else{ - //String value = value; Object objValue = new Yaml().load(value); if( objValue instanceof Map || objValue instanceof List){ if(!complexProperty){ diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/utils/PropertyValueConstraintValidationUtil.java b/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/utils/PropertyValueConstraintValidationUtil.java new file mode 100644 index 0000000000..f2cdcc3a6d --- /dev/null +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/datamodel/utils/PropertyValueConstraintValidationUtil.java @@ -0,0 +1,374 @@ +/* + * Copyright © 2016-2018 European Support Limited + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.openecomp.sdc.be.datamodel.utils; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import fj.data.Either; +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.collections4.ListUtils; +import org.apache.commons.collections4.MapUtils; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; +import org.codehaus.jackson.map.ObjectMapper; +import org.codehaus.jackson.type.TypeReference; +import org.openecomp.sdc.be.components.impl.ResponseFormatManager; +import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.model.DataTypeDefinition; +import org.openecomp.sdc.be.model.InputDefinition; +import org.openecomp.sdc.be.model.PropertyConstraint; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache; +import org.openecomp.sdc.be.model.tosca.ToscaType; +import org.openecomp.sdc.be.model.tosca.constraints.ConstraintUtil; +import org.openecomp.sdc.be.model.tosca.constraints.ValidValuesConstraint; +import org.openecomp.sdc.be.model.tosca.constraints.exception.ConstraintValueDoNotMatchPropertyTypeException; +import org.openecomp.sdc.be.model.tosca.constraints.exception.ConstraintViolationException; +import org.openecomp.sdc.exception.ResponseFormat; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class PropertyValueConstraintValidationUtil { + + private static final String UNDERSCORE = "_"; + private static final String VALUE_PROVIDED_IN_INVALID_FORMAT_FOR_PROPERTY = + "%nValue provided in invalid format for %s property"; + private Map<String, DataTypeDefinition> dataTypeDefinitionCache; + private static final Logger logger = LoggerFactory.getLogger(PropertyValueConstraintValidationUtil.class); + private ObjectMapper objectMapper = new ObjectMapper(); + private List<String> errorMessages = new ArrayList<>(); + private StringBuilder completePropertyName; + private String completeInputName; + private static final String IGNORE_PROPERTY_VALUE_START_WITH = "{\"get_input\":"; + + public static PropertyValueConstraintValidationUtil getInstance() { + return new PropertyValueConstraintValidationUtil(); + } + + public Either<Boolean, ResponseFormat> validatePropertyConstraints( + Collection<? extends PropertyDefinition> propertyDefinitionList, + ApplicationDataTypeCache applicationDataTypeCache) { + ResponseFormatManager responseFormatManager = getResponseFormatManager(); + dataTypeDefinitionCache = applicationDataTypeCache.getAll().left().value(); + CollectionUtils.emptyIfNull(propertyDefinitionList).stream() + .filter(this::isValuePresent) + .forEach(this::evaluatePropertyTypeForConstraintValidation); + + if (CollectionUtils.isNotEmpty(errorMessages)) { + logger.error("Properties with Invalid Data:", errorMessages); + ResponseFormat inputResponse = responseFormatManager.getResponseFormat(ActionStatus + .INVALID_PROPERTY_VALUES, String.join(",", errorMessages)); + return Either.right(inputResponse); + } + + return Either.left(Boolean.TRUE); + } + + private boolean isValuePresent(PropertyDefinition propertyDefinition) { + if (propertyDefinition instanceof InputDefinition) { + return StringUtils.isNotEmpty(propertyDefinition.getDefaultValue()); + } + + return StringUtils.isNotEmpty(propertyDefinition.getValue()); + } + + private void evaluatePropertyTypeForConstraintValidation(PropertyDefinition propertyDefinition) { + if (Objects.nonNull(propertyDefinition.getType()) + && dataTypeDefinitionCache.containsKey(propertyDefinition.getType())) { + + completeInputName = ""; + completePropertyName = new StringBuilder(); + if (propertyDefinition instanceof InputDefinition) { + completeInputName = propertyDefinition.getName(); + propertyDefinition = getPropertyDefinitionObjectFromInputs(propertyDefinition); + } + + if (Objects.nonNull(propertyDefinition)) { + if (ToscaType.isPrimitiveType(propertyDefinition.getType())) { + propertyDefinition.setConstraints( + org.openecomp.sdc.be.dao.utils.CollectionUtils.merge(propertyDefinition.getConstraints(), + dataTypeDefinitionCache.get(propertyDefinition.getType()).getConstraints())); + evaluateConstraintsOnProperty(propertyDefinition); + } else if (ToscaType.isCollectionType(propertyDefinition.getType())) { + propertyDefinition.setConstraints( + org.openecomp.sdc.be.dao.utils.CollectionUtils.merge(propertyDefinition.getConstraints(), + dataTypeDefinitionCache.get(propertyDefinition.getType()).getConstraints())); + evaluateConstraintsOnProperty(propertyDefinition); + evaluateCollectionTypeProperties(propertyDefinition); + } else { + setCompletePropertyName(propertyDefinition); + evaluateComplexTypeProperties(propertyDefinition); + } + } + } else { + errorMessages.add("\nUnsupported datatype found for property " + getCompletePropertyName(propertyDefinition)); + } + } + + private void setCompletePropertyName(PropertyDefinition propertyDefinition) { + if(StringUtils.isNotBlank(propertyDefinition.getUniqueId())) { + completePropertyName.append( + propertyDefinition.getUniqueId().substring(propertyDefinition.getUniqueId().lastIndexOf('.') + 1)); + } + } + + private void evaluateConstraintsOnProperty(PropertyDefinition propertyDefinition) { + ToscaType toscaType = ToscaType.isValidType(propertyDefinition.getType()); + if (isPropertyNotMappedAsInput(propertyDefinition) + && CollectionUtils.isNotEmpty(propertyDefinition.getConstraints()) + && isValidValueConstraintPresent(propertyDefinition.getConstraints())) { + for (PropertyConstraint propertyConstraint : propertyDefinition.getConstraints()) { + try { + propertyConstraint.initialize(toscaType); + propertyConstraint.validate(toscaType, propertyDefinition.getValue()); + } catch (ConstraintValueDoNotMatchPropertyTypeException | ConstraintViolationException exception) { + errorMessages.add("\n" + propertyConstraint.getErrorMessage( + toscaType, exception, getCompletePropertyName(propertyDefinition))); + } + } + } else if (isPropertyNotMappedAsInput(propertyDefinition) + && ToscaType.isPrimitiveType(propertyDefinition.getType()) + && !toscaType.isValidValue(propertyDefinition.getValue())) { + errorMessages.add(String.format("\nUnsupported value provided for %s property supported value " + + "type is %s.", getCompletePropertyName(propertyDefinition), toscaType.getType())); + } + } + + private boolean isPropertyNotMappedAsInput(PropertyDefinition propertyDefinition) { + return !propertyDefinition.getValue().startsWith(IGNORE_PROPERTY_VALUE_START_WITH); + } + + private void checkAndEvaluatePrimitiveProperty(PropertyDefinition propertyDefinition, + DataTypeDefinition dataTypeDefinition) { + if (ToscaType.isPrimitiveType(dataTypeDefinition.getName()) + && CollectionUtils.isNotEmpty(dataTypeDefinition.getConstraints())) { + + PropertyDefinition definition = new PropertyDefinition(); + definition.setValue(propertyDefinition.getValue()); + definition.setType(dataTypeDefinition.getName()); + definition.setConstraints(dataTypeDefinition.getConstraints()); + + evaluateConstraintsOnProperty(propertyDefinition); + } + } + + private void evaluateComplexTypeProperties(PropertyDefinition propertyDefinition) { + List<PropertyDefinition> propertyDefinitions = + dataTypeDefinitionCache.get(propertyDefinition.getType()).getProperties(); + try { + Map<String, Object> valueMap = + MapUtils.emptyIfNull(ConstraintUtil.parseToCollection(propertyDefinition.getValue(), + new TypeReference<Map<String, Object>>() {})); + + if (CollectionUtils.isEmpty(propertyDefinitions)) { + checkAndEvaluatePrimitiveProperty(propertyDefinition, + dataTypeDefinitionCache.get(propertyDefinition.getType())); + } else { + ListUtils.emptyIfNull(propertyDefinitions) + .forEach(prop -> evaluateRegularComplexType(propertyDefinition, prop, valueMap)); + } + } catch (ConstraintValueDoNotMatchPropertyTypeException e) { + logger.debug(e.getMessage(), e); + errorMessages.add(String.format(VALUE_PROVIDED_IN_INVALID_FORMAT_FOR_PROPERTY, + getCompletePropertyName(propertyDefinition))); + } + } + + private void evaluateRegularComplexType(PropertyDefinition propertyDefinition, + PropertyDefinition prop, + Map<String, Object> valueMap) { + try { + if (valueMap.containsKey(prop.getName())) { + if (ToscaType.isPrimitiveType(prop.getType())) { + evaluateConstraintsOnProperty(createPropertyDefinition(prop, + String.valueOf(valueMap.get(prop.getName())))); + } else if (ToscaType.isCollectionType(prop.getType())) { + + evaluateCollectionTypeProperties(createPropertyDefinition(prop, + objectMapper.writeValueAsString(valueMap.get(prop.getName())))); + } else { + completePropertyName.append(UNDERSCORE); + completePropertyName.append(prop.getName()); + evaluateComplexTypeProperties( + createPropertyDefinition(prop, objectMapper.writeValueAsString( + valueMap.get(prop.getName())))); + } + } + } catch (IOException e) { + logger.error(e.getMessage(), e); + errorMessages.add(String.format(VALUE_PROVIDED_IN_INVALID_FORMAT_FOR_PROPERTY, + getCompletePropertyName(propertyDefinition))); + } + } + + private void evaluateCollectionTypeProperties(PropertyDefinition propertyDefinition) { + ToscaType toscaPropertyType = ToscaType.isValidType(propertyDefinition.getType()); + if (ToscaType.LIST == toscaPropertyType) { + evaluateListType(propertyDefinition); + } else if (ToscaType.MAP == toscaPropertyType) { + evaluateMapType(propertyDefinition); + } + } + + private void evaluateListType(PropertyDefinition propertyDefinition) { + try { + String schemaType = propertyDefinition.getSchemaType(); + List list = ConstraintUtil.parseToCollection(propertyDefinition.getValue(), + new TypeReference<List<Object>>() {}); + evaluateCollectionType(propertyDefinition, list, schemaType); + } catch (ConstraintValueDoNotMatchPropertyTypeException e) { + logger.debug(e.getMessage(), e); + errorMessages.add(String.format(VALUE_PROVIDED_IN_INVALID_FORMAT_FOR_PROPERTY, + getCompletePropertyName(propertyDefinition))); + } + } + + private void evaluateMapType(PropertyDefinition propertyDefinition) { + try { + String schemaType = propertyDefinition.getSchemaType(); + Map map = ConstraintUtil.parseToCollection(propertyDefinition.getValue(), + new TypeReference<Map<String, Object>>() { + }); + evaluateCollectionType(propertyDefinition, map.values(), schemaType); + } catch (ConstraintValueDoNotMatchPropertyTypeException e) { + logger.debug(e.getMessage(), e); + errorMessages.add(String.format(VALUE_PROVIDED_IN_INVALID_FORMAT_FOR_PROPERTY, + getCompletePropertyName(propertyDefinition))); + } + } + + private void evaluateCollectionPrimitiveSchemaType(PropertyDefinition propertyDefinition, + Object value, + String schemaType) { + if (Objects.nonNull(propertyDefinition.getSchema()) + && propertyDefinition.getSchema().getProperty() instanceof PropertyDefinition) { + propertyDefinition.setConstraints(((PropertyDefinition) propertyDefinition.getSchema() + .getProperty()).getConstraints()); + propertyDefinition.setValue(String.valueOf(value)); + propertyDefinition.setType(schemaType); + evaluateConstraintsOnProperty(propertyDefinition); + } + } + private void evaluateCollectionType(PropertyDefinition propertyDefinition, + Collection valueList, + String schemaType) { + for (Object value : valueList) { + try { + if (ToscaType.isPrimitiveType(schemaType)) { + evaluateCollectionPrimitiveSchemaType(propertyDefinition, value, schemaType); + } else if (ToscaType.isCollectionType(schemaType)) { + propertyDefinition.setValue(objectMapper.writeValueAsString(value)); + propertyDefinition.setType(schemaType); + evaluateCollectionTypeProperties(propertyDefinition); + } else { + propertyDefinition.setValue(objectMapper.writeValueAsString(value)); + propertyDefinition.setType(schemaType); + completePropertyName.append(UNDERSCORE); + completePropertyName.append(propertyDefinition.getName()); + evaluateComplexTypeProperties(propertyDefinition); + } + } catch (IOException e) { + logger.debug(e.getMessage(), e); + errorMessages.add(String.format(VALUE_PROVIDED_IN_INVALID_FORMAT_FOR_PROPERTY, + getCompletePropertyName(propertyDefinition))); + } + } + } + + private String getCompletePropertyName(PropertyDefinition propertyDefinition) { + return StringUtils.isNotBlank(completeInputName) ? completeInputName : + StringUtils.isBlank(completePropertyName) ? + propertyDefinition.getName() : completePropertyName + UNDERSCORE + propertyDefinition.getName(); + } + + private PropertyDefinition createPropertyDefinition(PropertyDefinition prop, String value) { + PropertyDefinition propertyDefinition = new PropertyDefinition(); + propertyDefinition.setName(prop.getName()); + propertyDefinition.setValue(value); + propertyDefinition.setType(prop.getType()); + propertyDefinition.setConstraints(prop.getConstraints()); + propertyDefinition.setSchema(prop.getSchema()); + + return propertyDefinition; + } + + private boolean isValidValueConstraintPresent(List<PropertyConstraint> propertyConstraints) { + return propertyConstraints.stream() + .anyMatch(propertyConstraint -> propertyConstraint instanceof ValidValuesConstraint); + } + + private PropertyDefinition getPropertyDefinitionObjectFromInputs( + PropertyDefinition property) { + InputDefinition inputDefinition = (InputDefinition) property; + PropertyDefinition propertyDefinition = null; + + if (CollectionUtils.isEmpty(inputDefinition.getProperties()) + || ToscaType.isPrimitiveType(inputDefinition.getProperties().get(0).getType())) { + propertyDefinition = new PropertyDefinition(); + propertyDefinition.setType(inputDefinition.getType()); + propertyDefinition.setValue(inputDefinition.getDefaultValue()); + propertyDefinition.setName(inputDefinition.getName()); + } else if (Objects.nonNull(inputDefinition.getInputPath())) { + propertyDefinition = evaluateComplexTypeInputs(inputDefinition); + } + + return propertyDefinition; + } + + private PropertyDefinition evaluateComplexTypeInputs(InputDefinition inputDefinition) { + Map<String, Object> inputMap = new HashMap<>(); + PropertyDefinition propertyDefinition = new PropertyDefinition(); + String[] inputPathArr = inputDefinition.getInputPath().split("#"); + if (inputPathArr.length > 1) { + inputPathArr = ArrayUtils.remove(inputPathArr, 0); + } + + try { + Map<String, Object> presentMap = inputMap; + for (int i = 0; i < inputPathArr.length ; i++) { + if (i == inputPathArr.length - 1) { + presentMap.computeIfAbsent(inputPathArr[i], k -> inputDefinition.getDefaultValue()); + } else { + presentMap.computeIfAbsent(inputPathArr[i], k -> new HashMap<String, Object>()); + presentMap = (Map<String, Object>) presentMap.get(inputPathArr[i]); + } + } + + if (CollectionUtils.isNotEmpty(inputDefinition.getProperties())) { + propertyDefinition.setType(inputDefinition.getProperties().get(0).getType()); + } + propertyDefinition.setName(inputDefinition.getName()); + propertyDefinition.setValue(objectMapper.writeValueAsString(inputMap)); + } catch (IOException e) { + logger.error(e.getMessage(), e); + errorMessages.add(String.format(VALUE_PROVIDED_IN_INVALID_FORMAT_FOR_PROPERTY, + inputDefinition.getName())); + } + + return propertyDefinition; + } + + protected ResponseFormatManager getResponseFormatManager() { + return ResponseFormatManager.getInstance(); + } +} diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentPropertyServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentPropertyServlet.java index 79e63c71b5..38c04a131c 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentPropertyServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ComponentPropertyServlet.java @@ -17,28 +17,45 @@ package org.openecomp.sdc.be.servlets; import com.jcabi.aspects.Loggable; + +import java.util.List; +import java.util.Map; + import fj.data.Either; -import io.swagger.annotations.*; +import io.swagger.annotations.Api; +import io.swagger.annotations.ApiOperation; +import io.swagger.annotations.ApiParam; +import io.swagger.annotations.ApiResponse; +import io.swagger.annotations.ApiResponses; import org.openecomp.sdc.be.components.impl.PropertyBusinessLogic; import org.openecomp.sdc.be.config.BeEcompErrorManager; import org.openecomp.sdc.be.dao.api.ActionStatus; +import org.openecomp.sdc.be.datamodel.utils.PropertyValueConstraintValidationUtil; import org.openecomp.sdc.be.model.PropertyDefinition; import org.openecomp.sdc.be.model.User; +import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache; import org.openecomp.sdc.be.resources.data.EntryData; import org.openecomp.sdc.common.api.Constants; import org.openecomp.sdc.exception.ResponseFormat; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import javax.inject.Singleton; import javax.servlet.ServletContext; import javax.servlet.http.HttpServletRequest; -import javax.ws.rs.*; +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.HeaderParam; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; import javax.ws.rs.core.Context; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import java.util.List; -import java.util.Map; @Loggable(prepend = true, value = Loggable.DEBUG, trim = false) @Path("/v1/catalog") @@ -46,6 +63,9 @@ import java.util.Map; @Singleton public class ComponentPropertyServlet extends BeGenericServlet { + @Autowired + ApplicationDataTypeCache applicationDataTypeCache; + private static final Logger log = LoggerFactory.getLogger(ComponentPropertyServlet.class); private static final String CREATE_PROPERTY = "Create Property"; private static final String DEBUG_MESSAGE = "Start handle request of {} modifier id is {}"; @@ -264,6 +284,16 @@ public class ComponentPropertyServlet extends BeGenericServlet { return buildErrorResponse(responseFormat); } + //Validate value and Constraint of property + Either<Boolean, ResponseFormat> constraintValidatorResponse = + PropertyValueConstraintValidationUtil.getInstance(). + validatePropertyConstraints(properties.values(), applicationDataTypeCache); + if (constraintValidatorResponse.isRight()) { + log.error("Failed validation value and constraint of property: {}", + constraintValidatorResponse.right().value()); + return buildErrorResponse(constraintValidatorResponse.right().value()); + } + // update property PropertyBusinessLogic businessLogic = getPropertyBL(context); diff --git a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ServiceConsumptionServlet.java b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ServiceConsumptionServlet.java index 4ed2f95676..990e3bc356 100644 --- a/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ServiceConsumptionServlet.java +++ b/catalog-be/src/main/java/org/openecomp/sdc/be/servlets/ServiceConsumptionServlet.java @@ -44,6 +44,7 @@ import org.openecomp.sdc.be.dao.api.ActionStatus; import org.openecomp.sdc.be.datatypes.elements.OperationInputDefinition; import org.openecomp.sdc.be.datatypes.enums.ComponentTypeEnum; import org.openecomp.sdc.be.model.Operation; +import org.openecomp.sdc.be.model.OperationInput; import org.openecomp.sdc.be.model.User; import org.openecomp.sdc.be.model.tosca.ToscaFunctions; import org.openecomp.sdc.be.resources.data.auditing.AuditingActionEnum; @@ -158,8 +159,7 @@ public class ServiceConsumptionServlet extends BeGenericServlet { } List<OperationInputDefinition> inputs = inputsEither.left().value(); - updateOperationInputListForUi(inputs); - return buildOkResponse(inputs); + return buildOkResponse(updateOperationInputListForUi(inputs, interfaceOperationBL)); } catch (Exception e) { BeEcompErrorManager.getInstance().logBeRestApiGeneralError("Get Operation Inputs"); @@ -169,43 +169,52 @@ public class ServiceConsumptionServlet extends BeGenericServlet { } } - private void updateOperationInputListForUi(List<OperationInputDefinition> inputsList) { - for(OperationInputDefinition input : inputsList) { - - String value = input.getValue(); - // No Additional UI mapping needed for STATIC source - if(StringUtils.isEmpty(value) - || ServiceConsumptionSource.STATIC.getSource().equals(input.getSource())) { - continue; - } - - - // Additional UI mapping needed for other sources - try { - Map<String, Object> valueAsMap = (new Gson()).fromJson(value, Map.class); - String toscaFunction = valueAsMap.keySet().iterator().next(); - Object consumptionValueName = valueAsMap.values().iterator().next(); - if(consumptionValueName instanceof List) { - List<Object> toscaFunctionList = (List<Object>) consumptionValueName; - String consumptionInputValue = null; - if (ToscaFunctions.GET_PROPERTY.getFunctionName().equals(toscaFunction)) { - consumptionInputValue = String.valueOf(toscaFunctionList.get(1)); - } else if (ToscaFunctions.GET_OPERATION_OUTPUT.getFunctionName().equals(toscaFunction)) { - //Return full output name - consumptionInputValue = - toscaFunctionList.get(1) + "." + toscaFunctionList.get(2) + "." +toscaFunctionList.get(3); - } - input.setValue(consumptionInputValue); - } else { - input.setValue(String.valueOf(consumptionValueName)); - } - } - catch(JsonParseException ex){ - log.info("This means it is static value for which no changes are needed"); - } - } - } - + private List<OperationInput> updateOperationInputListForUi(List<OperationInputDefinition> inputsList, + InterfaceOperationBusinessLogic interfaceOperationBL) { + List<OperationInput> operationInputs = new ArrayList<>(); + for(OperationInputDefinition input : inputsList) { + + String value = input.getValue(); + + // Additional UI mapping needed for other sources + if (StringUtils.isNotBlank(value) + && !ServiceConsumptionSource.STATIC.getSource().equals(input.getSource())) { + uiMappingForOtherSources(value, input); + } + + // Add Constraint for UI + OperationInput operationInput = new OperationInput(input); + operationInput.setConstraints(interfaceOperationBL.setInputConstraint(input)); + operationInputs.add(operationInput); + } + + return operationInputs; + } + + private void uiMappingForOtherSources(String value, OperationInputDefinition input) { + try { + Map<String, Object> valueAsMap = (new Gson()).fromJson(value, Map.class); + String toscaFunction = valueAsMap.keySet().iterator().next(); + Object consumptionValueName = valueAsMap.values().iterator().next(); + if(consumptionValueName instanceof List) { + List<Object> toscaFunctionList = (List<Object>) consumptionValueName; + String consumptionInputValue = null; + if (ToscaFunctions.GET_PROPERTY.getFunctionName().equals(toscaFunction)) { + consumptionInputValue = String.valueOf(toscaFunctionList.get(1)); + } else if (ToscaFunctions.GET_OPERATION_OUTPUT.getFunctionName().equals(toscaFunction)) { + //Return full output name + consumptionInputValue = + toscaFunctionList.get(1) + "." + toscaFunctionList.get(2) + "." +toscaFunctionList.get(3); + } + input.setValue(consumptionInputValue); + } else { + input.setValue(String.valueOf(consumptionValueName)); + } + } + catch(JsonParseException ex){ + log.info("This means it is static value for which no changes are needed"); + } + } private Either<Map<String, List<ServiceConsumptionData>>, ResponseFormat> getServiceConsumptionData(String data, User user) { diff --git a/catalog-be/src/main/resources/config/error-configuration.yaml b/catalog-be/src/main/resources/config/error-configuration.yaml index d9f8ffc7e4..312d90c307 100644 --- a/catalog-be/src/main/resources/config/error-configuration.yaml +++ b/catalog-be/src/main/resources/config/error-configuration.yaml @@ -2262,4 +2262,10 @@ errors: code: 400, message: "Error: Given value is different than input type. Needs to be %1", messageId: "SVC4725" + } +#---------SVC4726----------------------------- + INVALID_PROPERTY_VALUES: { + code: 400, + message: "Error: Invalid property values provided:\n %1", + messageId: "SVC4735" }
\ No newline at end of file diff --git a/catalog-be/src/test/java/org/openecomp/sdc/be/datamodel/utils/PropertyValueConstraintValidationUtilTest.java b/catalog-be/src/test/java/org/openecomp/sdc/be/datamodel/utils/PropertyValueConstraintValidationUtilTest.java new file mode 100644 index 0000000000..95020b6112 --- /dev/null +++ b/catalog-be/src/test/java/org/openecomp/sdc/be/datamodel/utils/PropertyValueConstraintValidationUtilTest.java @@ -0,0 +1,317 @@ +package org.openecomp.sdc.be.datamodel.utils; + +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.reflect.TypeToken; + +import java.io.BufferedReader; +import java.io.File; +import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Objects; + +import fj.data.Either; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.Mockito; +import org.mockito.MockitoAnnotations; +import org.mockito.Spy; +import org.openecomp.sdc.be.components.impl.ResponseFormatManager; +import org.openecomp.sdc.be.dao.titan.TitanOperationStatus; +import org.openecomp.sdc.be.model.ComponentInstanceProperty; +import org.openecomp.sdc.be.model.DataTypeDefinition; +import org.openecomp.sdc.be.model.InputDefinition; +import org.openecomp.sdc.be.model.PropertyConstraint; +import org.openecomp.sdc.be.model.PropertyDefinition; +import org.openecomp.sdc.be.model.cache.ApplicationDataTypeCache; +import org.openecomp.sdc.be.model.jsontitan.operations.ToscaOperationFacade; +import org.openecomp.sdc.be.model.operations.impl.PropertyOperation; +import org.openecomp.sdc.exception.ResponseFormat; + +public class PropertyValueConstraintValidationUtilTest { + + @Mock + ApplicationDataTypeCache applicationDataTypeCache; + + @Mock + ToscaOperationFacade toscaOperationFacade; + + @Spy + @InjectMocks + PropertyValueConstraintValidationUtil propertyValueConstraintValidationUtil; + + private Map<String, DataTypeDefinition> dataTypeDefinitionMap; + + @Before + public void init() { + MockitoAnnotations.initMocks(this); + ResponseFormatManager responseFormatManagerMock = Mockito.mock(ResponseFormatManager.class); + when(responseFormatManagerMock.getResponseFormat(any())).thenReturn(new ResponseFormat()); + when(responseFormatManagerMock.getResponseFormat(any(), any())).thenReturn(new ResponseFormat()); + when(responseFormatManagerMock.getResponseFormat(any(), any(), any())).thenReturn(new ResponseFormat()); + when(propertyValueConstraintValidationUtil.getResponseFormatManager()).thenReturn(responseFormatManagerMock); + + createDataTypeMap(); + } + + @Test + public void primitiveValueSuccessTest() { + Either<Map<String, DataTypeDefinition>, TitanOperationStatus> either = Either.left(dataTypeDefinitionMap); + Mockito.when(applicationDataTypeCache.getAll()).thenReturn(either); + + PropertyDefinition propertyDefinition = new PropertyDefinition(); + propertyDefinition.setType("integer"); + propertyDefinition.setValue("10"); + + Either<Boolean, ResponseFormat> responseEither = + propertyValueConstraintValidationUtil.validatePropertyConstraints( + Collections.singletonList(propertyDefinition), applicationDataTypeCache); + + Assert.assertTrue(responseEither.isLeft()); + } + + @Test + public void primitiveValueFailTest() { + Either<Map<String, DataTypeDefinition>, TitanOperationStatus> either = Either.left(dataTypeDefinitionMap); + Mockito.when(applicationDataTypeCache.getAll()).thenReturn(either); + + PropertyDefinition propertyDefinition = new PropertyDefinition(); + propertyDefinition.setType("integer"); + propertyDefinition.setValue("abcd"); + + Either<Boolean, ResponseFormat> responseEither = + propertyValueConstraintValidationUtil.validatePropertyConstraints( + Collections.singletonList(propertyDefinition), applicationDataTypeCache); + + Assert.assertTrue(responseEither.isRight()); + } + + @Test + public void complexWithValidValueSuccessTest() { + Either<Map<String, DataTypeDefinition>, TitanOperationStatus> either = Either.left(dataTypeDefinitionMap); + Mockito.when(applicationDataTypeCache.getAll()).thenReturn(either); + + PropertyDefinition propertyDefinition = new PropertyDefinition(); + propertyDefinition.setType("org.openecomp.datatypes.heat.network.neutron.Subnet"); + propertyDefinition.setValue("{\"prefixlen\":\"4\"}"); + + Either<Boolean, ResponseFormat> responseEither = + propertyValueConstraintValidationUtil.validatePropertyConstraints( + Collections.singletonList(propertyDefinition), applicationDataTypeCache); + + Assert.assertTrue(responseEither.isLeft()); + } + + @Test + public void complexWithValidValueFailTest() { + Either<Map<String, DataTypeDefinition>, TitanOperationStatus> either = Either.left(dataTypeDefinitionMap); + Mockito.when(applicationDataTypeCache.getAll()).thenReturn(either); + + PropertyDefinition propertyDefinition = new PropertyDefinition(); + propertyDefinition.setType("org.openecomp.datatypes.heat.network.neutron.Subnet"); + propertyDefinition.setValue("{\"prefixlen\":\"5\"}"); + + Either<Boolean, ResponseFormat> responseEither = + propertyValueConstraintValidationUtil.validatePropertyConstraints( + Collections.singletonList(propertyDefinition), applicationDataTypeCache); + + Assert.assertTrue(responseEither.isRight()); + } + + @Test + public void complexWithListWithPrimitiveValueSuccessTest() { + Either<Map<String, DataTypeDefinition>, TitanOperationStatus> either = Either.left(dataTypeDefinitionMap); + Mockito.when(applicationDataTypeCache.getAll()).thenReturn(either); + + PropertyDefinition propertyDefinition = new PropertyDefinition(); + propertyDefinition.setType("org.openecomp.datatypes.heat.network.neutron.Subnet"); + propertyDefinition.setValue("{\"allocation_pools\":[\"slaac\"]}"); + + Either<Boolean, ResponseFormat> responseEither = + propertyValueConstraintValidationUtil.validatePropertyConstraints( + Collections.singletonList(propertyDefinition), applicationDataTypeCache); + + Assert.assertTrue(responseEither.isLeft()); + } + + @Test + public void complexWithListWithPrimitiveValueFailTest() { + Either<Map<String, DataTypeDefinition>, TitanOperationStatus> either = Either.left(dataTypeDefinitionMap); + Mockito.when(applicationDataTypeCache.getAll()).thenReturn(either); + + PropertyDefinition propertyDefinition = new PropertyDefinition(); + propertyDefinition.setType("org.openecomp.datatypes.heat.network.neutron.Subnet"); + propertyDefinition.setValue("{\"allocation_pools\":[\"value\"]}"); + + Either<Boolean, ResponseFormat> responseEither = + propertyValueConstraintValidationUtil.validatePropertyConstraints( + Collections.singletonList(propertyDefinition), applicationDataTypeCache); + + Assert.assertTrue(responseEither.isRight()); + } + + @Test + public void complexWithMapWithPrimitiveValueSuccessTest() { + Either<Map<String, DataTypeDefinition>, TitanOperationStatus> either = Either.left(dataTypeDefinitionMap); + Mockito.when(applicationDataTypeCache.getAll()).thenReturn(either); + + PropertyDefinition propertyDefinition = new PropertyDefinition(); + propertyDefinition.setType("org.openecomp.datatypes.heat.network.neutron.Subnet"); + propertyDefinition.setValue("{\"value_specs\":{\"key\":\"slaac\"}}"); + + Either<Boolean, ResponseFormat> responseEither = + propertyValueConstraintValidationUtil.validatePropertyConstraints( + Collections.singletonList(propertyDefinition), applicationDataTypeCache); + + Assert.assertTrue(responseEither.isLeft()); + } + + @Test + public void complexWithMapWithPrimitiveValueFailTest() { + Either<Map<String, DataTypeDefinition>, TitanOperationStatus> either = Either.left(dataTypeDefinitionMap); + Mockito.when(applicationDataTypeCache.getAll()).thenReturn(either); + + PropertyDefinition propertyDefinition = new PropertyDefinition(); + propertyDefinition.setType("org.openecomp.datatypes.heat.network.neutron.Subnet"); + propertyDefinition.setValue("{\"value_specs\":{\"key\":\"value\"}}"); + + Either<Boolean, ResponseFormat> responseEither = + propertyValueConstraintValidationUtil.validatePropertyConstraints( + Collections.singletonList(propertyDefinition), applicationDataTypeCache); + + Assert.assertTrue(responseEither.isRight()); + } + + @Test + public void inputValidValueSuccessTest() { + Either<Map<String, DataTypeDefinition>, TitanOperationStatus> either = Either.left(dataTypeDefinitionMap); + Mockito.when(applicationDataTypeCache.getAll()).thenReturn(either); + + InputDefinition inputDefinition = new InputDefinition(); + inputDefinition.setInputPath("propetyName#ipv6_ra_mode"); + inputDefinition.setDefaultValue("slaac"); + inputDefinition.setType("string"); + ComponentInstanceProperty propertyDefinition = new ComponentInstanceProperty(); + propertyDefinition.setType("org.openecomp.datatypes.heat.network.neutron.Subnet"); + inputDefinition.setProperties(Collections.singletonList(propertyDefinition)); + + Either<Boolean, ResponseFormat> responseEither = + propertyValueConstraintValidationUtil.validatePropertyConstraints( + Collections.singletonList(inputDefinition), applicationDataTypeCache); + + Assert.assertTrue(responseEither.isLeft()); + } + + @Test + public void inputValidValueFailTest() { + Either<Map<String, DataTypeDefinition>, TitanOperationStatus> either = Either.left(dataTypeDefinitionMap); + Mockito.when(applicationDataTypeCache.getAll()).thenReturn(either); + + InputDefinition inputDefinition = new InputDefinition(); + inputDefinition.setInputPath("propetyName#ipv6_ra_mode"); + inputDefinition.setDefaultValue("incorrectValue"); + ComponentInstanceProperty propertyDefinition = new ComponentInstanceProperty(); + propertyDefinition.setType("org.openecomp.datatypes.heat.network.neutron.Subnet"); + inputDefinition.setProperties(Collections.singletonList(propertyDefinition)); + + Either<Boolean, ResponseFormat> responseEither = + propertyValueConstraintValidationUtil.validatePropertyConstraints( + Collections.singletonList(inputDefinition), applicationDataTypeCache); + + Assert.assertTrue(responseEither.isRight()); + } + + @Test + public void serviceConsumptionValidValueSuccessTest() { + Either<Map<String, DataTypeDefinition>, TitanOperationStatus> either = Either.left(dataTypeDefinitionMap); + Mockito.when(applicationDataTypeCache.getAll()).thenReturn(either); + + PropertyDefinition propertyDefinition = new PropertyDefinition(); + propertyDefinition.setType("org.openecomp.datatypes.heat.network.neutron.Subnet"); + propertyDefinition.setValue("{\"ipv6_ra_mode\":\"slaac\"}"); + propertyDefinition.setName("ipv6_ra_mode"); + + Either<Boolean, ResponseFormat> responseEither = + propertyValueConstraintValidationUtil.validatePropertyConstraints( + Collections.singletonList(propertyDefinition), applicationDataTypeCache); + + Assert.assertTrue(responseEither.isLeft()); + } + @Test + public void serviceConsumptionValidValueFailTest() { + Either<Map<String, DataTypeDefinition>, TitanOperationStatus> either = Either.left(dataTypeDefinitionMap); + Mockito.when(applicationDataTypeCache.getAll()).thenReturn(either); + + PropertyDefinition propertyDefinition = new PropertyDefinition(); + propertyDefinition.setType("org.openecomp.datatypes.heat.network.neutron.Subnet"); + propertyDefinition.setValue("{\"ipv6_ra_mode\":\"incorrectValue\"}"); + propertyDefinition.setName("ipv6_ra_mode"); + + Either<Boolean, ResponseFormat> responseEither = + propertyValueConstraintValidationUtil.validatePropertyConstraints( + Collections.singletonList(propertyDefinition), applicationDataTypeCache); + + Assert.assertTrue(responseEither.isRight()); + } + + private void createDataTypeMap() { + Type constraintType = new TypeToken<PropertyConstraint>() {}.getType(); + Type typeOfHashMap = new TypeToken<Map<String, DataTypeDefinition>>() { }.getType(); + Gson gson = new GsonBuilder().registerTypeAdapter(constraintType, + new PropertyOperation.PropertyConstraintDeserialiser()).create(); + + dataTypeDefinitionMap = gson.fromJson(readFile(), typeOfHashMap); + + DataTypeDefinition dataTypeDefinition = dataTypeDefinitionMap.get("org.openecomp.datatypes.heat.network" + + ".neutron.Subnet"); + + PropertyDefinition mapProperty = null; + PropertyDefinition listProperty = null; + List<PropertyConstraint> constraints = null; + for (PropertyDefinition propertyDefinition : dataTypeDefinition.getProperties()) { + if ("value_specs".equals(propertyDefinition.getName())) { + mapProperty = propertyDefinition; + } else if ("allocation_pools".equals(propertyDefinition.getName())) { + listProperty = propertyDefinition; + } else if ("ipv6_ra_mode".equals(propertyDefinition.getName())) { + constraints = propertyDefinition.getConstraints(); + } + } + + PropertyDefinition definition = new PropertyDefinition(mapProperty.getSchema().getProperty()); + definition.setConstraints(constraints); + mapProperty.getSchema().setProperty(definition); + + definition = new PropertyDefinition(listProperty.getSchema().getProperty()); + definition.setConstraints(constraints); + listProperty.getSchema().setProperty(definition); + } + + private static String readFile() { + StringBuilder stringBuilder = new StringBuilder(); + File file = new File(Objects.requireNonNull( + PropertyValueConstraintValidationUtilTest.class.getClassLoader().getResource("types/datatypes" + + "/constraintTest.json")).getFile()); + Path logFile = Paths.get(file.getAbsolutePath()); + try (BufferedReader reader = Files.newBufferedReader(logFile, StandardCharsets.UTF_8)) { + reader.lines().forEach(stringBuilder::append); + } catch (Exception e) { + Assert.fail(e.getMessage()); + e.printStackTrace(); + } + return stringBuilder.toString(); + } + +} diff --git a/catalog-be/src/test/resources/csars/with_groups.csar b/catalog-be/src/test/resources/csars/with_groups.csar Binary files differindex 3859114aa5..3a9e9ab8e0 100644 --- a/catalog-be/src/test/resources/csars/with_groups.csar +++ b/catalog-be/src/test/resources/csars/with_groups.csar diff --git a/catalog-be/src/test/resources/types/datatypes/constraintTest.json b/catalog-be/src/test/resources/types/datatypes/constraintTest.json new file mode 100644 index 0000000000..9596e92436 --- /dev/null +++ b/catalog-be/src/test/resources/types/datatypes/constraintTest.json @@ -0,0 +1,405 @@ +{ + "string": { + "derivedFrom": { + "name": "tosca.datatypes.Root", + "uniqueId": "tosca.datatypes.Root.datatype", + "description": "The TOSCA root Data Type all other TOSCA base Data Types derive from", + "creationTime": 1550136563278, + "modificationTime": 1550136563278, + "toscaPresentation": {} + }, + "name": "string", + "uniqueId": "string.datatype", + "derivedFromName": "tosca.datatypes.Root", + "creationTime": 1550136564103, + "modificationTime": 1550136564103, + "toscaPresentation": {} + }, + "org.openecomp.datatypes.heat.network.neutron.Subnet": { + "derivedFrom": { + "name": "tosca.datatypes.Root", + "uniqueId": "tosca.datatypes.Root.datatype", + "description": "The TOSCA root Data Type all other TOSCA base Data Types derive from", + "creationTime": 1550136563278, + "modificationTime": 1550136563278, + "toscaPresentation": {} + }, + "properties": [ + { + "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype.tenant_id", + "type": "string", + "required": false, + "definition": false, + "description": "The ID of the tenant who owns the network", + "password": false, + "name": "tenant_id", + "hidden": false, + "immutable": false, + "toscaPresentation": {} + }, + { + "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype.enable_dhcp", + "type": "boolean", + "required": false, + "definition": false, + "defaultValue": "true", + "description": "Set to true if DHCP is enabled and false if DHCP is disabled", + "password": false, + "name": "enable_dhcp", + "hidden": false, + "immutable": false, + "toscaPresentation": {} + }, + { + "constraints": [ + { + "validValues": [ + "dhcpv6-stateful", + "dhcpv6-stateless", + "slaac" + ] + } + ], + "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype.ipv6_address_mode", + "type": "string", + "required": false, + "definition": false, + "description": "IPv6 address mode", + "password": false, + "name": "ipv6_address_mode", + "hidden": false, + "immutable": false, + "toscaPresentation": {} + }, + { + "constraints": [ + { + "validValues": [ + "dhcpv6-stateful", + "dhcpv6-stateless", + "slaac" + ] + } + ], + "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype.ipv6_ra_mode", + "type": "string", + "required": false, + "definition": false, + "description": "IPv6 RA (Router Advertisement) mode", + "password": false, + "name": "ipv6_ra_mode", + "hidden": false, + "immutable": false, + "toscaPresentation": {} + }, + { + "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype.value_specs", + "type": "map", + "required": false, + "definition": false, + "defaultValue": "{}", + "description": "Extra parameters to include in the request", + "schema": { + "property": { + "constraints": [ + { + "validValues": [ + "dhcpv6-stateful", + "dhcpv6-stateless", + "slaac" + ] + } + ], + "type": "string", + "required": true, + "definition": false, + "password": false, + "hidden": false, + "immutable": false, + "toscaPresentation": {} + }, + "toscaPresentation": {} + }, + "password": false, + "name": "value_specs", + "hidden": false, + "immutable": false, + "toscaPresentation": {} + }, + { + "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype.allocation_pools", + "type": "list", + "required": false, + "definition": false, + "description": "The start and end addresses for the allocation pools", + "schema": { + "property": { + "type": "string", + "required": true, + "definition": false, + "password": false, + "hidden": false, + "immutable": false, + "toscaPresentation": {} + }, + "toscaPresentation": {} + }, + "password": false, + "name": "allocation_pools", + "hidden": false, + "immutable": false, + "toscaPresentation": {} + }, + { + "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype.subnetpool", + "type": "string", + "required": false, + "definition": false, + "description": "The name or ID of the subnet pool", + "password": false, + "name": "subnetpool", + "hidden": false, + "immutable": false, + "toscaPresentation": {} + }, + { + "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype.dns_nameservers", + "type": "list", + "required": false, + "definition": false, + "defaultValue": "[]", + "description": "A specified set of DNS name servers to be used", + "schema": { + "property": { + "type": "string", + "required": true, + "definition": false, + "password": false, + "hidden": false, + "immutable": false, + "toscaPresentation": {} + }, + "toscaPresentation": {} + }, + "password": false, + "name": "dns_nameservers", + "hidden": false, + "immutable": false, + "toscaPresentation": {} + }, + { + "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype.host_routes", + "type": "list", + "required": false, + "definition": false, + "description": "The gateway IP address", + "schema": { + "property": { + "type": "org.openecomp.datatypes.heat.network.subnet.HostRoute", + "required": true, + "definition": false, + "password": false, + "hidden": false, + "immutable": false, + "toscaPresentation": {} + }, + "toscaPresentation": {} + }, + "password": false, + "name": "host_routes", + "hidden": false, + "immutable": false, + "toscaPresentation": {} + }, + { + "constraints": [ + { + "validValues": [ + "4", + "6" + ] + } + ], + "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype.ip_version", + "type": "integer", + "required": false, + "definition": false, + "defaultValue": "4", + "description": "The gateway IP address", + "password": false, + "name": "ip_version", + "hidden": false, + "immutable": false, + "toscaPresentation": {} + }, + { + "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype.name", + "type": "string", + "required": false, + "definition": false, + "description": "The name of the subnet", + "password": false, + "name": "name", + "hidden": false, + "immutable": false, + "toscaPresentation": {} + }, + { + "constraints": [ + { + "greaterOrEqual": "0" + }, + { + "validValues": [ + "4", + "6" + ] + } + ], + "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype.prefixlen", + "type": "integer", + "required": false, + "definition": false, + "description": "Prefix length for subnet allocation from subnet pool", + "password": false, + "name": "prefixlen", + "hidden": false, + "immutable": false, + "toscaPresentation": {} + }, + { + "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype.cidr", + "type": "string", + "required": false, + "definition": false, + "description": "The CIDR", + "password": false, + "name": "cidr", + "hidden": false, + "immutable": false, + "toscaPresentation": {} + }, + { + "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype.gateway_ip", + "type": "string", + "required": false, + "definition": false, + "description": "The gateway IP address", + "password": false, + "name": "gateway_ip", + "hidden": false, + "immutable": false, + "toscaPresentation": {} + } + ], + "name": "org.openecomp.datatypes.heat.network.neutron.Subnet", + "uniqueId": "org.openecomp.datatypes.heat.network.neutron.Subnet.datatype", + "derivedFromName": "tosca.datatypes.Root", + "description": "A subnet represents an IP address block that can be used for assigning IP addresses to virtual instances", + "creationTime": 1550136564412, + "modificationTime": 1550136564464, + "toscaPresentation": {} + }, + "org.openecomp.datatypes.heat.contrailV2.virtual.machine.subInterface.MacAddress": { + "derivedFrom": { + "name": "tosca.datatypes.Root", + "uniqueId": "tosca.datatypes.Root.datatype", + "description": "The TOSCA root Data Type all other TOSCA base Data Types derive from", + "creationTime": 1550136563278, + "modificationTime": 1550136563278, + "toscaPresentation": {} + }, + "properties": [ + { + "uniqueId": "org.openecomp.datatypes.heat.contrailV2.virtual.machine.subInterface.MacAddress.datatype.mac_address", + "type": "list", + "required": false, + "definition": false, + "description": "Mac Addresses List.", + "schema": { + "property": { + "type": "string", + "required": true, + "definition": false, + "password": false, + "hidden": false, + "immutable": false, + "toscaPresentation": {} + }, + "toscaPresentation": {} + }, + "password": false, + "name": "mac_address", + "hidden": false, + "immutable": false, + "toscaPresentation": {} + } + ], + "name": "org.openecomp.datatypes.heat.contrailV2.virtual.machine.subInterface.MacAddress", + "uniqueId": "org.openecomp.datatypes.heat.contrailV2.virtual.machine.subInterface.MacAddress.datatype", + "derivedFromName": "tosca.datatypes.Root", + "description": "Virtual Machine Sub Interface Mac Address.", + "creationTime": 1550136565026, + "modificationTime": 1550136565030, + "toscaPresentation": {} + }, + "org.openecomp.datatypes.heat.contrailV2.network.rule.RuleList": { + "derivedFrom": { + "name": "tosca.datatypes.Root", + "uniqueId": "tosca.datatypes.Root.datatype", + "description": "The TOSCA root Data Type all other TOSCA base Data Types derive from", + "creationTime": 1550136563278, + "modificationTime": 1550136563278, + "toscaPresentation": {} + }, + "properties": [ + { + "uniqueId": "org.openecomp.datatypes.heat.contrailV2.network.rule.RuleList.datatype.network_policy_entries_policy_rule", + "type": "list", + "required": false, + "definition": false, + "description": "Contrail network rule", + "schema": { + "property": { + "type": "org.openecomp.datatypes.heat.contrailV2.network.rule.Rule", + "required": true, + "definition": false, + "password": false, + "hidden": false, + "immutable": false, + "toscaPresentation": {} + }, + "toscaPresentation": {} + }, + "password": false, + "name": "network_policy_entries_policy_rule", + "hidden": false, + "immutable": false, + "toscaPresentation": {} + } + ], + "name": "org.openecomp.datatypes.heat.contrailV2.network.rule.RuleList", + "uniqueId": "org.openecomp.datatypes.heat.contrailV2.network.rule.RuleList.datatype", + "derivedFromName": "tosca.datatypes.Root", + "description": "list of policy rules", + "creationTime": 1550136564716, + "modificationTime": 1550136564720, + "toscaPresentation": {} + }, + "integer": { + "derivedFrom": { + "name": "tosca.datatypes.Root", + "uniqueId": "tosca.datatypes.Root.datatype", + "description": "The TOSCA root Data Type all other TOSCA base Data Types derive from", + "creationTime": 1550136563278, + "modificationTime": 1550136563278, + "toscaPresentation": {} + }, + "name": "integer", + "uniqueId": "integer.datatype", + "derivedFromName": "tosca.datatypes.Root", + "creationTime": 1550136564094, + "modificationTime": 1550136564094, + "toscaPresentation": {} + } +}
\ No newline at end of file |