vmpooler 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2d15d54a0e93ce0f012a9272b1c1488421f83ce995cd07b452be405ce3c35011
4
- data.tar.gz: a41a95de2c2d630093efdc2accb9dbf63676b82b2a94488f9258825f0edc908c
3
+ metadata.gz: b65cd0483ea44e3ad8642c8c6ed8e22825601c5e707f7e277795eebb76057dd1
4
+ data.tar.gz: 1244464e0d901dac2878364dcd37a0e5c67ec19ae7736064751889913e8997c8
5
5
  SHA512:
6
- metadata.gz: 3dc7ee891431e86ed4748dbea9ad65836fab7924984a8c764fa5aef8a147f1b67f85d9325d3e79ebeef74bc72daae3d02c0af2aec94d242182050737206e2c61
7
- data.tar.gz: 2a1cca6c6525e2896e7d1fe613f9782d00445e859aea9248548e3e27f1170bb1f7eecfba798f7dda68834489889bd82c5de31e9b5da0f536babad5df336b4768
6
+ metadata.gz: cbc749d93c4da92e0009ccd8e792067b088fa024209355d7e9a71a8357dd91de05be6c3b62704adcace89da7b99328a9b282edc1be8b2e6753dc69f709625db9
7
+ data.tar.gz: d7c8071069919512beb841dd3ad453f0e12020565464fc62f24beff4353cffe9c997d2b0a805dde6eddc42fe00a7784eec82a319a8b7954e56f683a1bf856c05
@@ -147,12 +147,12 @@ module Vmpooler
147
147
 
148
148
  def export_tags(backend, hostname, tags)
149
149
  tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
150
- backend.pipelined do
150
+ backend.pipelined do |pipeline|
151
151
  tags.each_pair do |tag, value|
152
152
  next if value.nil? or value.empty?
153
153
 
154
- backend.hset("vmpooler__vm__#{hostname}", "tag:#{tag}", value)
155
- backend.hset("vmpooler__tag__#{Date.today}", "#{hostname}:#{tag}", value)
154
+ pipeline.hset("vmpooler__vm__#{hostname}", "tag:#{tag}", value)
155
+ pipeline.hset("vmpooler__tag__#{Date.today}", "#{hostname}:#{tag}", value)
156
156
  end
157
157
  end
158
158
  end
@@ -184,6 +184,8 @@ module Vmpooler
184
184
  def hostname_shorten(hostname, domain=nil)
185
185
  if domain && hostname =~ /^[\w-]+\.#{domain}$/
186
186
  hostname = hostname[/[^.]+/]
187
+ elsif hostname =~ /^[\w-]+\..+$/
188
+ hostname = hostname[/[^.]+/]
187
189
  end
188
190
 
189
191
  hostname
@@ -201,9 +203,9 @@ module Vmpooler
201
203
  tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
202
204
  # using pipelined is much faster than querying each of the pools and adding them
203
205
  # as we get the result.
204
- res = backend.pipelined do
206
+ res = backend.pipelined do |pipeline|
205
207
  pools.each do |pool|
206
- backend.scard(key + pool['name'])
208
+ pipeline.scard(key + pool['name'])
207
209
  end
208
210
  end
209
211
  res.inject(0) { |m, x| m + x }.to_i
@@ -217,9 +219,9 @@ module Vmpooler
217
219
  # using pipelined is much faster than querying each of the pools and adding them
218
220
  # as we get the result.
219
221
  temp_hash = {}
220
- res = backend.pipelined do
222
+ res = backend.pipelined do |pipeline|
221
223
  pools.each do |pool|
222
- backend.scard(key + pool['name'])
224
+ pipeline.scard(key + pool['name'])
223
225
  end
224
226
  end
225
227
  pools.each_with_index do |pool, i|
@@ -236,9 +238,9 @@ module Vmpooler
236
238
  # using pipelined is much faster than querying each of the pools and adding them
237
239
  # as we get the result.
238
240
  temp_hash = {}
239
- res = backend.pipelined do
241
+ res = backend.pipelined do |pipeline|
240
242
  pools.each do |pool|
241
- backend.hget(key, pool['name'])
243
+ pipeline.hget(key, pool['name'])
242
244
  end
243
245
  end
244
246
  pools.each_with_index do |pool, i|
@@ -6,66 +6,82 @@ module Vmpooler
6
6
  api_version = '1'
7
7
 
8
8
  get '/status/?' do
9
+ puts "DEPRECATION WARNING a client (#{request.user_agent}) called /status/? and got redirected to api_version=1, this behavior will change in the next major version, please modify the client to use v2 in advance"
9
10
  call env.merge('PATH_INFO' => "/api/v#{api_version}/status")
10
11
  end
11
12
 
12
13
  get '/summary/?' do
14
+ puts "DEPRECATION WARNING a client (#{request.user_agent}) called /summary/? and got redirected to api_version=1, this behavior will change in the next major version, please modify the client to use v2 in advance"
13
15
  call env.merge('PATH_INFO' => "/api/v#{api_version}/summary")
14
16
  end
15
17
 
16
18
  get '/summary/:route/?:key?/?' do
19
+ puts "DEPRECATION WARNING a client (#{request.user_agent}) called /summary/:route/?:key?/? and got redirected to api_version=1, this behavior will change in the next major version, please modify the client to use v2 in advance"
17
20
  call env.merge('PATH_INFO' => "/api/v#{api_version}/summary/#{params[:route]}/#{params[:key]}")
18
21
  end
19
22
 
20
23
  get '/token/?' do
24
+ puts "DEPRECATION WARNING a client (#{request.user_agent}) called /token/? and got redirected to api_version=1, this behavior will change in the next major version, please modify the client to use v2 in advance"
21
25
  call env.merge('PATH_INFO' => "/api/v#{api_version}/token")
22
26
  end
23
27
 
24
28
  post '/token/?' do
29
+ puts "DEPRECATION WARNING a client (#{request.user_agent}) called post /token/? and got redirected to api_version=1, this behavior will change in the next major version, please modify the client to use v2 in advance"
25
30
  call env.merge('PATH_INFO' => "/api/v#{api_version}/token")
26
31
  end
27
32
 
28
33
  get '/token/:token/?' do
34
+ puts "DEPRECATION WARNING a client (#{request.user_agent}) called /token/:token/? and got redirected to api_version=1, this behavior will change in the next major version, please modify the client to use v2 in advance"
29
35
  call env.merge('PATH_INFO' => "/api/v#{api_version}/token/#{params[:token]}")
30
36
  end
31
37
 
32
38
  delete '/token/:token/?' do
39
+ puts "DEPRECATION WARNING a client (#{request.user_agent}) called delete /token/:token/? and got redirected to api_version=1, this behavior will change in the next major version, please modify the client to use v2 in advance"
33
40
  call env.merge('PATH_INFO' => "/api/v#{api_version}/token/#{params[:token]}")
34
41
  end
35
42
 
36
43
  get '/vm/?' do
44
+ puts "DEPRECATION WARNING a client (#{request.user_agent}) called /vm? and got redirected to api_version=1, this behavior will change in the next major version, please modify the client to use v2 in advance"
37
45
  call env.merge('PATH_INFO' => "/api/v#{api_version}/vm")
38
46
  end
39
47
 
40
48
  post '/vm/?' do
49
+ puts "DEPRECATION WARNING a client (#{request.user_agent}) called post /vm? and got redirected to api_version=1, this behavior will change in the next major version, please modify the client to use v2 in advance"
41
50
  call env.merge('PATH_INFO' => "/api/v#{api_version}/vm")
42
51
  end
43
52
 
44
53
  post '/vm/:template/?' do
54
+ puts "DEPRECATION WARNING a client (#{request.user_agent}) called post /vm/:template/? and got redirected to api_version=1, this behavior will change in the next major version, please modify the client to use v2 in advance"
45
55
  call env.merge('PATH_INFO' => "/api/v#{api_version}/vm/#{params[:template]}")
46
56
  end
47
57
 
48
58
  get '/vm/:hostname/?' do
59
+ puts "DEPRECATION WARNING a client (#{request.user_agent}) called /vm/:hostname/? and got redirected to api_version=1, this behavior will change in the next major version, please modify the client to use v2 in advance"
49
60
  call env.merge('PATH_INFO' => "/api/v#{api_version}/vm/#{params[:hostname]}")
50
61
  end
51
62
 
52
63
  delete '/vm/:hostname/?' do
64
+ puts "DEPRECATION WARNING a client (#{request.user_agent}) called delete /vm/:hostname/? and got redirected to api_version=1, this behavior will change in the next major version, please modify the client to use v2 in advance"
53
65
  call env.merge('PATH_INFO' => "/api/v#{api_version}/vm/#{params[:hostname]}")
54
66
  end
55
67
 
56
68
  put '/vm/:hostname/?' do
69
+ puts "DEPRECATION WARNING a client (#{request.user_agent}) called put /vm/:hostname/? and got redirected to api_version=1, this behavior will change in the next major version, please modify the client to use v2 in advance"
57
70
  call env.merge('PATH_INFO' => "/api/v#{api_version}/vm/#{params[:hostname]}")
58
71
  end
59
72
 
60
73
  post '/vm/:hostname/snapshot/?' do
74
+ puts "DEPRECATION WARNING a client (#{request.user_agent}) called post /vm/:hostname/snapshot/? and got redirected to api_version=1, this behavior will change in the next major version, please modify the client to use v2 in advance"
61
75
  call env.merge('PATH_INFO' => "/api/v#{api_version}/vm/#{params[:hostname]}/snapshot")
62
76
  end
63
77
 
64
78
  post '/vm/:hostname/snapshot/:snapshot/?' do
79
+ puts "DEPRECATION WARNING a client (#{request.user_agent}) called post /vm/:hostname/snapshot/:snapshot/? and got redirected to api_version=1, this behavior will change in the next major version, please modify the client to use v2 in advance"
65
80
  call env.merge('PATH_INFO' => "/api/v#{api_version}/vm/#{params[:hostname]}/snapshot/#{params[:snapshot]}")
66
81
  end
67
82
 
68
83
  put '/vm/:hostname/disk/:size/?' do
84
+ puts "DEPRECATION WARNING a client (#{request.user_agent}) called put /vm/:hostname/disk/:size/? and got redirected to api_version=1, this behavior will change in the next major version, please modify the client to use v2 in advance"
69
85
  call env.merge('PATH_INFO' => "/api/v#{api_version}/vm/#{params[:hostname]}/disk/#{params[:size]}")
70
86
  end
71
87
  end
@@ -24,6 +24,10 @@ module Vmpooler
24
24
  Vmpooler::API.settings.config[:config]
25
25
  end
26
26
 
27
+ def full_config
28
+ Vmpooler::API.settings.config
29
+ end
30
+
27
31
  def pools
28
32
  Vmpooler::API.settings.config[:pools]
29
33
  end
@@ -1734,6 +1738,20 @@ module Vmpooler
1734
1738
  end
1735
1739
  JSON.pretty_generate(result)
1736
1740
  end
1741
+
1742
+ get "#{api_prefix}/full_config/?" do
1743
+ content_type :json
1744
+
1745
+ result = {
1746
+ full_config: full_config,
1747
+ status: {
1748
+ ok: true
1749
+ }
1750
+ }
1751
+
1752
+ status 200
1753
+ JSON.pretty_generate(result)
1754
+ end
1737
1755
  end
1738
1756
  end
1739
1757
  end
@@ -0,0 +1,429 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'vmpooler/api/v1'
4
+
5
+ module Vmpooler
6
+ class API
7
+ class V2 < Vmpooler::API::V1
8
+ api_version = '2'
9
+ api_prefix = "/api/v#{api_version}"
10
+
11
+ def full_config
12
+ Vmpooler::API.settings.config
13
+ end
14
+
15
+ def get_template_aliases(template)
16
+ tracer.in_span("Vmpooler::API::V2.#{__method__}") do
17
+ result = []
18
+ aliases = Vmpooler::API.settings.config[:alias]
19
+ if aliases
20
+ result += aliases[template] if aliases[template].is_a?(Array)
21
+ template_backends << aliases[template] if aliases[template].is_a?(String)
22
+ end
23
+ result
24
+ end
25
+ end
26
+
27
+ # Fetch a single vm from a pool
28
+ #
29
+ # @param [String] template
30
+ # The template that the vm should be created from
31
+ #
32
+ # @return [Tuple] vmname, vmpool, vmtemplate
33
+ # Returns a tuple containing the vm's name, the pool it came from, and
34
+ # what template was used, if successful. Otherwise the tuple contains.
35
+ # nil values.
36
+ def fetch_single_vm(template)
37
+ tracer.in_span("Vmpooler::API::V2.#{__method__}") do
38
+ template_backends = [template]
39
+ aliases = Vmpooler::API.settings.config[:alias]
40
+ if aliases
41
+ template_backends += aliases[template] if aliases[template].is_a?(Array)
42
+ template_backends << aliases[template] if aliases[template].is_a?(String)
43
+ pool_index = pool_index(pools)
44
+ weighted_pools = {}
45
+ template_backends.each do |t|
46
+ next unless pool_index.key? t
47
+
48
+ index = pool_index[t]
49
+ clone_target = pools[index]['clone_target'] || config['clone_target']
50
+ next unless config.key?('backend_weight')
51
+
52
+ weight = config['backend_weight'][clone_target]
53
+ if weight
54
+ weighted_pools[t] = weight
55
+ end
56
+ end
57
+
58
+ if weighted_pools.count == template_backends.count
59
+ pickup = Pickup.new(weighted_pools)
60
+ selection = pickup.pick
61
+ template_backends.delete(selection)
62
+ template_backends.unshift(selection)
63
+ else
64
+ first = template_backends.sample
65
+ template_backends.delete(first)
66
+ template_backends.unshift(first)
67
+ end
68
+ end
69
+
70
+ checkoutlock.synchronize do
71
+ template_backends.each do |template_backend|
72
+ vms = backend.smembers("vmpooler__ready__#{template_backend}")
73
+ next if vms.empty?
74
+
75
+ vm = vms.pop
76
+ smoved = backend.smove("vmpooler__ready__#{template_backend}", "vmpooler__running__#{template_backend}", vm)
77
+ if smoved
78
+ return [vm, template_backend, template]
79
+ end
80
+ end
81
+ [nil, nil, nil]
82
+ end
83
+ end
84
+ end
85
+
86
+ # The domain in the result body will be set to the one associated with the
87
+ # last vm added. The part of the response is only being retained for
88
+ # backwards compatibility as the hostnames are now fqdn's instead of bare
89
+ # hostnames. This change is a result of now being able to specify a domain
90
+ # per pool. If no vm's in the result had a domain sepcified then the
91
+ # domain key will be omitted similar to how it was previously omitted if
92
+ # the global option domain wasn't specified.
93
+ def atomically_allocate_vms(payload)
94
+ tracer.in_span("Vmpooler::API::V2.#{__method__}") do |span|
95
+ result = { 'ok' => false }
96
+ failed = false
97
+ vms = [] # vmpool, vmname, vmtemplate
98
+
99
+ validate_token(backend) if Vmpooler::API.settings.config[:auth] and has_token?
100
+
101
+ payload.each do |requested, count|
102
+ count.to_i.times do |_i|
103
+ vmname, vmpool, vmtemplate = fetch_single_vm(requested)
104
+ if vmname
105
+ account_for_starting_vm(vmpool, vmname)
106
+ vms << [vmpool, vmname, vmtemplate]
107
+ metrics.increment("checkout.success.#{vmpool}")
108
+ update_user_metrics('allocate', vmname) if Vmpooler::API.settings.config[:config]['usage_stats']
109
+ else
110
+ failed = true
111
+ metrics.increment("checkout.empty.#{requested}")
112
+ break
113
+ end
114
+ end
115
+ end
116
+
117
+ if failed
118
+ vms.each do |(vmpool, vmname, _vmtemplate)|
119
+ return_vm_to_ready_state(vmpool, vmname)
120
+ end
121
+ span.add_event('error', attributes: {
122
+ 'error.type' => 'Vmpooler::API::V2.atomically_allocate_vms',
123
+ 'error.message' => '503 due to failing to allocate one or more vms'
124
+ })
125
+ status 503
126
+ else
127
+ vm_names = []
128
+ vms.each do |(vmpool, vmname, vmtemplate)|
129
+ vmdomain = Parsing.get_domain_for_pool(full_config, vmpool)
130
+ if vmdomain
131
+ vmfqdn = "#{vmname}.#{vmdomain}"
132
+ update_result_hosts(result, vmtemplate, vmfqdn)
133
+ vm_names.append(vmfqdn)
134
+ else
135
+ update_result_hosts(result, vmtemplate, vmname)
136
+ vm_names.append(vmname)
137
+ end
138
+ end
139
+
140
+ span.set_attribute('vmpooler.vm_names', vm_names.join(',')) unless vm_names.empty?
141
+
142
+ result['ok'] = true
143
+ end
144
+
145
+ result
146
+ end
147
+ end
148
+
149
+ def generate_ondemand_request(payload)
150
+ tracer.in_span("Vmpooler::API::V2.#{__method__}") do |span|
151
+ result = { 'ok': false }
152
+
153
+ requested_instances = payload.reject { |k, _v| k == 'request_id' }
154
+ if too_many_requested?(requested_instances)
155
+ e_message = "requested amount of instances exceeds the maximum #{config['max_ondemand_instances_per_request']}"
156
+ result['message'] = e_message
157
+ status 403
158
+ span.add_event('error', attributes: {
159
+ 'error.type' => 'Vmpooler::API::V2.generate_ondemand_request',
160
+ 'error.message' => "403 due to #{e_message}"
161
+ })
162
+ return result
163
+ end
164
+
165
+ score = Time.now.to_i
166
+ request_id = payload['request_id']
167
+ request_id ||= generate_request_id
168
+ result['request_id'] = request_id
169
+ span.set_attribute('vmpooler.request_id', request_id)
170
+
171
+ if backend.exists?("vmpooler__odrequest__#{request_id}")
172
+ e_message = "request_id '#{request_id}' has already been created"
173
+ result['message'] = e_message
174
+ status 409
175
+ span.add_event('error', attributes: {
176
+ 'error.type' => 'Vmpooler::API::V2.generate_ondemand_request',
177
+ 'error.message' => "409 due to #{e_message}"
178
+ })
179
+ metrics.increment('ondemandrequest_generate.duplicaterequests')
180
+ return result
181
+ end
182
+
183
+ status 201
184
+
185
+ platforms_with_aliases = []
186
+ requested_instances.each do |poolname, count|
187
+ selection = evaluate_template_aliases(poolname, count)
188
+ selection.map { |selected_pool, selected_pool_count| platforms_with_aliases << "#{poolname}:#{selected_pool}:#{selected_pool_count}" }
189
+ end
190
+ platforms_string = platforms_with_aliases.join(',')
191
+
192
+ return result unless backend.zadd('vmpooler__provisioning__request', score, request_id)
193
+
194
+ backend.hset("vmpooler__odrequest__#{request_id}", 'requested', platforms_string)
195
+ if Vmpooler::API.settings.config[:auth] and has_token?
196
+ token_token = request.env['HTTP_X_AUTH_TOKEN']
197
+ token_user = backend.hget("vmpooler__token__#{token_token}", 'user')
198
+ backend.hset("vmpooler__odrequest__#{request_id}", 'token:token', token_token)
199
+ backend.hset("vmpooler__odrequest__#{request_id}", 'token:user', token_user)
200
+ span.set_attribute('enduser.id', token_user)
201
+ end
202
+
203
+ result[:ok] = true
204
+ metrics.increment('ondemandrequest_generate.success')
205
+ result
206
+ end
207
+ end
208
+
209
+ # Endpoints that use overridden methods
210
+
211
+ post "#{api_prefix}/vm/?" do
212
+ content_type :json
213
+ result = { 'ok' => false }
214
+ metrics.increment('http_requests_vm_total.post.vm.checkout')
215
+
216
+ payload = JSON.parse(request.body.read)
217
+
218
+ if payload
219
+ invalid = invalid_templates(payload)
220
+ if invalid.empty?
221
+ result = atomically_allocate_vms(payload)
222
+ else
223
+ invalid.each do |bad_template|
224
+ metrics.increment("checkout.invalid.#{bad_template}")
225
+ end
226
+ status 404
227
+ end
228
+ else
229
+ metrics.increment('checkout.invalid.unknown')
230
+ status 404
231
+ end
232
+
233
+ JSON.pretty_generate(result)
234
+ end
235
+
236
+ post "#{api_prefix}/vm/:template/?" do
237
+ content_type :json
238
+ result = { 'ok' => false }
239
+ metrics.increment('http_requests_vm_total.get.vm.template')
240
+
241
+ payload = extract_templates_from_query_params(params[:template])
242
+
243
+ if payload
244
+ invalid = invalid_templates(payload)
245
+ if invalid.empty?
246
+ result = atomically_allocate_vms(payload)
247
+ else
248
+ invalid.each do |bad_template|
249
+ metrics.increment("checkout.invalid.#{bad_template}")
250
+ end
251
+ status 404
252
+ end
253
+ else
254
+ metrics.increment('checkout.invalid.unknown')
255
+ status 404
256
+ end
257
+
258
+ JSON.pretty_generate(result)
259
+ end
260
+
261
+ post "#{api_prefix}/ondemandvm/?" do
262
+ content_type :json
263
+ metrics.increment('http_requests_vm_total.post.ondemand.requestid')
264
+
265
+ need_token! if Vmpooler::API.settings.config[:auth]
266
+
267
+ result = { 'ok' => false }
268
+
269
+ begin
270
+ payload = JSON.parse(request.body.read)
271
+
272
+ if payload
273
+ invalid = invalid_templates(payload.reject { |k, _v| k == 'request_id' })
274
+ if invalid.empty?
275
+ result = generate_ondemand_request(payload)
276
+ else
277
+ result[:bad_templates] = invalid
278
+ invalid.each do |bad_template|
279
+ metrics.increment("ondemandrequest_fail.invalid.#{bad_template}")
280
+ end
281
+ status 404
282
+ end
283
+ else
284
+ metrics.increment('ondemandrequest_fail.invalid.unknown')
285
+ status 404
286
+ end
287
+ rescue JSON::ParserError
288
+ span = OpenTelemetry::Trace.current_span
289
+ span.status = OpenTelemetry::Trace::Status.error('JSON payload could not be parsed')
290
+ status 400
291
+ result = {
292
+ 'ok' => false,
293
+ 'message' => 'JSON payload could not be parsed'
294
+ }
295
+ end
296
+
297
+ JSON.pretty_generate(result)
298
+ end
299
+
300
+ post "#{api_prefix}/ondemandvm/:template/?" do
301
+ content_type :json
302
+ result = { 'ok' => false }
303
+ metrics.increment('http_requests_vm_total.delete.ondemand.template')
304
+
305
+ need_token! if Vmpooler::API.settings.config[:auth]
306
+
307
+ payload = extract_templates_from_query_params(params[:template])
308
+
309
+ if payload
310
+ invalid = invalid_templates(payload.reject { |k, _v| k == 'request_id' })
311
+ if invalid.empty?
312
+ result = generate_ondemand_request(payload)
313
+ else
314
+ result[:bad_templates] = invalid
315
+ invalid.each do |bad_template|
316
+ metrics.increment("ondemandrequest_fail.invalid.#{bad_template}")
317
+ end
318
+ status 404
319
+ end
320
+ else
321
+ metrics.increment('ondemandrequest_fail.invalid.unknown')
322
+ status 404
323
+ end
324
+
325
+ JSON.pretty_generate(result)
326
+ end
327
+
328
+ get "#{api_prefix}/ondemandvm/:requestid/?" do
329
+ content_type :json
330
+ metrics.increment('http_requests_vm_total.get.ondemand.request')
331
+
332
+ status 404
333
+ result = check_ondemand_request(params[:requestid])
334
+
335
+ JSON.pretty_generate(result)
336
+ end
337
+
338
+ def check_ondemand_request(request_id)
339
+ tracer.in_span("Vmpooler::API::V2.#{__method__}") do |span|
340
+ span.set_attribute('vmpooler.request_id', request_id)
341
+ result = { 'ok' => false }
342
+ request_hash = backend.hgetall("vmpooler__odrequest__#{request_id}")
343
+ if request_hash.empty?
344
+ e_message = "no request found for request_id '#{request_id}'"
345
+ result['message'] = e_message
346
+ span.add_event('error', attributes: {
347
+ 'error.type' => 'Vmpooler::API::V2.check_ondemand_request',
348
+ 'error.message' => e_message
349
+ })
350
+ return result
351
+ end
352
+
353
+ result['request_id'] = request_id
354
+ result['ready'] = false
355
+ result['ok'] = true
356
+ status 202
357
+
358
+ case request_hash['status']
359
+ when 'ready'
360
+ result['ready'] = true
361
+ Parsing.get_platform_pool_count(request_hash['requested']) do |platform_alias, pool, _count|
362
+ instances = backend.smembers("vmpooler__#{request_id}__#{platform_alias}__#{pool}")
363
+ domain = Parsing.get_domain_for_pool(full_config, pool)
364
+ instances.map! { |instance| instance.concat(".#{domain}") } if domain
365
+
366
+ if result.key?(platform_alias)
367
+ result[platform_alias][:hostname] = result[platform_alias][:hostname] + instances
368
+ else
369
+ result[platform_alias] = { 'hostname': instances }
370
+ end
371
+ end
372
+ status 200
373
+ when 'failed'
374
+ result['message'] = "The request failed to provision instances within the configured ondemand_request_ttl '#{config['ondemand_request_ttl']}'"
375
+ status 200
376
+ when 'deleted'
377
+ result['message'] = 'The request has been deleted'
378
+ status 200
379
+ else
380
+ Parsing.get_platform_pool_count(request_hash['requested']) do |platform_alias, pool, count|
381
+ instance_count = backend.scard("vmpooler__#{request_id}__#{platform_alias}__#{pool}")
382
+ instances_pending = count.to_i - instance_count.to_i
383
+
384
+ if result.key?(platform_alias) && result[platform_alias].key?(:ready)
385
+ result[platform_alias][:ready] = (result[platform_alias][:ready].to_i + instance_count).to_s
386
+ result[platform_alias][:pending] = (result[platform_alias][:pending].to_i + instances_pending).to_s
387
+ else
388
+ result[platform_alias] = {
389
+ 'ready': instance_count.to_s,
390
+ 'pending': instances_pending.to_s
391
+ }
392
+ end
393
+ end
394
+ end
395
+
396
+ result
397
+ end
398
+ end
399
+
400
+ # Endpoints that only use bits from the V1 api are called here
401
+ # Note that traces will be named based on the route used in the V1 api
402
+ # but the http.url trace attribute will still have the actual requested url in it
403
+
404
+ delete "#{api_prefix}/*" do
405
+ versionless_path_info = request.path_info.delete_prefix("#{api_prefix}/")
406
+ request.path_info = "/api/v1/#{versionless_path_info}"
407
+ call env
408
+ end
409
+
410
+ get "#{api_prefix}/*" do
411
+ versionless_path_info = request.path_info.delete_prefix("#{api_prefix}/")
412
+ request.path_info = "/api/v1/#{versionless_path_info}"
413
+ call env
414
+ end
415
+
416
+ post "#{api_prefix}/*" do
417
+ versionless_path_info = request.path_info.delete_prefix("#{api_prefix}/")
418
+ request.path_info = "/api/v1/#{versionless_path_info}"
419
+ call env
420
+ end
421
+
422
+ put "#{api_prefix}/*" do
423
+ versionless_path_info = request.path_info.delete_prefix("#{api_prefix}/")
424
+ request.path_info = "/api/v1/#{versionless_path_info}"
425
+ call env
426
+ end
427
+ end
428
+ end
429
+ end
data/lib/vmpooler/api.rb CHANGED
@@ -3,7 +3,7 @@
3
3
  module Vmpooler
4
4
  class API < Sinatra::Base
5
5
  # Load API components
6
- %w[helpers dashboard reroute v1 request_logger healthcheck].each do |lib|
6
+ %w[helpers dashboard reroute v1 v2 request_logger healthcheck].each do |lib|
7
7
  require "vmpooler/api/#{lib}"
8
8
  end
9
9
  # Load dashboard components
@@ -54,6 +54,7 @@ module Vmpooler
54
54
  use Vmpooler::API::Dashboard
55
55
  use Vmpooler::API::Reroute
56
56
  use Vmpooler::API::V1
57
+ use Vmpooler::API::V2
57
58
  end
58
59
 
59
60
  # Get thee started O WebServer