vmpooler 2.1.0 → 2.4.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 +365 -299
- data/lib/vmpooler/api/reroute.rb +16 -0
- data/lib/vmpooler/api/v1.rb +501 -378
- data/lib/vmpooler/api/v2.rb +505 -0
- data/lib/vmpooler/api.rb +2 -1
- data/lib/vmpooler/pool_manager.rb +84 -63
- data/lib/vmpooler/providers/base.rb +1 -1
- data/lib/vmpooler/util/parsing.rb +21 -1
- data/lib/vmpooler/version.rb +1 -1
- data/lib/vmpooler.rb +6 -1
- metadata +103 -83
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 |pipeline|
|
151
|
+
tags.each_pair do |tag, value|
|
152
|
+
next if value.nil? or value.empty?
|
122
153
|
|
123
|
-
|
124
|
-
|
154
|
+
pipeline.hset("vmpooler__vm__#{hostname}", "tag:#{tag}", value)
|
155
|
+
pipeline.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)
|
@@ -147,310 +181,327 @@ module Vmpooler
|
|
147
181
|
/^\d{4}-\d{2}-\d{2}$/ === date_str
|
148
182
|
end
|
149
183
|
|
184
|
+
# NOTE: domain is not needed here, so we should update the callers of this method
|
150
185
|
def hostname_shorten(hostname, domain=nil)
|
151
|
-
|
152
|
-
hostname = hostname[/[^.]+/]
|
153
|
-
end
|
154
|
-
|
155
|
-
hostname
|
186
|
+
hostname[/[^.]+/]
|
156
187
|
end
|
157
188
|
|
158
189
|
def get_task_times(backend, task, date_str)
|
159
|
-
|
190
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
191
|
+
backend.hvals("vmpooler__#{task}__" + date_str).map(&:to_f)
|
192
|
+
end
|
160
193
|
end
|
161
194
|
|
162
195
|
# Takes the pools and a key to run scard on
|
163
196
|
# returns an integer for the total count
|
164
197
|
def get_total_across_pools_redis_scard(pools, key, backend)
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
198
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
199
|
+
# using pipelined is much faster than querying each of the pools and adding them
|
200
|
+
# as we get the result.
|
201
|
+
res = backend.pipelined do |pipeline|
|
202
|
+
pools.each do |pool|
|
203
|
+
pipeline.scard(key + pool['name'])
|
204
|
+
end
|
170
205
|
end
|
206
|
+
res.inject(0) { |m, x| m + x }.to_i
|
171
207
|
end
|
172
|
-
res.inject(0) { |m, x| m + x }.to_i
|
173
208
|
end
|
174
209
|
|
175
210
|
# Takes the pools and a key to run scard on
|
176
211
|
# returns a hash with each pool name as key and the value being the count as integer
|
177
212
|
def get_list_across_pools_redis_scard(pools, key, backend)
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
213
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
214
|
+
# using pipelined is much faster than querying each of the pools and adding them
|
215
|
+
# as we get the result.
|
216
|
+
temp_hash = {}
|
217
|
+
res = backend.pipelined do |pipeline|
|
218
|
+
pools.each do |pool|
|
219
|
+
pipeline.scard(key + pool['name'])
|
220
|
+
end
|
184
221
|
end
|
222
|
+
pools.each_with_index do |pool, i|
|
223
|
+
temp_hash[pool['name']] = res[i].to_i
|
224
|
+
end
|
225
|
+
temp_hash
|
185
226
|
end
|
186
|
-
pools.each_with_index do |pool, i|
|
187
|
-
temp_hash[pool['name']] = res[i].to_i
|
188
|
-
end
|
189
|
-
temp_hash
|
190
227
|
end
|
191
228
|
|
192
229
|
# Takes the pools and a key to run hget on
|
193
230
|
# returns a hash with each pool name as key and the value as string
|
194
231
|
def get_list_across_pools_redis_hget(pools, key, backend)
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
232
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
233
|
+
# using pipelined is much faster than querying each of the pools and adding them
|
234
|
+
# as we get the result.
|
235
|
+
temp_hash = {}
|
236
|
+
res = backend.pipelined do |pipeline|
|
237
|
+
pools.each do |pool|
|
238
|
+
pipeline.hget(key, pool['name'])
|
239
|
+
end
|
201
240
|
end
|
241
|
+
pools.each_with_index do |pool, i|
|
242
|
+
temp_hash[pool['name']] = res[i].to_s
|
243
|
+
end
|
244
|
+
temp_hash
|
202
245
|
end
|
203
|
-
pools.each_with_index do |pool, i|
|
204
|
-
temp_hash[pool['name']] = res[i].to_s
|
205
|
-
end
|
206
|
-
temp_hash
|
207
246
|
end
|
208
247
|
|
209
248
|
def get_capacity_metrics(pools, backend)
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
249
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
250
|
+
capacity = {
|
251
|
+
current: 0,
|
252
|
+
total: 0,
|
253
|
+
percent: 0
|
254
|
+
}
|
215
255
|
|
216
|
-
|
217
|
-
|
218
|
-
|
256
|
+
pools.each do |pool|
|
257
|
+
capacity[:total] += pool['size'].to_i
|
258
|
+
end
|
219
259
|
|
220
|
-
|
260
|
+
capacity[:current] = get_total_across_pools_redis_scard(pools, 'vmpooler__ready__', backend)
|
221
261
|
|
222
|
-
|
223
|
-
|
224
|
-
|
262
|
+
if capacity[:total] > 0
|
263
|
+
capacity[:percent] = (capacity[:current].fdiv(capacity[:total]) * 100.0).round(1)
|
264
|
+
end
|
225
265
|
|
226
|
-
|
266
|
+
capacity
|
267
|
+
end
|
227
268
|
end
|
228
269
|
|
229
270
|
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
|
-
|
271
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
272
|
+
queue = {
|
273
|
+
pending: 0,
|
274
|
+
cloning: 0,
|
275
|
+
booting: 0,
|
276
|
+
ready: 0,
|
277
|
+
running: 0,
|
278
|
+
completed: 0,
|
279
|
+
total: 0
|
280
|
+
}
|
281
|
+
|
282
|
+
queue[:pending] = get_total_across_pools_redis_scard(pools, 'vmpooler__pending__', backend)
|
283
|
+
queue[:ready] = get_total_across_pools_redis_scard(pools, 'vmpooler__ready__', backend)
|
284
|
+
queue[:running] = get_total_across_pools_redis_scard(pools, 'vmpooler__running__', backend)
|
285
|
+
queue[:completed] = get_total_across_pools_redis_scard(pools, 'vmpooler__completed__', backend)
|
286
|
+
|
287
|
+
queue[:cloning] = backend.get('vmpooler__tasks__clone').to_i + backend.get('vmpooler__tasks__ondemandclone').to_i
|
288
|
+
queue[:booting] = queue[:pending].to_i - queue[:cloning].to_i
|
289
|
+
queue[:booting] = 0 if queue[:booting] < 0
|
290
|
+
queue[:total] = queue[:pending].to_i + queue[:ready].to_i + queue[:running].to_i + queue[:completed].to_i
|
291
|
+
|
292
|
+
queue
|
293
|
+
end
|
251
294
|
end
|
252
295
|
|
253
296
|
def get_tag_metrics(backend, date_str, opts = {})
|
254
|
-
|
297
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
298
|
+
opts = {:only => false}.merge(opts)
|
255
299
|
|
256
|
-
|
300
|
+
tags = {}
|
257
301
|
|
258
|
-
|
259
|
-
|
260
|
-
|
302
|
+
backend.hgetall("vmpooler__tag__#{date_str}").each do |key, value|
|
303
|
+
hostname = 'unknown'
|
304
|
+
tag = 'unknown'
|
261
305
|
|
262
|
-
|
263
|
-
|
264
|
-
|
306
|
+
if key =~ /:/
|
307
|
+
hostname, tag = key.split(':', 2)
|
308
|
+
end
|
265
309
|
|
266
|
-
|
310
|
+
next if opts[:only] && tag != opts[:only]
|
267
311
|
|
268
|
-
|
269
|
-
|
270
|
-
|
312
|
+
tags[tag] ||= {}
|
313
|
+
tags[tag][value] ||= 0
|
314
|
+
tags[tag][value] += 1
|
271
315
|
|
272
|
-
|
273
|
-
|
274
|
-
|
316
|
+
tags[tag]['total'] ||= 0
|
317
|
+
tags[tag]['total'] += 1
|
318
|
+
end
|
275
319
|
|
276
|
-
|
320
|
+
tags
|
321
|
+
end
|
277
322
|
end
|
278
323
|
|
279
324
|
def get_tag_summary(backend, from_date, to_date, opts = {})
|
280
|
-
|
325
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
326
|
+
opts = {:only => false}.merge(opts)
|
281
327
|
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
}
|
286
|
-
|
287
|
-
(from_date..to_date).each do |date|
|
288
|
-
daily = {
|
289
|
-
date: date.to_s,
|
290
|
-
tag: get_tag_metrics(backend, date.to_s, opts)
|
328
|
+
result = {
|
329
|
+
tag: {},
|
330
|
+
daily: []
|
291
331
|
}
|
292
|
-
result[:daily].push(daily)
|
293
|
-
end
|
294
332
|
|
295
|
-
|
296
|
-
|
297
|
-
|
333
|
+
(from_date..to_date).each do |date|
|
334
|
+
daily = {
|
335
|
+
date: date.to_s,
|
336
|
+
tag: get_tag_metrics(backend, date.to_s, opts)
|
337
|
+
}
|
338
|
+
result[:daily].push(daily)
|
339
|
+
end
|
298
340
|
|
299
|
-
|
300
|
-
|
301
|
-
result[:tag][tag]
|
341
|
+
result[:daily].each do |daily|
|
342
|
+
daily[:tag].each_key do |tag|
|
343
|
+
result[:tag][tag] ||= {}
|
344
|
+
|
345
|
+
daily[:tag][tag].each do |key, value|
|
346
|
+
result[:tag][tag][key] ||= 0
|
347
|
+
result[:tag][tag][key] += value
|
348
|
+
end
|
302
349
|
end
|
303
350
|
end
|
304
|
-
end
|
305
351
|
|
306
|
-
|
352
|
+
result
|
353
|
+
end
|
307
354
|
end
|
308
355
|
|
309
356
|
def get_task_metrics(backend, task_str, date_str, opts = {})
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
357
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
358
|
+
opts = {:bypool => false, :only => false}.merge(opts)
|
359
|
+
|
360
|
+
task = {
|
361
|
+
duration: {
|
362
|
+
average: 0,
|
363
|
+
min: 0,
|
364
|
+
max: 0,
|
365
|
+
total: 0
|
366
|
+
},
|
367
|
+
count: {
|
368
|
+
total: 0
|
369
|
+
}
|
370
|
+
}
|
323
371
|
|
324
|
-
|
372
|
+
task[:count][:total] = backend.hlen("vmpooler__#{task_str}__#{date_str}").to_i
|
325
373
|
|
326
|
-
|
327
|
-
|
328
|
-
|
374
|
+
if task[:count][:total] > 0
|
375
|
+
if opts[:bypool] == true
|
376
|
+
task_times_bypool = {}
|
329
377
|
|
330
|
-
|
331
|
-
|
378
|
+
task[:count][:pool] = {}
|
379
|
+
task[:duration][:pool] = {}
|
332
380
|
|
333
|
-
|
334
|
-
|
335
|
-
|
381
|
+
backend.hgetall("vmpooler__#{task_str}__#{date_str}").each do |key, value|
|
382
|
+
pool = 'unknown'
|
383
|
+
hostname = 'unknown'
|
336
384
|
|
337
|
-
|
338
|
-
|
339
|
-
|
340
|
-
|
341
|
-
|
385
|
+
if key =~ /:/
|
386
|
+
pool, hostname = key.split(':')
|
387
|
+
else
|
388
|
+
hostname = key
|
389
|
+
end
|
342
390
|
|
343
|
-
|
344
|
-
|
391
|
+
task[:count][:pool][pool] ||= {}
|
392
|
+
task[:duration][:pool][pool] ||= {}
|
345
393
|
|
346
|
-
|
347
|
-
|
348
|
-
|
394
|
+
task_times_bypool[pool] ||= []
|
395
|
+
task_times_bypool[pool].push(value.to_f)
|
396
|
+
end
|
349
397
|
|
350
|
-
|
351
|
-
|
398
|
+
task_times_bypool.each_key do |pool|
|
399
|
+
task[:count][:pool][pool][:total] = task_times_bypool[pool].length
|
352
400
|
|
353
|
-
|
354
|
-
|
355
|
-
|
401
|
+
task[:duration][:pool][pool][:total] = task_times_bypool[pool].reduce(:+).to_f
|
402
|
+
task[:duration][:pool][pool][:average] = (task[:duration][:pool][pool][:total] / task[:count][:pool][pool][:total]).round(1)
|
403
|
+
task[:duration][:pool][pool][:min], task[:duration][:pool][pool][:max] = task_times_bypool[pool].minmax
|
404
|
+
end
|
356
405
|
end
|
357
|
-
end
|
358
406
|
|
359
|
-
|
407
|
+
task_times = get_task_times(backend, task_str, date_str)
|
360
408
|
|
361
|
-
|
362
|
-
|
363
|
-
|
364
|
-
|
409
|
+
task[:duration][:total] = task_times.reduce(:+).to_f
|
410
|
+
task[:duration][:average] = (task[:duration][:total] / task[:count][:total]).round(1)
|
411
|
+
task[:duration][:min], task[:duration][:max] = task_times.minmax
|
412
|
+
end
|
365
413
|
|
366
|
-
|
367
|
-
|
368
|
-
|
414
|
+
if opts[:only]
|
415
|
+
task.each_key do |key|
|
416
|
+
task.delete(key) unless key.to_s == opts[:only]
|
417
|
+
end
|
369
418
|
end
|
370
|
-
end
|
371
419
|
|
372
|
-
|
420
|
+
task
|
421
|
+
end
|
373
422
|
end
|
374
423
|
|
375
424
|
def get_task_summary(backend, task_str, from_date, to_date, opts = {})
|
376
|
-
|
377
|
-
|
378
|
-
task_sym = task_str.to_sym
|
425
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
426
|
+
opts = {:bypool => false, :only => false}.merge(opts)
|
379
427
|
|
380
|
-
|
381
|
-
task_sym => {},
|
382
|
-
daily: []
|
383
|
-
}
|
428
|
+
task_sym = task_str.to_sym
|
384
429
|
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
task_sym => get_task_metrics(backend, task_str, date.to_s, opts)
|
430
|
+
result = {
|
431
|
+
task_sym => {},
|
432
|
+
daily: []
|
389
433
|
}
|
390
|
-
result[:daily].push(daily)
|
391
|
-
end
|
392
434
|
|
393
|
-
|
394
|
-
|
435
|
+
(from_date..to_date).each do |date|
|
436
|
+
daily = {
|
437
|
+
date: date.to_s,
|
438
|
+
task_sym => get_task_metrics(backend, task_str, date.to_s, opts)
|
439
|
+
}
|
440
|
+
result[:daily].push(daily)
|
441
|
+
end
|
442
|
+
|
443
|
+
daily_task = {}
|
444
|
+
daily_task_bypool = {} if opts[:bypool] == true
|
395
445
|
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
446
|
+
result[:daily].each do |daily|
|
447
|
+
daily[task_sym].each_key do |type|
|
448
|
+
result[task_sym][type] ||= {}
|
449
|
+
daily_task[type] ||= {}
|
400
450
|
|
401
|
-
|
402
|
-
|
403
|
-
|
404
|
-
|
451
|
+
['min', 'max'].each do |key|
|
452
|
+
if daily[task_sym][type][key]
|
453
|
+
daily_task[type][:data] ||= []
|
454
|
+
daily_task[type][:data].push(daily[task_sym][type][key])
|
455
|
+
end
|
405
456
|
end
|
406
|
-
end
|
407
457
|
|
408
|
-
|
409
|
-
|
458
|
+
result[task_sym][type][:total] ||= 0
|
459
|
+
result[task_sym][type][:total] += daily[task_sym][type][:total]
|
410
460
|
|
411
|
-
|
412
|
-
|
413
|
-
|
461
|
+
if opts[:bypool] == true
|
462
|
+
result[task_sym][type][:pool] ||= {}
|
463
|
+
daily_task_bypool[type] ||= {}
|
414
464
|
|
415
|
-
|
465
|
+
next unless daily[task_sym][type][:pool]
|
416
466
|
|
417
|
-
|
418
|
-
|
419
|
-
|
467
|
+
daily[task_sym][type][:pool].each_key do |pool|
|
468
|
+
result[task_sym][type][:pool][pool] ||= {}
|
469
|
+
daily_task_bypool[type][pool] ||= {}
|
420
470
|
|
421
|
-
|
422
|
-
|
423
|
-
|
424
|
-
|
471
|
+
['min', 'max'].each do |key|
|
472
|
+
if daily[task_sym][type][:pool][pool][key.to_sym]
|
473
|
+
daily_task_bypool[type][pool][:data] ||= []
|
474
|
+
daily_task_bypool[type][pool][:data].push(daily[task_sym][type][:pool][pool][key.to_sym])
|
475
|
+
end
|
425
476
|
end
|
426
|
-
end
|
427
477
|
|
428
|
-
|
429
|
-
|
478
|
+
result[task_sym][type][:pool][pool][:total] ||= 0
|
479
|
+
result[task_sym][type][:pool][pool][:total] += daily[task_sym][type][:pool][pool][:total]
|
480
|
+
end
|
430
481
|
end
|
431
482
|
end
|
432
483
|
end
|
433
|
-
end
|
434
484
|
|
435
|
-
|
436
|
-
|
437
|
-
|
438
|
-
|
439
|
-
|
485
|
+
result[task_sym].each_key do |type|
|
486
|
+
if daily_task[type][:data]
|
487
|
+
result[task_sym][type][:min], result[task_sym][type][:max] = daily_task[type][:data].minmax
|
488
|
+
result[task_sym][type][:average] = mean(daily_task[type][:data])
|
489
|
+
end
|
440
490
|
|
441
|
-
|
442
|
-
|
443
|
-
|
444
|
-
|
445
|
-
|
446
|
-
|
491
|
+
if opts[:bypool] == true
|
492
|
+
result[task_sym].each_key do |type|
|
493
|
+
result[task_sym][type][:pool].each_key do |pool|
|
494
|
+
if daily_task_bypool[type][pool][:data]
|
495
|
+
result[task_sym][type][:pool][pool][:min], result[task_sym][type][:pool][pool][:max] = daily_task_bypool[type][pool][:data].minmax
|
496
|
+
result[task_sym][type][:pool][pool][:average] = mean(daily_task_bypool[type][pool][:data])
|
497
|
+
end
|
447
498
|
end
|
448
499
|
end
|
449
500
|
end
|
450
501
|
end
|
451
|
-
end
|
452
502
|
|
453
|
-
|
503
|
+
result
|
504
|
+
end
|
454
505
|
end
|
455
506
|
|
456
507
|
def pool_index(pools)
|
@@ -464,11 +515,13 @@ module Vmpooler
|
|
464
515
|
end
|
465
516
|
|
466
517
|
def template_ready?(pool, backend)
|
467
|
-
|
468
|
-
|
469
|
-
|
518
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
519
|
+
prepared_template = backend.hget('vmpooler__template__prepared', pool['name'])
|
520
|
+
return false if prepared_template.nil?
|
521
|
+
return true if pool['template'] == prepared_template
|
470
522
|
|
471
|
-
|
523
|
+
return false
|
524
|
+
end
|
472
525
|
end
|
473
526
|
|
474
527
|
def is_integer?(x)
|
@@ -479,26 +532,39 @@ module Vmpooler
|
|
479
532
|
end
|
480
533
|
|
481
534
|
def open_socket(host, domain = nil, timeout = 1, port = 22, &_block)
|
482
|
-
|
483
|
-
|
484
|
-
|
485
|
-
|
486
|
-
|
487
|
-
|
488
|
-
|
489
|
-
|
535
|
+
tracer.in_span(
|
536
|
+
"Vmpooler::API::Helpers.#{__method__}",
|
537
|
+
attributes: {
|
538
|
+
'net.peer.port' => port,
|
539
|
+
'net.transport' => 'ip_tcp'
|
540
|
+
},
|
541
|
+
kind: :client
|
542
|
+
) do
|
543
|
+
Timeout.timeout(timeout) do
|
544
|
+
target_host = host
|
545
|
+
target_host = "#{host}.#{domain}" if domain
|
546
|
+
span = OpenTelemetry::Trace.current_span
|
547
|
+
span.set_attribute('net.peer.name', target_host)
|
548
|
+
sock = TCPSocket.new target_host, port
|
549
|
+
begin
|
550
|
+
yield sock if block_given?
|
551
|
+
ensure
|
552
|
+
sock.close
|
553
|
+
end
|
490
554
|
end
|
491
555
|
end
|
492
556
|
end
|
493
557
|
|
494
558
|
def vm_ready?(vm_name, domain = nil)
|
495
|
-
|
496
|
-
|
497
|
-
|
498
|
-
|
499
|
-
|
559
|
+
tracer.in_span("Vmpooler::API::Helpers.#{__method__}") do
|
560
|
+
begin
|
561
|
+
open_socket(vm_name, domain)
|
562
|
+
rescue StandardError => _e
|
563
|
+
return false
|
564
|
+
end
|
500
565
|
|
501
|
-
|
566
|
+
true
|
567
|
+
end
|
502
568
|
end
|
503
569
|
end
|
504
570
|
end
|