lib/rvc/modules/vm_guest.rb in rvc-1.7.0 vs lib/rvc/modules/vm_guest.rb in rvc-1.8.0
- old
+ new
@@ -1,33 +1,57 @@
+# Copyright (c) 2013 VMware, Inc. All Rights Reserved.
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to deal
+# in the Software without restriction, including without limitation the rights
+# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+# copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+# THE SOFTWARE.
+
+require 'rvc/vim'
+
opts :authenticate do
summary "Authenticate within guest"
- arg :vm, nil, :lookup => VIM::VirtualMachine
+ arg :vm, nil, :lookup => VIM::VirtualMachine, :multi => true
opt :interactive_session, "Allow command to interact with desktop", :default => false, :type => :bool
opt :password, "Password in guest", :type => :string
opt :username, "Username in guest", :default => "root", :type => :string
end
-def authenticate vm, opts
- auth = ((@auths ||= {})[vm] ||= {})[opts[:username]]
-
- if opts[:password].nil? or opts[:password].empty?
- opts[:password] = ask("password: ") { |q| q.echo = false }
+def authenticate vms, opts
+ vms.each do |vm|
+ auth = ((@auths ||= {})[vm] ||= {})[opts[:username]]
+
+ if opts[:password].nil? or opts[:password].empty?
+ opts[:password] = ask("password: ") { |q| q.echo = false }
+ end
+
+ auth = VIM.NamePasswordAuthentication(
+ :username => opts[:username],
+ :password => opts[:password],
+ :interactiveSession => opts[:interactive_session]
+ )
+
+ @auths[vm][opts[:username]] = auth
+ begin
+ check_auth vm, opts
+ rescue
+ clear_auth vm, opts
+ err "Could not authenticate: #{$!}"
+ end
end
-
- auth = VIM.NamePasswordAuthentication(
- :username => opts[:username],
- :password => opts[:password],
- :interactiveSession => opts[:interactive_session]
- )
-
- @auths[vm][opts[:username]] = auth
- begin
- check_auth vm, opts
- rescue
- clear_auth vm, opts
- err "Could not authenticate: #{$!}"
- end
end
opts :check_auth do
summary "Check credentials"
@@ -238,11 +262,72 @@
:auth => auth,
:filePath => opts[:guest_path]
)
end
+def generic_http_download uri, local_path
+ http = Net::HTTP.new(uri.host, uri.port)
+ http.use_ssl = true
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
+ #http.set_debug_output $stderr
+ http.start
+# headers = { 'cookie' => connection.cookie }
+ headers = {}
+ http_path = "#{uri.path}?#{uri.query}"
+ http.request_get(http_path, headers) do |res|
+ case res
+ when Net::HTTPOK
+ len = res.content_length
+ count = 0
+ File.open(local_path, 'wb') do |io|
+ res.read_body do |segment|
+ count += segment.length
+ io.write segment
+ $stdout.write "\e[0G\e[Kdownloading #{count}/#{len} bytes (#{(count*100)/len}%)"
+ $stdout.flush
+ end
+ end
+ $stdout.puts
+ else
+ err "download failed: #{res.message}"
+ end
+ end
+end
+
+def generic_http_upload local_path, uri, size = nil
+ http = Net::HTTP.new(uri.host, uri.port)
+ http.use_ssl = true
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
+ #http.set_debug_output $stderr
+ http.start
+
+
+ open(local_path, 'rb') do |io|
+ stream = ProgressStream.new(io, size || io.stat.size) do |s|
+ $stdout.write "\e[0G\e[Kuploading #{s.count}/#{s.len} bytes (#{(s.count*100)/s.len}%)"
+ $stdout.flush
+ end
+
+ headers = {
+ 'content-length' => (size || io.stat.size).to_s,
+ 'Content-Type' => 'application/octet-stream',
+ }
+ http_path = "#{uri.path}?#{uri.query}"
+
+ request = Net::HTTP::Put.new http_path, headers
+ request.body_stream = stream
+ res = http.request(request)
+ $stdout.puts
+ case res
+ when Net::HTTPOK
+ else
+ err "upload failed: #{res.message}"
+ end
+ end
+end
+
opts :download_file do
summary "Download file from guest"
arg :vm, nil, :lookup => VIM::VirtualMachine
opt :guest_path, "Path in guest to download from", :required => true, :type => :string
opt :local_path, "Local file to download to", :required => true, :type => :string
@@ -263,56 +348,66 @@
:guestFilePath => opts[:guest_path]
).url
download_uri = URI.parse(download_url.gsub /http(s?):\/\/\*:[0-9]*/, "")
download_path = "#{download_uri.path}?#{download_uri.query}"
-
- http_download vm._connection, download_path, opts[:local_path]
+
+ generic_http_download download_uri, opts[:local_path]
end
opts :upload_file do
summary "Upload file to guest"
- arg :vm, nil, :lookup => VIM::VirtualMachine
+ arg :vm, nil, :lookup => VIM::VirtualMachine, :multi => true
opt :group_id, "Group ID of file", :type => :int
opt :guest_path, "Path in guest to upload to", :required => true, :type => :string
opt :local_path, "Local file to upload", :required => true, :type => :string
opt :overwrite, "Overwrite file", :default => false, :type => :bool
opt :owner_id, "Owner ID of file", :type => :int
opt :permissions, "Permissions of file", :type => :string
opt :username, "Username in guest", :default => "root", :type => :string
end
-def upload_file vm, opts
- guestOperationsManager = vm._connection.serviceContent.guestOperationsManager
- err "This command requires vSphere 5 or greater" unless guestOperationsManager.respond_to? :fileManager
- fileManager = guestOperationsManager.fileManager
-
- opts[:permissions] = opts[:permissions].to_i(8) if opts[:permissions]
-
- auth = get_auth vm, opts
-
- file = File.new(opts[:local_path], 'rb')
-
- upload_url = fileManager.
- InitiateFileTransferToGuest(
- :vm => vm,
- :auth => auth,
- :guestFilePath => opts[:guest_path],
- :fileAttributes => VIM.GuestPosixFileAttributes(
- :groupId => opts[:group_id],
- :ownerId => opts[:owner_id],
- :permissions => opts[:permissions]
- ),
- :fileSize => file.size,
- :overwrite => opts[:overwrite]
- )
-
- upload_uri = URI.parse(upload_url.gsub /http(s?):\/\/\*:[0-9]*/, "")
- upload_path = "#{upload_uri.path}?#{upload_uri.query}"
-
- http_upload vm._connection, opts[:local_path], upload_path
+def upload_file vms, opts
+ vms.each do |vm|
+ guestOperationsManager = vm._connection.serviceContent.guestOperationsManager
+ err "This command requires vSphere 5 or greater" unless guestOperationsManager.respond_to? :fileManager
+ fileManager = guestOperationsManager.fileManager
+
+ opts[:permissions] = opts[:permissions].to_i(8) if opts[:permissions]
+
+ auth = get_auth vm, opts
+
+ file_size = nil
+ if opts[:local_path] =~ /^http:/
+ # XXX: Not acceptable for big files
+ file_size = open(opts[:local_path], 'rb').read.length
+ else
+ err "local file does not exist" unless File.exists? local_path
+ file = File.new(opts[:local_path], 'rb')
+ file_size = file.size
+ end
+
+ upload_url = fileManager.
+ InitiateFileTransferToGuest(
+ :vm => vm,
+ :auth => auth,
+ :guestFilePath => opts[:guest_path],
+ :fileAttributes => VIM.GuestPosixFileAttributes(
+ :groupId => opts[:group_id],
+ :ownerId => opts[:owner_id],
+ :permissions => opts[:permissions]
+ ),
+ :fileSize => file_size,
+ :overwrite => opts[:overwrite]
+ )
+
+ upload_uri = URI.parse(upload_url.gsub /http(s?):\/\/\*:[0-9]*/, "")
+ upload_path = "#{upload_uri.path}?#{upload_uri.query}"
+
+ generic_http_upload opts[:local_path], upload_uri, file_size
+ end
end
opts :ls_guest do
summary "List files in guest"
@@ -429,11 +524,11 @@
# Process commands
opts :start_program do
summary "Run program in guest"
- arg :vm, nil, :lookup => VIM::VirtualMachine
+ arg :vm, nil, :lookup => VIM::VirtualMachine, :multi => true
opt :arguments, "Arguments of command", :default => "", :type => :string
opt :background, "Don't wait for process to finish", :default => false, :type => :bool
opt :delay, "Interval in seconds", :type => :float, :default => 5.0
opt :env, "Environment variable(s) to set (e.g. VAR=value)", :multi => true, :type => :string
opt :program_path, "Path to program in guest", :required => true, :type => :string
@@ -442,49 +537,53 @@
opt :working_directory, "Working directory of the program to run", :type => :string
conflicts :background, :timeout
conflicts :background, :delay
end
-def start_program vm, opts
- guestOperationsManager = vm._connection.serviceContent.guestOperationsManager
- err "This command requires vSphere 5 or greater" unless guestOperationsManager.respond_to? :processManager
- processManager = guestOperationsManager.processManager
-
- auth = get_auth vm, opts
-
- pid = processManager.
- StartProgramInGuest(
- :vm => vm,
- :auth => auth,
- :spec => VIM.GuestProgramSpec(
- :arguments => opts[:arguments],
- :programPath => opts[:program_path],
- :envVariables => opts[:env],
- :workingDirectory => opts[:working_directory]
- )
- )
-
- Timeout.timeout opts[:timeout] do
- while true
- processes = processManager.
- ListProcessesInGuest(
- :vm => vm,
- :auth => auth,
- :pids => [pid]
+def start_program vms, opts
+ vms.each do |vm|
+ guestOperationsManager = vm._connection.serviceContent.guestOperationsManager
+ err "This command requires vSphere 5 or greater" unless guestOperationsManager.respond_to? :processManager
+ processManager = guestOperationsManager.processManager
+
+ auth = get_auth vm, opts
+
+ pid = processManager.
+ StartProgramInGuest(
+ :vm => vm,
+ :auth => auth,
+ :spec => VIM.GuestProgramSpec(
+ :arguments => opts[:arguments],
+ :programPath => opts[:program_path],
+ :envVariables => opts[:env],
+ :workingDirectory => opts[:working_directory]
)
- process = processes.first
-
- if !process.endTime.nil?
- if process.exitCode != 0
- err "Process failed with exit code #{process.exitCode}"
+ )
+
+ begin
+ Timeout.timeout opts[:timeout] do
+ while true
+ processes = processManager.
+ ListProcessesInGuest(
+ :vm => vm,
+ :auth => auth,
+ :pids => [pid]
+ )
+ process = processes.first
+
+ if !process.endTime.nil?
+ if process.exitCode != 0
+ err "Process failed with exit code #{process.exitCode}"
+ end
+ break
+ elsif opts[:background]
+ break
+ end
+
+ sleep opts[:delay]
end
- break
- elsif opts[:background]
- break
end
-
- sleep opts[:delay]
+ rescue Timeout::Error
+ err "Timed out waiting for process to finish."
end
end
-rescue Timeout::Error
- err "Timed out waiting for process to finish."
end