Class: Miasma::Models::Orchestration::Aws

Inherits:
Miasma::Models::Orchestration show all
Includes:
Contrib::AwsApiCore::ApiCommon, Contrib::AwsApiCore::RequestUtils
Defined in:
lib/miasma/contrib/aws/orchestration.rb

Constant Summary collapse

API_SERVICE =

Service name of the API

'cloudformation'
API_VERSION =

Supported version of the AutoScaling API

'2010-05-15'
STACK_STATES =

Valid stack lookup states

[
  "CREATE_COMPLETE", "CREATE_FAILED", "CREATE_IN_PROGRESS", "DELETE_FAILED",
  "DELETE_IN_PROGRESS", "ROLLBACK_COMPLETE", "ROLLBACK_FAILED", "ROLLBACK_IN_PROGRESS",
  "UPDATE_COMPLETE", "UPDATE_COMPLETE_CLEANUP_IN_PROGRESS", "UPDATE_IN_PROGRESS",
  "UPDATE_ROLLBACK_COMPLETE", "UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS", "UPDATE_ROLLBACK_FAILED",
  "UPDATE_ROLLBACK_IN_PROGRESS"
]
RESOURCE_MAPPING =

Returns external to internal resource mapping.

Returns:

  • (Smash)

    external to internal resource mapping

Smash.new(
  'AWS::EC2::Instance' => Smash.new(
    :api => :compute,
    :collection => :servers
  ),
  'AWS::ElasticLoadBalancing::LoadBalancer' => Smash.new(
    :api => :load_balancer,
    :collection => :balancers
  ),
  'AWS::AutoScaling::AutoScalingGroup' => Smash.new(
    :api => :auto_scale,
    :collection => :groups
  )
)

Constants inherited from Miasma::Models::Orchestration

VALID_RESOURCE_STATES

Instance Method Summary collapse

Methods included from Contrib::AwsApiCore::RequestUtils

#all_result_pages

Methods included from Contrib::AwsApiCore::ApiCommon

#api_for, #connect, #connection, #endpoint, included, #make_request, #update_request, #uri_escape

Methods inherited from Miasma::Models::Orchestration

#stacks

Methods inherited from Types::Api

#api_for, #connect, #connection, #endpoint, #format_response, #initialize, #make_request, #provider, #request

Methods included from Utils::Memoization

#_memo, #clear_memoizations!, #memoize, #unmemoize

Methods included from Utils::Lazy

included

Constructor Details

This class inherits a constructor from Miasma::Types::Api

Instance Method Details

#event_all(stack, evt_id = nil) ⇒ Array<Models::Orchestration::Stack::Event>

Return all events for stack



286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
# File 'lib/miasma/contrib/aws/orchestration.rb', line 286

def event_all(stack, evt_id=nil)
  results = all_result_pages(nil, :body, 'DescribeStackEventsResponse', 'DescribeStackEventsResult', 'StackEvents', 'member') do |options|
    request(
      :path => '/',
      :params => options.merge(
        'Action' => 'DescribeStackEvents',
        'StackName' => stack.id
      )
    )
  end
  events = results.map do |event|
    Stack::Event.new(
      stack,
      :id => event['EventId'],
      :resource_id => event['PhysicalResourceId'],
      :resource_name => event['LogicalResourceId'],
      :resource_logical_id => event['LogicalResourceId'],
      :resource_state => event['ResourceStatus'].downcase.to_sym,
      :resource_status => event['ResourceStatus'],
      :resource_status_reason => event['ResourceStatusReason'],
      :time => Time.parse(event['Timestamp'])
    ).valid_state
  end
  if(evt_id)
    idx = events.index{|d| e.id == evt_id}
    idx = idx ? idx + 1 : 0
    events.slice(idx, events.size)
  else
    events
  end
end

#event_all_new(events) ⇒ Array<Models::Orchestration::Stack::Event>

Return all new events for event collection



322
323
324
# File 'lib/miasma/contrib/aws/orchestration.rb', line 322

def event_all_new(events)
  event_all(events.stack, events.all.first.id)
end

#event_reload(event) ⇒ Models::Orchestration::Event

Reload the stack event data from the API

Parameters:

Returns:

  • (Models::Orchestration::Event)


330
331
332
333
# File 'lib/miasma/contrib/aws/orchestration.rb', line 330

def event_reload(event)
  event.stack.events.reload
  event.stack.events.get(event.id)
end

#load_stack_data(stack = nil) ⇒ Array<Models::Orchestration::Stack>

Fetch stacks or update provided stack data

Parameters:

Returns:



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
# File 'lib/miasma/contrib/aws/orchestration.rb', line 45

def load_stack_data(stack=nil)
  d_params = Smash.new('Action' => 'DescribeStacks')
  l_params = Smash.new('Action' => 'ListStacks')
  STACK_STATES.each_with_index do |state, idx|
    l_params["StackStatusFilter.member.#{idx + 1}"] = state.to_s.upcase
  end
  if(stack)
    d_params['StackName'] = stack.id
  end
  descriptions = [
    request(:path => '/', :params => d_params).get(
      :body, 'DescribeStacksResponse', 'DescribeStacksResult', 'Stacks', 'member'
    )
  ].flatten(1).compact
  lists = request(:path => '/', :params => l_params)
  [
    lists.get(
      :body, 'ListStacksResponse', 'ListStacksResult',
      'StackSummaries', 'member'
    )
  ].flatten(1).compact.map do |stk|
    desc = descriptions.detect do |d_stk|
      d_stk['StackId'] == stk['StackId']
    end || Smash.new
    stk.merge!(desc)
    next if stack && stack.id != stk['StackId']
    new_stack = stack || Stack.new(self)
    new_stack.load_data(
      :id => stk['StackId'],
      :name => stk['StackName'],
      :capabilities => [stk.get('Capabilities', 'member')].flatten(1).compact,
      :description => stk['Description'],
      :created => stk['CreationTime'],
      :updated => stk['LastUpdatedTime'],
      :notification_topics => [stk.get('NotificationARNs', 'member')].flatten(1).compact,
      :timeout_in_minutes => stk['TimeoutInMinutes'],
      :status => stk['StackStatus'],
      :status_reason => stk['StackStatusReason'],
      :state => stk['StackStatus'].downcase.to_sym,
      :template_description => stk['TemplateDescription'],
      :disable_rollback => !!stk['DisableRollback'],
      :outputs => [stk.get('Outputs', 'member')].flatten(1).compact.map{|o|
        Smash.new(
          :key => o['OutputKey'],
          :value => o['OutputValue'],
          :description => o['Description']
        )
      },
      :parameters => Smash[
        [stk.fetch('Parameters', 'member', [])].flatten(1).map{|param|
          [param['ParameterKey'], param['ParameterValue']]
        }
      ]
    ).valid_state
  end
end

#resource_all(stack) ⇒ Array<Models::Orchestration::Stack::Resource>

Return all resources for stack



244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
# File 'lib/miasma/contrib/aws/orchestration.rb', line 244

def resource_all(stack)
  result = request(
    :path => '/',
    :params => Smash.new(
      'Action' => 'DescribeStackResources',
      'StackName' => stack.id
    )
  )
  [
    result.fetch(
      :body, 'DescribeStackResourcesResponse',
      'DescribeStackResourcesResult',
      'StackResources', 'member', []
    )
  ].flatten(1).compact.map do |res|
    Stack::Resource.new(
      stack,
      :id => res['PhysicalResourceId'],
      :name => res['LogicalResourceId'],
      :logical_id => res['LogicalResourceId'],
      :type => res['ResourceType'],
      :state => res['ResourceStatus'].downcase.to_sym,
      :status => res['ResourceStatus'],
      :status_reason => res['ResourceStatusReason'],
      :updated => res['Timestamp']
    ).valid_state
  end
end

#resource_reload(resource) ⇒ Models::Orchestration::Resource

Reload the stack resource data from the API

Parameters:

Returns:

  • (Models::Orchestration::Resource)


277
278
279
280
# File 'lib/miasma/contrib/aws/orchestration.rb', line 277

def resource_reload(resource)
  resource.stack.resources.reload
  resource.stack.resources.get(resource.id)
end

#stack_allArray<Models::Orchestration::Stack>

TODO:

check if we need any mappings on state set

Return all stacks

Parameters:

  • options (Hash)

    filter

Returns:



236
237
238
# File 'lib/miasma/contrib/aws/orchestration.rb', line 236

def stack_all
  load_stack_data
end

#stack_destroy(stack) ⇒ TrueClass, FalseClass

Delete the stack

Parameters:

Returns:

  • (TrueClass, FalseClass)


173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/miasma/contrib/aws/orchestration.rb', line 173

def stack_destroy(stack)
  if(stack.persisted?)
    request(
      :path => '/',
      :params => Smash.new(
        'Action' => 'DeleteStack',
        'StackName' => stack.id
      )
    )
    true
  else
    false
  end
end

#stack_reload(stack) ⇒ Models::Orchestration::Stack

Reload the stack data from the API



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
# File 'lib/miasma/contrib/aws/orchestration.rb', line 153

def stack_reload(stack)
  if(stack.persisted?)
    ustack = Stack.new(self)
    ustack.id = stack.id
    load_stack_data(ustack)
    if(ustack.data[:name])
      stack.load_data(ustack.attributes).valid_state
    else
      stack.status = 'DELETE_COMPLETE'
      stack.state = :delete_complete
      stack.valid_state
    end
  end
  stack
end

#stack_save(stack) ⇒ Models::Orchestration::Stack

Save the stack



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
# File 'lib/miasma/contrib/aws/orchestration.rb', line 106

def stack_save(stack)
  params = Smash.new('StackName' => stack.name)
  (stack.parameters || {}).each_with_index do |pair, idx|
    params["Parameters.member.#{idx + 1}.ParameterKey"] = pair.first
    params["Parameters.member.#{idx + 1}.ParameterValue"] = pair.last
  end
  (stack.capabilities || []).each_with_index do |cap, idx|
    params["Capabilities.member.#{idx + 1}"] = cap
  end
  (stack.notification_topics || []).each_with_index do |topic, idx|
    params["NotificationARNs.member.#{idx + 1}"] = topic
  end
  if(stack.template.empty?)
    params['UsePreviousTemplate'] = true
  else
    params['TemplateBody'] = MultiJson.dump(stack.template)
  end
  if(stack.persisted?)
    result = request(
      :path => '/',
      :method => :post,
      :params => Smash.new(
        'Action' => 'UpdateStack'
      ).merge(params)
    )
    stack
  else
    if(stack.timeout_in_minutes)
      params['TimeoutInMinutes'] = stack.timeout_in_minutes
    end
    result = request(
      :path => '/',
      :method => :post,
      :params => Smash.new(
        'Action' => 'CreateStack',
        'DisableRollback' => !!stack.disable_rollback
      ).merge(params)
    )
    stack.id = result.get(:body, 'CreateStackResponse', 'CreateStackResult', 'StackId')
    stack.valid_state
  end
end

#stack_template_load(stack) ⇒ Smash

Fetch stack template

Parameters:

Returns:

  • (Smash)

    stack template



192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/miasma/contrib/aws/orchestration.rb', line 192

def stack_template_load(stack)
  if(stack.persisted?)
    result = request(
      :path => '/',
      :params => Smash.new(
        'Action' => 'GetTemplate',
        'StackName' => stack.id
      )
    )
    MultiJson.load(
      result.get(:body, 'GetTemplateResponse', 'GetTemplateResult', 'TemplateBody')
    ).to_smash
  else
    Smash.new
  end
end

#stack_template_validate(stack) ⇒ NilClass, String

Validate stack template

Parameters:

Returns:

  • (NilClass, String)

    nil if valid, string error message if invalid



213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
# File 'lib/miasma/contrib/aws/orchestration.rb', line 213

def stack_template_validate(stack)
  begin
    result = request(
      :method => :post,
      :path => '/',
      :params => Smash.new(
        'Action' => 'ValidateTemplate',
        'TemplateBody' => MultiJson.dump(stack.template)
      )
    )
    nil
  rescue Error::ApiError::RequestError => e
    MultiXml.parse(e.response.body.to_s).to_smash.get(
      'ErrorResponse', 'Error', 'Message'
    )
  end
end