stax 0.1.5 → 0.1.9

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 75641822b021f927037f37d69b733a2a6fd2a894f20da3094ff922b9af846bd5
4
- data.tar.gz: ecfa6da9d9b67ce326c199c94e4709e6f3debcf223636d57e0f0e466884e6eef
3
+ metadata.gz: 184e068dc00c13a187864710303862b2049ec3f353cdf7bda094dc94fe711201
4
+ data.tar.gz: a2fa06ab9dad658167b57cfbbaf7411a73cbfeccf1cb2eb4ab4c5a50beea9c97
5
5
  SHA512:
6
- metadata.gz: a4ff5cdf4ffeb7bd24f5bcf2df160e725d84b45a13feb40d4886ccb351ae2f3abacff951159855da0aa23fd92025adcc620875c5b07c8ca406139268e3243903
7
- data.tar.gz: fb6672ac0878c1bd28266d5a06ce90d9bd477c911ed0755200c9246ba5836be35d9d12add0c8d8015432d94166fc395374c03e457afd401db348b7af691d3b84
6
+ metadata.gz: 6491ccdb338d2883cc657eceab4255d14b6202bea65494f3a9ef71a6e459affa813252a5bdb766fb9e12a10d4d3a2121ebe39b80f7ef7803c0f0894b10eba326
7
+ data.tar.gz: 76e87f6dc9e8569d025ab23fc6ac662e30bb00439b8f06c6e7cfb7a0cc42c7e12046a76627e7de3c6b0f493764ecef8f77e52a66fb7e68d98c0899266d6340fe
data/lib/stax/aws/cfn.rb CHANGED
@@ -7,6 +7,7 @@ module Stax
7
7
  CREATE_IN_PROGRESS CREATE_FAILED CREATE_COMPLETE
8
8
  ROLLBACK_IN_PROGRESS ROLLBACK_FAILED ROLLBACK_COMPLETE
9
9
  DELETE_IN_PROGRESS DELETE_FAILED
10
+ IMPORT_IN_PROGRESS IMPORT_COMPLETE IMPORT_ROLLBACK_IN_PROGRESS IMPORT_ROLLBACK_FAILED IMPORT_ROLLBACK_COMPLETE
10
11
  UPDATE_IN_PROGRESS UPDATE_COMPLETE_CLEANUP_IN_PROGRESS UPDATE_COMPLETE
11
12
  UPDATE_ROLLBACK_IN_PROGRESS UPDATE_ROLLBACK_FAILED UPDATE_ROLLBACK_COMPLETE_CLEANUP_IN_PROGRESS UPDATE_ROLLBACK_COMPLETE
12
13
  REVIEW_IN_PROGRESS
@@ -17,6 +18,7 @@ module Stax
17
18
  CREATE_COMPLETE: :green,
18
19
  DELETE_COMPLETE: :green,
19
20
  UPDATE_COMPLETE: :green,
21
+ IMPORT_COMPLETE: :green,
20
22
  CREATE_FAILED: :red,
21
23
  DELETE_FAILED: :red,
22
24
  UPDATE_FAILED: :red,
@@ -24,6 +26,7 @@ module Stax
24
26
  ROLLBACK_COMPLETE: :red,
25
27
  ## resource action
26
28
  Add: :green,
29
+ Import: :green,
27
30
  Modify: :yellow,
28
31
  Remove: :red,
29
32
  }
@@ -170,4 +173,4 @@ module Stax
170
173
 
171
174
  end
172
175
  end
173
- end
176
+ end
data/lib/stax/base.rb CHANGED
@@ -1,6 +1,9 @@
1
1
  require 'thor'
2
2
  require 'stax/aws/sts'
3
3
 
4
+ ## clean exit on ctrl-c for all methods
5
+ trap('SIGINT', 'EXIT')
6
+
4
7
  module Stax
5
8
  class Base < Thor
6
9
 
@@ -68,7 +71,9 @@ module Stax
68
71
  end
69
72
  end
70
73
 
71
- def color(string, hash)
74
+ ## color a string according to current class COLORS hash
75
+ def color(string, hash = nil)
76
+ hash ||= self.class::COLORS
72
77
  set_color(string, hash.fetch(string.to_sym, :yellow))
73
78
  end
74
79
 
@@ -118,6 +123,7 @@ module Stax
118
123
 
119
124
  ## convert a diff in seconds to d h m s
120
125
  def human_time_diff(t, n = 5)
126
+ t = t.round # handle fractional seconds
121
127
  mm, ss = t.divmod(60)
122
128
  hh, mm = mm.divmod(60)
123
129
  dd, hh = hh.divmod(24)
data/lib/stax/cli/crud.rb CHANGED
@@ -56,10 +56,11 @@ module Stax
56
56
  end
57
57
 
58
58
  desc 'delete', 'meta delete task'
59
+ method_option :notail, aliases: '-n', type: :boolean, default: false, description: 'do not tail stack events'
59
60
  def delete
60
61
  stack_objects.reverse.each do |s|
61
62
  if s.exists?
62
- s.delete
63
+ s.invoke(:delete, [], options)
63
64
  else
64
65
  say("#{s.stack_name} does not exist", :green)
65
66
  end
@@ -67,4 +68,4 @@ module Stax
67
68
  end
68
69
 
69
70
  end
70
- end
71
+ end
@@ -14,6 +14,7 @@ module Stax
14
14
 
15
15
  COLORS = {
16
16
  available: :green,
17
+ 'in-sync': :green,
17
18
  Complete: :green,
18
19
  Active: :green,
19
20
  }
@@ -40,13 +41,36 @@ module Stax
40
41
  def stack_db_subnet_groups
41
42
  Aws::Cfn.resources_by_type(my.stack_name, 'AWS::RDS::DBSubnetGroup')
42
43
  end
44
+
45
+ def print_rds_events(opt)
46
+ Aws::Rds.client.describe_events(opt).map(&:events).flatten.map do |e|
47
+ [ e.date, e.message ]
48
+ end.tap(&method(:print_table))
49
+ end
50
+
51
+ end
52
+
53
+ desc 'ls', 'list clusters with members'
54
+ def ls
55
+ debug("RDS databases for #{my.stack_name}")
56
+ stack_rds_clusters.map do |c|
57
+ cluster = [ c.db_cluster_identifier, 'cluster', color(c.status), c.engine ]
58
+ instances = c.db_cluster_members.map do |m|
59
+ role = m.is_cluster_writer ? 'writer' : 'reader'
60
+ i = Aws::Rds.instances(filters: [ { name: 'db-instance-id', values: [ m.db_instance_identifier ] } ]).first
61
+ [ '- ' + i.db_instance_identifier, role, color(i.db_instance_status), i.engine, i.availability_zone, i.db_instance_class ]
62
+ end
63
+ [ cluster ] + instances
64
+ end.flatten(1).tap do |list|
65
+ print_table list
66
+ end
43
67
  end
44
68
 
45
69
  desc 'clusters', 'list db clusters for stack'
46
70
  def clusters
47
71
  debug("RDS DB clusters for #{my.stack_name}")
48
72
  print_table stack_rds_clusters.map { |c|
49
- [c.db_cluster_identifier, c.engine, c.engine_version, color(c.status, COLORS), c.cluster_create_time]
73
+ [c.db_cluster_identifier, c.engine, c.engine_version, color(c.status), c.cluster_create_time]
50
74
  }
51
75
  end
52
76
 
@@ -65,7 +89,7 @@ module Stax
65
89
  def instances
66
90
  debug("RDS DB instances for #{my.stack_name}")
67
91
  print_table stack_rds_instances.map { |i|
68
- [i.db_instance_identifier, i.engine, i.engine_version, color(i.db_instance_status, COLORS), i.db_instance_class, i.db_subnet_group&.vpc_id, i.availability_zone]
92
+ [i.db_instance_identifier, i.engine, i.engine_version, color(i.db_instance_status), i.db_instance_class, i.db_subnet_group&.vpc_id, i.availability_zone]
69
93
  }
70
94
  end
71
95
 
@@ -92,11 +116,48 @@ module Stax
92
116
  end.flatten.each do |g|
93
117
  debug("Subnets for group #{g.db_subnet_group_name}")
94
118
  print_table g.subnets.map { |s|
95
- [s&.subnet_availability_zone&.name, s&.subnet_identifier, color(s&.subnet_status, COLORS)]
119
+ [s&.subnet_availability_zone&.name, s&.subnet_identifier, color(s&.subnet_status)]
96
120
  }
97
121
  end
98
122
  end
99
123
 
124
+ desc 'failover', 'failover clusters'
125
+ method_option :target, type: :string, default: nil, desc: 'id of instance to promote'
126
+ def failover
127
+ stack_rds_clusters.each do |c|
128
+ if yes?("Failover #{c.db_cluster_identifier}?", :yellow)
129
+ resp = Aws::Rds.client.failover_db_cluster(db_cluster_identifier: c.db_cluster_identifier, target_db_instance_identifier: options[:target])
130
+ puts "failing over #{resp.db_cluster.db_cluster_identifier}"
131
+ end
132
+ end
133
+ end
134
+
135
+ desc 'snapshots', 'list snapshots for stack clusters'
136
+ def snapshots
137
+ stack_db_clusters.map(&:physical_resource_id).each do |id|
138
+ debug("Snapshots for cluster #{id}")
139
+ Aws::Rds.client.describe_db_cluster_snapshots(db_cluster_identifier: id).map(&:db_cluster_snapshots).flatten.map do |s|
140
+ [ s.db_cluster_snapshot_identifier, s.snapshot_create_time, "#{s.allocated_storage}G", color(s.status), s.snapshot_type ]
141
+ end.tap do |list|
142
+ print_table list
143
+ end
144
+ end
145
+ end
146
+
147
+ desc 'events', 'list rds events for this stack'
148
+ option :duration, aliases: '-d', type: :numeric, default: 60*24, desc: 'duration in mins to show'
149
+ def events
150
+ stack_db_clusters.map(&:physical_resource_id).each do |id|
151
+ debug("Events for cluster #{id}")
152
+ print_rds_events(duration: options[:duration], source_type: 'db-cluster', source_identifier: id)
153
+ end
154
+
155
+ stack_db_instances.map(&:physical_resource_id).each do |id|
156
+ debug("Events for instance #{id}")
157
+ print_rds_events(duration: options[:duration], source_type: 'db-instance', source_identifier: id)
158
+ end
159
+ end
160
+
100
161
  end
101
162
  end
102
- end
163
+ end
@@ -30,6 +30,23 @@ module Stax
30
30
  fail_task(e.message)
31
31
  end
32
32
 
33
+ ## create change set to import a resource
34
+ def change_set_import(resource)
35
+ Aws::Cfn.changeset(
36
+ change_set_type: :IMPORT,
37
+ resources_to_import: [ resource ],
38
+ stack_name: stack_name,
39
+ template_body: cfn_template_body,
40
+ template_url: cfn_template_url,
41
+ parameters: cfn_parameters_update,
42
+ capabilities: cfn_capabilities,
43
+ notification_arns: cfn_notification_arns,
44
+ change_set_name: change_set_name,
45
+ ).id
46
+ rescue ::Aws::CloudFormation::Errors::ValidationError => e
47
+ fail_task(e.message)
48
+ end
49
+
33
50
  ## wait and return true if changeset ready for execute
34
51
  def change_set_complete?(id)
35
52
  begin
@@ -71,11 +88,15 @@ module Stax
71
88
  end
72
89
 
73
90
  def change_set_unlock
74
- Aws::Cfn.set_policy(stack_name: stack_name, stack_policy_body: stack_policy_during_update)
91
+ unless stack_policy_during_update.nil?
92
+ Aws::Cfn.set_policy(stack_name: stack_name, stack_policy_body: stack_policy_during_update)
93
+ end
75
94
  end
76
95
 
77
96
  def change_set_lock
78
- Aws::Cfn.set_policy(stack_name: stack_name, stack_policy_body: stack_policy)
97
+ unless stack_policy.nil?
98
+ Aws::Cfn.set_policy(stack_name: stack_name, stack_policy_body: stack_policy)
99
+ end
79
100
  end
80
101
  end
81
102
 
@@ -90,5 +111,32 @@ module Stax
90
111
  change_set_lock
91
112
  end
92
113
 
114
+ desc 'import', 'create and execute changeset to import a resource'
115
+ option :type, aliases: '-t', type: :string, default: nil, desc: 'cfn resource (e.g. AWS::DynamoDB::Table)'
116
+ option :id, aliases: '-i', type: :string, default: nil, desc: 'logical id (e.g. OrdersTable)'
117
+ option :key, aliases: '-k', type: :string, default: nil, desc: 'resource key (e.g. TableName)'
118
+ option :value, aliases: '-v', type: :string, default: nil, desc: 'resource value (e.g. orders)'
119
+ def import
120
+ ## prompt for missing options
121
+ %i[type id key value].each do |opt|
122
+ options[opt] ||= ask("Resource #{opt}?", :yellow)
123
+ end
124
+
125
+ ## create import changeset
126
+ debug("Creating import change set for #{stack_name}")
127
+ id = change_set_import(
128
+ resource_type: options[:type],
129
+ logical_resource_id: options[:id],
130
+ resource_identifier: {
131
+ options[:key] => options[:value]
132
+ }
133
+ )
134
+
135
+ ## wait for changeset, prompt for changes, and execute
136
+ change_set_complete?(id) || fail_task(change_set_reason(id))
137
+ change_set_changes(id)
138
+ change_set_execute(id) && tail && update_warn_imports
139
+ end
140
+
93
141
  end
94
- end
142
+ end
@@ -24,28 +24,31 @@ module Stax
24
24
  }
25
25
  end
26
26
 
27
- ## policy to lock the stack to all updates
27
+ ## policy to lock the stack to all updates, for example:
28
+ ## {
29
+ ## Statement: [
30
+ ## Effect: 'Deny',
31
+ ## Action: 'Update:*',
32
+ ## Principal: '*',
33
+ ## Resource: '*'
34
+ ## ]
35
+ ## }.to_json
28
36
  def stack_policy
29
- {
30
- Statement: [
31
- Effect: 'Deny',
32
- Action: 'Update:*',
33
- Principal: '*',
34
- Resource: '*'
35
- ]
36
- }.to_json
37
+ nil
37
38
  end
38
39
 
39
- ## temporary policy during updates; modify this to restrict resources
40
+ ## tmp policy during updates, in case a deny was set in stack_policy()
41
+ ## for example:
42
+ ## {
43
+ ## Statement: [
44
+ ## Effect: 'Allow',
45
+ ## Action: 'Update:*',
46
+ ## Principal: '*',
47
+ ## Resource: '*'
48
+ ## ]
49
+ ## }.to_json
40
50
  def stack_policy_during_update
41
- {
42
- Statement: [
43
- Effect: 'Allow',
44
- Action: 'Update:*',
45
- Principal: '*',
46
- Resource: '*'
47
- ]
48
- }.to_json
51
+ nil
49
52
  end
50
53
 
51
54
  ## cleanup sometimes needs to wait
@@ -206,11 +209,12 @@ module Stax
206
209
  end
207
210
 
208
211
  desc 'delete', 'delete stack'
212
+ method_option :notail, aliases: '-n', type: :boolean, default: false, description: 'do not tail stack events'
209
213
  def delete
210
214
  delete_warn_imports
211
215
  if yes? "Really delete stack #{stack_name}?", :yellow
212
216
  Aws::Cfn.delete(stack_name)
213
- tail
217
+ tail unless options[:notail]
214
218
  end
215
219
  rescue ::Aws::CloudFormation::Errors::ValidationError => e
216
220
  fail_task(e.message)
@@ -21,8 +21,8 @@ module Stax
21
21
  end
22
22
  end
23
23
 
24
- desc 'imports', 'list imports from this stack'
25
- def imports
24
+ desc 'exports', 'list exports from this stack, and stacks that import them'
25
+ def exports
26
26
  debug("Stacks that import from #{stack_name}")
27
27
  print_table Aws::Cfn.exports(stack_name).map { |e|
28
28
  imports = (i = Aws::Cfn.imports(e.export_name)).empty? ? '-' : i.join(' ')
@@ -30,5 +30,11 @@ module Stax
30
30
  }.sort
31
31
  end
32
32
 
33
+ desc 'imports', 'deprecated: use exports'
34
+ def imports
35
+ warn("deprecated method: please use 'exports' instead")
36
+ exports
37
+ end
38
+
33
39
  end
34
- end
40
+ end
data/lib/stax/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Stax
2
- VERSION = '0.1.5'
2
+ VERSION = '0.1.9'
3
3
  end
data/lib/stax.rb CHANGED
@@ -16,7 +16,7 @@ require 'stax/stack/crud'
16
16
  require 'stax/stack/changeset'
17
17
  require 'stax/stack/parameters'
18
18
  require 'stax/stack/outputs'
19
- require 'stax/stack/imports'
19
+ require 'stax/stack/exports'
20
20
  require 'stax/stack/resources'
21
21
  require 'stax/stack/drift'
22
22
 
data/stax.gemspec CHANGED
@@ -23,7 +23,6 @@ Gem::Specification.new do |spec|
23
23
 
24
24
  spec.add_development_dependency "bundler"
25
25
  spec.add_development_dependency "rake", "~> 10.0"
26
- spec.add_development_dependency "docile", "1.2.0"
27
26
  spec.add_development_dependency "stax-examples"
28
27
 
29
28
  spec.add_dependency('aws-sdk-cloudformation')
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: stax
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.5
4
+ version: 0.1.9
5
5
  platform: ruby
6
6
  authors:
7
7
  - Richard Lister
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-09-25 00:00:00.000000000 Z
11
+ date: 2021-10-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -38,20 +38,6 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '10.0'
41
- - !ruby/object:Gem::Dependency
42
- name: docile
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - '='
46
- - !ruby/object:Gem::Version
47
- version: 1.2.0
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - '='
53
- - !ruby/object:Gem::Version
54
- version: 1.2.0
55
41
  - !ruby/object:Gem::Dependency
56
42
  name: stax-examples
57
43
  requirement: !ruby/object:Gem::Requirement
@@ -596,7 +582,7 @@ files:
596
582
  - lib/stax/stack/changeset.rb
597
583
  - lib/stax/stack/crud.rb
598
584
  - lib/stax/stack/drift.rb
599
- - lib/stax/stack/imports.rb
585
+ - lib/stax/stack/exports.rb
600
586
  - lib/stax/stack/outputs.rb
601
587
  - lib/stax/stack/parameters.rb
602
588
  - lib/stax/stack/resources.rb
@@ -624,7 +610,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
624
610
  - !ruby/object:Gem::Version
625
611
  version: '0'
626
612
  requirements: []
627
- rubygems_version: 3.1.2
613
+ rubygems_version: 3.1.4
628
614
  signing_key:
629
615
  specification_version: 4
630
616
  summary: Control Cloudformation stack and other stuff.