Class: Stax::Stack
- Defined in:
- lib/stax/stack.rb,
lib/stax/cli/info.rb,
lib/stax/stack/cfn.rb,
lib/stax/stack/crud.rb,
lib/stax/stack/drift.rb,
lib/stax/stack/exports.rb,
lib/stax/stack/outputs.rb,
lib/stax/stack/template.rb,
lib/stax/stack/changeset.rb,
lib/stax/stack/resources.rb,
lib/stax/stack/parameters.rb,
lib/stax/generators/new/templates/lib/stack.rb,
lib/stax/cfer.rb
Constant Summary collapse
- COLORS =
{ IN_SYNC: :green, MODIFIED: :red, DELETED: :red, ADD: :green, REMOVE: :red, }
Instance Method Summary collapse
- #cancel ⇒ Object
- #change ⇒ Object
- #continue ⇒ Object
- #create ⇒ Object
- #delete ⇒ Object
- #drifts ⇒ Object
- #events ⇒ Object
- #exists ⇒ Object
- #exports ⇒ Object
- #generate ⇒ Object
- #id(resource) ⇒ Object
- #import ⇒ Object
- #imports ⇒ Object
- #info ⇒ Object
- #lint ⇒ Object
- #outputs(key = nil) ⇒ Object
- #parameters ⇒ Object
- #policy(json = nil) ⇒ Object
- #protection ⇒ Object
- #resources ⇒ Object
- #skeleton ⇒ Object
- #tags ⇒ Object
- #tail ⇒ Object
- #template ⇒ Object
- #update ⇒ Object
- #validate ⇒ Object
Instance Method Details
#cancel ⇒ Object
224 225 226 227 228 229 230 |
# File 'lib/stax/stack/crud.rb', line 224 def cancel debug("Cancelling update for #{stack_name}") Aws::Cfn.cancel(stack_name) tail rescue ::Aws::CloudFormation::Errors::ValidationError => e fail_task(e.) end |
#change ⇒ Object
104 105 106 107 108 109 110 111 112 |
# File 'lib/stax/stack/changeset.rb', line 104 def change id = change_set_update change_set_complete?(id) || fail_task(change_set_reason(id)) change_set_changes(id) change_set_unlock change_set_execute(id) && tail && update_warn_imports ensure change_set_lock end |
#continue ⇒ Object
239 240 241 242 243 244 245 246 247 |
# File 'lib/stax/stack/crud.rb', line 239 def continue Aws::Cfn.client.continue_update_rollback( stack_name: stack_name, resources_to_skip: [:skip], ) tail rescue ::Aws::CloudFormation::Errors::ValidationError => e fail_task(e.) end |
#create ⇒ Object
164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 |
# File 'lib/stax/stack/crud.rb', line 164 def create debug("Creating stack #{stack_name}") ## ensure stacks we import exist ensure_stack(*stack_imports) ## create the stack Aws::Cfn.create( stack_name: stack_name, template_body: cfn_template_body, template_url: cfn_template_url, parameters: cfn_parameters_create, capabilities: cfn_capabilities, stack_policy_body: stack_policy, notification_arns: cfn_notification_arns, enable_termination_protection: cfn_termination_protection, tags: , ) ## show stack events tail rescue ::Aws::CloudFormation::Errors::AlreadyExistsException => e fail_task(e.) rescue ::Aws::CloudFormation::Errors::ValidationError => e warn(e.) end |
#delete ⇒ Object
213 214 215 216 217 218 219 220 221 |
# File 'lib/stax/stack/crud.rb', line 213 def delete delete_warn_imports if yes? "Really delete stack #{stack_name}?", :yellow Aws::Cfn.delete(stack_name) tail unless [:notail] end rescue ::Aws::CloudFormation::Errors::ValidationError => e fail_task(e.) end |
#drifts ⇒ Object
49 50 51 52 53 |
# File 'lib/stax/stack/drift.rb', line 49 def drifts run_drift_detection drifts = show_drifts show_drifts_details(drifts) end |
#events ⇒ Object
34 35 36 37 38 |
# File 'lib/stax/stack/cfn.rb', line 34 def events print_events(Aws::Cfn.events(stack_name)[0..[:number]-1]) rescue ::Aws::CloudFormation::Errors::ValidationError => e puts e. end |
#exists ⇒ Object
47 48 49 |
# File 'lib/stax/stack.rb', line 47 def exists puts exists? end |
#exports ⇒ Object
25 26 27 28 29 30 31 |
# File 'lib/stax/stack/exports.rb', line 25 def exports debug("Stacks that import from #{stack_name}") print_table Aws::Cfn.exports(stack_name).map { |e| imports = (i = Aws::Cfn.imports(e.export_name)).empty? ? '-' : i.join(' ') [e.output_key, imports] }.sort end |
#generate ⇒ Object
233 234 235 |
# File 'lib/stax/stack/crud.rb', line 233 def generate puts cfn_template end |
#id(resource) ⇒ Object
30 31 32 |
# File 'lib/stax/stack/resources.rb', line 30 def id(resource) puts Aws::Cfn.id(stack_name, resource) end |
#import ⇒ Object
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/stax/stack/changeset.rb', line 119 def import ## prompt for missing options %i[type id key value].each do |opt| [opt] ||= ask("Resource #{opt}?", :yellow) end ## create import changeset debug("Creating import change set for #{stack_name}") id = change_set_import( resource_type: [:type], logical_resource_id: [:id], resource_identifier: { [:key] => [:value] } ) ## wait for changeset, prompt for changes, and execute change_set_complete?(id) || fail_task(change_set_reason(id)) change_set_changes(id) change_set_execute(id) && tail && update_warn_imports end |
#imports ⇒ Object
34 35 36 37 |
# File 'lib/stax/stack/exports.rb', line 34 def imports warn("deprecated method: please use 'exports' instead") exports end |
#info ⇒ Object
11 12 13 14 15 16 17 18 19 20 |
# File 'lib/stax/cli/info.rb', line 11 def info ## get mixins in the order we declared them self.class.subcommands.reverse.each do |cmd| begin invoke cmd, [:info] rescue Thor::UndefinedCommandError => e # no info no problem end end end |
#lint ⇒ Object
290 |
# File 'lib/stax/stack/crud.rb', line 290 desc 'lint', 'run cfn-lint on template' |
#outputs(key = nil) ⇒ Object
15 16 17 18 19 20 21 22 23 |
# File 'lib/stax/stack/outputs.rb', line 15 def outputs(key = nil) if key puts stack_output(key) else print_table Aws::Cfn.describe(stack_name).outputs.map { |o| [o.output_key, o.output_value, o.description, o.export_name] }.sort end end |
#parameters ⇒ Object
17 18 19 20 21 |
# File 'lib/stax/stack/parameters.rb', line 17 def parameters print_table stack_parameters.each_with_object({}) { |p, h| h[p.parameter_key] = p.parameter_value }.sort end |
#policy(json = nil) ⇒ Object
263 264 265 266 267 268 269 |
# File 'lib/stax/stack/crud.rb', line 263 def policy(json = nil) if json Aws::Cfn.set_policy(stack_name: stack_name, stack_policy_body: json) else puts Aws::Cfn.get_policy(stack_name: stack_name) end end |
#protection ⇒ Object
252 253 254 255 256 257 258 259 260 |
# File 'lib/stax/stack/crud.rb', line 252 def protection if [:enable] Aws::Cfn.protection(stack_name, true) elsif [:disable] Aws::Cfn.protection(stack_name, false) end debug("Termination protection for #{stack_name}") puts Aws::Cfn.describe(stack_name)&.enable_termination_protection end |
#resources ⇒ Object
18 19 20 21 22 23 24 25 26 27 |
# File 'lib/stax/stack/resources.rb', line 18 def resources print_table stack_resources.tap { |resources| if [:match] m = Regexp.new([:match], Regexp::IGNORECASE) resources.select! { |r| m.match(r.resource_type) } end }.map { |r| [r.logical_resource_id, r.resource_type, color(r.resource_status, Aws::Cfn::COLORS), r.physical_resource_id] } end |
#skeleton ⇒ Object
273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 |
# File 'lib/stax/stack/crud.rb', line 273 def skeleton skel = { StackName: stack_name, TemplateBody: cfn_template_body, TemplateURL: cfn_template_url, Parameters: cfn_parameters_create, Capabilities: cfn_capabilities, StackPolicyBody: stack_policy, NotificationARNs: cfn_notification_arns, EnableTerminationProtection: cfn_termination_protection, Tags: , }.compact method = [:pretty] ? :pretty_generate : :generate puts JSON.send(method, skel) end |
#tags ⇒ Object
73 74 75 76 77 |
# File 'lib/stax/stack/cfn.rb', line 73 def print_table Aws::Cfn.describe(stack_name)..map { |t| [ t.key, t.value ] } end |
#tail ⇒ Object
42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
# File 'lib/stax/stack/cfn.rb', line 42 def tail trap('SIGINT', 'EXIT') # clean exit with ctrl-c ## print some historical events events = Aws::Cfn.events(stack_name).first([:number] || 1) return unless events print_events(events) last_seen = events&.first&.event_id loop do sleep(1) events = [] Aws::Cfn.events(stack_name).each do |e| (last_seen == e.event_id) ? break : events << e end unless events.empty? print_events(events) last_seen = events.first.event_id end ## get stack status and break if stack gone, or delete complete/failed s = Aws::Cfn.describe(stack_name) break if s.nil? || s.stack_status.end_with?('COMPLETE', 'FAILED') end rescue ::Aws::CloudFormation::Errors::ValidationError => e puts e. end |
#template ⇒ Object
20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/stax/stack/cfn.rb', line 20 def template body = Aws::Cfn.template(stack_name) if [:pretty] begin body = JSON.pretty_generate(JSON.parse(body)) rescue JSON::ParserError ## not valid json, may be yaml end end puts body end |
#update ⇒ Object
192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 |
# File 'lib/stax/stack/crud.rb', line 192 def update return change if stack_force_changeset debug("Updating stack #{stack_name}") Aws::Cfn.update( stack_name: stack_name, template_body: cfn_template_body, template_url: cfn_template_url, parameters: cfn_parameters_update, capabilities: cfn_capabilities, stack_policy_during_update_body: stack_policy_during_update, notification_arns: cfn_notification_arns, tags: , ) tail update_warn_imports rescue ::Aws::CloudFormation::Errors::ValidationError => e warn(e.) end |