vmpooler 0.13.1 → 0.14.2

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: 3f6f3dafe8bbb4d65b5dc088ff36c24b12a3e6382aa2ec84f5a504e58e36eb6c
4
- data.tar.gz: e488162ea027f566d44c762aa10095529d5610048bff7674e4695c16b37d61a1
3
+ metadata.gz: 2b0e071edb016f25c0379ebc2d7768e945096333d9be2f1f31ce66fc32474fd1
4
+ data.tar.gz: 1bbac7250090c48a74bf671d316cb9aa45d1dc55af1f69351e9afd27f7c4ed9d
5
5
  SHA512:
6
- metadata.gz: 3ba72cb12cce3ab544437948751662434ce936014fdb68e63bbd6484bcceddaade2918b51852a6fd7d8171ea9a28d14135102cbe23cbae521fcbeb7f40ad6f7a
7
- data.tar.gz: 484fd410cd7f96bde01bc928e3afc4cb5fb9eeebffdda8ebf615fd0414d1db10a294f28afdacc0e5cac3cf7448fc8c3a4636b50b2d02c4dc017034da6a0c4f41
6
+ metadata.gz: 21bc1b2a3c83e82a2e4f3ad6f54a41a380a76a331ca8613b49acf0f7cd2df6ff69162e600f7d449e482e110d1ac7e3e5d9534cd1479d990dd4ff4f8c2c079b74
7
+ data.tar.gz: 109ae1cbfa75cc80a3afff19938677856f9ac0fd858cb546d6ea42b8dbbddf515cad3cdb6cfcb340addbe863c5ee1fc9c4025704bdb298584a7ab8696dd27de9
@@ -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.metrics_prefix}_http"
42
+ use Prometheus::Middleware::Exporter, path: metrics.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
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'vmpooler/util/parsing'
4
+
3
5
  module Vmpooler
4
6
  class API
5
7
  class V1 < Sinatra::Base
@@ -334,9 +336,10 @@ module Vmpooler
334
336
  end
335
337
 
336
338
  def too_many_requested?(payload)
337
- payload&.each do |_poolname, count|
339
+ payload&.each do |poolname, count|
338
340
  next unless count.to_i > config['max_ondemand_instances_per_request']
339
341
 
342
+ metrics.increment('ondemandrequest_fail.toomanyrequests.' + poolname)
340
343
  return true
341
344
  end
342
345
  false
@@ -357,9 +360,10 @@ module Vmpooler
357
360
  request_id ||= generate_request_id
358
361
  result['request_id'] = request_id
359
362
 
360
- if backend.exists("vmpooler__odrequest__#{request_id}")
363
+ if backend.exists?("vmpooler__odrequest__#{request_id}")
361
364
  result['message'] = "request_id '#{request_id}' has already been created"
362
365
  status 409
366
+ metrics.increment('ondemandrequest_generate.duplicaterequests')
363
367
  return result
364
368
  end
365
369
 
@@ -383,6 +387,7 @@ module Vmpooler
383
387
 
384
388
  result['domain'] = config['domain'] if config['domain']
385
389
  result[:ok] = true
390
+ metrics.increment('ondemandrequest_generate.success')
386
391
  result
387
392
  end
388
393
 
@@ -804,6 +809,7 @@ module Vmpooler
804
809
 
805
810
  post "#{api_prefix}/ondemandvm/?" do
806
811
  content_type :json
812
+ metrics.increment('api_vm.post.ondemand.requestid')
807
813
 
808
814
  need_token! if Vmpooler::API.settings.config[:auth]
809
815
 
@@ -819,12 +825,12 @@ module Vmpooler
819
825
  else
820
826
  result[:bad_templates] = invalid
821
827
  invalid.each do |bad_template|
822
- metrics.increment('ondemandrequest.invalid.' + bad_template)
828
+ metrics.increment('ondemandrequest_fail.invalid.' + bad_template)
823
829
  end
824
830
  status 404
825
831
  end
826
832
  else
827
- metrics.increment('ondemandrequest.invalid.unknown')
833
+ metrics.increment('ondemandrequest_fail.invalid.unknown')
828
834
  status 404
829
835
  end
830
836
  rescue JSON::ParserError
@@ -841,6 +847,7 @@ module Vmpooler
841
847
  post "#{api_prefix}/ondemandvm/:template/?" do
842
848
  content_type :json
843
849
  result = { 'ok' => false }
850
+ metrics.increment('api_vm.delete.ondemand.template')
844
851
 
845
852
  need_token! if Vmpooler::API.settings.config[:auth]
846
853
 
@@ -853,12 +860,12 @@ module Vmpooler
853
860
  else
854
861
  result[:bad_templates] = invalid
855
862
  invalid.each do |bad_template|
856
- metrics.increment('ondemandrequest.invalid.' + bad_template)
863
+ metrics.increment('ondemandrequest_fail.invalid.' + bad_template)
857
864
  end
858
865
  status 404
859
866
  end
860
867
  else
861
- metrics.increment('ondemandrequest.invalid.unknown')
868
+ metrics.increment('ondemandrequest_fail.invalid.unknown')
862
869
  status 404
863
870
  end
864
871
 
@@ -867,6 +874,7 @@ module Vmpooler
867
874
 
868
875
  get "#{api_prefix}/ondemandvm/:requestid/?" do
869
876
  content_type :json
877
+ metrics.increment('api_vm.get.ondemand.request')
870
878
 
871
879
  status 404
872
880
  result = check_ondemand_request(params[:requestid])
@@ -877,6 +885,7 @@ module Vmpooler
877
885
  delete "#{api_prefix}/ondemandvm/:requestid/?" do
878
886
  content_type :json
879
887
  need_token! if Vmpooler::API.settings.config[:auth]
888
+ metrics.increment('api_vm.delete.ondemand.request')
880
889
 
881
890
  status 404
882
891
  result = delete_ondemand_request(params[:requestid])
@@ -887,6 +896,7 @@ module Vmpooler
887
896
  post "#{api_prefix}/vm/?" do
888
897
  content_type :json
889
898
  result = { 'ok' => false }
899
+ metrics.increment('api_vm.post.vm.checkout')
890
900
 
891
901
  payload = JSON.parse(request.body.read)
892
902
 
@@ -974,11 +984,14 @@ module Vmpooler
974
984
 
975
985
  if request_hash['status'] == 'ready'
976
986
  result['ready'] = true
977
- platform_parts = request_hash['requested'].split(',')
978
- platform_parts.each do |platform|
979
- pool_alias, pool, _count = platform.split(':')
980
- instances = backend.smembers("vmpooler__#{request_id}__#{pool_alias}__#{pool}")
981
- result[pool_alias] = { 'hostname': instances }
987
+ Parsing.get_platform_pool_count(request_hash['requested']) do |platform_alias, pool, _count|
988
+ instances = backend.smembers("vmpooler__#{request_id}__#{platform_alias}__#{pool}")
989
+
990
+ if result.key?(platform_alias)
991
+ result[platform_alias][:hostname] = result[platform_alias][:hostname] + instances
992
+ else
993
+ result[platform_alias] = { 'hostname': instances }
994
+ end
982
995
  end
983
996
  result['domain'] = config['domain'] if config['domain']
984
997
  status 200
@@ -989,14 +1002,19 @@ module Vmpooler
989
1002
  result['message'] = 'The request has been deleted'
990
1003
  status 200
991
1004
  else
992
- platform_parts = request_hash['requested'].split(',')
993
- platform_parts.each do |platform|
994
- pool_alias, pool, count = platform.split(':')
995
- instance_count = backend.scard("vmpooler__#{request_id}__#{pool_alias}__#{pool}")
996
- result[pool_alias] = {
997
- 'ready': instance_count.to_s,
998
- 'pending': (count.to_i - instance_count.to_i).to_s
999
- }
1005
+ Parsing.get_platform_pool_count(request_hash['requested']) do |platform_alias, pool, count|
1006
+ instance_count = backend.scard("vmpooler__#{request_id}__#{platform_alias}__#{pool}")
1007
+ instances_pending = count.to_i - instance_count.to_i
1008
+
1009
+ if result.key?(platform_alias) && result[platform_alias].key?(:ready)
1010
+ result[platform_alias][:ready] = (result[platform_alias][:ready].to_i + instance_count).to_s
1011
+ result[platform_alias][:pending] = (result[platform_alias][:pending].to_i + instances_pending).to_s
1012
+ else
1013
+ result[platform_alias] = {
1014
+ 'ready': instance_count.to_s,
1015
+ 'pending': instances_pending.to_s
1016
+ }
1017
+ end
1000
1018
  end
1001
1019
  end
1002
1020
 
@@ -1017,12 +1035,11 @@ module Vmpooler
1017
1035
  else
1018
1036
  backend.hset("vmpooler__odrequest__#{request_id}", 'status', 'deleted')
1019
1037
 
1020
- platforms.split(',').each do |platform|
1021
- pool_alias, pool, _count = platform.split(':')
1022
- backend.smembers("vmpooler__#{request_id}__#{pool_alias}__#{pool}")&.each do |vm|
1038
+ Parsing.get_platform_pool_count(platforms) do |platform_alias, pool, _count|
1039
+ backend.smembers("vmpooler__#{request_id}__#{platform_alias}__#{pool}")&.each do |vm|
1023
1040
  backend.smove("vmpooler__running__#{pool}", "vmpooler__completed__#{pool}", vm)
1024
1041
  end
1025
- backend.del("vmpooler__#{request_id}__#{pool_alias}__#{pool}")
1042
+ backend.del("vmpooler__#{request_id}__#{platform_alias}__#{pool}")
1026
1043
  end
1027
1044
  backend.expire("vmpooler__odrequest__#{request_id}", 129_600_0)
1028
1045
  end
@@ -1034,6 +1051,7 @@ module Vmpooler
1034
1051
  post "#{api_prefix}/vm/:template/?" do
1035
1052
  content_type :json
1036
1053
  result = { 'ok' => false }
1054
+ metrics.increment('api_vm.get.vm.template')
1037
1055
 
1038
1056
  payload = extract_templates_from_query_params(params[:template])
1039
1057
 
@@ -1057,6 +1075,7 @@ module Vmpooler
1057
1075
 
1058
1076
  get "#{api_prefix}/vm/:hostname/?" do
1059
1077
  content_type :json
1078
+ metrics.increment('api_vm.get.vm.hostname')
1060
1079
 
1061
1080
  result = {}
1062
1081
 
@@ -1129,6 +1148,7 @@ module Vmpooler
1129
1148
 
1130
1149
  delete "#{api_prefix}/vm/:hostname/?" do
1131
1150
  content_type :json
1151
+ metrics.increment('api_vm.delete.vm.hostname')
1132
1152
 
1133
1153
  result = {}
1134
1154
 
@@ -1146,8 +1166,9 @@ module Vmpooler
1146
1166
 
1147
1167
  status 200
1148
1168
  result['ok'] = true
1169
+ metrics.increment('delete.success')
1149
1170
  else
1150
- metrics.increment('delete.srem.failed')
1171
+ metrics.increment('delete.failed')
1151
1172
  end
1152
1173
  end
1153
1174
 
@@ -1156,6 +1177,7 @@ module Vmpooler
1156
1177
 
1157
1178
  put "#{api_prefix}/vm/:hostname/?" do
1158
1179
  content_type :json
1180
+ metrics.increment('api_vm.put.vm.modify')
1159
1181
 
1160
1182
  status 404
1161
1183
  result = { 'ok' => false }
@@ -1164,7 +1186,7 @@ module Vmpooler
1164
1186
 
1165
1187
  params[:hostname] = hostname_shorten(params[:hostname], config['domain'])
1166
1188
 
1167
- if backend.exists('vmpooler__vm__' + params[:hostname])
1189
+ if backend.exists?('vmpooler__vm__' + params[:hostname])
1168
1190
  begin
1169
1191
  jdata = JSON.parse(request.body.read)
1170
1192
  rescue StandardError
@@ -1232,6 +1254,7 @@ module Vmpooler
1232
1254
 
1233
1255
  post "#{api_prefix}/vm/:hostname/disk/:size/?" do
1234
1256
  content_type :json
1257
+ metrics.increment('api_vm.post.vm.disksize')
1235
1258
 
1236
1259
  need_token! if Vmpooler::API.settings.config[:auth]
1237
1260
 
@@ -1240,7 +1263,7 @@ module Vmpooler
1240
1263
 
1241
1264
  params[:hostname] = hostname_shorten(params[:hostname], config['domain'])
1242
1265
 
1243
- if ((params[:size].to_i > 0 )and (backend.exists('vmpooler__vm__' + params[:hostname])))
1266
+ if ((params[:size].to_i > 0 )and (backend.exists?('vmpooler__vm__' + params[:hostname])))
1244
1267
  result[params[:hostname]] = {}
1245
1268
  result[params[:hostname]]['disk'] = "+#{params[:size]}gb"
1246
1269
 
@@ -1255,6 +1278,7 @@ module Vmpooler
1255
1278
 
1256
1279
  post "#{api_prefix}/vm/:hostname/snapshot/?" do
1257
1280
  content_type :json
1281
+ metrics.increment('api_vm.post.vm.snapshot')
1258
1282
 
1259
1283
  need_token! if Vmpooler::API.settings.config[:auth]
1260
1284
 
@@ -1263,7 +1287,7 @@ module Vmpooler
1263
1287
 
1264
1288
  params[:hostname] = hostname_shorten(params[:hostname], config['domain'])
1265
1289
 
1266
- if backend.exists('vmpooler__vm__' + params[:hostname])
1290
+ if backend.exists?('vmpooler__vm__' + params[:hostname])
1267
1291
  result[params[:hostname]] = {}
1268
1292
 
1269
1293
  o = [('a'..'z'), ('0'..'9')].map(&:to_a).flatten
@@ -1280,6 +1304,7 @@ module Vmpooler
1280
1304
 
1281
1305
  post "#{api_prefix}/vm/:hostname/snapshot/:snapshot/?" do
1282
1306
  content_type :json
1307
+ metrics.increment('api_vm.post.vm.disksize')
1283
1308
 
1284
1309
  need_token! if Vmpooler::API.settings.config[:auth]
1285
1310