vmfloaty 1.1.1 → 1.5.0

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: cfd72279e6067194457cfff7e798bffb6c3f7e516a215ab25507836a35918dfa
4
- data.tar.gz: e5f63b9b99f8969e557cf14993d89063353b2b8d2201e2945204375f4c8599f1
3
+ metadata.gz: 622a0112e8e8c09fd70d5c2d2b0f31e89032a907db86aebd84ce019238c3e4f5
4
+ data.tar.gz: 38f82e6bbf28d2669219b8f856af7876864ecdcef54e46f44c4d9dab8c09e56d
5
5
  SHA512:
6
- metadata.gz: 57500a3436d64a3edc4aa8a11bcfc5590a05788268fb7c556d70816a0dede112225298f657a762c8a5eec3b829117f91599e286115237e5e039dfe5554d9d2c2
7
- data.tar.gz: 288ded1bca5cfe6bff06be880b17264ddd49a10674649a1424515af7a48d646eb0b693123aee0ec353b6bb57424f209ca7cd653e1fd3287831b137593ebfe50b
6
+ metadata.gz: 47f457eeda161702eedd0246ea1d4e7fd146044d00d98334009746ae1dc3ab7ee1f5b80e27287ba1c4f330ee07ccdd889348362ede637503265b1b68ae3bd5b6
7
+ data.tar.gz: adc9ac4bf7ce2ab2ef4080b7ffc702866aa7a58177c9e6b1ab948d371e51e3deb9e6a0293dda83762633267376db831f0b4eaa036b4a0dc672268ffe51471306
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # vmfloaty
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/vmfloaty.svg)](https://badge.fury.io/rb/vmfloaty)
4
- [![Build Status](https://travis-ci.com/puppetlabs/vmfloaty.svg?branch=master)](https://travis-ci.com/puppetlabs/vmfloaty)
5
- [![Coverage Status](https://coveralls.io/repos/github/puppetlabs/vmfloaty/badge.svg?branch=master)](https://coveralls.io/github/puppetlabs/vmfloaty?branch=master)
4
+ [![Build Status](https://github.com/puppetlabs/vmfloaty/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/puppetlabs/vmfloaty/actions/workflows/ci.yml)
5
+ [![Coverage Status](https://github.com/puppetlabs/vmfloaty/badge.svg?branch=main)](https://coveralls.io/github/puppetlabs/vmfloaty?branch=main)
6
6
  [![Dependabot Status](https://api.dependabot.com/badges/status?host=github&repo=puppetlabs/vmfloaty)](https://dependabot.com)
7
7
 
8
8
  A CLI helper tool for [Puppet's vmpooler](https://github.com/puppetlabs/vmpooler) to help you stay afloat.
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
- if req_hash.key?('allocated_resources')
57
- req_hash['allocated_resources'].each do |onehost|
58
- hosts.push(onehost['hostname'])
59
- end
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' => job['allocated_resources'],
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
- os_list += JSON.parse(res_body['vmpooler_platforms']) # legacy ABS had another JSON string always-be-scheduling/pull/306
177
- else
178
- os_list += res_body['vmpooler_platforms']
179
- end
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
- os_list += JSON.parse(res_body['nspooler_platforms']) # legacy ABS had another JSON string always-be-scheduling/pull/306
205
- else
206
- os_list += res_body['nspooler_platforms']
207
- end
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
- os_list += JSON.parse(res_body['aws_platforms']) # legacy ABS had another JSON string always-be-scheduling/pull/306
219
- else
220
- os_list += res_body['aws_platforms']
221
- end
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
  #
@@ -248,15 +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
- saved_job_id = user + "-" + DateTime.now.strftime('%Q')
251
+ saved_job_id = if continue.nil?
252
+ "#{user}-#{DateTime.now.strftime('%Q')}"
253
+ else
254
+ continue
255
+ end
256
+
252
257
  req_obj = {
253
- :resources => os_types,
254
- :job => {
255
- :id => saved_job_id,
256
- :tags => {
257
- :user => user,
258
- },
259
- },
258
+ resources: os_types,
259
+ job: {
260
+ id: saved_job_id,
261
+ tags: {
262
+ user: user
263
+ }
264
+ }
260
265
  }
261
266
 
262
267
  if config['vmpooler_fallback'] # optional and not available as cli flag
@@ -266,11 +271,12 @@ class ABS
266
271
  end
267
272
 
268
273
  if config['priority']
269
- req_obj[:priority] = if config['priority'] == 'high'
274
+ req_obj[:priority] = case config['priority']
275
+ when 'high'
270
276
  1
271
- elsif config['priority'] == 'medium'
277
+ when 'medium'
272
278
  2
273
- elsif config['priority'] == 'low'
279
+ when 'low'
274
280
  3
275
281
  else
276
282
  config['priority'].to_i
@@ -281,26 +287,26 @@ class ABS
281
287
 
282
288
  # os_string = os_type.map { |os, num| Array(os) * num }.flatten.join('+')
283
289
  # raise MissingParamError, 'No operating systems provided to obtain.' if os_string.empty?
284
- FloatyLogger.info "Requesting VMs with job_id: #{saved_job_id}. Will retry for up to an hour."
290
+ FloatyLogger.info "Requesting VMs with job_id: #{saved_job_id} Will retry for up to an hour."
285
291
  res = conn.post 'request', req_obj.to_json
286
292
 
287
293
  retries = 360
288
294
 
289
- validate_queue_status_response(res.status, res.body, "Initial request", verbose)
295
+ status = validate_queue_status_response(res.status, res.body, 'Initial request', verbose)
290
296
 
291
297
  begin
292
298
  (1..retries).each do |i|
293
- queue_place, res_body = check_queue(conn, saved_job_id, req_obj, verbose)
294
- return translated(res_body, saved_job_id) if res_body
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
295
301
 
296
302
  sleep_seconds = 10 if i >= 10
297
303
  sleep_seconds = i if i < 10
298
- FloatyLogger.info "Waiting #{sleep_seconds} seconds to check if ABS request has been filled. Queue Position: #{queue_place}... (x#{i})"
304
+ FloatyLogger.info "Waiting #{sleep_seconds}s (x#{i}) #{res_body.strip}"
299
305
 
300
306
  sleep(sleep_seconds)
301
307
  end
302
308
  rescue SystemExit, Interrupt
303
- FloatyLogger.info "\n\nFloaty interrupted, you can query the state of your request via\n1) `floaty query #{saved_job_id}` or delete it via\n2) `floaty delete #{saved_job_id}`"
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}`"
304
310
  exit 1
305
311
  end
306
312
  nil
@@ -310,10 +316,10 @@ class ABS
310
316
  # We should fix the ABS API to be more like the vmpooler or nspooler api, but for now
311
317
  #
312
318
  def self.translated(res_body, job_id)
313
- vmpooler_formatted_body = {'job_id' => job_id}
319
+ vmpooler_formatted_body = { 'job_id' => job_id }
314
320
 
315
321
  res_body.each do |host|
316
- if vmpooler_formatted_body[host['type']] && vmpooler_formatted_body[host['type']]['hostname'].class == Array
322
+ if vmpooler_formatted_body[host['type']] && vmpooler_formatted_body[host['type']]['hostname'].instance_of?(Array)
317
323
  vmpooler_formatted_body[host['type']]['hostname'] << host['hostname']
318
324
  else
319
325
  vmpooler_formatted_body[host['type']] = { 'hostname' => [host['hostname']] }
@@ -324,23 +330,14 @@ class ABS
324
330
  vmpooler_formatted_body
325
331
  end
326
332
 
327
- def self.check_queue(conn, job_id, req_obj, verbose)
328
- queue_info_res = conn.get "status/queue/info/#{job_id}"
329
- if valid_json?(queue_info_res.body)
330
- queue_info = JSON.parse(queue_info_res.body)
331
- else
332
- FloatyLogger.warn "Could not parse the status/queue/info/#{job_id}"
333
- return [nil, nil]
334
- end
335
-
333
+ def self.check_queue(conn, _job_id, req_obj, verbose)
336
334
  res = conn.post 'request', req_obj.to_json
337
- validate_queue_status_response(res.status, res.body, "Check queue request", verbose)
338
-
335
+ status = validate_queue_status_response(res.status, res.body, 'Check queue request', verbose)
339
336
  unless res.body.empty? || !valid_json?(res.body)
340
337
  res_body = JSON.parse(res.body)
341
- return queue_info['queue_place'], res_body
338
+ return res_body
342
339
  end
343
- [queue_info['queue_place'], nil]
340
+ res.body
344
341
  end
345
342
 
346
343
  def self.snapshot(_verbose, _url, _hostname, _token)
@@ -355,7 +352,7 @@ class ABS
355
352
  res.body == 'OK'
356
353
  end
357
354
 
358
- def self.summary(verbose, url)
355
+ def self.summary(_verbose, _url)
359
356
  raise NoMethodError, 'summary is not defined for ABS'
360
357
  end
361
358
 
@@ -407,17 +404,17 @@ class ABS
407
404
 
408
405
  def self.valid_json?(json)
409
406
  JSON.parse(json)
410
- return true
407
+ true
411
408
  rescue TypeError, JSON::ParserError => e
412
- return false
409
+ false
413
410
  end
414
411
 
415
412
  # when missing, adds the required api/v2 in the url
416
413
  def self.supported_abs_url(url)
417
- expected_ending = "api/v2"
418
- if !url.include?(expected_ending)
414
+ expected_ending = 'api/v2'
415
+ unless url.include?(expected_ending)
419
416
  # add a slash if missing
420
- expected_ending = "/#{expected_ending}" if url[-1] != "/"
417
+ expected_ending = "/#{expected_ending}" if url[-1] != '/'
421
418
  url = "#{url}#{expected_ending}"
422
419
  end
423
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
- conn = Faraday.new(:url => url, :ssl => { :verify => false }) do |faraday|
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
- conn = Faraday.new(:url => url, :ssl => { :verify => false }) do |faraday|
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
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'logger'
2
4
 
3
5
  class FloatyLogger < ::Logger
@@ -17,11 +19,25 @@ class FloatyLogger < ::Logger
17
19
  FloatyLogger.logger.error msg
18
20
  end
19
21
 
22
+ def self.setlevel=(level)
23
+ level = level.downcase
24
+ case level
25
+ when 'debug'
26
+ logger.level = ::Logger::DEBUG
27
+ when 'info'
28
+ logger.level = ::Logger::INFO
29
+ when 'error'
30
+ logger.level = ::Logger::ERROR
31
+ else
32
+ error('set loglevel to debug, info or error')
33
+ end
34
+ end
35
+
20
36
  def initialize
21
- super(STDERR)
37
+ super($stderr)
22
38
  self.level = ::Logger::INFO
23
- self.formatter = proc do |severity, datetime, progname, msg|
24
- "#{msg}\n"
39
+ self.formatter = proc do |_severity, _datetime, _progname, msg|
40
+ "#{msg}\n"
25
41
  end
26
42
  end
27
43
  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, ondemand = nil)
25
+ def self.retrieve(verbose, os_type, token, url, _user, _options, _ondemand = nil, _continue = nil)
26
26
  conn = Http.get_conn(verbose, url)
27
27
  conn.headers['X-AUTH-TOKEN'] = token if token
28
28
 
@@ -46,7 +46,8 @@ class NonstandardPooler
46
46
  raise TokenError, 'Token provided was nil; Request cannot be made to modify VM' if token.nil?
47
47
 
48
48
  modify_hash.each do |key, _value|
49
- raise ModifyError, "Configured service type does not support modification of #{key}" unless %i[reason reserved_for_reason].include? key
49
+ raise ModifyError, "Configured service type does not support modification of #{key}" unless %i[reason
50
+ reserved_for_reason].include? key
50
51
  end
51
52
 
52
53
  if modify_hash[:reason]
@@ -12,13 +12,11 @@ class Pooler
12
12
  response = conn.get 'vm'
13
13
  response_body = JSON.parse(response.body)
14
14
 
15
- hosts = if os_filter
16
- response_body.select { |i| i[/#{os_filter}/] }
17
- else
18
- response_body
19
- end
20
-
21
- hosts
15
+ if os_filter
16
+ response_body.select { |i| i[/#{os_filter}/] }
17
+ else
18
+ response_body
19
+ end
22
20
  end
23
21
 
24
22
  def self.list_active(verbose, url, token, _user)
@@ -28,7 +26,7 @@ class Pooler
28
26
  vms
29
27
  end
30
28
 
31
- def self.retrieve(verbose, os_type, token, url, _user, _options, ondemand = nil)
29
+ def self.retrieve(verbose, os_type, token, url, _user, _options, ondemand = nil, _continue = nil)
32
30
  # NOTE:
33
31
  # Developers can use `Utils.generate_os_hash` to
34
32
  # generate the os_type param.
@@ -50,7 +48,10 @@ class Pooler
50
48
  elsif response.status == 403
51
49
  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}"
52
50
  else
53
- raise "HTTP #{response.status}: Failed to obtain VMs from the pooler at #{url}/vm/#{os_string}. #{res_body}" unless ondemand
51
+ unless ondemand
52
+ raise "HTTP #{response.status}: Failed to obtain VMs from the pooler at #{url}/vm/#{os_string}. #{res_body}"
53
+ end
54
+
54
55
  raise "HTTP #{response.status}: Failed to obtain VMs from the pooler at #{url}/ondemandvm/#{os_string}. #{res_body}"
55
56
  end
56
57
  end
@@ -63,7 +64,7 @@ class Pooler
63
64
  FloatyLogger.info "waiting for request #{request_id} to be fulfilled"
64
65
  sleep 5
65
66
  end
66
- FloatyLogger.info "The request has been fulfilled"
67
+ FloatyLogger.info 'The request has been fulfilled'
67
68
  check_ondemandvm(verbose, request_id, url)
68
69
  end
69
70
 
@@ -84,8 +85,9 @@ class Pooler
84
85
  def self.modify(verbose, url, hostname, token, modify_hash)
85
86
  raise TokenError, 'Token provided was nil. Request cannot be made to modify vm' if token.nil?
86
87
 
87
- modify_hash.keys.each do |key|
88
- raise ModifyError, "Configured service type does not support modification of #{key}." unless %i[tags lifetime disk].include? key
88
+ modify_hash.each_key do |key|
89
+ raise ModifyError, "Configured service type does not support modification of #{key}." unless %i[tags lifetime
90
+ disk].include? key
89
91
  end
90
92
 
91
93
  conn = Http.get_conn(verbose, url)
@@ -120,8 +122,7 @@ class Pooler
120
122
 
121
123
  response = conn.post "vm/#{hostname}/disk/#{disk}"
122
124
 
123
- res_body = JSON.parse(response.body)
124
- res_body
125
+ JSON.parse(response.body)
125
126
  end
126
127
 
127
128
  def self.delete(verbose, url, hosts, token, _user)
@@ -146,25 +147,21 @@ class Pooler
146
147
  conn = Http.get_conn(verbose, url)
147
148
 
148
149
  response = conn.get '/status'
149
- res_body = JSON.parse(response.body)
150
- res_body
150
+ JSON.parse(response.body)
151
151
  end
152
152
 
153
153
  def self.summary(verbose, url)
154
154
  conn = Http.get_conn(verbose, url)
155
155
 
156
156
  response = conn.get '/summary'
157
- res_body = JSON.parse(response.body)
158
- res_body
157
+ JSON.parse(response.body)
159
158
  end
160
159
 
161
160
  def self.query(verbose, url, hostname)
162
161
  conn = Http.get_conn(verbose, url)
163
162
 
164
163
  response = conn.get "vm/#{hostname}"
165
- res_body = JSON.parse(response.body)
166
-
167
- res_body
164
+ JSON.parse(response.body)
168
165
  end
169
166
 
170
167
  def self.snapshot(verbose, url, hostname, token)
@@ -174,8 +171,7 @@ class Pooler
174
171
  conn.headers['X-AUTH-TOKEN'] = token
175
172
 
176
173
  response = conn.post "vm/#{hostname}/snapshot"
177
- res_body = JSON.parse(response.body)
178
- res_body
174
+ JSON.parse(response.body)
179
175
  end
180
176
 
181
177
  def self.revert(verbose, url, hostname, token, snapshot_sha)
@@ -187,7 +183,6 @@ class Pooler
187
183
  raise "Snapshot SHA provided was nil, could not revert #{hostname}" if snapshot_sha.nil?
188
184
 
189
185
  response = conn.post "vm/#{hostname}/snapshot/#{snapshot_sha}"
190
- res_body = JSON.parse(response.body)
191
- res_body
186
+ JSON.parse(response.body)
192
187
  end
193
188
  end
@@ -39,7 +39,7 @@ class Service
39
39
  def user
40
40
  unless @config['user']
41
41
  FloatyLogger.info "Enter your #{@config['url']} service username:"
42
- @config['user'] = STDIN.gets.chomp
42
+ @config['user'] = $stdin.gets.chomp
43
43
  end
44
44
  @config['user']
45
45
  end
@@ -77,10 +77,10 @@ class Service
77
77
  @service_object.list_active verbose, url, token, user
78
78
  end
79
79
 
80
- def retrieve(verbose, os_types, use_token = true, ondemand = nil)
80
+ def retrieve(verbose, os_types, use_token = true, ondemand = nil, continue = nil)
81
81
  FloatyLogger.info 'Requesting a vm without a token...' unless use_token
82
82
  token_value = use_token ? token : nil
83
- @service_object.retrieve verbose, os_types, token_value, url, user, @config, ondemand
83
+ @service_object.retrieve verbose, os_types, token_value, url, user, @config, ondemand, continue
84
84
  end
85
85
 
86
86
  def wait_for_request(verbose, requestid)
@@ -140,8 +140,8 @@ class Service
140
140
  # some methods do not exist for ABS, and if possible should target the Pooler service
141
141
  def maybe_use_vmpooler
142
142
  if @service_object == ABS # this is not an instance
143
- if !self.silent
144
- FloatyLogger.info "The service in use is ABS, but the requested method should run against vmpooler directly, using fallback_vmpooler config from ~/.vmfloaty.yml"
143
+ unless silent
144
+ FloatyLogger.info 'The service in use is ABS, but the requested method should run against vmpooler directly, using fallback_vmpooler config from ~/.vmfloaty.yml'
145
145
  self.silent = true
146
146
  end
147
147