cuffsert 0.11.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1be8dd08dce49cf000289c1a1e198026bf48e2c5
4
- data.tar.gz: 3e0846cd94c5273d1ef260105b962c3c3196d6cc
3
+ metadata.gz: 5e2a534e878fbb69920af515d5829138351c4937
4
+ data.tar.gz: 9697ef60c78c97f5823f089d8efd67f95723a411
5
5
  SHA512:
6
- metadata.gz: 75340fd814849e4c1f42f6ec007eac89d20d2f925b599cdaf9ad32e489638ac00808a9879e2361f8c5d5833a2082b3b0f3992f90e2c061d8efa0f3e7ad6e4e3a
7
- data.tar.gz: 92da57f24fb3c7443462404602d22b9a28c615ecd258e648e4bf22640e3441224e48465266f766ffc930b0a639a885e2ba674de7109e602e457d647431c150fa
6
+ metadata.gz: 37643076b4d503a37ac1d12f997c27230a90904386157fcad1b4a668b126b886091f775e4244c9442d62f027e0b40fac9b7cc94e6c5b60c219563cc46da6690d
7
+ data.tar.gz: 46a6d4ba65176322eb3da8c3abb4fe5641ba0157d7885670410849b324880b5090b4c457251d6fed61feb2230e75a1e2e0126d2c49685b22ed28fc327ad702cc
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- cuffsert (0.11.0)
4
+ cuffsert (0.12.0)
5
5
  aws-sdk-cloudformation (~> 1.3.0)
6
6
  aws-sdk-s3 (~> 1.8.0)
7
7
  colorize
data/README.md CHANGED
@@ -14,7 +14,11 @@ If `./my-template.json` has no parameters the above command would create the sta
14
14
 
15
15
  If you also want to provide a value for a stack parameter (whether on creation or update), you can use `-p key=value` to pass parameters. For all other parameters, cuffsert will tell CloudFormation to use the existing value.
16
16
 
17
- Cuffsert can not (yet) be executed without a template in order to only change parameters.
17
+ Cuffsert can also be executed by naming an existing stack and no template in order to only change parameters, e.g.
18
+
19
+ ```bash
20
+ cuffsert -n my-stack -p MyDesiredCapacity=8
21
+ ```
18
22
 
19
23
  ## Parameters under version control
20
24
 
data/bin/cuffdown CHANGED
@@ -1,55 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require 'cuffsert/metadata'
4
- require 'cuffsert/rxcfclient'
5
- require 'yaml'
3
+ require 'cuffdown/main'
6
4
 
7
- module CuffDown
8
- def self.parameters(stack)
9
- (stack[:parameters] || []).map do |param|
10
- {
11
- 'Name' => param[:parameter_key],
12
- 'Value' => param[:parameter_value],
13
- }
14
- end
15
- end
16
-
17
- def self.tags(stack)
18
- (stack[:tags] || []).map do |param|
19
- {
20
- 'Name' => param[:key],
21
- 'Value' => param[:value],
22
- }
23
- end
24
- end
25
-
26
- def self.dump(name, params, tags, output)
27
- result = {
28
- 'Format' => 'v1',
29
- 'Suffix' => name,
30
- 'Parameters' => params,
31
- 'Tags' => tags,
32
- }
33
- YAML.dump(result, output)
34
- end
35
-
36
- def self.run(args)
37
- meta = CuffSert::StackConfig.new
38
- meta.stackname = args[0]
39
- client = CuffSert::RxCFClient.new
40
- stack = client.find_stack_blocking(meta)
41
- unless stack
42
- STDERR.puts "No such stack #{meta.stackname}"
43
- exit(1)
44
- end
45
- stack = stack.to_h
46
- self.dump(
47
- stack[:stack_name],
48
- self.parameters(stack),
49
- self.tags(stack),
50
- STDOUT
51
- )
52
- end
53
- end
54
-
55
- CuffDown.run(ARGV)
5
+ CuffDown.run(ARGV, STDOUT)
data/lib/cuffbase.rb CHANGED
@@ -1,6 +1,12 @@
1
1
  require 'yaml'
2
2
 
3
3
  module CuffBase
4
+ def self.shared_cli_args(opts, args)
5
+ opts.on('--region=aws_region', 'AWS region, overrides env variable AWS_REGION') do |region|
6
+ args[:aws_region] = region
7
+ end
8
+ end
9
+
4
10
  def self.empty_from_template(io)
5
11
  self.template_parameters(io) {|_| nil }
6
12
  end
@@ -0,0 +1,67 @@
1
+ require 'cuffbase'
2
+ require 'cuffsert/metadata'
3
+ require 'cuffsert/rxcfclient'
4
+ require 'optparse'
5
+ require 'yaml'
6
+
7
+ module CuffDown
8
+ def self.parse_cli_args(argv)
9
+ args = {}
10
+ parser = OptionParser.new do |opts|
11
+ opts.banner = 'Output CuffSert-formatted metadata from an existing stack.'
12
+ opts.separator('')
13
+ opts.separator('Usage: cuffdown stack-name')
14
+ CuffBase.shared_cli_args(opts, args)
15
+ end
16
+ stackname, _ = parser.parse(argv)
17
+ args[:stackname] = stackname
18
+ args
19
+ end
20
+
21
+ def self.parameters(stack)
22
+ (stack[:parameters] || []).map do |param|
23
+ {
24
+ 'Name' => param[:parameter_key],
25
+ 'Value' => param[:parameter_value],
26
+ }
27
+ end
28
+ end
29
+
30
+ def self.tags(stack)
31
+ (stack[:tags] || []).map do |param|
32
+ {
33
+ 'Name' => param[:key],
34
+ 'Value' => param[:value],
35
+ }
36
+ end
37
+ end
38
+
39
+ def self.dump(name, params, tags, output)
40
+ result = {
41
+ 'Format' => 'v1',
42
+ 'Suffix' => name,
43
+ 'Parameters' => params,
44
+ 'Tags' => tags,
45
+ }
46
+ YAML.dump(result, output)
47
+ end
48
+
49
+ def self.run(argv, output)
50
+ cli_args = self.parse_cli_args(argv)
51
+ meta = CuffSert::StackConfig.new
52
+ meta.stackname = cli_args[:stackname]
53
+ client = CuffSert::RxCFClient.new(cli_args[:aws_region])
54
+ stack = client.find_stack_blocking(meta)
55
+ unless stack
56
+ STDERR.puts "No such stack #{meta.stackname}"
57
+ exit(1)
58
+ end
59
+ stack = stack.to_h
60
+ self.dump(
61
+ stack[:stack_name],
62
+ self.parameters(stack),
63
+ self.tags(stack),
64
+ output
65
+ )
66
+ end
67
+ end
@@ -16,17 +16,31 @@ module CuffSert
16
16
  end
17
17
 
18
18
  def upload_template_if_oversized(cfargs)
19
- if cfargs[:template_body].nil? && cfargs[:template_url].nil?
19
+ if needs_template_upload?(cfargs)
20
20
  raise 'Template bigger than 51200; please supply --s3-upload-prefix' unless @s3client
21
21
  uri, progress = @s3client.upload(@meta.stack_uri)
22
- [CuffSert.s3_uri_to_https(uri).to_s, progress]
22
+ [CuffSert.s3_uri_to_https(uri, @meta.aws_region).to_s, progress]
23
23
  else
24
24
  [nil, Rx::Observable.empty]
25
25
  end
26
26
  end
27
+
28
+ private
29
+
30
+ def needs_template_upload?(cfargs)
31
+ cfargs[:template_body].nil? &&
32
+ cfargs[:template_url].nil? &&
33
+ !cfargs[:use_previous_template]
34
+ end
27
35
  end
28
36
 
29
37
  class CreateStackAction < BaseAction
38
+ def validate!
39
+ if @meta.stack_uri.nil?
40
+ raise "You need to pass a template to create #{@meta.stackname}" # in #{@meta.aws_region}."
41
+ end
42
+ end
43
+
30
44
  def as_observable
31
45
  cfargs = CuffSert.as_create_stack_args(@meta)
32
46
  upload_uri, maybe_upload = upload_template_if_oversized(cfargs)
@@ -48,43 +62,61 @@ module CuffSert
48
62
  end
49
63
 
50
64
  class UpdateStackAction < BaseAction
65
+ def validate!
66
+ if @meta.stack_uri.nil?
67
+ if @meta.parameters.empty? && @meta.tags.empty?
68
+ raise "Stack update without template needs at least one parameter (-p) or tag (-t)."
69
+ end
70
+ end
71
+ end
72
+
51
73
  def as_observable
52
- cfargs = CuffSert.as_update_change_set(@meta)
74
+ cfargs = CuffSert.as_update_change_set(@meta, @stack)
53
75
  upload_uri, maybe_upload = upload_template_if_oversized(cfargs)
54
76
  cfargs[:template_url] = upload_uri if upload_uri
55
77
  maybe_upload
56
- .concat(@cfclient.prepare_update(cfargs))
57
- .flat_map do |change_set|
58
- if change_set.is_a? Aws::CloudFormation::Types::DescribeChangeSetOutput
59
- Rx::Observable.concat(
60
- Rx::Observable.of(change_set),
61
- Rx::Observable.defer {
62
- if change_set[:status] == 'FAILED'
63
- Rx::Observable.concat(
64
- @cfclient.abort_update(change_set[:change_set_id]),
65
- Abort.new("Update failed: #{change_set[:status_reason]}").as_observable
66
- )
67
- elsif @confirmation.call(@meta, :update, change_set)
68
- Rx::Observable.concat(
69
- @cfclient.update_stack(change_set[:stack_id], change_set[:change_set_id]),
70
- Done.new.as_observable
71
- )
72
- else
73
- Rx::Observable.concat(
74
- @cfclient.abort_update(change_set[:change_set_id]),
75
- Abort.new('User abort!').as_observable
76
- )
77
- end
78
- }
79
- )
78
+ .concat(@cfclient.prepare_update(cfargs).map {|change_set| CuffSert::ChangeSet.new(change_set) })
79
+ .flat_map(&method(:on_event))
80
+ end
81
+
82
+ private
83
+
84
+ def on_event(event)
85
+ Rx::Observable.concat(
86
+ Rx::Observable.just(event),
87
+ Rx::Observable.defer do
88
+ case event
89
+ when CuffSert::ChangeSet
90
+ on_changeset(event.message)
80
91
  else
81
- Rx::Observable.just(change_set)
92
+ Rx::Observable.empty
82
93
  end
83
94
  end
95
+ )
96
+ end
97
+
98
+ def on_changeset(change_set)
99
+ if change_set[:status] == 'FAILED'
100
+ message = "Update failed: #{change_set[:status_reason]}"
101
+ @cfclient.abort_update(change_set[:change_set_id])
102
+ .concat(Abort.new(message).as_observable)
103
+ elsif @confirmation.call(@meta, :update, change_set)
104
+ @cfclient.update_stack(change_set[:stack_id], change_set[:change_set_id])
105
+ .concat(Done.new.as_observable)
106
+ else
107
+ @cfclient.abort_update(change_set[:change_set_id])
108
+ .concat(Abort.new('User abort!').as_observable)
109
+ end
84
110
  end
85
111
  end
86
112
 
87
113
  class RecreateStackAction < BaseAction
114
+ def validate!
115
+ if @meta.stack_uri.nil?
116
+ raise "You need to pass a template to re-create #{@meta.stackname}" # in #{@meta.aws_region}."
117
+ end
118
+ end
119
+
88
120
  def as_observable
89
121
  crt_args = CuffSert.as_create_stack_args(@meta)
90
122
  del_args = CuffSert.as_delete_stack_args(@stack)
@@ -33,7 +33,10 @@ module CuffSert
33
33
  end
34
34
  end
35
35
 
36
- cfargs.merge!(self.template_parameters(meta))
36
+ if meta.stack_uri
37
+ cfargs.merge!(self.template_parameters(meta))
38
+ end
39
+ cfargs
37
40
  end
38
41
 
39
42
  def self.as_create_stack_args(meta)
@@ -46,11 +49,26 @@ module CuffSert
46
49
  cfargs
47
50
  end
48
51
 
49
- def self.as_update_change_set(meta)
52
+ def self.as_update_change_set(meta, stack)
50
53
  cfargs = self.as_cloudformation_args(meta)
51
- cfargs[:use_previous_template] = false
52
54
  cfargs[:change_set_name] = meta.stackname
53
55
  cfargs[:change_set_type] = 'UPDATE'
56
+ if cfargs[:use_previous_template] = meta.stack_uri.nil?
57
+ Array(stack[:parameters]).each do |param|
58
+ key = param[:parameter_key]
59
+ unless meta.parameters.include?(key)
60
+ cfargs[:parameters] ||= []
61
+ cfargs[:parameters] << {:parameter_key => key, :use_previous_value => true}
62
+ end
63
+ end
64
+ if !meta.tags.empty?
65
+ Array(stack[:tags]).each do |tag|
66
+ unless meta.tags.include?(tag[:key])
67
+ cfargs[:tags] << tag
68
+ end
69
+ end
70
+ end
71
+ end
54
72
  cfargs
55
73
  end
56
74
 
@@ -58,8 +76,7 @@ module CuffSert
58
76
  { :stack_name => stack[:stack_id] }
59
77
  end
60
78
 
61
- def self.s3_uri_to_https(uri)
62
- region = ENV['AWS_REGION'] || ENV['AWS_DEFAULT_REGION'] || 'us-east-1'
79
+ def self.s3_uri_to_https(uri, region)
63
80
  bucket = uri.host
64
81
  key = uri.path
65
82
  host = region == 'us-east-1' ? 's3.amazonaws.com' : "s3-#{region}.amazonaws.com"
@@ -77,7 +94,7 @@ module CuffSert
77
94
  template_parameters = {}
78
95
 
79
96
  if meta.stack_uri.scheme == 's3'
80
- template_parameters[:template_url] = self.s3_uri_to_https(meta.stack_uri)
97
+ template_parameters[:template_url] = self.s3_uri_to_https(meta.stack_uri, meta.aws_region)
81
98
  elsif meta.stack_uri.scheme == 'https'
82
99
  if meta.stack_uri.host.end_with?('amazonaws.com')
83
100
  template_parameters[:template_url] = meta.stack_uri.to_s
@@ -1,4 +1,5 @@
1
1
  require 'optparse'
2
+ require 'cuffbase'
2
3
  require 'cuffsert/version'
3
4
 
4
5
  module CuffSert
@@ -18,7 +19,14 @@ module CuffSert
18
19
  parser = OptionParser.new do |opts|
19
20
  opts.banner = "Upsert a CloudFormation template, reading creation options and metadata from a yaml file. Currently, parameter values, stack name and stack tags are read from metadata file. Version #{CuffSert::VERSION}."
20
21
  opts.separator('')
21
- opts.separator('Usage: cuffsert --selector production/us stack.json')
22
+ opts.separator('Usage:')
23
+ opts.separator(' cuffsert --name <stackname> stack.json')
24
+ opts.separator(' cuffsert --name <stackname> {--parameter Name=Value | --tag Name=Value}... [stack.json]')
25
+ opts.separator(' cuffsert --metadata <metadata.json> --selector <path/in/metadata> stack.json')
26
+ opts.separator(' cuffsert --metadata <metadata.json> --selector <path/in/metadata> {--parameter Name=Value | --tag Name=Value}... [stack.json]')
27
+
28
+ CuffBase.shared_cli_args(opts, args)
29
+
22
30
  opts.on('--metadata path', '-m path', 'Yaml file to read stack metadata from') do |path|
23
31
  path = '/dev/stdin' if path == '-'
24
32
  unless File.exist?(path)
@@ -60,10 +68,6 @@ module CuffSert
60
68
  args[:overrides][:tags][key] = val
61
69
  end
62
70
 
63
- opts.on('--region=aws_region', 'AWS region, overrides env variable AWS_REGION') do |region|
64
- args[:aws_region] = region
65
- end
66
-
67
71
  opts.on('--s3-upload-prefix=prefix', 'Templates > 51200 bytes are uploaded here. Format: s3://bucket-name/[pre/fix]') do |prefix|
68
72
  unless prefix.start_with?('s3://')
69
73
  raise "Upload prefix #{prefix} must start with s3://"
@@ -87,13 +91,18 @@ module CuffSert
87
91
  args[:force_replace] = true
88
92
  end
89
93
 
94
+ opts.on('--ask', 'Always ask for confirmation') do
95
+ raise 'You can only use one of --yes, --ask and --dry-run' if args[:op_mode]
96
+ args[:op_mode] = :always_ask
97
+ end
98
+
90
99
  opts.on('--yes', '-y', 'Don\'t ask to replace and delete stack resources') do
91
- raise 'You cannot do --yes and --dry-run at the same time' if args[:op_mode]
100
+ raise 'You can only use one of --yes, --ask and --dry-run' if args[:op_mode]
92
101
  args[:op_mode] = :dangerous_ok
93
102
  end
94
103
 
95
104
  opts.on('--dry-run', 'Describe what would be done') do
96
- raise 'You cannot do --yes and --dry-run at the same time' if args[:op_mode]
105
+ raise 'You can only use one of --yes, --ask and --dry-run' if args[:op_mode]
97
106
  args[:op_mode] = :dry_run
98
107
  end
99
108
 
@@ -109,21 +118,21 @@ module CuffSert
109
118
  args
110
119
  end
111
120
  end
112
-
121
+
113
122
  def self.validate_cli_args(cli_args)
114
123
  errors = []
115
- if cli_args[:stack_path].nil? || cli_args[:stack_path].size != 1
116
- errors << 'Requires exactly one template'
124
+ if cli_args[:stack_path] != nil && cli_args[:stack_path].size > 1
125
+ errors << 'Require at most one template'
117
126
  end
118
127
 
119
128
  if cli_args[:metadata].nil? && cli_args[:overrides][:stackname].nil?
120
129
  errors << 'Without --metadata, you must supply --name to identify stack to update'
121
130
  end
122
-
131
+
123
132
  if cli_args[:selector] && cli_args[:metadata].nil?
124
133
  errors << 'You cannot use --selector without --metadata'
125
134
  end
126
-
135
+
127
136
  raise errors.join(', ') unless errors.empty?
128
137
  end
129
138
  end
@@ -2,6 +2,7 @@ require 'termios'
2
2
 
3
3
  module CuffSert
4
4
  def self.need_confirmation(meta, action, desc)
5
+ return true if meta.op_mode == :always_ask
5
6
  return false if meta.op_mode == :dangerous_ok
6
7
  case action
7
8
  when :create
data/lib/cuffsert/main.rb CHANGED
@@ -41,12 +41,13 @@ module CuffSert
41
41
  cli_args = CuffSert.parse_cli_args(argv)
42
42
  CuffSert.validate_cli_args(cli_args)
43
43
  meta = CuffSert.build_meta(cli_args)
44
- cfclient = RxCFClient.new(cli_args)
44
+ cfclient = RxCFClient.new(meta.aws_region)
45
45
  action = CuffSert.determine_action(meta, cfclient, force_replace: cli_args[:force_replace]) do |a|
46
46
  a.confirmation = CuffSert.method(:confirmation)
47
- a.s3client = RxS3Client.new(cli_args) if cli_args[:s3_upload_prefix]
47
+ a.s3client = RxS3Client.new(cli_args, meta.aws_region) if cli_args[:s3_upload_prefix]
48
48
  a.cfclient = cfclient
49
49
  end
50
+ action.validate!
50
51
  renderer = CuffSert.make_renderer(cli_args)
51
52
  RendererPresenter.new(action.as_observable, renderer)
52
53
  end
@@ -23,4 +23,5 @@ module CuffSert
23
23
  super('Done.')
24
24
  end
25
25
  end
26
+ class ChangeSet < Message ; end
26
27
  end
@@ -3,10 +3,11 @@ require 'yaml'
3
3
 
4
4
  module CuffSert
5
5
  class StackConfig
6
- attr_accessor :stackname, :selected_path, :op_mode, :stack_uri
6
+ attr_accessor :aws_region, :stackname, :selected_path, :op_mode, :stack_uri
7
7
  attr_accessor :suffix, :parameters, :tags
8
8
 
9
9
  def initialize
10
+ @aws_region = ENV['AWS_REGION'] || ENV['AWS_DEFAULT_REGION'] || 'us-east-1'
10
11
  @selected_path = []
11
12
  @op_mode = :normal
12
13
  @parameters = {}
@@ -57,7 +58,7 @@ module CuffSert
57
58
 
58
59
  def self.meta_for_path(metadata, path, target = StackConfig.new)
59
60
  target.update_from(metadata)
60
- candidate, path = path
61
+ candidate, *path = path
61
62
  key = candidate || metadata[:defaultpath]
62
63
  variants = metadata[:variants]
63
64
  if key.nil?
@@ -82,8 +83,9 @@ module CuffSert
82
83
  private_class_method
83
84
 
84
85
  def self.meta_defaults(cli_args)
85
- if File.exists?(cli_args[:stack_path][0])
86
- nil_params = CuffBase.empty_from_template(open(cli_args[:stack_path][0]))
86
+ stack_path = (cli_args[:stack_path] || [])[0]
87
+ if stack_path && File.exists?(stack_path)
88
+ nil_params = CuffBase.empty_from_template(open(stack_path))
87
89
  else
88
90
  nil_params = {}
89
91
  end
@@ -104,9 +106,11 @@ module CuffSert
104
106
 
105
107
  def self.cli_overrides(meta, cli_args)
106
108
  meta.update_from(cli_args[:overrides])
109
+ meta.aws_region = cli_args[:aws_region] || meta.aws_region
107
110
  meta.op_mode = cli_args[:op_mode] || meta.op_mode
108
- stack_path = cli_args[:stack_path][0]
109
- meta.stack_uri = CuffSert.validate_and_urlify(stack_path)
111
+ if (stack_path = (cli_args[:stack_path] || [])[0])
112
+ meta.stack_uri = CuffSert.validate_and_urlify(stack_path)
113
+ end
110
114
  meta
111
115
  end
112
116
 
@@ -57,8 +57,8 @@ module CuffSert
57
57
  case event
58
58
  when Aws::CloudFormation::Types::StackEvent
59
59
  on_stack_event(event)
60
- when Aws::CloudFormation::Types::DescribeChangeSetOutput
61
- on_change_set(event)
60
+ when ::CuffSert::ChangeSet
61
+ on_change_set(event.message)
62
62
  # when [:recreate, Aws::CloudFormation::Types::Stack]
63
63
  when Array
64
64
  on_stack(*event)
@@ -4,9 +4,9 @@ require 'rx'
4
4
 
5
5
  module CuffSert
6
6
  class RxCFClient
7
- def initialize(cli_args, **options)
7
+ def initialize(aws_region = nil, **options)
8
8
  initargs = {retry_limit: 8}
9
- initargs[:region] = cli_args[:aws_region] if cli_args[:aws_region]
9
+ initargs[:region] = aws_region if aws_region
10
10
  @cf = options[:aws_cf] || Aws::CloudFormation::Client.new(initargs)
11
11
  @max_items = options[:max_items] || 1000
12
12
  @pause = options[:pause] || 5
@@ -3,10 +3,10 @@ require 'rx'
3
3
 
4
4
  module CuffSert
5
5
  class RxS3Client
6
- def initialize(cli_args, client: nil)
6
+ def initialize(cli_args, aws_region = nil, client: nil)
7
7
  @bucket, @path_prefix = split_prefix(cli_args[:s3_upload_prefix])
8
8
  initargs = {retry_limit: 8}
9
- initargs[:region] = cli_args[:aws_region] if cli_args[:aws_region]
9
+ initargs[:region] = aws_region if aws_region
10
10
  @client = client || Aws::S3::Client.new(initargs)
11
11
  end
12
12
 
@@ -1,3 +1,3 @@
1
1
  module CuffSert
2
- VERSION = '0.11.0'
2
+ VERSION = '0.12.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cuffsert
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anders Qvist
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-08-30 00:00:00.000000000 Z
11
+ date: 2018-10-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-cloudformation
@@ -173,6 +173,7 @@ files:
173
173
  - bin/cuffup
174
174
  - cuffsert.gemspec
175
175
  - lib/cuffbase.rb
176
+ - lib/cuffdown/main.rb
176
177
  - lib/cuffsert/actions.rb
177
178
  - lib/cuffsert/cfarguments.rb
178
179
  - lib/cuffsert/cfstates.rb