Class: VM
- Inherits:
-
Object
- Object
- VM
- Defined in:
- lib/floatyhelper/vm.rb
Class Method Summary collapse
- .alive(host, query = nil) ⇒ Object
-
.destroy(id) ⇒ Object
VM Management ###.
- .find_pooled_platforms ⇒ Object
- .get_current_lifetime(host) ⇒ Object
-
.get_vm(platform: 'centos-7-x86_64', force_abs: false, number: 1) ⇒ Object
Get a VM from floaty ###.
- .getsnapshot(id, snaptag) ⇒ Object
- .increaselife(id, amount = nil) ⇒ Object
-
.parse_response(response) ⇒ Object
Response should be something like: - vm1.delivery.puppetlabs.net (platform-tag)n - vm2.delivery.puppetlabs.net (platform-tag)n.
-
.pooled_platforms_default ⇒ Object
Assume we only have 1 of each if we can’t find the info.
- .query(host) ⇒ Object
- .revert(id, snaptag) ⇒ Object
- .snaplist(tag) ⇒ Object
-
.snapshot(id, snaptag) ⇒ Object
Snapshots ###.
- .snaptag_exists?(id, snaptag) ⇒ Boolean
Class Method Details
.alive(host, query = nil) ⇒ Object
69 70 71 72 |
# File 'lib/floatyhelper/vm.rb', line 69 def self.alive(host, query = nil) query ||= query(host) query['ok'] && query[host]['state'] == 'running' end |
.destroy(id) ⇒ Object
VM Management ###
51 52 53 54 55 56 57 |
# File 'lib/floatyhelper/vm.rb', line 51 def self.destroy(id) hosts = Hosts.get_hosts_from_id(id) Groups.delete_tag(id) if Groups.tag?(id) Groups.delete_all if id == 'all' hosts = hosts.select { |host| alive(host) } hosts.each_slice(10) { |s| puts Floaty.floaty_cmd("delete #{s.join(',')} --service vmpooler") } unless hosts.empty? end |
.find_pooled_platforms ⇒ Object
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# File 'lib/floatyhelper/vm.rb', line 31 def self.find_pooled_platforms vmpooler_url = Floaty.vmpooler_url begin # rubocop:disable Style/RedundantBegin uri = URI.parse("#{vmpooler_url}/status") http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = true result = http.get(uri.request_uri) result = JSON.parse(result.body) # Techinally, 'max > 0' tells you if it's a pooled platform, but if # the pool is empty, we'll want to fall back to ABS anyway. result['pools'].select { |_pool, info| info['ready'].positive? }.map { |pool, info| [pool.gsub('-pixa4','').gsub('-pooled',''), info['ready']] }.to_h rescue StandardError # Not a great practice to swallow all errors, but this list is probably # pretty stable, so let's just pass along the default. puts "Error looking up pooled platforms from #{vmpooler_url}/status. Using default pooled platform list instead.".yellow pooled_platforms_default end end |
.get_current_lifetime(host) ⇒ Object
64 65 66 67 |
# File 'lib/floatyhelper/vm.rb', line 64 def self.get_current_lifetime(host) status = query(host) status['ok'] ? status[host]['lifetime'] : nil end |
.get_vm(platform: 'centos-7-x86_64', force_abs: false, number: 1) ⇒ Object
Get a VM from floaty ###
206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 |
# File 'lib/floatyhelper/vm.rb', line 206 def self.get_vm(platform: 'centos-7-x86_64', force_abs: false, number: 1) pools = find_pooled_platforms platform = platform.gsub('-pixa4','') vms_per_thread = 10 if !pools.keys.include?(platform) || force_abs || pools[platform] < number numthreads = number / vms_per_thread numthreads += 1 if number % vms_per_thread != 0 threads = [] responses = [] mutex = Mutex.new numleft = number numthreads.times do num = numleft < vms_per_thread ? numleft : vms_per_thread numleft -= num threads << Thread.new do Thread.current['print'] = false myresponse = Floaty.floaty_cmd("get #{platform}=#{num} --service abs --priority 1 --force", use_pty: true) mutex.synchronize { responses << myresponse } end end # Setting print to true then joining causes the thread not # to pick up the variable change sometimes. So this polls # the thread status and sets the print variable in a loop. puts "Fetching VMs using #{threads.count} thread#{threads.count > 1 ? 's' : ''}. Output shown will be from one of the currently alive threads, as well as the result of any completed threads, until all threads are finished.".cyan unless threads.count == 1 while threads.any? { |t| t.alive? } do # If we have no living threads with print set to true, # pick one and turn it on. if threads.select { |t| t.alive? && t['print'] == true }.empty? t = threads.find{ |t| t.alive? } t['print'] = true if !t.nil? end end # Just in case threads.each { |t| t.join } vms = [] responses.each { |r| vms += parse_response(r) } # When use_pty is true, we've already printed stderr/stdout, so no need to do so again. raise "Error obtaining a VM" if vms.empty? vms else response = Floaty.floaty_cmd("get #{platform}=#{number} --service vmpooler") raise "Error obtaining a VM: #{response}" if response.include?('error') parse_response(response) end end |
.getsnapshot(id, snaptag) ⇒ Object
140 141 142 143 |
# File 'lib/floatyhelper/vm.rb', line 140 def self.getsnapshot(id, snaptag) data = Config.load_data data['snapshots'][id][snaptag] end |
.increaselife(id, amount = nil) ⇒ Object
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/floatyhelper/vm.rb', line 74 def self.increaselife(id, amount = nil) amount ||= Config.get_config_setting('increaselife').to_i return if amount < 1 hosts = Hosts.get_hosts_from_id(id) hosts.each do |host| if (lifetime = get_current_lifetime(host)) lifetime += amount output = Floaty.floaty_cmd("modify #{host} --lifetime #{lifetime} --service vmpooler") if output =~ /Successfully modified/ puts "#{host} lifetime set to #{lifetime} hours".green else puts "Error setting VM lifetime: #{output}".red end else puts "Could not query host #{host}".red end end end |
.parse_response(response) ⇒ Object
Response should be something like:
-
vm1.delivery.puppetlabs.net (platform-tag)n
-
vm2.delivery.puppetlabs.net (platform-tag)n
201 202 203 |
# File 'lib/floatyhelper/vm.rb', line 201 def self.parse_response(response) response.scan(/- ([\w-]+)(?:.vmpooler-prod.puppet.net|.delivery.puppetlabs.net) \(/).flatten end |
.pooled_platforms_default ⇒ Object
Assume we only have 1 of each if we can’t find the info
14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# File 'lib/floatyhelper/vm.rb', line 14 def self.pooled_platforms_default [ 'centos-7-x86_64', 'centos-8-x86_64', 'oracle-7-x86_64', 'redhat-7-x86_64', 'redhat-8-x86_64', 'redhat-fips-7-x86_64', 'redhat-fips-8-x86_64', 'scientific-7-x86_64', 'sles-12-x86_64', 'sles-15-x86_64', 'ubuntu-1804-x86_64', 'ubuntu-2004-x86_64', ].map { |x| [x,1] }.to_h end |
.query(host) ⇒ Object
59 60 61 62 |
# File 'lib/floatyhelper/vm.rb', line 59 def self.query(host) output = Floaty.floaty_cmd("query #{host} --service vmpooler") Floaty.parse_floaty_json_output(output) end |
.revert(id, snaptag) ⇒ Object
156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 |
# File 'lib/floatyhelper/vm.rb', line 156 def self.revert(id, snaptag) clr = Config.get_config_setting('vertical_snapshot_status') clr = clr.to_s.downcase == 'true' snaptag ||= 'Blank Snaptag' shas = VM.getsnapshot(id, snaptag) lastlog = {} puts `tput clear` if clr shas.each do |host, sha| # Force a session to show up in lastlog lastlog[host] = `ssh -t root@#{host} lastlog -u root 2>/dev/null`.gsub("\r",'').gsub("\n",'') print "#{host}: #{sha} --- " puts Floaty.floaty_cmd("revert #{host} #{sha} --service vmpooler") end puts puts 'Waiting for all VMs to finish reverting...' alldone = false until alldone puts `tput cup #{shas.count + 2}` if clr alldone = true print "\r" unless clr lastlog.each do |host, value| begin result =`ssh root@#{host} lastlog -u root 2>/dev/null`.gsub("\r",'').gsub("\n",'') # Original will have some garbage about pseudo-terminal that we won't have here # Also, can't do this on Windows yet, so pretend we're done for those hosts. done = !lastlog[host].include?(result) || result.empty? rescue done = false end status = done ? 'Done'.green : 'Wait'.yellow if clr puts "* %s #{status} *" % "#{host}:".ljust(16) else print "* %s #{status} *" % "#{host}:".ljust(16) end alldone &= done end sleep(1) end puts '' end |
.snaplist(tag) ⇒ Object
150 151 152 153 154 |
# File 'lib/floatyhelper/vm.rb', line 150 def self.snaplist(tag) data = Config.load_data return [] if !data['snapshots'].keys.include?(tag) data['snapshots'][tag].keys end |
.snapshot(id, snaptag) ⇒ Object
Snapshots ###
94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 |
# File 'lib/floatyhelper/vm.rb', line 94 def self.snapshot(id, snaptag) clr = Config.get_config_setting('vertical_snapshot_status') clr = clr.to_s.downcase == 'true' snaptag ||= 'Blank Snaptag' hosts = Hosts.get_hosts_from_id(id) shas = {} # There's probably a better way to do this... puts `tput clear` if clr hosts.each do |host| result = Floaty.floaty_cmd("snapshot #{host} --service vmpooler") answer = Floaty.parse_floaty_json_output(result) sha = answer[host]['snapshot'] puts "#{host}: #{sha}" shas[host] = sha end data = Config.load_data data['snapshots'] ||= {} data['snapshots'][id] ||= {} data['snapshots'][id][snaptag] = shas Config.write_data(data) puts puts 'Waiting for snapshots to appear in floaty query...' alldone = false until alldone puts `tput cup #{hosts.count + 2}` if clr alldone = true print "\r" unless clr hosts.each do |host| answer = query(host)[host] done = answer.keys.include?('snapshots') && answer['snapshots'].include?(shas[host]) status = done ? 'Done'.green : 'Wait'.yellow if clr puts "* %s #{status} *" % "#{host}:".ljust(16) else print "* %s #{status} *" % "#{host}:".ljust(16) end alldone &= done end sleep(1) end puts '' end |