Class: Dcmgr::Drivers::Kvm
- Inherits:
-
Hypervisor
- Object
- Hypervisor
- Dcmgr::Drivers::Kvm
- Includes:
- Helpers::CliHelper, Helpers::NicHelper, Logger
- Defined in:
- lib/dcmgr/drivers/kvm.rb
Constant Summary collapse
- KVM_NIC_PCI_ADDR_OFFSET =
0x0-2 are reserved by KVM. 0=Host bridge 1=ISA bridge 2=VGA
0x10
Instance Method Summary collapse
- #attach_volume_to_guest(hc) ⇒ Object
- #detach_volume_from_guest(hc) ⇒ Object
- #reboot_instance(hc) ⇒ Object
- #run_instance(hc) ⇒ Object
- #terminate_instance(hc) ⇒ Object
Methods included from Helpers::NicHelper
#clean_mac, #find_nic, #is_natted?, #nic_state, #valid_nic?
Methods included from Helpers::CliHelper
Methods included from Logger
create, default_logdev, included
Methods inherited from Hypervisor
Instance Method Details
#attach_volume_to_guest(hc) ⇒ Object
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 |
# File 'lib/dcmgr/drivers/kvm.rb', line 106 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.(File.readlink(hc.os_devpath), '/dev/disk/by-path') connect_monitor(hc) { |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=#{drive_model(hc)},cache=off") # 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
148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/dcmgr/drivers/kvm.rb', line 148 def detach_volume_from_guest(hc) inst = hc.inst vol = hc.vol pci_devaddr = vol[:guest_device_name] connect_monitor(hc) { |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 "" pci_devaddr = pci_devaddr.split(':') pass=false tryagain do sleep 1 pass = t.shell_result("info pci").split(/\n/).grep(/\s+Bus\s+#{pci_devaddr[1].to_i(16)}, device\s+#{pci_devaddr[2].to_i(16)}, function/).empty? end raise "Detached disk device still be attached in qemu-kvm: #{pci_devaddr.join(':')}" if pass == false } end |
#reboot_instance(hc) ⇒ Object
93 94 95 96 97 98 99 100 101 102 103 104 |
# File 'lib/dcmgr/drivers/kvm.rb', line 93 def reboot_instance(hc) inst = hc.inst connect_monitor(hc) { |t| t.cmd("system_reset") # When the guest initiate halt/poweroff the KVM might become # "paused" status. At that time, "system_reset" command does # not work as it is an ACPI signal. The "cont" command allows # to bring the status back to running in this case. # It has no effect if the status is kept running already. t.cmd('cont') } end |
#run_instance(hc) ⇒ Object
18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/dcmgr/drivers/kvm.rb', line 18 def run_instance(hc) # tcp listen ports for KVM monitor and VNC console monitor_port = pick_tcp_listen_port vnc_port = pick_tcp_listen_port File.open(File.('monitor.port', hc.inst_data_dir), "w") { |f| f.write(monitor_port) } File.open(File.('vnc.port', hc.inst_data_dir), "w") { |f| f.write(vnc_port) } # run vm inst = hc.inst cmd = ["kvm -m %d -smp %d -name vdc-%s -vnc :%d", "-cpu host", "-pidfile %s", "-daemonize", "-monitor telnet:127.0.0.1:%d,server,nowait", "-no-shutdown", ] args=[inst[:memory_size], inst[:cpu_cores], inst[:uuid], vnc_port - 5900, # KVM -vnc offsets 5900 File.('kvm.pid', hc.inst_data_dir), monitor_port ] cmd << "-drive file=%s,media=disk,boot=on,index=0,cache=none,if=#{drive_model(hc)}" args << hc.os_devpath cmd << "-drive file=%s,media=disk,index=1,cache=none,if=#{drive_model(hc)}" args << hc. vifs = inst[:vif] if !vifs.empty? vifs.sort {|a, b| a[:device_index] <=> b[:device_index] }.each { |vif| cmd << "-net nic,vlan=#{vif[:device_index].to_i},macaddr=%s,model=#{nic_model(hc)},addr=%x -net tap,vlan=#{vif[:device_index].to_i},ifname=%s,script=no,downscript=no" args << vif[:mac_addr].unpack('A2'*6).join(':') args << (KVM_NIC_PCI_ADDR_OFFSET + vif[:device_index].to_i) args << vif[:uuid] } end sh(cmd.join(' '), args) vifs.each { |vif| if vif[:ipv4] sh("/sbin/ip link set %s up", [vif[:uuid]]) sh("/usr/sbin/brctl addif %s %s", [vif[:ipv4][:network][:link_interface], vif[:uuid]]) end } sleep 1 end |
#terminate_instance(hc) ⇒ Object
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/dcmgr/drivers/kvm.rb', line 73 def terminate_instance(hc) begin connect_monitor(hc) { |t| t.cmd("quit") } rescue Errno::ECONNRESET => e # succssfully terminated the process rescue => e kvm_pid = File.read(File.('kvm.pid', hc.inst_data_dir)) if kvm_pid.nil? || kvm_pid == '' kvm_pid=`pgrep -u root -f vdc-#{hc.inst_id}` end if kvm_pid.to_s =~ /^\d+$/ sh("/bin/kill -9 #{kvm_pid}") rescue logger.error($!) else logger.error("Can not find the KVM process. Skipping: #{hc.inst_id}") end end end |