vmpooler 0.11.3 → 0.13.3
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 +285 -17
- data/lib/vmpooler/generic_connection_pool.rb +5 -23
- data/lib/vmpooler/graphite.rb +2 -0
- data/lib/vmpooler/pool_manager.rb +750 -389
- data/lib/vmpooler/providers/base.rb +2 -1
- data/lib/vmpooler/providers/dummy.rb +2 -2
- data/lib/vmpooler/providers/vsphere.rb +50 -30
- data/lib/vmpooler/util/parsing.rb +16 -0
- data/lib/vmpooler/version.rb +1 -1
- metadata +18 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fe0ef9bcf3e665cc952fce0975a4381883fca200ef93a883e54c7db7e1fc10e7
|
4
|
+
data.tar.gz: d44b61c41a57f940cf0df4bf07aabed10b1a72e91cae5b2105f092a7d98d6d05
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e0e7bbec11ceecc5fdee0fe15b3d37e290a6c884a708a6a5acb2e790d54fb1f1e24ec6966973f02bbecd204a29497e9c17ae3b8be26a0d3f15cec508a0d64532
|
7
|
+
data.tar.gz: 7302cf41676a65ff5d0bb4108a8f5ac03a96a92e3cd0ec56deee2f2a60d6e73f09eee569ef0f4140e3c27e81a16c3e2d24b951764a772bdeaa082a96d8bde1fe
|
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
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'vmpooler/util/parsing'
|
4
|
+
|
3
5
|
module Vmpooler
|
4
6
|
class API
|
5
7
|
class V1 < Sinatra::Base
|
@@ -42,6 +44,68 @@ module Vmpooler
|
|
42
44
|
Vmpooler::API.settings.checkoutlock
|
43
45
|
end
|
44
46
|
|
47
|
+
def get_template_aliases(template)
|
48
|
+
result = []
|
49
|
+
aliases = Vmpooler::API.settings.config[:alias]
|
50
|
+
if aliases
|
51
|
+
result += aliases[template] if aliases[template].is_a?(Array)
|
52
|
+
template_backends << aliases[template] if aliases[template].is_a?(String)
|
53
|
+
end
|
54
|
+
result
|
55
|
+
end
|
56
|
+
|
57
|
+
def get_pool_weights(template_backends)
|
58
|
+
pool_index = pool_index(pools)
|
59
|
+
weighted_pools = {}
|
60
|
+
template_backends.each do |t|
|
61
|
+
next unless pool_index.key? t
|
62
|
+
|
63
|
+
index = pool_index[t]
|
64
|
+
clone_target = pools[index]['clone_target'] || config['clone_target']
|
65
|
+
next unless config.key?('backend_weight')
|
66
|
+
|
67
|
+
weight = config['backend_weight'][clone_target]
|
68
|
+
if weight
|
69
|
+
weighted_pools[t] = weight
|
70
|
+
end
|
71
|
+
end
|
72
|
+
weighted_pools
|
73
|
+
end
|
74
|
+
|
75
|
+
def count_selection(selection)
|
76
|
+
result = {}
|
77
|
+
selection.uniq.each do |poolname|
|
78
|
+
result[poolname] = selection.count(poolname)
|
79
|
+
end
|
80
|
+
result
|
81
|
+
end
|
82
|
+
|
83
|
+
def evaluate_template_aliases(template, count)
|
84
|
+
template_backends = []
|
85
|
+
template_backends << template if backend.sismember('vmpooler__pools', template)
|
86
|
+
selection = []
|
87
|
+
aliases = get_template_aliases(template)
|
88
|
+
if aliases
|
89
|
+
template_backends += aliases
|
90
|
+
weighted_pools = get_pool_weights(template_backends)
|
91
|
+
|
92
|
+
pickup = Pickup.new(weighted_pools) if weighted_pools.count == template_backends.count
|
93
|
+
count.to_i.times do
|
94
|
+
if pickup
|
95
|
+
selection << pickup.pick
|
96
|
+
else
|
97
|
+
selection << template_backends.sample
|
98
|
+
end
|
99
|
+
end
|
100
|
+
else
|
101
|
+
count.to_i.times do
|
102
|
+
selection << template
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
count_selection(selection)
|
107
|
+
end
|
108
|
+
|
45
109
|
def fetch_single_vm(template)
|
46
110
|
template_backends = [template]
|
47
111
|
aliases = Vmpooler::API.settings.config[:alias]
|
@@ -245,11 +309,9 @@ module Vmpooler
|
|
245
309
|
pool_index = pool_index(pools)
|
246
310
|
template_configs = backend.hgetall('vmpooler__config__template')
|
247
311
|
template_configs&.each do |poolname, template|
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
end
|
252
|
-
end
|
312
|
+
next unless pool_index.include? poolname
|
313
|
+
|
314
|
+
pools[pool_index[poolname]]['template'] = template
|
253
315
|
end
|
254
316
|
end
|
255
317
|
|
@@ -257,11 +319,9 @@ module Vmpooler
|
|
257
319
|
pool_index = pool_index(pools)
|
258
320
|
poolsize_configs = backend.hgetall('vmpooler__config__poolsize')
|
259
321
|
poolsize_configs&.each do |poolname, size|
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
end
|
264
|
-
end
|
322
|
+
next unless pool_index.include? poolname
|
323
|
+
|
324
|
+
pools[pool_index[poolname]]['size'] = size.to_i
|
265
325
|
end
|
266
326
|
end
|
267
327
|
|
@@ -269,12 +329,70 @@ module Vmpooler
|
|
269
329
|
pool_index = pool_index(pools)
|
270
330
|
clone_target_configs = backend.hgetall('vmpooler__config__clone_target')
|
271
331
|
clone_target_configs&.each do |poolname, clone_target|
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
332
|
+
next unless pool_index.include? poolname
|
333
|
+
|
334
|
+
pools[pool_index[poolname]]['clone_target'] = clone_target
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
def too_many_requested?(payload)
|
339
|
+
payload&.each do |poolname, count|
|
340
|
+
next unless count.to_i > config['max_ondemand_instances_per_request']
|
341
|
+
|
342
|
+
metrics.increment('ondemandrequest.toomanyrequests.' + poolname)
|
343
|
+
return true
|
344
|
+
end
|
345
|
+
false
|
346
|
+
end
|
347
|
+
|
348
|
+
def generate_ondemand_request(payload)
|
349
|
+
result = { 'ok': false }
|
350
|
+
|
351
|
+
requested_instances = payload.reject { |k, _v| k == 'request_id' }
|
352
|
+
if too_many_requested?(requested_instances)
|
353
|
+
result['message'] = "requested amount of instances exceeds the maximum #{config['max_ondemand_instances_per_request']}"
|
354
|
+
status 403
|
355
|
+
return result
|
356
|
+
end
|
357
|
+
|
358
|
+
score = Time.now.to_i
|
359
|
+
request_id = payload['request_id']
|
360
|
+
request_id ||= generate_request_id
|
361
|
+
result['request_id'] = request_id
|
362
|
+
|
363
|
+
if backend.exists("vmpooler__odrequest__#{request_id}")
|
364
|
+
result['message'] = "request_id '#{request_id}' has already been created"
|
365
|
+
status 409
|
366
|
+
metrics.increment('ondemandrequest.generate.duplicaterequests')
|
367
|
+
return result
|
368
|
+
end
|
369
|
+
|
370
|
+
status 201
|
371
|
+
|
372
|
+
platforms_with_aliases = []
|
373
|
+
requested_instances.each do |poolname, count|
|
374
|
+
selection = evaluate_template_aliases(poolname, count)
|
375
|
+
selection.map { |selected_pool, selected_pool_count| platforms_with_aliases << "#{poolname}:#{selected_pool}:#{selected_pool_count}" }
|
376
|
+
end
|
377
|
+
platforms_string = platforms_with_aliases.join(',')
|
378
|
+
|
379
|
+
return result unless backend.zadd('vmpooler__provisioning__request', score, request_id)
|
380
|
+
|
381
|
+
backend.hset("vmpooler__odrequest__#{request_id}", 'requested', platforms_string)
|
382
|
+
if Vmpooler::API.settings.config[:auth] and has_token?
|
383
|
+
backend.hset("vmpooler__odrequest__#{request_id}", 'token:token', request.env['HTTP_X_AUTH_TOKEN'])
|
384
|
+
backend.hset("vmpooler__odrequest__#{request_id}", 'token:user',
|
385
|
+
backend.hget('vmpooler__token__' + request.env['HTTP_X_AUTH_TOKEN'], 'user'))
|
277
386
|
end
|
387
|
+
|
388
|
+
result['domain'] = config['domain'] if config['domain']
|
389
|
+
result[:ok] = true
|
390
|
+
metrics.increment('ondemandrequest.generate.success')
|
391
|
+
result
|
392
|
+
end
|
393
|
+
|
394
|
+
def generate_request_id
|
395
|
+
SecureRandom.uuid
|
278
396
|
end
|
279
397
|
|
280
398
|
get '/' do
|
@@ -395,7 +513,7 @@ module Vmpooler
|
|
395
513
|
end
|
396
514
|
|
397
515
|
# for backwards compatibility, include separate "empty" stats in "status" block
|
398
|
-
if ready == 0
|
516
|
+
if ready == 0 && max != 0
|
399
517
|
result[:status][:empty] ||= []
|
400
518
|
result[:status][:empty].push(pool['name'])
|
401
519
|
|
@@ -689,6 +807,88 @@ module Vmpooler
|
|
689
807
|
JSON.pretty_generate(result)
|
690
808
|
end
|
691
809
|
|
810
|
+
post "#{api_prefix}/ondemandvm/?" do
|
811
|
+
content_type :json
|
812
|
+
|
813
|
+
need_token! if Vmpooler::API.settings.config[:auth]
|
814
|
+
|
815
|
+
result = { 'ok' => false }
|
816
|
+
|
817
|
+
begin
|
818
|
+
payload = JSON.parse(request.body.read)
|
819
|
+
|
820
|
+
if payload
|
821
|
+
invalid = invalid_templates(payload.reject { |k, _v| k == 'request_id' })
|
822
|
+
if invalid.empty?
|
823
|
+
result = generate_ondemand_request(payload)
|
824
|
+
else
|
825
|
+
result[:bad_templates] = invalid
|
826
|
+
invalid.each do |bad_template|
|
827
|
+
metrics.increment('ondemandrequest.invalid.' + bad_template)
|
828
|
+
end
|
829
|
+
status 404
|
830
|
+
end
|
831
|
+
else
|
832
|
+
metrics.increment('ondemandrequest.invalid.unknown')
|
833
|
+
status 404
|
834
|
+
end
|
835
|
+
rescue JSON::ParserError
|
836
|
+
status 400
|
837
|
+
result = {
|
838
|
+
'ok' => false,
|
839
|
+
'message' => 'JSON payload could not be parsed'
|
840
|
+
}
|
841
|
+
end
|
842
|
+
|
843
|
+
JSON.pretty_generate(result)
|
844
|
+
end
|
845
|
+
|
846
|
+
post "#{api_prefix}/ondemandvm/:template/?" do
|
847
|
+
content_type :json
|
848
|
+
result = { 'ok' => false }
|
849
|
+
|
850
|
+
need_token! if Vmpooler::API.settings.config[:auth]
|
851
|
+
|
852
|
+
payload = extract_templates_from_query_params(params[:template])
|
853
|
+
|
854
|
+
if payload
|
855
|
+
invalid = invalid_templates(payload.reject { |k, _v| k == 'request_id' })
|
856
|
+
if invalid.empty?
|
857
|
+
result = generate_ondemand_request(payload)
|
858
|
+
else
|
859
|
+
result[:bad_templates] = invalid
|
860
|
+
invalid.each do |bad_template|
|
861
|
+
metrics.increment('ondemandrequest.invalid.' + bad_template)
|
862
|
+
end
|
863
|
+
status 404
|
864
|
+
end
|
865
|
+
else
|
866
|
+
metrics.increment('ondemandrequest.invalid.unknown')
|
867
|
+
status 404
|
868
|
+
end
|
869
|
+
|
870
|
+
JSON.pretty_generate(result)
|
871
|
+
end
|
872
|
+
|
873
|
+
get "#{api_prefix}/ondemandvm/:requestid/?" do
|
874
|
+
content_type :json
|
875
|
+
|
876
|
+
status 404
|
877
|
+
result = check_ondemand_request(params[:requestid])
|
878
|
+
|
879
|
+
JSON.pretty_generate(result)
|
880
|
+
end
|
881
|
+
|
882
|
+
delete "#{api_prefix}/ondemandvm/:requestid/?" do
|
883
|
+
content_type :json
|
884
|
+
need_token! if Vmpooler::API.settings.config[:auth]
|
885
|
+
|
886
|
+
status 404
|
887
|
+
result = delete_ondemand_request(params[:requestid])
|
888
|
+
|
889
|
+
JSON.pretty_generate(result)
|
890
|
+
end
|
891
|
+
|
692
892
|
post "#{api_prefix}/vm/?" do
|
693
893
|
content_type :json
|
694
894
|
result = { 'ok' => false }
|
@@ -764,6 +964,73 @@ module Vmpooler
|
|
764
964
|
invalid
|
765
965
|
end
|
766
966
|
|
967
|
+
def check_ondemand_request(request_id)
|
968
|
+
result = { 'ok' => false }
|
969
|
+
request_hash = backend.hgetall("vmpooler__odrequest__#{request_id}")
|
970
|
+
if request_hash.empty?
|
971
|
+
result['message'] = "no request found for request_id '#{request_id}'"
|
972
|
+
return result
|
973
|
+
end
|
974
|
+
|
975
|
+
result['request_id'] = request_id
|
976
|
+
result['ready'] = false
|
977
|
+
result['ok'] = true
|
978
|
+
status 202
|
979
|
+
|
980
|
+
if request_hash['status'] == 'ready'
|
981
|
+
result['ready'] = true
|
982
|
+
Parsing.get_platform_pool_count(request_hash['requested']) do |platform_alias, pool, _count|
|
983
|
+
instances = backend.smembers("vmpooler__#{request_id}__#{platform_alias}__#{pool}")
|
984
|
+
result[platform_alias] = { 'hostname': instances }
|
985
|
+
end
|
986
|
+
result['domain'] = config['domain'] if config['domain']
|
987
|
+
status 200
|
988
|
+
elsif request_hash['status'] == 'failed'
|
989
|
+
result['message'] = "The request failed to provision instances within the configured ondemand_request_ttl '#{config['ondemand_request_ttl']}'"
|
990
|
+
status 200
|
991
|
+
elsif request_hash['status'] == 'deleted'
|
992
|
+
result['message'] = 'The request has been deleted'
|
993
|
+
status 200
|
994
|
+
else
|
995
|
+
Parsing.get_platform_pool_count(request_hash['requested']) do |platform_alias, pool, count|
|
996
|
+
instance_count = backend.scard("vmpooler__#{request_id}__#{platform_alias}__#{pool}")
|
997
|
+
result[platform_alias] = {
|
998
|
+
'ready': instance_count.to_s,
|
999
|
+
'pending': (count.to_i - instance_count.to_i).to_s
|
1000
|
+
}
|
1001
|
+
end
|
1002
|
+
end
|
1003
|
+
|
1004
|
+
result
|
1005
|
+
end
|
1006
|
+
|
1007
|
+
def delete_ondemand_request(request_id)
|
1008
|
+
result = { 'ok' => false }
|
1009
|
+
|
1010
|
+
platforms = backend.hget("vmpooler__odrequest__#{request_id}", 'requested')
|
1011
|
+
unless platforms
|
1012
|
+
result['message'] = "no request found for request_id '#{request_id}'"
|
1013
|
+
return result
|
1014
|
+
end
|
1015
|
+
|
1016
|
+
if backend.hget("vmpooler__odrequest__#{request_id}", 'status') == 'deleted'
|
1017
|
+
result['message'] = 'the request has already been deleted'
|
1018
|
+
else
|
1019
|
+
backend.hset("vmpooler__odrequest__#{request_id}", 'status', 'deleted')
|
1020
|
+
|
1021
|
+
Parsing.get_platform_pool_count(platforms) do |platform_alias, pool, _count|
|
1022
|
+
backend.smembers("vmpooler__#{request_id}__#{platform_alias}__#{pool}")&.each do |vm|
|
1023
|
+
backend.smove("vmpooler__running__#{pool}", "vmpooler__completed__#{pool}", vm)
|
1024
|
+
end
|
1025
|
+
backend.del("vmpooler__#{request_id}__#{platform_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
|
+
|
767
1034
|
post "#{api_prefix}/vm/:template/?" do
|
768
1035
|
content_type :json
|
769
1036
|
result = { 'ok' => false }
|
@@ -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
|