vmfloaty 1.3.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/lib/vmfloaty.rb +50 -56
- data/lib/vmfloaty/abs.rb +50 -51
- data/lib/vmfloaty/http.rb +2 -6
- data/lib/vmfloaty/logger.rb +13 -10
- data/lib/vmfloaty/nonstandard_pooler.rb +3 -2
- data/lib/vmfloaty/pooler.rb +19 -24
- data/lib/vmfloaty/service.rb +3 -3
- data/lib/vmfloaty/utils.rb +60 -61
- 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 +52 -43
- 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 +170 -164
- metadata +13 -7
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
|
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
|
|
@@ -43,9 +44,7 @@ class Vmfloaty
|
|
43
44
|
c.option '--loglevel STRING', String, 'the log level to use (debug, info, error)'
|
44
45
|
c.action do |args, options|
|
45
46
|
verbose = options.verbose || config['verbose']
|
46
|
-
if options.loglevel
|
47
|
-
FloatyLogger.setlevel = options.loglevel
|
48
|
-
end
|
47
|
+
FloatyLogger.setlevel = options.loglevel if options.loglevel
|
49
48
|
service = Service.new(options, config)
|
50
49
|
use_token = !options.notoken
|
51
50
|
force = options.force
|
@@ -100,21 +99,19 @@ class Vmfloaty
|
|
100
99
|
c.option '--loglevel STRING', String, 'the log level to use (debug, info, error)'
|
101
100
|
c.action do |args, options|
|
102
101
|
verbose = options.verbose || config['verbose']
|
103
|
-
if options.loglevel
|
104
|
-
FloatyLogger.setlevel = options.loglevel
|
105
|
-
end
|
102
|
+
FloatyLogger.setlevel = options.loglevel if options.loglevel
|
106
103
|
|
107
104
|
service = Service.new(options, config)
|
108
105
|
filter = args[0]
|
109
106
|
|
110
107
|
if options.active
|
111
108
|
# list active vms
|
112
|
-
if service.type ==
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
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
|
118
115
|
host = URI.parse(service.url).host
|
119
116
|
if running_vms.empty?
|
120
117
|
if options.json
|
@@ -122,17 +119,15 @@ class Vmfloaty
|
|
122
119
|
else
|
123
120
|
FloatyLogger.info "You have no running VMs on #{host}"
|
124
121
|
end
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
Utils.
|
130
|
-
Utils.print_fqdn_for_host(service, hostname, host_data)
|
131
|
-
end
|
132
|
-
else
|
133
|
-
puts "Your VMs on #{host}:"
|
134
|
-
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)
|
135
127
|
end
|
128
|
+
else
|
129
|
+
puts "Your VMs on #{host}:"
|
130
|
+
Utils.pretty_print_hosts(verbose, service, running_vms)
|
136
131
|
end
|
137
132
|
else
|
138
133
|
# list available vms from pooler
|
@@ -164,7 +159,8 @@ class Vmfloaty
|
|
164
159
|
c.syntax = 'floaty modify hostname [options]'
|
165
160
|
c.summary = 'Modify a VM\'s tags, time to live, disk space, or reservation reason'
|
166
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.'
|
167
|
-
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"}\''
|
168
164
|
c.option '--verbose', 'Enables verbose output'
|
169
165
|
c.option '--service STRING', String, 'Configured pooler service name'
|
170
166
|
c.option '--url STRING', String, 'URL of pooler service'
|
@@ -185,18 +181,18 @@ class Vmfloaty
|
|
185
181
|
exit 1
|
186
182
|
end
|
187
183
|
running_vms =
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
184
|
+
if modify_all
|
185
|
+
service.list_active(verbose)
|
186
|
+
else
|
187
|
+
hostname.split(',')
|
188
|
+
end
|
193
189
|
|
194
190
|
tags = options.tags ? JSON.parse(options.tags) : nil
|
195
191
|
modify_hash = {
|
196
|
-
:
|
197
|
-
:
|
198
|
-
:
|
199
|
-
:
|
192
|
+
lifetime: options.lifetime,
|
193
|
+
disk: options.disk,
|
194
|
+
tags: tags,
|
195
|
+
reason: options.reason
|
200
196
|
}
|
201
197
|
modify_hash.delete_if { |_, value| value.nil? }
|
202
198
|
|
@@ -204,12 +200,10 @@ class Vmfloaty
|
|
204
200
|
ok = true
|
205
201
|
modified_hash = {}
|
206
202
|
running_vms.each do |vm|
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
ok = false
|
212
|
-
end
|
203
|
+
modified_hash[vm] = service.modify(verbose, vm, modify_hash)
|
204
|
+
rescue ModifyError => e
|
205
|
+
FloatyLogger.error e
|
206
|
+
ok = false
|
213
207
|
end
|
214
208
|
if ok
|
215
209
|
if modify_all
|
@@ -241,9 +235,7 @@ class Vmfloaty
|
|
241
235
|
c.option '--loglevel STRING', String, 'the log level to use (debug, info, error)'
|
242
236
|
c.action do |args, options|
|
243
237
|
verbose = options.verbose || config['verbose']
|
244
|
-
if options.loglevel
|
245
|
-
FloatyLogger.setlevel = options.loglevel
|
246
|
-
end
|
238
|
+
FloatyLogger.setlevel = options.loglevel if options.loglevel
|
247
239
|
|
248
240
|
service = Service.new(options, config)
|
249
241
|
hostnames = args[0]
|
@@ -254,17 +246,17 @@ class Vmfloaty
|
|
254
246
|
successes = []
|
255
247
|
|
256
248
|
if delete_all
|
257
|
-
if service.type ==
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
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
|
263
255
|
if running_vms.empty?
|
264
256
|
if options.json
|
265
257
|
puts {}.to_json
|
266
258
|
else
|
267
|
-
FloatyLogger.info
|
259
|
+
FloatyLogger.info 'You have no running VMs.'
|
268
260
|
end
|
269
261
|
else
|
270
262
|
confirmed = true
|
@@ -328,7 +320,8 @@ class Vmfloaty
|
|
328
320
|
c.syntax = 'floaty snapshot hostname [options]'
|
329
321
|
c.summary = 'Takes a snapshot of a given vm'
|
330
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.'
|
331
|
-
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'
|
332
325
|
c.option '--verbose', 'Enables verbose output'
|
333
326
|
c.option '--service STRING', String, 'Configured pooler service name'
|
334
327
|
c.option '--url STRING', String, 'URL of pooler service'
|
@@ -354,7 +347,8 @@ class Vmfloaty
|
|
354
347
|
c.syntax = 'floaty revert hostname snapshot [options]'
|
355
348
|
c.summary = 'Reverts a vm to a specified snapshot'
|
356
349
|
c.description = 'Given a snapshot SHA, vmfloaty will request a revert to the pooler service to go back to a previous snapshot.'
|
357
|
-
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'
|
358
352
|
c.option '--verbose', 'Enables verbose output'
|
359
353
|
c.option '--service STRING', String, 'Configured pooler service name'
|
360
354
|
c.option '--url STRING', String, 'URL of pooler service'
|
@@ -366,7 +360,9 @@ class Vmfloaty
|
|
366
360
|
hostname = args[0]
|
367
361
|
snapshot_sha = args[1] || options.snapshot
|
368
362
|
|
369
|
-
|
363
|
+
if args[1] && options.snapshot
|
364
|
+
FloatyLogger.info "Two snapshot arguments were given....using snapshot #{snapshot_sha}"
|
365
|
+
end
|
370
366
|
|
371
367
|
begin
|
372
368
|
revert_req = service.revert(verbose, hostname, snapshot_sha)
|
@@ -391,9 +387,7 @@ class Vmfloaty
|
|
391
387
|
c.option '--loglevel STRING', String, 'the log level to use (debug, info, error)'
|
392
388
|
c.action do |_, options|
|
393
389
|
verbose = options.verbose || config['verbose']
|
394
|
-
if options.loglevel
|
395
|
-
FloatyLogger.setlevel = options.loglevel
|
396
|
-
end
|
390
|
+
FloatyLogger.setlevel = options.loglevel if options.loglevel
|
397
391
|
service = Service.new(options, config)
|
398
392
|
if options.json
|
399
393
|
pp service.status(verbose)
|
@@ -527,7 +521,7 @@ class Vmfloaty
|
|
527
521
|
c.example 'Print a list of the valid service types', 'floaty service types'
|
528
522
|
c.example 'Print a sample config file with multiple services', 'floaty service examples'
|
529
523
|
c.example 'list vms from the service named "nspooler-prod"', 'floaty list --service nspooler-prod'
|
530
|
-
c.action do |args,
|
524
|
+
c.action do |args, _options|
|
531
525
|
action = args.first
|
532
526
|
|
533
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
|
|
@@ -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
|
@@ -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
|
|
@@ -248,20 +248,20 @@ class ABS
|
|
248
248
|
conn = Http.get_conn(verbose, supported_abs_url(url))
|
249
249
|
conn.headers['X-AUTH-TOKEN'] = token if token
|
250
250
|
|
251
|
-
if continue.nil?
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
251
|
+
saved_job_id = if continue.nil?
|
252
|
+
"#{user}-#{DateTime.now.strftime('%Q')}"
|
253
|
+
else
|
254
|
+
continue
|
255
|
+
end
|
256
256
|
|
257
257
|
req_obj = {
|
258
|
-
:
|
259
|
-
:
|
260
|
-
:
|
261
|
-
:
|
262
|
-
:
|
263
|
-
}
|
264
|
-
}
|
258
|
+
resources: os_types,
|
259
|
+
job: {
|
260
|
+
id: saved_job_id,
|
261
|
+
tags: {
|
262
|
+
user: user
|
263
|
+
}
|
264
|
+
}
|
265
265
|
}
|
266
266
|
|
267
267
|
if config['vmpooler_fallback'] # optional and not available as cli flag
|
@@ -271,11 +271,12 @@ class ABS
|
|
271
271
|
end
|
272
272
|
|
273
273
|
if config['priority']
|
274
|
-
req_obj[:priority] =
|
274
|
+
req_obj[:priority] = case config['priority']
|
275
|
+
when 'high'
|
275
276
|
1
|
276
|
-
|
277
|
+
when 'medium'
|
277
278
|
2
|
278
|
-
|
279
|
+
when 'low'
|
279
280
|
3
|
280
281
|
else
|
281
282
|
config['priority'].to_i
|
@@ -291,14 +292,12 @@ class ABS
|
|
291
292
|
|
292
293
|
retries = 360
|
293
294
|
|
294
|
-
status = validate_queue_status_response(res.status, res.body,
|
295
|
+
status = validate_queue_status_response(res.status, res.body, 'Initial request', verbose)
|
295
296
|
|
296
297
|
begin
|
297
298
|
(1..retries).each do |i|
|
298
299
|
res_body = check_queue(conn, saved_job_id, req_obj, verbose)
|
299
|
-
|
300
|
-
return translated(res_body, saved_job_id)
|
301
|
-
end
|
300
|
+
return translated(res_body, saved_job_id) if res_body.is_a?(Array) # when we get a response with hostnames
|
302
301
|
|
303
302
|
sleep_seconds = 10 if i >= 10
|
304
303
|
sleep_seconds = i if i < 10
|
@@ -317,10 +316,10 @@ class ABS
|
|
317
316
|
# We should fix the ABS API to be more like the vmpooler or nspooler api, but for now
|
318
317
|
#
|
319
318
|
def self.translated(res_body, job_id)
|
320
|
-
vmpooler_formatted_body = {'job_id' => job_id}
|
319
|
+
vmpooler_formatted_body = { 'job_id' => job_id }
|
321
320
|
|
322
321
|
res_body.each do |host|
|
323
|
-
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)
|
324
323
|
vmpooler_formatted_body[host['type']]['hostname'] << host['hostname']
|
325
324
|
else
|
326
325
|
vmpooler_formatted_body[host['type']] = { 'hostname' => [host['hostname']] }
|
@@ -331,9 +330,9 @@ class ABS
|
|
331
330
|
vmpooler_formatted_body
|
332
331
|
end
|
333
332
|
|
334
|
-
def self.check_queue(conn,
|
333
|
+
def self.check_queue(conn, _job_id, req_obj, verbose)
|
335
334
|
res = conn.post 'request', req_obj.to_json
|
336
|
-
status = validate_queue_status_response(res.status, res.body,
|
335
|
+
status = validate_queue_status_response(res.status, res.body, 'Check queue request', verbose)
|
337
336
|
unless res.body.empty? || !valid_json?(res.body)
|
338
337
|
res_body = JSON.parse(res.body)
|
339
338
|
return res_body
|
@@ -353,7 +352,7 @@ class ABS
|
|
353
352
|
res.body == 'OK'
|
354
353
|
end
|
355
354
|
|
356
|
-
def self.summary(
|
355
|
+
def self.summary(_verbose, _url)
|
357
356
|
raise NoMethodError, 'summary is not defined for ABS'
|
358
357
|
end
|
359
358
|
|
@@ -405,17 +404,17 @@ class ABS
|
|
405
404
|
|
406
405
|
def self.valid_json?(json)
|
407
406
|
JSON.parse(json)
|
408
|
-
|
407
|
+
true
|
409
408
|
rescue TypeError, JSON::ParserError => e
|
410
|
-
|
409
|
+
false
|
411
410
|
end
|
412
411
|
|
413
412
|
# when missing, adds the required api/v2 in the url
|
414
413
|
def self.supported_abs_url(url)
|
415
|
-
expected_ending =
|
416
|
-
|
414
|
+
expected_ending = 'api/v2'
|
415
|
+
unless url.include?(expected_ending)
|
417
416
|
# add a slash if missing
|
418
|
-
expected_ending = "/#{expected_ending}" if url[-1] !=
|
417
|
+
expected_ending = "/#{expected_ending}" if url[-1] != '/'
|
419
418
|
url = "#{url}#{expected_ending}"
|
420
419
|
end
|
421
420
|
url
|
data/lib/vmfloaty/http.rb
CHANGED
@@ -21,13 +21,11 @@ class Http
|
|
21
21
|
|
22
22
|
url = "https://#{url}" unless url?(url)
|
23
23
|
|
24
|
-
|
24
|
+
Faraday.new(url: url, ssl: { verify: false }) do |faraday|
|
25
25
|
faraday.request :url_encoded
|
26
26
|
faraday.response :logger if verbose
|
27
27
|
faraday.adapter Faraday.default_adapter
|
28
28
|
end
|
29
|
-
|
30
|
-
conn
|
31
29
|
end
|
32
30
|
|
33
31
|
def self.get_conn_with_auth(verbose, url, user, password)
|
@@ -37,13 +35,11 @@ class Http
|
|
37
35
|
|
38
36
|
url = "https://#{url}" unless url?(url)
|
39
37
|
|
40
|
-
|
38
|
+
Faraday.new(url: url, ssl: { verify: false }) do |faraday|
|
41
39
|
faraday.request :url_encoded
|
42
40
|
faraday.request :basic_auth, user, password
|
43
41
|
faraday.response :logger if verbose
|
44
42
|
faraday.adapter Faraday.default_adapter
|
45
43
|
end
|
46
|
-
|
47
|
-
conn
|
48
44
|
end
|
49
45
|
end
|