class StackMaster::Commands::Apply

Constants

TEMPLATE_TOO_LARGE_ERROR_MESSAGE

Public Class Methods

new(*_args) click to toggle source
Calls superclass method StackMaster::Command::new
# File lib/stack_master/commands/apply.rb, line 9
def initialize(*_args)
  super
  @s3_config = @stack_definition.s3
  @from_time = Time.now
end

Public Instance Methods

perform() click to toggle source
# File lib/stack_master/commands/apply.rb, line 15
def perform
  diff_stacks
  ensure_valid_parameters!
  ensure_valid_template_body_size!
  create_or_update_stack
  tail_stack_events unless StackMaster.quiet?
  set_stack_policy
end

Private Instance Methods

abort_if_review_in_progress() click to toggle source
# File lib/stack_master/commands/apply.rb, line 46
def abort_if_review_in_progress
  if stack_exists? && stack.stack_status == "REVIEW_IN_PROGRESS"
    StackMaster.stderr.puts "Stack currently exists and is in #{stack.stack_status}"
    failed! "You will need to delete the stack (#{stack.stack_name}) before continuing"
  end
end
ask_to_cancel_stack_update() click to toggle source
# File lib/stack_master/commands/apply.rb, line 113
def ask_to_cancel_stack_update
  if ask?("Cancel stack update?")
    StackMaster.stdout.puts "Attempting to cancel stack update"
    cf.cancel_update_stack(stack_name: stack_name)
    tail_stack_events
  end
end
ask_update_confirmation!() click to toggle source
# File lib/stack_master/commands/apply.rb, line 138
def ask_update_confirmation!
  unless ask?("Apply change set (y/n)? ")
    ChangeSet.delete(@change_set.id)
    halt! "Stack update aborted"
  end
end
cf() click to toggle source
# File lib/stack_master/commands/apply.rb, line 26
def cf
  @cf ||= StackMaster.cloud_formation_driver
end
create_or_update_stack() click to toggle source
# File lib/stack_master/commands/apply.rb, line 66
def create_or_update_stack
  if stack_exists?
    update_stack
  else
    create_stack
  end
end
create_stack() click to toggle source
# File lib/stack_master/commands/apply.rb, line 74
def create_stack
  upload_files
  if use_change_set?
    create_stack_by_change_set
  else
    create_stack_directly
  end
end
create_stack_by_change_set() click to toggle source
# File lib/stack_master/commands/apply.rb, line 87
def create_stack_by_change_set
  begin
    @change_set = ChangeSet.create(stack_options.merge(change_set_type: 'CREATE'))
    if @change_set.failed?
      ChangeSet.delete(@change_set.id)
      halt!(@change_set.status_reason)
    end

    @change_set.display(StackMaster.stdout)
    unless ask?('Create stack (y/n)? ')
      cf.delete_stack(stack_name: stack_name)
      halt!('Stack creation aborted')
    end
  rescue StackMaster::CtrlC
    cf.delete_stack(stack_name: stack_name)
    raise
  end

  execute_change_set
end
create_stack_directly() click to toggle source
# File lib/stack_master/commands/apply.rb, line 108
def create_stack_directly
  failed!('Stack creation aborted') unless ask?('Create stack (y/n)? ')
  cf.create_stack(stack_options.merge(on_failure: @options.on_failure))
end
diff_stacks() click to toggle source
# File lib/stack_master/commands/apply.rb, line 57
def diff_stacks
  abort_if_review_in_progress
  differ.output_diff
end
differ() click to toggle source
# File lib/stack_master/commands/apply.rb, line 62
def differ
  @differ ||= StackDiffer.new(proposed_stack, stack)
end
ensure_valid_parameters!() click to toggle source
# File lib/stack_master/commands/apply.rb, line 205
def ensure_valid_parameters!
  pv = ParameterValidator.new(stack: @proposed_stack, stack_definition: @stack_definition)
  failed!(pv.error_message) if pv.missing_parameters?
end
ensure_valid_template_body_size!() click to toggle source
# File lib/stack_master/commands/apply.rb, line 210
def ensure_valid_template_body_size!
  if proposed_stack.too_big?(use_s3?)
    failed! TEMPLATE_TOO_LARGE_ERROR_MESSAGE
  end
end
execute_change_set() click to toggle source
# File lib/stack_master/commands/apply.rb, line 199
def execute_change_set
  ChangeSet.execute(@change_set.id, stack_name)
rescue StackMaster::CtrlC
  ask_to_cancel_stack_update
end
files_to_upload() click to toggle source
# File lib/stack_master/commands/apply.rb, line 162
def files_to_upload
  return {} unless use_s3?
  @stack_definition.s3_files.tap do |files|
    files[@stack_definition.s3_template_file_name] = {
      path: @stack_definition.template_file_path,
      body: proposed_stack.template
    }
  end
end
proposed_stack() click to toggle source
# File lib/stack_master/commands/apply.rb, line 38
def proposed_stack
  @proposed_stack ||= Stack.generate(@stack_definition, @config)
end
s3() click to toggle source
# File lib/stack_master/commands/apply.rb, line 30
def s3
  @s3 ||= StackMaster.s3_driver
end
s3_options() click to toggle source
# File lib/stack_master/commands/apply.rb, line 184
def s3_options
  {
    bucket: @s3_config['bucket'],
    prefix: @s3_config['prefix'],
    region: @s3_config['region'],
    files: files_to_upload
  }
end
set_stack_policy() click to toggle source
# File lib/stack_master/commands/apply.rb, line 216
def set_stack_policy
  current_policy = stack && stack.stack_policy_body
  proposed_policy = proposed_stack.stack_policy_body
  # No need to reset a stack policy if it's nil or not changed
  return if proposed_policy.nil? || proposed_policy == current_policy
  StackMaster.stdout.print 'Setting a stack policy...'
  cf.set_stack_policy(
    stack_name: stack_name,
    stack_policy_body: proposed_policy
  )
  StackMaster.stdout.puts 'done.'
end
stack() click to toggle source
# File lib/stack_master/commands/apply.rb, line 34
def stack
  @stack ||= Stack.find(region, stack_name)
end
stack_exists?() click to toggle source
# File lib/stack_master/commands/apply.rb, line 42
def stack_exists?
  !stack.nil?
end
stack_options() click to toggle source
# File lib/stack_master/commands/apply.rb, line 172
def stack_options
  {
    stack_name: stack_name,
    parameters: proposed_stack.aws_parameters,
    tags: proposed_stack.aws_tags,
    capabilities: ['CAPABILITY_IAM', 'CAPABILITY_NAMED_IAM', 'CAPABILITY_AUTO_EXPAND'],
    role_arn: proposed_stack.role_arn,
    notification_arns: proposed_stack.notification_arns,
    template_method => template_value
  }
end
tail_stack_events() click to toggle source
# File lib/stack_master/commands/apply.rb, line 193
def tail_stack_events
  StackEvents::Streamer.stream(stack_name, region, io: StackMaster.stdout, from: @from_time)
rescue StackMaster::CtrlC
  ask_to_cancel_stack_update
end
template_method() click to toggle source
# File lib/stack_master/commands/apply.rb, line 150
def template_method
  use_s3? ? :template_url : :template_body
end
template_value() click to toggle source
# File lib/stack_master/commands/apply.rb, line 154
def template_value
  if use_s3?
    s3.url(bucket: @s3_config['bucket'], prefix: @s3_config['prefix'], region: @s3_config['region'], template: @stack_definition.s3_template_file_name)
  else
    proposed_stack.template
  end
end
update_stack() click to toggle source
# File lib/stack_master/commands/apply.rb, line 121
def update_stack
  upload_files
  @change_set = ChangeSet.create(stack_options)
  if @change_set.failed?
    ChangeSet.delete(@change_set.id)
    halt!(@change_set.status_reason)
  end

  @change_set.display(StackMaster.stdout)
  if differ.single_param_update?(@options.yes_param)
    StackMaster.stdout.puts("Auto-approving update to single parameter #{@options.yes_param}")
  else
    ask_update_confirmation!
  end
  execute_change_set
end
upload_files() click to toggle source
# File lib/stack_master/commands/apply.rb, line 145
def upload_files
  return unless use_s3?
  s3.upload_files(**s3_options)
end
use_change_set?() click to toggle source
# File lib/stack_master/commands/apply.rb, line 83
def use_change_set?
  @options.on_failure.nil?
end
use_s3?() click to toggle source
# File lib/stack_master/commands/apply.rb, line 53
def use_s3?
  !@s3_config.empty?
end