lsaws 0.2.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: '09f8ec552161ab82ab45a5c57e50e7756b434974088dadd90e8417d97c317ecc'
4
- data.tar.gz: c77880939cc6058a9f8120e95f3df65392ddfe4105783fac7183277edd19c31a
3
+ metadata.gz: e2b87621670d3747c4c1b6cb9979c7401f7e736ceb8c257819a42dc31b190471
4
+ data.tar.gz: ab3227e58e62f14a718858242bd2cdd5ffd8f6a5f15acc38550605a01aea2352
5
5
  SHA512:
6
- metadata.gz: df5f2f83c723a75be975af1c96e38b91e14661d920b62407817ee05a8cce33da9e6be2b59bce23bc0d5638f5bd6be821e2ea674df8991f6902233e22b5d3b2f2
7
- data.tar.gz: 7e07bfb922870d91b12cd8f94ef9ddb354817e921cb34e269cf6a4d85d3c84737fa69dd69eec104d18cffd6709a2a77767500613312d0caf0dde4430f6d9cef6
6
+ metadata.gz: 4eeb107b1267e40dadb27fccb5dc619f53807410c68c3b85cda9c5e63e3c57da9ab731b422f1c236a0b3bc7a2701e4bffee989257676a9e3cff20cfc9ce2b07c
7
+ data.tar.gz: a725ba9efec0bf251516ca30a8841dac825ca3dacaf2adf00dcef453f2806e22d946512a6b4f6e70bb6f72547f2204e474065f623f86bc258e0a48624c8e9aef
data/Gemfile CHANGED
@@ -8,8 +8,8 @@ gemspec
8
8
  group :development, :test do
9
9
  gem "activesupport", "~> 7.0"
10
10
  gem "aws-sdk"
11
+ gem "pry"
11
12
  gem "rake", "~> 13.0"
12
13
  gem "rspec", "~> 3.0"
13
14
  gem "rubocop", "~> 1.21"
14
- gem "debug"
15
15
  end
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- lsaws (0.1.0)
4
+ lsaws (0.3.0)
5
5
  aws-sdk-core (~> 3.131)
6
6
  tabulo (~> 2.8)
7
7
 
@@ -1379,27 +1379,24 @@ GEM
1379
1379
  aws-sigv2 (1.1.0)
1380
1380
  aws-sigv4 (1.5.2)
1381
1381
  aws-eventstream (~> 1, >= 1.0.2)
1382
+ coderay (1.1.3)
1382
1383
  concurrent-ruby (1.2.0)
1383
- debug (1.7.1)
1384
- irb (>= 1.5.0)
1385
- reline (>= 0.3.1)
1386
1384
  diff-lcs (1.5.0)
1387
1385
  i18n (1.12.0)
1388
1386
  concurrent-ruby (~> 1.0)
1389
- io-console (0.6.0)
1390
- irb (1.6.2)
1391
- reline (>= 0.3.0)
1392
1387
  jmespath (1.6.2)
1393
1388
  json (2.6.3)
1389
+ method_source (1.0.0)
1394
1390
  minitest (5.17.0)
1395
1391
  parallel (1.22.1)
1396
1392
  parser (3.2.0.0)
1397
1393
  ast (~> 2.4.1)
1394
+ pry (0.14.2)
1395
+ coderay (~> 1.1)
1396
+ method_source (~> 1.0)
1398
1397
  rainbow (3.1.1)
1399
1398
  rake (13.0.6)
1400
1399
  regexp_parser (2.6.2)
1401
- reline (0.3.2)
1402
- io-console (~> 0.5)
1403
1400
  rexml (3.2.5)
1404
1401
  rspec (3.12.0)
1405
1402
  rspec-core (~> 3.12.0)
@@ -1441,8 +1438,8 @@ PLATFORMS
1441
1438
  DEPENDENCIES
1442
1439
  activesupport (~> 7.0)
1443
1440
  aws-sdk
1444
- debug
1445
1441
  lsaws!
1442
+ pry
1446
1443
  rake (~> 13.0)
1447
1444
  rspec (~> 3.0)
1448
1445
  rubocop (~> 1.21)
data/README.md CHANGED
@@ -23,6 +23,88 @@ User-friendly AWS resources listing tool
23
23
  -A, --all List all entity types within SDK
24
24
 
25
25
 
26
+ ### Listing installed SDKs
27
+
28
+ # lsaws -L
29
+
30
+ accessanalyzer
31
+ account
32
+ acm
33
+ acmpca
34
+ alexaforbusiness
35
+ amplify
36
+ amplifybackend
37
+ amplifyuibuilder
38
+ apigateway
39
+ apigatewaymanagementapi
40
+ apigatewayv2
41
+ appconfig
42
+ appconfigdata
43
+ appflow
44
+ appintegrationsservice
45
+ applicationautoscaling
46
+ applicationcostprofiler
47
+ applicationdiscoveryservice
48
+ applicationinsights
49
+ appmesh
50
+ appregistry
51
+ apprunner
52
+ appstream
53
+ appsync
54
+ arczonalshift
55
+ ...
56
+
57
+
58
+ ### Listing listable entities from EC2 sdk
59
+
60
+ # lsaws ec2 -L
61
+
62
+ account_attributes
63
+ address_transfers
64
+ addresses
65
+ availability_zones
66
+ aws_network_performance_metric_subscriptions
67
+ bundle_tasks
68
+ capacity_reservation_fleets
69
+ capacity_reservations
70
+ carrier_gateways
71
+ classic_link_instances
72
+ client_vpn_endpoints
73
+ coip_pools
74
+ conversion_tasks
75
+ customer_gateways
76
+ dhcp_options
77
+ egress_only_internet_gateways
78
+ elastic_gpus
79
+ export_image_tasks
80
+ export_tasks
81
+ fast_launch_images
82
+ fast_snapshot_restores
83
+ fleets
84
+ flow_logs
85
+ fpga_images
86
+ host_reservation_offerings
87
+ ...
88
+
89
+
90
+ ### Listing EC2 instances
91
+
92
+ # lsaws ec2
93
+
94
+ ┌─────────────────────┬─────────────┬───────────────────────┬────────────────────┬─────────────────────────┐
95
+ │ instance_id │ name │ vpc_id │ private_ip_address │ launch_time │
96
+ ├─────────────────────┼─────────────┼───────────────────────┼────────────────────┼─────────────────────────┤
97
+ │ i-1234567890abcdef0 │ my-instance │ vpc-1234567890abcdef0 │ 10-0-0-157 │ 2022-11-15 10:48:59 UTC │
98
+ └─────────────────────┴─────────────┴───────────────────────┴────────────────────┴─────────────────────────┘
99
+
100
+ ### Listing specific columns of EC2 images as json-stream
101
+
102
+ # lsaws ec2 images -c image_id,creation_date -o js
103
+
104
+ {"image_id":"ami-1234e6197567838b4","creation_date":"2023-01-11T13:02:00.000Z"}
105
+ {"image_id":"ami-1234f58a167898416","creation_date":"2023-01-11T02:02:00.000Z"}
106
+ {"image_id":"ami-12341a1fd567897a8","creation_date":"2023-01-01T01:02:00.000Z"}
107
+
26
108
  ## License
27
109
 
28
110
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/README.md.tpl CHANGED
@@ -6,6 +6,32 @@ User-friendly AWS resources listing tool
6
6
 
7
7
  % lsaws
8
8
 
9
+ ### Listing installed SDKs
10
+
11
+ % lsaws -L
12
+
13
+ ### Listing listable entities from EC2 sdk
14
+
15
+ % lsaws ec2 -L
16
+
17
+ ### Listing EC2 instances
18
+
19
+ # lsaws ec2
20
+
21
+ ┌─────────────────────┬─────────────┬───────────────────────┬────────────────────┬─────────────────────────┐
22
+ │ instance_id │ name │ vpc_id │ private_ip_address │ launch_time │
23
+ ├─────────────────────┼─────────────┼───────────────────────┼────────────────────┼─────────────────────────┤
24
+ │ i-1234567890abcdef0 │ my-instance │ vpc-1234567890abcdef0 │ 10-0-0-157 │ 2022-11-15 10:48:59 UTC │
25
+ └─────────────────────┴─────────────┴───────────────────────┴────────────────────┴─────────────────────────┘
26
+
27
+ ### Listing specific columns of EC2 images as json-stream
28
+
29
+ # lsaws ec2 images -c image_id,creation_date -o js
30
+
31
+ {"image_id":"ami-0245e6197bf3138b4","creation_date":"2023-01-19T12:03:38.000Z"}
32
+ {"image_id":"ami-0bc3f58a172118416","creation_date":"2023-01-20T09:37:32.000Z"}
33
+ {"image_id":"ami-07e71a1fdf49957a8","creation_date":"2023-02-01T02:06:29.000Z"}
34
+
9
35
  ## License
10
36
 
11
37
  The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/lib/lsaws/lister.rb CHANGED
@@ -3,20 +3,31 @@
3
3
  require "aws-sdk-core"
4
4
  require "json"
5
5
  require "tabulo"
6
- require "yaml"
7
6
 
8
7
  module Lsaws
9
8
  class Lister
10
- CONFIG = YAML.load_file(File.join(Lsaws.root, "lsaws.yml"))
11
-
12
9
  include Utils
13
10
 
11
+ NEXT_PAGE_FIELDS = %i[next_token next_marker next_page_token page_token].freeze
12
+
14
13
  def initialize(options)
15
14
  @options = options
15
+ @options[:max_width] = nil if @options[:max_width].to_i.zero?
16
+ end
17
+
18
+ def _abort_with_list(sdk, type)
19
+ if type == "default"
20
+ warn "[!] no default entity type set for #{sdk.inspect} SDK"
21
+ else
22
+ warn "[!] #{sdk.inspect} SDK does not have #{type.inspect} entity type"
23
+ end
24
+ puts "Known entity types are:"
25
+ list_entity_types(sdk)
26
+ exit 1
16
27
  end
17
28
 
18
29
  def _prepare_entities(sdk, type, &block)
19
- edef = CONFIG.dig(sdk, type)
30
+ edef = Lsaws.config.dig(sdk, type)
20
31
  return _prepare_entities(sdk, edef, &block) if edef.is_a?(String) # redirect like 'default' -> 'instances'
21
32
 
22
33
  edef ||= {}
@@ -33,38 +44,43 @@ module Lsaws
33
44
  sdkp = SDKParser.new(sdk)
34
45
  client_class = edef["client_class"] || sdkp.client_class_name
35
46
  client = Kernel.const_get(client_class).new
36
- method_name = edef["method"] || (client.respond_to?("describe_#{type}") ? "describe_#{type}" : "list_#{type}")
37
- unless client.respond_to?(method_name)
38
- if type == "default"
39
- warn "[!] no default entity type set for #{sdk.inspect} SDK"
40
- else
41
- warn "[!] #{sdk.inspect} SDK does not have #{type.inspect} entity type"
42
- end
43
- puts "Known entity types are:"
44
- list_entity_types(sdk)
45
- exit 1
46
- end
47
+ method_name = edef["method"] || sdkp.etype2method(type)
48
+ _abort_with_list(sdk, type) unless method_name
49
+ warn "[d] #{method_name} #{params}" if @options[:debug]
47
50
  results = client.send(method_name, params)
48
51
 
49
- pp results if @options[:debug]
52
+ warn "[d] #{File.basename(__FILE__)}:#{__LINE__} results:\n#{results.pretty_inspect}" if @options[:debug]
50
53
 
51
54
  if !edef["result_keys"] && results.any?
52
55
  r = results.first
53
56
  r = r.last if r.is_a?(Array)
54
- edef["result_keys"] = if r.respond_to?(type)
55
- [type]
56
- else
57
- [(r.members - [:next_token]).first]
58
- end
57
+ edef["result_keys"] =
58
+ if r.respond_to?(type)
59
+ [type]
60
+ elsif NEXT_PAGE_FIELDS.any? { |t| r.respond_to?(t) }
61
+ data_members = r.members - NEXT_PAGE_FIELDS
62
+ if data_members.size == 1
63
+ [data_members[0]]
64
+ else
65
+ # XXX what if there's more than one array?
66
+ [data_members.find { |key| r[key].is_a?(Array) }].compact
67
+ end
68
+ else
69
+ []
70
+ end
59
71
  end
72
+
60
73
  edef["result_keys"].each do |key|
61
74
  results = if results.is_a?(Array)
62
- results.map(&key.to_sym).flatten
75
+ results.map(&key.to_sym).flatten # TODO: is flatten necessary?
63
76
  else
64
- results.send(key)
77
+ results[key]
65
78
  end
66
79
  end
80
+
81
+ warn "[d] #{File.basename(__FILE__)}:#{__LINE__} results:\n#{results.pretty_inspect}" if @options[:debug]
67
82
  edef["cols"] = @options[:show_cols] if @options[:show_cols].any?
83
+ warn "[d] edef: #{edef}" if @options[:debug]
68
84
 
69
85
  col_defs = {}
70
86
  Array(edef["cols"]).each do |r|
@@ -77,10 +93,12 @@ module Lsaws
77
93
  raise Error, "unexpected #{r.inspect}"
78
94
  end
79
95
  end
96
+ # TODO: check with all types
80
97
  col_defs["tags"] = _convert_tags_proc if @options[:show_tags] || col_defs["tags"]
81
98
 
82
99
  results ||= []
83
- if results.any? && !results.first.respond_to?(:name)
100
+ warn "[d] #{results.inspect}" if @options[:debug]
101
+ if results.respond_to?(:any?) && results.any? && !results.first.respond_to?(:name) && results.first.respond_to?(:tags)
84
102
  results.first.class.class_eval do
85
103
  def name
86
104
  tags.find { |tag| tag.key == "Name" }&.value
@@ -88,9 +106,19 @@ module Lsaws
88
106
  end
89
107
  end
90
108
 
91
- # ec2 instance_event_notification_attributes
92
- # 'Array(results)' doesn't work here
93
- results = [results] unless results.is_a?(Array)
109
+ case results
110
+ when Hash
111
+ col_defs = {
112
+ key: :first,
113
+ value: :last
114
+ }
115
+ when Array
116
+ # ok
117
+ else
118
+ # ec2 instance_event_notification_attributes
119
+ # 'Array(results)' doesn't work here
120
+ results = [results]
121
+ end
94
122
 
95
123
  if block_given?
96
124
  results.map do |entity|
@@ -106,6 +134,9 @@ module Lsaws
106
134
  if rows.is_a?(Array) && rows[0].is_a?(String)
107
135
  # sqs
108
136
  cols = { value: proc { |entity| entity } }
137
+ elsif rows.is_a?(Array) && rows[0].is_a?(Hash)
138
+ # securitylake:log_sources
139
+ cols = { value: proc { |entity| entity } }
109
140
  elsif rows.respond_to?(:members)
110
141
  rows = [rows]
111
142
  end
@@ -168,12 +199,23 @@ module Lsaws
168
199
  _list_array SDKParser.new(sdk).entity_types
169
200
  end
170
201
 
202
+ # elasticache:global_replication_groups has 'members' as a column, so cannot just use `rows.members`
203
+ # assuming row is always subclass of Struct here
204
+ def _get_cols(row)
205
+ if row.is_a?(Struct)
206
+ Struct.instance_method(:members).bind_call(row)
207
+ else
208
+ row.members
209
+ end
210
+ end
211
+
171
212
  def _tabulo_guess_max_cols(rows, _cols)
172
- max_cols = rows[0].members.size
213
+ all_cols = _get_cols(rows[0])
214
+ max_cols = all_cols.size
173
215
  return max_cols if max_cols < 4 || !@options[:max_width]
174
216
 
175
217
  4.upto(max_cols) do |ncols|
176
- tbl = Tabulo::Table.new(rows[0, 100], *rows[0].members[0, ncols])
218
+ tbl = Tabulo::Table.new(rows[0, 100], *all_cols[0, ncols])
177
219
  tbl.autosize_columns
178
220
  tbl_width = tbl.column_registry.values.map { |c| c.padded_width + 1 }.inject(:+) + 1
179
221
  return ncols - 1 if tbl_width >= @options[:max_width]
@@ -187,7 +229,7 @@ module Lsaws
187
229
  elsif type == :list
188
230
  return list_entity_types(sdk)
189
231
  elsif type == :all
190
- get_entity_types(sdk).each do |etype|
232
+ SDKParser.new(sdk).entity_types.each do |etype|
191
233
  puts "#{etype}:"
192
234
  process_command(sdk, etype)
193
235
  end
@@ -208,7 +250,7 @@ module Lsaws
208
250
  cols.each { |name, func| tbl.add_column(name, &func) }
209
251
  else
210
252
  max_cols = _tabulo_guess_max_cols(rows, cols)
211
- rows[0].members[0, max_cols].each { |col| tbl.add_column(col) }
253
+ _get_cols(rows[0])[0, max_cols].each { |col| tbl.add_column(col) }
212
254
  end
213
255
  puts tbl.pack(max_table_width: @options[:max_width])
214
256
  when :json
@@ -2,6 +2,11 @@
2
2
 
3
3
  module Lsaws
4
4
  class SDKParser
5
+ IGNORED_SDKS = [
6
+ "core", "resources", # do not contain any resource listing methods
7
+ "s3control" # requires account_id param for all requests
8
+ ].freeze
9
+
5
10
  def self.get_sdks
6
11
  r = []
7
12
  Gem.path.each do |p|
@@ -12,7 +17,7 @@ module Lsaws
12
17
  a.size == 4 ? a[2] : nil
13
18
  end)
14
19
  end
15
- r.compact.uniq.sort - ["core"]
20
+ r.compact.uniq.sort - IGNORED_SDKS
16
21
  end
17
22
 
18
23
  def initialize(sdk)
@@ -23,6 +28,7 @@ module Lsaws
23
28
  def client_class_name
24
29
  @client_class_name ||=
25
30
  begin
31
+ # TODO: use constants from gems/aws-sdk-resources-x.xxx
26
32
  c = Aws.constants.find { |x| x.to_s.downcase == @sdk }
27
33
  "Aws::#{c}::Client"
28
34
  end
@@ -32,10 +38,25 @@ module Lsaws
32
38
  @client_class ||= Kernel.const_get(client_class_name)
33
39
  end
34
40
 
41
+ # order is important!
42
+ LIST_METHOD_PREFIXES = %w[list describe get].freeze
43
+
44
+ def etype2method(etype)
45
+ LIST_METHOD_PREFIXES.each do |prefix|
46
+ m = "#{prefix}_#{etype}"
47
+ return m if client_class.public_method_defined?(m)
48
+ end
49
+ nil
50
+ end
51
+
52
+ def method2etype(method)
53
+ method.to_s.sub(/^(?:#{LIST_METHOD_PREFIXES.join("|")})_/, "")
54
+ end
55
+
35
56
  def entity_types
36
57
  methods = client_class
37
58
  .instance_methods
38
- .find_all { |m| m =~ /^(describe|list)_.+s$/ && m !~ /(status|access)$/ }
59
+ .find_all { |m| m =~ /^(?:#{LIST_METHOD_PREFIXES.join("|")})_.+s$/ && m !~ /(?:status|access)$/ }
39
60
 
40
61
  return [] if methods.empty?
41
62
 
@@ -44,10 +65,10 @@ module Lsaws
44
65
  next(true) unless rdoc
45
66
 
46
67
  required_params = rdoc.scan(/^\s+# @option params \[required, (.+?)\] :(\w+)/)
47
- required_params.any?
68
+ required_params.any? || Lsaws.config.dig(@sdk, method2etype(m), "required_params")
48
69
  end
49
70
 
50
- methods.map { |m| m.to_s.sub(/^(describe|list)_/, "") }.sort
71
+ methods.map { |m| method2etype(m) }.uniq.sort
51
72
  end
52
73
 
53
74
  def get_method_rdoc(method)
@@ -64,5 +85,10 @@ module Lsaws
64
85
  end
65
86
  chunk[chunk.rindex("\n\n") + 2..]
66
87
  end
88
+
89
+ def get_method_api(method)
90
+ # calling private API!
91
+ client_class.api.operation(method)
92
+ end
67
93
  end
68
94
  end
data/lib/lsaws/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Lsaws
4
- VERSION = "0.2.0"
4
+ VERSION = "0.3.1"
5
5
  end
data/lib/lsaws.rb CHANGED
@@ -1,11 +1,17 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "yaml"
4
+
3
5
  module Lsaws
4
6
  class Error < StandardError; end
5
7
 
6
8
  def self.root
7
9
  File.dirname(File.dirname(File.expand_path(__FILE__)))
8
10
  end
11
+
12
+ def self.config
13
+ @config ||= YAML.load_file(File.join(Lsaws.root, "lsaws.yml"))
14
+ end
9
15
  end
10
16
 
11
17
  require_relative "lsaws/version"
data/lsaws.yml CHANGED
@@ -1,3 +1,8 @@
1
+ cloudformation:
2
+ stack_resources:
3
+ required_params:
4
+ - [ stack_name ]
5
+ - [ physical_resource_id ]
1
6
  ec2:
2
7
  default: instances
3
8
  images:
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lsaws
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrey "Zed" Zaikin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2023-02-10 00:00:00.000000000 Z
11
+ date: 2023-02-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-core