class CfDeployer::Stack

Constants

FAILED_STATS
READY_STATS
SUCCESS_STATS

Public Class Methods

new(stack_name, component, context) click to toggle source
# File lib/cf_deployer/stack.rb, line 11
def initialize(stack_name, component, context)
  @stack_name = stack_name
  @cf_driver = context[:cf_driver] || CfDeployer::Driver::CloudFormation.new(stack_name)
  @context = context
  @component = component
end

Public Instance Methods

delete() click to toggle source
# File lib/cf_deployer/stack.rb, line 64
def delete
  if exists?
    CfDeployer::Driver::DryRun.guard "Skipping delete" do
      Log.info "deleting stack #{@stack_name}"
      @cf_driver.delete_stack
      wait_for_stack_to_delete
    end
  end
end
deploy() click to toggle source
# File lib/cf_deployer/stack.rb, line 18
def deploy
  config_dir = @context[:config_dir]
  template = CfDeployer::ConfigLoader.erb_to_json(@component, @context)
  capabilities = @context[:capabilities] || []
  notify = @context[:notify] || []
  tags = @context[:tags] || {}
  params = to_str(@context[:inputs].select{|key, value| @context[:defined_parameters].keys.include?(key)})
  CfDeployer::Driver::DryRun.guard "Skipping deploy" do
    if exists?
      override_policy_json = nil
      unless @context[:settings][:'override-stack-policy'].nil?
        override_policy_json = CfDeployer::ConfigLoader.erb_to_json(@context[:settings][:'override-stack-policy'], @context)
      end
      update_stack(template, params, capabilities, tags, override_policy_json)
    else
      create_policy_json = nil
      unless @context[:settings][:'create-stack-policy'].nil?
        create_policy_json = CfDeployer::ConfigLoader.erb_to_json(@context[:settings][:'create-stack-policy'], @context)
      end
      create_stack(template, params, capabilities, tags, notify, create_policy_json)
    end
  end
end
exists?() click to toggle source
# File lib/cf_deployer/stack.rb, line 74
def exists?
  @cf_driver.stack_exists?
end
find_output(key) click to toggle source
# File lib/cf_deployer/stack.rb, line 56
def find_output key
  begin
    @cf_driver.query_output(key)
  rescue AWS::CloudFormation::Errors::ValidationError => e
    raise ResourceNotInReadyState.new("Resource stack not in ready state yet, perhaps you should provision it first?")
  end
end
name() click to toggle source
# File lib/cf_deployer/stack.rb, line 107
def name
  @stack_name
end
output(key) click to toggle source
# File lib/cf_deployer/stack.rb, line 52
def output key
  find_output(key) || (raise ApplicationError.new("'#{key}' is empty from stack #{name} output"))
end
outputs() click to toggle source
# File lib/cf_deployer/stack.rb, line 42
def outputs
  return {} unless ready?
  @cf_driver.outputs
end
parameters() click to toggle source
# File lib/cf_deployer/stack.rb, line 47
def parameters
  return {} unless ready?
  @cf_driver.parameters
end
ready?() click to toggle source
# File lib/cf_deployer/stack.rb, line 78
def ready?
  READY_STATS.include? @cf_driver.stack_status
end
resource_statuses() click to toggle source
# File lib/cf_deployer/stack.rb, line 90
def resource_statuses
  AWS.memoize do
    resources = @cf_driver.resource_statuses.merge( { :asg_instances => {}, :instances => {} } )
    if resources['AWS::AutoScaling::AutoScalingGroup']
      resources['AWS::AutoScaling::AutoScalingGroup'].keys.each do |asg_name|
        resources[:asg_instances][asg_name] = CfDeployer::Driver::AutoScalingGroup.new(asg_name).instance_statuses
      end
    end
    if resources['AWS::EC2::Instance']
      resources['AWS::EC2::Instance'].keys.each do |instance_id|
        resources[:instances][instance_id] = CfDeployer::Driver::Instance.new(instance_id).status
      end
    end
    resources
  end
end
status() click to toggle source
# File lib/cf_deployer/stack.rb, line 82
def status
  if exists?
    ready? ? :ready : :exists
  else
    :does_not_exist
  end
end
template() click to toggle source
# File lib/cf_deployer/stack.rb, line 111
def template
  @cf_driver.template
end

Private Instance Methods

create_stack(template, params, capabilities, tags, notify, create_policy_json) click to toggle source
# File lib/cf_deployer/stack.rb, line 134
def create_stack(template, params, capabilities, tags, notify, create_policy_json)
  Log.info "Creating stack #{@stack_name}..."
  args = {
    :disable_rollback => true,
    :capabilities => capabilities,
    :notify => notify,
    :tags => reformat_tags(tags),
    :parameters => params
  }
  unless create_policy_json.nil?
    args[:stack_policy_body] = create_policy_json
  end
  @cf_driver.create_stack(template, args)
  wait_for_stack_op_terminate
end
reformat_tags(tags_hash) click to toggle source
# File lib/cf_deployer/stack.rb, line 181
def reformat_tags tags_hash
  tags_hash.keys.map { |key| { 'Key' => key.to_s, 'Value' => tags_hash[key].to_s } }
end
stack_status() click to toggle source
# File lib/cf_deployer/stack.rb, line 150
def stack_status
  @cf_driver.stack_status
end
to_str(hash) click to toggle source
# File lib/cf_deployer/stack.rb, line 117
def to_str(hash)
  hash.each { |k,v| hash[k] = v.to_s }
end
update_stack(template, params, capabilities, tags, override_policy_json) click to toggle source
# File lib/cf_deployer/stack.rb, line 121
def update_stack(template, params, capabilities, tags, override_policy_json)
  Log.info "Updating stack #{@stack_name}..."
  args = {
    :capabilities => capabilities,
    :parameters => params
  }
  unless override_policy_json.nil?
    args[:stack_policy_during_update_body] = override_policy_json
  end
  stack_updated = @cf_driver.update_stack(template, args)
  wait_for_stack_op_terminate if stack_updated
end
wait_for_stack_op_terminate() click to toggle source
# File lib/cf_deployer/stack.rb, line 154
def wait_for_stack_op_terminate
  stats = stack_status
  while !SUCCESS_STATS.include?(stats)
    sleep 15
    stats = stack_status
    raise ApplicationError.new("Resource stack update failed!") if FAILED_STATS.include? stats
    Log.info "current status: #{stack_status}"
  end
end
wait_for_stack_to_delete() click to toggle source
# File lib/cf_deployer/stack.rb, line 164
def wait_for_stack_to_delete
  Timeout::timeout(900){
    while exists?
      begin
        Log.info "current status: #{stack_status}"
        sleep 15
      rescue AWS::CloudFormation::Errors::ValidationError => e
        if e.message =~ /does not exist/
          break # This is what we wanted anyways
        else
          raise e
        end
      end
    end
  }
end