vmfloaty 0.9.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 +4 -4
- data/README.md +83 -47
- data/lib/vmfloaty.rb +64 -35
- data/lib/vmfloaty/abs.rb +56 -13
- data/lib/vmfloaty/conf.rb +1 -1
- data/lib/vmfloaty/logger.rb +27 -0
- data/lib/vmfloaty/nonstandard_pooler.rb +2 -2
- data/lib/vmfloaty/pooler.rb +34 -4
- data/lib/vmfloaty/service.rb +12 -17
- data/lib/vmfloaty/ssh.rb +11 -5
- data/lib/vmfloaty/utils.rb +54 -28
- data/lib/vmfloaty/version.rb +1 -1
- data/spec/spec_helper.rb +11 -0
- data/spec/vmfloaty/abs_spec.rb +32 -2
- data/spec/vmfloaty/nonstandard_pooler_spec.rb +2 -2
- data/spec/vmfloaty/pooler_spec.rb +22 -2
- data/spec/vmfloaty/ssh_spec.rb +49 -0
- data/spec/vmfloaty/utils_spec.rb +4 -4
- data/spec/vmfloaty/vmfloaty_services_spec.rb +39 -0
- metadata +27 -15
data/lib/vmfloaty/abs.rb
CHANGED
@@ -68,7 +68,7 @@ class ABS
|
|
68
68
|
|
69
69
|
ret_val.push(req_hash)
|
70
70
|
rescue NoMethodError
|
71
|
-
|
71
|
+
FloatyLogger.warn "Warning: couldn't parse line returned from abs/status/queue: "
|
72
72
|
end
|
73
73
|
end
|
74
74
|
|
@@ -85,7 +85,7 @@ class ABS
|
|
85
85
|
conn = Http.get_conn(verbose, url)
|
86
86
|
conn.headers['X-AUTH-TOKEN'] = token if token
|
87
87
|
|
88
|
-
|
88
|
+
FloatyLogger.info "Trying to delete hosts #{hosts}" if verbose
|
89
89
|
requests = get_active_requests(verbose, url, user)
|
90
90
|
|
91
91
|
jobs_to_delete = []
|
@@ -100,6 +100,11 @@ class ABS
|
|
100
100
|
requests.each do |req_hash|
|
101
101
|
next unless req_hash['state'] == 'allocated' || req_hash['state'] == 'filled'
|
102
102
|
|
103
|
+
if hosts.include? req_hash['request']['job']['id']
|
104
|
+
jobs_to_delete.push(req_hash)
|
105
|
+
next
|
106
|
+
end
|
107
|
+
|
103
108
|
req_hash['allocated_resources'].each do |vm_name, _i|
|
104
109
|
if hosts.include? vm_name['hostname']
|
105
110
|
if all_job_resources_accounted_for(req_hash['allocated_resources'], hosts)
|
@@ -108,7 +113,7 @@ class ABS
|
|
108
113
|
}
|
109
114
|
jobs_to_delete.push(req_hash)
|
110
115
|
else
|
111
|
-
|
116
|
+
FloatyLogger.info "When using ABS you must delete all vms that you requested at the same time: Can't delete #{req_hash['request']['job']['id']}: #{hosts} does not include all of #{req_hash['allocated_resources']}"
|
112
117
|
end
|
113
118
|
end
|
114
119
|
end
|
@@ -122,7 +127,7 @@ class ABS
|
|
122
127
|
'hosts' => job['allocated_resources'],
|
123
128
|
}
|
124
129
|
|
125
|
-
|
130
|
+
FloatyLogger.info "Deleting #{req_obj}" if verbose
|
126
131
|
|
127
132
|
return_result = conn.post 'return', req_obj.to_json
|
128
133
|
req_obj['hosts'].each do |host|
|
@@ -145,6 +150,14 @@ class ABS
|
|
145
150
|
os_list << '*** VMPOOLER Pools ***'
|
146
151
|
os_list += JSON.parse(res_body['vmpooler_platforms'])
|
147
152
|
|
153
|
+
res = conn.get 'status/platforms/ondemand_vmpooler'
|
154
|
+
res_body = JSON.parse(res.body)
|
155
|
+
unless res_body['ondemand_vmpooler_platforms'] == '[]'
|
156
|
+
os_list << ''
|
157
|
+
os_list << '*** VMPOOLER ONDEMAND Pools ***'
|
158
|
+
os_list += JSON.parse(res_body['ondemand_vmpooler_platforms'])
|
159
|
+
end
|
160
|
+
|
148
161
|
res = conn.get 'status/platforms/nspooler'
|
149
162
|
res_body = JSON.parse(res.body)
|
150
163
|
os_list << ''
|
@@ -163,7 +176,7 @@ class ABS
|
|
163
176
|
end
|
164
177
|
|
165
178
|
# Retrieve an OS from ABS.
|
166
|
-
def self.retrieve(verbose, os_types, token, url, user, options)
|
179
|
+
def self.retrieve(verbose, os_types, token, url, user, options, _ondemand = nil)
|
167
180
|
#
|
168
181
|
# Contents of post must be like:
|
169
182
|
#
|
@@ -207,24 +220,24 @@ class ABS
|
|
207
220
|
end
|
208
221
|
end
|
209
222
|
|
210
|
-
|
223
|
+
FloatyLogger.info "Posting to ABS #{req_obj.to_json}" if verbose
|
211
224
|
|
212
225
|
# os_string = os_type.map { |os, num| Array(os) * num }.flatten.join('+')
|
213
226
|
# raise MissingParamError, 'No operating systems provided to obtain.' if os_string.empty?
|
214
|
-
|
227
|
+
FloatyLogger.info "Requesting VMs with job_id: #{saved_job_id}. Will retry for up to an hour."
|
215
228
|
res = conn.post 'request', req_obj.to_json
|
216
229
|
|
217
230
|
retries = 360
|
218
231
|
|
219
|
-
|
232
|
+
validate_queue_status_response(res.status, res.body, "Initial request", verbose)
|
220
233
|
|
221
234
|
(1..retries).each do |i|
|
222
|
-
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)
|
223
236
|
return translated(res_body) if res_body
|
224
237
|
|
225
238
|
sleep_seconds = 10 if i >= 10
|
226
239
|
sleep_seconds = i if i < 10
|
227
|
-
|
240
|
+
FloatyLogger.info "Waiting #{sleep_seconds} seconds to check if ABS request has been filled. Queue Position: #{queue_place}... (x#{i})"
|
228
241
|
|
229
242
|
sleep(sleep_seconds)
|
230
243
|
end
|
@@ -249,11 +262,12 @@ class ABS
|
|
249
262
|
vmpooler_formatted_body
|
250
263
|
end
|
251
264
|
|
252
|
-
def self.check_queue(conn, job_id, req_obj)
|
265
|
+
def self.check_queue(conn, job_id, req_obj, verbose)
|
253
266
|
queue_info_res = conn.get "status/queue/info/#{job_id}"
|
254
267
|
queue_info = JSON.parse(queue_info_res.body)
|
255
268
|
|
256
269
|
res = conn.post 'request', req_obj.to_json
|
270
|
+
validate_queue_status_response(res.status, res.body, "Check queue request", verbose)
|
257
271
|
|
258
272
|
unless res.body.empty?
|
259
273
|
res_body = JSON.parse(res.body)
|
@@ -263,7 +277,7 @@ class ABS
|
|
263
277
|
end
|
264
278
|
|
265
279
|
def self.snapshot(_verbose, _url, _hostname, _token)
|
266
|
-
|
280
|
+
FloatyLogger.info "Can't snapshot with ABS, use '--service vmpooler' (even for vms checked out with ABS)"
|
267
281
|
end
|
268
282
|
|
269
283
|
def self.status(verbose, url)
|
@@ -284,10 +298,39 @@ class ABS
|
|
284
298
|
def self.query(verbose, url, hostname)
|
285
299
|
return @active_hostnames if @active_hostnames
|
286
300
|
|
287
|
-
|
301
|
+
FloatyLogger.info "For vmpooler/snapshot information, use '--service vmpooler' (even for vms checked out with ABS)"
|
288
302
|
conn = Http.get_conn(verbose, url)
|
289
303
|
|
290
304
|
res = conn.get "host/#{hostname}"
|
291
305
|
JSON.parse(res.body)
|
292
306
|
end
|
307
|
+
|
308
|
+
def self.modify(_verbose, _url, _hostname, _token, _modify_hash)
|
309
|
+
raise NoMethodError, 'modify is not defined for ABS'
|
310
|
+
end
|
311
|
+
|
312
|
+
def self.disk(_verbose, _url, _hostname, _token, _disk)
|
313
|
+
raise NoMethodError, 'disk is not defined for ABS'
|
314
|
+
end
|
315
|
+
|
316
|
+
def self.revert(_verbose, _url, _hostname, _token, _snapshot_sha)
|
317
|
+
raise NoMethodError, 'revert is not defined for ABS'
|
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
|
293
336
|
end
|
data/lib/vmfloaty/conf.rb
CHANGED
@@ -8,7 +8,7 @@ class Conf
|
|
8
8
|
begin
|
9
9
|
conf = YAML.load_file("#{Dir.home}/.vmfloaty.yml")
|
10
10
|
rescue StandardError
|
11
|
-
|
11
|
+
FloatyLogger.warn "WARNING: There was no config file at #{Dir.home}/.vmfloaty.yml"
|
12
12
|
end
|
13
13
|
conf
|
14
14
|
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
class FloatyLogger < ::Logger
|
4
|
+
def self.logger
|
5
|
+
@@logger ||= FloatyLogger.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.info(msg)
|
9
|
+
FloatyLogger.logger.info msg
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.warn(msg)
|
13
|
+
FloatyLogger.logger.warn msg
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.error(msg)
|
17
|
+
FloatyLogger.logger.error msg
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize
|
21
|
+
super(STDERR)
|
22
|
+
self.level = ::Logger::INFO
|
23
|
+
self.formatter = proc do |severity, datetime, progname, msg|
|
24
|
+
"#{msg}\n"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
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
|
|
@@ -77,7 +77,7 @@ class NonstandardPooler
|
|
77
77
|
raise ModifyError, 'Configured service type does not support snapshots'
|
78
78
|
end
|
79
79
|
|
80
|
-
def self.delete(verbose, url, hosts, token)
|
80
|
+
def self.delete(verbose, url, hosts, token, _user)
|
81
81
|
raise TokenError, 'Token provided was nil; Request cannot be made to delete VM' if token.nil?
|
82
82
|
|
83
83
|
conn = Http.get_conn(verbose, url)
|
data/lib/vmfloaty/pooler.rb
CHANGED
@@ -28,7 +28,7 @@ class Pooler
|
|
28
28
|
vms
|
29
29
|
end
|
30
30
|
|
31
|
-
def self.retrieve(verbose, os_type, token, url, _user, _options)
|
31
|
+
def self.retrieve(verbose, os_type, token, url, _user, _options, ondemand = nil)
|
32
32
|
# NOTE:
|
33
33
|
# Developers can use `Utils.generate_os_hash` to
|
34
34
|
# generate the os_type param.
|
@@ -38,7 +38,8 @@ class Pooler
|
|
38
38
|
os_string = os_type.map { |os, num| Array(os) * num }.flatten.join('+')
|
39
39
|
raise MissingParamError, 'No operating systems provided to obtain.' if os_string.empty?
|
40
40
|
|
41
|
-
response = conn.post "vm/#{os_string}"
|
41
|
+
response = conn.post "vm/#{os_string}" unless ondemand
|
42
|
+
response ||= conn.post "ondemandvm/#{os_string}"
|
42
43
|
|
43
44
|
res_body = JSON.parse(response.body)
|
44
45
|
|
@@ -46,11 +47,40 @@ class Pooler
|
|
46
47
|
res_body
|
47
48
|
elsif response.status == 401
|
48
49
|
raise AuthError, "HTTP #{response.status}: The token provided could not authenticate to the pooler.\n#{res_body}"
|
50
|
+
elsif response.status == 403
|
51
|
+
raise "HTTP #{response.status}: Failed to obtain VMs from the pooler at #{url}/vm/#{os_string}. Request exceeds the configured per pool maximum. #{res_body}"
|
49
52
|
else
|
50
|
-
raise "HTTP #{response.status}: Failed to obtain VMs from the pooler at #{url}/vm/#{os_string}. #{res_body}"
|
53
|
+
raise "HTTP #{response.status}: Failed to obtain VMs from the pooler at #{url}/vm/#{os_string}. #{res_body}" unless ondemand
|
54
|
+
raise "HTTP #{response.status}: Failed to obtain VMs from the pooler at #{url}/ondemandvm/#{os_string}. #{res_body}"
|
51
55
|
end
|
52
56
|
end
|
53
57
|
|
58
|
+
def self.wait_for_request(verbose, request_id, url, timeout = 300)
|
59
|
+
start_time = Time.now
|
60
|
+
while check_ondemandvm(verbose, request_id, url) == false
|
61
|
+
return false if (Time.now - start_time).to_i > timeout
|
62
|
+
|
63
|
+
FloatyLogger.info "waiting for request #{request_id} to be fulfilled"
|
64
|
+
sleep 5
|
65
|
+
end
|
66
|
+
FloatyLogger.info "The request has been fulfilled"
|
67
|
+
check_ondemandvm(verbose, request_id, url)
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.check_ondemandvm(verbose, request_id, url)
|
71
|
+
conn = Http.get_conn(verbose, url)
|
72
|
+
|
73
|
+
response = conn.get "ondemandvm/#{request_id}"
|
74
|
+
res_body = JSON.parse(response.body)
|
75
|
+
return res_body if response.status == 200
|
76
|
+
|
77
|
+
return false if response.status == 202
|
78
|
+
|
79
|
+
raise "HTTP #{response.status}: The request cannot be found, or an unknown error occurred" if response.status == 404
|
80
|
+
|
81
|
+
false
|
82
|
+
end
|
83
|
+
|
54
84
|
def self.modify(verbose, url, hostname, token, modify_hash)
|
55
85
|
raise TokenError, 'Token provided was nil. Request cannot be made to modify vm' if token.nil?
|
56
86
|
|
@@ -94,7 +124,7 @@ class Pooler
|
|
94
124
|
res_body
|
95
125
|
end
|
96
126
|
|
97
|
-
def self.delete(verbose, url, hosts, token)
|
127
|
+
def self.delete(verbose, url, hosts, token, _user)
|
98
128
|
raise TokenError, 'Token provided was nil. Request cannot be made to delete vm' if token.nil?
|
99
129
|
|
100
130
|
conn = Http.get_conn(verbose, url)
|
data/lib/vmfloaty/service.rb
CHANGED
@@ -36,7 +36,7 @@ class Service
|
|
36
36
|
|
37
37
|
def user
|
38
38
|
unless @config['user']
|
39
|
-
|
39
|
+
FloatyLogger.info "Enter your #{@config['url']} service username:"
|
40
40
|
@config['user'] = STDIN.gets.chomp
|
41
41
|
end
|
42
42
|
@config['user']
|
@@ -44,7 +44,7 @@ class Service
|
|
44
44
|
|
45
45
|
def token
|
46
46
|
unless @config['token']
|
47
|
-
|
47
|
+
FloatyLogger.info 'No token found. Retrieving a token...'
|
48
48
|
@config['token'] = get_new_token(nil)
|
49
49
|
end
|
50
50
|
@config['token']
|
@@ -75,10 +75,14 @@ class Service
|
|
75
75
|
@service_object.list_active verbose, url, token, user
|
76
76
|
end
|
77
77
|
|
78
|
-
def retrieve(verbose, os_types, use_token = true)
|
79
|
-
|
78
|
+
def retrieve(verbose, os_types, use_token = true, ondemand = nil)
|
79
|
+
FloatyLogger.info 'Requesting a vm without a token...' unless use_token
|
80
80
|
token_value = use_token ? token : nil
|
81
|
-
@service_object.retrieve verbose, os_types, token_value, url, user, @config
|
81
|
+
@service_object.retrieve verbose, os_types, token_value, url, user, @config, ondemand
|
82
|
+
end
|
83
|
+
|
84
|
+
def wait_for_request(verbose, requestid)
|
85
|
+
@service_object.wait_for_request verbose, requestid, url
|
82
86
|
end
|
83
87
|
|
84
88
|
def ssh(verbose, host_os, use_token = true)
|
@@ -87,20 +91,11 @@ class Service
|
|
87
91
|
begin
|
88
92
|
token_value = token || get_new_token(verbose)
|
89
93
|
rescue TokenError => e
|
90
|
-
|
91
|
-
|
94
|
+
FloatyLogger.error e
|
95
|
+
FloatyLogger.info 'Could not get token... requesting vm without a token anyway...'
|
92
96
|
end
|
93
97
|
end
|
94
|
-
Ssh.ssh(verbose, host_os, token_value
|
95
|
-
end
|
96
|
-
|
97
|
-
def pretty_print_running(verbose, hostnames = [])
|
98
|
-
if hostnames.empty?
|
99
|
-
puts 'You have no running VMs.'
|
100
|
-
else
|
101
|
-
puts 'Running VMs:'
|
102
|
-
@service_object.pretty_print_hosts(verbose, hostnames, url)
|
103
|
-
end
|
98
|
+
Ssh.ssh(verbose, self, host_os, token_value)
|
104
99
|
end
|
105
100
|
|
106
101
|
def query(verbose, hostname)
|
data/lib/vmfloaty/ssh.rb
CHANGED
@@ -14,21 +14,27 @@ class Ssh
|
|
14
14
|
nil
|
15
15
|
end
|
16
16
|
|
17
|
-
def self.
|
17
|
+
def self.command_string(verbose, service, host_os, use_token)
|
18
18
|
ssh_path = which('ssh')
|
19
19
|
raise 'Could not determine path to ssh' unless ssh_path
|
20
20
|
|
21
21
|
os_types = {}
|
22
22
|
os_types[host_os] = 1
|
23
23
|
|
24
|
-
response =
|
25
|
-
raise "Could not get vm from
|
24
|
+
response = service.retrieve(verbose, os_types, use_token)
|
25
|
+
raise "Could not get vm from #{service.type}:\n #{response}" unless response['ok']
|
26
26
|
|
27
27
|
user = /win/.match?(host_os) ? 'Administrator' : 'root'
|
28
28
|
|
29
|
-
hostname =
|
30
|
-
|
29
|
+
hostname = response[host_os]['hostname']
|
30
|
+
hostname = response[host_os]['hostname'][0] if response[host_os]['hostname'].is_a?(Array)
|
31
|
+
hostname = "#{hostname}.#{response['domain']}" unless hostname.end_with?('puppetlabs.net')
|
31
32
|
|
33
|
+
"#{ssh_path} #{user}@#{hostname}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.ssh(verbose, service, host_os, use_token)
|
37
|
+
cmd = command_string(verbose, service, host_os, use_token)
|
32
38
|
# TODO: Should this respect more ssh settings? Can it be configured
|
33
39
|
# by users ssh config and does this respect those settings?
|
34
40
|
Kernel.exec(cmd)
|
data/lib/vmfloaty/utils.rb
CHANGED
@@ -45,7 +45,8 @@ class Utils
|
|
45
45
|
|
46
46
|
result = {}
|
47
47
|
|
48
|
-
response_body.
|
48
|
+
filtered_response_body = response_body.reject { |key, _| key == 'request_id' || key == 'ready' }
|
49
|
+
filtered_response_body.each do |os, value|
|
49
50
|
hostnames = Array(value['hostname'])
|
50
51
|
hostnames.map! { |host| "#{host}.#{domain}" } if domain
|
51
52
|
result[os] = hostnames
|
@@ -77,41 +78,63 @@ class Utils
|
|
77
78
|
os_types
|
78
79
|
end
|
79
80
|
|
80
|
-
def self.pretty_print_hosts(verbose, service, hostnames = [])
|
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 = {}
|
81
110
|
hostnames = [hostnames] unless hostnames.is_a? Array
|
82
111
|
hostnames.each do |hostname|
|
83
112
|
begin
|
84
113
|
response = service.query(verbose, hostname)
|
85
114
|
host_data = response[hostname]
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
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
|
93
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}"
|
94
130
|
end
|
95
|
-
when 'Pooler'
|
96
|
-
tag_pairs = []
|
97
|
-
tag_pairs = host_data['tags'].map { |key, value| "#{key}: #{value}" } unless host_data['tags'].nil?
|
98
|
-
duration = "#{host_data['running']}/#{host_data['lifetime']} hours"
|
99
|
-
metadata = [host_data['template'], duration, *tag_pairs]
|
100
|
-
puts "- #{hostname}.#{host_data['domain']} (#{metadata.join(', ')})"
|
101
|
-
when 'NonstandardPooler'
|
102
|
-
line = "- #{host_data['fqdn']} (#{host_data['os_triple']}"
|
103
|
-
line += ", #{host_data['hours_left_on_reservation']}h remaining"
|
104
|
-
line += ", reason: #{host_data['reserved_for_reason']}" unless host_data['reserved_for_reason'].empty?
|
105
|
-
line += ')'
|
106
|
-
puts line
|
107
|
-
else
|
108
|
-
raise "Invalid service type #{service.type}"
|
109
131
|
end
|
110
132
|
rescue StandardError => e
|
111
|
-
|
112
|
-
|
133
|
+
FloatyLogger.error("Something went wrong while trying to gather information on #{hostname}:")
|
134
|
+
FloatyLogger.error(e)
|
113
135
|
end
|
114
136
|
end
|
137
|
+
result
|
115
138
|
end
|
116
139
|
|
117
140
|
def self.pretty_print_status(verbose, service)
|
@@ -133,7 +156,7 @@ class Utils
|
|
133
156
|
char = 'o'
|
134
157
|
puts "#{name.ljust(width)} #{(char * ready).green}#{(char * pending).yellow}#{(char * missing).red}"
|
135
158
|
rescue StandardError => e
|
136
|
-
|
159
|
+
FloatyLogger.error "#{name.ljust(width)} #{e.red}"
|
137
160
|
end
|
138
161
|
end
|
139
162
|
puts message.colorize(status_response['status']['ok'] ? :default : :red)
|
@@ -152,11 +175,11 @@ class Utils
|
|
152
175
|
char = 'o'
|
153
176
|
puts "#{name.ljust(width)} #{(char * ready).green}#{(char * pending).yellow}#{(char * missing).red}"
|
154
177
|
rescue StandardError => e
|
155
|
-
|
178
|
+
FloatyLogger.error "#{name.ljust(width)} #{e.red}"
|
156
179
|
end
|
157
180
|
end
|
158
181
|
when 'ABS'
|
159
|
-
|
182
|
+
FloatyLogger.error 'ABS Not OK' unless status_response
|
160
183
|
puts 'ABS is OK'.green if status_response
|
161
184
|
else
|
162
185
|
raise "Invalid service type #{service.type}"
|
@@ -205,6 +228,9 @@ class Utils
|
|
205
228
|
# If the service is configured but some values are missing, use the top-level defaults to fill them in
|
206
229
|
service_config.merge! config['services'][options.service]
|
207
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
|
208
234
|
end
|
209
235
|
|
210
236
|
# Prioritize an explicitly specified url, user, or token if the user provided one
|