swa 0.8.6 → 1.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 (78) hide show
  1. checksums.yaml +4 -4
  2. data/.beads/.gitignore +18 -0
  3. data/.beads/issues.jsonl +5 -0
  4. data/.rubocop.yml +39 -0
  5. data/AGENTS.md +541 -0
  6. data/CLAUDE.md +5 -0
  7. data/Gemfile +9 -1
  8. data/README.md +0 -5
  9. data/Rakefile +2 -0
  10. data/bin/console +1 -0
  11. data/exe/swa +2 -1
  12. data/lib/swa/athena/catalog.rb +4 -0
  13. data/lib/swa/athena/database.rb +4 -0
  14. data/lib/swa/athena/query_execution.rb +4 -0
  15. data/lib/swa/athena/work_group.rb +4 -0
  16. data/lib/swa/cli/athena_command.rb +93 -42
  17. data/lib/swa/cli/base_command.rb +22 -14
  18. data/lib/swa/cli/cloud_formation_command.rb +11 -4
  19. data/lib/swa/cli/cloudtrail_command.rb +130 -0
  20. data/lib/swa/cli/collection_behaviour.rb +4 -2
  21. data/lib/swa/cli/data_output.rb +12 -11
  22. data/lib/swa/cli/ec2_command.rb +21 -37
  23. data/lib/swa/cli/elb_command.rb +5 -3
  24. data/lib/swa/cli/filter_options.rb +6 -1
  25. data/lib/swa/cli/glue_command.rb +84 -36
  26. data/lib/swa/cli/iam_command.rb +42 -33
  27. data/lib/swa/cli/item_behaviour.rb +4 -2
  28. data/lib/swa/cli/kms_command.rb +26 -5
  29. data/lib/swa/cli/lake_formation_command.rb +72 -11
  30. data/lib/swa/cli/main_command.rb +19 -9
  31. data/lib/swa/cli/s3_command.rb +32 -24
  32. data/lib/swa/cli/selector.rb +4 -0
  33. data/lib/swa/cli/tag_filter_options.rb +6 -2
  34. data/lib/swa/cloud_formation/stack.rb +5 -1
  35. data/lib/swa/cloud_trail/event.rb +49 -0
  36. data/lib/swa/data_presentation.rb +23 -22
  37. data/lib/swa/ec2/image.rb +7 -5
  38. data/lib/swa/ec2/instance.rb +5 -1
  39. data/lib/swa/ec2/key_pair.rb +4 -0
  40. data/lib/swa/ec2/security_group.rb +5 -3
  41. data/lib/swa/ec2/snapshot.rb +6 -4
  42. data/lib/swa/ec2/subnet.rb +5 -3
  43. data/lib/swa/ec2/tagged_resource.rb +4 -0
  44. data/lib/swa/ec2/volume.rb +7 -5
  45. data/lib/swa/ec2/vpc.rb +5 -3
  46. data/lib/swa/elb/load_balancer.rb +4 -0
  47. data/lib/swa/glue/crawl.rb +5 -1
  48. data/lib/swa/glue/crawler.rb +5 -1
  49. data/lib/swa/glue/database.rb +5 -0
  50. data/lib/swa/glue/job.rb +4 -0
  51. data/lib/swa/glue/job_bookmark_entry.rb +4 -0
  52. data/lib/swa/glue/job_run.rb +5 -1
  53. data/lib/swa/glue/partition.rb +5 -1
  54. data/lib/swa/glue/table.rb +4 -0
  55. data/lib/swa/iam/credentials.rb +7 -7
  56. data/lib/swa/iam/group.rb +5 -3
  57. data/lib/swa/iam/instance_profile.rb +5 -3
  58. data/lib/swa/iam/policy.rb +5 -3
  59. data/lib/swa/iam/role.rb +10 -3
  60. data/lib/swa/iam/role_policy.rb +5 -3
  61. data/lib/swa/iam/user.rb +5 -3
  62. data/lib/swa/kms/alias.rb +4 -0
  63. data/lib/swa/kms/key.rb +4 -0
  64. data/lib/swa/lake_formation/data_lake_settings.rb +15 -0
  65. data/lib/swa/lake_formation/permission.rb +5 -1
  66. data/lib/swa/lake_formation/resource_info.rb +4 -0
  67. data/lib/swa/lake_formation/tag.rb +25 -0
  68. data/lib/swa/polyfill.rb +3 -1
  69. data/lib/swa/record.rb +5 -3
  70. data/lib/swa/resource.rb +3 -1
  71. data/lib/swa/s3/bucket.rb +5 -3
  72. data/lib/swa/s3/object.rb +7 -5
  73. data/lib/swa/s3/object_list_entry.rb +4 -0
  74. data/lib/swa/s3/object_version.rb +13 -7
  75. data/lib/swa/version.rb +5 -1
  76. data/lib/swa.rb +2 -0
  77. data/swa.gemspec +29 -25
  78. metadata +63 -29
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "aws-sdk-ec2"
2
4
  require "swa/cli/base_command"
3
5
  require "swa/cli/collection_behaviour"
@@ -13,6 +15,7 @@ require "swa/ec2/volume"
13
15
  require "swa/ec2/vpc"
14
16
 
15
17
  module Swa
18
+
16
19
  module CLI
17
20
 
18
21
  class Ec2Command < BaseCommand
@@ -56,7 +59,7 @@ module Swa
56
59
  use `--owned-by` to select a different scope.
57
60
  EOF
58
61
 
59
- option "--owned-by", "OWNER", "with specified owner", :default => "self"
62
+ option "--owned-by", "OWNER", "with specified owner", default: "self"
60
63
  option "--named", "PATTERN", "with matching name"
61
64
 
62
65
  option ["--created-after", "--after"], "WHEN", "earliest creation-date"
@@ -65,8 +68,6 @@ module Swa
65
68
  include TagFilterOptions
66
69
  include CollectionBehaviour
67
70
 
68
- private
69
-
70
71
  def named=(name_pattern)
71
72
  add_filter("name", name_pattern)
72
73
  end
@@ -108,8 +109,13 @@ module Swa
108
109
 
109
110
  end
110
111
 
111
- %w(stop start reboot terminate).each do |action|
112
- class_eval <<-RUBY
112
+ %w[stop start reboot terminate].each do |action|
113
+ # subcommand "stop", "Stop the instance" do
114
+ # def execute
115
+ # instance.stop
116
+ # end
117
+ # end
118
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1 # rubocop:disable Style/DocumentDynamicEvalDefinition
113
119
  subcommand "#{action}", "#{action.capitalize} the instance" do
114
120
  def execute
115
121
  instance.#{action}
@@ -118,8 +124,6 @@ module Swa
118
124
  RUBY
119
125
  end
120
126
 
121
- private
122
-
123
127
  def instance
124
128
  Swa::EC2::Instance.new(ec2.instance(instance_id))
125
129
  end
@@ -138,7 +142,7 @@ module Swa
138
142
  EOF
139
143
 
140
144
  option ["--state"], "STATE", "with specified status",
141
- :default => "running"
145
+ default: "running"
142
146
 
143
147
  option "--named", "NAME", "with matching name" do |name|
144
148
  add_tag_filter("Name", name)
@@ -162,8 +166,13 @@ module Swa
162
166
  include TagFilterOptions
163
167
  include CollectionBehaviour
164
168
 
165
- %w(stop start reboot terminate).each do |action|
166
- class_eval <<-RUBY
169
+ %w[stop start reboot terminate].each do |action|
170
+ # subcommand "stop", "Stop all instances" do
171
+ # def execute
172
+ # instances.each { |i| i.stop }
173
+ # end
174
+ # end
175
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1 # rubocop:disable Style/DocumentDynamicEvalDefinition
167
176
  subcommand "#{action}", "#{action.capitalize} all instances" do
168
177
  def execute
169
178
  instances.each do |i|
@@ -188,8 +197,6 @@ module Swa
188
197
  end
189
198
  end
190
199
 
191
- private
192
-
193
200
  def instances
194
201
  add_filter("instance-state-name", state)
195
202
  query_for(:instances, Swa::EC2::Instance)
@@ -211,8 +218,6 @@ module Swa
211
218
  end
212
219
  end
213
220
 
214
- private
215
-
216
221
  def key_pair
217
222
  Swa::EC2::KeyPair.new(ec2.key_pair(name))
218
223
  end
@@ -238,8 +243,6 @@ module Swa
238
243
  end
239
244
  end
240
245
 
241
- private
242
-
243
246
  def named=(pattern)
244
247
  selector.add do |kp|
245
248
  File.fnmatch(pattern, kp.name)
@@ -266,8 +269,6 @@ module Swa
266
269
  end
267
270
  end
268
271
 
269
- private
270
-
271
272
  def security_group
272
273
  Swa::EC2::SecurityGroup.new(ec2.security_group(group_id))
273
274
  end
@@ -287,8 +288,6 @@ module Swa
287
288
  end
288
289
  end
289
290
 
290
- private
291
-
292
291
  def security_groups
293
292
  query_for(:security_groups, Swa::EC2::SecurityGroup)
294
293
  end
@@ -309,8 +308,6 @@ module Swa
309
308
  end
310
309
  end
311
310
 
312
- private
313
-
314
311
  def snapshot
315
312
  Swa::EC2::Snapshot.new(ec2.snapshot(snapshot_id))
316
313
  end
@@ -328,7 +325,7 @@ module Swa
328
325
  use `--owned-by` to select a different scope.
329
326
  EOF
330
327
 
331
- option "--owned-by", "OWNER", "with specified owner", :default => "self"
328
+ option "--owned-by", "OWNER", "with specified owner", default: "self"
332
329
  option ["--volume", "--of"], "VOLUME-ID", "for specified volume"
333
330
 
334
331
  option ["--started-after", "--after"], "WHEN", "earliest start-time"
@@ -337,8 +334,6 @@ module Swa
337
334
  include TagFilterOptions
338
335
  include CollectionBehaviour
339
336
 
340
- private
341
-
342
337
  def volume=(volume_id)
343
338
  add_filter("volume-id", volume_id)
344
339
  end
@@ -372,8 +367,6 @@ module Swa
372
367
 
373
368
  include ItemBehaviour
374
369
 
375
- private
376
-
377
370
  def subnet
378
371
  Swa::EC2::Subnet.new(ec2.subnet(subnet_id))
379
372
  end
@@ -387,8 +380,6 @@ module Swa
387
380
  include TagFilterOptions
388
381
  include CollectionBehaviour
389
382
 
390
- private
391
-
392
383
  def subnets
393
384
  query_for(:subnets, Swa::EC2::Subnet)
394
385
  end
@@ -403,8 +394,6 @@ module Swa
403
394
 
404
395
  include ItemBehaviour
405
396
 
406
- private
407
-
408
397
  def volume
409
398
  Swa::EC2::Volume.new(ec2.volume(volume_id))
410
399
  end
@@ -422,8 +411,6 @@ module Swa
422
411
  include TagFilterOptions
423
412
  include CollectionBehaviour
424
413
 
425
- private
426
-
427
414
  def volumes
428
415
  query_for(:volumes, Swa::EC2::Volume)
429
416
  end
@@ -438,8 +425,6 @@ module Swa
438
425
 
439
426
  include ItemBehaviour
440
427
 
441
- private
442
-
443
428
  def vpc
444
429
  Swa::EC2::Vpc.new(ec2.vpc(vpc_id))
445
430
  end
@@ -457,8 +442,6 @@ module Swa
457
442
  add_tag_filter("Name", name)
458
443
  end
459
444
 
460
- private
461
-
462
445
  def vpcs
463
446
  query_for(:vpcs, Swa::EC2::Vpc)
464
447
  end
@@ -482,4 +465,5 @@ module Swa
482
465
  end
483
466
 
484
467
  end
468
+
485
469
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "aws-sdk-elasticloadbalancing"
2
4
  require "swa/cli/base_command"
3
5
  require "swa/cli/collection_behaviour"
@@ -5,6 +7,7 @@ require "swa/cli/item_behaviour"
5
7
  require "swa/elb/load_balancer"
6
8
 
7
9
  module Swa
10
+
8
11
  module CLI
9
12
 
10
13
  class ElbCommand < BaseCommand
@@ -18,7 +21,7 @@ module Swa
18
21
  private
19
22
 
20
23
  def item
21
- results = describe_load_balancers(:load_balancer_names => [name])
24
+ results = describe_load_balancers(load_balancer_names: [name])
22
25
  signal_error "No such ELB '#{name}'" unless results.any?
23
26
  Swa::ELB::LoadBalancer.new(results.first)
24
27
  end
@@ -29,8 +32,6 @@ module Swa
29
32
 
30
33
  include CollectionBehaviour
31
34
 
32
- private
33
-
34
35
  def collection
35
36
  Swa::ELB::LoadBalancer.list(describe_load_balancers)
36
37
  end
@@ -50,4 +51,5 @@ module Swa
50
51
  end
51
52
 
52
53
  end
54
+
53
55
  end
@@ -1,6 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "clamp"
2
4
 
3
5
  module Swa
6
+
4
7
  module CLI
5
8
 
6
9
  module FilterOptions
@@ -8,7 +11,7 @@ module Swa
8
11
  extend Clamp::Option::Declaration
9
12
 
10
13
  option "--filter", "NAME=VALUE", "apply a filter",
11
- :multivalued => true, :attribute_name => :filters
14
+ multivalued: true, attribute_name: :filters
12
15
 
13
16
  protected
14
17
 
@@ -26,10 +29,12 @@ module Swa
26
29
  def append_to_filters(arg)
27
30
  name, value = arg.split("=", 2)
28
31
  raise ArgumentError, "no value supplied" unless value
32
+
29
33
  add_filter(name, value)
30
34
  end
31
35
 
32
36
  end
33
37
 
34
38
  end
39
+
35
40
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "aws-sdk-glue"
2
4
  require "swa/cli/base_command"
3
5
  require "swa/cli/collection_behaviour"
@@ -12,6 +14,7 @@ require "swa/glue/partition"
12
14
  require "swa/glue/table"
13
15
 
14
16
  module Swa
17
+
15
18
  module CLI
16
19
 
17
20
  class GlueCommand < BaseCommand
@@ -29,15 +32,13 @@ module Swa
29
32
  private
30
33
 
31
34
  def collection
32
- query_for(:list_crawls, :crawls, Swa::Glue::Crawl, :crawler_name => name)
35
+ query_for(:list_crawls, :crawls, Swa::Glue::Crawl, crawler_name: name)
33
36
  end
34
37
 
35
38
  end
36
39
 
37
- private
38
-
39
40
  def item
40
- Swa::Glue::Crawler.new(glue_client.get_crawler(:name => name).crawler)
41
+ Swa::Glue::Crawler.new(glue_client.get_crawler(name: name).crawler)
41
42
  end
42
43
 
43
44
  end
@@ -46,8 +47,6 @@ module Swa
46
47
 
47
48
  include CollectionBehaviour
48
49
 
49
- private
50
-
51
50
  def collection
52
51
  query_for(:get_crawlers, :crawlers, Swa::Glue::Crawler)
53
52
  end
@@ -56,20 +55,28 @@ module Swa
56
55
 
57
56
  subcommand ["database"], "Show database" do
58
57
 
58
+ option %w[--catalog], "NAME", "Catalog ID"
59
+
59
60
  parameter "NAME", "database name"
60
61
 
61
62
  include ItemBehaviour
62
63
 
63
- private
64
-
65
64
  def item
66
- Swa::Glue::Database.new(glue_client.get_database(:name => name).database)
65
+ Swa::Glue::Database.new(glue_client.get_database(catalog_id: catalog, name: name).database)
66
+ end
67
+
68
+ subcommand ["arn"], "Show database ARN" do
69
+
70
+ def execute
71
+ puts "arn:aws:glue:#{region}:#{item.catalog_id}:database/#{name}"
72
+ end
73
+
67
74
  end
68
75
 
69
76
  subcommand ["delete"], "Delete database" do
70
77
 
71
78
  def execute
72
- glue_client.delete_database(:name => name)
79
+ glue_client.delete_database(name: name, **catalog_constraint)
73
80
  end
74
81
 
75
82
  end
@@ -84,10 +91,9 @@ module Swa
84
91
 
85
92
  include CollectionBehaviour
86
93
 
87
- private
88
-
89
94
  def collection
90
- query_for(:get_partitions, :partitions, Swa::Glue::Partition, :database_name => name, :table_name => table_name)
95
+ query_for(:get_partitions, :partitions, Swa::Glue::Partition, catalog_id: catalog,
96
+ database_name: name, table_name: table_name)
91
97
  end
92
98
 
93
99
  end
@@ -95,29 +101,68 @@ module Swa
95
101
  subcommand ["delete"], "Delete table" do
96
102
 
97
103
  def execute
98
- glue_client.delete_table(:database_name => name, :name => table_name)
104
+ glue_client.delete_table(catalog_id: catalog, database_name: name, name: table_name)
99
105
  end
100
106
 
101
107
  end
102
108
 
103
- private
109
+ subcommand ["lf-tags"], "Show associated LakeFormation tags" do
110
+
111
+ include CollectionBehaviour
112
+
113
+ def collection
114
+ Swa::LakeFormation::Tag.list_from_query(
115
+ lf_client, :get_resource_lf_tags, :lf_tags_on_table, resource: lf_resource_spec
116
+ )
117
+ end
118
+
119
+ end
120
+
121
+ subcommand ["lf-permissions"], "Show LakeFormation permissions" do
122
+
123
+ option ["--principal", "-P"], "ARN", "Principal ARN"
124
+
125
+ include CollectionBehaviour
126
+
127
+ def collection
128
+ query_args = {
129
+ resource: lf_resource_spec
130
+ }
131
+ if principal
132
+ query_args[:principal] = {
133
+ data_lake_principal_identifier: principal
134
+ }
135
+ end
136
+ Swa::LakeFormation::Permission.list_from_query(
137
+ lf_client, :list_permissions, :principal_resource_permissions, **query_args
138
+ )
139
+ end
140
+
141
+ end
104
142
 
105
143
  def item
106
144
  Swa::Glue::Table.new(glue_client.get_table(
107
- :database_name => name, :name => table_name
145
+ catalog_id: catalog, database_name: name, name: table_name
108
146
  ).table)
109
147
  end
110
148
 
149
+ def lf_resource_spec
150
+ {
151
+ table: {
152
+ database_name: name,
153
+ name: table_name
154
+ }
155
+ }
156
+ end
157
+
111
158
  end
112
159
 
113
160
  subcommand ["tables"], "Show tables" do
114
161
 
115
162
  include CollectionBehaviour
116
163
 
117
- private
118
-
119
164
  def collection
120
- query_for(:get_tables, :table_list, Swa::Glue::Table, :database_name => name)
165
+ query_for(:get_tables, :table_list, Swa::Glue::Table, catalog_id: catalog, database_name: name)
121
166
  end
122
167
 
123
168
  end
@@ -126,12 +171,12 @@ module Swa
126
171
 
127
172
  subcommand ["databases"], "Show databases" do
128
173
 
129
- include CollectionBehaviour
174
+ option %w[--catalog], "NAME", "Catalog ID"
130
175
 
131
- private
176
+ include CollectionBehaviour
132
177
 
133
178
  def collection
134
- query_for(:get_databases, :database_list, Swa::Glue::Database)
179
+ query_for(:get_databases, :database_list, Swa::Glue::Database, catalog_id: catalog)
135
180
  end
136
181
 
137
182
  end
@@ -142,10 +187,8 @@ module Swa
142
187
 
143
188
  include ItemBehaviour
144
189
 
145
- private
146
-
147
190
  def item
148
- Swa::Glue::Job.new(glue_client.get_job(:job_name => name).job)
191
+ Swa::Glue::Job.new(glue_client.get_job(job_name: name).job)
149
192
  end
150
193
 
151
194
  subcommand ["run"], "Show run" do
@@ -160,20 +203,16 @@ module Swa
160
203
 
161
204
  include ItemBehaviour
162
205
 
163
- private
164
-
165
206
  def item
166
207
  Swa::Glue::JobBookmarkEntry.new(
167
- glue_client.get_job_bookmark(:job_name => name, :run_id => run_id).job_bookmark_entry
208
+ glue_client.get_job_bookmark(job_name: name, run_id: run_id).job_bookmark_entry
168
209
  )
169
210
  end
170
211
 
171
212
  end
172
213
 
173
- private
174
-
175
214
  def item
176
- Swa::Glue::JobRun.new(glue_client.get_job_run(:job_name => name, :run_id => run_id).job_run)
215
+ Swa::Glue::JobRun.new(glue_client.get_job_run(job_name: name, run_id: run_id).job_run)
177
216
  end
178
217
 
179
218
  end
@@ -182,10 +221,8 @@ module Swa
182
221
 
183
222
  include CollectionBehaviour
184
223
 
185
- private
186
-
187
224
  def collection
188
- query_for(:get_job_runs, :job_runs, Swa::Glue::JobRun, :job_name => name)
225
+ query_for(:get_job_runs, :job_runs, Swa::Glue::JobRun, job_name: name)
189
226
  end
190
227
 
191
228
  end
@@ -196,8 +233,6 @@ module Swa
196
233
 
197
234
  include CollectionBehaviour
198
235
 
199
- private
200
-
201
236
  def collection
202
237
  query_for(:get_jobs, :jobs, Swa::Glue::Job)
203
238
  end
@@ -214,7 +249,20 @@ module Swa
214
249
  model.list_from_query(glue_client, query_method, response_key, **query_args)
215
250
  end
216
251
 
252
+ def lf_client
253
+ ::Aws::LakeFormation::Client.new(aws_config)
254
+ end
255
+
256
+ def parse_parameters
257
+ case remaining_arguments.first
258
+ when /^(\w+)\.(\w+)$/
259
+ remaining_arguments[0, 1] = ["database", ::Regexp.last_match(1), "table", ::Regexp.last_match(2)]
260
+ end
261
+ super
262
+ end
263
+
217
264
  end
218
265
 
219
266
  end
267
+
220
268
  end