lsaws 0.2.0 → 0.3.0

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: fc348c9f2fd3c7a4f3159329804809b7800307aa42eedfdc01b17d9c8e220021
4
+ data.tar.gz: b558293f705f7df368d75aeb41a6bc133fd7bb3a366ddef2f790f99267c019c5
5
5
  SHA512:
6
- metadata.gz: df5f2f83c723a75be975af1c96e38b91e14661d920b62407817ee05a8cce33da9e6be2b59bce23bc0d5638f5bd6be821e2ea674df8991f6902233e22b5d3b2f2
7
- data.tar.gz: 7e07bfb922870d91b12cd8f94ef9ddb354817e921cb34e269cf6a4d85d3c84737fa69dd69eec104d18cffd6709a2a77767500613312d0caf0dde4430f6d9cef6
6
+ metadata.gz: 2c2a9d0c17689697c13aa3be30e05b6406a7d0031102342e3bddfcd56a486b73e23c57cdfcae8fa9653443e66fefb8b5d962c57abd044f103ecf26e85a69d7a4
7
+ data.tar.gz: 2dc1db342c3d646d9b5e7504b01cf2fdd9f83ad9e90298bde50f69eaf9b5adffce0405a0b8b86ea7890617fb484262780397a9ee08bb0e43a9a652d22d8672e8
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/lib/lsaws/lister.rb CHANGED
@@ -3,20 +3,20 @@
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
16
  end
17
17
 
18
18
  def _prepare_entities(sdk, type, &block)
19
- edef = CONFIG.dig(sdk, type)
19
+ edef = Lsaws.config.dig(sdk, type)
20
20
  return _prepare_entities(sdk, edef, &block) if edef.is_a?(String) # redirect like 'default' -> 'instances'
21
21
 
22
22
  edef ||= {}
@@ -33,7 +33,7 @@ module Lsaws
33
33
  sdkp = SDKParser.new(sdk)
34
34
  client_class = edef["client_class"] || sdkp.client_class_name
35
35
  client = Kernel.const_get(client_class).new
36
- method_name = edef["method"] || (client.respond_to?("describe_#{type}") ? "describe_#{type}" : "list_#{type}")
36
+ method_name = edef["method"] || sdkp.etype2method(type)
37
37
  unless client.respond_to?(method_name)
38
38
  if type == "default"
39
39
  warn "[!] no default entity type set for #{sdk.inspect} SDK"
@@ -44,27 +44,41 @@ module Lsaws
44
44
  list_entity_types(sdk)
45
45
  exit 1
46
46
  end
47
+ warn "[d] #{method_name} #{params}" if @options[:debug]
47
48
  results = client.send(method_name, params)
48
49
 
49
- pp results if @options[:debug]
50
+ warn "[d] #{File.basename(__FILE__)}:#{__LINE__} results:\n#{results.pretty_inspect}" if @options[:debug]
50
51
 
51
52
  if !edef["result_keys"] && results.any?
52
53
  r = results.first
53
54
  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
55
+ edef["result_keys"] =
56
+ if r.respond_to?(type)
57
+ [type]
58
+ elsif NEXT_PAGE_FIELDS.any? { |t| r.respond_to?(t) }
59
+ data_members = r.members - NEXT_PAGE_FIELDS
60
+ if data_members.size == 1
61
+ [data_members[0]]
62
+ else
63
+ # XXX what if there's more than one array?
64
+ [data_members.find { |key| r[key].is_a?(Array) }].compact
65
+ end
66
+ else
67
+ []
68
+ end
59
69
  end
70
+
60
71
  edef["result_keys"].each do |key|
61
72
  results = if results.is_a?(Array)
62
- results.map(&key.to_sym).flatten
73
+ results.map(&key.to_sym).flatten # TODO: is flatten necessary?
63
74
  else
64
- results.send(key)
75
+ results[key]
65
76
  end
66
77
  end
78
+
79
+ warn "[d] #{File.basename(__FILE__)}:#{__LINE__} results:\n#{results.pretty_inspect}" if @options[:debug]
67
80
  edef["cols"] = @options[:show_cols] if @options[:show_cols].any?
81
+ warn "[d] edef: #{edef}" if @options[:debug]
68
82
 
69
83
  col_defs = {}
70
84
  Array(edef["cols"]).each do |r|
@@ -77,10 +91,12 @@ module Lsaws
77
91
  raise Error, "unexpected #{r.inspect}"
78
92
  end
79
93
  end
94
+ # TODO: check with all types
80
95
  col_defs["tags"] = _convert_tags_proc if @options[:show_tags] || col_defs["tags"]
81
96
 
82
97
  results ||= []
83
- if results.any? && !results.first.respond_to?(:name)
98
+ warn "[d] #{results.inspect}" if @options[:debug]
99
+ if results.respond_to?(:any?) && results.any? && !results.first.respond_to?(:name) && results.first.respond_to?(:tags)
84
100
  results.first.class.class_eval do
85
101
  def name
86
102
  tags.find { |tag| tag.key == "Name" }&.value
@@ -88,9 +104,19 @@ module Lsaws
88
104
  end
89
105
  end
90
106
 
91
- # ec2 instance_event_notification_attributes
92
- # 'Array(results)' doesn't work here
93
- results = [results] unless results.is_a?(Array)
107
+ case results
108
+ when Hash
109
+ col_defs = {
110
+ key: :first,
111
+ value: :last
112
+ }
113
+ when Array
114
+ # ok
115
+ else
116
+ # ec2 instance_event_notification_attributes
117
+ # 'Array(results)' doesn't work here
118
+ results = [results]
119
+ end
94
120
 
95
121
  if block_given?
96
122
  results.map do |entity|
@@ -106,6 +132,9 @@ module Lsaws
106
132
  if rows.is_a?(Array) && rows[0].is_a?(String)
107
133
  # sqs
108
134
  cols = { value: proc { |entity| entity } }
135
+ elsif rows.is_a?(Array) && rows[0].is_a?(Hash)
136
+ # securitylake:log_sources
137
+ cols = { value: proc { |entity| entity } }
109
138
  elsif rows.respond_to?(:members)
110
139
  rows = [rows]
111
140
  end
@@ -168,12 +197,23 @@ module Lsaws
168
197
  _list_array SDKParser.new(sdk).entity_types
169
198
  end
170
199
 
200
+ # elasticache:global_replication_groups has 'members' as a column, so cannot just use `rows.members`
201
+ # assuming row is always subclass of Struct here
202
+ def _get_cols(row)
203
+ if row.is_a?(Struct)
204
+ Struct.instance_method(:members).bind_call(row)
205
+ else
206
+ row.members
207
+ end
208
+ end
209
+
171
210
  def _tabulo_guess_max_cols(rows, _cols)
172
- max_cols = rows[0].members.size
211
+ all_cols = _get_cols(rows[0])
212
+ max_cols = all_cols.size
173
213
  return max_cols if max_cols < 4 || !@options[:max_width]
174
214
 
175
215
  4.upto(max_cols) do |ncols|
176
- tbl = Tabulo::Table.new(rows[0, 100], *rows[0].members[0, ncols])
216
+ tbl = Tabulo::Table.new(rows[0, 100], *all_cols[0, ncols])
177
217
  tbl.autosize_columns
178
218
  tbl_width = tbl.column_registry.values.map { |c| c.padded_width + 1 }.inject(:+) + 1
179
219
  return ncols - 1 if tbl_width >= @options[:max_width]
@@ -187,7 +227,7 @@ module Lsaws
187
227
  elsif type == :list
188
228
  return list_entity_types(sdk)
189
229
  elsif type == :all
190
- get_entity_types(sdk).each do |etype|
230
+ SDKParser.new(sdk).entity_types.each do |etype|
191
231
  puts "#{etype}:"
192
232
  process_command(sdk, etype)
193
233
  end
@@ -208,7 +248,7 @@ module Lsaws
208
248
  cols.each { |name, func| tbl.add_column(name, &func) }
209
249
  else
210
250
  max_cols = _tabulo_guess_max_cols(rows, cols)
211
- rows[0].members[0, max_cols].each { |col| tbl.add_column(col) }
251
+ _get_cols(rows[0])[0, max_cols].each { |col| tbl.add_column(col) }
212
252
  end
213
253
  puts tbl.pack(max_table_width: @options[:max_width])
214
254
  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) }.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.0"
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.0
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-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk-core