class Support::GuestOperations
Encapsulate VMware Tools GOM interaction, inspired by github:dnuffer/raidopt
Attributes
gom[R]
guest_auth[R]
ssl_verify[R]
vm[R]
Public Class Methods
new(vim, vm, guest_auth, ssl_verify = true)
click to toggle source
# File lib/support/guest_operations.rb, line 9 def initialize(vim, vm, guest_auth, ssl_verify = true) @gom = vim.serviceContent.guestOperationsManager @vm = vm @guest_auth = guest_auth @ssl_verify = ssl_verify end
Public Instance Methods
delete_dir(dir)
click to toggle source
# File lib/support/guest_operations.rb, line 31 def delete_dir(dir) gom.fileManager.DeleteDirectoryInGuest(vm: vm, auth: guest_auth, directoryPath: dir, recursive: true) end
download_file(remote_file, local_file)
click to toggle source
# File lib/support/guest_operations.rb, line 135 def download_file(remote_file, local_file) info = gom.fileManager.InitiateFileTransferFromGuest(vm: vm, auth: guest_auth, guestFilePath: remote_file) uri = URI.parse(info.url) request = Net::HTTP::Get.new(uri.request_uri) http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = (uri.scheme == "https") http.verify_mode = ssl_verify ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE response = http.request(request) if response.body.size != info.size raise format("Downloaded file has different size than reported: %s (%d bytes instead of %d bytes)", remote_file, response.body.size, info.size) end local_file.nil? ? response.body : File.open(local_file, "w") { |file| file.write(response.body) } end
linux?()
click to toggle source
# File lib/support/guest_operations.rb, line 23 def linux? os_family == :linux end
os_family()
click to toggle source
# File lib/support/guest_operations.rb, line 16 def os_family return vm.guest.guestFamily == "windowsGuest" ? :windows : :linux if vm.guest.guestFamily # VMware tools are not initialized or missing, infer from Guest Id vm.config&.guestId&.match(/^win/) ? :windows : :linux end
process_exit_code(pid)
click to toggle source
# File lib/support/guest_operations.rb, line 40 def process_exit_code(pid) gom.processManager.ListProcessesInGuest(vm: vm, auth: guest_auth, pids: [pid])&.first&.exitCode end
process_is_running(pid)
click to toggle source
# File lib/support/guest_operations.rb, line 35 def process_is_running(pid) procs = gom.processManager.ListProcessesInGuest(vm: vm, auth: guest_auth, pids: [pid]) procs.empty? || procs.any? { |gpi| gpi.exitCode.nil? } end
read_file(remote_file)
click to toggle source
# File lib/support/guest_operations.rb, line 126 def read_file(remote_file) download_file(remote_file, nil) end
run_program(path, args = "", timeout = 60.0)
click to toggle source
# File lib/support/guest_operations.rb, line 57 def run_program(path, args = "", timeout = 60.0) Kitchen.logger.debug format("Running %s %s", path, args) pid = gom.processManager.StartProgramInGuest(vm: vm, auth: guest_auth, spec: RbVmomi::VIM::GuestProgramSpec.new(programPath: path, arguments: args)) wait_for_process_exit(pid, timeout) exit_code = process_exit_code(pid) raise format("Failed to run '%s %s'. Exit code: %d", path, args, exit_code) if exit_code != 0 exit_code end
run_shell_capture_output(command, shell = :auto, timeout = 60.0)
click to toggle source
# File lib/support/guest_operations.rb, line 69 def run_shell_capture_output(command, shell = :auto, timeout = 60.0) if shell == :auto shell = :linux if linux? shell = :cmd if windows? end if shell == :linux tmp_out_fname = format("/tmp/vm_utils_run_out_%s", Random.rand) tmp_err_fname = format("/tmp/vm_utils_run_err_%s", Random.rand) shell = "/bin/sh" args = format("-c '(%s) > %s 2> %s'", command.gsub("'", %q{\\\'}), tmp_out_fname, tmp_err_fname) elsif shell == :cmd tmp_out_fname = format('C:\Windows\TEMP\vm_utils_run_out_%s', Random.rand) tmp_err_fname = format('C:\Windows\TEMP\vm_utils_run_err_%s', Random.rand) shell = "cmd.exe" args = format('/c "%s > %s 2> %s"', command.gsub("\"", %q{\\\"}), tmp_out_fname, tmp_err_fname) elsif shell == :powershell tmp_out_fname = format('C:\Windows\TEMP\vm_utils_run_out_%s', Random.rand) tmp_err_fname = format('C:\Windows\TEMP\vm_utils_run_err_%s', Random.rand) shell = 'C:\Windows\System32\WindowsPowershell\v1.0\powershell.exe' args = format('-Command "%s > %s 2> %s"', command.gsub("\"", %q{\\\"}), tmp_out_fname, tmp_err_fname) end begin exit_code = run_program(shell, args, timeout) rescue StandardError proc_err = "" # read_file(tmp_err_fname) raise format("Error executing command %s. Exit code: %d. StdErr %s", command, exit_code, proc_err) end read_file(tmp_out_fname) end
upload_file(local_file, remote_file)
click to toggle source
# File lib/support/guest_operations.rb, line 130 def upload_file(local_file, remote_file) Kitchen.logger.debug format("Copy %s to %s", local_file, remote_file) write_file(remote_file, File.open(local_file, "rb").read) end
wait_for_process_exit(pid, timeout = 60.0, interval = 1.0)
click to toggle source
# File lib/support/guest_operations.rb, line 44 def wait_for_process_exit(pid, timeout = 60.0, interval = 1.0) start = Time.new loop do return unless process_is_running(pid) break if (Time.new - start) >= timeout sleep interval end raise format("Timeout waiting for process %d to exit after %d seconds", pid, timeout) if (Time.new - start) >= timeout end
windows?()
click to toggle source
# File lib/support/guest_operations.rb, line 27 def windows? os_family == :windows end
write_file(remote_file, contents)
click to toggle source
# File lib/support/guest_operations.rb, line 102 def write_file(remote_file, contents) # Required privilege: VirtualMachine.GuestOperations.Modify put_url = gom.fileManager.InitiateFileTransferToGuest( vm: vm, auth: guest_auth, guestFilePath: remote_file, fileAttributes: RbVmomi::VIM::GuestFileAttributes(), fileSize: contents.size, overwrite: true ) put_url = put_url.gsub(%r{^https://\*:}, format("https://%s:%s", vm._connection.host, put_url)) uri = URI.parse(put_url) request = Net::HTTP::Put.new(uri.request_uri) request["Transfer-Encoding"] = "chunked" request["Content-Length"] = contents.size request.body = contents http = Net::HTTP.new(uri.host, uri.port) http.use_ssl = (uri.scheme == "https") http.verify_mode = ssl_verify ? OpenSSL::SSL::VERIFY_PEER : OpenSSL::SSL::VERIFY_NONE http.request(request) end