vmfloaty 0.11.0 → 0.11.1

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: 248dd5c9a8890b8990a7dad8dd7a21f52c8a8c2b65112c55449a5b5d3ac818af
4
- data.tar.gz: 22cf2070b571a0feded3967308e6b11d42b5ea296d94be7c434a73454611f6df
3
+ metadata.gz: 5ebdafe4b60af0f238330584cbe7ee1a3a5258b1671b7805d45551c16c69465a
4
+ data.tar.gz: '002138e04b43f670d76d7f0311dbb4770e2153306874a527f0e537c59dfafc9e'
5
5
  SHA512:
6
- metadata.gz: 8cd836baeb4a37720024616f1ce113046fc6291cc73694edbaf74ee727648c1339ada9e004ba0d630822a315948d69bb9e6c67da1ec04df3ae079bf207a432c7
7
- data.tar.gz: 46e15ff3d3d1cecd68cb92ed3fcd5d8240f68f45f704dff9fbf1e87007cae7b95b2d6f9d4b08753979b2c82fa6f412534a93e3bb17b96fb052003e821b31cf94
6
+ metadata.gz: 23e7ea9dbb546740ea16418f7a5e00d184df44634bf5dc9ff5421907a7fac55ff65d7d74516f1762a805cf865ff941b97e474e20db101029b176b89f1946d662
7
+ data.tar.gz: 7ffa31b013b4d332a6e19f56b56a6f55560dbc6a65702cf1b81be7317bc1b59b434af674f7f54ddb13f4dc611e96e27c947aa6c4679031f32b3475b49c1e5e40
@@ -87,6 +87,7 @@ class Vmfloaty
87
87
  c.option '--verbose', 'Enables verbose output'
88
88
  c.option '--service STRING', String, 'Configured pooler service name'
89
89
  c.option '--active', 'Prints information about active vms for a given token'
90
+ c.option '--json', 'Prints information as JSON'
90
91
  c.option '--token STRING', String, 'Token for pooler service'
91
92
  c.option '--url STRING', String, 'URL of pooler service'
92
93
  c.action do |args, options|
@@ -100,10 +101,18 @@ class Vmfloaty
100
101
  running_vms = service.list_active(verbose)
101
102
  host = URI.parse(service.url).host
102
103
  if running_vms.empty?
103
- puts "You have no running VMs on #{host}"
104
+ if options.json
105
+ puts {}.to_json
106
+ else
107
+ FloatyLogger.info "You have no running VMs on #{host}"
108
+ end
104
109
  else
105
- puts "Your VMs on #{host}:"
106
- Utils.pretty_print_hosts(verbose, service, running_vms)
110
+ if options.json
111
+ puts Utils.get_host_data(verbose, service, running_vms).to_json
112
+ else
113
+ puts "Your VMs on #{host}:"
114
+ Utils.pretty_print_hosts(verbose, service, running_vms)
115
+ end
107
116
  end
108
117
  else
109
118
  # list available vms from pooler
@@ -200,6 +209,7 @@ class Vmfloaty
200
209
  c.option '--service STRING', String, 'Configured pooler service name'
201
210
  c.option '--all', 'Deletes all vms acquired by a token'
202
211
  c.option '-f', 'Does not prompt user when deleting all vms'
212
+ c.option '--json', 'Outputs hosts scheduled for deletion as JSON'
203
213
  c.option '--token STRING', String, 'Token for pooler service'
204
214
  c.option '--url STRING', String, 'URL of pooler service'
205
215
  c.action do |args, options|
@@ -215,12 +225,18 @@ class Vmfloaty
215
225
  if delete_all
216
226
  running_vms = service.list_active(verbose)
217
227
  if running_vms.empty?
218
- puts 'You have no running VMs.'
228
+ if options.json
229
+ puts {}.to_json
230
+ else
231
+ FloatyLogger.info "You have no running VMs."
232
+ end
219
233
  else
220
- Utils.pretty_print_hosts(verbose, service, running_vms, true)
221
- # Confirm deletion
222
234
  confirmed = true
223
- confirmed = agree('Delete all these VMs? [y/N]') unless force
235
+ unless force
236
+ Utils.pretty_print_hosts(verbose, service, running_vms, true)
237
+ # Confirm deletion
238
+ confirmed = agree('Delete all these VMs? [y/N]')
239
+ end
224
240
  if confirmed
225
241
  response = service.delete(verbose, running_vms)
226
242
  response.each do |hostname, result|
@@ -257,9 +273,15 @@ class Vmfloaty
257
273
 
258
274
  unless successes.empty?
259
275
  FloatyLogger.info unless failures.empty?
260
- puts 'Scheduled the following VMs for deletion:'
261
- successes.each do |hostname|
262
- puts "- #{hostname}"
276
+ if options.json
277
+ puts successes.to_json
278
+ else
279
+ puts 'Scheduled the following VMs for deletion:'
280
+ output = ''
281
+ successes.each do |hostname|
282
+ output += "- #{hostname}\n"
283
+ end
284
+ puts output
263
285
  end
264
286
  end
265
287
 
@@ -229,10 +229,10 @@ class ABS
229
229
 
230
230
  retries = 360
231
231
 
232
- raise AuthError, "HTTP #{res.status}: The token provided could not authenticate to the pooler.\n#{res_body}" if res.status == 401
232
+ validate_queue_status_response(res.status, res.body, "Initial request", verbose)
233
233
 
234
234
  (1..retries).each do |i|
235
- queue_place, res_body = check_queue(conn, saved_job_id, req_obj)
235
+ queue_place, res_body = check_queue(conn, saved_job_id, req_obj, verbose)
236
236
  return translated(res_body) if res_body
237
237
 
238
238
  sleep_seconds = 10 if i >= 10
@@ -262,11 +262,12 @@ class ABS
262
262
  vmpooler_formatted_body
263
263
  end
264
264
 
265
- def self.check_queue(conn, job_id, req_obj)
265
+ def self.check_queue(conn, job_id, req_obj, verbose)
266
266
  queue_info_res = conn.get "status/queue/info/#{job_id}"
267
267
  queue_info = JSON.parse(queue_info_res.body)
268
268
 
269
269
  res = conn.post 'request', req_obj.to_json
270
+ validate_queue_status_response(res.status, res.body, "Check queue request", verbose)
270
271
 
271
272
  unless res.body.empty?
272
273
  res_body = JSON.parse(res.body)
@@ -315,4 +316,21 @@ class ABS
315
316
  def self.revert(_verbose, _url, _hostname, _token, _snapshot_sha)
316
317
  raise NoMethodError, 'revert is not defined for ABS'
317
318
  end
319
+
320
+ # Validate the http code returned during a queue status request.
321
+ #
322
+ # Return a success message that can be displayed if the status code is
323
+ # success, otherwise raise an error.
324
+ def self.validate_queue_status_response(status_code, body, request_name, verbose)
325
+ case status_code
326
+ when 200
327
+ "#{request_name} returned success (Code 200)" if verbose
328
+ when 202
329
+ "#{request_name} returned accepted, processing (Code 202)" if verbose
330
+ when 401
331
+ raise AuthError, "HTTP #{status_code}: The token provided could not authenticate.\n#{body}"
332
+ else
333
+ raise "HTTP #{status_code}: #{request_name} request to ABS failed!\n#{body}"
334
+ end
335
+ end
318
336
  end
@@ -22,7 +22,7 @@ class NonstandardPooler
22
22
  status['reserved_hosts'] || []
23
23
  end
24
24
 
25
- def self.retrieve(verbose, os_type, token, url, _user, _options)
25
+ def self.retrieve(verbose, os_type, token, url, _user, _options, ondemand = nil)
26
26
  conn = Http.get_conn(verbose, url)
27
27
  conn.headers['X-AUTH-TOKEN'] = token if token
28
28
 
@@ -79,40 +79,62 @@ class Utils
79
79
  end
80
80
 
81
81
  def self.pretty_print_hosts(verbose, service, hostnames = [], print_to_stderr = false)
82
+ fetched_data = self.get_host_data(verbose, service, hostnames)
83
+ fetched_data.each do |hostname, host_data|
84
+ case service.type
85
+ when 'ABS'
86
+ # For ABS, 'hostname' variable is the jobID
87
+ host_data['allocated_resources'].each do |vm_name, _i|
88
+ puts "- [JobID:#{host_data['request']['job']['id']}] #{vm_name['hostname']} (#{vm_name['type']}) <#{host_data['state']}>"
89
+ end
90
+ when 'Pooler'
91
+ tag_pairs = []
92
+ tag_pairs = host_data['tags'].map { |key, value| "#{key}: #{value}" } unless host_data['tags'].nil?
93
+ duration = "#{host_data['running']}/#{host_data['lifetime']} hours"
94
+ metadata = [host_data['template'], duration, *tag_pairs]
95
+ puts "- #{hostname}.#{host_data['domain']} (#{metadata.join(', ')})"
96
+ when 'NonstandardPooler'
97
+ line = "- #{host_data['fqdn']} (#{host_data['os_triple']}"
98
+ line += ", #{host_data['hours_left_on_reservation']}h remaining"
99
+ line += ", reason: #{host_data['reserved_for_reason']}" unless host_data['reserved_for_reason'].empty?
100
+ line += ')'
101
+ puts line
102
+ else
103
+ raise "Invalid service type #{service.type}"
104
+ end
105
+ end
106
+ end
107
+
108
+ def self.get_host_data(verbose, service, hostnames = [])
109
+ result = {}
82
110
  hostnames = [hostnames] unless hostnames.is_a? Array
83
111
  hostnames.each do |hostname|
84
112
  begin
85
113
  response = service.query(verbose, hostname)
86
114
  host_data = response[hostname]
87
-
88
- case service.type
89
- when 'ABS'
90
- # For ABS, 'hostname' variable is the jobID
91
- if host_data['state'] == 'allocated' || host_data['state'] == 'filled'
92
- host_data['allocated_resources'].each do |vm_name, _i|
93
- puts "- [JobID:#{host_data['request']['job']['id']}] #{vm_name['hostname']} (#{vm_name['type']}) <#{host_data['state']}>"
115
+ if block_given?
116
+ yield host_data result
117
+ else
118
+ case service.type
119
+ when 'ABS'
120
+ # For ABS, 'hostname' variable is the jobID
121
+ if host_data['state'] == 'allocated' || host_data['state'] == 'filled'
122
+ result[hostname] = host_data
94
123
  end
124
+ when 'Pooler'
125
+ result[hostname] = host_data
126
+ when 'NonstandardPooler'
127
+ result[hostname] = host_data
128
+ else
129
+ raise "Invalid service type #{service.type}"
95
130
  end
96
- when 'Pooler'
97
- tag_pairs = []
98
- tag_pairs = host_data['tags'].map { |key, value| "#{key}: #{value}" } unless host_data['tags'].nil?
99
- duration = "#{host_data['running']}/#{host_data['lifetime']} hours"
100
- metadata = [host_data['template'], duration, *tag_pairs]
101
- puts "- #{hostname}.#{host_data['domain']} (#{metadata.join(', ')})"
102
- when 'NonstandardPooler'
103
- line = "- #{host_data['fqdn']} (#{host_data['os_triple']}"
104
- line += ", #{host_data['hours_left_on_reservation']}h remaining"
105
- line += ", reason: #{host_data['reserved_for_reason']}" unless host_data['reserved_for_reason'].empty?
106
- line += ')'
107
- puts line
108
- else
109
- raise "Invalid service type #{service.type}"
110
131
  end
111
132
  rescue StandardError => e
112
133
  FloatyLogger.error("Something went wrong while trying to gather information on #{hostname}:")
113
134
  FloatyLogger.error(e)
114
135
  end
115
136
  end
137
+ result
116
138
  end
117
139
 
118
140
  def self.pretty_print_status(verbose, service)
@@ -206,6 +228,9 @@ class Utils
206
228
  # If the service is configured but some values are missing, use the top-level defaults to fill them in
207
229
  service_config.merge! config['services'][options.service]
208
230
  end
231
+ # No config file but service is declared on command line
232
+ elsif !config['services'] && options.service
233
+ service_config['type'] = options.service
209
234
  end
210
235
 
211
236
  # Prioritize an explicitly specified url, user, or token if the user provided one
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Vmfloaty
4
- VERSION = '0.11.0'
4
+ VERSION = '0.11.1'
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: vmfloaty
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.11.0
4
+ version: 0.11.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Cain
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2020-08-12 00:00:00.000000000 Z
12
+ date: 2020-08-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: colorize