lono 6.1.11 → 7.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (240) hide show
  1. checksums.yaml +4 -4
  2. data/.cody/acceptance.sh +19 -3
  3. data/.gitignore +2 -2
  4. data/CHANGELOG.md +16 -1
  5. data/README.md +18 -20
  6. data/Rakefile +1 -0
  7. data/lib/lono.rb +7 -5
  8. data/lib/lono/abstract_base.rb +25 -0
  9. data/lib/lono/api/client.rb +30 -0
  10. data/lib/lono/api/proxy.rb +58 -0
  11. data/lib/lono/api/repos.rb +8 -0
  12. data/lib/lono/api/verify.rb +13 -0
  13. data/lib/lono/app_file/base.rb +4 -11
  14. data/lib/lono/app_file/build.rb +1 -1
  15. data/lib/lono/app_file/upload.rb +1 -4
  16. data/lib/lono/autoloader.rb +3 -1
  17. data/lib/lono/aws_services.rb +9 -9
  18. data/lib/lono/aws_services/helper.rb +14 -0
  19. data/lib/lono/aws_services/{util.rb → stack.rb} +1 -9
  20. data/lib/lono/aws_services/stack_set.rb +41 -0
  21. data/lib/lono/blueprint.rb +2 -2
  22. data/lib/lono/blueprint/configset/loader.rb +7 -0
  23. data/lib/lono/blueprint/helper.rb +8 -2
  24. data/lib/lono/blueprint/meta.rb +4 -12
  25. data/lib/lono/blueprint/new.rb +3 -3
  26. data/lib/lono/blueprint/root.rb +6 -26
  27. data/lib/lono/bundle.rb +54 -0
  28. data/lib/lono/cfn.rb +31 -75
  29. data/lib/lono/cfn/base.rb +39 -136
  30. data/lib/lono/cfn/cancel.rb +14 -9
  31. data/lib/lono/cfn/create.rb +15 -19
  32. data/lib/lono/cfn/delete.rb +9 -9
  33. data/lib/lono/cfn/deploy.rb +4 -4
  34. data/lib/lono/cfn/download.rb +27 -9
  35. data/lib/lono/cfn/opts.rb +80 -0
  36. data/lib/lono/cfn/preview/changeset.rb +23 -23
  37. data/lib/lono/cfn/preview/codediff.rb +5 -6
  38. data/lib/lono/cfn/preview/param.rb +10 -10
  39. data/lib/lono/cfn/rollback.rb +5 -5
  40. data/lib/lono/cfn/status.rb +0 -10
  41. data/lib/lono/cfn/update.rb +22 -27
  42. data/lib/lono/clean.rb +3 -3
  43. data/lib/lono/cli.rb +69 -34
  44. data/lib/lono/code.rb +22 -0
  45. data/lib/lono/command.rb +7 -0
  46. data/lib/lono/config_location.rb +6 -13
  47. data/lib/lono/configset.rb +9 -0
  48. data/lib/lono/configset/combiner.rb +128 -0
  49. data/lib/lono/configset/evaluate_file.rb +8 -0
  50. data/lib/lono/configset/list.rb +67 -0
  51. data/lib/lono/configset/loader.rb +98 -0
  52. data/lib/lono/configset/loader/dsl.rb +9 -0
  53. data/lib/lono/configset/materializer/final.rb +10 -0
  54. data/lib/lono/configset/materializer/gems_builder.rb +81 -0
  55. data/lib/lono/configset/materializer/jade.rb +15 -0
  56. data/lib/lono/configset/materializer/source.rb +54 -0
  57. data/lib/lono/configset/meta.rb +19 -0
  58. data/lib/lono/configset/meta/dsl.rb +12 -0
  59. data/lib/lono/configset/new.rb +84 -0
  60. data/lib/lono/configset/preparer.rb +44 -0
  61. data/lib/lono/configset/register/base.rb +121 -0
  62. data/lib/lono/configset/register/blueprint.rb +16 -0
  63. data/lib/lono/configset/register/dsl.rb +15 -0
  64. data/lib/lono/configset/register/project.rb +12 -0
  65. data/lib/lono/configset/registry.rb +34 -0
  66. data/lib/lono/configset/resolver.rb +42 -0
  67. data/lib/lono/conventions.rb +18 -7
  68. data/lib/lono/core.rb +16 -20
  69. data/lib/lono/default/settings.yml +2 -3
  70. data/lib/lono/ext/bundler.rb +7 -0
  71. data/lib/lono/file_uploader.rb +8 -5
  72. data/lib/lono/finder/base.rb +140 -0
  73. data/lib/lono/finder/blueprint.rb +11 -0
  74. data/lib/lono/finder/blueprint/configset.rb +17 -0
  75. data/lib/lono/finder/configset.rb +11 -0
  76. data/lib/lono/generate.rb +93 -0
  77. data/lib/lono/help/blueprint/new.md +0 -1
  78. data/lib/lono/help/cfn/delete.md +1 -1
  79. data/lib/lono/help/cfn/deploy.md +5 -76
  80. data/lib/lono/help/cfn/status.md +0 -4
  81. data/lib/lono/help/cfn/update.md +1 -1
  82. data/lib/lono/help/code/convert.md +51 -0
  83. data/lib/lono/help/code/import.md +30 -0
  84. data/lib/lono/help/configsets.md +24 -0
  85. data/lib/lono/help/generate.md +4 -4
  86. data/lib/lono/help/new.md +1 -2
  87. data/lib/lono/help/sets/delete.md +8 -0
  88. data/lib/lono/help/sets/deploy.md +76 -0
  89. data/lib/lono/help/sets/instances/delete.md +21 -0
  90. data/lib/lono/help/sets/instances/list.md +14 -0
  91. data/lib/lono/help/sets/instances/status.md +15 -0
  92. data/lib/lono/help/sets/instances/sync.md +88 -0
  93. data/lib/lono/help/sets/status.md +23 -0
  94. data/lib/lono/help/upgrade.md +1 -0
  95. data/lib/lono/importer.rb +22 -0
  96. data/lib/lono/importer/base.rb +59 -0
  97. data/lib/lono/importer/converter.rb +19 -0
  98. data/lib/lono/importer/download.rb +46 -0
  99. data/lib/lono/importer/dsl.rb +36 -0
  100. data/lib/lono/importer/erb.rb +31 -0
  101. data/lib/lono/importer/params.rb +56 -0
  102. data/lib/lono/importer/service/coder.rb +81 -0
  103. data/lib/lono/inspector/base.rb +12 -22
  104. data/lib/lono/inspector/graph.rb +1 -1
  105. data/lib/lono/inspector/summary.rb +41 -17
  106. data/lib/lono/jade.rb +103 -0
  107. data/lib/lono/jade/circular.rb +26 -0
  108. data/lib/lono/jadespec.rb +41 -0
  109. data/lib/lono/new.rb +2 -2
  110. data/lib/lono/opts.rb +43 -0
  111. data/lib/lono/output/template.rb +48 -0
  112. data/lib/lono/param.rb +3 -5
  113. data/lib/lono/param/generator.rb +13 -33
  114. data/lib/lono/pro.rb +15 -0
  115. data/lib/lono/pro/base.rb +16 -0
  116. data/lib/lono/pro/repo.rb +27 -0
  117. data/lib/lono/project_checker.rb +4 -29
  118. data/lib/lono/registration.rb +15 -0
  119. data/lib/lono/registration/base.rb +37 -0
  120. data/lib/lono/registration/check.rb +15 -0
  121. data/lib/lono/registration/temp.rb +60 -0
  122. data/lib/lono/registration/user.rb +54 -0
  123. data/lib/lono/script/base.rb +1 -10
  124. data/lib/lono/script/upload.rb +2 -12
  125. data/lib/lono/seed.rb +2 -11
  126. data/lib/lono/seed/base.rb +55 -110
  127. data/lib/lono/sets.rb +38 -0
  128. data/lib/lono/sets/base.rb +45 -0
  129. data/lib/lono/sets/create.rb +30 -0
  130. data/lib/lono/sets/delete.rb +47 -0
  131. data/lib/lono/sets/deploy.rb +11 -0
  132. data/lib/lono/sets/instances.rb +33 -0
  133. data/lib/lono/sets/instances/base.rb +30 -0
  134. data/lib/lono/sets/instances/delete.rb +69 -0
  135. data/lib/lono/sets/instances/list.rb +13 -0
  136. data/lib/lono/sets/instances/opts.rb +29 -0
  137. data/lib/lono/sets/instances/status.rb +12 -0
  138. data/lib/lono/sets/instances/sync.rb +182 -0
  139. data/lib/lono/sets/list.rb +35 -0
  140. data/lib/lono/sets/opts.rb +18 -0
  141. data/lib/lono/sets/preview/codediff.rb +35 -0
  142. data/lib/lono/sets/preview/param.rb +32 -0
  143. data/lib/lono/sets/status.rb +116 -0
  144. data/lib/lono/sets/status/instance.rb +20 -0
  145. data/lib/lono/sets/status/instance/base.rb +120 -0
  146. data/lib/lono/sets/status/instance/completed.rb +35 -0
  147. data/lib/lono/sets/status/instance/deleted.rb +32 -0
  148. data/lib/lono/sets/status/instance/show.rb +7 -0
  149. data/lib/lono/sets/status/instances.rb +111 -0
  150. data/lib/lono/sets/summarize.rb +20 -0
  151. data/lib/lono/sets/time_spent.rb +11 -0
  152. data/lib/lono/sets/update.rb +81 -0
  153. data/lib/lono/template.rb +5 -7
  154. data/lib/lono/template/configset_injector.rb +50 -0
  155. data/lib/lono/template/context.rb +4 -4
  156. data/lib/lono/template/context/loader.rb +4 -16
  157. data/lib/lono/template/evaluate.rb +2 -1
  158. data/lib/lono/template/generator.rb +17 -15
  159. data/lib/lono/template/helper.rb +7 -7
  160. data/lib/lono/template/post_processor.rb +2 -12
  161. data/lib/lono/template/strategy/base.rb +4 -0
  162. data/lib/lono/template/{dsl.rb → strategy/dsl.rb} +4 -6
  163. data/lib/lono/template/{dsl → strategy/dsl}/builder.rb +11 -15
  164. data/lib/lono/template/{dsl → strategy/dsl}/builder/fn.rb +1 -1
  165. data/lib/lono/template/strategy/dsl/builder/helpers.rb +11 -0
  166. data/lib/lono/template/strategy/dsl/builder/helpers/core_helper.rb +14 -0
  167. data/lib/lono/template/strategy/dsl/builder/helpers/file_helper.rb +48 -0
  168. data/lib/lono/template/strategy/dsl/builder/helpers/lookup_helper.rb +27 -0
  169. data/lib/lono/template/strategy/dsl/builder/helpers/s3_helper.rb +13 -0
  170. data/lib/lono/template/strategy/dsl/builder/helpers/tags_helper.rb +39 -0
  171. data/lib/lono/template/{dsl/builder → strategy/dsl/builder/section}/base.rb +6 -17
  172. data/lib/lono/template/{dsl/builder → strategy/dsl/builder/section}/condition.rb +1 -1
  173. data/lib/lono/template/strategy/dsl/builder/section/extensions.rb +9 -0
  174. data/lib/lono/template/{dsl/builder → strategy/dsl/builder/section}/mapping.rb +1 -1
  175. data/lib/lono/template/{dsl/builder/section_methods.rb → strategy/dsl/builder/section/methods.rb} +9 -2
  176. data/lib/lono/template/{dsl/builder → strategy/dsl/builder/section}/output.rb +1 -1
  177. data/lib/lono/template/strategy/dsl/builder/section/parameter.rb +69 -0
  178. data/lib/lono/template/{dsl/builder → strategy/dsl/builder/section}/resource.rb +1 -1
  179. data/lib/lono/template/{dsl/builder → strategy/dsl/builder/section}/resource/property_mover.rb +1 -1
  180. data/lib/lono/template/{dsl/builder → strategy/dsl/builder/section}/section.rb +1 -1
  181. data/lib/lono/template/{dsl → strategy/dsl}/builder/squeezer.rb +1 -1
  182. data/lib/lono/template/strategy/dsl/builder/stringify.rb +15 -0
  183. data/lib/lono/template/{dsl → strategy/dsl}/builder/syntax.rb +3 -2
  184. data/lib/lono/template/strategy/dsl/finalizer.rb +12 -0
  185. data/lib/lono/template/strategy/dsl/finalizer/parameter_groups.rb +56 -0
  186. data/lib/lono/template/{erb.rb → strategy/erb.rb} +5 -5
  187. data/lib/lono/template/strategy/source.rb +8 -0
  188. data/lib/lono/template/template.rb +1 -1
  189. data/lib/lono/template/upload.rb +4 -9
  190. data/lib/lono/template/util.rb +0 -40
  191. data/lib/lono/upgrade.rb +12 -10
  192. data/lib/lono/user_data.rb +4 -4
  193. data/lib/lono/utils/pretty_time.rb +14 -0
  194. data/lib/lono/utils/sure.rb +23 -0
  195. data/lib/lono/version.rb +1 -1
  196. data/lib/lono/yamler/loader.rb +52 -0
  197. data/lib/lono/yamler/validator.rb +51 -0
  198. data/lib/templates/blueprint/%blueprint_name%.gemspec.tt +4 -0
  199. data/lib/templates/blueprint/README.md.tt +1 -1
  200. data/lib/templates/blueprint/seed/configs.rb +2 -2
  201. data/lib/templates/blueprint_types/dsl/app/templates/%blueprint_name%.rb +17 -18
  202. data/lib/templates/blueprint_types/erb/app/templates/%blueprint_name%.yml +63 -4
  203. data/lib/templates/configset/%configset_name%.gemspec.tt +41 -0
  204. data/lib/templates/configset/.gitignore +11 -0
  205. data/lib/templates/configset/CHANGELOG.md +7 -0
  206. data/lib/templates/configset/Gemfile +4 -0
  207. data/lib/templates/configset/README.md.tt +3 -0
  208. data/lib/templates/configset/Rakefile.tt +9 -0
  209. data/lib/templates/configset/lib/configset.yml +20 -0
  210. data/lib/templates/skeleton/.gitignore +1 -0
  211. data/lib/templates/skeleton/Gemfile +0 -1
  212. data/lib/templates/skeleton/README.md +4 -4
  213. data/lib/templates/skeleton/configs/settings.yml +1 -1
  214. data/lono.gemspec +1 -4
  215. metadata +146 -79
  216. data/Guardfile +0 -19
  217. data/lib/lono/app_file.rb +0 -5
  218. data/lib/lono/blueprint/find.rb +0 -90
  219. data/lib/lono/blueprint/info.rb +0 -10
  220. data/lib/lono/blueprint/list.rb +0 -14
  221. data/lib/lono/cfn/current.rb +0 -95
  222. data/lib/lono/cfn/preview.rb +0 -4
  223. data/lib/lono/cfn/suffix.rb +0 -67
  224. data/lib/lono/cfn/util.rb +0 -27
  225. data/lib/lono/help/cfn/current.md +0 -18
  226. data/lib/lono/help/upgrade4.md +0 -25
  227. data/lib/lono/inspector.rb +0 -4
  228. data/lib/lono/output_template.rb +0 -35
  229. data/lib/lono/template/base.rb +0 -13
  230. data/lib/lono/template/dsl/builder/helpers.rb +0 -8
  231. data/lib/lono/template/dsl/builder/helpers/core_helper.rb +0 -107
  232. data/lib/lono/template/dsl/builder/helpers/param_helper.rb +0 -61
  233. data/lib/lono/template/dsl/builder/parameter.rb +0 -39
  234. data/lib/lono/upgrade/upgrade4.rb +0 -175
  235. data/lib/lono/upgrade/upgrade42.rb +0 -36
  236. data/lib/lono/upgrade/upgrade5.rb +0 -55
  237. data/lib/templates/blueprint/.meta/config.yml.tt +0 -4
  238. data/lib/templates/skeleton/Guardfile +0 -12
  239. data/lib/templates/upgrade5/blueprints/main/.lono/config.yml +0 -3
  240. data/lib/templates/upgrade5/blueprints/main/.meta/config.yml +0 -3
@@ -0,0 +1,32 @@
1
+ module Lono::Sets::Preview
2
+ # Inherits from Lono::Cfn::Preview::Param and override what's needed:
3
+ #
4
+ # stack_parameters
5
+ #
6
+ class Param < Lono::Cfn::Preview::Param
7
+ def run
8
+ return unless stack_set_exists?(@stack)
9
+
10
+ generated_parameters # eager call generated_parameters so its output is above Parameter Diff Preview
11
+ puts "Parameter Diff Preview:".color(:green)
12
+ if @options[:noop]
13
+ puts "NOOP CloudFormation parameters preview for #{@stack} update"
14
+ return
15
+ end
16
+
17
+ write_to_tmp(existing_path, existing_params)
18
+ write_to_tmp(new_path, new_params)
19
+
20
+ show_diff(existing_path, new_path)
21
+ end
22
+
23
+ def stack_parameters
24
+ stack_set_parameters
25
+ end
26
+
27
+ def stack_set_parameters
28
+ resp = cfn.describe_stack_set(stack_set_name: @stack)
29
+ resp.stack_set.parameters
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,116 @@
1
+ class Lono::Sets
2
+ class Status
3
+ extend Memoist
4
+ include Lono::AwsServices
5
+ include Summarize
6
+ include TimeSpent
7
+
8
+ attr_reader :operation_id
9
+ def initialize(options={})
10
+ @options = options
11
+ @stack, @operation_id = options[:stack], options[:operation_id]
12
+ @shown = []
13
+ @output = "" # for say method and specs
14
+ end
15
+
16
+ def wait
17
+ status = nil
18
+ until completed?(status)
19
+ resp = display_one
20
+ stack_set_operation = resp.stack_set_operation
21
+ status = stack_set_operation.status
22
+ # always sleep delay even if completed to provide start_instances_status_waiter some extra time to complete
23
+ sleep 5
24
+ if completed?(status)
25
+ show_time_spent(stack_set_operation)
26
+ else
27
+ start_instances_status_waiter
28
+ end
29
+ end
30
+ status == "SUCCEEDED"
31
+ end
32
+
33
+ def display_one
34
+ resp = cfn.describe_stack_set_operation(
35
+ stack_set_name: @stack,
36
+ operation_id: operation_id,
37
+ )
38
+ stack_set_operation = resp.stack_set_operation
39
+ show_stack_set_operation(stack_set_operation)
40
+ @shown << stack_set_operation
41
+ resp
42
+ end
43
+
44
+ def show
45
+ display_one
46
+ o = @options.merge(show_time_spent: false)
47
+ instances_status = Lono::Sets::Instances::Status.new(o)
48
+ instances_status.run
49
+ summarize(operation_id)
50
+ end
51
+
52
+ @@instances_status_waiter_started = false
53
+ def start_instances_status_waiter
54
+ return if @@instances_status_waiter_started
55
+ if stack_instances.empty?
56
+ @@instances_status_waiter_started = true
57
+ return
58
+ end
59
+
60
+ Thread.new do
61
+ # show_time_spent because we already show it in this status class. Dont want it to show twice.
62
+ o = @options.merge(start_on_outdated: true, show_time_spent: false)
63
+ instances_status = Lono::Sets::Instances::Status.new(o)
64
+ instances_status.run
65
+ end
66
+ @@instances_status_waiter_started = true
67
+ end
68
+
69
+ def show_stack_set_operation(stack_set_operation)
70
+ already_shown = @shown.detect do |o|
71
+ o[:status] == stack_set_operation[:status]
72
+ end
73
+ return if already_shown
74
+
75
+ say "Stack Set Operation Status: #{stack_set_operation.status}"
76
+ end
77
+
78
+ def say(text)
79
+ ENV["LONO_TEST"] ? @output << "#{text}\n" : puts(text)
80
+ end
81
+
82
+ # describe_stack_set_operation stack_set_operation.status is
83
+ # one of RUNNING, SUCCEEDED, FAILED, STOPPING, STOPPED
84
+ def completed?(status)
85
+ completed_statuses = %w[SUCCEEDED FAILED STOPPED]
86
+ completed_statuses.include?(status)
87
+ end
88
+
89
+ def stack_set_status
90
+ resp = cfn.describe_stack_set_operation(
91
+ stack_set_name: @stack,
92
+ operation_id: operation_id,
93
+ )
94
+ # describe_stack_set_operation stack_set_operation.status is
95
+ # status one of RUNNING, SUCCEEDED, FAILED, STOPPING, STOPPED
96
+ resp.stack_set_operation.status
97
+ end
98
+
99
+ def operation_id
100
+ @operation_id ||= latest_operation_id
101
+ end
102
+
103
+ def latest_operation_id
104
+ resp = cfn.list_stack_set_operations(
105
+ stack_set_name: @stack,
106
+ max_results: 1,
107
+ )
108
+ resp.summaries.first.operation_id
109
+ end
110
+
111
+ def stack_instances
112
+ Lono::Sets::Status::Instances.new(@options).stack_instances
113
+ end
114
+ memoize :stack_instances
115
+ end
116
+ end
@@ -0,0 +1,20 @@
1
+ class Lono::Sets::Status
2
+ class Instance
3
+ def initialize(stack_instance)
4
+ @stack_instance = stack_instance
5
+ end
6
+
7
+ def tail(to="completed")
8
+ case to
9
+ when "completed"
10
+ Completed.new(@stack_instance).tail
11
+ when "deleted"
12
+ Deleted.new(@stack_instance).tail
13
+ end
14
+ end
15
+
16
+ def show
17
+ Show.new(@stack_instance).run
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,120 @@
1
+ # The Completed and Deleted classes inherit from Base.
2
+ # They implement `tail` and should not override `show`.
3
+ #
4
+ # They guarantee at least one status line is shown.
5
+ # After which they start a thread that tails until a "terminal" status is detected. However, describe_stack_instance
6
+ # resp.stack_instance.status returns:
7
+ #
8
+ # CURRENT, OUTDATED, INOPERABLE
9
+ #
10
+ # There is no well-defined terminal status. For example, sometimes the terminal status is `CURRENT`, when the stack
11
+ # instance updates successfully:
12
+ #
13
+ # CURRENT -> OUTDATED -> CURRENT (terminal)
14
+ #
15
+ # But sometimes the terminal state is `OUTDATED`, when the stack instance fails to update:
16
+ #
17
+ # CURRENT -> OUTDATED (terminal)
18
+ #
19
+ # Essentially, the `describe_stack_instance` resp does not provide enough information to determine the completion of
20
+ # the `tail` logic.
21
+ #
22
+ # Hence the Completed and Deleted classes cannot be used to control the end of the polling loop. Instead, the calling
23
+ # logic is responsible for and should control when to end the polling loop.
24
+ #
25
+ # Example in Lono::Sets::Status::Instances:
26
+ #
27
+ # with_instances do |instance|
28
+ # Thread.new { instance.tail(to) }
29
+ # end.map(&:join)
30
+ # wait_until_stack_set_operation_complete
31
+ #
32
+ # The Instances logic waits on the operation results instead because its more accurate. We know from
33
+ # `describe_stack_set_operation` when the status is actually complete. The describe_stack_set_operation
34
+ # stack_set_operation.status is one of RUNNING, SUCCEEDED, FAILED, STOPPING, STOPPED.
35
+ #
36
+ # In this case, there are threads within threads. The first thread at the Instances level starts polling status
37
+ # in parallel. The instance.tail delegates to the Completed and Deleted classes.
38
+ #
39
+ # Finally, the Completed and Deleted classes are designed to block with the first poll request. So it can show at
40
+ # least one status line. Then it starts it's own thread to poll for more statuses. Those latter statuses are not
41
+ # guaranteed to be shown. This is the responsibility of the Instances class since it has the information required to
42
+ # determine when to finish the polling loop.
43
+ #
44
+ class Lono::Sets::Status::Instance
45
+ class Base
46
+ include Lono::AwsServices
47
+
48
+ class_attribute :show_time_progress
49
+ class_attribute :delay_factor
50
+
51
+ def initialize(stack_instance)
52
+ @stack_instance = stack_instance
53
+ @shown = []
54
+ @output = "" # for say method and specs
55
+ end
56
+
57
+ def show_instance(stack_instance)
58
+ already_shown = @shown.detect do |o|
59
+ o[:account] == stack_instance[:account] &&
60
+ o[:region] == stack_instance[:region] &&
61
+ o[:status] == stack_instance[:status] &&
62
+ o[:status_reason] == stack_instance[:status_reason]
63
+ end
64
+ return if already_shown
65
+
66
+ s = stack_instance
67
+ say status_line(s.account, s.region, s.status, s.status_reason)
68
+ end
69
+
70
+ def show_time_progress
71
+ self.class.show_time_progress
72
+ end
73
+
74
+ def status_line(account, region, status, reason=nil)
75
+ time = Time.now.strftime("%F %I:%M:%S%p") if show_time_progress
76
+ items = [
77
+ time,
78
+ "Stack Instance:",
79
+ "account".color(:purple), account,
80
+ "region".color(:purple), region,
81
+ "status".color(:purple), status,
82
+ ]
83
+ items += ["reason".color(:purple), reason] if reason
84
+ items.compact.join(" ")
85
+ end
86
+
87
+ def say(text)
88
+ ENV["LONO_TEST"] ? @output << "#{text}\n" : puts(text)
89
+ end
90
+
91
+ def describe_stack_instance
92
+ retries = 0
93
+ begin
94
+ cfn.describe_stack_instance(
95
+ stack_instance_account: @stack_instance.account,
96
+ stack_instance_region: @stack_instance.region,
97
+ stack_set_name: @stack_instance.stack_set_id)
98
+ rescue Aws::CloudFormation::Errors::Throttling => e
99
+ retries += 1
100
+ delay = 2 ** retries
101
+ if ENV['LONO_DEBUG_THROTTLE']
102
+ puts "#{e.class}: #{e.message}"
103
+ puts "Backing off for #{delay}s and will retry"
104
+ end
105
+ sleep delay
106
+ retry
107
+ end
108
+ end
109
+
110
+ def delay
111
+ # delay factor based on number of stack instances
112
+ factor = self.class.delay_factor || 1
113
+ base = 4.5
114
+ delay = factor * base
115
+ delay = [delay, 30].min # limit the delay to a max
116
+ puts "Sleeping for #{delay}s..." if ENV['LONO_DEBUG_THROTTLE']
117
+ sleep delay
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,35 @@
1
+ # Refer to Lono::Sets::Status::Instance::Base for more detailed docs.
2
+ class Lono::Sets::Status::Instance
3
+ class Completed < Base
4
+ def tail
5
+ display_one
6
+ Thread.new do
7
+ loop!
8
+ end
9
+ end
10
+
11
+ def loop!
12
+ # resp.stack_instance.status : one of CURRENT, OUTDATED, INOPERABLE
13
+ status = nil
14
+ until completed?(status)
15
+ resp = display_one
16
+ status = resp.stack_instance.status
17
+ delay unless completed?(status)
18
+ end
19
+ end
20
+
21
+ def display_one
22
+ resp = describe_stack_instance
23
+ stack_instance = resp.stack_instance
24
+ show_instance(stack_instance)
25
+ @shown << stack_instance
26
+ resp
27
+ end
28
+
29
+ # status: one of CURRENT, OUTDATED, INOPERABLE
30
+ def completed?(status)
31
+ completed_statuses = %w[CURRENT INOPERABLE]
32
+ completed_statuses.include?(status)
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,32 @@
1
+ # Refer to Lono::Sets::Status::Instance::Base for more detailed docs.
2
+ class Lono::Sets::Status::Instance
3
+ class Deleted < Base
4
+ def tail
5
+ display_one
6
+ Thread.new do
7
+ loop!
8
+ end
9
+ end
10
+
11
+ def loop!
12
+ # resp.stack_instance.status : one of CURRENT, OUTDATED, INOPERABLE
13
+ while true
14
+ begin
15
+ display_one
16
+ rescue Aws::CloudFormation::Errors::StackInstanceNotFoundException
17
+ say status_line(@stack_instance.account, @stack_instance.region, "DELETED")
18
+ break
19
+ end
20
+ delay
21
+ end
22
+ end
23
+
24
+ def display_one
25
+ resp = describe_stack_instance
26
+ stack_instance = resp.stack_instance
27
+ show_instance(stack_instance)
28
+ @shown << stack_instance
29
+ resp
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,7 @@
1
+ class Lono::Sets::Status::Instance
2
+ class Show < Base
3
+ def run
4
+ show_instance(@stack_instance)
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,111 @@
1
+ class Lono::Sets::Status
2
+ class Instances
3
+ include Lono::AwsServices
4
+ include Lono::Sets::TimeSpent
5
+
6
+ def initialize(options={})
7
+ @options = options
8
+ @stack, @operation_id = options[:stack], options[:operation_id]
9
+ @show_time_spent = options[:show_time_spent].nil? ? true : options[:show_time_spent]
10
+ end
11
+
12
+ def wait(to="completed")
13
+ puts "Stack Instance statuses... (takes a while)"
14
+ wait_until_outdated if @options[:start_on_outdated]
15
+
16
+ with_instances do |instance|
17
+ Thread.new { instance.tail(to) }
18
+ end.map(&:join)
19
+ wait_until_stack_set_operation_complete
20
+ end
21
+
22
+ def show
23
+ if stack_instances.empty?
24
+ # Note: no access to @blueprint here
25
+ puts <<~EOL
26
+ There are 0 stack instances associated with the #{@stack} stack set. Add files
27
+ Add accounts and regions configs use `lono sets instances sync` to add stack instances.
28
+ EOL
29
+ return
30
+ end
31
+
32
+ with_instances do |instance|
33
+ Thread.new { instance.show }
34
+ end.map(&:join)
35
+ wait_until_stack_set_operation_complete
36
+ end
37
+
38
+ def with_instances
39
+ stack_instances.map do |stack_instance|
40
+ instance = Instance.new(stack_instance)
41
+ yield(instance)
42
+ end
43
+ end
44
+
45
+ def wait_until_stack_set_operation_complete
46
+ status, stack_set_operation = nil, nil
47
+ until completed?(status)
48
+ resp = cfn.describe_stack_set_operation(
49
+ stack_set_name: @stack,
50
+ operation_id: operation_id,
51
+ )
52
+ stack_set_operation = resp.stack_set_operation
53
+ status = stack_set_operation.status
54
+ # puts "DEBUG: wait_until_stack_set_operation_complete"
55
+ unless completed?(status)
56
+ sleep 5
57
+ end
58
+ end
59
+ if @show_time_spent # or else it double shows from `lono sets deploy`. Do want it to show for `lono sets instances sync` though
60
+ show_time_spent(stack_set_operation)
61
+ puts "Stack set operation completed."
62
+ end
63
+ end
64
+
65
+ # describe_stack_set_operation stack_set_operation.status is
66
+ # one of RUNNING, SUCCEEDED, FAILED, STOPPING, STOPPED
67
+ def completed?(status)
68
+ completed_statuses = %w[SUCCEEDED FAILED STOPPED]
69
+ completed_statuses.include?(status)
70
+ end
71
+
72
+ # If we dont wait until OUTDATED, during a `lono sets deploy` it'll immediately think that the instance statuses are done
73
+ def wait_until_outdated
74
+ outdated = false
75
+ until outdated
76
+ outdated = stack_instances.detect { |stack_instance| stack_instance.status == "OUTDATED" }
77
+ sleep 5
78
+ end
79
+ end
80
+
81
+ def instances
82
+ stack_instances.map { |stack_instance| Instance.new(stack_instance) }
83
+ end
84
+
85
+ def stack_instances
86
+ resp = cfn.list_stack_instances(stack_set_name: @stack)
87
+ summaries = resp.summaries
88
+ # filter is really only used internally. So it's fine to keep it as complex data structure since that's what we
89
+ # build it up as in Lono::Sets::Instances::Deploy
90
+ filter = @options[:filter] # [["112233445566", "us-west-1"],["112233445566", "us-west-2"]]
91
+ return summaries unless filter
92
+
93
+ summaries.reject do |s|
94
+ intersect = [[s.account, s.region]] & filter
95
+ intersect.empty?
96
+ end
97
+ end
98
+
99
+ def operation_id
100
+ @operation_id ||= latest_operation_id
101
+ end
102
+
103
+ def latest_operation_id
104
+ resp = cfn.list_stack_set_operations(
105
+ stack_set_name: @stack,
106
+ max_results: 1,
107
+ )
108
+ resp.summaries.first.operation_id
109
+ end
110
+ end
111
+ end