class QemuToolkit::VM
Abstracts a virtual machine on a vm host. This class provides all sorts of methods that execute administration actions.
Attributes
Boot order (if set)
The number of cpus to configure, defaults to 2.
Other devices
iSCSI target iqn and ip address to connect to
Keyboard layout
VM
name
A list of network configuration statements that will be passed through to qemu.
A list of network cards that will be connected to vnics on the host.
Ram in megabytes
VNC display port
Public Class Methods
Access the definition of a single vm.
# File lib/qemu-toolkit/vm.rb, line 41 def [](name, backend=nil) all(backend).find { |vm| vm.name === name } end
Load all vm descriptions and provide an iterator for them.
# File lib/qemu-toolkit/vm.rb, line 16 def all(backend=nil) Enumerator.new do |yielder| libdir = Config.etc('lib') if ::File.directory? libdir $:.unshift libdir end Dir[Config.etc('*.rb')].each do |vm_file| # Load all virtual machines from the given file dsl = DSL::File.new dsl.add_toplevel_target :virtual_machine, lambda { |name| VM.new(backend).tap { |vm| vm.name = name } } dsl.load_file(vm_file) # Yield them all in turn dsl.objects.each do |vm| yielder << vm end end end end
# File lib/qemu-toolkit/vm.rb, line 68 def initialize(backend) @disks = [] @drives = [] @nics = [] @nets = [] @cpus = 2 @ram = 1024 @backend = backend @vnc_display = nil @extra_args = [] # TODO document @devices = [] end
Public Instance Methods
# File lib/qemu-toolkit/vm.rb, line 82 def add_device(driver, parameters) @devices << [driver, parameters] end
# File lib/qemu-toolkit/vm.rb, line 88 def add_disk(path) @disks << path end
# File lib/qemu-toolkit/vm.rb, line 85 def add_drive(parameters) @drives << parameters end
# File lib/qemu-toolkit/vm.rb, line 97 def add_extra_arg(argument) @extra_args << argument end
# File lib/qemu-toolkit/vm.rb, line 94 def add_net(type, parameters) @nets << [type, parameters] end
# File lib/qemu-toolkit/vm.rb, line 91 def add_nic(name, parameters) @nics << [name, parameters] end
Returns the command that is needed to run this virtual machine. Note that this also modifies system configuration and is not just a routine that returns a string.
@return String command to run the machine
# File lib/qemu-toolkit/vm.rb, line 119 def command opts={} cmd = [] cmd << "-name #{name}" cmd << "-m #{ram}" cmd << "-daemonize" cmd << '-nographic' cmd << "-cpu qemu64" cmd << "-smp #{cpus}" cmd << "-no-hpet" cmd << "-enable-kvm" cmd << "-vga cirrus" cmd << "-parallel none" cmd << "-usb" cmd << '-usbdevice tablet' if keyboard_layout cmd << "-k #{keyboard_layout}" end # Add disks cmd += disk_options # Was an iso image given to boot from? if iso_path=opts[:bootiso] cmd << "-cdrom #{iso_path}" cmd << "-boot order=cd,once=d" else cmd << '-boot order=cd' end # Set paths for communication with vm cmd << "-pidfile #{pid_path}" cmd << socket_chardev(:monitor, monitor_path) cmd << "-monitor chardev:monitor" cmd << socket_chardev(:serial0, run_path('vm.console')) cmd << "-serial chardev:serial0" cmd << socket_chardev(:serial1, run_path('vm.ttyb')) cmd << "-serial chardev:serial1" # vnc socket cmd << "-vnc unix:#{run_path('vm.vnc')}" # If vnc_display is set, allow configuring a TCP based VNC port: if vnc_display cmd << "-vnc #{vnc_display}" end # Other devices devices.each do |driver, parameters| cmd << "-device #{driver}," + parameter_list(parameters) end # Boot order if boot cmd << "-boot " + parameter_list(boot) end cmd += network_options # Extra arguments cmd += @extra_args return cmd end
Connects the current terminal to the given socket. Available sockets include :monitor, :vnc, :console, :ttyb.
# File lib/qemu-toolkit/vm.rb, line 289 def connect(socket) socket_path = run_path("vm.#{socket}") cmd = "socat stdio unix-connect:#{socket_path}" exec cmd end
# File lib/qemu-toolkit/vm.rb, line 241 def disk_options cmd = [] if @disks.empty? && !iscsi_target && @drives.empty? raise "No disks defined, can't run." end disk_index = 0 if iscsi_target target = produce_target(*iscsi_target) target.ensure_exists target.disks.each do |device| params = { file: device, if: 'virtio', index: disk_index, media: 'disk', cache: 'none' } params[:boot] = 'on' if disk_index == 0 cmd << "-drive " + parameter_list(params) disk_index += 1 end end @disks.each do |path| params = { file: path, if: 'virtio', index: disk_index, media: "disk" } params[:boot] = 'on' if disk_index == 0 cmd << "-drive " + parameter_list(params) disk_index += 1 end @drives.each do |drive_options| cmd << "-drive " + parameter_list(drive_options.merge(index: disk_index)) disk_index += 1 end return cmd end
Kills the vm the hard way.
# File lib/qemu-toolkit/vm.rb, line 298 def kill run_cmd "kill #{pid}" end
# File lib/qemu-toolkit/vm.rb, line 186 def network_options cmd = [] # networking: nic vlan = 0 # Look up all existing vnics for this virtual machine vnics = Vnic.for_prefix(name, @backend) nics.each do |nic_name, parameters| via = parameters.delete(:via) model = parameters.delete(:model) || 'virtio' macaddr = parameters.delete(:macaddr) # All vnics that travel via the given interface (via) vnic = vnics.allocate(via, macaddr) # If no vnic has been found, create a new one. unless vnic vnic = Vnic.create(name, via, @backend, macaddr) end cmd << "-net vnic,"+ parameter_list( parameters.merge( vlan: vlan, name: nic_name, ifname: vnic.vnic_name, )) if model == 'virtio' cmd << '-device virtio-net-pci,'+ parameter_list( mac: vnic.macaddr, tx: 'timer', x_txtimer: 200000, x_txburst: 128, vlan: vlan) else cmd << "-net nic,"+ parameter_list( vlan: vlan, name: nic_name, model: model, macaddr: vnic.macaddr) end vlan += 1 end # networking: net nets.each do |type, parameters| map(parameters, :macaddr) { |a| Network::MacAddress.new(a) } cmd << "-net #{type},"+ parameter_list(parameters) end cmd end
Attempts to read and return the pid of the running VM
process.
# File lib/qemu-toolkit/vm.rb, line 335 def pid Integer(File.read(pid_path).lines.first.chomp) end
Returns an ISCSITarget
for host and port.
# File lib/qemu-toolkit/vm.rb, line 310 def produce_target(host, port) ISCSITarget.new(host, port, @backend) end
Returns true if the virtual machine seems to be currently running.
# File lib/qemu-toolkit/vm.rb, line 316 def running? if File.exist?(pid_path) # Prod the process using kill. This will not actually kill the # process! begin Process.kill(0, pid) rescue Errno::ESRCH # When this point is reached, the process doesn't exist. return false end return true end return false end
Sends a shutdown command via the monitor socket of the virtual machine.
# File lib/qemu-toolkit/vm.rb, line 304 def shutdown monitor_cmd 'system_powerdown' end
Runs the VM
using qemu.
# File lib/qemu-toolkit/vm.rb, line 102 def start(dryrun, opts={}) if dryrun puts command(opts) else # Make sure var/run/qemu-toolkit/VMNAME exists. FileUtils.mkdir_p run_path @backend.qemu("vm<#{name}>", command(opts)) end end
Private Instance Methods
Maps a key from a hash to a new value returned by the block.
# File lib/qemu-toolkit/vm.rb, line 348 def map hash, key, &block return unless hash.has_key? key hash[key] = block.call(hash[key]) end
# File lib/qemu-toolkit/vm.rb, line 340 def monitor_cmd(cmd) socket = ::UNIXSocket.new(monitor_path) socket.puts cmd socket.close end
Returns the file path of the monitor socket (unix socket below /var/run) usually. )
# File lib/qemu-toolkit/vm.rb, line 386 def monitor_path run_path 'vm.monitor' end
Formats a parameter list as key=value,key=value
# File lib/qemu-toolkit/vm.rb, line 359 def parameter_list(parameters) key_translator = Hash.new { |h,k| k } key_translator.update( x_txtimer: 'x-txtimer', x_txburst: 'x-txburst') parameters. map { |k,v| "#{key_translator[k]}=#{v}" }. join(',') end
Returns the file path of the vm pid file.
# File lib/qemu-toolkit/vm.rb, line 379 def pid_path run_path 'vm.pid' end
Runs a command and returns its stdout. This raises an error if the command doesn’t exit with a status of 0.
# File lib/qemu-toolkit/vm.rb, line 393 def run_cmd(*args) cmd = args.join(' ') ret = %x(#{cmd}) raise "Execution error: #{cmd}." unless $?.success? ret end
Returns the path below /var/run (usually) that contains runtime files for the virtual machine.
# File lib/qemu-toolkit/vm.rb, line 373 def run_path(*args) Config.var_run(name, *args) end
# File lib/qemu-toolkit/vm.rb, line 353 def socket_chardev(name, path) "-chardev socket,id=#{name},path=#{path},server,nowait" end