forked from CiscoCloud/toscalib
-
Notifications
You must be signed in to change notification settings - Fork 0
/
service_template.go
240 lines (207 loc) · 10.2 KB
/
service_template.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
/*
Copyright 2015 - Olivier Wulveryck
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 toscalib
import "github.com/kenjones-cisco/mergo"
// ServiceTemplateDefinition is the meta structure containing an entire tosca document as described in
// http://docs.oasis-open.org/tosca/TOSCA-Simple-Profile-YAML/v1.0/csd03/TOSCA-Simple-Profile-YAML-v1.0-csd03.html
type ServiceTemplateDefinition struct {
DefinitionsVersion string `yaml:"tosca_definitions_version" json:"tosca_definitions_version"` // A.9.3.1 tosca_definitions_version
Metadata Metadata `yaml:"metadata,omitempty" json:"metadata"`
Description string `yaml:"description,omitempty" json:"description,omitempty"`
DslDefinitions interface{} `yaml:"dsl_definitions,omitempty" json:"dsl_definitions,omitempty"` // Declares optional DSL-specific definitions and conventions. For example, in YAML, this allows defining reusable YAML macros (i.e., YAML alias anchors) for use throughout the TOSCA Service Template.
Repositories map[string]RepositoryDefinition `yaml:"repositories,omitempty" json:"repositories,omitempty"` // Declares the list of external repositories which contain artifacts that are referenced in the service template along with their addresses and necessary credential information used to connect to them in order to retrieve the artifacts.
Imports []ImportDefinition `yaml:"imports,omitempty" json:"imports,omitempty"` // Declares import statements external TOSCA Definitions documents. For example, these may be file location or URIs relative to the service template file within the same TOSCA CSAR file.
ArtifactTypes map[string]ArtifactType `yaml:"artifact_types,omitempty" json:"artifact_types,omitempty"` // This section contains an optional list of artifact type definitions for use in service templates
DataTypes map[string]DataType `yaml:"data_types,omitempty" json:"data_types,omitempty"` // Declares a list of optional TOSCA Data Type definitions.
CapabilityTypes map[string]CapabilityType `yaml:"capability_types,omitempty" json:"capability_types,omitempty"` // This section contains an optional list of capability type definitions for use in service templates.
InterfaceTypes map[string]InterfaceType `yaml:"interface_types,omitempty" json:"interface_types,omitempty"` // This section contains an optional list of interface type definitions for use in service templates.
RelationshipTypes map[string]RelationshipType `yaml:"relationship_types,omitempty" json:"relationship_types,omitempty"` // This section contains a set of relationship type definitions for use in service templates.
NodeTypes map[string]NodeType `yaml:"node_types,omitempty" json:"node_types,omitempty"` // This section contains a set of node type definitions for use in service templates.
GroupTypes map[string]GroupType `yaml:"group_types,omitempty" json:"group_types,omitempty"`
PolicyTypes map[string]PolicyType `yaml:"policy_types" json:"policy_types"`
TopologyTemplate TopologyTemplateType `yaml:"topology_template" json:"topology_template"` // Defines the topology template of an application or service, consisting of node templates that represent the application’s or service’s components, as well as relationship templates representing relations between the components.
}
func (s *ServiceTemplateDefinition) resolve() {
// reflect properties to attributes
s.reflectProperties()
// resolve inherited data
ft := flattenHierarchy(*s)
s.TopologyTemplate.extendFrom(ft)
}
func (s *ServiceTemplateDefinition) reflectProperties() {
for k, v := range s.CapabilityTypes {
v.reflectProperties()
s.CapabilityTypes[k] = v
}
for k, v := range s.RelationshipTypes {
v.reflectProperties()
s.RelationshipTypes[k] = v
}
for k, v := range s.NodeTypes {
v.reflectProperties()
s.NodeTypes[k] = v
}
s.TopologyTemplate.reflectProperties()
}
// Clone creates a deep copy of a Service Template Definition
func (s *ServiceTemplateDefinition) Clone() ServiceTemplateDefinition {
var ns ServiceTemplateDefinition
tmp := clone(*s)
ns, _ = tmp.(ServiceTemplateDefinition)
return ns
}
// Merge applies the data from one ServiceTemplate to the current ServiceTemplate
func (s *ServiceTemplateDefinition) Merge(u ServiceTemplateDefinition) ServiceTemplateDefinition {
std := s.Clone()
_ = mergo.MergeWithOverwrite(&std, u)
return std
}
// GetNodeTemplate returns a pointer to a node template given its name
// its returns nil if not found
func (s *ServiceTemplateDefinition) GetNodeTemplate(nodeName string) *NodeTemplate {
if nt, ok := s.TopologyTemplate.NodeTemplates[nodeName]; ok {
return &nt
}
return nil
}
// GetRelationshipSource verifies the RelationshipTemplate exists and then searches the NodeTemplates
// to determine which one has a requirement for a specific RelationshipTemplate.
func (s *ServiceTemplateDefinition) GetRelationshipSource(relationshipName string) *NodeTemplate {
for _, nt := range s.TopologyTemplate.NodeTemplates {
nodeName := nt.GetRelationshipSource(relationshipName)
if nodeName != "" && nt.Name == nodeName {
return &nt
}
}
return nil
}
// GetRelationshipTarget verifies the RelationshipTemplate exists and then searches the NodeTemplates
// to determine which one has a requirement for a specific RelationshipTemplate with target node specified.
func (s *ServiceTemplateDefinition) GetRelationshipTarget(relationshipName string) *NodeTemplate {
for _, nt := range s.TopologyTemplate.NodeTemplates {
if nodeName := nt.GetRelationshipTarget(relationshipName); nodeName != "" {
return s.GetNodeTemplate(nodeName)
}
}
return nil
}
// GetProperty returns the property "prop"'s value for node named node
func (s *ServiceTemplateDefinition) GetProperty(node, prop string) *PropertyAssignment {
var output PropertyAssignment
if nt := s.GetNodeTemplate(node); nt != nil {
if val, ok := nt.Properties[prop]; ok {
output = val
}
}
return &output
}
// GetAttribute returns the attribute of a Node
func (s *ServiceTemplateDefinition) GetAttribute(node, attr string) *AttributeAssignment {
var output AttributeAssignment
if nt := s.GetNodeTemplate(node); nt != nil {
if val, ok := nt.Attributes[attr]; ok {
output = val
}
}
return &output
}
// GetInputValue retrieves an input value from Service Template Definition in
// the raw form (function evaluation not performed), or actual value after all
// function evaluation has completed.
func (s *ServiceTemplateDefinition) GetInputValue(prop string, raw bool) interface{} {
if raw {
return s.TopologyTemplate.Inputs[prop].Value
}
input := s.TopologyTemplate.Inputs[prop].Value
return input.Evaluate(s, "")
}
// GetWorkflowInputValue retrieves a worflow input value from Service Template Definition in
// the raw form (function evaluation not performed), or actual value after all
// function evaluation has completed.
func (s *ServiceTemplateDefinition) GetWorkflowInputValue(prop, wfname string, raw bool) interface{} {
if _, ok := s.TopologyTemplate.Workflows[wfname].Inputs[prop]; !ok {
// No workflow inputs, lets use Evaluate to find out if the its present in template inputs
return s.GetInputValue(prop, raw)
}
// Its there in the workflow, lets fetch it.
if raw {
return s.TopologyTemplate.Workflows[wfname].Inputs[prop].Value
}
input := s.TopologyTemplate.Workflows[wfname].Inputs[prop].Value
return input.Evaluate(s, "")
}
// SetWorkFlowInputValue sets an input value on a Service Template Definition
func (s *ServiceTemplateDefinition) SetWorkFlowInputValue(prop, wfname string, value interface{}) {
v := newPAValue(value)
s.TopologyTemplate.Workflows[wfname].Inputs[prop] = PropertyDefinition{Value: *v}
}
// SetInputValue sets an input value on a Service Template Definition
func (s *ServiceTemplateDefinition) SetInputValue(prop string, value interface{}) {
v := newPAValue(value)
s.TopologyTemplate.Inputs[prop] = PropertyDefinition{Value: *v}
}
// SetAttribute provides the ability to set a value to a named attribute
func (s *ServiceTemplateDefinition) SetAttribute(node, attr string, value interface{}) {
if nt := s.GetNodeTemplate(node); nt != nil {
nt.setAttribute(attr, value)
s.TopologyTemplate.NodeTemplates[node] = *nt
}
}
func (s *ServiceTemplateDefinition) nodeTypeHierarchy(name string) []string {
var types []string
typeName := name
for typeName != "" {
if nt, ok := s.NodeTypes[typeName]; ok {
types = append(types, typeName)
typeName = nt.DerivedFrom
} else {
typeName = ""
}
}
return types
}
func (s *ServiceTemplateDefinition) findHostNode(name string) *NodeTemplate {
nt := s.GetNodeTemplate(name)
if nt == nil {
return nil
}
if req := nt.getRequirementByRelationship("tosca.relationships.HostedOn"); req != nil {
// TODO(kenjones): assume the requirement has a node specified, otherwise need to use the
// value stored on the node type to get a list of node templates and then filter
// based on the requirement node filter sequence.
if targetNode := s.GetNodeTemplate(req.Node); targetNode != nil {
nth := s.nodeTypeHierarchy(nt.Type)
if targetNode.checkCapabilityMatch(req.Capability, nth) {
return targetNode
}
}
}
return nil
}
func (s *ServiceTemplateDefinition) findNodeTemplate(name, ctx string) *NodeTemplate {
switch name {
case Self:
return s.GetNodeTemplate(ctx)
case Host:
// find the host
return s.findHostNode(ctx)
case Source:
// find relationship source
return s.GetRelationshipSource(ctx)
case Target:
// find relationship target
return s.GetRelationshipTarget(ctx)
default:
return s.GetNodeTemplate(name)
}
}