stackmate 0.0.4 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. data/CHANGELOG.txt +7 -0
  2. data/README.md +25 -8
  3. data/bin/stackmate.rb +57 -53
  4. data/lib/stackmate/aws_attribs.rb +31 -31
  5. data/lib/stackmate/classmap.rb +33 -25
  6. data/lib/stackmate/client.rb +80 -0
  7. data/lib/stackmate/intrinsic_functions.rb +94 -38
  8. data/lib/stackmate/logging.rb +19 -19
  9. data/lib/stackmate/participants/cloudstack.rb +250 -165
  10. data/lib/stackmate/participants/cloudstack_affinitygroup.rb +122 -0
  11. data/lib/stackmate/participants/cloudstack_autoscalepolicy.rb +113 -0
  12. data/lib/stackmate/participants/cloudstack_autoscalevmgroup.rb +86 -0
  13. data/lib/stackmate/participants/cloudstack_autoscalevmprofile.rb +140 -0
  14. data/lib/stackmate/participants/cloudstack_condition.rb +122 -0
  15. data/lib/stackmate/participants/cloudstack_egressfirewallrule.rb +149 -0
  16. data/lib/stackmate/participants/cloudstack_firewallrule.rb +149 -0
  17. data/lib/stackmate/participants/cloudstack_globalloadbalancerrule.rb +158 -0
  18. data/lib/stackmate/participants/cloudstack_instancegroup.rb +113 -0
  19. data/lib/stackmate/participants/cloudstack_ipaddress.rb +149 -0
  20. data/lib/stackmate/participants/cloudstack_ipforwardingrule.rb +131 -0
  21. data/lib/stackmate/participants/cloudstack_iptonic.rb +95 -0
  22. data/lib/stackmate/participants/cloudstack_iso.rb +95 -0
  23. data/lib/stackmate/participants/cloudstack_lbhealthcheckpolicy.rb +140 -0
  24. data/lib/stackmate/participants/cloudstack_lbstickinesspolicy.rb +122 -0
  25. data/lib/stackmate/participants/cloudstack_loadbalancer.rb +158 -0
  26. data/lib/stackmate/participants/cloudstack_loadbalancerrule.rb +185 -0
  27. data/lib/stackmate/participants/cloudstack_network.rb +293 -0
  28. data/lib/stackmate/participants/cloudstack_networkacl.rb +176 -0
  29. data/lib/stackmate/participants/cloudstack_networkacllist.rb +104 -0
  30. data/lib/stackmate/participants/cloudstack_nictovirtualmachine.rb +104 -0
  31. data/lib/stackmate/participants/cloudstack_portforwardingrule.rb +176 -0
  32. data/lib/stackmate/participants/cloudstack_project.rb +113 -0
  33. data/lib/stackmate/participants/cloudstack_remoteaccessvpn.rb +122 -0
  34. data/lib/stackmate/participants/cloudstack_securitygroup.rb +122 -0
  35. data/lib/stackmate/participants/cloudstack_securitygroupegress.rb +185 -0
  36. data/lib/stackmate/participants/cloudstack_securitygroupingress.rb +185 -0
  37. data/lib/stackmate/participants/cloudstack_snapshot.rb +113 -0
  38. data/lib/stackmate/participants/cloudstack_snapshotpolicy.rb +122 -0
  39. data/lib/stackmate/participants/cloudstack_sshkeypair.rb +113 -0
  40. data/lib/stackmate/participants/cloudstack_staticnat.rb +113 -0
  41. data/lib/stackmate/participants/cloudstack_staticroute.rb +95 -0
  42. data/lib/stackmate/participants/cloudstack_tags.rb +113 -0
  43. data/lib/stackmate/participants/cloudstack_template.rb +212 -0
  44. data/lib/stackmate/participants/cloudstack_togloballoadbalancerrule.rb +104 -0
  45. data/lib/stackmate/participants/cloudstack_toloadbalancerrule.rb +95 -0
  46. data/lib/stackmate/participants/cloudstack_virtualmachine.rb +348 -0
  47. data/lib/stackmate/participants/cloudstack_virtualmachineops.rb +95 -0
  48. data/lib/stackmate/participants/cloudstack_vmsnapshot.rb +113 -0
  49. data/lib/stackmate/participants/cloudstack_volume.rb +176 -0
  50. data/lib/stackmate/participants/cloudstack_volumeops.rb +111 -0
  51. data/lib/stackmate/participants/cloudstack_vpc.rb +158 -0
  52. data/lib/stackmate/participants/cloudstack_vpnconnection.rb +95 -0
  53. data/lib/stackmate/participants/cloudstack_vpncustomergateway.rb +176 -0
  54. data/lib/stackmate/participants/cloudstack_vpngateway.rb +86 -0
  55. data/lib/stackmate/participants/cloudstack_vpnuser.rb +122 -0
  56. data/lib/stackmate/participants/common.rb +219 -70
  57. data/lib/stackmate/participants/stacknest.rb +6 -0
  58. data/lib/stackmate/resolver.rb +122 -0
  59. data/lib/stackmate/stack.rb +116 -60
  60. data/lib/stackmate/stack_executor.rb +99 -37
  61. data/lib/stackmate/stackpi.rb +46 -0
  62. data/lib/stackmate/version.rb +1 -1
  63. data/lib/stackmate/waitcondition_server.rb +15 -15
  64. data/lib/stackmate.rb +1 -1
  65. data/stackmate.gemspec +2 -4
  66. 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 WaitConditionHandle < Ruote::Participant
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
- def on_workitem
12
- logger.debug "Entering #{participant_name} "
13
- workitem[participant_name] = {}
14
- presigned_url = 'http://localhost:4567/waitcondition/' + workitem.fei.wfid + '/' + participant_name
15
- workitem.fields['ResolvedNames'][participant_name] = presigned_url
16
- logger.info "Your pre-signed URL is: #{presigned_url} "
17
- logger.info "Try: \ncurl -X PUT --data 'foo' #{presigned_url}"
18
- WaitCondition.create_handle(participant_name, presigned_url)
19
- workitem[participant_name][:physical_id] = presigned_url
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
- reply
22
- end
23
- end
24
-
25
- class WaitCondition < Ruote::Participant
26
- include Logging
27
- @@handles = {}
28
- @@conditions = []
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
- def self.create_handle(handle_name, handle)
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
- end
88
+ end
89
+
90
+ def self.delete_handle(handle_name)
91
+ @@handles.delete(handle_name)
92
+ end
41
93
 
42
- def set_handle(handle_name)
94
+ def set_handle(handle_name)
43
95
  reply(workitem) if @@handles[handle_name]
44
- end
96
+ end
45
97
 
46
- def self.get_conditions()
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
- end
50
-
51
- class Output < Ruote::Participant
52
- include Logging
53
- include Intrinsic
54
-
55
- def on_workitem
56
- #p workitem.fields.keys
57
- logger.debug "Entering #{workitem.participant_name} "
58
- outputs = workitem.fields['Outputs']
59
- logger.debug "In StackMate::Output.on_workitem #{outputs.inspect}"
60
- outputs.each do |key, val|
61
- v = val['Value']
62
- constructed_value = intrinsic(v, workitem)
63
- val['Value'] = constructed_value
64
- logger.debug "Output: key = #{key}, value = #{constructed_value} descr = #{val['Description']}"
65
- end
66
-
67
- logger.debug "Output Done"
68
- reply
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
- end
71
-
72
- class NoOpResource < Ruote::Participant
73
- include Logging
74
-
75
- def on_workitem
76
- logger.debug "Entering #{participant_name} wfid=#{workitem.fei.wfid} fei=#{workitem.fei.to_h}"
77
- workitem[participant_name] = {}
78
- stackname = workitem.fields['ResolvedNames']['AWS::StackName']
79
- logger.debug "physical id is #{stackname}-#{participant_name} "
80
- workitem[participant_name][:physical_id] = stackname + '-' + participant_name
81
- typ = workitem['Resources'][participant_name]['Type']
82
- if AWS_FAKE_ATTRIB_VALUES[typ]
83
- AWS_FAKE_ATTRIB_VALUES[typ].each do |k,v|
84
- workitem[participant_name][k] = v
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,6 @@
1
+ require 'json'
2
+ require 'cloudstack_ruby_client'
3
+ require 'yaml'
4
+ require 'stackmate/logging'
5
+ require 'stackmate/intrinsic_functions'
6
+ require 'stackmate/resolver'
@@ -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
@@ -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
- @stackname = stackname
16
- @resolved = params
17
- @templ = JSON.parse(stackstr)
18
- @templ['StackName'] = @stackname
19
- @param_names = @templ['Parameters']
20
- @deps = {}
21
- @pdeps = {}
22
- validate_param_values
23
- resolve_dependencies()
24
- @templ['ResolvedNames'] = @resolved
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
- #TODO CloudFormation parameters have validity constraints specified
30
- #Use them to validate parameter values (e.g., email addresses)
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
- @templ['Resources'].each { |key,val|
35
- deps = Set.new
36
- pdeps = Set.new
37
- find_refs(key, val, deps, pdeps)
38
- deps << val['DependsOn'] if val['DependsOn']
39
- #print key, " depends on ", deps.to_a, "\n"
40
- @deps[key] = deps.to_a
41
- @pdeps[key] = pdeps.to_a
42
- }
43
- @pdeps.keys.each do |k|
44
- unres = @pdeps[k] - @resolved.keys
45
- if ! unres.empty?
46
- unres.each do |u|
47
- deflt = @param_names[u]['Default']
48
- #print "Found default value ", deflt, " for ", u, "\n" if deflt
49
- @resolved[u] = deflt if deflt
50
- end
51
- unres = @pdeps[k] - @resolved.keys
52
- throw :unresolved, (@pdeps[k] - @resolved.keys) if !unres.empty?
53
- end
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
- case jsn
60
- when Array
61
- jsn.each {|x| find_refs(parent, x, deps, pdeps)}
62
- #print parent, ": ", jsn, "\n"
63
- when Hash
64
- jsn.keys.each do |k|
65
- #TODO Fn::GetAtt
66
- if k == "Ref"
67
- #only resolve dependencies on other resources for now
68
- if !@param_names.keys.index(jsn[k]) && jsn[k] != 'AWS::Region' && jsn[k] != 'AWS::StackId' && jsn[k] != 'AWS::StackName'
69
- deps << jsn[k]
70
- #print parent, ": ", deps.to_a, "\n"
71
- else if @param_names.keys.index(jsn[k])
72
- pdeps << jsn[k]
73
- end
74
- end
75
- else
76
- find_refs(parent, jsn[k], deps, pdeps)
77
- end
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
- return deps
135
+ end
136
+ return deps
81
137
  end
82
138
 
83
139
  def tsort_each_node(&block)
84
- @deps.each_key(&block)
140
+ @deps.each_key(&block)
85
141
  end
86
142
 
87
143
  def tsort_each_child(name, &block)
88
- @deps[name].each(&block) if @deps.has_key?(name)
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