Skip to content

Commit

Permalink
Change set on update (#178)
Browse files Browse the repository at this point in the history
Use a ChangeSet for stack updates.
  • Loading branch information
askreet authored Nov 25, 2016
1 parent 7894df7 commit ed3e624
Show file tree
Hide file tree
Showing 14 changed files with 186 additions and 269 deletions.
30 changes: 24 additions & 6 deletions docs/user-guide/cli.md
Original file line number Diff line number Diff line change
Expand Up @@ -139,12 +139,19 @@ ELB failures which will result in instance replacements.

## `moonshot update`

Update an environment with the latest local CloudFormation template,
and any Parameter updates specified via `--answer-file` or
`--parameter`. If there are new parameters in the template and they
are not specified, the user will be prompted for their values, unless
`--no-interactive` is specified, in which case an error will be
displayed.
Update an environment with the latest local CloudFormation template
using a ChangeSet. Keep all existing parameters, unless they are
specified by `--answer-file` and/or `--parameter`. If there are new
parameters in the template and they are not specified, the user will
be prompted for their values, unless `--no-interactive` is specified,
in which case an error will be displayed.

The user is prompted interactively to accept the ChangeSet, unless
`--no-interactive` is set. `--force` can be specified to automatically
accept the changes. If `--dry-run` is set, the changes are
automatically rejected after being displayed, which can be useful for
seeing what the impact of a template change might be in a given
environment.

### Options

Expand All @@ -164,6 +171,17 @@ See [create][#moonshot-create].

See [create][#moonshot-create].

#### `--force`

Automatically accept the ChangeSet that was generated, without
prompting the user. The changes are still displayed in the log
output.

#### `--dry-run`

Automatically reject the ChangeSet that was generated, after
displaying the changes.

### Examples

Update a single Stack parameter, using the latest template:
Expand Down
95 changes: 0 additions & 95 deletions docs/user-guide/stack_parameter_strategies.md

This file was deleted.

2 changes: 0 additions & 2 deletions lib/moonshot.rb
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,6 @@ module Plugins
'stack_config',
'stack_lister',
'stack_events_poller',
'merge_strategy',
'default_strategy',
'ask_user_source',
'always_use_default_source',

Expand Down
100 changes: 100 additions & 0 deletions lib/moonshot/change_set.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
module Moonshot
class ChangeSet
attr_reader :name
attr_reader :stack_name

def initialize(name, stack_name)
@name = name
@stack_name = stack_name
@change_set = nil
@cf_client = Aws::CloudFormation::Client.new
end

def confirm?
unless Moonshot.config.interactive
raise 'Cannot confirm ChangeSet when interactive mode is disabled!'
end

loop do
print 'Apply changes? '
resp = gets.chomp.downcase

return true if resp == 'yes'
return false if resp == 'no'
puts "Please enter 'yes' or 'no'!"
end
end

def valid?
@change_set.status == 'CREATE_COMPLETE'
end

def invalid_reason
@change_set.status_reason
end

def display_changes
wait_for_change_set unless @change_set

@change_set.changes.map(&:resource_change).each do |c|
puts "* #{c.action} #{c.logical_resource_id} (#{c.resource_type})"

if c.replacement == 'True'
puts ' - Will be replaced'
elsif c.replacement == 'Conditional'
puts ' - May be replaced (Conditional)'
end

c.details.each do |d|
case d.change_source
when 'ResourceReference', 'ParameterReference'
puts " - Caused by #{d.causing_entity.blue} (#{d.change_source})"
when 'DirectModification'
puts " - Caused by template change (#{d.target.attribute}: #{d.target.name})"
end
end
end
end

def execute
wait_for_change_set unless @change_set
@cf_client.execute_change_set(
change_set_name: @name,
stack_name: @stack_name)
end

def delete
wait_for_change_set unless @change_set
@cf_client.delete_change_set(
change_set_name: @name,
stack_name: @stack_name)
rescue Aws::CloudFormation::Errors::InvalidChangeSetStatus
sleep 1
retry
end

# NOTE: At the time of this patch, AWS-SDK native Waiters do not
# have support for ChangeSets. Once they add this, we can make
# this code much better.
def wait_for_change_set
start = Time.now.to_i

loop do
resp = @cf_client.describe_change_set(
change_set_name: @name,
stack_name: @stack_name)

if %w(CREATE_COMPLETE FAILED).include?(resp.status)
@change_set = resp
return
end

if Time.now.to_i > start + 30
raise 'ChangeSet did not complete creation within 30 seconds!'
end

sleep 0.25 # http://bit.ly/1qY1ZXJ
end
end
end
end
24 changes: 12 additions & 12 deletions lib/moonshot/commands/update.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,22 +8,22 @@ class Update < Moonshot::Command
self.usage = 'update [options]'
self.description = 'Update the CloudFormation stack within an environment.'

def execute
controller.update
end
def parser
parser = super

private
parser.on('--dry-run', TrueClass, 'Show the changes that would be applied, but do not execute them') do |v| # rubocop:disable LineLength
@dry_run = v
end

def parameter_strategy_factory(value)
case value.to_sym
when :default
Moonshot::ParameterStrategy::DefaultStrategy.new
when :merge
Moonshot::ParameterStrategy::MergeStrategy.new
else
raise "Unknown parameter strategy: #{value}"
parser.on('--force', '-f', TrueClass, 'Apply ChangeSet without confirmation') do |v|
@force = v
end
end

def execute
@force = true unless Moonshot.config.interactive
controller.update(dry_run: @dry_run, force: @force)
end
end
end
end
4 changes: 2 additions & 2 deletions lib/moonshot/controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ def create # rubocop:disable AbcSize
end
end

def update # rubocop:disable AbcSize
def update(dry_run:, force:) # rubocop:disable AbcSize
# Scan the template for all required parameters and configure
# the ParameterCollection.
@config.parameters = ParameterCollection.from_template(stack.template)
Expand Down Expand Up @@ -119,7 +119,7 @@ def update # rubocop:disable AbcSize
end

run_hook(:deploy, :pre_update)
stack.update
stack.update(dry_run: dry_run, force: force)
run_hook(:deploy, :post_update)
run_plugins(:post_update)
end
Expand Down
1 change: 0 additions & 1 deletion lib/moonshot/controller_config.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
require_relative 'default_strategy'
require_relative 'ssh_config'
require_relative 'task'
require_relative 'ask_user_source'
Expand Down
16 changes: 0 additions & 16 deletions lib/moonshot/default_strategy.rb

This file was deleted.

31 changes: 0 additions & 31 deletions lib/moonshot/merge_strategy.rb

This file was deleted.

Loading

0 comments on commit ed3e624

Please sign in to comment.