vmpooler 0.13.3 → 0.14.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: fe0ef9bcf3e665cc952fce0975a4381883fca200ef93a883e54c7db7e1fc10e7
4
- data.tar.gz: d44b61c41a57f940cf0df4bf07aabed10b1a72e91cae5b2105f092a7d98d6d05
3
+ metadata.gz: dd5d793e0bdaa8748908f18a27002b9499f5bb468bd70c500c429a3d83a0f74b
4
+ data.tar.gz: 5723731e8ada5a3ee03dba3494579896fd124c7033a2a497c43d23cffdf8673f
5
5
  SHA512:
6
- metadata.gz: e0e7bbec11ceecc5fdee0fe15b3d37e290a6c884a708a6a5acb2e790d54fb1f1e24ec6966973f02bbecd204a29497e9c17ae3b8be26a0d3f15cec508a0d64532
7
- data.tar.gz: 7302cf41676a65ff5d0bb4108a8f5ac03a96a92e3cd0ec56deee2f2a60d6e73f09eee569ef0f4140e3c27e81a16c3e2d24b951764a772bdeaa082a96d8bde1fe
6
+ metadata.gz: 2806679a57218a92e71de1e28a83782cace4297ba152adcd03386a1501edf4a2697800775e9a782c6988b85117768a3d6f442a5c0d8dc16afbcc22b3bd4d36aa
7
+ data.tar.gz: 72873b8aff48ac8dc484b5f097feab31f3e44605bb220368382e7fc3b6553b4c4627dca40cc5066a91b88d69e07d98fdce169aa1ec3d192a3be968ed966daa39
@@ -11,33 +11,38 @@ redis_connection_pool_size = config[:redis]['connection_pool_size']
11
11
  redis_connection_pool_timeout = config[:redis]['connection_pool_timeout']
12
12
  logger_file = config[:config]['logfile']
13
13
 
14
- metrics = Vmpooler.new_metrics(config)
14
+ logger = Vmpooler::Logger.new logger_file
15
+ metrics = Vmpooler::Metrics.init(logger, config)
15
16
 
16
17
  torun_threads = []
17
18
  if ARGV.count == 0
18
- torun = ['api', 'manager']
19
+ torun = %i[api manager]
19
20
  else
20
21
  torun = []
21
- torun << 'api' if ARGV.include? 'api'
22
- torun << 'manager' if ARGV.include? 'manager'
22
+ torun << :api if ARGV.include? 'api'
23
+ torun << :manager if ARGV.include? 'manager'
23
24
  exit(2) if torun.empty?
24
25
  end
25
26
 
26
- if torun.include? 'api'
27
+ if torun.include? :api
27
28
  api = Thread.new do
28
- thr = Vmpooler::API.new
29
29
  redis = Vmpooler.new_redis(redis_host, redis_port, redis_password)
30
- thr.helpers.configure(config, redis, metrics)
31
- thr.helpers.execute!
30
+ Vmpooler::API.execute(torun, config, redis, metrics, logger)
32
31
  end
33
32
  torun_threads << api
33
+ elsif metrics.respond_to?(:setup_prometheus_metrics)
34
+ # Run the cut down API - Prometheus Metrics only.
35
+ prometheus_only_api = Thread.new do
36
+ Vmpooler::API.execute(torun, config, nil, metrics, logger)
37
+ end
38
+ torun_threads << prometheus_only_api
34
39
  end
35
40
 
36
- if torun.include? 'manager'
41
+ if torun.include? :manager
37
42
  manager = Thread.new do
38
43
  Vmpooler::PoolManager.new(
39
44
  config,
40
- Vmpooler.new_logger(logger_file),
45
+ logger,
41
46
  Vmpooler.redis_connection_pool(redis_host, redis_port, redis_password, redis_connection_pool_size, redis_connection_pool_timeout, metrics),
42
47
  metrics
43
48
  ).execute!
@@ -15,7 +15,7 @@ module Vmpooler
15
15
  require 'timeout'
16
16
  require 'yaml'
17
17
 
18
- %w[api graphite logger pool_manager statsd dummy_statsd generic_connection_pool].each do |lib|
18
+ %w[api metrics logger pool_manager generic_connection_pool].each do |lib|
19
19
  require "vmpooler/#{lib}"
20
20
  end
21
21
 
@@ -84,6 +84,7 @@ module Vmpooler
84
84
  parsed_config[:config]['experimental_features'] = ENV['EXPERIMENTAL_FEATURES'] if ENV['EXPERIMENTAL_FEATURES']
85
85
  parsed_config[:config]['purge_unconfigured_folders'] = ENV['PURGE_UNCONFIGURED_FOLDERS'] if ENV['PURGE_UNCONFIGURED_FOLDERS']
86
86
  parsed_config[:config]['usage_stats'] = ENV['USAGE_STATS'] if ENV['USAGE_STATS']
87
+ parsed_config[:config]['request_logger'] = ENV['REQUEST_LOGGER'] if ENV['REQUEST_LOGGER']
87
88
 
88
89
  parsed_config[:redis] = parsed_config[:redis] || {}
89
90
  parsed_config[:redis]['server'] = ENV['REDIS_SERVER'] || parsed_config[:redis]['server'] || 'localhost'
@@ -166,7 +167,8 @@ module Vmpooler
166
167
  def self.redis_connection_pool(host, port, password, size, timeout, metrics)
167
168
  Vmpooler::PoolManager::GenericConnectionPool.new(
168
169
  metrics: metrics,
169
- metric_prefix: 'redis_connection_pool',
170
+ connpool_type: 'redis_connection_pool',
171
+ connpool_provider: 'manager',
170
172
  size: size,
171
173
  timeout: timeout
172
174
  ) do
@@ -180,20 +182,6 @@ module Vmpooler
180
182
  Redis.new(host: host, port: port, password: password)
181
183
  end
182
184
 
183
- def self.new_logger(logfile)
184
- Vmpooler::Logger.new logfile
185
- end
186
-
187
- def self.new_metrics(params)
188
- if params[:statsd]
189
- Vmpooler::Statsd.new(params[:statsd])
190
- elsif params[:graphite]
191
- Vmpooler::Graphite.new(params[:graphite])
192
- else
193
- Vmpooler::DummyStatsd.new
194
- end
195
- end
196
-
197
185
  def self.pools(conf)
198
186
  conf[:pools]
199
187
  end
@@ -2,51 +2,58 @@
2
2
 
3
3
  module Vmpooler
4
4
  class API < Sinatra::Base
5
- def initialize
6
- super
5
+ # Load API components
6
+ %w[helpers dashboard reroute v1 request_logger].each do |lib|
7
+ require "vmpooler/api/#{lib}"
7
8
  end
9
+ # Load dashboard components
10
+ require 'vmpooler/dashboard'
8
11
 
9
- not_found do
10
- content_type :json
12
+ def self.execute(torun, config, redis, metrics, logger)
13
+ self.settings.set :config, config
14
+ self.settings.set :redis, redis unless redis.nil?
15
+ self.settings.set :metrics, metrics
16
+ self.settings.set :checkoutlock, Mutex.new
11
17
 
12
- result = {
13
- ok: false
14
- }
18
+ # Deflating in all situations
19
+ # https://www.schneems.com/2017/11/08/80-smaller-rails-footprint-with-rack-deflate/
20
+ use Rack::Deflater
15
21
 
16
- JSON.pretty_generate(result)
17
- end
22
+ # not_found clause placed here to fix rspec test issue.
23
+ not_found do
24
+ content_type :json
18
25
 
19
- # Load dashboard components
20
- begin
21
- require 'dashboard'
22
- rescue LoadError
23
- require File.expand_path(File.join(File.dirname(__FILE__), 'dashboard'))
24
- end
26
+ result = {
27
+ ok: false
28
+ }
25
29
 
26
- use Vmpooler::Dashboard
30
+ JSON.pretty_generate(result)
31
+ end
27
32
 
28
- # Load API components
29
- %w[helpers dashboard reroute v1].each do |lib|
30
- begin
31
- require "api/#{lib}"
32
- rescue LoadError
33
- require File.expand_path(File.join(File.dirname(__FILE__), 'api', lib))
33
+ if metrics.respond_to?(:setup_prometheus_metrics)
34
+ # Prometheus metrics are only setup if actually specified
35
+ # in the config file.
36
+ metrics.setup_prometheus_metrics(torun)
37
+
38
+ # Using customised collector that filters out hostnames on API paths
39
+ require 'vmpooler/metrics/promstats/collector_middleware'
40
+ require 'prometheus/middleware/exporter'
41
+ use Vmpooler::Metrics::Promstats::CollectorMiddleware, metrics_prefix: "#{metrics.prometheus_prefix}_http"
42
+ use Prometheus::Middleware::Exporter, path: metrics.prometheus_endpoint
34
43
  end
35
- end
36
44
 
37
- use Vmpooler::API::Dashboard
38
- use Vmpooler::API::Reroute
39
- use Vmpooler::API::V1
45
+ if torun.include? :api
46
+ # Enable API request logging only if required
47
+ use Vmpooler::API::RequestLogger, logger: logger if config[:config]['request_logger']
40
48
 
41
- def configure(config, redis, metrics)
42
- self.settings.set :config, config
43
- self.settings.set :redis, redis
44
- self.settings.set :metrics, metrics
45
- self.settings.set :checkoutlock, Mutex.new
46
- end
49
+ use Vmpooler::Dashboard
50
+ use Vmpooler::API::Dashboard
51
+ use Vmpooler::API::Reroute
52
+ use Vmpooler::API::V1
53
+ end
47
54
 
48
- def execute!
49
- self.settings.run!
55
+ # Get thee started O WebServer
56
+ self.run!
50
57
  end
51
58
  end
52
59
  end
@@ -13,7 +13,7 @@ module Vmpooler
13
13
  def valid_token?(backend)
14
14
  return false unless has_token?
15
15
 
16
- backend.exists('vmpooler__token__' + request.env['HTTP_X_AUTH_TOKEN']) ? true : false
16
+ backend.exists?('vmpooler__token__' + request.env['HTTP_X_AUTH_TOKEN']) ? true : false
17
17
  end
18
18
 
19
19
  def validate_token(backend)
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Vmpooler
4
+ class API
5
+ class RequestLogger
6
+ attr_reader :app
7
+
8
+ def initialize(app, options = {})
9
+ @app = app
10
+ @logger = options[:logger]
11
+ end
12
+
13
+ def call(env)
14
+ status, headers, body = @app.call(env)
15
+ @logger.log('s', "[ ] API: Method: #{env['REQUEST_METHOD']}, Status: #{status}, Path: #{env['PATH_INFO']}, Body: #{body}")
16
+ [status, headers, body]
17
+ end
18
+ end
19
+ end
20
+ end
@@ -89,18 +89,16 @@ module Vmpooler
89
89
  template_backends += aliases
90
90
  weighted_pools = get_pool_weights(template_backends)
91
91
 
92
- pickup = Pickup.new(weighted_pools) if weighted_pools.count == template_backends.count
93
- count.to_i.times do
94
- if pickup
92
+ if weighted_pools.count > 1 && weighted_pools.count == template_backends.count
93
+ pickup = Pickup.new(weighted_pools)
94
+ count.to_i.times do
95
95
  selection << pickup.pick
96
- else
96
+ end
97
+ else
98
+ count.to_i.times do
97
99
  selection << template_backends.sample
98
100
  end
99
101
  end
100
- else
101
- count.to_i.times do
102
- selection << template
103
- end
104
102
  end
105
103
 
106
104
  count_selection(selection)
@@ -339,7 +337,7 @@ module Vmpooler
339
337
  payload&.each do |poolname, count|
340
338
  next unless count.to_i > config['max_ondemand_instances_per_request']
341
339
 
342
- metrics.increment('ondemandrequest.toomanyrequests.' + poolname)
340
+ metrics.increment('ondemandrequest_fail.toomanyrequests.' + poolname)
343
341
  return true
344
342
  end
345
343
  false
@@ -360,10 +358,10 @@ module Vmpooler
360
358
  request_id ||= generate_request_id
361
359
  result['request_id'] = request_id
362
360
 
363
- if backend.exists("vmpooler__odrequest__#{request_id}")
361
+ if backend.exists?("vmpooler__odrequest__#{request_id}")
364
362
  result['message'] = "request_id '#{request_id}' has already been created"
365
363
  status 409
366
- metrics.increment('ondemandrequest.generate.duplicaterequests')
364
+ metrics.increment('ondemandrequest_generate.duplicaterequests')
367
365
  return result
368
366
  end
369
367
 
@@ -387,7 +385,7 @@ module Vmpooler
387
385
 
388
386
  result['domain'] = config['domain'] if config['domain']
389
387
  result[:ok] = true
390
- metrics.increment('ondemandrequest.generate.success')
388
+ metrics.increment('ondemandrequest_generate.success')
391
389
  result
392
390
  end
393
391
 
@@ -809,6 +807,7 @@ module Vmpooler
809
807
 
810
808
  post "#{api_prefix}/ondemandvm/?" do
811
809
  content_type :json
810
+ metrics.increment('http_requests_vm_total.post.ondemand.requestid')
812
811
 
813
812
  need_token! if Vmpooler::API.settings.config[:auth]
814
813
 
@@ -824,12 +823,12 @@ module Vmpooler
824
823
  else
825
824
  result[:bad_templates] = invalid
826
825
  invalid.each do |bad_template|
827
- metrics.increment('ondemandrequest.invalid.' + bad_template)
826
+ metrics.increment('ondemandrequest_fail.invalid.' + bad_template)
828
827
  end
829
828
  status 404
830
829
  end
831
830
  else
832
- metrics.increment('ondemandrequest.invalid.unknown')
831
+ metrics.increment('ondemandrequest_fail.invalid.unknown')
833
832
  status 404
834
833
  end
835
834
  rescue JSON::ParserError
@@ -846,6 +845,7 @@ module Vmpooler
846
845
  post "#{api_prefix}/ondemandvm/:template/?" do
847
846
  content_type :json
848
847
  result = { 'ok' => false }
848
+ metrics.increment('http_requests_vm_total.delete.ondemand.template')
849
849
 
850
850
  need_token! if Vmpooler::API.settings.config[:auth]
851
851
 
@@ -858,12 +858,12 @@ module Vmpooler
858
858
  else
859
859
  result[:bad_templates] = invalid
860
860
  invalid.each do |bad_template|
861
- metrics.increment('ondemandrequest.invalid.' + bad_template)
861
+ metrics.increment('ondemandrequest_fail.invalid.' + bad_template)
862
862
  end
863
863
  status 404
864
864
  end
865
865
  else
866
- metrics.increment('ondemandrequest.invalid.unknown')
866
+ metrics.increment('ondemandrequest_fail.invalid.unknown')
867
867
  status 404
868
868
  end
869
869
 
@@ -872,6 +872,7 @@ module Vmpooler
872
872
 
873
873
  get "#{api_prefix}/ondemandvm/:requestid/?" do
874
874
  content_type :json
875
+ metrics.increment('http_requests_vm_total.get.ondemand.request')
875
876
 
876
877
  status 404
877
878
  result = check_ondemand_request(params[:requestid])
@@ -882,6 +883,7 @@ module Vmpooler
882
883
  delete "#{api_prefix}/ondemandvm/:requestid/?" do
883
884
  content_type :json
884
885
  need_token! if Vmpooler::API.settings.config[:auth]
886
+ metrics.increment('http_requests_vm_total.delete.ondemand.request')
885
887
 
886
888
  status 404
887
889
  result = delete_ondemand_request(params[:requestid])
@@ -892,6 +894,7 @@ module Vmpooler
892
894
  post "#{api_prefix}/vm/?" do
893
895
  content_type :json
894
896
  result = { 'ok' => false }
897
+ metrics.increment('http_requests_vm_total.post.vm.checkout')
895
898
 
896
899
  payload = JSON.parse(request.body.read)
897
900
 
@@ -981,7 +984,12 @@ module Vmpooler
981
984
  result['ready'] = true
982
985
  Parsing.get_platform_pool_count(request_hash['requested']) do |platform_alias, pool, _count|
983
986
  instances = backend.smembers("vmpooler__#{request_id}__#{platform_alias}__#{pool}")
984
- result[platform_alias] = { 'hostname': instances }
987
+
988
+ if result.key?(platform_alias)
989
+ result[platform_alias][:hostname] = result[platform_alias][:hostname] + instances
990
+ else
991
+ result[platform_alias] = { 'hostname': instances }
992
+ end
985
993
  end
986
994
  result['domain'] = config['domain'] if config['domain']
987
995
  status 200
@@ -994,10 +1002,17 @@ module Vmpooler
994
1002
  else
995
1003
  Parsing.get_platform_pool_count(request_hash['requested']) do |platform_alias, pool, count|
996
1004
  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
- }
1005
+ instances_pending = count.to_i - instance_count.to_i
1006
+
1007
+ if result.key?(platform_alias) && result[platform_alias].key?(:ready)
1008
+ result[platform_alias][:ready] = (result[platform_alias][:ready].to_i + instance_count).to_s
1009
+ result[platform_alias][:pending] = (result[platform_alias][:pending].to_i + instances_pending).to_s
1010
+ else
1011
+ result[platform_alias] = {
1012
+ 'ready': instance_count.to_s,
1013
+ 'pending': instances_pending.to_s
1014
+ }
1015
+ end
1001
1016
  end
1002
1017
  end
1003
1018
 
@@ -1034,6 +1049,7 @@ module Vmpooler
1034
1049
  post "#{api_prefix}/vm/:template/?" do
1035
1050
  content_type :json
1036
1051
  result = { 'ok' => false }
1052
+ metrics.increment('http_requests_vm_total.get.vm.template')
1037
1053
 
1038
1054
  payload = extract_templates_from_query_params(params[:template])
1039
1055
 
@@ -1057,6 +1073,7 @@ module Vmpooler
1057
1073
 
1058
1074
  get "#{api_prefix}/vm/:hostname/?" do
1059
1075
  content_type :json
1076
+ metrics.increment('http_requests_vm_total.get.vm.hostname')
1060
1077
 
1061
1078
  result = {}
1062
1079
 
@@ -1129,6 +1146,7 @@ module Vmpooler
1129
1146
 
1130
1147
  delete "#{api_prefix}/vm/:hostname/?" do
1131
1148
  content_type :json
1149
+ metrics.increment('http_requests_vm_total.delete.vm.hostname')
1132
1150
 
1133
1151
  result = {}
1134
1152
 
@@ -1146,8 +1164,9 @@ module Vmpooler
1146
1164
 
1147
1165
  status 200
1148
1166
  result['ok'] = true
1167
+ metrics.increment('delete.success')
1149
1168
  else
1150
- metrics.increment('delete.srem.failed')
1169
+ metrics.increment('delete.failed')
1151
1170
  end
1152
1171
  end
1153
1172
 
@@ -1156,6 +1175,7 @@ module Vmpooler
1156
1175
 
1157
1176
  put "#{api_prefix}/vm/:hostname/?" do
1158
1177
  content_type :json
1178
+ metrics.increment('http_requests_vm_total.put.vm.modify')
1159
1179
 
1160
1180
  status 404
1161
1181
  result = { 'ok' => false }
@@ -1164,7 +1184,7 @@ module Vmpooler
1164
1184
 
1165
1185
  params[:hostname] = hostname_shorten(params[:hostname], config['domain'])
1166
1186
 
1167
- if backend.exists('vmpooler__vm__' + params[:hostname])
1187
+ if backend.exists?('vmpooler__vm__' + params[:hostname])
1168
1188
  begin
1169
1189
  jdata = JSON.parse(request.body.read)
1170
1190
  rescue StandardError
@@ -1232,6 +1252,7 @@ module Vmpooler
1232
1252
 
1233
1253
  post "#{api_prefix}/vm/:hostname/disk/:size/?" do
1234
1254
  content_type :json
1255
+ metrics.increment('http_requests_vm_total.post.vm.disksize')
1235
1256
 
1236
1257
  need_token! if Vmpooler::API.settings.config[:auth]
1237
1258
 
@@ -1240,7 +1261,7 @@ module Vmpooler
1240
1261
 
1241
1262
  params[:hostname] = hostname_shorten(params[:hostname], config['domain'])
1242
1263
 
1243
- if ((params[:size].to_i > 0 )and (backend.exists('vmpooler__vm__' + params[:hostname])))
1264
+ if ((params[:size].to_i > 0 )and (backend.exists?('vmpooler__vm__' + params[:hostname])))
1244
1265
  result[params[:hostname]] = {}
1245
1266
  result[params[:hostname]]['disk'] = "+#{params[:size]}gb"
1246
1267
 
@@ -1255,6 +1276,7 @@ module Vmpooler
1255
1276
 
1256
1277
  post "#{api_prefix}/vm/:hostname/snapshot/?" do
1257
1278
  content_type :json
1279
+ metrics.increment('http_requests_vm_total.post.vm.snapshot')
1258
1280
 
1259
1281
  need_token! if Vmpooler::API.settings.config[:auth]
1260
1282
 
@@ -1263,7 +1285,7 @@ module Vmpooler
1263
1285
 
1264
1286
  params[:hostname] = hostname_shorten(params[:hostname], config['domain'])
1265
1287
 
1266
- if backend.exists('vmpooler__vm__' + params[:hostname])
1288
+ if backend.exists?('vmpooler__vm__' + params[:hostname])
1267
1289
  result[params[:hostname]] = {}
1268
1290
 
1269
1291
  o = [('a'..'z'), ('0'..'9')].map(&:to_a).flatten
@@ -1280,6 +1302,7 @@ module Vmpooler
1280
1302
 
1281
1303
  post "#{api_prefix}/vm/:hostname/snapshot/:snapshot/?" do
1282
1304
  content_type :json
1305
+ metrics.increment('http_requests_vm_total.post.vm.disksize')
1283
1306
 
1284
1307
  need_token! if Vmpooler::API.settings.config[:auth]
1285
1308