vmfloaty 1.0.0 → 1.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/extras/completions/floaty.bash +16 -8
- data/extras/completions/floaty.zsh +13 -7
- data/lib/vmfloaty.rb +62 -50
- data/lib/vmfloaty/abs.rb +86 -69
- data/lib/vmfloaty/http.rb +2 -6
- data/lib/vmfloaty/logger.rb +19 -3
- data/lib/vmfloaty/nonstandard_pooler.rb +3 -2
- data/lib/vmfloaty/pooler.rb +20 -25
- data/lib/vmfloaty/service.rb +6 -6
- data/lib/vmfloaty/utils.rb +67 -62
- data/lib/vmfloaty/version.rb +1 -2
- data/spec/spec_helper.rb +20 -3
- data/spec/vmfloaty/abs/auth_spec.rb +26 -17
- data/spec/vmfloaty/abs_spec.rb +55 -46
- data/spec/vmfloaty/auth_spec.rb +23 -13
- data/spec/vmfloaty/nonstandard_pooler_spec.rb +32 -31
- data/spec/vmfloaty/pooler_spec.rb +29 -26
- data/spec/vmfloaty/service_spec.rb +10 -10
- data/spec/vmfloaty/ssh_spec.rb +3 -3
- data/spec/vmfloaty/utils_spec.rb +191 -159
- metadata +17 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7dde0d683f0fd9ba231b9441473e3b501fc45979de87256403809c68e03c1b43
|
4
|
+
data.tar.gz: 79e88b4ff40d432fcea114b82b2cd8ef952d74e8b4bb6a3bcf047be345d54be6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b6c470d8d4c369f5e39b8a42d031ae4378165278e44bd00cacfbdfc7dc7aabafdf8a8bb1291fe33ab081be7c1c45195e10567708e45a0c34d2ff40340338b8e3
|
7
|
+
data.tar.gz: 2f7305e4f363dbb71ae45d1d14a38ddbde7289e6c5d0d58c72faef01c6840ae39ad76eacde81b638387dc12fcdcf446ad5225f0dad8d4f87c346ba57a8e587a9
|
@@ -2,29 +2,37 @@
|
|
2
2
|
|
3
3
|
_vmfloaty()
|
4
4
|
{
|
5
|
-
local cur prev
|
5
|
+
local cur prev commands template_arg_commands hostname_arg_commands service_subcommands
|
6
|
+
|
6
7
|
COMPREPLY=()
|
7
8
|
cur="${COMP_WORDS[COMP_CWORD]}"
|
8
9
|
prev="${COMP_WORDS[COMP_CWORD-1]}"
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
commands="delete get help list modify query revert service snapshot ssh status summary token"
|
12
|
+
template_arg_commands="get ssh"
|
13
|
+
hostname_arg_commands="delete modify query revert snapshot"
|
14
|
+
service_subcommands="types examples"
|
13
15
|
|
14
16
|
if [[ $cur == -* ]] ; then
|
15
17
|
# TODO: option completion
|
16
18
|
COMPREPLY=()
|
17
|
-
elif [[ $
|
19
|
+
elif [[ $template_arg_commands =~ (^| )$prev($| ) ]] ; then
|
18
20
|
if [[ -z "$_vmfloaty_avail_templates" ]] ; then
|
21
|
+
# TODO: need a --hostnameonly equivalent here because the section headers of
|
22
|
+
# `floaty list` are adding some spurious entries (including files in current
|
23
|
+
# directory because part of the headers is `**` which is getting expanded)
|
19
24
|
_vmfloaty_avail_templates=$(floaty list 2>/dev/null)
|
20
25
|
fi
|
21
26
|
|
22
27
|
COMPREPLY=( $(compgen -W "${_vmfloaty_avail_templates}" -- "${cur}") )
|
23
|
-
elif [[ $
|
28
|
+
elif [[ $hostname_arg_commands =~ (^| )$prev($| ) ]] ; then
|
24
29
|
_vmfloaty_active_hostnames=$(floaty list --active --hostnameonly 2>/dev/null)
|
25
30
|
COMPREPLY=( $(compgen -W "${_vmfloaty_active_hostnames}" -- "${cur}") )
|
26
|
-
|
27
|
-
COMPREPLY=( $(compgen -W "${
|
31
|
+
elif [[ "service" == $prev ]] ; then
|
32
|
+
COMPREPLY=( $(compgen -W "${service_subcommands}" -- "${cur}") )
|
33
|
+
elif [[ $1 == $prev ]] ; then
|
34
|
+
# only show top level commands we are at root
|
35
|
+
COMPREPLY=( $(compgen -W "${commands}" -- "${cur}") )
|
28
36
|
fi
|
29
37
|
}
|
30
38
|
complete -F _vmfloaty floaty
|
@@ -1,26 +1,32 @@
|
|
1
1
|
_floaty()
|
2
2
|
{
|
3
|
-
local line
|
3
|
+
local line commands template_arg_commands hostname_arg_commands service_subcommands
|
4
4
|
|
5
|
-
|
5
|
+
commands="delete get help list modify query revert service snapshot ssh status summary token"
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
template_arg_commands=("get" "ssh")
|
8
|
+
hostname_arg_commands=("delete" "modify" "query" "revert" "snapshot")
|
9
|
+
service_subcommands=("types" "examples")
|
9
10
|
|
10
11
|
_arguments -C \
|
11
|
-
"1: :(${
|
12
|
+
"1: :(${commands})" \
|
12
13
|
"*::arg:->args"
|
13
14
|
|
14
|
-
if ((
|
15
|
+
if ((template_arg_commands[(Ie)$line[1]])); then
|
15
16
|
_floaty_template_sub
|
16
|
-
elif ((
|
17
|
+
elif ((hostname_arg_commands[(Ie)$line[1]])); then
|
17
18
|
_floaty_hostname_sub
|
19
|
+
elif [[ "service" == $line[1] ]]; then
|
20
|
+
_arguments "1: :(${service_subcommands})"
|
18
21
|
fi
|
19
22
|
}
|
20
23
|
|
21
24
|
_floaty_template_sub()
|
22
25
|
{
|
23
26
|
if [[ -z "$_vmfloaty_avail_templates" ]] ; then
|
27
|
+
# TODO: need a --hostnameonly equivalent here because the section headers of
|
28
|
+
# `floaty list` are adding some spurious entries (including files in current
|
29
|
+
# directory because part of the headers is `**` which is getting expanded)
|
24
30
|
_vmfloaty_avail_templates=$(floaty list 2>/dev/null)
|
25
31
|
fi
|
26
32
|
|
data/lib/vmfloaty.rb
CHANGED
@@ -20,7 +20,8 @@ class Vmfloaty
|
|
20
20
|
|
21
21
|
def run # rubocop:disable Metrics/AbcSize
|
22
22
|
program :version, Vmfloaty::VERSION
|
23
|
-
program :description,
|
23
|
+
program :description,
|
24
|
+
"A CLI helper tool for Puppet's vmpooler to help you stay afloat.\n\nConfiguration may be placed in a ~/.vmfloaty.yml file."
|
24
25
|
|
25
26
|
config = Conf.read_config
|
26
27
|
|
@@ -39,8 +40,11 @@ class Vmfloaty
|
|
39
40
|
c.option '--force', 'Forces vmfloaty to get requested vms'
|
40
41
|
c.option '--json', 'Prints retrieved vms in JSON format'
|
41
42
|
c.option '--ondemand', 'Requested vms are provisioned upon receival of the request, tracked by a request ID'
|
43
|
+
c.option '--continue STRING', String, 'resume polling ABS for job_id, for use when the cli was interrupted'
|
44
|
+
c.option '--loglevel STRING', String, 'the log level to use (debug, info, error)'
|
42
45
|
c.action do |args, options|
|
43
46
|
verbose = options.verbose || config['verbose']
|
47
|
+
FloatyLogger.setlevel = options.loglevel if options.loglevel
|
44
48
|
service = Service.new(options, config)
|
45
49
|
use_token = !options.notoken
|
46
50
|
force = options.force
|
@@ -52,6 +56,11 @@ class Vmfloaty
|
|
52
56
|
|
53
57
|
os_types = Utils.generate_os_hash(args)
|
54
58
|
|
59
|
+
if os_types.empty?
|
60
|
+
FloatyLogger.error 'No operating systems provided to obtain. See `floaty get --help` for more information on how to get VMs.'
|
61
|
+
exit 1
|
62
|
+
end
|
63
|
+
|
55
64
|
max_pool_request = 5
|
56
65
|
large_pool_requests = os_types.select { |_, v| v > max_pool_request }
|
57
66
|
if !large_pool_requests.empty? && !force
|
@@ -60,12 +69,7 @@ class Vmfloaty
|
|
60
69
|
exit 1
|
61
70
|
end
|
62
71
|
|
63
|
-
|
64
|
-
FloatyLogger.error 'No operating systems provided to obtain. See `floaty get --help` for more information on how to get VMs.'
|
65
|
-
exit 1
|
66
|
-
end
|
67
|
-
|
68
|
-
response = service.retrieve(verbose, os_types, use_token, options.ondemand)
|
72
|
+
response = service.retrieve(verbose, os_types, use_token, options.ondemand, options.continue)
|
69
73
|
request_id = response['request_id'] if options.ondemand
|
70
74
|
response = service.wait_for_request(verbose, request_id) if options.ondemand
|
71
75
|
|
@@ -92,20 +96,22 @@ class Vmfloaty
|
|
92
96
|
c.option '--token STRING', String, 'Token for pooler service'
|
93
97
|
c.option '--url STRING', String, 'URL of pooler service'
|
94
98
|
c.option '--user STRING', String, 'User to authenticate with'
|
99
|
+
c.option '--loglevel STRING', String, 'the log level to use (debug, info, error)'
|
95
100
|
c.action do |args, options|
|
96
101
|
verbose = options.verbose || config['verbose']
|
102
|
+
FloatyLogger.setlevel = options.loglevel if options.loglevel
|
97
103
|
|
98
104
|
service = Service.new(options, config)
|
99
105
|
filter = args[0]
|
100
106
|
|
101
107
|
if options.active
|
102
108
|
# list active vms
|
103
|
-
if service.type ==
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
+
running_vms = if service.type == 'ABS'
|
110
|
+
# this is actually job_ids
|
111
|
+
service.list_active_job_ids(verbose, service.url, service.user)
|
112
|
+
else
|
113
|
+
service.list_active(verbose)
|
114
|
+
end
|
109
115
|
host = URI.parse(service.url).host
|
110
116
|
if running_vms.empty?
|
111
117
|
if options.json
|
@@ -113,17 +119,15 @@ class Vmfloaty
|
|
113
119
|
else
|
114
120
|
FloatyLogger.info "You have no running VMs on #{host}"
|
115
121
|
end
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
Utils.
|
121
|
-
Utils.print_fqdn_for_host(service, hostname, host_data)
|
122
|
-
end
|
123
|
-
else
|
124
|
-
puts "Your VMs on #{host}:"
|
125
|
-
Utils.pretty_print_hosts(verbose, service, running_vms)
|
122
|
+
elsif options.json
|
123
|
+
puts Utils.get_host_data(verbose, service, running_vms).to_json
|
124
|
+
elsif options.hostnameonly
|
125
|
+
Utils.get_host_data(verbose, service, running_vms).each do |hostname, host_data|
|
126
|
+
Utils.print_fqdn_for_host(service, hostname, host_data)
|
126
127
|
end
|
128
|
+
else
|
129
|
+
puts "Your VMs on #{host}:"
|
130
|
+
Utils.pretty_print_hosts(verbose, service, running_vms)
|
127
131
|
end
|
128
132
|
else
|
129
133
|
# list available vms from pooler
|
@@ -155,7 +159,8 @@ class Vmfloaty
|
|
155
159
|
c.syntax = 'floaty modify hostname [options]'
|
156
160
|
c.summary = 'Modify a VM\'s tags, time to live, disk space, or reservation reason'
|
157
161
|
c.description = 'This command makes modifications to the virtual machines state in the pooler service. You can either append tags to the vm, increase how long it stays active for, or increase the amount of disk space.'
|
158
|
-
c.example 'Modifies myhost1 to have a TTL of 12 hours and adds a custom tag',
|
162
|
+
c.example 'Modifies myhost1 to have a TTL of 12 hours and adds a custom tag',
|
163
|
+
'floaty modify myhost1 --lifetime 12 --url https://myurl --token mytokenstring --tags \'{"tag":"myvalue"}\''
|
159
164
|
c.option '--verbose', 'Enables verbose output'
|
160
165
|
c.option '--service STRING', String, 'Configured pooler service name'
|
161
166
|
c.option '--url STRING', String, 'URL of pooler service'
|
@@ -176,18 +181,18 @@ class Vmfloaty
|
|
176
181
|
exit 1
|
177
182
|
end
|
178
183
|
running_vms =
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
+
if modify_all
|
185
|
+
service.list_active(verbose)
|
186
|
+
else
|
187
|
+
hostname.split(',')
|
188
|
+
end
|
184
189
|
|
185
190
|
tags = options.tags ? JSON.parse(options.tags) : nil
|
186
191
|
modify_hash = {
|
187
|
-
:
|
188
|
-
:
|
189
|
-
:
|
190
|
-
:
|
192
|
+
lifetime: options.lifetime,
|
193
|
+
disk: options.disk,
|
194
|
+
tags: tags,
|
195
|
+
reason: options.reason
|
191
196
|
}
|
192
197
|
modify_hash.delete_if { |_, value| value.nil? }
|
193
198
|
|
@@ -195,12 +200,10 @@ class Vmfloaty
|
|
195
200
|
ok = true
|
196
201
|
modified_hash = {}
|
197
202
|
running_vms.each do |vm|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
ok = false
|
203
|
-
end
|
203
|
+
modified_hash[vm] = service.modify(verbose, vm, modify_hash)
|
204
|
+
rescue ModifyError => e
|
205
|
+
FloatyLogger.error e
|
206
|
+
ok = false
|
204
207
|
end
|
205
208
|
if ok
|
206
209
|
if modify_all
|
@@ -229,8 +232,11 @@ class Vmfloaty
|
|
229
232
|
c.option '--token STRING', String, 'Token for pooler service'
|
230
233
|
c.option '--url STRING', String, 'URL of pooler service'
|
231
234
|
c.option '--user STRING', String, 'User to authenticate with'
|
235
|
+
c.option '--loglevel STRING', String, 'the log level to use (debug, info, error)'
|
232
236
|
c.action do |args, options|
|
233
237
|
verbose = options.verbose || config['verbose']
|
238
|
+
FloatyLogger.setlevel = options.loglevel if options.loglevel
|
239
|
+
|
234
240
|
service = Service.new(options, config)
|
235
241
|
hostnames = args[0]
|
236
242
|
delete_all = options.all
|
@@ -240,17 +246,17 @@ class Vmfloaty
|
|
240
246
|
successes = []
|
241
247
|
|
242
248
|
if delete_all
|
243
|
-
if service.type ==
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
+
running_vms = if service.type == 'ABS'
|
250
|
+
# this is actually job_ids
|
251
|
+
service.list_active_job_ids(verbose, service.url, service.user)
|
252
|
+
else
|
253
|
+
service.list_active(verbose)
|
254
|
+
end
|
249
255
|
if running_vms.empty?
|
250
256
|
if options.json
|
251
257
|
puts {}.to_json
|
252
258
|
else
|
253
|
-
FloatyLogger.info
|
259
|
+
FloatyLogger.info 'You have no running VMs.'
|
254
260
|
end
|
255
261
|
else
|
256
262
|
confirmed = true
|
@@ -314,7 +320,8 @@ class Vmfloaty
|
|
314
320
|
c.syntax = 'floaty snapshot hostname [options]'
|
315
321
|
c.summary = 'Takes a snapshot of a given vm'
|
316
322
|
c.description = 'Will request a snapshot be taken of the given hostname in the pooler service. This command is known to take a while depending on how much load is on the pooler service.'
|
317
|
-
c.example 'Takes a snapshot for a given host',
|
323
|
+
c.example 'Takes a snapshot for a given host',
|
324
|
+
'floaty snapshot myvm.example.com --url http://vmpooler.example.com --token a9znth9dn01t416hrguu56ze37t790bl'
|
318
325
|
c.option '--verbose', 'Enables verbose output'
|
319
326
|
c.option '--service STRING', String, 'Configured pooler service name'
|
320
327
|
c.option '--url STRING', String, 'URL of pooler service'
|
@@ -340,7 +347,8 @@ class Vmfloaty
|
|
340
347
|
c.syntax = 'floaty revert hostname snapshot [options]'
|
341
348
|
c.summary = 'Reverts a vm to a specified snapshot'
|
342
349
|
c.description = 'Given a snapshot SHA, vmfloaty will request a revert to the pooler service to go back to a previous snapshot.'
|
343
|
-
c.example 'Reverts to a snapshot for a given host',
|
350
|
+
c.example 'Reverts to a snapshot for a given host',
|
351
|
+
'floaty revert myvm.example.com n4eb4kdtp7rwv4x158366vd9jhac8btq --url http://vmpooler.example.com --token a9znth9dn01t416hrguu56ze37t790bl'
|
344
352
|
c.option '--verbose', 'Enables verbose output'
|
345
353
|
c.option '--service STRING', String, 'Configured pooler service name'
|
346
354
|
c.option '--url STRING', String, 'URL of pooler service'
|
@@ -352,7 +360,9 @@ class Vmfloaty
|
|
352
360
|
hostname = args[0]
|
353
361
|
snapshot_sha = args[1] || options.snapshot
|
354
362
|
|
355
|
-
|
363
|
+
if args[1] && options.snapshot
|
364
|
+
FloatyLogger.info "Two snapshot arguments were given....using snapshot #{snapshot_sha}"
|
365
|
+
end
|
356
366
|
|
357
367
|
begin
|
358
368
|
revert_req = service.revert(verbose, hostname, snapshot_sha)
|
@@ -374,8 +384,10 @@ class Vmfloaty
|
|
374
384
|
c.option '--service STRING', String, 'Configured pooler service name'
|
375
385
|
c.option '--url STRING', String, 'URL of pooler service'
|
376
386
|
c.option '--json', 'Prints status in JSON format'
|
387
|
+
c.option '--loglevel STRING', String, 'the log level to use (debug, info, error)'
|
377
388
|
c.action do |_, options|
|
378
389
|
verbose = options.verbose || config['verbose']
|
390
|
+
FloatyLogger.setlevel = options.loglevel if options.loglevel
|
379
391
|
service = Service.new(options, config)
|
380
392
|
if options.json
|
381
393
|
pp service.status(verbose)
|
@@ -509,7 +521,7 @@ class Vmfloaty
|
|
509
521
|
c.example 'Print a list of the valid service types', 'floaty service types'
|
510
522
|
c.example 'Print a sample config file with multiple services', 'floaty service examples'
|
511
523
|
c.example 'list vms from the service named "nspooler-prod"', 'floaty list --service nspooler-prod'
|
512
|
-
c.action do |args,
|
524
|
+
c.action do |args, _options|
|
513
525
|
action = args.first
|
514
526
|
|
515
527
|
example_config = Utils.strip_heredoc(<<-CONFIG)
|
data/lib/vmfloaty/abs.rb
CHANGED
@@ -53,10 +53,10 @@ class ABS
|
|
53
53
|
def self.list_active(verbose, url, _token, user)
|
54
54
|
hosts = []
|
55
55
|
get_active_requests(verbose, url, user).each do |req_hash|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
56
|
+
next unless req_hash.key?('allocated_resources')
|
57
|
+
|
58
|
+
req_hash['allocated_resources'].each do |onehost|
|
59
|
+
hosts.push(onehost['hostname'])
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
@@ -64,7 +64,7 @@ class ABS
|
|
64
64
|
end
|
65
65
|
|
66
66
|
def self.get_active_requests(verbose, url, user)
|
67
|
-
conn = Http.get_conn(verbose, url)
|
67
|
+
conn = Http.get_conn(verbose, supported_abs_url(url))
|
68
68
|
res = conn.get 'status/queue'
|
69
69
|
if valid_json?(res.body)
|
70
70
|
requests = JSON.parse(res.body)
|
@@ -105,7 +105,7 @@ class ABS
|
|
105
105
|
|
106
106
|
def self.delete(verbose, url, hosts, token, user)
|
107
107
|
# In ABS terms, this is a "returned" host.
|
108
|
-
conn = Http.get_conn(verbose, url)
|
108
|
+
conn = Http.get_conn(verbose, supported_abs_url(url))
|
109
109
|
conn.headers['X-AUTH-TOKEN'] = token if token
|
110
110
|
|
111
111
|
FloatyLogger.info "Trying to delete hosts #{hosts}" if verbose
|
@@ -116,7 +116,7 @@ class ABS
|
|
116
116
|
ret_status = {}
|
117
117
|
hosts.each do |host|
|
118
118
|
ret_status[host] = {
|
119
|
-
'ok' => false
|
119
|
+
'ok' => false
|
120
120
|
}
|
121
121
|
end
|
122
122
|
|
@@ -132,7 +132,7 @@ class ABS
|
|
132
132
|
if hosts.include? vm_name['hostname']
|
133
133
|
if all_job_resources_accounted_for(req_hash['allocated_resources'], hosts)
|
134
134
|
ret_status[vm_name['hostname']] = {
|
135
|
-
'ok' => true
|
135
|
+
'ok' => true
|
136
136
|
}
|
137
137
|
jobs_to_delete.push(req_hash)
|
138
138
|
else
|
@@ -147,7 +147,7 @@ class ABS
|
|
147
147
|
jobs_to_delete.each do |job|
|
148
148
|
req_obj = {
|
149
149
|
'job_id' => job['request']['job']['id'],
|
150
|
-
'hosts'
|
150
|
+
'hosts' => job['allocated_resources']
|
151
151
|
}
|
152
152
|
|
153
153
|
FloatyLogger.info "Deleting #{req_obj}" if verbose
|
@@ -163,7 +163,7 @@ class ABS
|
|
163
163
|
|
164
164
|
# List available VMs in ABS
|
165
165
|
def self.list(verbose, url, os_filter = nil)
|
166
|
-
conn = Http.get_conn(verbose, url)
|
166
|
+
conn = Http.get_conn(verbose, supported_abs_url(url))
|
167
167
|
|
168
168
|
os_list = []
|
169
169
|
|
@@ -172,11 +172,11 @@ class ABS
|
|
172
172
|
res_body = JSON.parse(res.body)
|
173
173
|
if res_body.key?('vmpooler_platforms')
|
174
174
|
os_list << '*** VMPOOLER Pools ***'
|
175
|
-
if res_body['vmpooler_platforms'].is_a?(String)
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
175
|
+
os_list += if res_body['vmpooler_platforms'].is_a?(String)
|
176
|
+
JSON.parse(res_body['vmpooler_platforms']) # legacy ABS had another JSON string always-be-scheduling/pull/306
|
177
|
+
else
|
178
|
+
res_body['vmpooler_platforms']
|
179
|
+
end
|
180
180
|
end
|
181
181
|
end
|
182
182
|
|
@@ -200,11 +200,11 @@ class ABS
|
|
200
200
|
if res_body.key?('nspooler_platforms')
|
201
201
|
os_list << ''
|
202
202
|
os_list << '*** NSPOOLER Pools ***'
|
203
|
-
if res_body['nspooler_platforms'].is_a?(String)
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
203
|
+
os_list += if res_body['nspooler_platforms'].is_a?(String)
|
204
|
+
JSON.parse(res_body['nspooler_platforms']) # legacy ABS had another JSON string always-be-scheduling/pull/306
|
205
|
+
else
|
206
|
+
res_body['nspooler_platforms']
|
207
|
+
end
|
208
208
|
end
|
209
209
|
end
|
210
210
|
|
@@ -214,11 +214,11 @@ class ABS
|
|
214
214
|
if res_body.key?('aws_platforms')
|
215
215
|
os_list << ''
|
216
216
|
os_list << '*** AWS Pools ***'
|
217
|
-
if res_body['aws_platforms'].is_a?(String)
|
218
|
-
|
219
|
-
|
220
|
-
|
221
|
-
|
217
|
+
os_list += if res_body['aws_platforms'].is_a?(String)
|
218
|
+
JSON.parse(res_body['aws_platforms']) # legacy ABS had another JSON string always-be-scheduling/pull/306
|
219
|
+
else
|
220
|
+
res_body['aws_platforms']
|
221
|
+
end
|
222
222
|
end
|
223
223
|
end
|
224
224
|
|
@@ -228,7 +228,7 @@ class ABS
|
|
228
228
|
end
|
229
229
|
|
230
230
|
# Retrieve an OS from ABS.
|
231
|
-
def self.retrieve(verbose, os_types, token, url, user, config, _ondemand = nil)
|
231
|
+
def self.retrieve(verbose, os_types, token, url, user, config, _ondemand = nil, continue = nil)
|
232
232
|
#
|
233
233
|
# Contents of post must be like:
|
234
234
|
#
|
@@ -245,28 +245,38 @@ class ABS
|
|
245
245
|
# }
|
246
246
|
# }
|
247
247
|
|
248
|
-
conn = Http.get_conn(verbose, url)
|
248
|
+
conn = Http.get_conn(verbose, supported_abs_url(url))
|
249
249
|
conn.headers['X-AUTH-TOKEN'] = token if token
|
250
250
|
|
251
|
-
saved_job_id =
|
252
|
-
|
251
|
+
saved_job_id = if continue.nil?
|
252
|
+
"#{user}-#{DateTime.now.strftime('%Q')}"
|
253
|
+
else
|
254
|
+
continue
|
255
|
+
end
|
256
|
+
|
253
257
|
req_obj = {
|
254
|
-
:
|
255
|
-
:
|
256
|
-
:
|
257
|
-
:
|
258
|
-
:
|
259
|
-
}
|
260
|
-
}
|
261
|
-
:vm_token => vmpooler_config['token'] # request with this token, on behalf of this user
|
258
|
+
resources: os_types,
|
259
|
+
job: {
|
260
|
+
id: saved_job_id,
|
261
|
+
tags: {
|
262
|
+
user: user
|
263
|
+
}
|
264
|
+
}
|
262
265
|
}
|
263
266
|
|
267
|
+
if config['vmpooler_fallback'] # optional and not available as cli flag
|
268
|
+
vmpooler_config = Utils.get_vmpooler_service_config(config['vmpooler_fallback'])
|
269
|
+
# request with this token, on behalf of this user
|
270
|
+
req_obj[:vm_token] = vmpooler_config['token']
|
271
|
+
end
|
272
|
+
|
264
273
|
if config['priority']
|
265
|
-
req_obj[:priority] =
|
274
|
+
req_obj[:priority] = case config['priority']
|
275
|
+
when 'high'
|
266
276
|
1
|
267
|
-
|
277
|
+
when 'medium'
|
268
278
|
2
|
269
|
-
|
279
|
+
when 'low'
|
270
280
|
3
|
271
281
|
else
|
272
282
|
config['priority'].to_i
|
@@ -277,22 +287,27 @@ class ABS
|
|
277
287
|
|
278
288
|
# os_string = os_type.map { |os, num| Array(os) * num }.flatten.join('+')
|
279
289
|
# raise MissingParamError, 'No operating systems provided to obtain.' if os_string.empty?
|
280
|
-
FloatyLogger.info "Requesting VMs with job_id: #{saved_job_id}
|
290
|
+
FloatyLogger.info "Requesting VMs with job_id: #{saved_job_id} Will retry for up to an hour."
|
281
291
|
res = conn.post 'request', req_obj.to_json
|
282
292
|
|
283
293
|
retries = 360
|
284
294
|
|
285
|
-
validate_queue_status_response(res.status, res.body,
|
295
|
+
status = validate_queue_status_response(res.status, res.body, 'Initial request', verbose)
|
286
296
|
|
287
|
-
|
288
|
-
|
289
|
-
|
297
|
+
begin
|
298
|
+
(1..retries).each do |i|
|
299
|
+
res_body = check_queue(conn, saved_job_id, req_obj, verbose)
|
300
|
+
return translated(res_body, saved_job_id) if res_body.is_a?(Array) # when we get a response with hostnames
|
290
301
|
|
291
|
-
|
292
|
-
|
293
|
-
|
302
|
+
sleep_seconds = 10 if i >= 10
|
303
|
+
sleep_seconds = i if i < 10
|
304
|
+
FloatyLogger.info "Waiting #{sleep_seconds}s (x#{i}) #{res_body.strip}"
|
294
305
|
|
295
|
-
|
306
|
+
sleep(sleep_seconds)
|
307
|
+
end
|
308
|
+
rescue SystemExit, Interrupt
|
309
|
+
FloatyLogger.info "\n\nFloaty interrupted, you can resume polling with\n1) `floaty get [same arguments] and adding the flag --continue #{saved_job_id}` or query the state of the queue via\n2) `floaty query #{saved_job_id}` or delete it via\n3) `floaty delete #{saved_job_id}`"
|
310
|
+
exit 1
|
296
311
|
end
|
297
312
|
nil
|
298
313
|
end
|
@@ -301,10 +316,10 @@ class ABS
|
|
301
316
|
# We should fix the ABS API to be more like the vmpooler or nspooler api, but for now
|
302
317
|
#
|
303
318
|
def self.translated(res_body, job_id)
|
304
|
-
vmpooler_formatted_body = {'job_id' => job_id}
|
319
|
+
vmpooler_formatted_body = { 'job_id' => job_id }
|
305
320
|
|
306
321
|
res_body.each do |host|
|
307
|
-
if vmpooler_formatted_body[host['type']] && vmpooler_formatted_body[host['type']]['hostname'].
|
322
|
+
if vmpooler_formatted_body[host['type']] && vmpooler_formatted_body[host['type']]['hostname'].instance_of?(Array)
|
308
323
|
vmpooler_formatted_body[host['type']]['hostname'] << host['hostname']
|
309
324
|
else
|
310
325
|
vmpooler_formatted_body[host['type']] = { 'hostname' => [host['hostname']] }
|
@@ -315,23 +330,14 @@ class ABS
|
|
315
330
|
vmpooler_formatted_body
|
316
331
|
end
|
317
332
|
|
318
|
-
def self.check_queue(conn,
|
319
|
-
queue_info_res = conn.get "status/queue/info/#{job_id}"
|
320
|
-
if valid_json?(queue_info_res.body)
|
321
|
-
queue_info = JSON.parse(queue_info_res.body)
|
322
|
-
else
|
323
|
-
FloatyLogger.warn "Could not parse the status/queue/info/#{job_id}"
|
324
|
-
return [nil, nil]
|
325
|
-
end
|
326
|
-
|
333
|
+
def self.check_queue(conn, _job_id, req_obj, verbose)
|
327
334
|
res = conn.post 'request', req_obj.to_json
|
328
|
-
validate_queue_status_response(res.status, res.body,
|
329
|
-
|
335
|
+
status = validate_queue_status_response(res.status, res.body, 'Check queue request', verbose)
|
330
336
|
unless res.body.empty? || !valid_json?(res.body)
|
331
337
|
res_body = JSON.parse(res.body)
|
332
|
-
return
|
338
|
+
return res_body
|
333
339
|
end
|
334
|
-
|
340
|
+
res.body
|
335
341
|
end
|
336
342
|
|
337
343
|
def self.snapshot(_verbose, _url, _hostname, _token)
|
@@ -339,14 +345,14 @@ class ABS
|
|
339
345
|
end
|
340
346
|
|
341
347
|
def self.status(verbose, url)
|
342
|
-
conn = Http.get_conn(verbose, url)
|
348
|
+
conn = Http.get_conn(verbose, supported_abs_url(url))
|
343
349
|
|
344
350
|
res = conn.get 'status'
|
345
351
|
|
346
352
|
res.body == 'OK'
|
347
353
|
end
|
348
354
|
|
349
|
-
def self.summary(
|
355
|
+
def self.summary(_verbose, _url)
|
350
356
|
raise NoMethodError, 'summary is not defined for ABS'
|
351
357
|
end
|
352
358
|
|
@@ -357,7 +363,7 @@ class ABS
|
|
357
363
|
return @active_hostnames if @active_hostnames && !@active_hostnames.empty?
|
358
364
|
|
359
365
|
# If using the cli query job_id
|
360
|
-
conn = Http.get_conn(verbose, url)
|
366
|
+
conn = Http.get_conn(verbose, supported_abs_url(url))
|
361
367
|
queue_info_res = conn.get "status/queue/info/#{job_id}"
|
362
368
|
if valid_json?(queue_info_res.body)
|
363
369
|
queue_info = JSON.parse(queue_info_res.body)
|
@@ -398,8 +404,19 @@ class ABS
|
|
398
404
|
|
399
405
|
def self.valid_json?(json)
|
400
406
|
JSON.parse(json)
|
401
|
-
|
407
|
+
true
|
402
408
|
rescue TypeError, JSON::ParserError => e
|
403
|
-
|
409
|
+
false
|
410
|
+
end
|
411
|
+
|
412
|
+
# when missing, adds the required api/v2 in the url
|
413
|
+
def self.supported_abs_url(url)
|
414
|
+
expected_ending = 'api/v2'
|
415
|
+
unless url.include?(expected_ending)
|
416
|
+
# add a slash if missing
|
417
|
+
expected_ending = "/#{expected_ending}" if url[-1] != '/'
|
418
|
+
url = "#{url}#{expected_ending}"
|
419
|
+
end
|
420
|
+
url
|
404
421
|
end
|
405
422
|
end
|