stackmate 0.0.4 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG.txt +7 -0
- data/README.md +25 -8
- data/bin/stackmate.rb +57 -53
- data/lib/stackmate/aws_attribs.rb +31 -31
- data/lib/stackmate/classmap.rb +33 -25
- data/lib/stackmate/client.rb +80 -0
- data/lib/stackmate/intrinsic_functions.rb +94 -38
- data/lib/stackmate/logging.rb +19 -19
- data/lib/stackmate/participants/cloudstack.rb +250 -165
- data/lib/stackmate/participants/cloudstack_affinitygroup.rb +122 -0
- data/lib/stackmate/participants/cloudstack_autoscalepolicy.rb +113 -0
- data/lib/stackmate/participants/cloudstack_autoscalevmgroup.rb +86 -0
- data/lib/stackmate/participants/cloudstack_autoscalevmprofile.rb +140 -0
- data/lib/stackmate/participants/cloudstack_condition.rb +122 -0
- data/lib/stackmate/participants/cloudstack_egressfirewallrule.rb +149 -0
- data/lib/stackmate/participants/cloudstack_firewallrule.rb +149 -0
- data/lib/stackmate/participants/cloudstack_globalloadbalancerrule.rb +158 -0
- data/lib/stackmate/participants/cloudstack_instancegroup.rb +113 -0
- data/lib/stackmate/participants/cloudstack_ipaddress.rb +149 -0
- data/lib/stackmate/participants/cloudstack_ipforwardingrule.rb +131 -0
- data/lib/stackmate/participants/cloudstack_iptonic.rb +95 -0
- data/lib/stackmate/participants/cloudstack_iso.rb +95 -0
- data/lib/stackmate/participants/cloudstack_lbhealthcheckpolicy.rb +140 -0
- data/lib/stackmate/participants/cloudstack_lbstickinesspolicy.rb +122 -0
- data/lib/stackmate/participants/cloudstack_loadbalancer.rb +158 -0
- data/lib/stackmate/participants/cloudstack_loadbalancerrule.rb +185 -0
- data/lib/stackmate/participants/cloudstack_network.rb +293 -0
- data/lib/stackmate/participants/cloudstack_networkacl.rb +176 -0
- data/lib/stackmate/participants/cloudstack_networkacllist.rb +104 -0
- data/lib/stackmate/participants/cloudstack_nictovirtualmachine.rb +104 -0
- data/lib/stackmate/participants/cloudstack_portforwardingrule.rb +176 -0
- data/lib/stackmate/participants/cloudstack_project.rb +113 -0
- data/lib/stackmate/participants/cloudstack_remoteaccessvpn.rb +122 -0
- data/lib/stackmate/participants/cloudstack_securitygroup.rb +122 -0
- data/lib/stackmate/participants/cloudstack_securitygroupegress.rb +185 -0
- data/lib/stackmate/participants/cloudstack_securitygroupingress.rb +185 -0
- data/lib/stackmate/participants/cloudstack_snapshot.rb +113 -0
- data/lib/stackmate/participants/cloudstack_snapshotpolicy.rb +122 -0
- data/lib/stackmate/participants/cloudstack_sshkeypair.rb +113 -0
- data/lib/stackmate/participants/cloudstack_staticnat.rb +113 -0
- data/lib/stackmate/participants/cloudstack_staticroute.rb +95 -0
- data/lib/stackmate/participants/cloudstack_tags.rb +113 -0
- data/lib/stackmate/participants/cloudstack_template.rb +212 -0
- data/lib/stackmate/participants/cloudstack_togloballoadbalancerrule.rb +104 -0
- data/lib/stackmate/participants/cloudstack_toloadbalancerrule.rb +95 -0
- data/lib/stackmate/participants/cloudstack_virtualmachine.rb +348 -0
- data/lib/stackmate/participants/cloudstack_virtualmachineops.rb +95 -0
- data/lib/stackmate/participants/cloudstack_vmsnapshot.rb +113 -0
- data/lib/stackmate/participants/cloudstack_volume.rb +176 -0
- data/lib/stackmate/participants/cloudstack_volumeops.rb +111 -0
- data/lib/stackmate/participants/cloudstack_vpc.rb +158 -0
- data/lib/stackmate/participants/cloudstack_vpnconnection.rb +95 -0
- data/lib/stackmate/participants/cloudstack_vpncustomergateway.rb +176 -0
- data/lib/stackmate/participants/cloudstack_vpngateway.rb +86 -0
- data/lib/stackmate/participants/cloudstack_vpnuser.rb +122 -0
- data/lib/stackmate/participants/common.rb +219 -70
- data/lib/stackmate/participants/stacknest.rb +6 -0
- data/lib/stackmate/resolver.rb +122 -0
- data/lib/stackmate/stack.rb +116 -60
- data/lib/stackmate/stack_executor.rb +99 -37
- data/lib/stackmate/stackpi.rb +46 -0
- data/lib/stackmate/version.rb +1 -1
- data/lib/stackmate/waitcondition_server.rb +15 -15
- data/lib/stackmate.rb +1 -1
- data/stackmate.gemspec +2 -4
- metadata +70 -19
@@ -1,91 +1,240 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'yaml'
|
1
3
|
require 'stackmate/logging'
|
2
|
-
require 'stackmate/aws_attribs'
|
3
4
|
require 'stackmate/intrinsic_functions'
|
5
|
+
require 'stackmate/resolver'
|
6
|
+
require 'stackmate/stackpi'
|
7
|
+
require 'net/http'
|
8
|
+
require 'uri'
|
9
|
+
require 'time'
|
4
10
|
|
5
11
|
module StackMate
|
6
12
|
|
7
13
|
|
8
|
-
class
|
9
|
-
include Logging
|
14
|
+
# class ParamHandle < Ruote::Participant
|
15
|
+
# include Logging
|
16
|
+
# def on_workitem
|
17
|
+
# logger.debug "Setting resolved parameter #{participant_name}"
|
18
|
+
# workitem['ResolvedNames'][participant_name] = workitem['']
|
19
|
+
# end
|
20
|
+
# end
|
21
|
+
|
22
|
+
class WaitConditionHandle < Ruote::Participant
|
23
|
+
include Logging
|
24
|
+
|
25
|
+
def create
|
26
|
+
logger.debug "Entering #{participant_name} "
|
27
|
+
workitem[participant_name] = {}
|
28
|
+
presigned_url = 'http://localhost:4567/waitcondition/' + workitem.fei.wfid + '/' + participant_name
|
29
|
+
workitem.fields['ResolvedNames'][participant_name] = presigned_url
|
30
|
+
logger.info "Your pre-signed URL is: #{presigned_url} "
|
31
|
+
logger.info "Try: \ncurl -X PUT --data 'foo' #{presigned_url}"
|
32
|
+
WaitCondition.create_handle(participant_name, presigned_url)
|
33
|
+
workitem[participant_name][:physical_id] = presigned_url
|
34
|
+
end
|
10
35
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
36
|
+
def delete
|
37
|
+
#p workitem
|
38
|
+
logger.info "In delete #{participant_name}"
|
39
|
+
return nil if !workitem[participant_name]
|
40
|
+
physical_id = workitem[participant_name][:physical_id]
|
41
|
+
if physical_id
|
42
|
+
workitem[participant_name] = {}
|
43
|
+
WaitCondition.delete_handle(participant_name)
|
44
|
+
end
|
45
|
+
end
|
20
46
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
def on_workitem
|
31
|
-
logger.debug "Entering #{workitem.participant_name} "
|
32
|
-
workitem[participant_name] = {}
|
33
|
-
@@conditions << self
|
34
|
-
stackname = workitem.fields['ResolvedNames']['AWS::StackName']
|
35
|
-
workitem[participant_name][:physical_id] = stackname + '-' + 'WaitCondition'
|
47
|
+
def on_workitem
|
48
|
+
if workitem['params']['operation'] == 'create'
|
49
|
+
create
|
50
|
+
else
|
51
|
+
#rollback / delete
|
52
|
+
delete
|
53
|
+
end
|
54
|
+
reply
|
55
|
+
end
|
36
56
|
end
|
37
57
|
|
38
|
-
|
58
|
+
class WaitCondition < Ruote::Participant
|
59
|
+
include Logging
|
60
|
+
@@handles = {}
|
61
|
+
@@conditions = []
|
62
|
+
|
63
|
+
def create
|
64
|
+
logger.debug "Entering #{workitem.participant_name} "
|
65
|
+
workitem[participant_name] = {}
|
66
|
+
@@conditions << self
|
67
|
+
stackname = workitem.fields['ResolvedNames']['AWS::StackName']
|
68
|
+
workitem[participant_name][:physical_id] = stackname + '-' + 'WaitCondition'
|
69
|
+
end
|
70
|
+
|
71
|
+
def delete
|
72
|
+
logger.info "In delete #{participant_name}"
|
73
|
+
#no-op
|
74
|
+
end
|
75
|
+
|
76
|
+
def on_workitem
|
77
|
+
if workitem['params']['operation'] == 'create'
|
78
|
+
create
|
79
|
+
else
|
80
|
+
#rollback / delete
|
81
|
+
delete
|
82
|
+
reply
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.create_handle(handle_name, handle)
|
39
87
|
@@handles[handle_name] = handle
|
40
|
-
|
88
|
+
end
|
89
|
+
|
90
|
+
def self.delete_handle(handle_name)
|
91
|
+
@@handles.delete(handle_name)
|
92
|
+
end
|
41
93
|
|
42
|
-
|
94
|
+
def set_handle(handle_name)
|
43
95
|
reply(workitem) if @@handles[handle_name]
|
44
|
-
|
96
|
+
end
|
45
97
|
|
46
|
-
|
98
|
+
def self.get_conditions()
|
47
99
|
@@conditions
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
class Output < Ruote::Participant
|
104
|
+
include Logging
|
105
|
+
include Intrinsic
|
106
|
+
|
107
|
+
def on_workitem
|
108
|
+
#p workitem.fields.keys
|
109
|
+
logger.debug "Entering #{workitem.participant_name} "
|
110
|
+
outputs = workitem.fields['Outputs']
|
111
|
+
logger.debug "In StackMate::Output.on_workitem #{outputs.inspect}"
|
112
|
+
outputs.each do |key, val|
|
113
|
+
v = val['Value']
|
114
|
+
constructed_value = intrinsic(v, workitem)
|
115
|
+
val['Value'] = constructed_value
|
116
|
+
logger.debug "Output: key = #{key}, value = #{constructed_value} descr = #{val['Description']}"
|
117
|
+
end
|
118
|
+
|
119
|
+
logger.debug "Output Done"
|
120
|
+
reply
|
121
|
+
end
|
48
122
|
end
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
end
|
66
|
-
|
67
|
-
|
68
|
-
|
123
|
+
|
124
|
+
class NoOpResource < Ruote::Participant
|
125
|
+
include Logging
|
126
|
+
|
127
|
+
def create
|
128
|
+
logger.debug "Creating #{participant_name} wfid=#{workitem.fei.wfid} fei=#{workitem.fei.to_h}"
|
129
|
+
workitem[participant_name] = {}
|
130
|
+
stackname = workitem.fields['ResolvedNames']['AWS::StackName']
|
131
|
+
logger.debug "physical id is #{stackname}-#{participant_name} "
|
132
|
+
workitem[participant_name][:physical_id] = stackname + '-' + participant_name
|
133
|
+
typ = workitem['Resources'][participant_name]['Type']
|
134
|
+
if AWS_FAKE_ATTRIB_VALUES[typ]
|
135
|
+
AWS_FAKE_ATTRIB_VALUES[typ].each do |k,v|
|
136
|
+
workitem[participant_name][k] = v
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
def delete
|
142
|
+
logger.debug "Deleting #{participant_name} wfid=#{workitem.fei.wfid} fei=#{workitem.fei.to_h}"
|
143
|
+
end
|
144
|
+
|
145
|
+
def on_workitem
|
146
|
+
@stackname = workitem['StackName']
|
147
|
+
if workitem['params']['operation'] == 'create'
|
148
|
+
create
|
149
|
+
else
|
150
|
+
delete
|
151
|
+
end
|
152
|
+
reply
|
153
|
+
end
|
69
154
|
end
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
155
|
+
|
156
|
+
class StackNest < Ruote::Participant
|
157
|
+
include Logging
|
158
|
+
include Intrinsic
|
159
|
+
include Resolver
|
160
|
+
include StackPi
|
161
|
+
|
162
|
+
def create
|
163
|
+
logger.debug("Creating nested stack #{@stackname}")
|
164
|
+
#Get template from URL
|
165
|
+
#Call stackmate API for launching new stack
|
166
|
+
#read outputs from predefined location
|
167
|
+
#copy all critical fields from workitems
|
168
|
+
|
169
|
+
#CAVEAT - needs file storage. may be move to database backed
|
170
|
+
# needs a Outputs tag. Not a big deal since nested stacks anyways need
|
171
|
+
#outputs tags
|
172
|
+
workitem[@stack_name] = {}
|
173
|
+
params = workitem['ResolvedNames']
|
174
|
+
stack_props = workitem['Resources'][@stack_name]['Properties']
|
175
|
+
template_url = URI(get_resolved(stack_props['TemplateURL'],workitem))
|
176
|
+
logger.debug("Fetching template for #{@stack_name} from URL #{template_url}")
|
177
|
+
http = Net::HTTP.new(template_url.host,template_url.port)
|
178
|
+
if template_url.scheme == 'https'
|
179
|
+
http.use_ssl = true
|
180
|
+
end
|
181
|
+
http.start {
|
182
|
+
http.request_get(template_url.path) { |res|
|
183
|
+
File.open("/tmp/#{@stack_name}.template", 'w') { |file| file.write(res.body) }
|
184
|
+
}
|
185
|
+
}
|
186
|
+
stack_props['Parameters'].each_key do |k|
|
187
|
+
params[k] = get_resolved(stack_props['Parameters'][k],workitem)
|
188
|
+
end
|
189
|
+
params['stackrand'] = Time.now().to_i #TODO use subid from fei or something
|
190
|
+
params['isnested'] = "True"
|
191
|
+
StackMate::StackPi.create_stack("/tmp/#{@stack_name}.template",@stack_name,format_params(params),true)
|
192
|
+
file_name = "/tmp/#{@stack_name}.workitem.#{params['stackrand']}"
|
193
|
+
if(File.exists?(file_name))
|
194
|
+
output_workitem = YAML.load(File.read(file_name))
|
195
|
+
workitem[@stack_name]['ResolvedNames'] = output_workitem['ResolvedNames'].clone
|
196
|
+
workitem[@stack_name]['Outputs'] = output_workitem['Outputs'].clone
|
197
|
+
workitem[@stack_name]['Resources'] = output_workitem['Resources'].clone
|
198
|
+
workitem[@stack_name]['IdMap'] = output_workitem['IdMap'].clone
|
199
|
+
#copy all resources created
|
200
|
+
output_workitem['Resources'].each_key do |resource|
|
201
|
+
workitem[@stack_name][resource] = output_workitem[resource].clone
|
202
|
+
end
|
203
|
+
logger.debug("Successfully created nested stack #{@stack_name}")
|
204
|
+
else
|
205
|
+
logger.debug("Unable to create nested stack #{@stack_name}")
|
206
|
+
raise "Nested Stack Failed"
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
def delete
|
211
|
+
logger.debug("Deleting stack #{@stack_name}")
|
212
|
+
#TODO write code to roll back all stack info
|
213
|
+
#Probably nothing needed since new engine launched takes care of it
|
214
|
+
#No, need to clean up if parent stack fails after the nested stack is successfully created
|
215
|
+
end
|
216
|
+
|
217
|
+
def on_workitem
|
218
|
+
@stack_name = workitem.participant_name
|
219
|
+
if workitem['params']['operation'] == 'create'
|
220
|
+
create
|
221
|
+
else
|
222
|
+
#rollback / delete
|
223
|
+
delete
|
224
|
+
end
|
225
|
+
reply
|
226
|
+
end
|
227
|
+
|
228
|
+
def format_params(params)
|
229
|
+
result = ""
|
230
|
+
add_semi = false
|
231
|
+
params.each_key do |k|
|
232
|
+
result = result + ";" if add_semi
|
233
|
+
result = result + k + "=" + params[k].to_s if !params[k].nil?
|
234
|
+
add_semi = true
|
85
235
|
end
|
236
|
+
result
|
86
237
|
end
|
87
|
-
reply
|
88
238
|
end
|
89
|
-
end
|
90
239
|
|
91
|
-
end
|
240
|
+
end
|
@@ -0,0 +1,122 @@
|
|
1
|
+
#require 'stackmate/logging'
|
2
|
+
require 'stackmate/intrinsic_functions'
|
3
|
+
|
4
|
+
module StackMate
|
5
|
+
module Resolver
|
6
|
+
@devicename_map=
|
7
|
+
{
|
8
|
+
'/dev/sdb' => '1',
|
9
|
+
'/dev/sdc' => '2',
|
10
|
+
'/dev/sdd' => '3',
|
11
|
+
'/dev/sde' => '4',
|
12
|
+
'/dev/sdf' => '5',
|
13
|
+
'/dev/sdg' => '6',
|
14
|
+
'/dev/sdh' => '7',
|
15
|
+
'/dev/sdi' => '8',
|
16
|
+
'/dev/sdj' => '9',
|
17
|
+
'/dev/xvdb' => '1',
|
18
|
+
'/dev/xvdc' => '2',
|
19
|
+
'/dev/xvdd' => '3',
|
20
|
+
'/dev/xvde' => '4',
|
21
|
+
'/dev/xvdf' => '5',
|
22
|
+
'/dev/xvdg' => '6',
|
23
|
+
'/dev/xvdh' => '7',
|
24
|
+
'/dev/xvdi' => '8',
|
25
|
+
'/dev/xvdj' => '9',
|
26
|
+
'xvdb' => '1',
|
27
|
+
'xvdc' => '2',
|
28
|
+
'xvdd' => '3',
|
29
|
+
'xvde' => '4',
|
30
|
+
'xvdf' => '5',
|
31
|
+
'xvdg' => '6',
|
32
|
+
'xvdh' => '7',
|
33
|
+
'xvdi' => '8',
|
34
|
+
'xvdj' => '9',
|
35
|
+
}
|
36
|
+
#comes from awsapi reference
|
37
|
+
STRINGEXP = /.+/
|
38
|
+
INTEXP = /[0-9]+/
|
39
|
+
UUIDEXP = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/
|
40
|
+
|
41
|
+
def get_resolved(lookup_data,workitem)
|
42
|
+
case lookup_data
|
43
|
+
when String
|
44
|
+
lookup_data
|
45
|
+
when Hash
|
46
|
+
intrinsic(lookup_data,workitem)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def validate_param(value,type)
|
51
|
+
return true
|
52
|
+
begin
|
53
|
+
case type
|
54
|
+
when "boolean"
|
55
|
+
["true","false"].include?(value)
|
56
|
+
when "date"
|
57
|
+
true
|
58
|
+
when "imageformat"
|
59
|
+
["vhd","qcow"].include?(value)
|
60
|
+
when "int"
|
61
|
+
!INTEXP.match(value).nil?
|
62
|
+
when "integer"
|
63
|
+
!INTEXP.match(value).nil?
|
64
|
+
when "list"
|
65
|
+
#eval(value).kind_of?(Array)
|
66
|
+
true
|
67
|
+
when "long"
|
68
|
+
!INTEXP.match(value).nil?
|
69
|
+
when "map"
|
70
|
+
#eval(value).kind_of?(Hash)
|
71
|
+
true
|
72
|
+
when "set"
|
73
|
+
#eval(value).kind_of?(Array) and eval(value).uniq == eval(value)
|
74
|
+
true
|
75
|
+
when "short"
|
76
|
+
!INTEXP.match(value).nil?
|
77
|
+
when "state"
|
78
|
+
true
|
79
|
+
when "string"
|
80
|
+
value.kind_of?(String)
|
81
|
+
when "tzdate"
|
82
|
+
true
|
83
|
+
when "uuid"
|
84
|
+
!UUIDEXP.match(value).nil?
|
85
|
+
else
|
86
|
+
true
|
87
|
+
end
|
88
|
+
rescue Exception => e
|
89
|
+
false
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def get_named_tag(tag_name,properties,workitem,default)
|
94
|
+
result = default
|
95
|
+
unless properties['Tags'].nil?
|
96
|
+
properties['Tags'].each do |tag|
|
97
|
+
k = tag['Key']
|
98
|
+
v = tag['Value']
|
99
|
+
if k.eql?(tag_name)
|
100
|
+
result = get_resolved(v,workitem)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
result
|
105
|
+
end
|
106
|
+
|
107
|
+
def resolve_tags(tags_array,workitem)
|
108
|
+
result = {}
|
109
|
+
tags_array.each do |tag|
|
110
|
+
k = tag['key']
|
111
|
+
v = tag['value']
|
112
|
+
resolved_v = get_resolved(v,workitem)
|
113
|
+
result[k] = resolved_v
|
114
|
+
end
|
115
|
+
result
|
116
|
+
end
|
117
|
+
|
118
|
+
def resolve_to_deviceid(devicename)
|
119
|
+
@devicename_map[devicename.downcase]
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
data/lib/stackmate/stack.rb
CHANGED
@@ -2,92 +2,148 @@ require 'json'
|
|
2
2
|
require 'set'
|
3
3
|
require 'tsort'
|
4
4
|
require 'stackmate/logging'
|
5
|
+
require 'yaml'
|
5
6
|
|
6
7
|
module StackMate
|
7
8
|
|
8
|
-
class Stacker
|
9
|
+
class Stacker
|
9
10
|
include TSort
|
10
11
|
include Logging
|
11
12
|
|
12
13
|
attr_accessor :templ
|
13
14
|
|
14
15
|
def initialize(stackstr, stackname, params)
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
16
|
+
@stackname = stackname
|
17
|
+
@resolved = params
|
18
|
+
@templ = JSON.parse(stackstr)
|
19
|
+
@templ['StackName'] = @stackname
|
20
|
+
@param_names = @templ['Parameters']
|
21
|
+
@deps = {}
|
22
|
+
@pdeps = {}
|
23
|
+
validate_param_values
|
24
|
+
resolve_dependencies()
|
25
|
+
validate_dependencies
|
26
|
+
@allowed_param_vales = get_allowed_values(@param_names)
|
27
|
+
@templ['ResolvedNames'] = populate_parameters(@param_names,@resolved)
|
28
|
+
#@templ['ResolvedNames']['StackId'] = SecureRandom.urlsafe_base64
|
29
|
+
@templ['IdMap'] = {}
|
30
|
+
end
|
31
|
+
|
32
|
+
def get_allowed_values(template_params)
|
33
|
+
allowed = {}
|
34
|
+
template_params.each_key do |k|
|
35
|
+
#Type is mandatory???
|
36
|
+
allowed[k] = {}
|
37
|
+
allowed[k]['Type'] = template_params[k]['Type'] if template_params[k].has_key?('Type')
|
38
|
+
allowed[k]['AllowedValues'] = template_params[k]['AllowedValues'] if template_params[k].has_key?('AllowedValues')
|
39
|
+
end
|
40
|
+
allowed
|
41
|
+
end
|
42
|
+
|
43
|
+
def populate_parameters(params,overrides)
|
44
|
+
populated={}
|
45
|
+
#Populate defaults
|
46
|
+
params.each_key do |k|
|
47
|
+
populated[k] = params[k]['Default']
|
48
|
+
end
|
49
|
+
#Then load local YAML mappings
|
50
|
+
begin
|
51
|
+
#TODO change to use stackid
|
52
|
+
#file_name = @stackname+".yml"
|
53
|
+
file_name = "local.yml"
|
54
|
+
localized = YAML.load_file(file_name)
|
55
|
+
localized.each_key do |k|
|
56
|
+
populated[k] = localized[k]
|
57
|
+
end
|
58
|
+
rescue
|
59
|
+
#raise "ERROR : Unable to load end point parameters"
|
60
|
+
logger.info("CAUTION: Unable to load end point parameters")
|
61
|
+
end
|
62
|
+
#Then override
|
63
|
+
overrides.each_key do |k|
|
64
|
+
populated[k] = overrides[k]
|
65
|
+
end
|
66
|
+
populated
|
25
67
|
end
|
26
68
|
|
27
|
-
|
28
69
|
def validate_param_values
|
29
|
-
|
30
|
-
|
70
|
+
#TODO CloudFormation parameters have validity constraints specified
|
71
|
+
#Use them to validate parameter values (e.g., email addresses)
|
72
|
+
#As of now used only in actual cloudstack calls
|
73
|
+
end
|
74
|
+
|
75
|
+
def validate_dependencies
|
76
|
+
resources = @deps.keys
|
77
|
+
@deps.each_key do |k|
|
78
|
+
@deps[k].each do |resource|
|
79
|
+
if !resources.include?(resource)
|
80
|
+
raise "Bad reference or dependency on resource #{resource}"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
31
84
|
end
|
32
85
|
|
33
86
|
def resolve_dependencies
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
87
|
+
@templ['Resources'].each { |key,val|
|
88
|
+
deps = Set.new
|
89
|
+
pdeps = Set.new
|
90
|
+
find_refs(key, val, deps, pdeps)
|
91
|
+
deps << val['DependsOn'] if val['DependsOn']
|
92
|
+
#print key, " depends on ", deps.to_a, "\n"
|
93
|
+
@deps[key] = deps.to_a
|
94
|
+
@pdeps[key] = pdeps.to_a
|
95
|
+
}
|
96
|
+
unresolved = []
|
97
|
+
@pdeps.keys.each do |k|
|
98
|
+
unres = @pdeps[k] - @resolved.keys
|
99
|
+
if ! unres.empty?
|
100
|
+
unres.each do |u|
|
101
|
+
deflt = @param_names[u]['Default']
|
102
|
+
#print "Found default value ", deflt, " for ", u, "\n" if deflt
|
103
|
+
@resolved[u] = deflt if deflt
|
104
|
+
end
|
105
|
+
unres = @pdeps[k] - @resolved.keys
|
106
|
+
unresolved = unresolved + unres
|
107
|
+
#throw :unresolved, (@pdeps[k] - @resolved.keys) if !unres.empty?
|
54
108
|
end
|
109
|
+
end
|
110
|
+
throw :unresolved, unresolved.uniq if !unresolved.empty?
|
55
111
|
end
|
56
112
|
|
57
113
|
|
58
114
|
def find_refs (parent, jsn, deps, pdeps)
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
end
|
115
|
+
case jsn
|
116
|
+
when Array
|
117
|
+
jsn.each {|x| find_refs(parent, x, deps, pdeps)}
|
118
|
+
#print parent, ": ", jsn, "\n"
|
119
|
+
when Hash
|
120
|
+
jsn.keys.each do |k|
|
121
|
+
#TODO Fn::GetAtt
|
122
|
+
if k == "Ref"
|
123
|
+
#only resolve dependencies on other resources for now
|
124
|
+
if !@param_names.keys.index(jsn[k]) && !@resolved.keys.index(jsn[k]) && jsn[k] != 'AWS::Region' && jsn[k] != 'AWS::StackId' && jsn[k] != 'AWS::StackName'
|
125
|
+
deps << jsn[k]
|
126
|
+
#print parent, ": ", deps.to_a, "\n"
|
127
|
+
else if @param_names.keys.index(jsn[k])
|
128
|
+
pdeps << jsn[k]
|
129
|
+
end
|
130
|
+
end
|
131
|
+
else
|
132
|
+
find_refs(parent, jsn[k], deps, pdeps)
|
133
|
+
end
|
79
134
|
end
|
80
|
-
|
135
|
+
end
|
136
|
+
return deps
|
81
137
|
end
|
82
138
|
|
83
139
|
def tsort_each_node(&block)
|
84
|
-
|
140
|
+
@deps.each_key(&block)
|
85
141
|
end
|
86
142
|
|
87
143
|
def tsort_each_child(name, &block)
|
88
|
-
|
144
|
+
@deps[name].each(&block) if @deps.has_key?(name)
|
89
145
|
end
|
90
|
-
|
91
|
-
end
|
92
146
|
|
93
|
-
end
|
147
|
+
end
|
148
|
+
|
149
|
+
end
|