Class: Dcmgr::Drivers::Kvm

Inherits:
Hypervisor show all
Includes:
Helpers::CliHelper, Helpers::NicHelper, Logger, Rpc::KvmHelper
Defined in:
lib/dcmgr/drivers/kvm.rb

Instance Method Summary collapse

Methods included from Helpers::NicHelper

#find_nic, #nic_state, #valid_nic?

Methods included from Rpc::KvmHelper

#connect_monitor

Methods included from Helpers::CliHelper

#sh, #tryagain

Methods included from Logger

create, default_logdev, included

Methods inherited from Hypervisor

select_hypervisor

Instance Method Details

#attach_volume_to_guest(hc) ⇒ Object



52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/dcmgr/drivers/kvm.rb', line 52

def attach_volume_to_guest(hc)
  # pci_devddr consists of three hex numbers with colon separator.
  #  dom <= 0xffff && bus <= 0xff && val <= 0x1f
  # see: qemu-0.12.5/hw/pci.c
  # /*
  # * Parse [[<domain>:]<bus>:]<slot>, return -1 on error
  # */
  # static int pci_parse_devaddr(const char *addr, int *domp, int *busp, unsigned *slotp)
  pci_devaddr = nil
  inst = hc.inst

  sddev = File.expand_path(File.readlink(hc.os_devpath), '/dev/disk/by-path')
  connect_monitor(inst[:runtime_config][:telnet_port]) { |t|
    # success message:
    #   OK domain 0, bus 0, slot 4, function 0
    # error message:
    #   failed to add file=/dev/xxxx,if=virtio
    c = t.cmd("pci_add auto storage file=#{sddev},if=scsi")
    # Note: pci_parse_devaddr() called in "pci_add" uses strtoul()
    # with base 16 so that the input is expected in hex. however
    # at the result display, void pci_device_hot_add_print() uses
    # %d for showing bus and slot addresses. use hex to preserve
    # those values to keep consistent.
    if c =~ /\nOK domain ([0-9a-fA-F]+), bus ([0-9a-fA-F]+), slot ([0-9a-fA-F]+), function/m
      # numbers in OK result is decimal. convert them to hex.
      pci_devaddr = [$1, $2, $3].map{|i| i.to_i.to_s(16) }
    else
      raise "Error in qemu console: #{c}"
    end

    # double check the pci address.
    c = t.cmd("info pci")

    # static void pci_info_device(PCIBus *bus, PCIDevice *d)
    # called in "info pci" gets back PCI bus info with %d.
    if c.split(/\n/).grep(/^\s+Bus\s+#{pci_devaddr[1].to_i(16)}, device\s+#{pci_devaddr[2].to_i(16)}, function/).empty?
      raise "Could not find new disk device attached to qemu-kvm: #{pci_devaddr.join(':')}"
    end
  }
  pci_devaddr.join(':')
end

#detach_volume_from_guest(hc) ⇒ Object



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# File 'lib/dcmgr/drivers/kvm.rb', line 94

def detach_volume_from_guest(hc)
  inst = hc.inst
  vol = hc.vol
  pci_devaddr = vol[:guest_device_name]

  connect_monitor(inst[:runtime_config][:telnet_port]) { |t|
    t.cmd("pci_del #{pci_devaddr}")
    #
    #  Bus  0, device   4, function 0:
    #    SCSI controller: PCI device 1af4:1001
    #      IRQ 0.
    #      BAR0: I/O at 0x1000 [0x103f].
    #      BAR1: 32 bit memory at 0x08000000 [0x08000fff].
    #      id ""
    c = t.cmd("info pci")
    pci_devaddr = pci_devaddr.split(':')
    unless c.split(/\n/).grep(/\s+Bus\s+#{pci_devaddr[1].to_i(16)}, device\s+#{pci_devaddr[2].to_i(16)}, function/).empty?
      raise "Detached disk device still be attached in qemu-kvm: #{pci_devaddr.join(':')}"
    end
  }
end

#reboot_instance(hc) ⇒ Object



45
46
47
48
49
50
# File 'lib/dcmgr/drivers/kvm.rb', line 45

def reboot_instance(hc)
  inst = hc.inst
  connect_monitor(inst[:runtime_config][:telnet_port]) { |t|
    t.cmd("system_reset")
  }
end

#run_instance(hc) ⇒ Object



9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/dcmgr/drivers/kvm.rb', line 9

def run_instance(hc)
  # run vm
  inst = hc.inst
  cmd = "kvm -m %d -smp %d -name vdc-%s -vnc :%d -drive file=%s -pidfile %s -daemonize -monitor telnet::%d,server,nowait"
  args=[inst[:instance_spec][:memory_size],
        inst[:instance_spec][:cpu_cores],
        inst[:uuid],
        inst[:runtime_config][:vnc_port],
        hc.os_devpath,
        File.expand_path('kvm.pid', hc.inst_data_dir),
        inst[:runtime_config][:telnet_port]
       ]
  if vnic = inst[:instance_nics].first
    cmd += " -net nic,macaddr=%s -net tap,ifname=%s,script=,downscript="
    args << vnic[:mac_addr].unpack('A2'*6).join(':')
    args << vnic[:uuid]
  end
  sh(cmd, args)

  unless vnic.nil?
    sh("/sbin/ifconfig %s 0.0.0.0 up", [vnic[:uuid]])
    sh("/usr/sbin/brctl addif %s %s", [hc.bridge_if, vnic[:uuid]])
  end

  sleep 1
end

#terminate_instance(hc) ⇒ Object



36
37
38
39
40
41
42
43
# File 'lib/dcmgr/drivers/kvm.rb', line 36

def terminate_instance(hc)
  kvm_pid=`pgrep -u root -f vdc-#{hc.inst_id}`
  if $?.exitstatus == 0 && kvm_pid.to_s =~ /^\d+$/
    sh("/bin/kill #{kvm_pid}")
  else
    logger.error("Can not find the KVM process. Skipping: kvm -name vdc-#{hc.inst_id}")
  end
end