lono 1.1.3 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (83) hide show
  1. checksums.yaml +4 -4
  2. data/.gitmodules +3 -0
  3. data/CHANGELOG.md +8 -0
  4. data/README.md +150 -39
  5. data/bin/lono +2 -2
  6. data/circle.yml +4 -0
  7. data/lib/lono.rb +16 -7
  8. data/lib/lono/cfn.rb +64 -0
  9. data/lib/lono/cfn/aws_services.rb +37 -0
  10. data/lib/lono/cfn/base.rb +144 -0
  11. data/lib/lono/cfn/create.rb +34 -0
  12. data/lib/lono/cfn/delete.rb +26 -0
  13. data/lib/lono/cfn/diff.rb +43 -0
  14. data/lib/lono/cfn/help.rb +93 -0
  15. data/lib/lono/cfn/preview.rb +133 -0
  16. data/lib/lono/cfn/update.rb +62 -0
  17. data/lib/lono/cfn/util.rb +21 -0
  18. data/lib/lono/cli.rb +19 -10
  19. data/lib/lono/command.rb +25 -0
  20. data/lib/lono/help.rb +59 -0
  21. data/lib/lono/new.rb +3 -2
  22. data/lib/lono/param.rb +20 -0
  23. data/lib/lono/param/generator.rb +90 -0
  24. data/lib/lono/param/help.rb +15 -0
  25. data/lib/lono/project_checker.rb +44 -0
  26. data/lib/lono/template.rb +22 -248
  27. data/lib/lono/template/bashify.rb +39 -0
  28. data/lib/lono/template/dsl.rb +139 -0
  29. data/lib/lono/template/help.rb +25 -0
  30. data/lib/lono/template/template.rb +251 -0
  31. data/lib/lono/version.rb +1 -1
  32. data/lib/{starter_project_yaml → starter_projects/json_project}/Gemfile +0 -1
  33. data/lib/{starter_project_json → starter_projects/json_project}/Guardfile +0 -0
  34. data/lib/{starter_project_json → starter_projects/json_project}/config/lono.rb +0 -0
  35. data/lib/{starter_project_json → starter_projects/json_project}/config/lono/api.rb +0 -0
  36. data/lib/starter_projects/json_project/params/api-web-prod.txt +20 -0
  37. data/lib/{starter_project_json → starter_projects/json_project}/templates/db.json.erb +0 -0
  38. data/lib/{starter_project_json → starter_projects/json_project}/templates/partial/host_record.json.erb +0 -0
  39. data/lib/{starter_project_json → starter_projects/json_project}/templates/partial/server.json.erb +0 -0
  40. data/lib/{starter_project_json → starter_projects/json_project}/templates/user_data/app.sh.erb +0 -0
  41. data/lib/{starter_project_json → starter_projects/json_project}/templates/user_data/db.sh.erb +0 -0
  42. data/lib/{starter_project_json → starter_projects/json_project}/templates/user_data/db2.sh.erb +0 -0
  43. data/lib/{starter_project_json → starter_projects/json_project}/templates/user_data/ruby_script.rb.erb +0 -0
  44. data/lib/{starter_project_json → starter_projects/json_project}/templates/web.json.erb +0 -0
  45. data/lib/{starter_project_json → starter_projects/yaml_project}/Gemfile +0 -1
  46. data/lib/{starter_project_yaml → starter_projects/yaml_project}/Guardfile +0 -0
  47. data/lib/{starter_project_yaml → starter_projects/yaml_project}/config/lono.rb +0 -0
  48. data/lib/{starter_project_yaml → starter_projects/yaml_project}/config/lono/api.rb +0 -0
  49. data/lib/starter_projects/yaml_project/params/api-web-prod.txt +20 -0
  50. data/lib/{starter_project_yaml → starter_projects/yaml_project}/templates/db.yml.erb +0 -0
  51. data/lib/{starter_project_yaml → starter_projects/yaml_project}/templates/partial/host_record.yml.erb +0 -0
  52. data/lib/{starter_project_yaml → starter_projects/yaml_project}/templates/partial/server.yml.erb +0 -0
  53. data/lib/{starter_project_yaml → starter_projects/yaml_project}/templates/partial/user_data/bootstrap.sh.erb +0 -0
  54. data/lib/{starter_project_yaml → starter_projects/yaml_project}/templates/web.yml.erb +0 -0
  55. data/lono.gemspec +15 -10
  56. data/spec/fixtures/my_project/config/lono.rb +1 -0
  57. data/spec/fixtures/my_project/params/my-stack.txt +3 -0
  58. data/spec/fixtures/my_project/templates/.gitkeep +0 -0
  59. data/spec/fixtures/my_project/templates/my-stack.yml.erb +0 -0
  60. data/spec/lib/lono/cfn_spec.rb +35 -0
  61. data/spec/lib/lono/new_spec.rb +3 -3
  62. data/spec/lib/lono/param_spec.rb +15 -0
  63. data/spec/lib/lono/{dsl_spec.rb → template/dsl_spec.rb} +9 -9
  64. data/spec/lib/lono/template/template_spec.rb +104 -0
  65. data/spec/lib/lono/template_spec.rb +22 -37
  66. data/spec/lib/lono_spec.rb +6 -83
  67. data/vendor/plissken/Gemfile +14 -0
  68. data/vendor/plissken/LICENSE.txt +20 -0
  69. data/vendor/plissken/README.md +46 -0
  70. data/vendor/plissken/Rakefile +56 -0
  71. data/vendor/plissken/VERSION +1 -0
  72. data/vendor/plissken/lib/plissken.rb +1 -0
  73. data/vendor/plissken/lib/plissken/ext/hash/to_snake_keys.rb +45 -0
  74. data/vendor/plissken/plissken.gemspec +61 -0
  75. data/vendor/plissken/spec/lib/to_snake_keys_spec.rb +177 -0
  76. data/vendor/plissken/spec/spec_helper.rb +90 -0
  77. data/vendor/plissken/test/helper.rb +20 -0
  78. data/vendor/plissken/test/plissken/ext/hash/to_snake_keys_test.rb +184 -0
  79. data/vendor/plissken/test/test_plissken.rb +2 -0
  80. metadata +115 -39
  81. data/lib/lono/bashify.rb +0 -41
  82. data/lib/lono/cli/help.rb +0 -37
  83. data/lib/lono/dsl.rb +0 -132
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 9f79d721191571eaa17df7a5e037281b4631ca0e
4
- data.tar.gz: f38b1dbae7db19838efae137471d0685710b43d8
3
+ metadata.gz: 380e874615eea57c1cc0788f77aef520d453e8c1
4
+ data.tar.gz: fb70edb0ff4a31521f6df6d3085fdde5fd47014d
5
5
  SHA512:
6
- metadata.gz: 6d3eeb1096333c819438a73d03c81de71fcc367e5ab1ba34393fae138b39b99e8a5f7bd9cec1d4fcdcbd38af62eca13d91d6fbce93ab41b592f95da78f93e2f7
7
- data.tar.gz: 250cabca938f4f5eb8b48f15843ac6cd70387ed7e322e5ff40cd00918f22da36b5de247b73ba55138bff77ca8eb98aed6ebccc1b167a298ebe471d6c18ce9568
6
+ metadata.gz: c529da1117901155fe7ddc3033d779611370d3654ad01e76e5c5364a917f956911501d4014228166e22386457f3d2a2dbfa335ba9272eb1ef63ef0b85934dc4a
7
+ data.tar.gz: c31a6c825e2c42a1828d333fc22034c9605566c2cd6433104df21df25be0ea17e7990d555e55bb97ce07ecace12c119e8262153c12bf636b6e1c85df7bd74cd4
@@ -0,0 +1,3 @@
1
+ [submodule "vendor/plissken"]
2
+ path = vendor/plissken
3
+ url = git@github.com:tongueroo/plissken.git
@@ -3,6 +3,14 @@
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
+ ## [2.0.0]
7
+ - added lono cfn subcommand to launch CloudFormation stacks
8
+ - added lono params subcommand to generate CloudFormation parameter files
9
+ - moved lono template methods into subcommand. lono generate still available at top level.
10
+
11
+ ## [1.1.4]
12
+ - allow --help or -h at the end of the command
13
+
6
14
  ## [1.1.3]
7
15
  - make display output path prettier
8
16
 
data/README.md CHANGED
@@ -2,30 +2,27 @@
2
2
 
3
3
  [![ReadmeCI](http://www.readmeci.com/images/readmeci-badge.svg)](http://www.readmeci.com/tongueroo/lono)
4
4
  [![Gem Version](https://badge.fury.io/rb/lono.png)](http://badge.fury.io/rb/lono)
5
- [![Build History][2]][1]
5
+ [![CircleCI](https://circleci.com/gh/tongueroo/lono.svg?style=svg)](https://circleci.com/gh/tongueroo/lono)
6
6
  [![Code Climate][3]][4]
7
7
  [![Dependency Status](https://gemnasium.com/tongueroo/lono.png)](https://gemnasium.com/tongueroo/lono)
8
8
  [![Coverage Status](https://coveralls.io/repos/tongueroo/lono/badge.png)](https://coveralls.io/r/tongueroo/lono)
9
9
 
10
- [1]: http://travis-ci.org/tongueroo/lono
11
- [2]: https://secure.travis-ci.org/tongueroo/lono.png?branch=master
12
10
  [3]: https://codeclimate.com/repos/51d7f1407e00a4042c010ab4/badges/5273fe6cdb5a13e58554/gpa.png
13
11
  [4]: https://codeclimate.com/repos/51d7f1407e00a4042c010ab4/feed
14
12
 
15
- Lono is a CloudFormation Template generator. Lono generates CloudFormation templates based on ERB ruby templates in either `yaml` or `json` format.
13
+ Lono is a tool for managing CloudFormation templates.
16
14
 
17
- Lono can be used with [lono-cfn](https://github.com/tongueroo/lono-cfn). Lono-cfn automatically calls `lono generate` as part of launching the stack so you never forget to run it. These blog posts cover both lono and lono-cfn:
15
+ * Lono generates CloudFormation templates based on ERB ruby templates in either `yaml` or `json` format.
16
+ * Lono takes simple env-like files to and generates the CloudFormation parameter files.
17
+ * Lono wraps the CloudFormation api calls in a simple interface using the generated files to launch the CloudFormation stacks.
18
+
19
+ These blog posts lono:
18
20
 
19
21
  * [Why Generate CloudFormation Templates with Lono](https://medium.com/boltops/why-generate-cloudformation-templates-with-lono-65b8ea5eb87d)
20
22
  * [Generating CloudFormation Templates with Lono](https://medium.com/boltops/generating-cloudformation-templates-with-lono-4709afa1299b)
21
23
  * [AutoScaling CloudFormation Template with Lono](https://medium.com/boltops/autoscaling-cloudformation-template-with-lono-3dc520480c5f)
22
- * [CloudFormation Tools: lono, lono-params and lono-cfn Together
23
- ](https://medium.com/boltops/cloudformation-tools-lono-lono-params-and-lono-cfn-play-together-620af51e616)
24
- * [AWS CloudFormation dry-run with lono-cfn plan](https://medium.com/boltops/aws-cloudformation-dry-run-with-lono-cfn-plan-2a1e0f80d13c)
25
-
26
- **UPDATE**: lono now supports yaml format for CloudFormation! The old json format is still supported. For current projects, you do not have to change anything as the format is autodetected as part of `lono generate`.
27
-
28
- Newly generated projects with `lono new infra` will use the yaml format by default. If you prefer the json format use `lono new --format json infra`. You cannot mix and match json and yaml format in one project, it's either all json or yaml. If any one has questions feel free to ping me: tongueroo@gmail.com.
24
+ * [CloudFormation Tools: lono, lono-params and lono cfn Together](https://medium.com/boltops/cloudformation-tools-lono-lono-params-and-lono-cfn-play-together-620af51e616)
25
+ * [AWS CloudFormation dry-run with lono cfn preview](https://medium.com/boltops/aws-cloudformation-dry-run-with-lono-cfn-plan-2a1e0f80d13c)
29
26
 
30
27
  ## Usage
31
28
 
@@ -33,14 +30,18 @@ Newly generated projects with `lono new infra` will use the yaml format by defau
33
30
  $ lono new infra
34
31
  </pre>
35
32
 
36
- This sets up a starter lono project called infra with example templates. Next you cd into the folder and generate the templates.
33
+ This sets up a starter lono project called infra with example templates. Next you cd into the folder and generate the template and parameter files.
37
34
 
38
35
  <pre>
39
36
  $ cd infra
40
37
  $ lono generate
41
38
  </pre>
42
39
 
43
- This generates the templates in the `config` and `templates` folders to the `output` folder.
40
+ This CloudFormation template and parameter files are now available under `output` and `output/params`.
41
+
42
+ ### Generate Template Files
43
+
44
+ The CloudFormation templates files that were generated from the `config` and `templates` folders and written to the `output` folder.
44
45
 
45
46
  The starter lono template project config files looks like [this](lib/starter_project_yaml/config/lono.rb) and [this](lib/starter_project_yaml/config/lono/api.rb). Here's a snippet from one of the config files: [config/lono.rb](lib/starter_project_yaml/config/lono.rb).
46
47
 
@@ -171,6 +172,31 @@ You can use the generated CloudFormation templates in the `output` folder just a
171
172
 
172
173
  ![Lono flowchart](http://tongueroo.com/images/github-readmes/lono-flowchart.png "Lono flowchart")
173
174
 
175
+ ### Generate Parameter Files
176
+
177
+ With lono you write simpler params file that is formatted with a simple `key=value` env-like file. The `params/mystack.txt` is shorter format versus the verbose standard CloudFormation parameters json file. Here is an example of a simple `params/mystack.txt` param file.
178
+
179
+ ```bash
180
+ Param1=1
181
+ Param2=2
182
+ ```
183
+
184
+ The `lono generate` command generates the CloudFormation parameter file in `output/params/mystack.json` which looks like this:
185
+
186
+
187
+ ```json
188
+ [
189
+ {
190
+ "ParameterKey": "Param1",
191
+ "ParameterValue": "1"
192
+ },
193
+ {
194
+ "ParameterKey": "Param2",
195
+ "ParameterValue": "2"
196
+ }
197
+ ]
198
+ ```
199
+
174
200
  ## Template helper methods
175
201
 
176
202
  There are helper methods that are available in templates.
@@ -189,7 +215,7 @@ If you have a lot of templates, the config/lono.rb file can get unwieldy long.
189
215
 
190
216
  ## Generate
191
217
 
192
- You can generate the CF templates by running:
218
+ You can generate the CloudFormation templates by running:
193
219
 
194
220
  <pre>
195
221
  $ lono generate
@@ -202,39 +228,124 @@ The lono init command also sets up guard-lono. Guard-lono continuously generate
202
228
  $ guard
203
229
  </pre>
204
230
 
205
- ## lono-cfn and lono-params
231
+ # lono cfn
206
232
 
207
- Running `lono generate` and building up the `aws cloudformation create-stack` command repeatedly gets old. The `lono-cfn` tool will automatically run `lono generate` and then launch the CloudFormation stack all in one command. Example usage:
233
+ ## Summary
234
+ Lono also provides a `lono cfn` wrapper command that allows you to launch stacks from the lono templates. The `lono cfn` tool automatically runs `lono generate` internally and then launches the CloudFormation stack all in one command. Provided that you are in a lono project and have a `my-stack` lono template definition. To create a stack you can simply run:
208
235
 
209
236
  ```
210
- $ lono-cfn create mystack-$(date +%Y%m%d%H%M%S) --template mystack --params mystack
211
- $ lono-cfn create mystack-$(date +%Y%m%d%H%M%S) # shorthand if template and params file matches.
212
- $ lono-cfn update mystack-1493859659
213
- $ lono-cfn delete mystack-1493859659
237
+ $ lono cfn create my-stack
214
238
  ```
215
239
 
216
- More info about lono-cfn here: [lono-cfn](https://github.com/tongueroo/lono-cfn) - Wrapper cfn tool to quickly create CloudFormation stacks from lono templates and params files.
240
+ The above command will generate files to `output/my-stack.json` and `output/params/my-stack.txt` and use them to create a CloudFormation stack. Here are some more examples of cfn commands:
217
241
 
218
- The params file is formatted with a simple `key=value`, env-like file. It is cleaner to have a `params/mystack.txt` file like so:
242
+ ```
243
+ $ lono cfn create mystack-$(date +%Y%m%d%H%M%S) --template mystack --params mystack
244
+ $ lono cfn create mystack-$(date +%Y%m%d%H%M%S) # shorthand if template and params file matches.
245
+ $ lono cfn diff mystack-1493859659
246
+ $ lono cfn preview mystack-1493859659
247
+ $ lono cfn update mystack-1493859659
248
+ $ lono cfn delete mystack-1493859659
249
+ $ lono cfn create -h # getting help
250
+ ```
219
251
 
220
- ```bash
221
- Param1=1
222
- Param2=2
252
+ ### Conventions
253
+
254
+ The template by convention defaults to the name of the stack. In turn, the params by convention defaults to the name of the template.
255
+
256
+ * stack - This is a required parameter and is the CLI first parameter.
257
+ * template - By convention matches the stack name but can be overriden with `--template`.
258
+ * params - By convention matches the template name but can be overriden with `--params`.
259
+
260
+ The conventions allows the command to be a very nice short command that can be easily remembered. For example, these 2 commands are the same:
261
+
262
+ ### lono cfn create
263
+
264
+ Long form:
265
+
266
+ ```
267
+ $ lono cfn create my-stack --template my-stack --params --my-stack
223
268
  ```
224
269
 
225
- Verus the rather verbose standard CloudFormation parameters json file:
270
+ Short form:
226
271
 
227
- ```json
228
- [
229
- {
230
- "ParameterKey": "Param1",
231
- "ParameterValue": "1"
232
- },
233
- {
234
- "ParameterKey": "Param2",
235
- "ParameterValue": "2"
236
- }
237
- ]
238
272
  ```
273
+ $ lono cfn create my-stack
274
+ ```
275
+
276
+
277
+ Both template and params conventions can be overridden. Here are examples of overriding the template and params name conventions.
278
+
279
+ ```
280
+ $ lono cfn create my-stack --template different-name1
281
+ ```
282
+
283
+ The template that will be use is output/different-name1.json and the parameters will use params/different-name1.json.
239
284
 
240
- More info about lono-params here: [lono-params](https://github.com/tongueroo/lono-params) - Tool to generate a CloudFormation parameters json formatted file from a simplier env like file.
285
+ ```
286
+ $ lono cfn create my-stack --params different-name2
287
+ ```
288
+
289
+ The template that will be use is output/different-name2.json and the parameters will use params/different-name2.json.
290
+
291
+ ```
292
+ $ lono cfn create my-stack --template different-name3 --params different-name4
293
+ ```
294
+
295
+ The template that will be use is output/different-name3.json and the parameters will use params/different-name4.json.
296
+
297
+ ### lono cfn update
298
+
299
+ To update stacks you can use `lono cfn update`:
300
+
301
+ ```
302
+ $ lono cfn update my-stack --template template-name --params params-name
303
+ ```
304
+
305
+ By default the update command will display a preview of the stack changes before applying the update and prompt to check if you are sure. If you want to bypass the are you sure prompt, use the `--sure` option.
306
+
307
+ ```
308
+ $ lono cfn update my-stack --template template-name --params params-name --sure
309
+ ```
310
+
311
+ ### lono cfn delete
312
+
313
+ ```
314
+ $ lono cfn delete my-stack --sure
315
+ ```
316
+
317
+ ### lono cfn preview
318
+
319
+ If you want to see the CloudFormation preview without updating the stack you can also use the `lono cfn preview` command. The preview command is also covered in this blog post: [AWS CloudFormation dry-run with lono cfn preview](https://medium.com/boltops/aws-cloudformation-dry-run-with-lono cfn-plan-2a1e0f80d13c)
320
+
321
+ ```
322
+ $ lono cfn preview example --template single_instance --params single_instance
323
+ Using template: output/single_instance.yml
324
+ Using parameters: params/single_instance.txt
325
+ Generating CloudFormation templates:
326
+ ./output/single_instance.yml
327
+ Params file generated for example at ./output/params/example.json
328
+ Generating CloudFormation Change Set for preview.....
329
+ CloudFormation preview for 'example' stack update. Changes:
330
+ Remove AWS::Route53::RecordSet: DnsRecord testsubdomain.sub.tongueroo.com
331
+ $
332
+ ```
333
+
334
+
335
+ ## Contributing
336
+
337
+ 1. Fork it
338
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
339
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
340
+ 4. Push to the branch (`git push origin my-new-feature`)
341
+ 5. Create new Pull Request
342
+
343
+ ## Developing
344
+
345
+ There is a submodule in this project, so when you check out remember to sync the submodule.
346
+
347
+ ```bash
348
+ $ git clone git@github.com:yourfork/lono.git
349
+ $ git submodule sync
350
+ $ git submodule update --init
351
+ ```
data/bin/lono CHANGED
@@ -1,4 +1,4 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
- require File.expand_path("../../lib/lono", __FILE__)
4
- Lono::CLI.start
3
+ require_relative "../lib/lono"
4
+ Lono::CLI.start
@@ -0,0 +1,4 @@
1
+ checkout:
2
+ post:
3
+ - git submodule sync --recursive
4
+ - git submodule update --init --recursive
@@ -4,10 +4,19 @@ require 'pp'
4
4
  require 'colorize'
5
5
  require 'fileutils'
6
6
 
7
- $:.unshift File.dirname(__FILE__)
8
- require 'lono/version'
9
- require 'lono/cli'
10
- require 'lono/new'
11
- require 'lono/template'
12
- require 'lono/dsl'
13
- require 'lono/bashify'
7
+ # vendor because need https://github.com/futurechimp/plissken/pull/6 to be merged
8
+ $:.unshift(File.expand_path("../../vendor/plissken/lib", __FILE__))
9
+ require "plissken"
10
+
11
+ $:.unshift(File.expand_path('../', __FILE__))
12
+ module Lono
13
+ autoload :VERSION, 'lono/version'
14
+ autoload :Help, 'lono/help'
15
+ autoload :ProjectChecker, 'lono/project_checker'
16
+ autoload :Command, 'lono/command'
17
+ autoload :CLI, 'lono/cli'
18
+ autoload :New, 'lono/new'
19
+ autoload :Template, 'lono/template'
20
+ autoload :Cfn, 'lono/cfn'
21
+ autoload :Param, 'lono/param'
22
+ end
@@ -0,0 +1,64 @@
1
+ require "thor"
2
+
3
+ module Lono
4
+ class Cfn < Command
5
+ autoload :Help, 'lono/cfn/help'
6
+ autoload :AwsServices, 'lono/cfn/aws_services'
7
+ autoload :Util, 'lono/cfn/util'
8
+ autoload :CLI, 'lono/cfn/cli'
9
+ autoload :Base, 'lono/cfn/base'
10
+ autoload :Create, 'lono/cfn/create'
11
+ autoload :Update, 'lono/cfn/update'
12
+ autoload :Delete, 'lono/cfn/delete'
13
+ autoload :Preview, 'lono/cfn/preview'
14
+ autoload :Diff, 'lono/cfn/diff'
15
+
16
+ class_option :verbose, type: :boolean
17
+ class_option :noop, type: :boolean
18
+ class_option :project_root, desc: "Project folder. Defaults to current directory", default: "."
19
+ class_option :region, desc: "AWS region"
20
+
21
+ # common to create and update
22
+ class_option :template, desc: "override convention and specify the template file to use"
23
+ class_option :param, desc: "override convention and specify the param file to use"
24
+ class_option :lono, type: :boolean, desc: "invoke lono to generate CloudFormation templates", default: true
25
+
26
+ desc "create STACK", "create a CloudFormation stack"
27
+ long_desc Help.create
28
+ def create(name)
29
+ Create.new(name, options).run
30
+ end
31
+
32
+ desc "update STACK", "update a CloudFormation stack"
33
+ long_desc Help.update
34
+ option :change_set, type: :boolean, default: true, desc: "Uses generated change set to update the stack. If false, will perform normal update-stack."
35
+ option :diff, type: :boolean, default: true, desc: "Show diff of the source code template changes before continuing."
36
+ option :preview, type: :boolean, default: true, desc: "Show preview of the stack changes before continuing."
37
+ option :sure, type: :boolean, desc: "Skips are you sure prompt"
38
+ def update(name)
39
+ Update.new(name, options).run
40
+ end
41
+
42
+ desc "delete STACK", "delete a CloudFormation stack"
43
+ long_desc Help.delete
44
+ option :sure, type: :boolean, desc: "Skips are you sure prompt"
45
+ def delete(name)
46
+ Delete.new(name, options).run
47
+ end
48
+
49
+ desc "preview STACK", "preview a CloudFormation stack update"
50
+ long_desc Help.preview
51
+ option :keep, type: :boolean, desc: "keep the changeset instead of deleting it afterwards"
52
+ option :diff, type: :boolean, default: true, desc: "Show diff of the source code template changes also."
53
+ def preview(name)
54
+ Diff.new(name, options).run if options[:diff]
55
+ Preview.new(name, options).run
56
+ end
57
+
58
+ desc "diff STACK", "diff of newly generated template vs existing template in AWS"
59
+ long_desc Help.diff
60
+ def diff(name)
61
+ Diff.new(name, options).run
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,37 @@
1
+ require "aws-sdk"
2
+
3
+ module Lono::Cfn::AwsServices
4
+ def cfn
5
+ @cfn ||= Aws::CloudFormation::Client.new
6
+ end
7
+
8
+ def stack_exists?(stack_name)
9
+ return true if testing_update?
10
+ return false if @options[:noop]
11
+
12
+ exist = nil
13
+ begin
14
+ # When the stack does not exist an exception is raised. Example:
15
+ # Aws::CloudFormation::Errors::ValidationError: Stack with id blah does not exist
16
+ resp = cfn.describe_stacks(stack_name: stack_name)
17
+ exist = true
18
+ rescue Aws::CloudFormation::Errors::ValidationError => e
19
+ if e.message =~ /does not exist/
20
+ exist = false
21
+ elsif e.message.include?("'stackName' failed to satisfy constraint")
22
+ # Example of e.message when describe_stack with invalid stack name
23
+ # "1 validation error detected: Value 'instance_and_route53' at 'stackName' failed to satisfy constraint: Member must satisfy regular expression pattern: [a-zA-Z][-a-zA-Z0-9]*|arn:[-a-zA-Z0-9:/._+]*"
24
+ puts "Invalid stack name: #{stack_name}"
25
+ puts "Full error message: #{e.message}"
26
+ exit 1
27
+ else
28
+ raise # re-raise exception because unsure what other errors can happen
29
+ end
30
+ end
31
+ exist
32
+ end
33
+
34
+ def testing_update?
35
+ ENV['TEST'] && self.class.name == "LonoCfn::Update"
36
+ end
37
+ end
@@ -0,0 +1,144 @@
1
+ require "lono"
2
+
3
+ class Lono::Cfn::Base
4
+ include Lono::Cfn::AwsServices
5
+ include Lono::Cfn::Util
6
+
7
+ def initialize(stack_name, options={})
8
+ @stack_name = stack_name
9
+ @options = options
10
+ @project_root = options[:project_root] || '.'
11
+ ProjectChecker.check(@project_root) unless options[:lono] # already ran checker in lono generate
12
+
13
+ template_name = options[:template] || @stack_name
14
+ param_name = options[:param] || template_name
15
+ @template_path = get_source_path(template_name, :template)
16
+ @param_path = get_source_path(param_name, :param)
17
+ puts "Using template: #{@template_path}" unless @options[:mute_using]
18
+ puts "Using parameters: #{@param_path}" unless @options[:mute_using]
19
+ end
20
+
21
+ def run
22
+ params = generate_all
23
+ save_stack(params) # defined in the sub class
24
+ end
25
+
26
+ def generate_all
27
+ generate_templates if @options[:lono]
28
+ check_for_errors
29
+ generate_params(mute: @options[:mute_params])
30
+ end
31
+
32
+ def generate_templates
33
+ Lono::Template::DSL.new(
34
+ project_root: @project_root,
35
+ pretty: true
36
+ ).run
37
+ end
38
+
39
+ def generate_params(options={})
40
+ generator_options = {
41
+ project_root: @project_root,
42
+ path: @param_path,
43
+ allow_no_file: true
44
+ }.merge(options)
45
+ generator = Lono::Param::Generator.new(@stack_name, generator_options)
46
+ generator.generate # Writes the json file in CamelCase keys format
47
+ generator.params # Returns Array in underscore keys format
48
+ end
49
+
50
+ def check_for_errors
51
+ errors, warns = check_files
52
+ unless errors.empty?
53
+ puts "Please double check the command you ran. There were some errors."
54
+ puts "ERROR: #{errors.join("\n")}".colorize(:red)
55
+ exit
56
+ end
57
+ unless warns.empty?
58
+ puts "Please double check the command you ran. There were some warnings."
59
+ puts "WARN: #{warns.join("\n")}".colorize(:yellow)
60
+ end
61
+ end
62
+
63
+ def check_files
64
+ errors, warns = [], []
65
+ unless File.exist?(@template_path)
66
+ warns << "Template file missing: could not find #{@template_path}"
67
+ end
68
+ if @options[:param] && !File.exist?(@param_path)
69
+ warns << "Parameters file missing: could not find #{@param_path}"
70
+ end
71
+ [errors, warns]
72
+ end
73
+
74
+ # if existing in params path then use that
75
+ # if it doesnt assume it is a full path and check that
76
+ # else fall back to convention, which also eventually gets checked in check_for_errors
77
+ #
78
+ # Type - :param or :template
79
+ def get_source_path(path, type)
80
+ if path.nil?
81
+ default_convention_path = convention_path(@stack_name, type)
82
+ else
83
+ # convention path based on the input from the user
84
+ convention_path(path, type)
85
+ end
86
+ end
87
+
88
+ def convention_path(name, type)
89
+ path = case type
90
+ when :template
91
+ format = detect_format
92
+ "#{@project_root}/output/#{name}.#{format}"
93
+ when :param
94
+ "#{@project_root}/params/#{name}.txt"
95
+ else
96
+ raise "hell: dont come here"
97
+ end
98
+ path.sub(/^\.\//, '')
99
+ end
100
+
101
+ # Returns String with value of "yml" or "json".
102
+ def detect_format
103
+ formats = Dir.glob("#{@project_root}/output/**/*").map { |path| path }.
104
+ reject { |s| s =~ %r{/params/} }. # reject output/params folder
105
+ map { |path| File.extname(path) }.
106
+ reject { |s| s.empty? }. # reject ""
107
+ uniq
108
+ if formats.size > 1
109
+ puts "ERROR: Detected multiple formats: #{formats.join(", ")}".colorize(:red)
110
+ puts "All the output files must use the same format. Either all json or all yml."
111
+ exit 1
112
+ elsif formats.size == 1
113
+ formats.first.sub(/^\./,'')
114
+ else
115
+ puts "WARN: Did not detect any template formats. Defaulting to yml. Please check the config and templates folders."
116
+ "yml" # default format
117
+ end
118
+ end
119
+
120
+ # All CloudFormation states listed here:
121
+ # http://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/using-cfn-describing-stacks.html
122
+ def stack_status(stack_name)
123
+ return true if testing_update?
124
+ return false if @options[:noop]
125
+
126
+ resp = cfn.describe_stacks(stack_name: stack_name)
127
+ status = resp.stacks[0].stack_status
128
+ end
129
+
130
+ def exist_unless_updatable(status)
131
+ return true if testing_update?
132
+ return false if @options[:noop]
133
+
134
+ unless status =~ /_COMPLETE$/
135
+ puts "Cannot create a change set for the stack because the #{@stack_name} is not in an updatable state. Stack status: #{status}"
136
+ quit(1)
137
+ end
138
+ end
139
+
140
+ # To allow mocking in specs
141
+ def quit(signal)
142
+ exit signal
143
+ end
144
+ end