vmpooler 0.2.0 → 0.2.1
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.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
|