qemu-toolkit / lib / qemu-toolkit / vmadm.rb

require 'clamp'
require 'fileutils'

require 'qemu-toolkit/local_disk_set'

module QemuToolkit
  class Vmadm < Clamp::Command 
    
    option ['-v', '--verbose'], :flag, 'be chatty'
    option ['-n', '--dry-run'], :flag, 
      "don't execute commands, instead just print them"
    
    option '--vmpath', "VMPATH", 
      "path to vm descriptions", default: '/etc/qemu-toolkit'
    option '--varrun', 'VARRUN', 
      'path to runtime files', default: '/var/run/qemu-toolkit'
      
    # Command backend to use during the processing of subcommands. 
    #
    def backend
      Config.backend
    end

    # Main execute method - delegates to _execute in the subcommands. This 
    # handles transforming Ruby errors into simple shell errors. 
    #
    def execute
      backend.verbose = verbose?
      
      Config.etc = vmpath
      Config.var_run = varrun

      fail NotImplementedError, "Missing subcommand." unless respond_to?(:_execute)
      _execute 
    rescue => error
      raise if verbose? || $rspec_executing

      $stderr.puts error.to_s
      exit 1
    end
    
    subcommand('list', 
      'Lists all virtual machines on this system') do

        option %w(-o --fields), 'FIELDLIST', "Only outputs fields given; default is all fields (name, pid)"

        def _execute
          output_fields = (fields || 'name,pid').split(/,/)
          VM.all(backend).each do |vm|
            printf "%-20s", vm.name if output_fields.include?('name')
            printf " %5s", vm.running? ? vm.pid : 'off' if output_fields.include?('pid')
            puts
          end
        end
      end
      
    # subcommand('random-mac', 
    #   'Generates a random MAC address') do
    #     def _execute
    #       puts random_mac_address
    #     end
    #   end          
    
    subcommand('create', 
      'Creates a configuration file for the VM from a template, filling in plausible values.') do

        parameter 'NAME', 'name of the virtual machine'
        
        def _execute
          if VM[name]
            puts "Machine already exists."
            exit 1
          end
          
          File.write(
            Config.etc("#{name}.rb"), 
            vm_template(name))
            
          FileUtils.mkdir(Config.var_run(name))
        end
        
        def vm_template(name)
          local_disks = StringIO.new

          disk_sets = LocalDiskSet.for(name, backend)
          disk_sets.each do |set|
            local_disks.puts "  # Disks for storage at #{set.name}"
            set.each_disk do |dev_path|
              local_disks.puts "  disk '#{dev_path}'"
            end
            local_disks.puts
          end

          %Q(virtual_machine "#{name}" do
  # Block device setup
  # 
  # Either configure a remote disk (via iSCSI):
  # iscsi_target 'iqn.2012-01.com.qemu-toolkit:#{name}', "10.40.0.1"
  # 
  # Or a local disk, like a zvol for example: 
  # disk /dev/zvol/rdsk/pool/#{name}/disk1
#{local_disks.string}

  # Network configuration
  # nic 'eth0', 
  #   macaddr: '#{random_mac_address}', 
  #   via: 'igbX'
end
)
        end
      end

    subcommand('start', 
      'Starts the virtual machine and daemonizes it.') do

        parameter 'NAME', 'name of the virtual machine'
        option '--bootiso', 'BOOTISO', 'boots this ISO instead of disk0'
        
        def _execute
          vm(name).start(dry_run?, bootiso: bootiso)
        end
      end
      
    subcommand('monitor', 
      'Enter QEMU monitor interactively for given VM.') do
        parameter 'NAME', 'name of the virtual machine'

        def _execute
          vm(name).connect(:monitor)
        end
      end
    subcommand('shutdown', 
      'Shuts the VM down by issuing a system/powerdown event.') do
        parameter 'NAME', 'name of the virtual machine'

        def _execute
          vm(name).shutdown
        end
      end

    subcommand('kill', 
      'Tries to kill the VM using the kill command.') do
        parameter 'NAME', 'name of the virtual machine'

        def _execute
          vm(name).kill
        end
      end
        
    subcommand('vnc', 
      'Connect VM VNC server to standard IO. (use ssvnc to connect)') do
        parameter 'NAME', 'name of the virtual machine'
        
        def _execute
          vm(name).connect(:vnc)
        end
      end

    subcommand('console', 
      'Opens serial console to VM. This only works if you configure your VM accordingly.') do
        parameter 'NAME', 'name of the virtual machine'
        
        def _execute
          vm(name).connect(:console)
        end
      end

    subcommand('generate_mac', 
      'Generates a random MAC address.') do
        def _execute
          puts random_mac_address
        end
      end

    def random_mac_address
      # Please see this discussion if improving this: 
      # http://stackoverflow.com/questions/8484877/mac-address-generator-in-python
      mac = [ 0x00, 0x24, 0x81,
          rand(0x7f),
          rand(0xff),
          rand(0xff) ]
      mac.map { |e| e.to_s(16) }.join(':')
    end
    def vm(name)
      vm = VM[name, backend]
      unless vm
        puts "No virtual machine by the name '#{name}' found."
        exit 1
      end
    
      vm
    end
  end
end 
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.