lono 5.3.4 → 6.0.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.
Files changed (56) hide show
  1. checksums.yaml +4 -4
  2. data/.cody/demo.rb +21 -21
  3. data/CHANGELOG.md +14 -0
  4. data/lib/lono.rb +1 -1
  5. data/lib/lono/blueprint/meta.rb +38 -0
  6. data/lib/lono/cfn/base.rb +19 -12
  7. data/lib/lono/cfn/delete.rb +2 -1
  8. data/lib/lono/cfn/preview/changeset.rb +14 -1
  9. data/lib/lono/cfn/rollback.rb +1 -1
  10. data/lib/lono/cfn/status.rb +1 -1
  11. data/lib/lono/help/blueprint.md +35 -24
  12. data/lib/lono/help/param.md +4 -1
  13. data/lib/lono/help/seed.md +13 -6
  14. data/lib/lono/help/summary.md +22 -8
  15. data/lib/lono/inspector/summary.rb +4 -3
  16. data/lib/lono/output_template.rb +2 -2
  17. data/lib/lono/s3/bucket.rb +1 -1
  18. data/lib/lono/seed/base.rb +1 -0
  19. data/lib/lono/seed/service_role.rb +11 -0
  20. data/lib/lono/template/dsl/builder.rb +3 -7
  21. data/lib/lono/template/dsl/builder/base.rb +24 -3
  22. data/lib/lono/template/dsl/builder/fn.rb +15 -11
  23. data/lib/lono/template/dsl/builder/{helper.rb → helpers.rb} +5 -4
  24. data/lib/lono/template/dsl/builder/helpers/param_helper.rb +33 -0
  25. data/lib/lono/template/dsl/builder/output.rb +4 -4
  26. data/lib/lono/template/dsl/builder/parameter.rb +2 -2
  27. data/lib/lono/template/dsl/builder/resource.rb +4 -3
  28. data/lib/lono/template/dsl/builder/resource/property_mover.rb +4 -0
  29. data/lib/lono/template/dsl/builder/syntax.rb +6 -7
  30. data/lib/lono/version.rb +1 -1
  31. data/lib/templates/blueprint/%blueprint_name%.gemspec.tt +1 -1
  32. data/lib/templates/blueprint/.meta/config.yml.tt +2 -1
  33. data/lib/templates/blueprint/README.md +1 -1
  34. data/lib/templates/blueprint_types/dsl/app/templates/%blueprint_name%.rb +22 -22
  35. data/lib/templates/skeleton/README.md +1 -1
  36. data/lono.gemspec +1 -1
  37. data/vendor/cfn-status/CHANGELOG.md +4 -0
  38. data/vendor/cfn-status/README.md +4 -2
  39. data/vendor/cfn-status/bin/console +1 -1
  40. data/vendor/cfn-status/cfn-status.gemspec +2 -2
  41. data/vendor/cfn-status/lib/cfn-status.rb +1 -1
  42. data/vendor/cfn-status/lib/cfn_status.rb +245 -0
  43. data/vendor/cfn-status/lib/{cfn → cfn_status}/aws_service.rb +1 -1
  44. data/vendor/cfn-status/lib/cfn_status/version.rb +3 -0
  45. data/vendor/cfn-status/spec/fixtures/cfn/pages/fresh/describe_stack_events-1.json +1103 -0
  46. data/vendor/cfn-status/spec/fixtures/cfn/pages/fresh/describe_stack_events-2.json +1104 -0
  47. data/vendor/cfn-status/spec/fixtures/cfn/pages/fresh/describe_stack_events-3.json +1103 -0
  48. data/vendor/cfn-status/spec/fixtures/cfn/pages/updating/describe_stack_events-1.json +1103 -0
  49. data/vendor/cfn-status/spec/fixtures/cfn/pages/updating/describe_stack_events-2.json +1104 -0
  50. data/vendor/cfn-status/spec/fixtures/cfn/pages/updating/describe_stack_events-3.json +1103 -0
  51. data/vendor/cfn-status/spec/lib/cfn_status_spec.rb +153 -0
  52. data/vendor/cfn-status/spec/spec_helper.rb +1 -1
  53. metadata +17 -8
  54. data/vendor/cfn-status/lib/cfn/status.rb +0 -219
  55. data/vendor/cfn-status/lib/cfn/status/version.rb +0 -5
  56. data/vendor/cfn-status/spec/cfn/status_spec.rb +0 -81
@@ -0,0 +1,153 @@
1
+ RSpec.describe CfnStatus do
2
+ it "has a version number" do
3
+ expect(CfnStatus::VERSION).not_to be nil
4
+ end
5
+
6
+ let(:status) do
7
+ status = CfnStatus.new("test-stack")
8
+ allow(status).to receive(:cfn).and_return(cfn)
9
+ status
10
+ end
11
+ let(:cfn) do
12
+ service = double("service").as_null_object
13
+ allow(service).to receive(:describe_stacks).and_return(stack_status)
14
+ allow(service).to receive(:describe_stack_events).and_return(stack_events)
15
+ service
16
+ end
17
+
18
+ context "in progress" do
19
+ let(:stack_status) { "UPDATE_IN_PROGRESS" }
20
+ let(:stack_events) { JSON.load(IO.read("spec/fixtures/cfn/stack-events-in-progress.json")) }
21
+ it "lists events since user initiated event" do
22
+ status.refresh_events
23
+ i = status.start_index
24
+ expect(i).to eq 15
25
+ # uncomment to view and debug
26
+ # status.show_events
27
+ # puts "****"
28
+ # status.show_events # should not show anything
29
+ end
30
+
31
+ it "lists events since last shown event" do
32
+ # first display
33
+ status.refresh_events
34
+ i = status.start_index
35
+ expect(i).to eq 15
36
+
37
+ # move the last event back in time 4 events, so should print 3 events
38
+ status.instance_variable_set(:@last_shown_event_id, "TargetGroup-ec634c43-b887-4bde-a525-7c69782865a6")
39
+
40
+ captured_events = []
41
+ allow(status).to receive(:print_event) do |e|
42
+ captured_events << "#{e["resource_type"]} #{e["resource_status"]}"
43
+ end
44
+ status.show_events
45
+ expect(captured_events).to eq([
46
+ "AWS::ElasticLoadBalancingV2::LoadBalancer DELETE_IN_PROGRESS",
47
+ "AWS::ElasticLoadBalancingV2::LoadBalancer DELETE_COMPLETE",
48
+ "AWS::EC2::SecurityGroup DELETE_IN_PROGRESS",
49
+ ])
50
+ end
51
+ end
52
+
53
+ context "complete" do
54
+ let(:stack_status) { "UPDATE_COMPLETE" }
55
+ let(:stack_events) { JSON.load(IO.read("spec/fixtures/cfn/stack-events-complete.json")) }
56
+ it "lists events all the way to completion" do
57
+ status.refresh_events
58
+ i = status.start_index
59
+ expect(i).to eq 17
60
+ # uncomment to view and debug
61
+ # status.show_events
62
+ end
63
+ end
64
+
65
+ context "update_rollback" do
66
+ let(:stack_status) { "UPDATE_ROLLBACK_COMPLETE" }
67
+ let(:stack_events) { JSON.load(IO.read("spec/fixtures/cfn/stack-events-update-rollback-complete.json")) }
68
+ it "lists events all the way to update rollback complete" do
69
+ status.refresh_events
70
+ expect(status.success?).to be false
71
+ expect(status.update_rollback?).to be true
72
+ expect(status.rollback_error_message).to include("STATIC_NAME")
73
+
74
+ # i = status.start_index
75
+ # expect(i).to eq 17
76
+ # uncomment to view and debug
77
+ # status.show_events
78
+ end
79
+ end
80
+
81
+ context "huge template with large number of stack_events" do
82
+ # Grabbed the fixture data with `jets status`
83
+ context "fresh" do
84
+ # Special mock for pagination testing
85
+ let(:cfn) do
86
+ service = double("service").as_null_object
87
+ allow(service).to receive(:describe_stacks).and_return(stack_status)
88
+
89
+ allow(service).to receive(:describe_stack_events) do |args|
90
+ case args
91
+ when {:stack_name=>"test-stack"}
92
+ stack_events1
93
+ when {:stack_name=>"test-stack", :next_token=>"2"}
94
+ stack_events2
95
+ else
96
+ stack_events3 # final page since "User Initiated" is found
97
+ end
98
+ end
99
+
100
+ service
101
+ end
102
+ let(:stack_status) { "UPDATE_COMPLETE" }
103
+ let(:stack_events1) { JSON.load(IO.read("spec/fixtures/cfn/pages/fresh/describe_stack_events-1.json")) }
104
+ let(:stack_events2) { JSON.load(IO.read("spec/fixtures/cfn/pages/fresh/describe_stack_events-2.json")) }
105
+ let(:stack_events3) { JSON.load(IO.read("spec/fixtures/cfn/pages/fresh/describe_stack_events-3.json")) }
106
+
107
+ it "paginates" do
108
+ status.refresh_events
109
+ expect(status.events.size).to eq 300 # 3 pages worth of events to find the "User Initiated"
110
+ end
111
+ end
112
+
113
+ # Grabbed the fixture data with `jets jets`
114
+ context "updating" do
115
+ # Special mock for pagination testing
116
+ let(:cfn) do
117
+ service = double("service").as_null_object
118
+ allow(service).to receive(:describe_stacks).and_return(stack_status)
119
+
120
+ allow(service).to receive(:describe_stack_events) do |args|
121
+ case args
122
+ when {:stack_name=>"test-stack"}
123
+ stack_events1
124
+ when {:stack_name=>"test-stack", :next_token=>"2"}
125
+ stack_events2
126
+ else
127
+ stack_events3 # final page since "User Initiated" is found
128
+ end
129
+ end
130
+
131
+ service
132
+ end
133
+ let(:stack_status) { "UPDATE_COMPLETE" }
134
+ let(:stack_events1) { JSON.load(IO.read("spec/fixtures/cfn/pages/updating/describe_stack_events-1.json")) }
135
+ let(:stack_events2) { JSON.load(IO.read("spec/fixtures/cfn/pages/updating/describe_stack_events-2.json")) }
136
+ let(:stack_events3) { JSON.load(IO.read("spec/fixtures/cfn/pages/updating/describe_stack_events-3.json")) }
137
+
138
+ it "found event on page 2" do
139
+ # random event id grabbed from fixture on page 2
140
+ status.instance_variable_set(:@last_shown_event_id, "Hard10Job-UPDATE_COMPLETE-2019-10-20T18:03:02.943Z")
141
+ status.refresh_events
142
+ expect(status.events.size).to eq 200 # 2 pages worth of events to find the :@last_shown_event_id
143
+ end
144
+
145
+ it "found event on page 3" do
146
+ # random event id grabbed from fixture on page 3
147
+ status.instance_variable_set(:@last_shown_event_id, "Hard42Job-UPDATE_COMPLETE-2019-10-20T18:01:33.209Z")
148
+ status.refresh_events
149
+ expect(status.events.size).to eq 300 # 3 pages worth of events to find the :@last_shown_event_id
150
+ end
151
+ end
152
+ end
153
+ end
@@ -1,5 +1,5 @@
1
1
  require "bundler/setup"
2
- require "cfn/status"
2
+ require "cfn_status"
3
3
 
4
4
  RSpec.configure do |config|
5
5
  # Enable flags like --only-failures and --next-failure
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lono
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.3.4
4
+ version: 6.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tung Nguyen
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-11-26 00:00:00.000000000 Z
11
+ date: 2019-11-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -458,6 +458,7 @@ files:
458
458
  - lib/lono/blueprint/helper.rb
459
459
  - lib/lono/blueprint/info.rb
460
460
  - lib/lono/blueprint/list.rb
461
+ - lib/lono/blueprint/meta.rb
461
462
  - lib/lono/blueprint/new.rb
462
463
  - lib/lono/blueprint/root.rb
463
464
  - lib/lono/cfn.rb
@@ -537,6 +538,7 @@ files:
537
538
  - lib/lono/script/upload.rb
538
539
  - lib/lono/seed.rb
539
540
  - lib/lono/seed/base.rb
541
+ - lib/lono/seed/service_role.rb
540
542
  - lib/lono/sequence.rb
541
543
  - lib/lono/setting.rb
542
544
  - lib/lono/template.rb
@@ -552,7 +554,8 @@ files:
552
554
  - lib/lono/template/dsl/builder/base.rb
553
555
  - lib/lono/template/dsl/builder/condition.rb
554
556
  - lib/lono/template/dsl/builder/fn.rb
555
- - lib/lono/template/dsl/builder/helper.rb
557
+ - lib/lono/template/dsl/builder/helpers.rb
558
+ - lib/lono/template/dsl/builder/helpers/param_helper.rb
556
559
  - lib/lono/template/dsl/builder/mapping.rb
557
560
  - lib/lono/template/dsl/builder/output.rb
558
561
  - lib/lono/template/dsl/builder/parameter.rb
@@ -608,13 +611,19 @@ files:
608
611
  - vendor/cfn-status/bin/setup
609
612
  - vendor/cfn-status/cfn-status.gemspec
610
613
  - vendor/cfn-status/lib/cfn-status.rb
611
- - vendor/cfn-status/lib/cfn/aws_service.rb
612
- - vendor/cfn-status/lib/cfn/status.rb
613
- - vendor/cfn-status/lib/cfn/status/version.rb
614
- - vendor/cfn-status/spec/cfn/status_spec.rb
614
+ - vendor/cfn-status/lib/cfn_status.rb
615
+ - vendor/cfn-status/lib/cfn_status/aws_service.rb
616
+ - vendor/cfn-status/lib/cfn_status/version.rb
617
+ - vendor/cfn-status/spec/fixtures/cfn/pages/fresh/describe_stack_events-1.json
618
+ - vendor/cfn-status/spec/fixtures/cfn/pages/fresh/describe_stack_events-2.json
619
+ - vendor/cfn-status/spec/fixtures/cfn/pages/fresh/describe_stack_events-3.json
620
+ - vendor/cfn-status/spec/fixtures/cfn/pages/updating/describe_stack_events-1.json
621
+ - vendor/cfn-status/spec/fixtures/cfn/pages/updating/describe_stack_events-2.json
622
+ - vendor/cfn-status/spec/fixtures/cfn/pages/updating/describe_stack_events-3.json
615
623
  - vendor/cfn-status/spec/fixtures/cfn/stack-events-complete.json
616
624
  - vendor/cfn-status/spec/fixtures/cfn/stack-events-in-progress.json
617
625
  - vendor/cfn-status/spec/fixtures/cfn/stack-events-update-rollback-complete.json
626
+ - vendor/cfn-status/spec/lib/cfn_status_spec.rb
618
627
  - vendor/cfn-status/spec/spec_helper.rb
619
628
  homepage: https://lono.cloud
620
629
  licenses:
@@ -638,5 +647,5 @@ requirements: []
638
647
  rubygems_version: 3.0.6
639
648
  signing_key:
640
649
  specification_version: 4
641
- summary: Powerful CloudFormation Framework
650
+ summary: The CloudFormation Framework
642
651
  test_files: []
@@ -1,219 +0,0 @@
1
- require "cfn/status/version"
2
-
3
- module Cfn
4
- autoload :AwsService, "cfn/aws_service"
5
-
6
- class Status
7
- class Error < StandardError; end
8
-
9
- include AwsService
10
-
11
- attr_reader :events
12
- def initialize(stack_name, options={})
13
- @stack_name = stack_name
14
- @options = options
15
- reset
16
- end
17
-
18
- def run
19
- unless stack_exists?(@stack_name)
20
- puts "The stack #{@stack_name.color(:green)} does not exist."
21
- return true
22
- end
23
-
24
- resp = cfn.describe_stacks(stack_name: @stack_name)
25
- stack = resp.stacks.first
26
-
27
- puts "The current status for the stack #{@stack_name.color(:green)} is #{stack.stack_status.color(:green)}"
28
- if stack.stack_status =~ /_IN_PROGRESS$/
29
- puts "Stack events (tailing):"
30
- # tail all events until done
31
- @hide_time_took = true
32
- wait
33
- else
34
- puts "Stack events:"
35
- # show the last events that was user initiated
36
- refresh_events
37
- show_events(true)
38
- end
39
- success?
40
- end
41
-
42
- def reset
43
- @events = [] # constantly replaced with recent events
44
- @last_shown_event_id = nil
45
- @stack_deletion_completed = nil
46
- end
47
-
48
- # check for /(_COMPLETE|_FAILED)$/ status
49
- def wait
50
- puts "Waiting for stack to complete"
51
- start_time = Time.now
52
-
53
- refresh_events
54
- until completed || @stack_deletion_completed
55
- show_events
56
- end
57
- show_events(true) # show the final event
58
-
59
- if @stack_deletion_completed
60
- puts "Stack #{@stack_name} deleted."
61
- return
62
- end
63
-
64
- if last_event_status =~ /_FAILED/
65
- puts "Stack failed: #{last_event_status}".color(:red)
66
- puts "Stack reason #{@events[0]["resource_status_reason"]}".color(:red)
67
- elsif last_event_status =~ /_ROLLBACK_/
68
- puts "Stack rolled back: #{last_event_status}".color(:red)
69
- else # success
70
- puts "Stack success status: #{last_event_status}".color(:green)
71
- end
72
-
73
- # Never gets here when deleting a stack because the describe stack returns nothing
74
- # once the stack is deleted. Gets here for stack create and update though.
75
- return if @hide_time_took # set in run
76
- took = Time.now - start_time
77
- puts "Time took for stack deployment: #{pretty_time(took).color(:green)}."
78
- success?
79
- end
80
-
81
- def completed
82
- last_event_status =~ /(_COMPLETE|_FAILED)$/ &&
83
- @events[0]["logical_resource_id"] == @stack_name &&
84
- @events[0]["resource_type"] == "AWS::CloudFormation::Stack"
85
- end
86
-
87
- def last_event_status
88
- @events[0]["resource_status"]
89
- end
90
-
91
- # Only shows new events
92
- def show_events(final=false)
93
- if @last_shown_event_id.nil?
94
- i = find_index(:start, final)
95
- print_events(i)
96
- else
97
- i = find_index(:last_shown, final)
98
- # puts "last_shown index #{i}"
99
- print_events(i-1) unless i == 0
100
- end
101
-
102
- return if final
103
- sleep 5 unless ENV['TEST']
104
- refresh_events
105
- end
106
-
107
- def print_events(i)
108
- @events[0..i].reverse.each do |e|
109
- print_event(e)
110
- end
111
- @last_shown_event_id = @events[0]["event_id"]
112
- # puts "@last_shown_event_id #{@last_shown_event_id.inspect}"
113
- end
114
-
115
- def print_event(e)
116
- message = [
117
- event_time(e["timestamp"]),
118
- e["resource_status"],
119
- e["resource_type"],
120
- e["logical_resource_id"],
121
- e["resource_status_reason"]
122
- ].join(" ")
123
- message = message.color(:red) if e["resource_status"] =~ /_FAILED/
124
- puts message
125
- end
126
-
127
- # https://stackoverflow.com/questions/18000432/rails-12-hour-am-pm-range-for-a-day
128
- def event_time(timestamp)
129
- Time.parse(timestamp.to_s).localtime.strftime("%I:%M:%S%p")
130
- end
131
-
132
- # refreshes the loaded events in memory
133
- def refresh_events
134
- resp = cfn.describe_stack_events(stack_name: @stack_name)
135
- @events = resp["stack_events"]
136
- rescue Aws::CloudFormation::Errors::ValidationError => e
137
- if e.message =~ /Stack .* does not exis/
138
- @stack_deletion_completed = true
139
- else
140
- raise
141
- end
142
- end
143
-
144
- def find_index(name, final=false)
145
- send("#{name}_index", final)
146
- end
147
-
148
- def start_index(final=false)
149
- index = @events.find_index do |event|
150
- event["resource_type"] == "AWS::CloudFormation::Stack" &&
151
- event["resource_status_reason"] == "User Initiated"
152
- end
153
- # Instead of paginating until until we find the first "User Initiated" "AWS::CloudFormation::Stack" event
154
- # we'll use the max.
155
- index ? index : @events.size - 1
156
- end
157
-
158
- def last_shown_index(_)
159
- @events.find_index do |event|
160
- event["event_id"] == @last_shown_event_id
161
- end
162
- end
163
-
164
- def success?
165
- resource_status = @events[0]["resource_status"]
166
- %w[CREATE_COMPLETE UPDATE_COMPLETE].include?(resource_status)
167
- end
168
-
169
- def update_rollback?
170
- @events[0]["resource_status"] == "UPDATE_ROLLBACK_COMPLETE"
171
- end
172
-
173
- def find_update_failed_event
174
- i = @events.find_index do |event|
175
- event["resource_type"] == "AWS::CloudFormation::Stack" &&
176
- event["resource_status_reason"] == "User Initiated"
177
- end
178
-
179
- @events[0..i].reverse.find do |e|
180
- e["resource_status"] == "UPDATE_FAILED"
181
- end
182
- end
183
-
184
- def rollback_error_message
185
- return unless update_rollback?
186
-
187
- event = find_update_failed_event
188
- return unless event
189
-
190
- reason = event["resource_status_reason"]
191
- messages_map.each do |pattern, message|
192
- if reason =~ pattern
193
- return message
194
- end
195
- end
196
-
197
- reason # default message is original reason if not found in messages map
198
- end
199
-
200
- def messages_map
201
- {
202
- /CloudFormation cannot update a stack when a custom-named resource requires replacing/ => "A workaround is to run ufo again with STATIC_NAME=0 and to switch to dynamic names for resources. Then run ufo again with STATIC_NAME=1 to get back to statically name resources. Note, there are caveats with the workaround.",
203
- /cannot be associated with more than one load balancer/ => "There's was an issue updating the stack. Target groups can only be associated with one load balancer at a time. The workaround for this is to use UFO_FORCE_TARGET_GROUP=1 and run the command again. This will force the recreation of the target group resource.",
204
- /SetSubnets is not supported for load balancers of type/ => "Changing subnets for Network Load Balancers is currently not supported. You can try workarouding this with UFO_FORCE_ELB=1 and run the command again. This will force the recreation of the elb resource."
205
- }
206
- end
207
-
208
- # http://stackoverflow.com/questions/4175733/convert-duration-to-hoursminutesseconds-or-similar-in-rails-3-or-ruby
209
- def pretty_time(total_seconds)
210
- minutes = (total_seconds / 60) % 60
211
- seconds = total_seconds % 60
212
- if total_seconds < 60
213
- "#{seconds.to_i}s"
214
- else
215
- "#{minutes.to_i}m #{seconds.to_i}s"
216
- end
217
- end
218
- end
219
- end