stackmate 0.0.4 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|