miasma-aws 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,86 @@
1
+ require 'miasma'
2
+
3
+ module Miasma
4
+ module Models
5
+ class AutoScale
6
+ class Aws < AutoScale
7
+
8
+ # Service name of the API
9
+ API_SERVICE = 'autoscaling'
10
+ # Supported version of the AutoScaling API
11
+ API_VERSION = '2011-01-01'
12
+
13
+ include Contrib::AwsApiCore::ApiCommon
14
+ include Contrib::AwsApiCore::RequestUtils
15
+
16
+ # Save auto scale group
17
+ #
18
+ # @param group [Models::AutoScale::Group]
19
+ # @return [Models::AutoScale::Group]
20
+ def group_save(group)
21
+ raise NotImplementedError
22
+ end
23
+
24
+ # Reload the group data from the API
25
+ #
26
+ # @param group [Models::AutoScale::Group]
27
+ # @return [Models::AutoScale::Group]
28
+ def group_reload(group)
29
+ if(group.id || group.name)
30
+ load_group_data(group)
31
+ end
32
+ group
33
+ end
34
+
35
+ # Delete auto scale group
36
+ #
37
+ # @param group [Models::AutoScale::Group]
38
+ # @return [TrueClass, FalseClass]
39
+ def group_destroy(group)
40
+ raise NotImplemented
41
+ end
42
+
43
+ # Fetch groups or update provided group data
44
+ #
45
+ # @param group [Models::AutoScale::Group]
46
+ # @return [Array<Models::AutoScale::Group>]
47
+ def load_group_data(group=nil)
48
+ params = Smash.new('Action' => 'DescribeAutoScalingGroups')
49
+ if(group)
50
+ params.merge('AutoScalingGroupNames.member.1' => group.id || group.name)
51
+ end
52
+ result = all_result_pages(nil, :body, 'DescribeAutoScalingGroupsResponse', 'DescribeAutoScalingGroupsResult', 'AutoScalingGroups', 'member') do |options|
53
+ request(
54
+ :path => '/',
55
+ :params => options.merge(params)
56
+ )
57
+ end.map do |grp|
58
+ (group || Group.new(self)).load_data(
59
+ :id => grp['AutoScalingGroupName'],
60
+ :name => grp['AutoScalingGroupName'],
61
+ :servers => [grp.get('Instances', 'member')].flatten(1).compact.map{|i|
62
+ Group::Server.new(self, :id => i['InstanceId'])
63
+ },
64
+ :minimum_size => grp['MinSize'],
65
+ :maximum_size => grp['MaxSize'],
66
+ :status => grp['Status'],
67
+ :load_balancers => [grp.get('LoadBalancerNames', 'member')].flatten(1).compact.map{|i|
68
+ Group::Balancer.new(self, :id => i, :name => i)
69
+ }
70
+ ).valid_state
71
+ end
72
+ end
73
+
74
+
75
+ # Return all auto scale groups
76
+ #
77
+ # @param options [Hash] filter
78
+ # @return [Array<Models::AutoScale::Group>]
79
+ def group_all(options={})
80
+ load_group_data
81
+ end
82
+
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,113 @@
1
+ require 'miasma'
2
+
3
+ module Miasma
4
+
5
+ module Models
6
+ class Compute
7
+ # Compute interface for AWS
8
+ class Aws < Compute
9
+
10
+ # Service name of the API
11
+ API_SERVICE = 'ec2'
12
+ # Supported version of the EC2 API
13
+ API_VERSION = '2014-06-15'
14
+
15
+ include Contrib::AwsApiCore::ApiCommon
16
+ include Contrib::AwsApiCore::RequestUtils
17
+
18
+ # @return [Smash] map state to valid internal values
19
+ SERVER_STATE_MAP = Smash.new(
20
+ 'running' => :running,
21
+ 'pending' => :pending,
22
+ 'shutting-down' => :pending,
23
+ 'terminated' => :terminated,
24
+ 'stopping' => :pending,
25
+ 'stopped' => :stopped
26
+ )
27
+
28
+ # @todo catch bad lookup and clear model
29
+ def server_reload(server)
30
+ result = request(
31
+ :path => '/',
32
+ :params => {
33
+ 'Action' => 'DescribeInstances',
34
+ 'InstanceId.1' => server.id
35
+ }
36
+ )
37
+ srv = result.get(:body, 'DescribeInstancesResponse', 'reservationSet', 'item', 'instancesSet', 'item')
38
+ server.load_data(
39
+ :id => srv[:instanceId],
40
+ :name => srv.fetch(:tagSet, :item, []).map{|tag| tag[:value] if tag.is_a?(Hash) && tag[:key] == 'Name'}.compact.first,
41
+ :image_id => srv[:imageId],
42
+ :flavor_id => srv[:instanceType],
43
+ :state => SERVER_STATE_MAP.fetch(srv.get(:instanceState, :name), :pending),
44
+ :addresses_private => [Server::Address.new(:version => 4, :address => srv[:privateIpAddress])],
45
+ :addresses_public => [Server::Address.new(:version => 4, :address => srv[:ipAddress])],
46
+ :status => srv.get(:instanceState, :name),
47
+ :key_name => srv[:keyName]
48
+ )
49
+ server.valid_state
50
+ end
51
+
52
+ def server_destroy(server)
53
+ if(server.persisted?)
54
+ result = request(
55
+ :path => '/',
56
+ :params => {
57
+ 'Action' => 'TerminateInstances',
58
+ 'InstanceId.1' => server.id
59
+ }
60
+ )
61
+ else
62
+ raise "this doesn't even exist"
63
+ end
64
+ end
65
+
66
+ def server_save(server)
67
+ unless(server.persisted?)
68
+ server.load_data(server.attributes)
69
+ result = request(
70
+ :path => '/',
71
+ :params => {
72
+ 'Action' => 'RunInstances',
73
+ 'ImageId' => server.image_id,
74
+ 'InstanceType' => server.flavor_id,
75
+ 'KeyName' => server.key_name,
76
+ 'MinCount' => 1,
77
+ 'MaxCount' => 1
78
+ }
79
+ )
80
+ server.id = result.get(:body, 'RunInstancesResponse', 'instancesSet', 'item', 'instanceId')
81
+ else
82
+ raise 'WAT DO I DO!?'
83
+ end
84
+ end
85
+
86
+ # @todo need to add auto pagination helper (as common util)
87
+ def server_all
88
+ results = all_result_pages(nil, :body, 'DescribeInstancesResponse', 'reservationSet', 'item') do |options|
89
+ request(:path => '/', :params => options.merge('Action' => 'DescribeInstances'))
90
+ end
91
+ results.map do |srv|
92
+ [srv[:instancesSet][:item]].flatten.compact.map do |srv|
93
+ Server.new(
94
+ self,
95
+ :id => srv[:instanceId],
96
+ :name => srv.fetch(:tagSet, :item, []).map{|tag| tag[:value] if tag.is_a?(Hash) && tag[:key] == 'Name'}.compact.first,
97
+ :image_id => srv[:imageId],
98
+ :flavor_id => srv[:instanceType],
99
+ :state => SERVER_STATE_MAP.fetch(srv.get(:instanceState, :name), :pending),
100
+ :addresses_private => [Server::Address.new(:version => 4, :address => srv[:privateIpAddress])],
101
+ :addresses_public => [Server::Address.new(:version => 4, :address => srv[:ipAddress])],
102
+ :status => srv.get(:instanceState, :name),
103
+ :key_name => srv[:keyName]
104
+ ).valid_state
105
+ end
106
+ end.flatten
107
+ end
108
+
109
+ end
110
+ end
111
+ end
112
+
113
+ end
@@ -0,0 +1,187 @@
1
+ require 'miasma'
2
+
3
+ module Miasma
4
+ module Models
5
+ class LoadBalancer
6
+ class Aws < LoadBalancer
7
+
8
+ include Contrib::AwsApiCore::ApiCommon
9
+ include Contrib::AwsApiCore::RequestUtils
10
+
11
+ # Service name of API
12
+ API_SERVICE = 'elasticloadbalancing'
13
+ # Supported version of the ELB API
14
+ API_VERSION = '2012-06-01'
15
+
16
+ # Save load balancer
17
+ #
18
+ # @param balancer [Models::LoadBalancer::Balancer]
19
+ # @return [Models::LoadBalancer::Balancer]
20
+ def balancer_save(balancer)
21
+ unless(balancer.persisted?)
22
+ params = Smash.new(
23
+ 'LoadBalancerName' => balancer.name
24
+ )
25
+ availability_zones.each_with_index do |az, i|
26
+ params["AvailabilityZones.member.#{i+1}"] = az
27
+ end
28
+ if(balancer.listeners)
29
+ balancer.listeners.each_with_index do |listener, i|
30
+ key = "Listeners.member.#{i + 1}"
31
+ params["#{key}.Protocol"] = listener.protocol
32
+ params["#{key}.InstanceProtocol"] = listener.instance_protocol
33
+ params["#{key}.LoadBalancerPort"] = listener.load_balancer_port
34
+ params["#{key}.InstancePort"] = listener.instance_port
35
+ if(listener.ssl_certificate_id)
36
+ params["#{key}.SSLCertificateId"] = listener.ssl_certificate_id
37
+ end
38
+ end
39
+ end
40
+ result = request(
41
+ :path => '/',
42
+ :params => params.merge(
43
+ Smash.new(
44
+ 'Action' => 'CreateLoadBalancer'
45
+ )
46
+ )
47
+ )
48
+ balancer.public_addresses = [
49
+ :address => result.get(:body, 'CreateLoadBalancerResponse', 'CreateLoadBalancerResult', 'DNSName')
50
+ ]
51
+ balancer.load_data(:id => balancer.name).valid_state
52
+ if(balancer.health_check)
53
+ balancer_health_check(balancer)
54
+ end
55
+ if(balancer.servers && !balancer.servers.empty?)
56
+ balancer_set_instances(balancer)
57
+ end
58
+ else
59
+ if(balancer.dirty?)
60
+ if(balancer.dirty?(:health_check))
61
+ balancer_health_check(balancer)
62
+ end
63
+ if(balancer.dirty?(:servers))
64
+ balancer_set_instances(balancer)
65
+ end
66
+ balancer.reload
67
+ end
68
+ balancer
69
+ end
70
+ end
71
+
72
+ # Save the load balancer health check
73
+ #
74
+ # @param balancer [Models::LoadBalancer::Balancer]
75
+ # @return [Models::LoadBalancer::Balancer]
76
+ def balancer_health_check(balancer)
77
+ balancer
78
+ end
79
+
80
+ # Save the load balancer attached servers
81
+ #
82
+ # @param balancer [Models::LoadBalancer::Balancer]
83
+ # @return [Models::LoadBalancer::Balancer]
84
+ def balancer_set_instances(balancer)
85
+ balancer
86
+ end
87
+
88
+ # Reload the balancer data from the API
89
+ #
90
+ # @param balancer [Models::LoadBalancer::Balancer]
91
+ # @return [Models::LoadBalancer::Balancer]
92
+ def balancer_reload(balancer)
93
+ if(balancer.persisted?)
94
+ load_balancer_data(balancer)
95
+ end
96
+ balancer
97
+ end
98
+
99
+ # Fetch balancers or update provided balancer data
100
+ #
101
+ # @param balancer [Models::LoadBalancer::Balancer]
102
+ # @return [Array<Models::LoadBalancer::Balancer>]
103
+ def load_balancer_data(balancer=nil)
104
+ params = Smash.new('Action' => 'DescribeLoadBalancers')
105
+ if(balancer)
106
+ params.merge('LoadBalancerNames.member.1' => balancer.id || balancer.name)
107
+ end
108
+ result = all_result_pages(nil, :body, 'DescribeLoadBalancersResponse', 'DescribeLoadBalancersResult', 'LoadBalancerDescriptions', 'member') do |options|
109
+ request(
110
+ :path => '/',
111
+ :params => options.merge(params)
112
+ )
113
+ end
114
+ result.map do |blr|
115
+ (balancer || Balancer.new(self)).load_data(
116
+ :id => blr['LoadBalancerName'],
117
+ :name => blr['LoadBalancerName'],
118
+ :state => :active,
119
+ :status => 'ACTIVE',
120
+ :created => blr['CreatedTime'],
121
+ :updated => blr['CreatedTime'],
122
+ :public_addresses => [
123
+ Balancer::Address.new(
124
+ :address => blr['DNSName'],
125
+ :version => 4
126
+ )
127
+ ],
128
+ :servers => [blr.get('Instances', 'member')].flatten(1).compact.map{|i|
129
+ Balancer::Server.new(self.api_for(:compute), :id => i['InstanceId'])
130
+ }
131
+ ).valid_state
132
+ end
133
+ end
134
+
135
+ # Delete load balancer
136
+ #
137
+ # @param balancer [Models::LoadBalancer::Balancer]
138
+ # @return [TrueClass, FalseClass]
139
+ def balancer_destroy(balancer)
140
+ if(balancer.persisted?)
141
+ request(
142
+ :path => '/',
143
+ :params => Smash.new(
144
+ 'Action' => 'DeleteLoadBalancer',
145
+ 'LoadBalancerName' => balancer.name
146
+ )
147
+ )
148
+ balancer.state = :pending
149
+ balancer.status = 'DELETE_IN_PROGRESS'
150
+ balancer.valid_state
151
+ true
152
+ else
153
+ false
154
+ end
155
+ end
156
+
157
+ # Return all load balancers
158
+ #
159
+ # @param options [Hash] filter
160
+ # @return [Array<Models::LoadBalancer::Balancer>]
161
+ def balancer_all(options={})
162
+ load_balancer_data
163
+ end
164
+
165
+ protected
166
+
167
+ # @return [Array<String>] availability zones
168
+ def availability_zones
169
+ memoize(:availability_zones) do
170
+ res = api_for(:compute).request(
171
+ :path => '/',
172
+ :params => Smash.new(
173
+ 'Action' => 'DescribeAvailabilityZones'
174
+ )
175
+ ).fetch(:body, 'DescribeAvailabilityZonesResponse', 'availabilityZoneInfo', 'item', [])
176
+ [res].flatten.compact.map do |item|
177
+ if(item['zoneState'] == 'available')
178
+ item['zoneName']
179
+ end
180
+ end.compact
181
+ end
182
+ end
183
+
184
+ end
185
+ end
186
+ end
187
+ end
@@ -0,0 +1,350 @@
1
+ require 'miasma'
2
+
3
+ module Miasma
4
+ module Models
5
+ class Orchestration
6
+ class Aws < Orchestration
7
+
8
+ # Service name of the API
9
+ API_SERVICE = 'cloudformation'
10
+ # Supported version of the AutoScaling API
11
+ API_VERSION = '2010-05-15'
12
+
13
+ # Valid stack lookup states
14
+ STACK_STATES = [
15
+ "CREATE_COMPLETE", "CREATE_FAILED", "CREATE_IN_PROGRESS", "DELETE_FAILED",
16
+ "DELETE_IN_PROGRESS", "ROLLBACK_COMPLETE", "ROLLBACK_FAILED", "ROLLBACK_IN_PROGRESS",
17
+ "UPDATE_COMPLETE", "UPDATE_COMPLETE_CLEANUP_IN_PROGRESS", "UPDATE_IN_PROGRESS",
18
+ "UPDATE_ROLLBACK_COMPLETE", "UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS", "UPDATE_ROLLBACK_FAILED",
19
+ "UPDATE_ROLLBACK_IN_PROGRESS"
20
+ ]
21
+
22
+ include Contrib::AwsApiCore::ApiCommon
23
+ include Contrib::AwsApiCore::RequestUtils
24
+
25
+ # @return [Smash] external to internal resource mapping
26
+ RESOURCE_MAPPING = Smash.new(
27
+ 'AWS::EC2::Instance' => Smash.new(
28
+ :api => :compute,
29
+ :collection => :servers
30
+ ),
31
+ 'AWS::ElasticLoadBalancing::LoadBalancer' => Smash.new(
32
+ :api => :load_balancer,
33
+ :collection => :balancers
34
+ ),
35
+ 'AWS::AutoScaling::AutoScalingGroup' => Smash.new(
36
+ :api => :auto_scale,
37
+ :collection => :groups
38
+ )
39
+ )
40
+
41
+ # Fetch stacks or update provided stack data
42
+ #
43
+ # @param stack [Models::Orchestration::Stack]
44
+ # @return [Array<Models::Orchestration::Stack>]
45
+ def load_stack_data(stack=nil)
46
+ d_params = Smash.new('Action' => 'DescribeStacks')
47
+ l_params = Smash.new('Action' => 'ListStacks')
48
+ STACK_STATES.each_with_index do |state, idx|
49
+ l_params["StackStatusFilter.member.#{idx + 1}"] = state.to_s.upcase
50
+ end
51
+ if(stack)
52
+ d_params['StackName'] = stack.id
53
+ descriptions = all_result_pages(nil, :body, 'DescribeStacksResponse', 'DescribeStacksResult', 'Stacks', 'member') do |options|
54
+ request(
55
+ :path => '/',
56
+ :params => options.merge(d_params)
57
+ )
58
+ end
59
+ else
60
+ descriptions = []
61
+ end
62
+ lists = all_result_pages(nil, :body, 'ListStacksResponse', 'ListStacksResult', 'StackSummaries', 'member') do |options|
63
+ request(
64
+ :path => '/',
65
+ :params => options.merge(l_params)
66
+ )
67
+ end.map do |stk|
68
+ desc = descriptions.detect do |d_stk|
69
+ d_stk['StackId'] == stk['StackId']
70
+ end || Smash.new
71
+ stk.merge!(desc)
72
+ if(stack)
73
+ next if stack.id != stk['StackId'] && stk['StackId'].split('/')[1] != stack.id
74
+ end
75
+ new_stack = stack || Stack.new(self)
76
+ new_stack.load_data(
77
+ :id => stk['StackId'],
78
+ :name => stk['StackName'],
79
+ :capabilities => [stk.get('Capabilities', 'member')].flatten(1).compact,
80
+ :description => stk['Description'],
81
+ :created => stk['CreationTime'],
82
+ :updated => stk['LastUpdatedTime'],
83
+ :notification_topics => [stk.get('NotificationARNs', 'member')].flatten(1).compact,
84
+ :timeout_in_minutes => stk['TimeoutInMinutes'] ? stk['TimeoutInMinutes'].to_i : nil,
85
+ :status => stk['StackStatus'],
86
+ :status_reason => stk['StackStatusReason'],
87
+ :state => stk['StackStatus'].downcase.to_sym,
88
+ :template_description => stk['TemplateDescription'],
89
+ :disable_rollback => !!stk['DisableRollback'],
90
+ :outputs => [stk.get('Outputs', 'member')].flatten(1).compact.map{|o|
91
+ Smash.new(
92
+ :key => o['OutputKey'],
93
+ :value => o['OutputValue'],
94
+ :description => o['Description']
95
+ )
96
+ },
97
+ :parameters => Smash[
98
+ [stk.fetch('Parameters', 'member', [])].flatten(1).map{|param|
99
+ [param['ParameterKey'], param['ParameterValue']]
100
+ }
101
+ ]
102
+ ).valid_state
103
+ end
104
+ end
105
+
106
+ # Save the stack
107
+ #
108
+ # @param stack [Models::Orchestration::Stack]
109
+ # @return [Models::Orchestration::Stack]
110
+ def stack_save(stack)
111
+ params = Smash.new('StackName' => stack.name)
112
+ (stack.parameters || {}).each_with_index do |pair, idx|
113
+ params["Parameters.member.#{idx + 1}.ParameterKey"] = pair.first
114
+ params["Parameters.member.#{idx + 1}.ParameterValue"] = pair.last
115
+ end
116
+ (stack.capabilities || []).each_with_index do |cap, idx|
117
+ params["Capabilities.member.#{idx + 1}"] = cap
118
+ end
119
+ (stack.notification_topics || []).each_with_index do |topic, idx|
120
+ params["NotificationARNs.member.#{idx + 1}"] = topic
121
+ end
122
+ if(stack.template.empty?)
123
+ params['UsePreviousTemplate'] = true
124
+ else
125
+ params['TemplateBody'] = MultiJson.dump(stack.template)
126
+ end
127
+ if(stack.persisted?)
128
+ result = request(
129
+ :path => '/',
130
+ :method => :post,
131
+ :params => Smash.new(
132
+ 'Action' => 'UpdateStack'
133
+ ).merge(params)
134
+ )
135
+ stack
136
+ else
137
+ if(stack.timeout_in_minutes)
138
+ params['TimeoutInMinutes'] = stack.timeout_in_minutes
139
+ end
140
+ result = request(
141
+ :path => '/',
142
+ :method => :post,
143
+ :params => Smash.new(
144
+ 'Action' => 'CreateStack',
145
+ 'DisableRollback' => !!stack.disable_rollback
146
+ ).merge(params)
147
+ )
148
+ stack.id = result.get(:body, 'CreateStackResponse', 'CreateStackResult', 'StackId')
149
+ stack.valid_state
150
+ end
151
+ end
152
+
153
+ # Reload the stack data from the API
154
+ #
155
+ # @param stack [Models::Orchestration::Stack]
156
+ # @return [Models::Orchestration::Stack]
157
+ def stack_reload(stack)
158
+ if(stack.persisted?)
159
+ ustack = Stack.new(self)
160
+ ustack.id = stack.id
161
+ load_stack_data(ustack)
162
+ if(ustack.data[:name])
163
+ stack.load_data(ustack.attributes).valid_state
164
+ else
165
+ stack.status = 'DELETE_COMPLETE'
166
+ stack.state = :delete_complete
167
+ stack.valid_state
168
+ end
169
+ end
170
+ stack
171
+ end
172
+
173
+ # Delete the stack
174
+ #
175
+ # @param stack [Models::Orchestration::Stack]
176
+ # @return [TrueClass, FalseClass]
177
+ def stack_destroy(stack)
178
+ if(stack.persisted?)
179
+ request(
180
+ :path => '/',
181
+ :params => Smash.new(
182
+ 'Action' => 'DeleteStack',
183
+ 'StackName' => stack.id
184
+ )
185
+ )
186
+ true
187
+ else
188
+ false
189
+ end
190
+ end
191
+
192
+ # Fetch stack template
193
+ #
194
+ # @param stack [Stack]
195
+ # @return [Smash] stack template
196
+ def stack_template_load(stack)
197
+ if(stack.persisted?)
198
+ result = request(
199
+ :path => '/',
200
+ :params => Smash.new(
201
+ 'Action' => 'GetTemplate',
202
+ 'StackName' => stack.id
203
+ )
204
+ )
205
+ MultiJson.load(
206
+ result.get(:body, 'GetTemplateResponse', 'GetTemplateResult', 'TemplateBody')
207
+ ).to_smash
208
+ else
209
+ Smash.new
210
+ end
211
+ end
212
+
213
+ # Validate stack template
214
+ #
215
+ # @param stack [Stack]
216
+ # @return [NilClass, String] nil if valid, string error message if invalid
217
+ def stack_template_validate(stack)
218
+ begin
219
+ result = request(
220
+ :method => :post,
221
+ :path => '/',
222
+ :params => Smash.new(
223
+ 'Action' => 'ValidateTemplate',
224
+ 'TemplateBody' => MultiJson.dump(stack.template)
225
+ )
226
+ )
227
+ nil
228
+ rescue Error::ApiError::RequestError => e
229
+ MultiXml.parse(e.response.body.to_s).to_smash.get(
230
+ 'ErrorResponse', 'Error', 'Message'
231
+ )
232
+ end
233
+ end
234
+
235
+ # Return single stack
236
+ #
237
+ # @param ident [String] name or ID
238
+ # @return [Stack]
239
+ def stack_get(ident)
240
+ i = Stack.new(self)
241
+ i.id = ident
242
+ i.reload
243
+ i.name ? i : nil
244
+ end
245
+
246
+ # Return all stacks
247
+ #
248
+ # @param options [Hash] filter
249
+ # @return [Array<Models::Orchestration::Stack>]
250
+ # @todo check if we need any mappings on state set
251
+ def stack_all
252
+ load_stack_data
253
+ end
254
+
255
+ # Return all resources for stack
256
+ #
257
+ # @param stack [Models::Orchestration::Stack]
258
+ # @return [Array<Models::Orchestration::Stack::Resource>]
259
+ def resource_all(stack)
260
+ results = all_result_pages(nil, :body, 'DescribeStackResourcesResponse', 'DescribeStackResourcesResult', 'StackResources', 'member') do |options|
261
+ request(
262
+ :path => '/',
263
+ :params => options.merge(
264
+ Smash.new(
265
+ 'Action' => 'DescribeStackResources',
266
+ 'StackName' => stack.id
267
+ )
268
+ )
269
+ )
270
+ end.map do |res|
271
+ Stack::Resource.new(
272
+ stack,
273
+ :id => res['PhysicalResourceId'],
274
+ :name => res['LogicalResourceId'],
275
+ :logical_id => res['LogicalResourceId'],
276
+ :type => res['ResourceType'],
277
+ :state => res['ResourceStatus'].downcase.to_sym,
278
+ :status => res['ResourceStatus'],
279
+ :status_reason => res['ResourceStatusReason'],
280
+ :updated => res['Timestamp']
281
+ ).valid_state
282
+ end
283
+ end
284
+
285
+ # Reload the stack resource data from the API
286
+ #
287
+ # @param resource [Models::Orchestration::Stack::Resource]
288
+ # @return [Models::Orchestration::Resource]
289
+ def resource_reload(resource)
290
+ resource.stack.resources.reload
291
+ resource.stack.resources.get(resource.id)
292
+ end
293
+
294
+ # Return all events for stack
295
+ #
296
+ # @param stack [Models::Orchestration::Stack]
297
+ # @return [Array<Models::Orchestration::Stack::Event>]
298
+ def event_all(stack, evt_id=nil)
299
+ results = all_result_pages(nil, :body, 'DescribeStackEventsResponse', 'DescribeStackEventsResult', 'StackEvents', 'member') do |options|
300
+ request(
301
+ :path => '/',
302
+ :params => options.merge(
303
+ 'Action' => 'DescribeStackEvents',
304
+ 'StackName' => stack.id
305
+ )
306
+ )
307
+ end
308
+ events = results.map do |event|
309
+ Stack::Event.new(
310
+ stack,
311
+ :id => event['EventId'],
312
+ :resource_id => event['PhysicalResourceId'],
313
+ :resource_name => event['LogicalResourceId'],
314
+ :resource_logical_id => event['LogicalResourceId'],
315
+ :resource_state => event['ResourceStatus'].downcase.to_sym,
316
+ :resource_status => event['ResourceStatus'],
317
+ :resource_status_reason => event['ResourceStatusReason'],
318
+ :time => Time.parse(event['Timestamp'])
319
+ ).valid_state
320
+ end
321
+ if(evt_id)
322
+ idx = events.index{|d| e.id == evt_id}
323
+ idx = idx ? idx + 1 : 0
324
+ events.slice(idx, events.size)
325
+ else
326
+ events
327
+ end
328
+ end
329
+
330
+ # Return all new events for event collection
331
+ #
332
+ # @param events [Models::Orchestration::Stack::Events]
333
+ # @return [Array<Models::Orchestration::Stack::Event>]
334
+ def event_all_new(events)
335
+ event_all(events.stack, events.all.first.id)
336
+ end
337
+
338
+ # Reload the stack event data from the API
339
+ #
340
+ # @param resource [Models::Orchestration::Stack::Event]
341
+ # @return [Models::Orchestration::Event]
342
+ def event_reload(event)
343
+ event.stack.events.reload
344
+ event.stack.events.get(event.id)
345
+ end
346
+
347
+ end
348
+ end
349
+ end
350
+ end