Skip to content

Commit

Permalink
Handle substitutions, operations, capabilities, relationships and req…
Browse files Browse the repository at this point in the history
…uirements
  • Loading branch information
stefbenoist committed Nov 19, 2019
1 parent 4055bf1 commit d5d08b8
Show file tree
Hide file tree
Showing 18 changed files with 326 additions and 700 deletions.
2 changes: 1 addition & 1 deletion deployments/attribute_notifications.go
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ func addSubstitutionMappingAttributeNotification(ctx context.Context, deployment
// This allows to store notifications for attributes depending on other ones or on operation outputs in order to ensure events publication when attribute value change
// This allows too to publish initial state for default attribute value
func addAttributeNotifications(ctx context.Context, deploymentID, nodeName, instanceName, attributeName string) error {
substitutionInstance, err := isSubstitutionNodeInstance(deploymentID, nodeName, instanceName)
substitutionInstance, err := isSubstitutionNodeInstance(ctx, deploymentID, nodeName, instanceName)
if err != nil {
return err
}
Expand Down
104 changes: 46 additions & 58 deletions deployments/capabilities.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,33 +45,27 @@ func TypeHasCapability(ctx context.Context, deploymentID, typeName, capabilityTy
return len(capabilities) > 0, err
}

// GetCapabilitiesOfType returns names of all capabilities in a given type hierarchy that derives from a given capability type
// GetCapabilitiesOfType returns names of all capabilities for a given node type hierarchy that derives from a given capability type
func GetCapabilitiesOfType(ctx context.Context, deploymentID, typeName, capabilityTypeName string) ([]string, error) {
capabilities := make([]string, 0)
typePath, err := locateTypePath(deploymentID, typeName)

node := new(tosca.NodeType)
err := getTypeStruct(deploymentID, typeName, node)
if err != nil {
return capabilities, err
}
capabilitiesKeys, err := consulutil.GetKeys(path.Join(typePath, "capabilities"))
if err != nil {
return capabilities, errors.Wrap(err, consulutil.ConsulGenericErrMsg)
}

for _, capName := range capabilitiesKeys {
exist, value, err := consulutil.GetStringValue(path.Join(capName, "type"))
if err != nil {
return capabilities, errors.Wrap(err, consulutil.ConsulGenericErrMsg)
}
if !exist || value == "" {
return capabilities, errors.Errorf("Missing \"type\" key for type capability %q", capName)
for name, capability := range node.Capabilities {
if capability.Type == "" {
return capabilities, errors.Errorf("Missing \"type\" key for type capability %q", name)
}
var isCorrectType bool
isCorrectType, err = IsTypeDerivedFrom(ctx, deploymentID, value, capabilityTypeName)
isCorrectType, err = IsTypeDerivedFrom(ctx, deploymentID, capability.Type, capabilityTypeName)
if err != nil {
return capabilities, err
}
if isCorrectType {
capabilities = append(capabilities, path.Base(capName))
capabilities = append(capabilities, name)
}
}

Expand Down Expand Up @@ -140,11 +134,22 @@ func GetCapabilityPropertyValue(ctx context.Context, deploymentID, nodeName, cap
if is && &ca != nil {
va, is = ca.Properties[propertyName]
if is && va != nil && va.Type != tosca.ValueAssignmentFunction {
return resolveVA(ctx, va, nestedKeys...), nil
return resolveComplexVA(ctx, va, nestedKeys...), nil
}
}

// Retrieve related propertyDefinition with default property
// Retrieve related va from node type
if va == nil {
va, err := GetNodeTypeCapabilityPropertyValueAssignment(ctx, deploymentID, node.Type, capabilityName, propertyName)
if err != nil {
return nil, err
}
if va != nil && va.Type != tosca.ValueAssignmentFunction {
return resolveComplexVA(ctx, va, nestedKeys...), nil
}
}

// Retrieve related propertyDefinition with default property at capability type
capabilityType, err := GetNodeCapabilityType(ctx, deploymentID, nodeName, capabilityName)
if err != nil {
return nil, err
Expand Down Expand Up @@ -201,7 +206,7 @@ func GetInstanceCapabilityAttributeValue(ctx context.Context, deploymentID, node

// Capability attributes of a Service referencing an application in another
// deployment are actually available as attributes of the node template
substitutionInstance, err := isSubstitutionNodeInstance(deploymentID, nodeName, instanceName)
substitutionInstance, err := isSubstitutionNodeInstance(ctx, deploymentID, nodeName, instanceName)
if err != nil {
return nil, err
}
Expand All @@ -226,11 +231,21 @@ func GetInstanceCapabilityAttributeValue(ctx context.Context, deploymentID, node
}

// Then look at global node level
nodeCapPath := path.Join(consulutil.DeploymentKVPrefix, deploymentID, "topology/nodes", nodeName, "capabilities", capabilityName, "attributes", attributeName)
result, err = getValueAssignmentWithDataType(ctx, deploymentID, nodeCapPath, nodeName, instanceName, "", attrDataType, nestedKeys...)
if err != nil || result != nil {
// If there is an error or attribute was found
return result, errors.Wrapf(err, "Failed to get attribute %q for capability %q on node %q (instance %q)", attributeName, capabilityName, nodeName, instanceName)
node, err := getNodeTemplateStruct(ctx, deploymentID, nodeName)
if err != nil {
return nil, err
}

ca, is := node.Capabilities[capabilityName]
if is && &ca != nil {
va, is := ca.Attributes[attributeName]
if is && va != nil && va.Type != tosca.ValueAssignmentFunction {
result, err := getValueAssignment(ctx, deploymentID, nodeName, instanceName, "", va, nil, nestedKeys...)
if err != nil || result != nil {
// If there is an error or attribute was found
return result, errors.Wrapf(err, "Failed to get attribute %q for capability %q on node %q (instance %q)", attributeName, capabilityName, nodeName, instanceName)
}
}
}

// Now look at capability type for default
Expand Down Expand Up @@ -415,50 +430,23 @@ func GetNodeTypeCapabilityType(ctx context.Context, deploymentID, nodeType, capa
return GetNodeTypeCapabilityType(ctx, deploymentID, parentType, capabilityName)
}

func GetNodeTypeCapabilityDefinition(ctx context.Context, deploymentID, nodeType, capabilityName string) (*tosca.CapabilityDefinition, error) {
func GetNodeTypeCapabilityPropertyValueAssignment(ctx context.Context, deploymentID, nodeType, capabilityName, propertyName string) (*tosca.ValueAssignment, error) {
typ := new(tosca.NodeType)
err := getTypeStruct(deploymentID, nodeType, typ)
if err != nil {
return nil, err
}

capDef, is := typ.Capabilities[capabilityName]
if is {
return &capDef, nil
}

parentType, err := GetParentType(ctx, deploymentID, nodeType)
if err != nil {
return nil, err
}
if parentType == "" {
return nil, nil
}
return GetNodeTypeCapabilityDefinition(ctx, deploymentID, parentType, capabilityName)
}

// GetNodeTypeCapabilityPropertyValue retrieves the property value of a node type capability identified by its name
//
// It explores the type hierarchy (derived_from) to found the given capability.
func GetNodeTypeCapabilityPropertyValue(ctx context.Context, deploymentID, nodeType, capabilityName, propertyName, propDataType string, nestedKeys ...string) (*TOSCAValue, error) {
typePath, err := locateTypePath(deploymentID, nodeType)
if err != nil {
return nil, err
}
capPropPath := path.Join(typePath, "capabilities", capabilityName, "properties", propertyName)
result, err := getValueAssignmentWithDataType(ctx, deploymentID, capPropPath, "", "", "", propDataType, nestedKeys...)
if err != nil || result != nil {
return result, errors.Wrapf(err, "Failed to get property %q for capability %q on node type %q", propertyName, capabilityName, nodeType)
}

parentType, err := GetParentType(ctx, deploymentID, nodeType)
if err != nil {
return nil, err
if is && &capDef != nil {
va, is := capDef.Properties[propertyName]
if is && va != nil {
return va, nil
}
}
if parentType == "" {
if typ.DerivedFrom == "" {
return nil, nil
}
return GetNodeTypeCapabilityPropertyValue(ctx, deploymentID, parentType, capabilityName, propertyName, propDataType, nestedKeys...)
return GetNodeTypeCapabilityPropertyValueAssignment(ctx, deploymentID, typ.DerivedFrom, capabilityName, propertyName)
}

func notifyAndPublishCapabilityAttributeValueChange(ctx context.Context, deploymentID, nodeName, instanceName, capabilityName, attributeName string, attributeValue interface{}) error {
Expand Down
6 changes: 3 additions & 3 deletions deployments/commons.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func getValueAssignment(ctx context.Context, deploymentID, nodeName, instanceNam

}

func resolveVA(ctx context.Context, va *tosca.ValueAssignment, nestedKeys ...string) *TOSCAValue {
func resolveComplexVA(ctx context.Context, va *tosca.ValueAssignment, nestedKeys ...string) *TOSCAValue {
if len(nestedKeys) == 0 {
return &TOSCAValue{Value: va.Value}
}
Expand All @@ -38,7 +38,7 @@ func resolveVA(ctx context.Context, va *tosca.ValueAssignment, nestedKeys ...str
if ok {
v, ok := m[nestedKeys[0]].(tosca.ValueAssignment)
if ok {
return resolveVA(ctx, &v, nestedKeys[1:]...)
return resolveComplexVA(ctx, &v, nestedKeys[1:]...)
}
return &TOSCAValue{Value: m[nestedKeys[0]]}
}
Expand All @@ -56,7 +56,7 @@ func getValueAssignmentWithoutResolve(ctx context.Context, va, vaDef *tosca.Valu
return &TOSCAValue{Value: va.Value}, false, nil
case tosca.ValueAssignmentList, tosca.ValueAssignmentMap:
if len(nestedKeys) > 0 {
return resolveVA(ctx, va, nestedKeys...), false, nil
return resolveComplexVA(ctx, va, nestedKeys...), false, nil
}
return &TOSCAValue{Value: va.Value}, false, nil
}
Expand Down
67 changes: 16 additions & 51 deletions deployments/definition_store.go
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ func createInstanceAndFixModel(ctx context.Context, consulStore consulutil.Consu
return isCompute, err
}

substitutable, err := isSubstitutableNode(deploymentID, nodeName)
substitutable, err := isSubstitutableNode(ctx, deploymentID, nodeName)
if err != nil {
return isCompute, err
}
Expand Down Expand Up @@ -360,42 +360,19 @@ func fixAlienBlockStorages(ctx context.Context, deploymentID, nodeName string) e
return err
}
if isBS {
attachReqs, err := GetRequirementAssignmentsByTypeForNode(ctx, deploymentID, nodeName, "attachment")
attachReqs, err := GetRequirementsByTypeForNode(ctx, deploymentID, nodeName, "attachment")
if err != nil {
return err
}
for _, attachReq := range attachReqs {
req := tosca.RequirementAssignment{}
req := attachReq.RequirementAssignment
// Reverse the target node
computeNodeName := req.Node
req.Node = nodeName
exist, value, err := consulutil.GetStringValue(path.Join(attachReq, "node"))
if err != nil {
return errors.Wrapf(err, "Failed to fix Alien-specific BlockStorage %q", nodeName)
}
//var computeNodeName string
//if exist {
// computeNodeName = value
//}
exist, value, err = consulutil.GetStringValue(path.Join(attachReq, "capability"))
if err != nil {
return errors.Wrapf(err, "Failed to fix Alien-specific BlockStorage %q", nodeName)
}
if exist {
req.Capability = value
}
exist, value, err = consulutil.GetStringValue(path.Join(attachReq, "relationship"))
if err != nil {
return errors.Wrapf(err, "Failed to fix Alien-specific BlockStorage %q", nodeName)
}
if exist {
req.Relationship = value
}
device, err := GetNodePropertyValue(ctx, deploymentID, nodeName, "device")
if err != nil {
return errors.Wrapf(err, "Failed to fix Alien-specific BlockStorage %q", nodeName)
}

req.RelationshipProps = make(map[string]*tosca.ValueAssignment)

if device != nil {
va := &tosca.ValueAssignment{}
if device.RawString() != "" {
Expand All @@ -404,33 +381,21 @@ func fixAlienBlockStorages(ctx context.Context, deploymentID, nodeName string) e
return errors.Wrapf(err, "Failed to fix Alien-specific BlockStorage %q, failed to parse device property", nodeName)
}
}
// Add device requirement property
if req.RelationshipProps == nil {
req.RelationshipProps = make(map[string]*tosca.ValueAssignment)
}
req.RelationshipProps["device"] = va
}

// Get all requirement properties
// Appending a final "/" here is not necessary as there is no other keys starting with "properties" prefix
kvs, err := consulutil.List(path.Join(attachReq, "properties"))
// Update the compute node with new requirement
node, err := getNodeTemplateStruct(ctx, deploymentID, nodeName)
if err != nil {
return errors.Wrapf(err, "Failed to fix Alien-specific BlockStorage %q", nodeName)
}
for key, value := range kvs {
va := &tosca.ValueAssignment{}
err := yaml.Unmarshal(value, va)
if err != nil {
return errors.Wrapf(err, "Failed to fix Alien-specific BlockStorage %q", nodeName)
}
req.RelationshipProps[path.Base(key)] = va
return err
}
//FIXME this needs to be done with new storage
//newReqID, err := GetNbRequirementsForNode(ctx, deploymentID, computeNodeName)
//if err != nil {
// return err
//}

// Do not share the consul store as we have to compute the number of requirements for nodes and as we will modify it asynchronously it may lead to overwriting
//internal.StoreRequirementAssignment(consulStore, req, path.Join(consulutil.DeploymentKVPrefix, deploymentID, "topology/nodes", computeNodeName, "requirements", fmt.Sprint(newReqID)), "local_storage")
nodePrefix := path.Join(consulutil.DeploymentKVPrefix, "topology", "nodes", computeNodeName)
storage.GetStore(storageTypes.StoreTypeDeployment).Set(nodePrefix, node)
}

}

return nil
Expand All @@ -456,7 +421,7 @@ func createNodeInstances(consulStore consulutil.ConsulStore, numberInstances uin
func createMissingBlockStorageForNodes(ctx context.Context, consulStore consulutil.ConsulStore, deploymentID string, nodeNames []string) error {

for _, nodeName := range nodeNames {
requirements, err := GetRequirementAssignmentsByTypeForNode(ctx, deploymentID, nodeName, "local_storage")
requirements, err := GetRequirementsByTypeForNode(ctx, deploymentID, nodeName, "local_storage")
if err != nil {
return err
}
Expand Down Expand Up @@ -486,7 +451,7 @@ func createMissingBlockStorageForNodes(ctx context.Context, consulStore consulut
This function check if a nodes need a block storage, and return the name of BlockStorage node.
*/
func checkBlockStorage(ctx context.Context, deploymentID, nodeName string) (bool, []string, error) {
requirements, err := GetRequirementAssignmentsByTypeForNode(ctx, deploymentID, nodeName, "local_storage")
requirements, err := GetRequirementsByTypeForNode(ctx, deploymentID, nodeName, "local_storage")
if err != nil {
return false, nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion deployments/instances.go
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ func GetInstanceAttributeValue(ctx context.Context, deploymentID, nodeName, inst

func getInstanceAttributeValue(ctx context.Context, deploymentID, nodeName, instanceName, attributeName string, skipInstanceLevel bool, nestedKeys ...string) (*TOSCAValue, error) {

substitutionInstance, err := isSubstitutionNodeInstance(deploymentID, nodeName, instanceName)
substitutionInstance, err := isSubstitutionNodeInstance(ctx, deploymentID, nodeName, instanceName)
if err != nil {
return nil, err
}
Expand Down
Loading

0 comments on commit d5d08b8

Please sign in to comment.