lono 5.2.8 → 5.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +7 -0
- data/README.md +2 -0
- data/lib/lono/cfn.rb +9 -13
- data/lib/lono/cfn/preview.rb +2 -149
- data/lib/lono/cfn/preview/changeset.rb +154 -0
- data/lib/lono/cfn/{diff.rb → preview/codediff.rb} +6 -14
- data/lib/lono/cfn/preview/diff_viewer.rb +19 -0
- data/lib/lono/cfn/preview/param.rb +73 -0
- data/lib/lono/cfn/update.rb +15 -8
- data/lib/lono/inspector.rb +1 -1
- data/lib/lono/inspector/base.rb +30 -36
- data/lib/lono/inspector/graph.rb +100 -99
- data/lib/lono/inspector/summary.rb +48 -59
- data/lib/lono/output_template.rb +35 -0
- data/lib/lono/param/generator.rb +38 -9
- data/lib/lono/seed/base.rb +5 -3
- data/lib/lono/template/context.rb +2 -0
- data/lib/lono/template/context/helpers.rb +14 -0
- data/lib/lono/template/context/ssm_fetcher.rb +23 -0
- data/lib/lono/template/dsl/builder/parameter.rb +4 -4
- data/lib/lono/template/dsl/builder/resource.rb +10 -5
- data/lib/lono/template/dsl/builder/resource/property_mover.rb +19 -0
- data/lib/lono/version.rb +1 -1
- data/lono.gemspec +1 -0
- metadata +24 -4
- data/lib/lono/help/cfn/diff.md +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 805088c405e44e3e7b228f5d03a893af2a99c2ce990615bb89b906c0c2bb56ee
|
4
|
+
data.tar.gz: fff83f7bdae3c28fed272a489e3170d09f803d35a05e943b98db33c89e5d7a9e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bd70ed81d8e4495dff371cd2ec66b519b1002325dac0d17d094a31127ea4e9d186a00001200391f36b9dcece8f85b25f085abeb09c49eedc1f269be457113ad0
|
7
|
+
data.tar.gz: 9bb60f3efa20a1c06a0597656f0729e1723380c2af6b20f673f28f4b08fe2ac941876e3252f405864bd488b989b5d7436ce3dad50b65bb059bf51371751b0290
|
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
|
+
## [5.3.0]
|
7
|
+
- #8 param preview feature. 3rd type of preview.
|
8
|
+
- #9 ssm helper support in configs
|
9
|
+
- Simplify param lookup with direct lookup logic.
|
10
|
+
- Allow params files to have different extensions. Both.txt and .sh work are auto-inferred conventionally.
|
11
|
+
- Allow condition and depends_on to be a properties level and auto-moved to the attributes level.
|
12
|
+
|
6
13
|
## [5.2.8]
|
7
14
|
- add mfa support for normal IAM user
|
8
15
|
|
data/README.md
CHANGED
@@ -8,6 +8,8 @@
|
|
8
8
|
[![CircleCI](https://circleci.com/gh/tongueroo/lono.svg?style=svg)](https://circleci.com/gh/tongueroo/lono)
|
9
9
|
[![Support](https://img.shields.io/badge/get-support-blue.svg)](https://boltops.com?utm_source=badge&utm_medium=badge&utm_campaign=lono)
|
10
10
|
|
11
|
+
[![BoltOps Badge](https://img.boltops.com/boltops/badges/boltops-badge.png)](https://www.boltops.com)
|
12
|
+
|
11
13
|
Lono is a powerful CloudFormation framework. Lono handles the entire CloudFormation lifecycle. It builds, manages and deploys CloudFormation templates.
|
12
14
|
|
13
15
|
* Lono generates CloudFormation templates based on a [DSL](http://lono.cloud/docs/dsl/).
|
data/lib/lono/cfn.rb
CHANGED
@@ -22,8 +22,9 @@ module Lono
|
|
22
22
|
end
|
23
23
|
update_options = Proc.new do
|
24
24
|
option :change_set, type: :boolean, default: true, desc: "Uses generated change set to update the stack. If false, will perform normal update-stack."
|
25
|
-
option :
|
26
|
-
option :
|
25
|
+
option :codediff_preview, type: :boolean, default: true, desc: "Show codediff changes preview."
|
26
|
+
option :changeset_preview, type: :boolean, default: true, desc: "Show ChangeSet changes preview."
|
27
|
+
option :param_preview, type: :boolean, default: true, desc: "Show parameter diff preview."
|
27
28
|
option :sure, type: :boolean, desc: "Skips are you sure prompt"
|
28
29
|
end
|
29
30
|
|
@@ -75,20 +76,15 @@ module Lono
|
|
75
76
|
desc "preview STACK", "Preview a CloudFormation stack update. This is similar to terraform's plan or puppet's dry-run mode."
|
76
77
|
long_desc Lono::Help.text("cfn/preview")
|
77
78
|
option :keep, type: :boolean, desc: "keep the changeset instead of deleting it afterwards"
|
78
|
-
option :
|
79
|
+
option :param_preview, type: :boolean, default: true, desc: "Show parameter diff preview."
|
80
|
+
option :codediff_preview, type: :boolean, default: true, desc: "Show codediff changes preview."
|
81
|
+
option :changeset_preview, type: :boolean, default: true, desc: "Show ChangeSet changes preview."
|
79
82
|
base_options.call
|
80
83
|
suffix_option.call
|
81
84
|
def preview(stack_name=:current)
|
82
|
-
|
83
|
-
Preview.new(stack_name, options).run
|
84
|
-
|
85
|
-
|
86
|
-
desc "diff STACK", "Diff newly generated template vs existing template."
|
87
|
-
long_desc Lono::Help.text("cfn/diff")
|
88
|
-
base_options.call
|
89
|
-
suffix_option.call
|
90
|
-
def diff(stack_name=:current)
|
91
|
-
Diff.new(stack_name, options).run
|
85
|
+
Preview::Param.new(stack_name, options).run if options[:param_preview]
|
86
|
+
Preview::Codediff.new(stack_name, options).run if options[:codediff_preview]
|
87
|
+
Preview::Changeset.new(stack_name, options).run if options[:changeset_preview]
|
92
88
|
end
|
93
89
|
|
94
90
|
desc "download STACK", "Download CloudFormation template from existing stack."
|
data/lib/lono/cfn/preview.rb
CHANGED
@@ -1,151 +1,4 @@
|
|
1
1
|
class Lono::Cfn
|
2
|
-
|
3
|
-
# Override run from Base superclass, the run method is different enough with Preview
|
4
|
-
def run
|
5
|
-
if @options[:noop]
|
6
|
-
puts "NOOP CloudFormation preview for #{@stack_name} update"
|
7
|
-
else
|
8
|
-
params = generate_all
|
9
|
-
success = preview_change_set(params)
|
10
|
-
delete_change_set if success && !@options[:keep] # Clean up and delete the change set
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
def preview_change_set(params)
|
15
|
-
success = create_change_set(params)
|
16
|
-
display_change_set if success
|
17
|
-
end
|
18
|
-
|
19
|
-
def create_change_set(params)
|
20
|
-
unless stack_exists?(@stack_name)
|
21
|
-
puts "WARN: Cannot create a change set for the stack because the #{@stack_name} does not exists.".color(:yellow)
|
22
|
-
return false
|
23
|
-
end
|
24
|
-
exit_unless_updatable!(stack_status(@stack_name))
|
25
|
-
|
26
|
-
params = {
|
27
|
-
change_set_name: change_set_name,
|
28
|
-
stack_name: @stack_name,
|
29
|
-
parameters: params,
|
30
|
-
capabilities: capabilities, # ["CAPABILITY_IAM", "CAPABILITY_NAMED_IAM"],
|
31
|
-
}
|
32
|
-
params[:tags] = tags unless tags.empty?
|
33
|
-
set_template_body!(params)
|
34
|
-
show_parameters(params, "cfn.create_change_set")
|
35
|
-
begin
|
36
|
-
cfn.create_change_set(params)
|
37
|
-
rescue Aws::CloudFormation::Errors::ValidationError => e
|
38
|
-
handle_error(e)
|
39
|
-
end
|
40
|
-
true
|
41
|
-
end
|
42
|
-
|
43
|
-
# Example errors:
|
44
|
-
# "Template error: variable names in Fn::Sub syntax must contain only alphanumeric characters, underscores, periods, and colons"
|
45
|
-
def handle_error(e)
|
46
|
-
raise if ENV['FULL_BACKTRACE']
|
47
|
-
|
48
|
-
if e.message =~ /^Parameters: / || e.message =~ /^Template error: /
|
49
|
-
puts "Error creating CloudFormation preview because invalid CloudFormation parameters. Full error message:".color(:red)
|
50
|
-
puts e.message
|
51
|
-
puts "For full backtrace run command again with FULL_BACKTRACE=1"
|
52
|
-
quit(1)
|
53
|
-
else
|
54
|
-
raise
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
def display_change_set
|
59
|
-
print "Generating CloudFormation Change Set for preview.."
|
60
|
-
change_set = describe_change_set
|
61
|
-
until change_set_finished?(change_set) do
|
62
|
-
change_set = describe_change_set
|
63
|
-
sleep 1
|
64
|
-
print '.'
|
65
|
-
end
|
66
|
-
puts
|
67
|
-
|
68
|
-
case change_set.status
|
69
|
-
when "CREATE_COMPLETE"
|
70
|
-
puts "CloudFormation preview for '#{@stack_name}' stack update. Changes:"
|
71
|
-
changes = change_set.changes.sort_by do |change|
|
72
|
-
change["resource_change"]["action"]
|
73
|
-
end
|
74
|
-
changes.each do |change|
|
75
|
-
display_change(change)
|
76
|
-
end
|
77
|
-
when "FAILED"
|
78
|
-
puts "WARN: Fail to create a CloudFormation preview for '#{@stack_name}' stack update. Reason:".color(:yellow)
|
79
|
-
puts change_set.status_reason
|
80
|
-
quit(0)
|
81
|
-
else
|
82
|
-
raise "hell: never come here"
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
def delete_change_set
|
87
|
-
cfn.delete_change_set(
|
88
|
-
change_set_name: change_set_name,
|
89
|
-
stack_name: @stack_name
|
90
|
-
)
|
91
|
-
end
|
92
|
-
|
93
|
-
def execute_change_set
|
94
|
-
cfn.execute_change_set(
|
95
|
-
change_set_name: change_set_name,
|
96
|
-
stack_name: @stack_name
|
97
|
-
)
|
98
|
-
end
|
99
|
-
|
100
|
-
# generates a change set name
|
101
|
-
def change_set_name
|
102
|
-
@change_set_name ||= "changeset-#{Time.now.strftime("%Y%d%m%H%M%S")}"
|
103
|
-
end
|
104
|
-
|
105
|
-
private
|
106
|
-
# Private: formats a Aws::CloudFormation::Types::Change in pretty human readable form
|
107
|
-
#
|
108
|
-
# change - Aws::CloudFormation::Types::Change
|
109
|
-
#
|
110
|
-
# Examples
|
111
|
-
#
|
112
|
-
# display_change(change)
|
113
|
-
# => Remove AWS::Route53::RecordSet: DnsRecord testsubdomain.sub.tongueroo.com
|
114
|
-
#
|
115
|
-
# Returns nil
|
116
|
-
#
|
117
|
-
# change.to_h
|
118
|
-
# {:type=>"Resource",
|
119
|
-
# :resource_change=>
|
120
|
-
# {:action=>"Remove",
|
121
|
-
# :logical_resource_id=>"DnsRecord",
|
122
|
-
# :physical_resource_id=>"testsubdomain.sub.tongueroo.com",
|
123
|
-
# :resource_type=>"AWS::Route53::RecordSet",
|
124
|
-
# :scope=>[],
|
125
|
-
# :details=>[]}}
|
126
|
-
def display_change(change)
|
127
|
-
message = if change.type == "Resource"
|
128
|
-
c = change.resource_change
|
129
|
-
"#{c.action} #{c.resource_type}: #{c.logical_resource_id} #{c.physical_resource_id}"
|
130
|
-
else
|
131
|
-
change.to_h
|
132
|
-
end
|
133
|
-
|
134
|
-
colors = { Remove: :red, Add: :green, Modify: :yellow }
|
135
|
-
action = change.resource_change.action.to_sym
|
136
|
-
message = message.color(colors[action]) if colors.has_key?(action)
|
137
|
-
puts message
|
138
|
-
end
|
139
|
-
|
140
|
-
def change_set_finished?(change_set)
|
141
|
-
change_set.status =~ /_COMPLETE/ || change_set.status == "FAILED"
|
142
|
-
end
|
143
|
-
|
144
|
-
def describe_change_set
|
145
|
-
cfn.describe_change_set(
|
146
|
-
change_set_name: change_set_name,
|
147
|
-
stack_name: @stack_name
|
148
|
-
)
|
149
|
-
end
|
2
|
+
module Preview
|
150
3
|
end
|
151
|
-
end
|
4
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
module Lono::Cfn::Preview
|
2
|
+
class Changeset < Lono::Cfn::Base
|
3
|
+
# Override run from Base superclass, the run method is different enough with Preview
|
4
|
+
def run
|
5
|
+
puts "Changeset Preview:".color(:green)
|
6
|
+
|
7
|
+
if @options[:noop]
|
8
|
+
puts "NOOP CloudFormation preview for #{@stack_name} update"
|
9
|
+
return
|
10
|
+
end
|
11
|
+
|
12
|
+
params = generate_all
|
13
|
+
success = preview_change_set(params)
|
14
|
+
delete_change_set if success && !@options[:keep] # Clean up and delete the change set
|
15
|
+
end
|
16
|
+
|
17
|
+
def preview_change_set(params)
|
18
|
+
success = create_change_set(params)
|
19
|
+
display_change_set if success
|
20
|
+
end
|
21
|
+
|
22
|
+
def create_change_set(params)
|
23
|
+
unless stack_exists?(@stack_name)
|
24
|
+
puts "WARN: Cannot create a change set for the stack because the #{@stack_name} does not exists.".color(:yellow)
|
25
|
+
return false
|
26
|
+
end
|
27
|
+
exit_unless_updatable!(stack_status(@stack_name))
|
28
|
+
|
29
|
+
params = {
|
30
|
+
change_set_name: change_set_name,
|
31
|
+
stack_name: @stack_name,
|
32
|
+
parameters: params,
|
33
|
+
capabilities: capabilities, # ["CAPABILITY_IAM", "CAPABILITY_NAMED_IAM"],
|
34
|
+
}
|
35
|
+
params[:tags] = tags unless tags.empty?
|
36
|
+
set_template_body!(params)
|
37
|
+
show_parameters(params, "cfn.create_change_set")
|
38
|
+
begin
|
39
|
+
cfn.create_change_set(params)
|
40
|
+
rescue Aws::CloudFormation::Errors::ValidationError => e
|
41
|
+
handle_error(e)
|
42
|
+
end
|
43
|
+
true
|
44
|
+
end
|
45
|
+
|
46
|
+
# Example errors:
|
47
|
+
# "Template error: variable names in Fn::Sub syntax must contain only alphanumeric characters, underscores, periods, and colons"
|
48
|
+
def handle_error(e)
|
49
|
+
raise if ENV['FULL_BACKTRACE']
|
50
|
+
|
51
|
+
if e.message =~ /^Parameters: / || e.message =~ /^Template error: /
|
52
|
+
puts "Error creating CloudFormation preview because invalid CloudFormation parameters. Full error message:".color(:red)
|
53
|
+
puts e.message
|
54
|
+
puts "For full backtrace run command again with FULL_BACKTRACE=1"
|
55
|
+
quit(1)
|
56
|
+
else
|
57
|
+
raise
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def display_change_set
|
62
|
+
print "Generating CloudFormation Change Set for preview.."
|
63
|
+
change_set = describe_change_set
|
64
|
+
until change_set_finished?(change_set) do
|
65
|
+
change_set = describe_change_set
|
66
|
+
sleep 1
|
67
|
+
print '.'
|
68
|
+
end
|
69
|
+
puts
|
70
|
+
|
71
|
+
case change_set.status
|
72
|
+
when "CREATE_COMPLETE"
|
73
|
+
puts "CloudFormation preview for '#{@stack_name}' stack update. Changes:"
|
74
|
+
changes = change_set.changes.sort_by do |change|
|
75
|
+
change["resource_change"]["action"]
|
76
|
+
end
|
77
|
+
changes.each do |change|
|
78
|
+
display_change(change)
|
79
|
+
end
|
80
|
+
when "FAILED"
|
81
|
+
puts "WARN: Fail to create a CloudFormation preview for '#{@stack_name}' stack update. Reason:".color(:yellow)
|
82
|
+
puts change_set.status_reason
|
83
|
+
quit(0)
|
84
|
+
else
|
85
|
+
raise "hell: never come here"
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def delete_change_set
|
90
|
+
cfn.delete_change_set(
|
91
|
+
change_set_name: change_set_name,
|
92
|
+
stack_name: @stack_name
|
93
|
+
)
|
94
|
+
end
|
95
|
+
|
96
|
+
def execute_change_set
|
97
|
+
cfn.execute_change_set(
|
98
|
+
change_set_name: change_set_name,
|
99
|
+
stack_name: @stack_name
|
100
|
+
)
|
101
|
+
end
|
102
|
+
|
103
|
+
# generates a change set name
|
104
|
+
def change_set_name
|
105
|
+
@change_set_name ||= "changeset-#{Time.now.strftime("%Y%d%m%H%M%S")}"
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
# Private: formats a Aws::CloudFormation::Types::Change in pretty human readable form
|
110
|
+
#
|
111
|
+
# change - Aws::CloudFormation::Types::Change
|
112
|
+
#
|
113
|
+
# Examples
|
114
|
+
#
|
115
|
+
# display_change(change)
|
116
|
+
# => Remove AWS::Route53::RecordSet: DnsRecord testsubdomain.sub.tongueroo.com
|
117
|
+
#
|
118
|
+
# Returns nil
|
119
|
+
#
|
120
|
+
# change.to_h
|
121
|
+
# {:type=>"Resource",
|
122
|
+
# :resource_change=>
|
123
|
+
# {:action=>"Remove",
|
124
|
+
# :logical_resource_id=>"DnsRecord",
|
125
|
+
# :physical_resource_id=>"testsubdomain.sub.tongueroo.com",
|
126
|
+
# :resource_type=>"AWS::Route53::RecordSet",
|
127
|
+
# :scope=>[],
|
128
|
+
# :details=>[]}}
|
129
|
+
def display_change(change)
|
130
|
+
message = if change.type == "Resource"
|
131
|
+
c = change.resource_change
|
132
|
+
"#{c.action} #{c.resource_type}: #{c.logical_resource_id} #{c.physical_resource_id}"
|
133
|
+
else
|
134
|
+
change.to_h
|
135
|
+
end
|
136
|
+
|
137
|
+
colors = { Remove: :red, Add: :green, Modify: :yellow }
|
138
|
+
action = change.resource_change.action.to_sym
|
139
|
+
message = message.color(colors[action]) if colors.has_key?(action)
|
140
|
+
puts message
|
141
|
+
end
|
142
|
+
|
143
|
+
def change_set_finished?(change_set)
|
144
|
+
change_set.status =~ /_COMPLETE/ || change_set.status == "FAILED"
|
145
|
+
end
|
146
|
+
|
147
|
+
def describe_change_set
|
148
|
+
cfn.describe_change_set(
|
149
|
+
change_set_name: change_set_name,
|
150
|
+
stack_name: @stack_name
|
151
|
+
)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -1,8 +1,11 @@
|
|
1
|
-
|
2
|
-
class
|
1
|
+
module Lono::Cfn::Preview
|
2
|
+
class Codediff < Lono::Cfn::Base
|
3
|
+
include DiffViewer
|
3
4
|
include Lono::AwsServices
|
4
5
|
|
5
6
|
def run
|
7
|
+
puts "Code Diff Preview:".color(:green)
|
8
|
+
|
6
9
|
unless stack_exists?(@stack_name)
|
7
10
|
puts "WARN: Cannot create a diff for the stack because the #{@stack_name} does not exists.".color(:yellow)
|
8
11
|
return
|
@@ -14,7 +17,7 @@ class Lono::Cfn
|
|
14
17
|
generate_all # from Base superclass. Generates the output lono teplates
|
15
18
|
puts "Generating CloudFormation source code diff..."
|
16
19
|
download_existing_cfn_template
|
17
|
-
|
20
|
+
show_diff(existing_template_path, new_cfn_template)
|
18
21
|
end
|
19
22
|
end
|
20
23
|
|
@@ -27,22 +30,11 @@ class Lono::Cfn
|
|
27
30
|
IO.write(existing_template_path, resp.template_body)
|
28
31
|
end
|
29
32
|
|
30
|
-
def show_changes
|
31
|
-
command = "#{diff_viewer} #{existing_template_path} #{new_cfn_template}"
|
32
|
-
puts "Running: #{command}"
|
33
|
-
system(command)
|
34
|
-
end
|
35
|
-
|
36
33
|
# for clarity
|
37
34
|
def new_cfn_template
|
38
35
|
@template_path
|
39
36
|
end
|
40
37
|
|
41
|
-
def diff_viewer
|
42
|
-
return ENV['LONO_DIFF'] if ENV['LONO_DIFF']
|
43
|
-
system("type colordiff > /dev/null") ? "colordiff" : "diff"
|
44
|
-
end
|
45
|
-
|
46
38
|
def existing_template_path
|
47
39
|
"/tmp/existing_cfn_template.yml"
|
48
40
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Lono::Cfn::Preview
|
2
|
+
module DiffViewer
|
3
|
+
def show_diff(existing_path, new_path)
|
4
|
+
command = "#{diff_viewer} #{existing_path} #{new_path}"
|
5
|
+
puts "Running: #{command}"
|
6
|
+
out = `#{command}`
|
7
|
+
if out.strip == ''
|
8
|
+
puts "There were no differences."
|
9
|
+
else
|
10
|
+
puts out
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def diff_viewer
|
15
|
+
return ENV['LONO_DIFF'] if ENV['LONO_DIFF']
|
16
|
+
system("type colordiff > /dev/null") ? "colordiff" : "diff"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|