It’s not pretty, but here it is. I think this is where the “methods should be 10 lines or less” rule makes things a little more convoluted than it could be.
def construct_guest_auth
username = @gom_config['username']
password = @gom_config.decrypt('password')
fail 'guest username & password are required!' unless username && password
guest_auth = RbVmomi::VIM::NamePasswordAuthentication(
interactiveSession: false,
username: username,
password: password
)
guest_auth
end
def get_guest_temp_file(filename)
temp_file_suffix = File.extname(filename)
temp_file_prefix = File.basename(filename, temp_file_suffix) + '_'
guest_file = @gom.fileManager.CreateTemporaryFileInGuest(
vm: @vim_vm,
auth: @guest_auth,
prefix: temp_file_prefix,
suffix: temp_file_suffix
)
fail 'unable to obtain a temp guest file' if guest_file.nil?
guest_file
end
def use_sudo
if @guest_auth[:username] == 'root'
false
elsif $evm.object['use_sudo'].nil?
@gom_config['use_sudo']
else
$evm.object['use_sudo']
end
end
def linux_program_path(interpreter)
sudo_path = $evm.object['sudo_path']
use_sudo ? sudo_path : interpreter
end
def get_guest_program_path(platform, interpreter)
guest_program_path =
if platform == 'linux'
linux_program_path(interpreter)
elsif platform == 'windows'
interpreter
else
fail 'only linux & windows are supported'
end
guest_program_path
end
def get_linux_program_args(guest_file, interpreter, interpreter_args, username, password)
guest_args =
if use_sudo
"#{interpreter} #{interpreter_args} #{guest_file} #{username} #{password}"
else
"#{interpreter_args} #{guest_file} #{username} #{password}"
end
guest_args
end
def get_guest_args(platform, guest_file, interpreter, interpreter_args, username, password)
guest_args =
if platform == 'linux'
get_linux_program_args(guest_file, interpreter, interpreter_args, username, password)
else
fail 'only linux supported'
end
guest_args
end
def get_guest_command(platform, guest_file, username, password)
interpreter = $evm.object["#{platform}_interpreter"]
interpreter_args = $evm.object["#{platform}_interpreter_args"]
guest_program_path = get_guest_program_path(platform, interpreter)
guest_args = get_guest_args(platform, guest_file, interpreter,
interpreter_args, username, password)
[guest_program_path, guest_args]
end
def get_file_attrs(platform)
# file will be created with 0644 permissions
file_attrs =
if platform == 'linux'
RbVmomi::VIM::GuestPosixFileAttributes()
elsif platform == 'windows'
RbVmomi::VIM::GuestWindowsFileAttributes()
else
fail 'only linux & windows are supported'
end
file_attrs
end
def get_put_path(guest_file, platform, file_size)
file_attrs = get_file_attrs(platform)
put_path = @gom.fileManager.InitiateFileTransferToGuest(
vm: @vim_vm, auth: @guest_auth, guestFilePath: guest_file,
fileAttributes: file_attrs, fileSize: file_size, overwrite: true
)
put_path
end
def construct_request(request_uri, host_file, file_size)
request = Net::HTTP::Put.new(request_uri)
request.body_stream = File.open(host_file)
request['Content-Type'] = 'multipart/form-data'
request.add_field('Content-Length', file_size)
request
end
def put_file(host_file, guest_file, platform)
file_size = File.size(host_file)
put_path = get_put_path(guest_file, platform, file_size)
uri = URI.parse(put_path)
http = Net::HTTP.new(uri.host, uri.port)
http.use_ssl = (uri.scheme == 'https')
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
request = construct_request(uri.request_uri, host_file, file_size)
http_response = http.request(request)
http_response
end
def process_http_response(http_response)
if http_response.code == '200'
@logger.log(:info, http_response.body)
else
fail "The transfer of '#{host_file}' to '#{guest_file}' FAILED!"
end
end
def get_program_pids(guest_program_path, guest_args, guest_directory)
prog_spec = RbVmomi::VIM::GuestProgramSpec(
programPath: guest_program_path,
arguments: guest_args,
workingDirectory: guest_directory
)
pids = []
pids << @gom.processManager.StartProgramInGuest(
vm: @vim_vm, auth: @guest_auth, spec: prog_spec
)
pids
end
def log_process(process, sleep_time)
if process.endTime.nil?
@logger.log(:info, "'#{process.cmdLine}' is still running, sleeping " \
"for #{sleep_time} seconds")
return true
else
@logger.log(:info, "'#{process.cmdLine}' has finished running")
return false
end
end
def report_proccess(processes)
need_to_sleep = false
sleep_time = 15.seconds
processes.each do |process|
need_to_sleep ||= log_process(process, sleep_time)
end
sleep sleep_time if need_to_sleep
end
def wait_for_command(pids)
processes = @gom.processManager.ListProcessesInGuest(
vm: @vim_vm, auth: @guest_auth, pids: pids
)
# wait for completion
while processes.any? { |process| process.endTime.nil? }
report_proccess(processes)
processes = @gom.processManager.ListProcessesInGuest(
vm: @vim_vm, auth: @guest_auth, pids: pids
)
end
report_proccess(processes)
end
def process_command_success(processes)
return unless processes.all? { |process| process.exitCode == 0 }
@logger.log(:info, 'All processes completed successfully!')
end
def process_command_failure(processes)
return unless processes.any? { |process| process.exitCode != 0 }
processes.each do |process|
@logger.log(:info, "'#{process.cmdLine}' finished with exitCode " \
"'#{process.exitCode}'")
end
fail 'One or more processes did not complete sucessfully.'
end
def process_command_results(pids)
processes = @gom.processManager.ListProcessesInGuest(
vm: @vim_vm, auth: @guest_auth, pids: pids
)
process_command_success(processes)
process_command_failure(processes)
end
And to set it up:
platform = vm.platform
# Guest Operations Manager Setup
@gom = vim.serviceContent.guestOperationsManager
@gom_config = $evm.instantiate("/Configuration/GuestCredentials/#{platform}" \
"/#{cust_id}")
@guest_auth = construct_guest_auth
I hope that’s enough to get you going. We keep the to-be-inserted files on an NFS share that is mounted to all of the appliances for ease of management.
Matt