Class: MinimalPipeline::Cloudformation

Inherits:
Object
  • Object
show all
Defined in:
lib/minimal_pipeline/cloudformation.rb

Overview

Here is an example of how to use this class to deploy CloudFormation Stacks.

“‘ cloudformation = MinimalPipeline::Cloudformation.new

parameters =

'Vpc' => 'vpc-123456',
'AsgSubnets' => %w[sg-one sg-two sg-three],
'ElbSecurityGroup' => 'sg-123456',
'CertName' => 'example'

cloudformation.deploy_stack(‘EXAMPLE_ELB’, parameters, ‘stack.yaml’) name = cloudformation.stack_output(stack_name, ‘LoadBalancerName’) “‘

You will need the following environment variables to be present:

  • ‘AWS_REGION` or `region`

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(wait_max_attempts = 120, wait_delay = 30) ⇒ Cloudformation

Sets up ‘Aws::CloudFormation::Client` Requires environment variable `AWS_REGION` or `region` to be set.

stack create or update is complete. a stack’s status

Parameters:

  • wait_max_attempts (Fixnum) (defaults to: 120)

    Number of attempts to wait until all

  • wait_delay (Fixnum) (defaults to: 30)

    The sleep interval for checking the status of



37
38
39
40
41
42
43
44
45
46
# File 'lib/minimal_pipeline/cloudformation.rb', line 37

def initialize(wait_max_attempts = 120, wait_delay = 30)
  raise 'You must set env variable AWS_REGION or region.' \
    if ENV['AWS_REGION'].nil? && ENV['region'].nil?

  region = ENV['AWS_REGION'] || ENV['region']
  @client = Aws::CloudFormation::Client.new(region: region)
  @wait_max_attempts = wait_max_attempts
  @wait_delay = wait_delay
  @outputs = {}
end

Instance Attribute Details

#clientObject (readonly)

Instance of ‘Aws::CloudFormation::Client`



26
27
28
# File 'lib/minimal_pipeline/cloudformation.rb', line 26

def client
  @client
end

#wait_delayObject

Returns the value of attribute wait_delay.



28
29
30
# File 'lib/minimal_pipeline/cloudformation.rb', line 28

def wait_delay
  @wait_delay
end

#wait_max_attemptsObject

Returns the value of attribute wait_max_attempts.



27
28
29
# File 'lib/minimal_pipeline/cloudformation.rb', line 27

def wait_max_attempts
  @wait_max_attempts
end

Instance Method Details

#deploy_stack(stack_name, parameters, template, capabilities = ['CAPABILITY_IAM']) ⇒ Object

Parameters:

  • stack_name (String)

    The name of the CloudFormation stack

  • stack_parameters (Hash)

    Parameters to be passed into the stack



105
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
# File 'lib/minimal_pipeline/cloudformation.rb', line 105

def deploy_stack(stack_name, parameters, template,
                 capabilities = ['CAPABILITY_IAM'])
  wait_options = {
    max_attempts: @wait_max_attempts,
    delay: @wait_delay
  }

  stack_parameters = {
    stack_name: stack_name,
    template_body: File.read(template),
    capabilities: capabilities,
    parameters: params(parameters)
  }

  unless @client.describe_stacks(stack_name: stack_name).stacks.empty?
    puts 'Updating the existing stack' if ENV['DEBUG']
    @client.update_stack(stack_parameters)
    @client.wait_until(:stack_update_complete, { stack_name: stack_name },
                       wait_options)
  end
rescue Aws::CloudFormation::Errors::ValidationError => error
  if error.to_s.include? 'No updates are to be performed.'
    puts 'Nothing to do.' if ENV['DEBUG']
  elsif error.to_s.include? 'Template error'
    raise error
  else
    puts 'Creating a new stack' if ENV['DEBUG']
    @client.create_stack(stack_parameters)
    @client.wait_until(:stack_create_complete, { stack_name: stack_name },
                       wait_options)
  end
end

#params(parameters) ⇒ Hash

Converts a parameter Hash into a CloudFormation friendly structure

Parameters:

  • parameters (Hash)

    Key value pair of parameters for a CFN stack.

Returns:

  • (Hash)

    CloudFormation friendly data structure of parameter



52
53
54
55
56
57
58
# File 'lib/minimal_pipeline/cloudformation.rb', line 52

def params(parameters)
  parameter_list = []
  parameters.each do |k, v|
    parameter_list.push(parameter_key: k, parameter_value: v)
  end
  parameter_list
end

#stack_exists?(stack_name) ⇒ Boolean

Checks to see if a stack exists

Parameters:

  • stack_name (String)

    The name of the CloudFormation stack

Returns:

  • (Boolean)

    true/false depending on whether or not the stack exists



142
143
144
145
146
147
# File 'lib/minimal_pipeline/cloudformation.rb', line 142

def stack_exists?(stack_name)
  stacks = @client.describe_stacks(stack_name: stack_name).stacks
  !stacks.empty?
rescue ::Aws::CloudFormation::Errors::ValidationError
  false
end

#stack_output(stack, output) ⇒ String

Retrieves the CloudFormation stack output of a single value

Parameters:

  • stack (String)

    The name of the CloudFormation stack

  • output (String)

    The name of the output to fetch the value of

Returns:

  • (String)

    The value of the output for the CloudFormation stack



65
66
67
68
69
70
71
# File 'lib/minimal_pipeline/cloudformation.rb', line 65

def stack_output(stack, output)
  outputs = stack_outputs(stack)
  message = "#{stack.upcase} stack does not have a(n) '#{output}' output!"
  raise message unless outputs.key?(output)

  outputs[output]
end

#stack_outputs(stack, attempt = 1) ⇒ Hash

Retrieves all CloudFormation stack outputs

Parameters:

  • stack (String)

    The name of the CloudFormation stack

Returns:

  • (Hash)

    Key value pairs of stack outputs



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
# File 'lib/minimal_pipeline/cloudformation.rb', line 77

def stack_outputs(stack, attempt = 1)
  response = @client.describe_stacks(stack_name: stack)
  raise "#{stack.upcase} stack does not exist!" if response.stacks.empty?

  @outputs[stack] ||= {}
  if @outputs[stack].empty?
    response.stacks.first.outputs.each do |output|
      @outputs[stack][output.output_key] = output.output_value
    end
  end

  @outputs[stack]
rescue Aws::CloudFormation::Errors::Throttling => error
  raise 'Unable to get stack outputs' if attempt > 5

  delay = attempt * 15
  puts "#{error.message} - Retrying in #{delay}"
  sleep delay
  attempt += 1
  stack_outputs(stack, attempt)
end