vmpooler 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/vmpooler.rb +3 -2
- data/lib/vmpooler/api/v1.rb +29 -6
- data/lib/vmpooler/pool_manager.rb +132 -95
- data/lib/vmpooler/providers/vsphere.rb +1 -1
- data/lib/vmpooler/version.rb +1 -1
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a1b32e5280b92e461243bc99e275e1637fe3c644
|
4
|
+
data.tar.gz: 702ee61515185102a99cecc1d1475b84f2c19ada
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9566067bbaee8024bdcd05d715082e158a61503de81e9d35a7600ba9567e4f033638350718143c86c17db0e912a1fb42f42032b465350afba666a7f3856c8acb
|
7
|
+
data.tar.gz: 415ebd0a8bbbd125ec0a0972be930197f88ac1d927f41683e526aec4465406fe0a6954750892b0b1991b16046686ad64420bb103821620e68e8a017a9b37f208
|
data/lib/vmpooler.rb
CHANGED
@@ -1,15 +1,16 @@
|
|
1
1
|
module Vmpooler
|
2
2
|
require 'date'
|
3
3
|
require 'json'
|
4
|
-
require 'open-uri'
|
5
4
|
require 'net/ldap'
|
5
|
+
require 'open-uri'
|
6
|
+
require 'pickup'
|
6
7
|
require 'rbvmomi'
|
7
8
|
require 'redis'
|
9
|
+
require 'set'
|
8
10
|
require 'sinatra/base'
|
9
11
|
require 'time'
|
10
12
|
require 'timeout'
|
11
13
|
require 'yaml'
|
12
|
-
require 'set'
|
13
14
|
|
14
15
|
%w[api graphite logger pool_manager statsd dummy_statsd generic_connection_pool].each do |lib|
|
15
16
|
require "vmpooler/#{lib}"
|
data/lib/vmpooler/api/v1.rb
CHANGED
@@ -37,15 +37,38 @@ module Vmpooler
|
|
37
37
|
end
|
38
38
|
|
39
39
|
def fetch_single_vm(template)
|
40
|
-
|
41
|
-
return [vm, template] if vm
|
42
|
-
|
40
|
+
template_backends = [template]
|
43
41
|
aliases = Vmpooler::API.settings.config[:alias]
|
44
|
-
if aliases
|
45
|
-
|
46
|
-
|
42
|
+
if aliases
|
43
|
+
template_backends << aliases[template] if aliases[template]
|
44
|
+
|
45
|
+
pool_index = pool_index(pools)
|
46
|
+
weighted_pools = {}
|
47
|
+
template_backends.each do |t|
|
48
|
+
next unless pool_index.key? t
|
49
|
+
index = pool_index[t]
|
50
|
+
clone_target = pools[index]['clone_target'] || config['clone_target']
|
51
|
+
next unless config.key?('backend_weight')
|
52
|
+
weight = config['backend_weight'][clone_target]
|
53
|
+
if weight
|
54
|
+
weighted_pools[t] = weight
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
if weighted_pools.count == template_backends.count
|
59
|
+
pickup = Pickup.new(weighted_pools)
|
60
|
+
selection = pickup.pick
|
61
|
+
template_backends.delete(selection)
|
62
|
+
template_backends.unshift(selection)
|
63
|
+
else
|
64
|
+
template_backends = template_backends.sample(template_backends.count)
|
65
|
+
end
|
47
66
|
end
|
48
67
|
|
68
|
+
template_backends.each do |t|
|
69
|
+
vm = backend.spop('vmpooler__ready__' + t)
|
70
|
+
return [vm, t] if vm
|
71
|
+
end
|
49
72
|
[nil, nil]
|
50
73
|
end
|
51
74
|
|
@@ -188,8 +188,10 @@ module Vmpooler
|
|
188
188
|
|
189
189
|
# Check if the hostname has magically changed from underneath Pooler
|
190
190
|
vm_hash = provider.get_vm(pool['name'], vm)
|
191
|
+
return unless vm_hash.is_a? Hash
|
191
192
|
hostname = vm_hash['hostname']
|
192
193
|
|
194
|
+
return if hostname.nil?
|
193
195
|
return if hostname.empty?
|
194
196
|
return if hostname == vm
|
195
197
|
$redis.smove('vmpooler__ready__' + pool['name'], 'vmpooler__completed__' + pool['name'], vm)
|
@@ -243,20 +245,18 @@ module Vmpooler
|
|
243
245
|
end
|
244
246
|
|
245
247
|
# Clone a VM
|
246
|
-
def clone_vm(
|
248
|
+
def clone_vm(pool_name, provider)
|
247
249
|
Thread.new do
|
248
250
|
begin
|
249
|
-
_clone_vm(
|
251
|
+
_clone_vm(pool_name, provider)
|
250
252
|
rescue => err
|
251
|
-
$logger.log('s', "[!] [#{
|
253
|
+
$logger.log('s', "[!] [#{pool_name}] failed while cloning VM with an error: #{err}")
|
252
254
|
raise
|
253
255
|
end
|
254
256
|
end
|
255
257
|
end
|
256
258
|
|
257
|
-
def _clone_vm(
|
258
|
-
pool_name = pool['name']
|
259
|
-
|
259
|
+
def _clone_vm(pool_name, provider)
|
260
260
|
# Generate a randomized hostname
|
261
261
|
o = [('a'..'z'), ('0'..'9')].map(&:to_a).flatten
|
262
262
|
new_vmname = $config[:config]['prefix'] + o[rand(25)] + (0...14).map { o[rand(o.length)] }.join
|
@@ -723,7 +723,16 @@ module Vmpooler
|
|
723
723
|
end
|
724
724
|
|
725
725
|
def prepare_template(pool, provider)
|
726
|
-
|
726
|
+
if $config[:config]['create_template_delta_disks']
|
727
|
+
unless $redis.sismember('vmpooler__template__deltas', pool['template'])
|
728
|
+
begin
|
729
|
+
provider.create_template_delta_disks(pool)
|
730
|
+
$redis.sadd('vmpooler__template__deltas', pool['template'])
|
731
|
+
rescue => err
|
732
|
+
$logger.log('s', "[!] [#{pool['name']}] failed while preparing a template with an error. As a result vmpooler could not create the template delta disks. Either a template delta disk already exists, or the template delta disk creation failed. The error is: #{err}")
|
733
|
+
end
|
734
|
+
end
|
735
|
+
end
|
727
736
|
$redis.hset('vmpooler__template__prepared', pool['name'], pool['template'])
|
728
737
|
end
|
729
738
|
|
@@ -779,7 +788,9 @@ module Vmpooler
|
|
779
788
|
$logger.log('s', "[*] [#{pool['name']}] is ready for use")
|
780
789
|
end
|
781
790
|
|
782
|
-
def remove_excess_vms(pool
|
791
|
+
def remove_excess_vms(pool)
|
792
|
+
ready = $redis.scard("vmpooler__ready__#{pool['name']}")
|
793
|
+
total = $redis.scard("vmpooler__pending__#{pool['name']}") + ready
|
783
794
|
return if total.nil?
|
784
795
|
return if total == 0
|
785
796
|
mutex = pool_mutex(pool['name'])
|
@@ -811,17 +822,7 @@ module Vmpooler
|
|
811
822
|
end
|
812
823
|
end
|
813
824
|
|
814
|
-
def
|
815
|
-
pool_check_response = {
|
816
|
-
discovered_vms: 0,
|
817
|
-
checked_running_vms: 0,
|
818
|
-
checked_ready_vms: 0,
|
819
|
-
checked_pending_vms: 0,
|
820
|
-
destroyed_vms: 0,
|
821
|
-
migrated_vms: 0,
|
822
|
-
cloned_vms: 0
|
823
|
-
}
|
824
|
-
# INVENTORY
|
825
|
+
def create_inventory(pool, provider, pool_check_response)
|
825
826
|
inventory = {}
|
826
827
|
begin
|
827
828
|
mutex = pool_mutex(pool['name'])
|
@@ -844,103 +845,170 @@ module Vmpooler
|
|
844
845
|
end
|
845
846
|
end
|
846
847
|
rescue => err
|
847
|
-
$logger.log('s', "[!] [#{pool['name']}] _check_pool failed with an error while
|
848
|
-
|
848
|
+
$logger.log('s', "[!] [#{pool['name']}] _check_pool failed with an error while running create_inventory: #{err}")
|
849
|
+
raise(err)
|
849
850
|
end
|
851
|
+
inventory
|
852
|
+
end
|
850
853
|
|
851
|
-
|
852
|
-
$redis.smembers("vmpooler__running__#{
|
854
|
+
def check_running_pool_vms(pool_name, provider, pool_check_response, inventory)
|
855
|
+
$redis.smembers("vmpooler__running__#{pool_name}").each do |vm|
|
853
856
|
if inventory[vm]
|
854
857
|
begin
|
855
858
|
vm_lifetime = $redis.hget('vmpooler__vm__' + vm, 'lifetime') || $config[:config]['vm_lifetime'] || 12
|
856
859
|
pool_check_response[:checked_running_vms] += 1
|
857
|
-
check_running_vm(vm,
|
860
|
+
check_running_vm(vm, pool_name, vm_lifetime, provider)
|
858
861
|
rescue => err
|
859
|
-
$logger.log('d', "[!] [#{
|
862
|
+
$logger.log('d', "[!] [#{pool_name}] _check_pool with an error while evaluating running VMs: #{err}")
|
860
863
|
end
|
861
864
|
else
|
862
|
-
move_vm_queue(
|
865
|
+
move_vm_queue(pool_name, vm, 'running', 'completed', 'is a running VM but is missing from inventory. Marking as completed.')
|
863
866
|
end
|
864
867
|
end
|
868
|
+
end
|
865
869
|
|
866
|
-
|
867
|
-
$redis.smembers("vmpooler__ready__#{
|
870
|
+
def check_ready_pool_vms(pool_name, provider, pool_check_response, inventory, pool_ttl = 0)
|
871
|
+
$redis.smembers("vmpooler__ready__#{pool_name}").each do |vm|
|
868
872
|
if inventory[vm]
|
869
873
|
begin
|
870
874
|
pool_check_response[:checked_ready_vms] += 1
|
871
|
-
check_ready_vm(vm,
|
875
|
+
check_ready_vm(vm, pool_name, pool_ttl || 0, provider)
|
872
876
|
rescue => err
|
873
|
-
$logger.log('d', "[!] [#{
|
877
|
+
$logger.log('d', "[!] [#{pool_name}] _check_pool failed with an error while evaluating ready VMs: #{err}")
|
874
878
|
end
|
875
879
|
else
|
876
|
-
move_vm_queue(
|
880
|
+
move_vm_queue(pool_name, vm, 'ready', 'completed', 'is a ready VM but is missing from inventory. Marking as completed.')
|
877
881
|
end
|
878
882
|
end
|
883
|
+
end
|
879
884
|
|
880
|
-
|
881
|
-
$
|
882
|
-
|
885
|
+
def check_pending_pool_vms(pool_name, provider, pool_check_response, inventory, pool_timeout = nil)
|
886
|
+
pool_timeout ||= $config[:config]['timeout'] || 15
|
887
|
+
$redis.smembers("vmpooler__pending__#{pool_name}").each do |vm|
|
883
888
|
if inventory[vm]
|
884
889
|
begin
|
885
890
|
pool_check_response[:checked_pending_vms] += 1
|
886
|
-
check_pending_vm(vm,
|
891
|
+
check_pending_vm(vm, pool_name, pool_timeout, provider)
|
887
892
|
rescue => err
|
888
|
-
$logger.log('d', "[!] [#{
|
893
|
+
$logger.log('d', "[!] [#{pool_name}] _check_pool failed with an error while evaluating pending VMs: #{err}")
|
889
894
|
end
|
890
895
|
else
|
891
|
-
fail_pending_vm(vm,
|
896
|
+
fail_pending_vm(vm, pool_name, pool_timeout, false)
|
892
897
|
end
|
893
898
|
end
|
899
|
+
end
|
894
900
|
|
895
|
-
|
896
|
-
$redis.smembers("vmpooler__completed__#{
|
901
|
+
def check_completed_pool_vms(pool_name, provider, pool_check_response, inventory)
|
902
|
+
$redis.smembers("vmpooler__completed__#{pool_name}").each do |vm|
|
897
903
|
if inventory[vm]
|
898
904
|
begin
|
899
905
|
pool_check_response[:destroyed_vms] += 1
|
900
|
-
destroy_vm(vm,
|
906
|
+
destroy_vm(vm, pool_name, provider)
|
901
907
|
rescue => err
|
902
|
-
$redis.srem("vmpooler__completed__#{
|
903
|
-
$redis.hdel("vmpooler__active__#{
|
908
|
+
$redis.srem("vmpooler__completed__#{pool_name}", vm)
|
909
|
+
$redis.hdel("vmpooler__active__#{pool_name}", vm)
|
904
910
|
$redis.del("vmpooler__vm__#{vm}")
|
905
|
-
$logger.log('d', "[!] [#{
|
911
|
+
$logger.log('d', "[!] [#{pool_name}] _check_pool failed with an error while evaluating completed VMs: #{err}")
|
906
912
|
end
|
907
913
|
else
|
908
|
-
$logger.log('s', "[!] [#{
|
909
|
-
$redis.srem("vmpooler__completed__#{
|
910
|
-
$redis.hdel("vmpooler__active__#{
|
914
|
+
$logger.log('s', "[!] [#{pool_name}] '#{vm}' not found in inventory, removed from 'completed' queue")
|
915
|
+
$redis.srem("vmpooler__completed__#{pool_name}", vm)
|
916
|
+
$redis.hdel("vmpooler__active__#{pool_name}", vm)
|
911
917
|
$redis.del("vmpooler__vm__#{vm}")
|
912
918
|
end
|
913
919
|
end
|
920
|
+
end
|
914
921
|
|
915
|
-
|
922
|
+
def check_discovered_pool_vms(pool_name)
|
916
923
|
begin
|
917
|
-
$redis.smembers("vmpooler__discovered__#{
|
924
|
+
$redis.smembers("vmpooler__discovered__#{pool_name}").each do |vm|
|
918
925
|
%w[pending ready running completed].each do |queue|
|
919
|
-
if $redis.sismember("vmpooler__#{queue}__#{
|
920
|
-
$logger.log('d', "[!] [#{
|
921
|
-
$redis.srem("vmpooler__discovered__#{
|
926
|
+
if $redis.sismember("vmpooler__#{queue}__#{pool_name}", vm)
|
927
|
+
$logger.log('d', "[!] [#{pool_name}] '#{vm}' found in '#{queue}', removed from 'discovered' queue")
|
928
|
+
$redis.srem("vmpooler__discovered__#{pool_name}", vm)
|
922
929
|
end
|
923
930
|
end
|
924
931
|
|
925
|
-
if $redis.sismember("vmpooler__discovered__#{
|
926
|
-
$redis.smove("vmpooler__discovered__#{
|
932
|
+
if $redis.sismember("vmpooler__discovered__#{pool_name}", vm)
|
933
|
+
$redis.smove("vmpooler__discovered__#{pool_name}", "vmpooler__completed__#{pool_name}", vm)
|
927
934
|
end
|
928
935
|
end
|
929
936
|
rescue => err
|
930
|
-
$logger.log('d', "[!] [#{
|
937
|
+
$logger.log('d', "[!] [#{pool_name}] _check_pool failed with an error while evaluating discovered VMs: #{err}")
|
931
938
|
end
|
939
|
+
end
|
932
940
|
|
933
|
-
|
934
|
-
$redis.smembers("vmpooler__migrating__#{
|
941
|
+
def check_migrating_pool_vms(pool_name, provider, pool_check_response, inventory)
|
942
|
+
$redis.smembers("vmpooler__migrating__#{pool_name}").each do |vm|
|
935
943
|
if inventory[vm]
|
936
944
|
begin
|
937
945
|
pool_check_response[:migrated_vms] += 1
|
938
|
-
migrate_vm(vm,
|
946
|
+
migrate_vm(vm, pool_name, provider)
|
947
|
+
rescue => err
|
948
|
+
$logger.log('s', "[x] [#{pool_name}] '#{vm}' failed to migrate: #{err}")
|
949
|
+
end
|
950
|
+
end
|
951
|
+
end
|
952
|
+
end
|
953
|
+
|
954
|
+
def repopulate_pool_vms(pool_name, provider, pool_check_response, pool_size)
|
955
|
+
return if pool_mutex(pool_name).locked?
|
956
|
+
ready = $redis.scard("vmpooler__ready__#{pool_name}")
|
957
|
+
total = $redis.scard("vmpooler__pending__#{pool_name}") + ready
|
958
|
+
|
959
|
+
$metrics.gauge("ready.#{pool_name}", $redis.scard("vmpooler__ready__#{pool_name}"))
|
960
|
+
$metrics.gauge("running.#{pool_name}", $redis.scard("vmpooler__running__#{pool_name}"))
|
961
|
+
|
962
|
+
if $redis.get("vmpooler__empty__#{pool_name}")
|
963
|
+
$redis.del("vmpooler__empty__#{pool_name}") unless ready.zero?
|
964
|
+
elsif ready.zero?
|
965
|
+
$redis.set("vmpooler__empty__#{pool_name}", 'true')
|
966
|
+
$logger.log('s', "[!] [#{pool_name}] is empty")
|
967
|
+
end
|
968
|
+
|
969
|
+
(pool_size - total).times do
|
970
|
+
if $redis.get('vmpooler__tasks__clone').to_i < $config[:config]['task_limit'].to_i
|
971
|
+
begin
|
972
|
+
$redis.incr('vmpooler__tasks__clone')
|
973
|
+
pool_check_response[:cloned_vms] += 1
|
974
|
+
clone_vm(pool_name, provider)
|
939
975
|
rescue => err
|
940
|
-
$logger.log('s', "[
|
976
|
+
$logger.log('s', "[!] [#{pool_name}] clone failed during check_pool with an error: #{err}")
|
977
|
+
$redis.decr('vmpooler__tasks__clone')
|
978
|
+
raise
|
941
979
|
end
|
942
980
|
end
|
943
981
|
end
|
982
|
+
end
|
983
|
+
|
984
|
+
def _check_pool(pool, provider)
|
985
|
+
pool_check_response = {
|
986
|
+
discovered_vms: 0,
|
987
|
+
checked_running_vms: 0,
|
988
|
+
checked_ready_vms: 0,
|
989
|
+
checked_pending_vms: 0,
|
990
|
+
destroyed_vms: 0,
|
991
|
+
migrated_vms: 0,
|
992
|
+
cloned_vms: 0
|
993
|
+
}
|
994
|
+
|
995
|
+
begin
|
996
|
+
inventory = create_inventory(pool, provider, pool_check_response)
|
997
|
+
rescue => err
|
998
|
+
return(pool_check_response)
|
999
|
+
end
|
1000
|
+
|
1001
|
+
check_running_pool_vms(pool['name'], provider, pool_check_response, inventory)
|
1002
|
+
|
1003
|
+
check_ready_pool_vms(pool['name'], provider, pool_check_response, inventory, pool['ready_ttl'])
|
1004
|
+
|
1005
|
+
check_pending_pool_vms(pool['name'], provider, pool_check_response, inventory, pool['timeout'])
|
1006
|
+
|
1007
|
+
check_completed_pool_vms(pool['name'], provider, pool_check_response, inventory)
|
1008
|
+
|
1009
|
+
check_discovered_pool_vms(pool['name'])
|
1010
|
+
|
1011
|
+
check_migrating_pool_vms(pool['name'], provider, pool_check_response, inventory)
|
944
1012
|
|
945
1013
|
# UPDATE TEMPLATE
|
946
1014
|
# Evaluates a pool template to ensure templates are prepared adequately for the configured provider
|
@@ -948,46 +1016,15 @@ module Vmpooler
|
|
948
1016
|
# Additionally, a pool will drain ready and pending instances
|
949
1017
|
evaluate_template(pool, provider)
|
950
1018
|
|
951
|
-
#
|
952
|
-
#
|
953
|
-
|
954
|
-
|
955
|
-
total = $redis.scard("vmpooler__pending__#{pool['name']}") + ready
|
1019
|
+
# Check to see if a pool size change has been made via the configuration API
|
1020
|
+
# Since check_pool runs in a loop it does not
|
1021
|
+
# otherwise identify this change when running
|
1022
|
+
update_pool_size(pool)
|
956
1023
|
|
957
|
-
|
958
|
-
$metrics.gauge("running.#{pool['name']}", $redis.scard("vmpooler__running__#{pool['name']}"))
|
959
|
-
|
960
|
-
if $redis.get("vmpooler__empty__#{pool['name']}")
|
961
|
-
$redis.del("vmpooler__empty__#{pool['name']}") unless ready.zero?
|
962
|
-
elsif ready.zero?
|
963
|
-
$redis.set("vmpooler__empty__#{pool['name']}", 'true')
|
964
|
-
$logger.log('s', "[!] [#{pool['name']}] is empty")
|
965
|
-
end
|
966
|
-
|
967
|
-
# Check to see if a pool size change has been made via the configuration API
|
968
|
-
# Since check_pool runs in a loop it does not
|
969
|
-
# otherwise identify this change when running
|
970
|
-
update_pool_size(pool)
|
971
|
-
|
972
|
-
if total < pool['size']
|
973
|
-
(1..(pool['size'] - total)).each do |_i|
|
974
|
-
if $redis.get('vmpooler__tasks__clone').to_i < $config[:config]['task_limit'].to_i
|
975
|
-
begin
|
976
|
-
$redis.incr('vmpooler__tasks__clone')
|
977
|
-
pool_check_response[:cloned_vms] += 1
|
978
|
-
clone_vm(pool, provider)
|
979
|
-
rescue => err
|
980
|
-
$logger.log('s', "[!] [#{pool['name']}] clone failed during check_pool with an error: #{err}")
|
981
|
-
$redis.decr('vmpooler__tasks__clone')
|
982
|
-
raise
|
983
|
-
end
|
984
|
-
end
|
985
|
-
end
|
986
|
-
end
|
987
|
-
end
|
1024
|
+
repopulate_pool_vms(pool['name'], provider, pool_check_response, pool['size'])
|
988
1025
|
|
989
1026
|
# Remove VMs in excess of the configured pool size
|
990
|
-
remove_excess_vms(pool
|
1027
|
+
remove_excess_vms(pool)
|
991
1028
|
|
992
1029
|
pool_check_response
|
993
1030
|
end
|
data/lib/vmpooler/version.rb
CHANGED
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vmpooler
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Puppet
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-09-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: pickup
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.0.11
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.0.11
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: puma
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|