vmpooler 0.13.3 → 0.14.4

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: 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