class Dpl::Providers::Cloudformation

Public Instance Methods

deploy() click to toggle source
# File lib/dpl/providers/cloudformation.rb, line 54
def deploy
  stack_exists? ? update : create
  store_events if output_file?
rescue Aws::CloudFormation::Errors::InvalidAccessKeyId
  error :invalid_creds
end
login() click to toggle source
# File lib/dpl/providers/cloudformation.rb, line 50
def login
  info :login
end

Private Instance Methods

assume_role(params) click to toggle source
# File lib/dpl/providers/cloudformation.rb, line 196
def assume_role(params)
  assumed_role = Aws::STS::Client.new(params).assume_role(
    role_arn: sts_assume_role,
    role_session_name: "travis-build-#{build_number}"
  )
  Aws::Credentials.new(
    assumed_role.credentials.access_key_id,
    assumed_role.credentials.secret_access_key,
    assumed_role.credentials.session_token
  )
end
change_set_contains_changes?(change_set) click to toggle source
# File lib/dpl/providers/cloudformation.rb, line 110
def change_set_contains_changes?(change_set)
  data = client.describe_change_set(change_set_name: change_set.id)
  data.status_reason.start_with?(%(The submitted information didn't contain changes))
end
change_set_params(type) click to toggle source
# File lib/dpl/providers/cloudformation.rb, line 102
def change_set_params(type)
  {
    change_set_type: type.to_s.upcase,
    change_set_name: interpolate(str(:change_set_name)),
    description: interpolate(str(:change_set_desc))
  }
end
client() click to toggle source
# File lib/dpl/providers/cloudformation.rb, line 182
def client
  @client ||= Aws::CloudFormation::Client.new(client_options)
end
client_options() click to toggle source
# File lib/dpl/providers/cloudformation.rb, line 186
def client_options
  params = { region:, credentials: }
  params = params.merge(credentials: assume_role(params)) if sts_assume_role?
  params
end
common_params() click to toggle source
# File lib/dpl/providers/cloudformation.rb, line 148
def common_params
  params = {
    stack_name:,
    role_arn:,
    capabilities:,
    parameters:
  }
  params.merge!(template_param)
  @common_params ||= compact(params)
end
create() click to toggle source
# File lib/dpl/providers/cloudformation.rb, line 78
def create
  promote? ? create_stack : create_change_set(:create)
end
create_change_set(type) click to toggle source
# File lib/dpl/providers/cloudformation.rb, line 90
def create_change_set(type)
  info :create_change_set
  set = client.create_change_set(common_params.merge(change_set_params(type)))
  wait_for(:change_set_create_complete, change_set_name: set.id) if wait? && !test?
  info :done
rescue Aws::Waiters::Errors::FailureStateError => e
  raise e unless change_set_contains_changes?(set)

  info :delete_change_set
  client.delete_change_set(change_set_name: set.id)
end
create_stack() click to toggle source
# File lib/dpl/providers/cloudformation.rb, line 82
def create_stack
  info :create_stack
  params = { timeout_in_minutes: create_timeout, on_failure: 'ROLLBACK' }
  client.create_stack(common_params.merge(params))
  stream_events(stack_name, :stack_create_complete) if wait?
  info :done
end
create_timeout() click to toggle source
Calls superclass method
# File lib/dpl/providers/cloudformation.rb, line 166
def create_timeout
  super / 60
end
credentials() click to toggle source
# File lib/dpl/providers/cloudformation.rb, line 192
def credentials
  Aws::Credentials.new(access_key_id, secret_access_key)
end
last_stack() click to toggle source
# File lib/dpl/providers/cloudformation.rb, line 144
def last_stack
  client.describe_stacks(stack_name:)[:stacks].first
end
now() click to toggle source
# File lib/dpl/providers/cloudformation.rb, line 208
def now
  Time.now.strftime('%Y%m%d%H%M%S')
end
parameters() click to toggle source
Calls superclass method
# File lib/dpl/providers/cloudformation.rb, line 159
def parameters
  @parameters ||= Array(super).map do |str|
    key, value = str.split('=', 2)
    { parameter_key: key, parameter_value: value || ENV[key] }
  end
end
promote() click to toggle source
# File lib/dpl/providers/cloudformation.rb, line 71
def promote
  info :promote_stack
  client.update_stack(common_params)
  stream_events(stack_name, :stack_update_complete) if wait?
  info :done
end
stack_exists?() click to toggle source
# File lib/dpl/providers/cloudformation.rb, line 115
def stack_exists?
  stack = last_stack
  stack && stack.stack_status != 'REVIEW_IN_PROGRESS'
rescue Aws::CloudFormation::Errors::ValidationError => e
  raise e unless e.message.include?('does not exist')

  false
end
stack_name() click to toggle source
# File lib/dpl/providers/cloudformation.rb, line 170
def stack_name
  @stack_name ||= "#{stack_name_prefix}#{super}"
end
store_events() click to toggle source
# File lib/dpl/providers/cloudformation.rb, line 138
def store_events
  logs = last_stack.outputs || {}
  logs = logs.map { |log| "#{log[:output_key]}=#{log[:output_value]}" }
  File.write(output_file, logs.join("\n"))
end
stream_events(stack_name, condition) click to toggle source
# File lib/dpl/providers/cloudformation.rb, line 124
def stream_events(stack_name, condition)
  stream = EventStream.new(client, stack_name, method(:info))
  wait_for(condition, stack_name:) unless test? # hmm.
ensure
  stream&.stop
end
template_param() click to toggle source
# File lib/dpl/providers/cloudformation.rb, line 174
def template_param
  str = template
  return { template_url: str } if url?(str)
  return { template_body: read(str) } if file?(str)

  error(:missing_template)
end
update() click to toggle source
# File lib/dpl/providers/cloudformation.rb, line 63
def update
  promote? ? promote : create_change_set(:update)
rescue Aws::CloudFormation::Errors::ValidationError => e
  raise e unless e.message.start_with?('No updates are to be performed')

  info :stack_up_to_date
end
url?(str) click to toggle source
# File lib/dpl/providers/cloudformation.rb, line 212
def url?(str)
  str =~ %r{^https?://}
end
wait_for(cond, params) click to toggle source
# File lib/dpl/providers/cloudformation.rb, line 131
def wait_for(cond, params)
  started_at = Time.now
  timeout = ->(*) { throw :failure if Time.now - started_at > wait_timeout }
  # params = params.merge(max_attempts: nil, delay: 5, before_wait: timeout)
  client.wait_until(cond, params) { |w| w.before_wait(&timeout) }
end