lono 4.1.0 → 4.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +3 -1
- data/exe/lono +1 -1
- data/lib/lono.rb +17 -15
- data/lib/lono/cfn.rb +54 -24
- data/lib/lono/cfn/base.rb +95 -17
- data/lib/lono/cfn/create.rb +5 -29
- data/lib/lono/cfn/current.rb +95 -0
- data/lib/lono/cfn/delete.rb +15 -1
- data/lib/lono/cfn/preview.rb +5 -3
- data/lib/lono/cfn/status.rb +212 -0
- data/lib/lono/cfn/update.rb +6 -12
- data/lib/lono/cfn/util.rb +2 -2
- data/lib/lono/cli.rb +4 -6
- data/lib/lono/core.rb +23 -5
- data/lib/lono/default/settings.yml +1 -1
- data/lib/lono/file_uploader.rb +119 -0
- data/lib/lono/help/cfn/current.md +18 -0
- data/lib/lono/help/cfn/status.md +19 -0
- data/lib/lono/script/build.rb +2 -1
- data/lib/lono/script/upload.rb +1 -1
- data/lib/lono/template/helper.rb +8 -0
- data/lib/lono/template/upload.rb +13 -1
- data/lib/lono/upgrade.rb +16 -0
- data/lib/lono/{upgrade4.rb → upgrade/upgrade4.rb} +1 -1
- data/lib/lono/upgrade/upgrade42.rb +36 -0
- data/lib/lono/version.rb +1 -1
- data/lib/starter_projects/autoscaling/.gitignore +1 -0
- data/lib/starter_projects/autoscaling/README.md +1 -1
- data/lib/starter_projects/autoscaling/config/settings.yml +1 -1
- data/lib/starter_projects/ec2/.gitignore +1 -0
- data/lib/starter_projects/ec2/config/settings.yml +1 -1
- data/lib/starter_projects/skeleton/.gitignore +1 -0
- data/lib/starter_projects/skeleton/config/settings.yml +1 -1
- data/lono.gemspec +1 -0
- data/spec/fixtures/cfn/stack-events-complete.json +1080 -0
- data/spec/fixtures/cfn/stack-events-in-progress.json +1080 -0
- data/spec/fixtures/cfn/stack-events-update-rollback-complete.json +1086 -0
- data/spec/fixtures/lono_project/config/settings.yml +1 -1
- data/spec/lib/lono/cfn/status_spec.rb +77 -0
- metadata +33 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2a5ca91b3f1e36849794c7dd3450bdad734b95105ac76d8b24bbf51886b22890
|
4
|
+
data.tar.gz: 05f32b9ee239b75b9fbc99fefee557352acffa35a39e812367f39247892e9e27
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e71a1fe6b43df90adc2d0fc91d9a506b2e6610ff8d72c9640366baf306720cb969da972af6711ee66b9c362103666dd0f44863918ee74a454694f23062344190
|
7
|
+
data.tar.gz: c2109dd8da019dbcba4ec958b49d90951a0aaa83e2b9d1259fcba89f8c4bda9cbb7bb6ad911473cc80c4c266f8a4214fbf81ddc3c816426530c9ff7286723df1
|
data/CHANGELOG.md
CHANGED
@@ -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
|
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
data/lib/lono.rb
CHANGED
@@ -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 :
|
28
|
-
autoload :
|
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 :
|
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
|
data/lib/lono/cfn.rb
CHANGED
@@ -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 :
|
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
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
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
|
-
|
34
|
+
base_options.call
|
35
|
+
wait_option.call
|
28
36
|
long_desc Lono::Help.text("cfn/create")
|
29
|
-
def create(
|
30
|
-
Create.new(
|
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
|
-
|
40
|
-
|
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
|
-
|
47
|
-
|
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
|
-
|
55
|
-
|
56
|
-
|
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
|
-
|
62
|
-
|
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
|
-
|
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
|
data/lib/lono/cfn/base.rb
CHANGED
@@ -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
|
-
@
|
10
|
-
|
11
|
-
@
|
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] ||
|
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
|
-
#
|
176
|
-
|
177
|
-
|
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
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
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
|
-
|
235
|
+
stack_name
|
186
236
|
end
|
187
237
|
end
|
188
238
|
|
189
|
-
|
190
|
-
|
191
|
-
|
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['
|
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
|
data/lib/lono/cfn/create.rb
CHANGED
@@ -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
|
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
|
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
|