lono 4.1.0 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +7 -0
  3. data/README.md +3 -1
  4. data/exe/lono +1 -1
  5. data/lib/lono.rb +17 -15
  6. data/lib/lono/cfn.rb +54 -24
  7. data/lib/lono/cfn/base.rb +95 -17
  8. data/lib/lono/cfn/create.rb +5 -29
  9. data/lib/lono/cfn/current.rb +95 -0
  10. data/lib/lono/cfn/delete.rb +15 -1
  11. data/lib/lono/cfn/preview.rb +5 -3
  12. data/lib/lono/cfn/status.rb +212 -0
  13. data/lib/lono/cfn/update.rb +6 -12
  14. data/lib/lono/cfn/util.rb +2 -2
  15. data/lib/lono/cli.rb +4 -6
  16. data/lib/lono/core.rb +23 -5
  17. data/lib/lono/default/settings.yml +1 -1
  18. data/lib/lono/file_uploader.rb +119 -0
  19. data/lib/lono/help/cfn/current.md +18 -0
  20. data/lib/lono/help/cfn/status.md +19 -0
  21. data/lib/lono/script/build.rb +2 -1
  22. data/lib/lono/script/upload.rb +1 -1
  23. data/lib/lono/template/helper.rb +8 -0
  24. data/lib/lono/template/upload.rb +13 -1
  25. data/lib/lono/upgrade.rb +16 -0
  26. data/lib/lono/{upgrade4.rb → upgrade/upgrade4.rb} +1 -1
  27. data/lib/lono/upgrade/upgrade42.rb +36 -0
  28. data/lib/lono/version.rb +1 -1
  29. data/lib/starter_projects/autoscaling/.gitignore +1 -0
  30. data/lib/starter_projects/autoscaling/README.md +1 -1
  31. data/lib/starter_projects/autoscaling/config/settings.yml +1 -1
  32. data/lib/starter_projects/ec2/.gitignore +1 -0
  33. data/lib/starter_projects/ec2/config/settings.yml +1 -1
  34. data/lib/starter_projects/skeleton/.gitignore +1 -0
  35. data/lib/starter_projects/skeleton/config/settings.yml +1 -1
  36. data/lono.gemspec +1 -0
  37. data/spec/fixtures/cfn/stack-events-complete.json +1080 -0
  38. data/spec/fixtures/cfn/stack-events-in-progress.json +1080 -0
  39. data/spec/fixtures/cfn/stack-events-update-rollback-complete.json +1086 -0
  40. data/spec/fixtures/lono_project/config/settings.yml +1 -1
  41. data/spec/lib/lono/cfn/status_spec.rb +77 -0
  42. metadata +33 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 14ca2afc46780d2abc5bb0ecabaf53a685befb89abe63263fa02d847201582f4
4
- data.tar.gz: b3ccb40f3ecc4902b769651c67ef1a76dfb330c0d547c3da686e2913857b048a
3
+ metadata.gz: 2a5ca91b3f1e36849794c7dd3450bdad734b95105ac76d8b24bbf51886b22890
4
+ data.tar.gz: 05f32b9ee239b75b9fbc99fefee557352acffa35a39e812367f39247892e9e27
5
5
  SHA512:
6
- metadata.gz: 63bcc9ff8a025fba3666fb8bcd73fb1a7ffa5e9382dcdf2d407f4c7ea678fb63302887a3bddc8f527c13846100af26d91361f6a7f9bfc2583d4345635ab698de
7
- data.tar.gz: ac98507f3f1a706602662f47af7055b6b983c6c373d8c78f13706dab323fbf8a33d35b16d87234de9674ca7e2c5464d2dcfe1cbd475f6d1ba19b6539ba81a7a1
6
+ metadata.gz: e71a1fe6b43df90adc2d0fc91d9a506b2e6610ff8d72c9640366baf306720cb969da972af6711ee66b9c362103666dd0f44863918ee74a454694f23062344190
7
+ data.tar.gz: c2109dd8da019dbcba4ec958b49d90951a0aaa83e2b9d1259fcba89f8c4bda9cbb7bb6ad911473cc80c4c266f8a4214fbf81ddc3c816426530c9ff7286723df1
@@ -3,6 +3,13 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  This project *tries* to adhere to [Semantic Versioning](http://semver.org/), even before v1.0.
5
5
 
6
+ ## [4.2.0]
7
+ - lono current
8
+ - lono cfn status
9
+ - app/files support with file_s3_key helper
10
+ - Display status of stack deployment and wait for completion
11
+ - fix iam retry logic for cfn update
12
+
6
13
  ## [4.1.0]
7
14
  - Merge pull request #36 from tongueroo/cli_markdown
8
15
  - fix current_region helper in variables, add s3_region setting
data/README.md CHANGED
@@ -25,7 +25,9 @@ See [lono.cloud](http://lono.cloud) for full lono documentation.
25
25
 
26
26
  ## Important
27
27
 
28
- If you are on version 3, you can run `lono upgrade4` within your project to upgrade it to version 4. Refer to the [CHANGELOG](CHANGELOG.md).
28
+ If you are on version 3, you can run `lono upgrade v3to4` within your project to upgrade it to version 4. Refer to the [CHANGELOG](CHANGELOG.md).
29
+
30
+ If you are on version 4.0 or 4.1 and need to uppgrade to 4.2. You can run `lono upgrade v4to4_2` within your project to upgrade it to version 4.2. Refer to the [CHANGELOG](CHANGELOG.md).
29
31
 
30
32
  ## Blog Posts
31
33
 
data/exe/lono CHANGED
@@ -3,7 +3,7 @@
3
3
  # Trap ^C
4
4
  Signal.trap("INT") {
5
5
  puts "\nCtrl-C detected. Exiting..."
6
- sleep 1
6
+ sleep 0.1
7
7
  exit
8
8
  }
9
9
 
@@ -5,6 +5,7 @@ require 'json'
5
5
  require 'pp'
6
6
  require 'render_me_pretty'
7
7
  require 'yaml'
8
+ require 'memoist'
8
9
 
9
10
  # vendor because need https://github.com/futurechimp/plissken/pull/6 to be merged
10
11
  $:.unshift(File.expand_path("../../vendor/plissken/lib", __FILE__))
@@ -12,27 +13,28 @@ require "plissken"
12
13
 
13
14
  $:.unshift(File.expand_path('../', __FILE__))
14
15
  module Lono
15
- autoload :VERSION, 'lono/version'
16
- autoload :Env, 'lono/env'
17
- autoload :Help, 'lono/help'
18
- autoload :ProjectChecker, 'lono/project_checker'
19
- autoload :Command, 'lono/command'
20
- autoload :CLI, 'lono/cli'
21
- autoload :New, 'lono/new'
22
- autoload :Sequence, 'lono/sequence'
23
- autoload :Template, 'lono/template'
24
16
  autoload :Cfn, 'lono/cfn'
25
- autoload :Param, 'lono/param'
26
17
  autoload :Clean, 'lono/clean'
27
- autoload :Setting, 'lono/setting'
28
- autoload :Importer, 'lono/importer'
29
- autoload :Inspector, 'lono/inspector'
30
- autoload :Completion, 'lono/completion'
18
+ autoload :CLI, 'lono/cli'
19
+ autoload :Command, 'lono/command'
31
20
  autoload :Completer, 'lono/completer'
21
+ autoload :Completion, 'lono/completion'
32
22
  autoload :Core, 'lono/core'
33
- autoload :Upgrade4, 'lono/upgrade4'
23
+ autoload :Env, 'lono/env'
24
+ autoload :FileUploader, 'lono/file_uploader'
25
+ autoload :Help, 'lono/help'
26
+ autoload :Importer, 'lono/importer'
27
+ autoload :Inspector, 'lono/inspector'
28
+ autoload :New, 'lono/new'
29
+ autoload :Param, 'lono/param'
30
+ autoload :ProjectChecker, 'lono/project_checker'
34
31
  autoload :Script, 'lono/script'
32
+ autoload :Sequence, 'lono/sequence'
33
+ autoload :Setting, 'lono/setting'
34
+ autoload :Template, 'lono/template'
35
+ autoload :Upgrade, 'lono/upgrade'
35
36
  autoload :UserData, 'lono/user_data'
37
+ autoload :VERSION, 'lono/version'
36
38
 
37
39
  extend Core
38
40
  end
@@ -2,32 +2,40 @@ require "thor"
2
2
 
3
3
  class Lono::Cfn < Lono::Command
4
4
  autoload :AwsService, 'lono/cfn/aws_service'
5
- autoload :Util, 'lono/cfn/util'
6
- autoload :CLI, 'lono/cfn/cli'
7
5
  autoload :Base, 'lono/cfn/base'
6
+ autoload :CLI, 'lono/cfn/cli'
8
7
  autoload :Create, 'lono/cfn/create'
9
- autoload :Update, 'lono/cfn/update'
8
+ autoload :Current, 'lono/cfn/current'
10
9
  autoload :Delete, 'lono/cfn/delete'
11
- autoload :Preview, 'lono/cfn/preview'
12
10
  autoload :Diff, 'lono/cfn/diff'
13
11
  autoload :Download, 'lono/cfn/download'
12
+ autoload :Preview, 'lono/cfn/preview'
13
+ autoload :Status, 'lono/cfn/status'
14
+ autoload :Update, 'lono/cfn/update'
15
+ autoload :Util, 'lono/cfn/util'
14
16
 
15
17
  class_option :verbose, type: :boolean
16
18
  class_option :noop, type: :boolean
17
19
 
18
- # common to create and update
19
- class_option :template, desc: "override convention and specify the template file to use"
20
- class_option :param, desc: "override convention and specify the param file to use"
21
- class_option :lono, type: :boolean, desc: "invoke lono to generate CloudFormation templates", default: true
22
- class_option :capabilities, type: :array, desc: "iam capabilities. Ex: CAPABILITY_IAM, CAPABILITY_NAMED_IAM"
23
- class_option :iam, type: :boolean, desc: "Shortcut for common IAM capabilities: CAPABILITY_IAM, CAPABILITY_NAMED_IAM"
24
- class_option :rollback, type: :boolean, desc: "rollback", default: true
20
+ base_options = Proc.new do
21
+ # common to create and update
22
+ option :template, desc: "override convention and specify the template file to use"
23
+ option :param, desc: "override convention and specify the param file to use"
24
+ option :lono, type: :boolean, desc: "invoke lono to generate CloudFormation templates", default: true
25
+ option :capabilities, type: :array, desc: "iam capabilities. Ex: CAPABILITY_IAM, CAPABILITY_NAMED_IAM"
26
+ option :iam, type: :boolean, desc: "Shortcut for common IAM capabilities: CAPABILITY_IAM, CAPABILITY_NAMED_IAM"
27
+ option :rollback, type: :boolean, desc: "rollback", default: true
28
+ end
29
+ wait_option = Proc.new do
30
+ option :wait, type: :boolean, desc: "Wait for stack operation to complete.", default: true
31
+ end
25
32
 
26
33
  desc "create STACK", "Create a CloudFormation stack using the generated template."
27
- option :randomize_stack_name, type: :boolean, desc: "tack on random string at the end of the stack name", default: nil
34
+ base_options.call
35
+ wait_option.call
28
36
  long_desc Lono::Help.text("cfn/create")
29
- def create(name)
30
- Create.new(name, options).run
37
+ def create(stack_name)
38
+ Create.new(stack_name, options).run
31
39
  end
32
40
 
33
41
  desc "update STACK", "Update a CloudFormation stack using the generated template."
@@ -36,36 +44,58 @@ class Lono::Cfn < Lono::Command
36
44
  option :diff, type: :boolean, default: true, desc: "Show diff of the source code template changes before continuing."
37
45
  option :preview, type: :boolean, default: true, desc: "Show preview of the stack changes before continuing."
38
46
  option :sure, type: :boolean, desc: "Skips are you sure prompt"
39
- def update(name)
40
- Update.new(name, options).run
47
+ base_options.call
48
+ wait_option.call
49
+ def update(stack_name=:current)
50
+ Update.new(stack_name, options).run
41
51
  end
42
52
 
43
53
  desc "delete STACK", "Delete a CloudFormation stack."
44
54
  long_desc Lono::Help.text("cfn/delete")
45
55
  option :sure, type: :boolean, desc: "Skips are you sure prompt"
46
- def delete(name)
47
- Delete.new(name, options).run
56
+ base_options.call
57
+ wait_option.call
58
+ def delete(stack_name=:current)
59
+ Delete.new(stack_name, options).run
48
60
  end
49
61
 
50
62
  desc "preview STACK", "Preview a CloudFormation stack update. This is similar to terraform's plan or puppet's dry-run mode."
51
63
  long_desc Lono::Help.text("cfn/preview")
52
64
  option :keep, type: :boolean, desc: "keep the changeset instead of deleting it afterwards"
53
65
  option :diff, type: :boolean, default: true, desc: "Show diff of the source code template changes also."
54
- def preview(name)
55
- Diff.new(name, options).run if options[:diff]
56
- Preview.new(name, options).run
66
+ base_options.call
67
+ def preview(stack_name=:current)
68
+ Diff.new(stack_name, options).run if options[:diff]
69
+ Preview.new(stack_name, options).run
57
70
  end
58
71
 
59
72
  desc "diff STACK", "Diff newly generated template vs existing template."
60
73
  long_desc Lono::Help.text("cfn/diff")
61
- def diff(name)
62
- Diff.new(name, options).run
74
+ base_options.call
75
+ def diff(stack_name=:current)
76
+ Diff.new(stack_name, options).run
63
77
  end
64
78
 
65
79
  desc "download STACK", "Download CloudFormation template from existing stack."
66
80
  long_desc Lono::Help.text("cfn/download")
67
81
  option :name, desc: "Name you want to save the template as. Default: existing stack name."
68
- def download(stack_name)
82
+ base_options.call
83
+ def download(stack_name=:current)
69
84
  Download.new(stack_name, options).run
70
85
  end
86
+
87
+ desc "current", "Current stack that you're working with."
88
+ long_desc Lono::Help.text("cfn/current")
89
+ option :rm, type: :boolean, desc: "Remove all current settings. Removes `.lono/current`"
90
+ option :name, desc: "Current stack name."
91
+ option :suffix, desc: "Current suffix for stack name."
92
+ def current
93
+ Current.new(options).run
94
+ end
95
+
96
+ desc "status", "Shows the current status for the stack."
97
+ long_desc Lono::Help.text("cfn/status")
98
+ def status(stack_name=:current)
99
+ Status.new(stack_name, options).run
100
+ end
71
101
  end
@@ -4,14 +4,13 @@ class Lono::Cfn::Base
4
4
  include Lono::Cfn::AwsService
5
5
  include Lono::Cfn::Util
6
6
 
7
- attr_reader :randomize_stack_name
8
7
  def initialize(stack_name, options={})
9
- @randomize_stack_name = options[:randomize_stack_name]
10
- @stack_name = randomize(stack_name)
11
- @options = options
8
+ @options = options # options must be set first because @option used in append_suffix
9
+ stack_name = switch_current(stack_name)
10
+ @stack_name = append_suffix(stack_name)
12
11
  Lono::ProjectChecker.check unless options[:lono] # already ran checker in lono generate
13
12
 
14
- @template_name = options[:template] || derandomize(@stack_name)
13
+ @template_name = options[:template] || remove_suffix(@stack_name)
15
14
  @param_name = options[:param] || @template_name
16
15
  @template_path = get_source_path(@template_name, :template)
17
16
  @param_path = get_source_path(@param_name, :param)
@@ -19,7 +18,18 @@ class Lono::Cfn::Base
19
18
  puts "Using parameters: #{@param_path}" unless @options[:mute_using]
20
19
  end
21
20
 
21
+ def switch_current(stack_name)
22
+ Lono::Cfn::Current.name!(stack_name)
23
+ end
24
+
25
+ def starting_message
26
+ action = self.class.to_s.split('::').last
27
+ action = action[0..-2] + 'ing' # create => creating
28
+ puts "#{action} #{@stack_name.colorize(:green)} stack..."
29
+ end
30
+
22
31
  def run
32
+ starting_message
23
33
  params = generate_all
24
34
  begin
25
35
  save_stack(params) # defined in the sub class
@@ -35,6 +45,13 @@ class Lono::Cfn::Base
35
45
  exit 1
36
46
  end
37
47
  end
48
+
49
+ return unless @options[:wait]
50
+ status.wait
51
+ end
52
+
53
+ def status
54
+ @status ||= Lono::Cfn::Status.new(@stack_name)
38
55
  end
39
56
 
40
57
  def prompt_for_iam(capabilities)
@@ -55,6 +72,7 @@ class Lono::Cfn::Base
55
72
  generate_templates
56
73
  unless @options[:noop]
57
74
  upload_scripts
75
+ upload_files
58
76
  upload_templates
59
77
  end
60
78
  end
@@ -82,6 +100,11 @@ class Lono::Cfn::Base
82
100
  Lono::Script::Upload.new.run
83
101
  end
84
102
 
103
+ def upload_files
104
+ return unless s3_folder
105
+ Lono::FileUploader.new.upload_all
106
+ end
107
+
85
108
  def generate_params(options={})
86
109
  generator_options = {
87
110
  path: @param_path,
@@ -172,28 +195,61 @@ class Lono::Cfn::Base
172
195
  exit signal
173
196
  end
174
197
 
175
- # Do nothing unless in Create class
176
- def randomize(stack_name)
177
- stack_name
198
+ # Appends a short suffix at the end of a stack name.
199
+ # Lono internally strips this same suffix for the template name.
200
+ # Makes it convenient for the development flow.
201
+ #
202
+ # lono cfn current --suffix 1
203
+ # lono cfn create demo => demo-1
204
+ # lono cfn update demo-1
205
+ #
206
+ # Instead of typing:
207
+ #
208
+ # lono cfn create demo-1 --template demo
209
+ # lono cfn update demo-1 --template demo
210
+ #
211
+ # The suffix can be specified at the CLI but can also be saved as a
212
+ # preference.
213
+ #
214
+ # A random suffix can be specified with random. Example:
215
+ #
216
+ # lono cfn current --suffix random
217
+ # lono cfn create demo => demo-[RANDOM], example: demo-abc
218
+ # lono cfn update demo-abc
219
+ #
220
+ # It is not a default setting because it might confuse new lono users.
221
+ def append_suffix(stack_name)
222
+ suffix = Lono.suffix == 'random' ? random_suffix : Lono.suffix
223
+ [stack_name, suffix].compact.join('-')
178
224
  end
179
225
 
180
- # Strip the random string at end of the template name
181
- def derandomize(template_name)
182
- if randomize_stack_name?
183
- template_name.sub(/-(\w{3})$/,'') # strip the random part at the end
226
+ def remove_suffix(stack_name)
227
+ return stack_name unless Lono.suffix
228
+
229
+ if stack_name_suffix == 'random'
230
+ stack_name.sub(/-(\w{3})$/,'') # strip the random suffix at the end
231
+ elsif stack_name_suffix
232
+ pattern = Regexp.new("-#{stack_name_suffix}$",'')
233
+ stack_name.sub(pattern, '') # strip suffix
184
234
  else
185
- template_name
235
+ stack_name
186
236
  end
187
237
  end
188
238
 
189
- def randomize_stack_name?
190
- if !randomize_stack_name.nil?
191
- return randomize_stack_name # CLI option takes highest precedence
239
+ # only generate random suffix for Lono::Cfn::Create class
240
+ def random_suffix
241
+ return nil unless self.class.name.to_s =~ /Create/
242
+ (0...3).map { (65 + rand(26)).chr }.join.downcase # Ex: jhx
243
+ end
244
+
245
+ def stack_name_suffix
246
+ if @options[:suffix] && !@options[:suffix].nil?
247
+ return @options[:suffix] # CLI option takes highest precedence
192
248
  end
193
249
 
194
250
  # otherwise use the settings preference
195
251
  settings = Lono::Setting.new
196
- settings.data['randomize_stack_name']
252
+ settings.data['stack_name_suffix']
197
253
  end
198
254
 
199
255
  def capabilities
@@ -215,4 +271,26 @@ class Lono::Cfn::Base
215
271
  setting = Lono::Setting.new
216
272
  setting.s3_folder
217
273
  end
274
+
275
+ # Either set the templmate_body or template_url attribute based on
276
+ # if template was uploaded to s3.
277
+ # Nice to reference s3 url because the max size of the template body is
278
+ # greater if the template body is on s3. Limits:
279
+ #
280
+ # template_body: 51,200 bytes
281
+ # template_url: 460,800 bytes
282
+ #
283
+ # Reference: https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/cloudformation-limits.html
284
+ def set_template_body!(params)
285
+ # if s3_folder is set this means s3 upload is enabled
286
+ if s3_folder # s3_folder defined in cfn/base.rb
287
+ upload = Lono::Template::Upload.new
288
+ url = upload.s3_presigned_url(@template_path)
289
+ params[:template_url] = url
290
+ else
291
+ params[:template_body] = IO.read(@template_path)
292
+ end
293
+
294
+ params
295
+ end
218
296
  end
@@ -8,56 +8,32 @@ class Lono::Cfn::Create < Lono::Cfn::Base
8
8
 
9
9
  # aws cloudformation create-stack --stack-name prod-hi-123456789 --parameters file://output/params/prod-hi-123456789.json --template-body file://output/prod-hi.json
10
10
  def create_stack(params)
11
- message = "Creating #{@stack_name} stack."
11
+ message = "Creating #{@stack_name.colorize(:green)} stack."
12
12
  if @options[:noop]
13
13
  puts "NOOP #{message}"
14
14
  return
15
15
  end
16
16
 
17
17
  if stack_exists?(@stack_name)
18
- puts "Cannot create '#{@stack_name}' stack because it already exists.".colorize(:red)
18
+ puts "Cannot create #{@stack_name.colorize(:green)} stack because it already exists.".colorize(:red)
19
19
  return
20
20
  end
21
21
 
22
22
  unless File.exist?(@template_path)
23
- puts "Cannot create '#{@stack_name}' template not found: #{@template_path}."
23
+ puts "Cannot create #{@stack_name.colorize(:green)} template not found: #{@template_path}."
24
24
  return
25
25
  end
26
26
 
27
- template_body = IO.read(@template_path)
28
27
  params = {
29
28
  stack_name: @stack_name,
30
- template_body: template_body,
31
29
  parameters: params,
32
30
  capabilities: capabilities, # ["CAPABILITY_IAM", "CAPABILITY_NAMED_IAM"]
33
31
  disable_rollback: !@options[:rollback],
34
32
  }
33
+ set_template_body!(params)
34
+
35
35
  show_parameters(params, "cfn.create_stack")
36
36
  cfn.create_stack(params)
37
37
  puts message unless @options[:mute]
38
38
  end
39
-
40
- # Appends a short random string at the end of a stack name.
41
- # Later we will strip this same random string from the template name.
42
- # Very makes it convenient. We can just type:
43
- #
44
- # lono cfn create main --randomize-stack-name
45
- #
46
- # instead of:
47
- #
48
- # lono cfn create main-[RANDOM] --template main
49
- #
50
- # The randomize_stack_name can be specified at the CLI but can also be saved as a
51
- # preference.
52
- #
53
- # It is not a default setting because it might confuse new lono users.
54
- def randomize(stack_name)
55
- if randomize_stack_name?
56
- random = (0...3).map { (65 + rand(26)).chr }.join.downcase # Ex: jhx
57
- [stack_name, random].join('-')
58
- else
59
- stack_name
60
- end
61
- end
62
-
63
39
  end