awsutils 1.4.3

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.
@@ -0,0 +1,84 @@
1
+ require 'json'
2
+ require 'net/http'
3
+ # require 'aws-sdk' # see the comment on `image_details` below
4
+
5
+ module AwsUtils
6
+ class Ec2LatestImage
7
+ def releases
8
+ @releases ||= begin
9
+ resp = JSON.parse(
10
+ Net::HTTP.get(
11
+ URI('http://cloud-images.ubuntu.com/locator/ec2/releasesTable')
12
+ ).sub(/\],\n\]/, "]\n]")
13
+ )
14
+ parse_releases_array(resp['aaData']).select do |rel|
15
+ rel[:region] == 'us-east-1' &&
16
+ rel[:distro_version] == '14.04 LTS' &&
17
+ rel[:arch] == 'amd64'
18
+ end
19
+ end
20
+ end
21
+
22
+ def run
23
+ print_releases
24
+ end
25
+
26
+ private
27
+
28
+ def print_releases
29
+ # Print a header
30
+ printf("%-13s %-10s %-9s %-20s\n", 'ID', 'Version', 'Release', 'Type')
31
+
32
+ puts('-' * 53)
33
+
34
+ # Print the releases
35
+ releases.each do |rel|
36
+ printf(
37
+ "%-13s %-10s %-9s %-20s\n",
38
+ rel[:ami],
39
+ rel[:distro_version],
40
+ rel[:release],
41
+ rel[:type]
42
+ )
43
+ end
44
+ end
45
+
46
+ # def image_details
47
+ # This functionalty allows us to get more image details from the AWS API but
48
+ # it's not necessary for the library to work and right now we're not using it
49
+ # because it slows down loading time.
50
+ #
51
+ # @our_images ||= begin
52
+ # our_ami_ids = releases.map { |rel| rel[:ami] }
53
+ # images_details = connection.describe_images(image_ids: our_ami_ids).images
54
+
55
+ # images_details.each_with_object({}) { |ami, m| m[ami.image_id] = ami }
56
+ # end
57
+ # end
58
+
59
+ # rubocop:disable Metrics/MethodLength
60
+ def parse_releases_array(releases)
61
+ releases.map do |rel|
62
+ {
63
+ region: rel[0],
64
+ distro_name: rel[1],
65
+ distro_version: rel[2],
66
+ arch: rel[3],
67
+ type: rel[4],
68
+ release: rel[5],
69
+ ami: parse_ami_link(rel[6]),
70
+ aki: rel[7]
71
+ }
72
+ end
73
+ end
74
+ # rubocop:enable Metrics/MethodLength
75
+
76
+ def parse_ami_link(link)
77
+ link.match(/launchAmi=(ami-\w{8})/)[1]
78
+ end
79
+
80
+ def connection
81
+ @connection ||= Aws::EC2::Client.new
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,406 @@
1
+ require 'rubygems'
2
+ require 'trollop'
3
+ require 'fog'
4
+
5
+ gem 'fog', '>= 1.6.0'
6
+
7
+ class Array
8
+ def longest
9
+ length = 0
10
+ val = ''
11
+ each do |a|
12
+ len_new = a.length
13
+ if len_new > length
14
+ length = len_new
15
+ val = a
16
+ end
17
+ end
18
+ val
19
+ end
20
+ end
21
+
22
+ module AwsUtils
23
+ class Ec2ListMachines
24
+ def connect
25
+ @connect = Fog::Compute.new(provider: 'AWS')
26
+ if $DEBUG
27
+ puts 'Inspect connection result:'
28
+ puts connect.inspect
29
+ end
30
+
31
+ @connect
32
+ end
33
+
34
+ def get_servers(opts)
35
+ static_ips = []
36
+ connect.addresses.all.each do |eip|
37
+ static_ips << eip.public_ip
38
+ end
39
+
40
+ group_map = {}
41
+ connect.security_groups.map { |g| group_map[g.name] = g.group_id }
42
+
43
+ if opts[:search]
44
+ servers = connect.servers.select do |s|
45
+ s.tags['Name'] =~ /.*#{opts[:search]}.*/
46
+ end
47
+ else
48
+ servers = connect.servers
49
+ end
50
+
51
+ servers_a = []
52
+
53
+ servers.each do |s|
54
+ if (opts[:state].nil? || (s.state == opts[:state])) &&
55
+ (
56
+ (opts[:terminated] == true) ||
57
+ (s.state != 'terminated') ||
58
+ (opts[:state] == 'terminated')
59
+ ) &&
60
+ (opts[:flavor].nil? || (s.flavor_id == opts[:flavor])) &&
61
+ (opts[:role].nil? || (s.tags['Role'] == opts[:role])) &&
62
+ (opts[:zone].nil? || (s.availability_zone.to_s == opts[:zone]))
63
+
64
+ if s.public_ip_address.nil?
65
+ pub_ip = ''
66
+ else
67
+ pub_ip = s.public_ip_address
68
+
69
+ static_ip = static_ips.include?(pub_ip) ? '(S)' : '(D)'
70
+ end
71
+
72
+ role = s.tags['Role'] ? '-' : s.tags['Role']
73
+
74
+ if s.groups.first =~ /-/
75
+ group_to_insert = "#{group_map[s.groups.first]}/#{s.groups.first}"
76
+ else
77
+ group_to_insert = s.groups.first
78
+ end
79
+
80
+ created = s.tags['created_on'] ||= s.created_at
81
+
82
+ servers_a << {
83
+ name: s.tags['Name'].to_s,
84
+ date: created.to_s,
85
+ role: role.to_s,
86
+ az: s.availability_zone.to_s,
87
+ id: s.id,
88
+ group: group_to_insert,
89
+ pub_ip: pub_ip,
90
+ static_ip: static_ip,
91
+ flavor: s.flavor_id,
92
+ state: s.state
93
+ }
94
+
95
+ end
96
+ end
97
+
98
+ servers_a
99
+ end
100
+
101
+ def sort_servers(servers_a, sort_col)
102
+ case sort_col
103
+ when 'role'
104
+ servers_a.sort_by { |a| a[:role] }
105
+ when 'az'
106
+ servers_a.sort_by { |a| a[:az] }
107
+ when 'name'
108
+ servers_a.sort_by { |a| a[:name] }
109
+ when 'id'
110
+ servers_a.sort_by { |a| a[:id] }
111
+ when 'group'
112
+ servers_a.sort_by { |a| a[:group] }
113
+ when 'flavor'
114
+ servers_a.sort_by { |a| a[:flavor] }
115
+ when 'state'
116
+ servers_a.sort_by { |a| a[:state] }
117
+ when 'ip'
118
+ servers_a.sort_by { |a| a[:pub_ip] }
119
+ when 'static'
120
+ servers_a.sort_by { |a| a[:static_ip] }
121
+ when 'date'
122
+ servers_a.sort_by { |a| a[:date] }
123
+ else
124
+ servers_a.sort_by { |a| a[:name] }
125
+ end
126
+ end
127
+
128
+ def get_longest_server_name(servers_sorted)
129
+ server_names = []
130
+ servers_sorted.each do |server|
131
+ server_names << server[:name]
132
+ end
133
+
134
+ server_names.longest.length + 1
135
+ end
136
+
137
+ def print_headers(csv_opt, servers_sorted, longest_server_name, show_dates)
138
+ if csv_opt == true
139
+ if show_dates
140
+ printf(
141
+ "%s,%s,%s,%s,%s,%s,%s,%s,%s\n",
142
+ 'Name',
143
+ 'Created',
144
+ 'Role',
145
+ 'AZ',
146
+ 'ID',
147
+ 'Sec Group',
148
+ 'Public IP,(S/D)',
149
+ 'Flavor',
150
+ 'State'
151
+ )
152
+ else
153
+ printf(
154
+ "%s,%s,%s,%s,%s,%s,%s,%s\n",
155
+ 'Name',
156
+ 'Role',
157
+ 'AZ',
158
+ 'ID',
159
+ 'Sec Group',
160
+ 'Public IP,(S/D)',
161
+ 'Flavor',
162
+ 'State'
163
+ )
164
+ end
165
+ else
166
+ if show_dates
167
+ printf(
168
+ "\033[0;4m%-#{longest_server_name}s %-30s %-16s %-10s %-10s " \
169
+ "%-24s %-19s %-10s %-7s\033[0m\n",
170
+ 'Name',
171
+ 'Created',
172
+ 'Role',
173
+ 'AZ',
174
+ 'ID',
175
+ 'Sec Group',
176
+ 'Public IP (S/D)',
177
+ 'Flavor',
178
+ 'State'
179
+ )
180
+ else
181
+ printf(
182
+ "\033[0;4m%-#{longest_server_name}s %-16s %-10s %-10s %-24s " \
183
+ "%-19s %-10s %-7s\033[0m\n",
184
+ 'Name',
185
+ 'Role',
186
+ 'AZ',
187
+ 'ID',
188
+ 'Sec Group',
189
+ 'Public IP (S/D)',
190
+ 'Flavor',
191
+ 'State'
192
+ )
193
+ end
194
+ end
195
+ end
196
+
197
+ def get_flavor_color(flavor)
198
+ case flavor
199
+ when 't1.micro'
200
+ '1;33'
201
+ when 'm1.large'
202
+ '0;33'
203
+ when 'm1.xlarge'
204
+ '0;34'
205
+ when 'm2.2xlarge'
206
+ '0;35'
207
+ when 'm2.4xlarge'
208
+ '0;31'
209
+ when 'm2.xlarge'
210
+ '0;36'
211
+ else
212
+ '0'
213
+ end
214
+ end
215
+
216
+ def get_state_color(state)
217
+ case state
218
+ when 'running'
219
+ '1;32'
220
+ when 'stopped'
221
+ '1;31'
222
+ when 'starting'
223
+ '5;32'
224
+ when 'stopping'
225
+ '5;31'
226
+ else
227
+ '0'
228
+ end
229
+ end
230
+
231
+ def print_machine_list(servers_sorted, nocolor_opt, csv_opt, longest_server_name, show_dates)
232
+ servers_sorted.each do |server|
233
+ name = server[:name]
234
+ date = server[:date]
235
+ role = server[:role]
236
+ az = server[:az]
237
+ id = server[:id]
238
+ group = server[:group]
239
+ ip = server[:pub_ip]
240
+ static_ip = server[:static_ip]
241
+ flavor = server[:flavor]
242
+ state = server[:state]
243
+ fcolor = get_flavor_color(flavor)
244
+ scolor = get_state_color(state)
245
+
246
+ if (nocolor_opt == false) && (csv_opt == false)
247
+ if show_dates
248
+ printf(
249
+ "\033[1m%-#{longest_server_name}s\033[0m %-30s %-16s %-10s %-10s " \
250
+ "%-24s %-19s \033[#{fcolor}m%-11s\033[#{scolor}m%-7s\033[0m\n",
251
+ name,
252
+ date,
253
+ role,
254
+ az,
255
+ id,
256
+ group,
257
+ "#{ip} #{static_ip}",
258
+ flavor,
259
+ state
260
+ )
261
+ else
262
+ printf(
263
+ "\033[1m%-#{longest_server_name}s\033[0m %-16s %-10s %-10s " \
264
+ "%-24s %-19s \033[#{fcolor}m%-11s\033[#{scolor}m%-7s\033[0m\n",
265
+ name,
266
+ role,
267
+ az,
268
+ id,
269
+ group,
270
+ "#{ip} #{static_ip}",
271
+ flavor,
272
+ state
273
+ )
274
+ end
275
+ elsif csv_opt == true
276
+ if show_dates
277
+ printf(
278
+ "%s,%s,%s,%s,%s,%s,%s,%s,%s\n",
279
+ name,
280
+ date,
281
+ role,
282
+ az,
283
+ id,
284
+ group,
285
+ "#{ip},#{static_ip}",
286
+ flavor,
287
+ state
288
+ )
289
+ else
290
+ printf(
291
+ "%s,%s,%s,%s,%s,%s,%s,%s\n",
292
+ name,
293
+ role,
294
+ az,
295
+ id,
296
+ group,
297
+ "#{ip},#{static_ip}",
298
+ flavor,
299
+ state
300
+ )
301
+ end
302
+ else
303
+ if show_dates
304
+ printf(
305
+ "%-#{longest_server_name}s %-20s %-16s %-10s %-10s %-20s %-19s %-11s%-7s\n",
306
+ name,
307
+ date,
308
+ role,
309
+ az,
310
+ id,
311
+ group,
312
+ "#{ip} #{static_ip}",
313
+ flavor,
314
+ state
315
+ )
316
+ else
317
+ printf(
318
+ "%-#{longest_server_name}s %-16s %-10s %-10s %-20s %-19s %-11s%-7s\n",
319
+ name,
320
+ role,
321
+ az,
322
+ id,
323
+ group,
324
+ "#{ip} #{static_ip}",
325
+ flavor,
326
+ state
327
+ )
328
+ end
329
+ end
330
+ end
331
+ end
332
+
333
+ def print_counts(servers_sorted, opts_csv)
334
+ flavor_data = {}
335
+ connect.flavors.each do |f|
336
+ flavor_data[f.id] = {
337
+ 'cores' => f.cores,
338
+ 'disk' => f.disk,
339
+ 'ram' => f.ram
340
+ }
341
+ end
342
+ total_cores = 0
343
+ total_disk = 0.0
344
+ total_ram = 0.0
345
+
346
+ servers_sorted.each do |s|
347
+ total_cores += flavor_data[s[:flavor]]['cores']
348
+ total_disk += flavor_data[s[:flavor]]['disk'].to_f
349
+ total_ram += flavor_data[s[:flavor]]['ram'].to_f
350
+ end
351
+
352
+ if opts_csv
353
+ puts "total_instances,#{servers_sorted.count}"
354
+ puts "total_cores,#{total_cores}"
355
+ puts "total_disk,#{total_disk}"
356
+ puts "total_ram,#{total_ram}"
357
+ else
358
+ puts "\nTotals"
359
+ puts "\tInstances: #{servers_sorted.count}"
360
+ puts "\tCores: #{total_cores}"
361
+ printf("\tInstance storage: %.2f TB\n", total_disk / 1024)
362
+ printf("\tRAM: %.2f GB\n", total_ram / 1024)
363
+ end
364
+ end
365
+
366
+ def list_instances(opts)
367
+ servers = get_servers(opts)
368
+ servers_sorted = sort_servers(servers, opts[:sort])
369
+ longest_server_name = get_longest_server_name(servers_sorted)
370
+ print_headers(opts[:csv], servers_sorted, longest_server_name, opts[:dates])
371
+ print_machine_list(
372
+ servers_sorted,
373
+ opts[:nocolor],
374
+ opts[:csv],
375
+ longest_server_name,
376
+ opts[:dates]
377
+ )
378
+
379
+ print_counts(servers_sorted, opts[:csv])
380
+ end
381
+
382
+ def parse_opts
383
+ opts = Trollop.options do
384
+ opt :sort, 'Sort order', short: 's', type: String
385
+ opt :state, 'State', short: 'S', type: String
386
+ opt :flavor, 'Flavor', short: 'F', type: String
387
+ opt :role, 'Role', short: 'r', type: String
388
+ opt :zone, 'Availability Zone', short: 'Z', type: String
389
+ opt :csv, 'Output in CSV Format', short: 'C', default: false
390
+ opt :dates, 'Show creation timestamp', short: 'd', default: false
391
+ opt :terminated, 'Show terminated instances', short: 't', default: false
392
+ opt :nocolor, 'No color', short: 'c'
393
+ end
394
+
395
+ opts[:search] = ARGV[0] unless ARGV[0].empty?
396
+
397
+ opts
398
+ end
399
+
400
+ def initialize
401
+ list_instances(parse_opts)
402
+ rescue Interrupt
403
+ puts 'Interrupted by user (SIGINT, Ctrl+C, etc.)'
404
+ end
405
+ end
406
+ end