vmpooler 0.11.1 → 0.13.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/bin/vmpooler +3 -1
- data/lib/vmpooler.rb +23 -1
- data/lib/vmpooler/api/helpers.rb +16 -16
- data/lib/vmpooler/api/v1.rb +294 -26
- data/lib/vmpooler/generic_connection_pool.rb +5 -23
- data/lib/vmpooler/pool_manager.rb +747 -384
- data/lib/vmpooler/providers/base.rb +2 -1
- data/lib/vmpooler/providers/dummy.rb +2 -2
- data/lib/vmpooler/providers/vsphere.rb +55 -35
- data/lib/vmpooler/version.rb +1 -1
- metadata +18 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3f6f3dafe8bbb4d65b5dc088ff36c24b12a3e6382aa2ec84f5a504e58e36eb6c
|
4
|
+
data.tar.gz: e488162ea027f566d44c762aa10095529d5610048bff7674e4695c16b37d61a1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3ba72cb12cce3ab544437948751662434ce936014fdb68e63bbd6484bcceddaade2918b51852a6fd7d8171ea9a28d14135102cbe23cbae521fcbeb7f40ad6f7a
|
7
|
+
data.tar.gz: 484fd410cd7f96bde01bc928e3afc4cb5fb9eeebffdda8ebf615fd0414d1db10a294f28afdacc0e5cac3cf7448fc8c3a4636b50b2d02c4dc017034da6a0c4f41
|
data/bin/vmpooler
CHANGED
@@ -7,6 +7,8 @@ config = Vmpooler.config
|
|
7
7
|
redis_host = config[:redis]['server']
|
8
8
|
redis_port = config[:redis]['port']
|
9
9
|
redis_password = config[:redis]['password']
|
10
|
+
redis_connection_pool_size = config[:redis]['connection_pool_size']
|
11
|
+
redis_connection_pool_timeout = config[:redis]['connection_pool_timeout']
|
10
12
|
logger_file = config[:config]['logfile']
|
11
13
|
|
12
14
|
metrics = Vmpooler.new_metrics(config)
|
@@ -36,7 +38,7 @@ if torun.include? 'manager'
|
|
36
38
|
Vmpooler::PoolManager.new(
|
37
39
|
config,
|
38
40
|
Vmpooler.new_logger(logger_file),
|
39
|
-
Vmpooler.
|
41
|
+
Vmpooler.redis_connection_pool(redis_host, redis_port, redis_password, redis_connection_pool_size, redis_connection_pool_timeout, metrics),
|
40
42
|
metrics
|
41
43
|
).execute!
|
42
44
|
end
|
data/lib/vmpooler.rb
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Vmpooler
|
4
|
+
require 'concurrent'
|
4
5
|
require 'date'
|
5
6
|
require 'json'
|
6
7
|
require 'net/ldap'
|
@@ -58,9 +59,14 @@ module Vmpooler
|
|
58
59
|
|
59
60
|
# Set some configuration defaults
|
60
61
|
parsed_config[:config]['task_limit'] = string_to_int(ENV['TASK_LIMIT']) || parsed_config[:config]['task_limit'] || 10
|
62
|
+
parsed_config[:config]['ondemand_clone_limit'] = string_to_int(ENV['ONDEMAND_CLONE_LIMIT']) || parsed_config[:config]['ondemand_clone_limit'] || 10
|
63
|
+
parsed_config[:config]['max_ondemand_instances_per_request'] = string_to_int(ENV['MAX_ONDEMAND_INSTANCES_PER_REQUEST']) || parsed_config[:config]['max_ondemand_instances_per_request'] || 10
|
61
64
|
parsed_config[:config]['migration_limit'] = string_to_int(ENV['MIGRATION_LIMIT']) if ENV['MIGRATION_LIMIT']
|
62
65
|
parsed_config[:config]['vm_checktime'] = string_to_int(ENV['VM_CHECKTIME']) || parsed_config[:config]['vm_checktime'] || 1
|
63
66
|
parsed_config[:config]['vm_lifetime'] = string_to_int(ENV['VM_LIFETIME']) || parsed_config[:config]['vm_lifetime'] || 24
|
67
|
+
parsed_config[:config]['max_lifetime_upper_limit'] = string_to_int(ENV['MAX_LIFETIME_UPPER_LIMIT']) || parsed_config[:config]['max_lifetime_upper_limit']
|
68
|
+
parsed_config[:config]['ready_ttl'] = string_to_int(ENV['READY_TTL']) || parsed_config[:config]['ready_ttl'] || 60
|
69
|
+
parsed_config[:config]['ondemand_request_ttl'] = string_to_int(ENV['ONDEMAND_REQUEST_TTL']) || parsed_config[:config]['ondemand_request_ttl'] || 5
|
64
70
|
parsed_config[:config]['prefix'] = ENV['PREFIX'] || parsed_config[:config]['prefix'] || ''
|
65
71
|
|
66
72
|
parsed_config[:config]['logfile'] = ENV['LOGFILE'] if ENV['LOGFILE']
|
@@ -72,7 +78,7 @@ module Vmpooler
|
|
72
78
|
parsed_config[:config]['vm_lifetime_auth'] = string_to_int(ENV['VM_LIFETIME_AUTH']) if ENV['VM_LIFETIME_AUTH']
|
73
79
|
parsed_config[:config]['max_tries'] = string_to_int(ENV['MAX_TRIES']) if ENV['MAX_TRIES']
|
74
80
|
parsed_config[:config]['retry_factor'] = string_to_int(ENV['RETRY_FACTOR']) if ENV['RETRY_FACTOR']
|
75
|
-
parsed_config[:config]['create_folders'] = ENV['CREATE_FOLDERS'] if ENV['CREATE_FOLDERS']
|
81
|
+
parsed_config[:config]['create_folders'] = true?(ENV['CREATE_FOLDERS']) if ENV['CREATE_FOLDERS']
|
76
82
|
parsed_config[:config]['create_template_delta_disks'] = ENV['CREATE_TEMPLATE_DELTA_DISKS'] if ENV['CREATE_TEMPLATE_DELTA_DISKS']
|
77
83
|
set_linked_clone(parsed_config)
|
78
84
|
parsed_config[:config]['experimental_features'] = ENV['EXPERIMENTAL_FEATURES'] if ENV['EXPERIMENTAL_FEATURES']
|
@@ -84,6 +90,8 @@ module Vmpooler
|
|
84
90
|
parsed_config[:redis]['port'] = string_to_int(ENV['REDIS_PORT']) if ENV['REDIS_PORT']
|
85
91
|
parsed_config[:redis]['password'] = ENV['REDIS_PASSWORD'] if ENV['REDIS_PASSWORD']
|
86
92
|
parsed_config[:redis]['data_ttl'] = string_to_int(ENV['REDIS_DATA_TTL']) || parsed_config[:redis]['data_ttl'] || 168
|
93
|
+
parsed_config[:redis]['connection_pool_size'] = string_to_int(ENV['REDIS_CONNECTION_POOL_SIZE']) || parsed_config[:redis]['connection_pool_size'] || 10
|
94
|
+
parsed_config[:redis]['connection_pool_timeout'] = string_to_int(ENV['REDIS_CONNECTION_POOL_TIMEOUT']) || parsed_config[:redis]['connection_pool_timeout'] || 5
|
87
95
|
|
88
96
|
parsed_config[:statsd] = parsed_config[:statsd] || {} if ENV['STATSD_SERVER']
|
89
97
|
parsed_config[:statsd]['server'] = ENV['STATSD_SERVER'] if ENV['STATSD_SERVER']
|
@@ -117,6 +125,7 @@ module Vmpooler
|
|
117
125
|
|
118
126
|
parsed_config[:pools].each do |pool|
|
119
127
|
parsed_config[:pool_names] << pool['name']
|
128
|
+
pool['ready_ttl'] ||= parsed_config[:config]['ready_ttl']
|
120
129
|
if pool['alias']
|
121
130
|
if pool['alias'].is_a?(Array)
|
122
131
|
pool['alias'].each do |pool_alias|
|
@@ -154,6 +163,19 @@ module Vmpooler
|
|
154
163
|
pools
|
155
164
|
end
|
156
165
|
|
166
|
+
def self.redis_connection_pool(host, port, password, size, timeout, metrics)
|
167
|
+
Vmpooler::PoolManager::GenericConnectionPool.new(
|
168
|
+
metrics: metrics,
|
169
|
+
metric_prefix: 'redis_connection_pool',
|
170
|
+
size: size,
|
171
|
+
timeout: timeout
|
172
|
+
) do
|
173
|
+
connection = Concurrent::Hash.new
|
174
|
+
redis = new_redis(host, port, password)
|
175
|
+
connection['connection'] = redis
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
157
179
|
def self.new_redis(host = 'localhost', port = nil, password = nil)
|
158
180
|
Redis.new(host: host, port: port, password: password)
|
159
181
|
end
|
data/lib/vmpooler/api/helpers.rb
CHANGED
@@ -84,29 +84,29 @@ module Vmpooler
|
|
84
84
|
when 'ldap'
|
85
85
|
ldap_base = auth[:ldap]['base']
|
86
86
|
ldap_port = auth[:ldap]['port'] || 389
|
87
|
+
ldap_user_obj = auth[:ldap]['user_object']
|
88
|
+
ldap_host = auth[:ldap]['host']
|
87
89
|
|
88
|
-
|
89
|
-
ldap_base
|
90
|
+
unless ldap_base.is_a? Array
|
91
|
+
ldap_base = ldap_base.split
|
92
|
+
end
|
93
|
+
|
94
|
+
unless ldap_user_obj.is_a? Array
|
95
|
+
ldap_user_obj = ldap_user_obj.split
|
96
|
+
end
|
97
|
+
|
98
|
+
ldap_base.each do |search_base|
|
99
|
+
ldap_user_obj.each do |search_user_obj|
|
90
100
|
result = authenticate_ldap(
|
91
101
|
ldap_port,
|
92
|
-
|
93
|
-
|
102
|
+
ldap_host,
|
103
|
+
search_user_obj,
|
94
104
|
search_base,
|
95
105
|
username_str,
|
96
106
|
password_str
|
97
107
|
)
|
98
|
-
return true if result
|
108
|
+
return true if result
|
99
109
|
end
|
100
|
-
else
|
101
|
-
result = authenticate_ldap(
|
102
|
-
ldap_port,
|
103
|
-
auth[:ldap]['host'],
|
104
|
-
auth[:ldap]['user_object'],
|
105
|
-
ldap_base,
|
106
|
-
username_str,
|
107
|
-
password_str
|
108
|
-
)
|
109
|
-
return result
|
110
110
|
end
|
111
111
|
|
112
112
|
return false
|
@@ -238,7 +238,7 @@ module Vmpooler
|
|
238
238
|
queue[:running] = get_total_across_pools_redis_scard(pools, 'vmpooler__running__', backend)
|
239
239
|
queue[:completed] = get_total_across_pools_redis_scard(pools, 'vmpooler__completed__', backend)
|
240
240
|
|
241
|
-
queue[:cloning] = backend.get('vmpooler__tasks__clone').to_i
|
241
|
+
queue[:cloning] = backend.get('vmpooler__tasks__clone').to_i + backend.get('vmpooler__tasks__ondemandclone').to_i
|
242
242
|
queue[:booting] = queue[:pending].to_i - queue[:cloning].to_i
|
243
243
|
queue[:booting] = 0 if queue[:booting] < 0
|
244
244
|
queue[:total] = queue[:pending].to_i + queue[:ready].to_i + queue[:running].to_i + queue[:completed].to_i
|
data/lib/vmpooler/api/v1.rb
CHANGED
@@ -42,6 +42,68 @@ module Vmpooler
|
|
42
42
|
Vmpooler::API.settings.checkoutlock
|
43
43
|
end
|
44
44
|
|
45
|
+
def get_template_aliases(template)
|
46
|
+
result = []
|
47
|
+
aliases = Vmpooler::API.settings.config[:alias]
|
48
|
+
if aliases
|
49
|
+
result += aliases[template] if aliases[template].is_a?(Array)
|
50
|
+
template_backends << aliases[template] if aliases[template].is_a?(String)
|
51
|
+
end
|
52
|
+
result
|
53
|
+
end
|
54
|
+
|
55
|
+
def get_pool_weights(template_backends)
|
56
|
+
pool_index = pool_index(pools)
|
57
|
+
weighted_pools = {}
|
58
|
+
template_backends.each do |t|
|
59
|
+
next unless pool_index.key? t
|
60
|
+
|
61
|
+
index = pool_index[t]
|
62
|
+
clone_target = pools[index]['clone_target'] || config['clone_target']
|
63
|
+
next unless config.key?('backend_weight')
|
64
|
+
|
65
|
+
weight = config['backend_weight'][clone_target]
|
66
|
+
if weight
|
67
|
+
weighted_pools[t] = weight
|
68
|
+
end
|
69
|
+
end
|
70
|
+
weighted_pools
|
71
|
+
end
|
72
|
+
|
73
|
+
def count_selection(selection)
|
74
|
+
result = {}
|
75
|
+
selection.uniq.each do |poolname|
|
76
|
+
result[poolname] = selection.count(poolname)
|
77
|
+
end
|
78
|
+
result
|
79
|
+
end
|
80
|
+
|
81
|
+
def evaluate_template_aliases(template, count)
|
82
|
+
template_backends = []
|
83
|
+
template_backends << template if backend.sismember('vmpooler__pools', template)
|
84
|
+
selection = []
|
85
|
+
aliases = get_template_aliases(template)
|
86
|
+
if aliases
|
87
|
+
template_backends += aliases
|
88
|
+
weighted_pools = get_pool_weights(template_backends)
|
89
|
+
|
90
|
+
pickup = Pickup.new(weighted_pools) if weighted_pools.count == template_backends.count
|
91
|
+
count.to_i.times do
|
92
|
+
if pickup
|
93
|
+
selection << pickup.pick
|
94
|
+
else
|
95
|
+
selection << template_backends.sample
|
96
|
+
end
|
97
|
+
end
|
98
|
+
else
|
99
|
+
count.to_i.times do
|
100
|
+
selection << template
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
count_selection(selection)
|
105
|
+
end
|
106
|
+
|
45
107
|
def fetch_single_vm(template)
|
46
108
|
template_backends = [template]
|
47
109
|
aliases = Vmpooler::API.settings.config[:alias]
|
@@ -83,8 +145,13 @@ module Vmpooler
|
|
83
145
|
vms.reverse.each do |vm|
|
84
146
|
ready = vm_ready?(vm, config['domain'])
|
85
147
|
if ready
|
86
|
-
backend.smove("vmpooler__ready__#{template_backend}", "vmpooler__running__#{template_backend}", vm)
|
87
|
-
|
148
|
+
smoved = backend.smove("vmpooler__ready__#{template_backend}", "vmpooler__running__#{template_backend}", vm)
|
149
|
+
if smoved
|
150
|
+
return [vm, template_backend, template]
|
151
|
+
else
|
152
|
+
metrics.increment("checkout.smove.failed.#{template_backend}")
|
153
|
+
return [nil, nil, nil]
|
154
|
+
end
|
88
155
|
else
|
89
156
|
backend.smove("vmpooler__ready__#{template_backend}", "vmpooler__completed__#{template_backend}", vm)
|
90
157
|
metrics.increment("checkout.nonresponsive.#{template_backend}")
|
@@ -240,11 +307,9 @@ module Vmpooler
|
|
240
307
|
pool_index = pool_index(pools)
|
241
308
|
template_configs = backend.hgetall('vmpooler__config__template')
|
242
309
|
template_configs&.each do |poolname, template|
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
end
|
247
|
-
end
|
310
|
+
next unless pool_index.include? poolname
|
311
|
+
|
312
|
+
pools[pool_index[poolname]]['template'] = template
|
248
313
|
end
|
249
314
|
end
|
250
315
|
|
@@ -252,11 +317,9 @@ module Vmpooler
|
|
252
317
|
pool_index = pool_index(pools)
|
253
318
|
poolsize_configs = backend.hgetall('vmpooler__config__poolsize')
|
254
319
|
poolsize_configs&.each do |poolname, size|
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
end
|
259
|
-
end
|
320
|
+
next unless pool_index.include? poolname
|
321
|
+
|
322
|
+
pools[pool_index[poolname]]['size'] = size.to_i
|
260
323
|
end
|
261
324
|
end
|
262
325
|
|
@@ -264,12 +327,67 @@ module Vmpooler
|
|
264
327
|
pool_index = pool_index(pools)
|
265
328
|
clone_target_configs = backend.hgetall('vmpooler__config__clone_target')
|
266
329
|
clone_target_configs&.each do |poolname, clone_target|
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
330
|
+
next unless pool_index.include? poolname
|
331
|
+
|
332
|
+
pools[pool_index[poolname]]['clone_target'] = clone_target
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
def too_many_requested?(payload)
|
337
|
+
payload&.each do |_poolname, count|
|
338
|
+
next unless count.to_i > config['max_ondemand_instances_per_request']
|
339
|
+
|
340
|
+
return true
|
341
|
+
end
|
342
|
+
false
|
343
|
+
end
|
344
|
+
|
345
|
+
def generate_ondemand_request(payload)
|
346
|
+
result = { 'ok': false }
|
347
|
+
|
348
|
+
requested_instances = payload.reject { |k, _v| k == 'request_id' }
|
349
|
+
if too_many_requested?(requested_instances)
|
350
|
+
result['message'] = "requested amount of instances exceeds the maximum #{config['max_ondemand_instances_per_request']}"
|
351
|
+
status 403
|
352
|
+
return result
|
353
|
+
end
|
354
|
+
|
355
|
+
score = Time.now.to_i
|
356
|
+
request_id = payload['request_id']
|
357
|
+
request_id ||= generate_request_id
|
358
|
+
result['request_id'] = request_id
|
359
|
+
|
360
|
+
if backend.exists("vmpooler__odrequest__#{request_id}")
|
361
|
+
result['message'] = "request_id '#{request_id}' has already been created"
|
362
|
+
status 409
|
363
|
+
return result
|
364
|
+
end
|
365
|
+
|
366
|
+
status 201
|
367
|
+
|
368
|
+
platforms_with_aliases = []
|
369
|
+
requested_instances.each do |poolname, count|
|
370
|
+
selection = evaluate_template_aliases(poolname, count)
|
371
|
+
selection.map { |selected_pool, selected_pool_count| platforms_with_aliases << "#{poolname}:#{selected_pool}:#{selected_pool_count}" }
|
372
|
+
end
|
373
|
+
platforms_string = platforms_with_aliases.join(',')
|
374
|
+
|
375
|
+
return result unless backend.zadd('vmpooler__provisioning__request', score, request_id)
|
376
|
+
|
377
|
+
backend.hset("vmpooler__odrequest__#{request_id}", 'requested', platforms_string)
|
378
|
+
if Vmpooler::API.settings.config[:auth] and has_token?
|
379
|
+
backend.hset("vmpooler__odrequest__#{request_id}", 'token:token', request.env['HTTP_X_AUTH_TOKEN'])
|
380
|
+
backend.hset("vmpooler__odrequest__#{request_id}", 'token:user',
|
381
|
+
backend.hget('vmpooler__token__' + request.env['HTTP_X_AUTH_TOKEN'], 'user'))
|
272
382
|
end
|
383
|
+
|
384
|
+
result['domain'] = config['domain'] if config['domain']
|
385
|
+
result[:ok] = true
|
386
|
+
result
|
387
|
+
end
|
388
|
+
|
389
|
+
def generate_request_id
|
390
|
+
SecureRandom.uuid
|
273
391
|
end
|
274
392
|
|
275
393
|
get '/' do
|
@@ -390,7 +508,7 @@ module Vmpooler
|
|
390
508
|
end
|
391
509
|
|
392
510
|
# for backwards compatibility, include separate "empty" stats in "status" block
|
393
|
-
if ready == 0
|
511
|
+
if ready == 0 && max != 0
|
394
512
|
result[:status][:empty] ||= []
|
395
513
|
result[:status][:empty].push(pool['name'])
|
396
514
|
|
@@ -684,6 +802,88 @@ module Vmpooler
|
|
684
802
|
JSON.pretty_generate(result)
|
685
803
|
end
|
686
804
|
|
805
|
+
post "#{api_prefix}/ondemandvm/?" do
|
806
|
+
content_type :json
|
807
|
+
|
808
|
+
need_token! if Vmpooler::API.settings.config[:auth]
|
809
|
+
|
810
|
+
result = { 'ok' => false }
|
811
|
+
|
812
|
+
begin
|
813
|
+
payload = JSON.parse(request.body.read)
|
814
|
+
|
815
|
+
if payload
|
816
|
+
invalid = invalid_templates(payload.reject { |k, _v| k == 'request_id' })
|
817
|
+
if invalid.empty?
|
818
|
+
result = generate_ondemand_request(payload)
|
819
|
+
else
|
820
|
+
result[:bad_templates] = invalid
|
821
|
+
invalid.each do |bad_template|
|
822
|
+
metrics.increment('ondemandrequest.invalid.' + bad_template)
|
823
|
+
end
|
824
|
+
status 404
|
825
|
+
end
|
826
|
+
else
|
827
|
+
metrics.increment('ondemandrequest.invalid.unknown')
|
828
|
+
status 404
|
829
|
+
end
|
830
|
+
rescue JSON::ParserError
|
831
|
+
status 400
|
832
|
+
result = {
|
833
|
+
'ok' => false,
|
834
|
+
'message' => 'JSON payload could not be parsed'
|
835
|
+
}
|
836
|
+
end
|
837
|
+
|
838
|
+
JSON.pretty_generate(result)
|
839
|
+
end
|
840
|
+
|
841
|
+
post "#{api_prefix}/ondemandvm/:template/?" do
|
842
|
+
content_type :json
|
843
|
+
result = { 'ok' => false }
|
844
|
+
|
845
|
+
need_token! if Vmpooler::API.settings.config[:auth]
|
846
|
+
|
847
|
+
payload = extract_templates_from_query_params(params[:template])
|
848
|
+
|
849
|
+
if payload
|
850
|
+
invalid = invalid_templates(payload.reject { |k, _v| k == 'request_id' })
|
851
|
+
if invalid.empty?
|
852
|
+
result = generate_ondemand_request(payload)
|
853
|
+
else
|
854
|
+
result[:bad_templates] = invalid
|
855
|
+
invalid.each do |bad_template|
|
856
|
+
metrics.increment('ondemandrequest.invalid.' + bad_template)
|
857
|
+
end
|
858
|
+
status 404
|
859
|
+
end
|
860
|
+
else
|
861
|
+
metrics.increment('ondemandrequest.invalid.unknown')
|
862
|
+
status 404
|
863
|
+
end
|
864
|
+
|
865
|
+
JSON.pretty_generate(result)
|
866
|
+
end
|
867
|
+
|
868
|
+
get "#{api_prefix}/ondemandvm/:requestid/?" do
|
869
|
+
content_type :json
|
870
|
+
|
871
|
+
status 404
|
872
|
+
result = check_ondemand_request(params[:requestid])
|
873
|
+
|
874
|
+
JSON.pretty_generate(result)
|
875
|
+
end
|
876
|
+
|
877
|
+
delete "#{api_prefix}/ondemandvm/:requestid/?" do
|
878
|
+
content_type :json
|
879
|
+
need_token! if Vmpooler::API.settings.config[:auth]
|
880
|
+
|
881
|
+
status 404
|
882
|
+
result = delete_ondemand_request(params[:requestid])
|
883
|
+
|
884
|
+
JSON.pretty_generate(result)
|
885
|
+
end
|
886
|
+
|
687
887
|
post "#{api_prefix}/vm/?" do
|
688
888
|
content_type :json
|
689
889
|
result = { 'ok' => false }
|
@@ -759,6 +959,78 @@ module Vmpooler
|
|
759
959
|
invalid
|
760
960
|
end
|
761
961
|
|
962
|
+
def check_ondemand_request(request_id)
|
963
|
+
result = { 'ok' => false }
|
964
|
+
request_hash = backend.hgetall("vmpooler__odrequest__#{request_id}")
|
965
|
+
if request_hash.empty?
|
966
|
+
result['message'] = "no request found for request_id '#{request_id}'"
|
967
|
+
return result
|
968
|
+
end
|
969
|
+
|
970
|
+
result['request_id'] = request_id
|
971
|
+
result['ready'] = false
|
972
|
+
result['ok'] = true
|
973
|
+
status 202
|
974
|
+
|
975
|
+
if request_hash['status'] == 'ready'
|
976
|
+
result['ready'] = true
|
977
|
+
platform_parts = request_hash['requested'].split(',')
|
978
|
+
platform_parts.each do |platform|
|
979
|
+
pool_alias, pool, _count = platform.split(':')
|
980
|
+
instances = backend.smembers("vmpooler__#{request_id}__#{pool_alias}__#{pool}")
|
981
|
+
result[pool_alias] = { 'hostname': instances }
|
982
|
+
end
|
983
|
+
result['domain'] = config['domain'] if config['domain']
|
984
|
+
status 200
|
985
|
+
elsif request_hash['status'] == 'failed'
|
986
|
+
result['message'] = "The request failed to provision instances within the configured ondemand_request_ttl '#{config['ondemand_request_ttl']}'"
|
987
|
+
status 200
|
988
|
+
elsif request_hash['status'] == 'deleted'
|
989
|
+
result['message'] = 'The request has been deleted'
|
990
|
+
status 200
|
991
|
+
else
|
992
|
+
platform_parts = request_hash['requested'].split(',')
|
993
|
+
platform_parts.each do |platform|
|
994
|
+
pool_alias, pool, count = platform.split(':')
|
995
|
+
instance_count = backend.scard("vmpooler__#{request_id}__#{pool_alias}__#{pool}")
|
996
|
+
result[pool_alias] = {
|
997
|
+
'ready': instance_count.to_s,
|
998
|
+
'pending': (count.to_i - instance_count.to_i).to_s
|
999
|
+
}
|
1000
|
+
end
|
1001
|
+
end
|
1002
|
+
|
1003
|
+
result
|
1004
|
+
end
|
1005
|
+
|
1006
|
+
def delete_ondemand_request(request_id)
|
1007
|
+
result = { 'ok' => false }
|
1008
|
+
|
1009
|
+
platforms = backend.hget("vmpooler__odrequest__#{request_id}", 'requested')
|
1010
|
+
unless platforms
|
1011
|
+
result['message'] = "no request found for request_id '#{request_id}'"
|
1012
|
+
return result
|
1013
|
+
end
|
1014
|
+
|
1015
|
+
if backend.hget("vmpooler__odrequest__#{request_id}", 'status') == 'deleted'
|
1016
|
+
result['message'] = 'the request has already been deleted'
|
1017
|
+
else
|
1018
|
+
backend.hset("vmpooler__odrequest__#{request_id}", 'status', 'deleted')
|
1019
|
+
|
1020
|
+
platforms.split(',').each do |platform|
|
1021
|
+
pool_alias, pool, _count = platform.split(':')
|
1022
|
+
backend.smembers("vmpooler__#{request_id}__#{pool_alias}__#{pool}")&.each do |vm|
|
1023
|
+
backend.smove("vmpooler__running__#{pool}", "vmpooler__completed__#{pool}", vm)
|
1024
|
+
end
|
1025
|
+
backend.del("vmpooler__#{request_id}__#{pool_alias}__#{pool}")
|
1026
|
+
end
|
1027
|
+
backend.expire("vmpooler__odrequest__#{request_id}", 129_600_0)
|
1028
|
+
end
|
1029
|
+
status 200
|
1030
|
+
result['ok'] = true
|
1031
|
+
result
|
1032
|
+
end
|
1033
|
+
|
762
1034
|
post "#{api_prefix}/vm/:template/?" do
|
763
1035
|
content_type :json
|
764
1036
|
result = { 'ok' => false }
|
@@ -874,6 +1146,8 @@ module Vmpooler
|
|
874
1146
|
|
875
1147
|
status 200
|
876
1148
|
result['ok'] = true
|
1149
|
+
else
|
1150
|
+
metrics.increment('delete.srem.failed')
|
877
1151
|
end
|
878
1152
|
end
|
879
1153
|
|
@@ -909,13 +1183,6 @@ module Vmpooler
|
|
909
1183
|
max_lifetime_upper_limit = max_lifetime_upper_limit.to_i
|
910
1184
|
if arg.to_i >= max_lifetime_upper_limit
|
911
1185
|
failure.push("You provided a lifetime (#{arg}) that exceeds the configured maximum of #{max_lifetime_upper_limit}.")
|
912
|
-
else
|
913
|
-
# also make sure we do not extend past max_lifetime_upper_limit
|
914
|
-
rdata = backend.hgetall('vmpooler__vm__' + params[:hostname])
|
915
|
-
running = ((Time.now - Time.parse(rdata['checkout'])) / 60 / 60).round(2)
|
916
|
-
unless running + arg.to_i < max_lifetime_upper_limit
|
917
|
-
failure.push("You provided a lifetime (#{arg}) that will extend the current lifetime past the configured maximum of #{max_lifetime_upper_limit}.")
|
918
|
-
end
|
919
1186
|
end
|
920
1187
|
end
|
921
1188
|
|
@@ -923,6 +1190,7 @@ module Vmpooler
|
|
923
1190
|
unless arg.to_i > 0
|
924
1191
|
failure.push("You provided a lifetime (#{arg}) but you must provide a positive number.")
|
925
1192
|
end
|
1193
|
+
|
926
1194
|
when 'tags'
|
927
1195
|
unless arg.is_a?(Hash)
|
928
1196
|
failure.push("You provided tags (#{arg}) as something other than a hash.")
|
@@ -1047,7 +1315,7 @@ module Vmpooler
|
|
1047
1315
|
invalid.each do |bad_template|
|
1048
1316
|
metrics.increment("config.invalid.#{bad_template}")
|
1049
1317
|
end
|
1050
|
-
result[:
|
1318
|
+
result[:not_configured] = invalid
|
1051
1319
|
status 400
|
1052
1320
|
end
|
1053
1321
|
else
|