vmpooler 2.1.0 → 2.2.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 +4 -4
- data/lib/vmpooler/api/helpers.rb +363 -294
- data/lib/vmpooler/api/v1.rb +482 -377
- data/lib/vmpooler/providers/base.rb +1 -1
- data/lib/vmpooler/version.rb +1 -1
- data/lib/vmpooler.rb +2 -1
- metadata +36 -16
data/lib/vmpooler/api/helpers.rb
CHANGED
@@ -6,136 +6,170 @@ module Vmpooler
|
|
6
6
|
|
7
7
|
module Helpers
|
8
8
|
|
9
|
+
def tracer
|
10
|
+
@tracer ||= OpenTelemetry.tracer_provider.tracer('api', Vmpooler::VERSION)
|
11
|
+
end
|
12
|
+
|
9
13
|
def has_token?
|
10
14
|
request.env['HTTP_X_AUTH_TOKEN'].nil? ? false : true
|
11
15
|
end
|
12
16
|
|
13
17
|
def valid_token?(backend)
|
14
|
-
|
18
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
19
|
+
return false unless has_token?
|
15
20
|
|
16
|
-
|
21
|
+
backend.exists?("vmpooler__token__#{request.env['HTTP_X_AUTH_TOKEN']}") ? true : false
|
22
|
+
end
|
17
23
|
end
|
18
24
|
|
19
25
|
def validate_token(backend)
|
20
|
-
|
21
|
-
backend
|
26
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
27
|
+
if valid_token?(backend)
|
28
|
+
backend.hset("vmpooler__token__#{request.env['HTTP_X_AUTH_TOKEN']}", 'last', Time.now)
|
22
29
|
|
23
|
-
|
24
|
-
|
30
|
+
return true
|
31
|
+
end
|
25
32
|
|
26
|
-
|
33
|
+
content_type :json
|
27
34
|
|
28
|
-
|
35
|
+
result = { 'ok' => false }
|
29
36
|
|
30
|
-
|
31
|
-
|
37
|
+
headers['WWW-Authenticate'] = 'Basic realm="Authentication required"'
|
38
|
+
halt 401, JSON.pretty_generate(result)
|
39
|
+
end
|
32
40
|
end
|
33
41
|
|
34
42
|
def validate_auth(backend)
|
35
|
-
|
43
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
44
|
+
return if authorized?
|
36
45
|
|
37
|
-
|
46
|
+
content_type :json
|
38
47
|
|
39
|
-
|
48
|
+
result = { 'ok' => false }
|
40
49
|
|
41
|
-
|
42
|
-
|
50
|
+
headers['WWW-Authenticate'] = 'Basic realm="Authentication required"'
|
51
|
+
halt 401, JSON.pretty_generate(result)
|
52
|
+
end
|
43
53
|
end
|
44
54
|
|
45
55
|
def authorized?
|
46
|
-
|
56
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
57
|
+
@auth ||= Rack::Auth::Basic::Request.new(request.env)
|
47
58
|
|
48
|
-
|
49
|
-
|
59
|
+
if @auth.provided? and @auth.basic? and @auth.credentials
|
60
|
+
username, password = @auth.credentials
|
50
61
|
|
51
|
-
|
52
|
-
|
62
|
+
if authenticate(Vmpooler::API.settings.config[:auth], username, password)
|
63
|
+
return true
|
64
|
+
end
|
53
65
|
end
|
54
|
-
end
|
55
66
|
|
56
|
-
|
67
|
+
return false
|
68
|
+
end
|
57
69
|
end
|
58
70
|
|
59
71
|
def authenticate_ldap(port, host, encryption_hash, user_object, base, username_str, password_str)
|
60
|
-
|
61
|
-
|
62
|
-
:
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
72
|
+
tracer.in_span(
|
73
|
+
"Vmpooler::API::Helpers.#{__method__}",
|
74
|
+
attributes: {
|
75
|
+
'net.peer.name' => host,
|
76
|
+
'net.peer.port' => port,
|
77
|
+
'net.transport' => 'ip_tcp',
|
78
|
+
'enduser.id' => username_str
|
79
|
+
},
|
80
|
+
kind: :client
|
81
|
+
) do
|
82
|
+
ldap = Net::LDAP.new(
|
83
|
+
:host => host,
|
84
|
+
:port => port,
|
85
|
+
:encryption => encryption_hash,
|
86
|
+
:base => base,
|
87
|
+
:auth => {
|
88
|
+
:method => :simple,
|
89
|
+
:username => "#{user_object}=#{username_str},#{base}",
|
90
|
+
:password => password_str
|
91
|
+
}
|
92
|
+
)
|
71
93
|
|
72
|
-
|
94
|
+
return true if ldap.bind
|
73
95
|
|
74
|
-
|
96
|
+
return false
|
97
|
+
end
|
75
98
|
end
|
76
99
|
|
77
100
|
def authenticate(auth, username_str, password_str)
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
ldap_base = auth[:ldap]['base']
|
83
|
-
ldap_port = auth[:ldap]['port'] || 389
|
84
|
-
ldap_user_obj = auth[:ldap]['user_object']
|
85
|
-
ldap_host = auth[:ldap]['host']
|
86
|
-
ldap_encryption_hash = auth[:ldap]['encryption'] || {
|
87
|
-
:method => :start_tls,
|
88
|
-
:tls_options => { :ssl_version => 'TLSv1' }
|
101
|
+
tracer.in_span(
|
102
|
+
"Vmpooler::API::Helpers.#{__method__}",
|
103
|
+
attributes: {
|
104
|
+
'enduser.id' => username_str
|
89
105
|
}
|
106
|
+
) do
|
107
|
+
case auth['provider']
|
108
|
+
when 'dummy'
|
109
|
+
return (username_str != password_str)
|
110
|
+
when 'ldap'
|
111
|
+
ldap_base = auth[:ldap]['base']
|
112
|
+
ldap_port = auth[:ldap]['port'] || 389
|
113
|
+
ldap_user_obj = auth[:ldap]['user_object']
|
114
|
+
ldap_host = auth[:ldap]['host']
|
115
|
+
ldap_encryption_hash = auth[:ldap]['encryption'] || {
|
116
|
+
:method => :start_tls,
|
117
|
+
:tls_options => { :ssl_version => 'TLSv1' }
|
118
|
+
}
|
90
119
|
|
91
|
-
|
92
|
-
|
93
|
-
|
120
|
+
unless ldap_base.is_a? Array
|
121
|
+
ldap_base = ldap_base.split
|
122
|
+
end
|
94
123
|
|
95
|
-
|
96
|
-
|
97
|
-
|
124
|
+
unless ldap_user_obj.is_a? Array
|
125
|
+
ldap_user_obj = ldap_user_obj.split
|
126
|
+
end
|
98
127
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
128
|
+
ldap_base.each do |search_base|
|
129
|
+
ldap_user_obj.each do |search_user_obj|
|
130
|
+
result = authenticate_ldap(
|
131
|
+
ldap_port,
|
132
|
+
ldap_host,
|
133
|
+
ldap_encryption_hash,
|
134
|
+
search_user_obj,
|
135
|
+
search_base,
|
136
|
+
username_str,
|
137
|
+
password_str
|
138
|
+
)
|
139
|
+
return true if result
|
140
|
+
end
|
111
141
|
end
|
112
|
-
end
|
113
142
|
|
114
|
-
|
143
|
+
return false
|
144
|
+
end
|
115
145
|
end
|
116
146
|
end
|
117
147
|
|
118
148
|
def export_tags(backend, hostname, tags)
|
119
|
-
|
120
|
-
|
121
|
-
|
149
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
150
|
+
backend.pipelined do
|
151
|
+
tags.each_pair do |tag, value|
|
152
|
+
next if value.nil? or value.empty?
|
122
153
|
|
123
|
-
|
124
|
-
|
154
|
+
backend.hset("vmpooler__vm__#{hostname}", "tag:#{tag}", value)
|
155
|
+
backend.hset("vmpooler__tag__#{Date.today}", "#{hostname}:#{tag}", value)
|
156
|
+
end
|
125
157
|
end
|
126
158
|
end
|
127
159
|
end
|
128
160
|
|
129
161
|
def filter_tags(tags)
|
130
|
-
|
162
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
163
|
+
return unless Vmpooler::API.settings.config[:tagfilter]
|
131
164
|
|
132
|
-
|
133
|
-
|
165
|
+
tags.each_pair do |tag, value|
|
166
|
+
next unless filter = Vmpooler::API.settings.config[:tagfilter][tag]
|
134
167
|
|
135
|
-
|
136
|
-
|
168
|
+
tags[tag] = value.match(filter).captures.join if value.match(filter)
|
169
|
+
end
|
137
170
|
|
138
|
-
|
171
|
+
tags
|
172
|
+
end
|
139
173
|
end
|
140
174
|
|
141
175
|
def mean(list)
|
@@ -156,301 +190,321 @@ module Vmpooler
|
|
156
190
|
end
|
157
191
|
|
158
192
|
def get_task_times(backend, task, date_str)
|
159
|
-
|
193
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
194
|
+
backend.hvals("vmpooler__#{task}__" + date_str).map(&:to_f)
|
195
|
+
end
|
160
196
|
end
|
161
197
|
|
162
198
|
# Takes the pools and a key to run scard on
|
163
199
|
# returns an integer for the total count
|
164
200
|
def get_total_across_pools_redis_scard(pools, key, backend)
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
201
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
202
|
+
# using pipelined is much faster than querying each of the pools and adding them
|
203
|
+
# as we get the result.
|
204
|
+
res = backend.pipelined do
|
205
|
+
pools.each do |pool|
|
206
|
+
backend.scard(key + pool['name'])
|
207
|
+
end
|
170
208
|
end
|
209
|
+
res.inject(0) { |m, x| m + x }.to_i
|
171
210
|
end
|
172
|
-
res.inject(0) { |m, x| m + x }.to_i
|
173
211
|
end
|
174
212
|
|
175
213
|
# Takes the pools and a key to run scard on
|
176
214
|
# returns a hash with each pool name as key and the value being the count as integer
|
177
215
|
def get_list_across_pools_redis_scard(pools, key, backend)
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
216
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
217
|
+
# using pipelined is much faster than querying each of the pools and adding them
|
218
|
+
# as we get the result.
|
219
|
+
temp_hash = {}
|
220
|
+
res = backend.pipelined do
|
221
|
+
pools.each do |pool|
|
222
|
+
backend.scard(key + pool['name'])
|
223
|
+
end
|
184
224
|
end
|
225
|
+
pools.each_with_index do |pool, i|
|
226
|
+
temp_hash[pool['name']] = res[i].to_i
|
227
|
+
end
|
228
|
+
temp_hash
|
185
229
|
end
|
186
|
-
pools.each_with_index do |pool, i|
|
187
|
-
temp_hash[pool['name']] = res[i].to_i
|
188
|
-
end
|
189
|
-
temp_hash
|
190
230
|
end
|
191
231
|
|
192
232
|
# Takes the pools and a key to run hget on
|
193
233
|
# returns a hash with each pool name as key and the value as string
|
194
234
|
def get_list_across_pools_redis_hget(pools, key, backend)
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
235
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
236
|
+
# using pipelined is much faster than querying each of the pools and adding them
|
237
|
+
# as we get the result.
|
238
|
+
temp_hash = {}
|
239
|
+
res = backend.pipelined do
|
240
|
+
pools.each do |pool|
|
241
|
+
backend.hget(key, pool['name'])
|
242
|
+
end
|
201
243
|
end
|
244
|
+
pools.each_with_index do |pool, i|
|
245
|
+
temp_hash[pool['name']] = res[i].to_s
|
246
|
+
end
|
247
|
+
temp_hash
|
202
248
|
end
|
203
|
-
pools.each_with_index do |pool, i|
|
204
|
-
temp_hash[pool['name']] = res[i].to_s
|
205
|
-
end
|
206
|
-
temp_hash
|
207
249
|
end
|
208
250
|
|
209
251
|
def get_capacity_metrics(pools, backend)
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
252
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
253
|
+
capacity = {
|
254
|
+
current: 0,
|
255
|
+
total: 0,
|
256
|
+
percent: 0
|
257
|
+
}
|
215
258
|
|
216
|
-
|
217
|
-
|
218
|
-
|
259
|
+
pools.each do |pool|
|
260
|
+
capacity[:total] += pool['size'].to_i
|
261
|
+
end
|
219
262
|
|
220
|
-
|
263
|
+
capacity[:current] = get_total_across_pools_redis_scard(pools, 'vmpooler__ready__', backend)
|
221
264
|
|
222
|
-
|
223
|
-
|
224
|
-
|
265
|
+
if capacity[:total] > 0
|
266
|
+
capacity[:percent] = (capacity[:current].fdiv(capacity[:total]) * 100.0).round(1)
|
267
|
+
end
|
225
268
|
|
226
|
-
|
269
|
+
capacity
|
270
|
+
end
|
227
271
|
end
|
228
272
|
|
229
273
|
def get_queue_metrics(pools, backend)
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
274
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
275
|
+
queue = {
|
276
|
+
pending: 0,
|
277
|
+
cloning: 0,
|
278
|
+
booting: 0,
|
279
|
+
ready: 0,
|
280
|
+
running: 0,
|
281
|
+
completed: 0,
|
282
|
+
total: 0
|
283
|
+
}
|
284
|
+
|
285
|
+
queue[:pending] = get_total_across_pools_redis_scard(pools, 'vmpooler__pending__', backend)
|
286
|
+
queue[:ready] = get_total_across_pools_redis_scard(pools, 'vmpooler__ready__', backend)
|
287
|
+
queue[:running] = get_total_across_pools_redis_scard(pools, 'vmpooler__running__', backend)
|
288
|
+
queue[:completed] = get_total_across_pools_redis_scard(pools, 'vmpooler__completed__', backend)
|
289
|
+
|
290
|
+
queue[:cloning] = backend.get('vmpooler__tasks__clone').to_i + backend.get('vmpooler__tasks__ondemandclone').to_i
|
291
|
+
queue[:booting] = queue[:pending].to_i - queue[:cloning].to_i
|
292
|
+
queue[:booting] = 0 if queue[:booting] < 0
|
293
|
+
queue[:total] = queue[:pending].to_i + queue[:ready].to_i + queue[:running].to_i + queue[:completed].to_i
|
294
|
+
|
295
|
+
queue
|
296
|
+
end
|
251
297
|
end
|
252
298
|
|
253
299
|
def get_tag_metrics(backend, date_str, opts = {})
|
254
|
-
|
300
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
301
|
+
opts = {:only => false}.merge(opts)
|
255
302
|
|
256
|
-
|
303
|
+
tags = {}
|
257
304
|
|
258
|
-
|
259
|
-
|
260
|
-
|
305
|
+
backend.hgetall("vmpooler__tag__#{date_str}").each do |key, value|
|
306
|
+
hostname = 'unknown'
|
307
|
+
tag = 'unknown'
|
261
308
|
|
262
|
-
|
263
|
-
|
264
|
-
|
309
|
+
if key =~ /:/
|
310
|
+
hostname, tag = key.split(':', 2)
|
311
|
+
end
|
265
312
|
|
266
|
-
|
313
|
+
next if opts[:only] && tag != opts[:only]
|
267
314
|
|
268
|
-
|
269
|
-
|
270
|
-
|
315
|
+
tags[tag] ||= {}
|
316
|
+
tags[tag][value] ||= 0
|
317
|
+
tags[tag][value] += 1
|
271
318
|
|
272
|
-
|
273
|
-
|
274
|
-
|
319
|
+
tags[tag]['total'] ||= 0
|
320
|
+
tags[tag]['total'] += 1
|
321
|
+
end
|
275
322
|
|
276
|
-
|
323
|
+
tags
|
324
|
+
end
|
277
325
|
end
|
278
326
|
|
279
327
|
def get_tag_summary(backend, from_date, to_date, opts = {})
|
280
|
-
|
281
|
-
|
282
|
-
result = {
|
283
|
-
tag: {},
|
284
|
-
daily: []
|
285
|
-
}
|
328
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
329
|
+
opts = {:only => false}.merge(opts)
|
286
330
|
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
tag: get_tag_metrics(backend, date.to_s, opts)
|
331
|
+
result = {
|
332
|
+
tag: {},
|
333
|
+
daily: []
|
291
334
|
}
|
292
|
-
result[:daily].push(daily)
|
293
|
-
end
|
294
335
|
|
295
|
-
|
296
|
-
|
297
|
-
|
336
|
+
(from_date..to_date).each do |date|
|
337
|
+
daily = {
|
338
|
+
date: date.to_s,
|
339
|
+
tag: get_tag_metrics(backend, date.to_s, opts)
|
340
|
+
}
|
341
|
+
result[:daily].push(daily)
|
342
|
+
end
|
343
|
+
|
344
|
+
result[:daily].each do |daily|
|
345
|
+
daily[:tag].each_key do |tag|
|
346
|
+
result[:tag][tag] ||= {}
|
298
347
|
|
299
|
-
|
300
|
-
|
301
|
-
|
348
|
+
daily[:tag][tag].each do |key, value|
|
349
|
+
result[:tag][tag][key] ||= 0
|
350
|
+
result[:tag][tag][key] += value
|
351
|
+
end
|
302
352
|
end
|
303
353
|
end
|
304
|
-
end
|
305
354
|
|
306
|
-
|
355
|
+
result
|
356
|
+
end
|
307
357
|
end
|
308
358
|
|
309
359
|
def get_task_metrics(backend, task_str, date_str, opts = {})
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
360
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
361
|
+
opts = {:bypool => false, :only => false}.merge(opts)
|
362
|
+
|
363
|
+
task = {
|
364
|
+
duration: {
|
365
|
+
average: 0,
|
366
|
+
min: 0,
|
367
|
+
max: 0,
|
368
|
+
total: 0
|
369
|
+
},
|
370
|
+
count: {
|
371
|
+
total: 0
|
372
|
+
}
|
373
|
+
}
|
323
374
|
|
324
|
-
|
375
|
+
task[:count][:total] = backend.hlen("vmpooler__#{task_str}__#{date_str}").to_i
|
325
376
|
|
326
|
-
|
327
|
-
|
328
|
-
|
377
|
+
if task[:count][:total] > 0
|
378
|
+
if opts[:bypool] == true
|
379
|
+
task_times_bypool = {}
|
329
380
|
|
330
|
-
|
331
|
-
|
381
|
+
task[:count][:pool] = {}
|
382
|
+
task[:duration][:pool] = {}
|
332
383
|
|
333
|
-
|
334
|
-
|
335
|
-
|
384
|
+
backend.hgetall("vmpooler__#{task_str}__#{date_str}").each do |key, value|
|
385
|
+
pool = 'unknown'
|
386
|
+
hostname = 'unknown'
|
336
387
|
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
388
|
+
if key =~ /:/
|
389
|
+
pool, hostname = key.split(':')
|
390
|
+
else
|
391
|
+
hostname = key
|
392
|
+
end
|
342
393
|
|
343
|
-
|
344
|
-
|
394
|
+
task[:count][:pool][pool] ||= {}
|
395
|
+
task[:duration][:pool][pool] ||= {}
|
345
396
|
|
346
|
-
|
347
|
-
|
348
|
-
|
397
|
+
task_times_bypool[pool] ||= []
|
398
|
+
task_times_bypool[pool].push(value.to_f)
|
399
|
+
end
|
349
400
|
|
350
|
-
|
351
|
-
|
401
|
+
task_times_bypool.each_key do |pool|
|
402
|
+
task[:count][:pool][pool][:total] = task_times_bypool[pool].length
|
352
403
|
|
353
|
-
|
354
|
-
|
355
|
-
|
404
|
+
task[:duration][:pool][pool][:total] = task_times_bypool[pool].reduce(:+).to_f
|
405
|
+
task[:duration][:pool][pool][:average] = (task[:duration][:pool][pool][:total] / task[:count][:pool][pool][:total]).round(1)
|
406
|
+
task[:duration][:pool][pool][:min], task[:duration][:pool][pool][:max] = task_times_bypool[pool].minmax
|
407
|
+
end
|
356
408
|
end
|
357
|
-
end
|
358
409
|
|
359
|
-
|
410
|
+
task_times = get_task_times(backend, task_str, date_str)
|
360
411
|
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
412
|
+
task[:duration][:total] = task_times.reduce(:+).to_f
|
413
|
+
task[:duration][:average] = (task[:duration][:total] / task[:count][:total]).round(1)
|
414
|
+
task[:duration][:min], task[:duration][:max] = task_times.minmax
|
415
|
+
end
|
365
416
|
|
366
|
-
|
367
|
-
|
368
|
-
|
417
|
+
if opts[:only]
|
418
|
+
task.each_key do |key|
|
419
|
+
task.delete(key) unless key.to_s == opts[:only]
|
420
|
+
end
|
369
421
|
end
|
370
|
-
end
|
371
422
|
|
372
|
-
|
423
|
+
task
|
424
|
+
end
|
373
425
|
end
|
374
426
|
|
375
427
|
def get_task_summary(backend, task_str, from_date, to_date, opts = {})
|
376
|
-
|
428
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
429
|
+
opts = {:bypool => false, :only => false}.merge(opts)
|
377
430
|
|
378
|
-
|
431
|
+
task_sym = task_str.to_sym
|
379
432
|
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
}
|
384
|
-
|
385
|
-
(from_date..to_date).each do |date|
|
386
|
-
daily = {
|
387
|
-
date: date.to_s,
|
388
|
-
task_sym => get_task_metrics(backend, task_str, date.to_s, opts)
|
433
|
+
result = {
|
434
|
+
task_sym => {},
|
435
|
+
daily: []
|
389
436
|
}
|
390
|
-
result[:daily].push(daily)
|
391
|
-
end
|
392
437
|
|
393
|
-
|
394
|
-
|
438
|
+
(from_date..to_date).each do |date|
|
439
|
+
daily = {
|
440
|
+
date: date.to_s,
|
441
|
+
task_sym => get_task_metrics(backend, task_str, date.to_s, opts)
|
442
|
+
}
|
443
|
+
result[:daily].push(daily)
|
444
|
+
end
|
395
445
|
|
396
|
-
|
397
|
-
|
398
|
-
result[task_sym][type] ||= {}
|
399
|
-
daily_task[type] ||= {}
|
446
|
+
daily_task = {}
|
447
|
+
daily_task_bypool = {} if opts[:bypool] == true
|
400
448
|
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
449
|
+
result[:daily].each do |daily|
|
450
|
+
daily[task_sym].each_key do |type|
|
451
|
+
result[task_sym][type] ||= {}
|
452
|
+
daily_task[type] ||= {}
|
453
|
+
|
454
|
+
['min', 'max'].each do |key|
|
455
|
+
if daily[task_sym][type][key]
|
456
|
+
daily_task[type][:data] ||= []
|
457
|
+
daily_task[type][:data].push(daily[task_sym][type][key])
|
458
|
+
end
|
405
459
|
end
|
406
|
-
end
|
407
460
|
|
408
|
-
|
409
|
-
|
461
|
+
result[task_sym][type][:total] ||= 0
|
462
|
+
result[task_sym][type][:total] += daily[task_sym][type][:total]
|
410
463
|
|
411
|
-
|
412
|
-
|
413
|
-
|
464
|
+
if opts[:bypool] == true
|
465
|
+
result[task_sym][type][:pool] ||= {}
|
466
|
+
daily_task_bypool[type] ||= {}
|
414
467
|
|
415
|
-
|
468
|
+
next unless daily[task_sym][type][:pool]
|
416
469
|
|
417
|
-
|
418
|
-
|
419
|
-
|
470
|
+
daily[task_sym][type][:pool].each_key do |pool|
|
471
|
+
result[task_sym][type][:pool][pool] ||= {}
|
472
|
+
daily_task_bypool[type][pool] ||= {}
|
420
473
|
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
474
|
+
['min', 'max'].each do |key|
|
475
|
+
if daily[task_sym][type][:pool][pool][key.to_sym]
|
476
|
+
daily_task_bypool[type][pool][:data] ||= []
|
477
|
+
daily_task_bypool[type][pool][:data].push(daily[task_sym][type][:pool][pool][key.to_sym])
|
478
|
+
end
|
425
479
|
end
|
426
|
-
end
|
427
480
|
|
428
|
-
|
429
|
-
|
481
|
+
result[task_sym][type][:pool][pool][:total] ||= 0
|
482
|
+
result[task_sym][type][:pool][pool][:total] += daily[task_sym][type][:pool][pool][:total]
|
483
|
+
end
|
430
484
|
end
|
431
485
|
end
|
432
486
|
end
|
433
|
-
end
|
434
487
|
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
488
|
+
result[task_sym].each_key do |type|
|
489
|
+
if daily_task[type][:data]
|
490
|
+
result[task_sym][type][:min], result[task_sym][type][:max] = daily_task[type][:data].minmax
|
491
|
+
result[task_sym][type][:average] = mean(daily_task[type][:data])
|
492
|
+
end
|
440
493
|
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
494
|
+
if opts[:bypool] == true
|
495
|
+
result[task_sym].each_key do |type|
|
496
|
+
result[task_sym][type][:pool].each_key do |pool|
|
497
|
+
if daily_task_bypool[type][pool][:data]
|
498
|
+
result[task_sym][type][:pool][pool][:min], result[task_sym][type][:pool][pool][:max] = daily_task_bypool[type][pool][:data].minmax
|
499
|
+
result[task_sym][type][:pool][pool][:average] = mean(daily_task_bypool[type][pool][:data])
|
500
|
+
end
|
447
501
|
end
|
448
502
|
end
|
449
503
|
end
|
450
504
|
end
|
451
|
-
end
|
452
505
|
|
453
|
-
|
506
|
+
result
|
507
|
+
end
|
454
508
|
end
|
455
509
|
|
456
510
|
def pool_index(pools)
|
@@ -464,11 +518,13 @@ module Vmpooler
|
|
464
518
|
end
|
465
519
|
|
466
520
|
def template_ready?(pool, backend)
|
467
|
-
|
468
|
-
|
469
|
-
|
521
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
522
|
+
prepared_template = backend.hget('vmpooler__template__prepared', pool['name'])
|
523
|
+
return false if prepared_template.nil?
|
524
|
+
return true if pool['template'] == prepared_template
|
470
525
|
|
471
|
-
|
526
|
+
return false
|
527
|
+
end
|
472
528
|
end
|
473
529
|
|
474
530
|
def is_integer?(x)
|
@@ -479,26 +535,39 @@ module Vmpooler
|
|
479
535
|
end
|
480
536
|
|
481
537
|
def open_socket(host, domain = nil, timeout = 1, port = 22, &_block)
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
538
|
+
tracer.in_span(
|
539
|
+
"Vmpooler::API::Helpers.#{__method__}",
|
540
|
+
attributes: {
|
541
|
+
'net.peer.port' => port,
|
542
|
+
'net.transport' => 'ip_tcp'
|
543
|
+
},
|
544
|
+
kind: :client
|
545
|
+
) do
|
546
|
+
Timeout.timeout(timeout) do
|
547
|
+
target_host = host
|
548
|
+
target_host = "#{host}.#{domain}" if domain
|
549
|
+
span = OpenTelemetry::Trace.current_span
|
550
|
+
span.set_attribute('net.peer.name', target_host)
|
551
|
+
sock = TCPSocket.new target_host, port
|
552
|
+
begin
|
553
|
+
yield sock if block_given?
|
554
|
+
ensure
|
555
|
+
sock.close
|
556
|
+
end
|
490
557
|
end
|
491
558
|
end
|
492
559
|
end
|
493
560
|
|
494
561
|
def vm_ready?(vm_name, domain = nil)
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
562
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
563
|
+
begin
|
564
|
+
open_socket(vm_name, domain)
|
565
|
+
rescue StandardError => _e
|
566
|
+
return false
|
567
|
+
end
|
500
568
|
|
501
|
-
|
569
|
+
true
|
570
|
+
end
|
502
571
|
end
|
503
572
|
end
|
504
573
|
end
|