Statistics
| Branch: | Tag: | Revision:

root / lib / hypervisor / hv_kvm.py @ 07813a9e

History | View | Annotate | Download (29.3 kB)

1 eb58f9b1 Guido Trotter
#
2 eb58f9b1 Guido Trotter
#
3 eb58f9b1 Guido Trotter
4 eb58f9b1 Guido Trotter
# Copyright (C) 2008 Google Inc.
5 eb58f9b1 Guido Trotter
#
6 eb58f9b1 Guido Trotter
# This program is free software; you can redistribute it and/or modify
7 eb58f9b1 Guido Trotter
# it under the terms of the GNU General Public License as published by
8 eb58f9b1 Guido Trotter
# the Free Software Foundation; either version 2 of the License, or
9 eb58f9b1 Guido Trotter
# (at your option) any later version.
10 eb58f9b1 Guido Trotter
#
11 eb58f9b1 Guido Trotter
# This program is distributed in the hope that it will be useful, but
12 eb58f9b1 Guido Trotter
# WITHOUT ANY WARRANTY; without even the implied warranty of
13 eb58f9b1 Guido Trotter
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 eb58f9b1 Guido Trotter
# General Public License for more details.
15 eb58f9b1 Guido Trotter
#
16 eb58f9b1 Guido Trotter
# You should have received a copy of the GNU General Public License
17 eb58f9b1 Guido Trotter
# along with this program; if not, write to the Free Software
18 eb58f9b1 Guido Trotter
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 eb58f9b1 Guido Trotter
# 02110-1301, USA.
20 eb58f9b1 Guido Trotter
21 eb58f9b1 Guido Trotter
22 eb58f9b1 Guido Trotter
"""KVM hypervisor
23 eb58f9b1 Guido Trotter

24 eb58f9b1 Guido Trotter
"""
25 eb58f9b1 Guido Trotter
26 eb58f9b1 Guido Trotter
import os
27 eb58f9b1 Guido Trotter
import os.path
28 eb58f9b1 Guido Trotter
import re
29 eb58f9b1 Guido Trotter
import tempfile
30 6567aff3 Guido Trotter
import time
31 30e42c4e Guido Trotter
import logging
32 eb58f9b1 Guido Trotter
from cStringIO import StringIO
33 eb58f9b1 Guido Trotter
34 eb58f9b1 Guido Trotter
from ganeti import utils
35 eb58f9b1 Guido Trotter
from ganeti import constants
36 eb58f9b1 Guido Trotter
from ganeti import errors
37 38e250ba Guido Trotter
from ganeti import serializer
38 38e250ba Guido Trotter
from ganeti import objects
39 eb58f9b1 Guido Trotter
from ganeti.hypervisor import hv_base
40 eb58f9b1 Guido Trotter
41 eb58f9b1 Guido Trotter
42 eb58f9b1 Guido Trotter
class KVMHypervisor(hv_base.BaseHypervisor):
43 c4469f75 Guido Trotter
  """KVM hypervisor interface"""
44 eb58f9b1 Guido Trotter
45 eb58f9b1 Guido Trotter
  _ROOT_DIR = constants.RUN_GANETI_DIR + "/kvm-hypervisor"
46 a1d79fc6 Guido Trotter
  _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids
47 a1d79fc6 Guido Trotter
  _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets
48 a1d79fc6 Guido Trotter
  _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data
49 a1d79fc6 Guido Trotter
  _DIRS = [_ROOT_DIR, _PIDS_DIR, _CTRL_DIR, _CONF_DIR]
50 eb58f9b1 Guido Trotter
51 6b5605e8 Iustin Pop
  PARAMETERS = [
52 6b5605e8 Iustin Pop
    constants.HV_KERNEL_PATH,
53 6b5605e8 Iustin Pop
    constants.HV_INITRD_PATH,
54 074ca009 Guido Trotter
    constants.HV_ROOT_PATH,
55 07813a9e Iustin Pop
    constants.HV_KERNEL_ARGS,
56 6b5605e8 Iustin Pop
    constants.HV_ACPI,
57 a2faf9ee Guido Trotter
    constants.HV_SERIAL_CONSOLE,
58 56fee73b Guido Trotter
    constants.HV_VNC_BIND_ADDRESS,
59 8b2d1013 Guido Trotter
    constants.HV_VNC_TLS,
60 8b2d1013 Guido Trotter
    constants.HV_VNC_X509,
61 8b2d1013 Guido Trotter
    constants.HV_VNC_X509_VERIFY,
62 66d5dbef Guido Trotter
    constants.HV_CDROM_IMAGE_PATH,
63 66d5dbef Guido Trotter
    constants.HV_BOOT_ORDER,
64 43440815 Guido Trotter
    constants.HV_NIC_TYPE,
65 43440815 Guido Trotter
    constants.HV_DISK_TYPE,
66 11344a50 Guido Trotter
    constants.HV_USB_MOUSE,
67 6b5605e8 Iustin Pop
    ]
68 6b5605e8 Iustin Pop
69 30e42c4e Guido Trotter
  _MIGRATION_STATUS_RE = re.compile('Migration\s+status:\s+(\w+)',
70 30e42c4e Guido Trotter
                                    re.M | re.I)
71 30e42c4e Guido Trotter
72 eb58f9b1 Guido Trotter
  def __init__(self):
73 eb58f9b1 Guido Trotter
    hv_base.BaseHypervisor.__init__(self)
74 eb58f9b1 Guido Trotter
    # Let's make sure the directories we need exist, even if the RUN_DIR lives
75 eb58f9b1 Guido Trotter
    # in a tmpfs filesystem or has been otherwise wiped out.
76 08137f9e Iustin Pop
    for mydir in self._DIRS:
77 08137f9e Iustin Pop
      if not os.path.exists(mydir):
78 08137f9e Iustin Pop
        os.mkdir(mydir)
79 eb58f9b1 Guido Trotter
80 1f8b3a27 Guido Trotter
  def _InstancePidAlive(self, instance_name):
81 1f8b3a27 Guido Trotter
    """Returns the instance pid and pidfile
82 1f8b3a27 Guido Trotter

83 1f8b3a27 Guido Trotter
    """
84 1f8b3a27 Guido Trotter
    pidfile = "%s/%s" % (self._PIDS_DIR, instance_name)
85 1f8b3a27 Guido Trotter
    pid = utils.ReadPidFile(pidfile)
86 1f8b3a27 Guido Trotter
    alive = utils.IsProcessAlive(pid)
87 1f8b3a27 Guido Trotter
88 1f8b3a27 Guido Trotter
    return (pidfile, pid, alive)
89 1f8b3a27 Guido Trotter
90 0df4d98a Guido Trotter
  @classmethod
91 0df4d98a Guido Trotter
  def _InstanceMonitor(cls, instance_name):
92 c4fbefc8 Guido Trotter
    """Returns the instance monitor socket name
93 c4fbefc8 Guido Trotter

94 c4fbefc8 Guido Trotter
    """
95 0df4d98a Guido Trotter
    return '%s/%s.monitor' % (cls._CTRL_DIR, instance_name)
96 c4fbefc8 Guido Trotter
97 0df4d98a Guido Trotter
  @classmethod
98 0df4d98a Guido Trotter
  def _InstanceSerial(cls, instance_name):
99 c4fbefc8 Guido Trotter
    """Returns the instance serial socket name
100 c4fbefc8 Guido Trotter

101 c4fbefc8 Guido Trotter
    """
102 0df4d98a Guido Trotter
    return '%s/%s.serial' % (cls._CTRL_DIR, instance_name)
103 c4fbefc8 Guido Trotter
104 0df4d98a Guido Trotter
  @classmethod
105 0df4d98a Guido Trotter
  def _InstanceKVMRuntime(cls, instance_name):
106 38e250ba Guido Trotter
    """Returns the instance KVM runtime filename
107 38e250ba Guido Trotter

108 38e250ba Guido Trotter
    """
109 0df4d98a Guido Trotter
    return '%s/%s.runtime' % (cls._CONF_DIR, instance_name)
110 38e250ba Guido Trotter
111 eb58f9b1 Guido Trotter
  def _WriteNetScript(self, instance, seq, nic):
112 eb58f9b1 Guido Trotter
    """Write a script to connect a net interface to the proper bridge.
113 eb58f9b1 Guido Trotter

114 eb58f9b1 Guido Trotter
    This can be used by any qemu-type hypervisor.
115 eb58f9b1 Guido Trotter

116 eb58f9b1 Guido Trotter
    @param instance: instance we're acting on
117 eb58f9b1 Guido Trotter
    @type instance: instance object
118 eb58f9b1 Guido Trotter
    @param seq: nic sequence number
119 eb58f9b1 Guido Trotter
    @type seq: int
120 eb58f9b1 Guido Trotter
    @param nic: nic we're acting on
121 eb58f9b1 Guido Trotter
    @type nic: nic object
122 eb58f9b1 Guido Trotter
    @return: netscript file name
123 eb58f9b1 Guido Trotter
    @rtype: string
124 eb58f9b1 Guido Trotter

125 eb58f9b1 Guido Trotter
    """
126 eb58f9b1 Guido Trotter
    script = StringIO()
127 eb58f9b1 Guido Trotter
    script.write("#!/bin/sh\n")
128 eb58f9b1 Guido Trotter
    script.write("# this is autogenerated by Ganeti, please do not edit\n#\n")
129 eb58f9b1 Guido Trotter
    script.write("export INSTANCE=%s\n" % instance.name)
130 eb58f9b1 Guido Trotter
    script.write("export MAC=%s\n" % nic.mac)
131 eb58f9b1 Guido Trotter
    script.write("export IP=%s\n" % nic.ip)
132 eb58f9b1 Guido Trotter
    script.write("export BRIDGE=%s\n" % nic.bridge)
133 eb58f9b1 Guido Trotter
    script.write("export INTERFACE=$1\n")
134 eb58f9b1 Guido Trotter
    # TODO: make this configurable at ./configure time
135 eb58f9b1 Guido Trotter
    script.write("if [ -x /etc/ganeti/kvm-vif-bridge ]; then\n")
136 eb58f9b1 Guido Trotter
    script.write("  # Execute the user-specific vif file\n")
137 eb58f9b1 Guido Trotter
    script.write("  /etc/ganeti/kvm-vif-bridge\n")
138 eb58f9b1 Guido Trotter
    script.write("else\n")
139 eb58f9b1 Guido Trotter
    script.write("  # Connect the interface to the bridge\n")
140 eb58f9b1 Guido Trotter
    script.write("  /sbin/ifconfig $INTERFACE 0.0.0.0 up\n")
141 eb58f9b1 Guido Trotter
    script.write("  /usr/sbin/brctl addif $BRIDGE $INTERFACE\n")
142 eb58f9b1 Guido Trotter
    script.write("fi\n\n")
143 eb58f9b1 Guido Trotter
    # As much as we'd like to put this in our _ROOT_DIR, that will happen to be
144 eb58f9b1 Guido Trotter
    # mounted noexec sometimes, so we'll have to find another place.
145 eb58f9b1 Guido Trotter
    (tmpfd, tmpfile_name) = tempfile.mkstemp()
146 eb58f9b1 Guido Trotter
    tmpfile = os.fdopen(tmpfd, 'w')
147 eb58f9b1 Guido Trotter
    tmpfile.write(script.getvalue())
148 eb58f9b1 Guido Trotter
    tmpfile.close()
149 eb58f9b1 Guido Trotter
    os.chmod(tmpfile_name, 0755)
150 eb58f9b1 Guido Trotter
    return tmpfile_name
151 eb58f9b1 Guido Trotter
152 eb58f9b1 Guido Trotter
  def ListInstances(self):
153 eb58f9b1 Guido Trotter
    """Get the list of running instances.
154 eb58f9b1 Guido Trotter

155 c41eea6e Iustin Pop
    We can do this by listing our live instances directory and
156 c41eea6e Iustin Pop
    checking whether the associated kvm process is still alive.
157 eb58f9b1 Guido Trotter

158 eb58f9b1 Guido Trotter
    """
159 eb58f9b1 Guido Trotter
    result = []
160 eb58f9b1 Guido Trotter
    for name in os.listdir(self._PIDS_DIR):
161 08137f9e Iustin Pop
      filename = "%s/%s" % (self._PIDS_DIR, name)
162 08137f9e Iustin Pop
      if utils.IsProcessAlive(utils.ReadPidFile(filename)):
163 eb58f9b1 Guido Trotter
        result.append(name)
164 eb58f9b1 Guido Trotter
    return result
165 eb58f9b1 Guido Trotter
166 eb58f9b1 Guido Trotter
  def GetInstanceInfo(self, instance_name):
167 eb58f9b1 Guido Trotter
    """Get instance properties.
168 eb58f9b1 Guido Trotter

169 c41eea6e Iustin Pop
    @param instance_name: the instance name
170 c41eea6e Iustin Pop

171 c41eea6e Iustin Pop
    @return: tuple (name, id, memory, vcpus, stat, times)
172 eb58f9b1 Guido Trotter

173 eb58f9b1 Guido Trotter
    """
174 1f8b3a27 Guido Trotter
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
175 1f8b3a27 Guido Trotter
    if not alive:
176 eb58f9b1 Guido Trotter
      return None
177 eb58f9b1 Guido Trotter
178 eb58f9b1 Guido Trotter
    cmdline_file = "/proc/%s/cmdline" % pid
179 eb58f9b1 Guido Trotter
    try:
180 eb58f9b1 Guido Trotter
      fh = open(cmdline_file, 'r')
181 eb58f9b1 Guido Trotter
      try:
182 eb58f9b1 Guido Trotter
        cmdline = fh.read()
183 eb58f9b1 Guido Trotter
      finally:
184 eb58f9b1 Guido Trotter
        fh.close()
185 90c024f6 Guido Trotter
    except EnvironmentError, err:
186 eb58f9b1 Guido Trotter
      raise errors.HypervisorError("Failed to list instance %s: %s" %
187 eb58f9b1 Guido Trotter
                                   (instance_name, err))
188 eb58f9b1 Guido Trotter
189 eb58f9b1 Guido Trotter
    memory = 0
190 eb58f9b1 Guido Trotter
    vcpus = 0
191 eb58f9b1 Guido Trotter
    stat = "---b-"
192 eb58f9b1 Guido Trotter
    times = "0"
193 eb58f9b1 Guido Trotter
194 eb58f9b1 Guido Trotter
    arg_list = cmdline.split('\x00')
195 eb58f9b1 Guido Trotter
    while arg_list:
196 eb58f9b1 Guido Trotter
      arg =  arg_list.pop(0)
197 eb58f9b1 Guido Trotter
      if arg == '-m':
198 eb58f9b1 Guido Trotter
        memory = arg_list.pop(0)
199 eb58f9b1 Guido Trotter
      elif arg == '-smp':
200 eb58f9b1 Guido Trotter
        vcpus = arg_list.pop(0)
201 eb58f9b1 Guido Trotter
202 eb58f9b1 Guido Trotter
    return (instance_name, pid, memory, vcpus, stat, times)
203 eb58f9b1 Guido Trotter
204 eb58f9b1 Guido Trotter
  def GetAllInstancesInfo(self):
205 eb58f9b1 Guido Trotter
    """Get properties of all instances.
206 eb58f9b1 Guido Trotter

207 c41eea6e Iustin Pop
    @return: list of tuples (name, id, memory, vcpus, stat, times)
208 c41eea6e Iustin Pop

209 eb58f9b1 Guido Trotter
    """
210 eb58f9b1 Guido Trotter
    data = []
211 eb58f9b1 Guido Trotter
    for name in os.listdir(self._PIDS_DIR):
212 08137f9e Iustin Pop
      filename = "%s/%s" % (self._PIDS_DIR, name)
213 08137f9e Iustin Pop
      if utils.IsProcessAlive(utils.ReadPidFile(filename)):
214 00ad5362 Guido Trotter
        try:
215 00ad5362 Guido Trotter
          info = self.GetInstanceInfo(name)
216 00ad5362 Guido Trotter
        except errors.HypervisorError, err:
217 00ad5362 Guido Trotter
          continue
218 00ad5362 Guido Trotter
        if info:
219 00ad5362 Guido Trotter
          data.append(info)
220 eb58f9b1 Guido Trotter
221 eb58f9b1 Guido Trotter
    return data
222 eb58f9b1 Guido Trotter
223 07813a9e Iustin Pop
  def _GenerateKVMRuntime(self, instance, block_devices):
224 ee5f20b0 Guido Trotter
    """Generate KVM information to start an instance.
225 eb58f9b1 Guido Trotter

226 eb58f9b1 Guido Trotter
    """
227 1f8b3a27 Guido Trotter
    pidfile, pid, alive = self._InstancePidAlive(instance.name)
228 eb58f9b1 Guido Trotter
    kvm = constants.KVM_PATH
229 eb58f9b1 Guido Trotter
    kvm_cmd = [kvm]
230 8b3fd458 Iustin Pop
    kvm_cmd.extend(['-m', instance.beparams[constants.BE_MEMORY]])
231 8b3fd458 Iustin Pop
    kvm_cmd.extend(['-smp', instance.beparams[constants.BE_VCPUS]])
232 eb58f9b1 Guido Trotter
    kvm_cmd.extend(['-pidfile', pidfile])
233 eb58f9b1 Guido Trotter
    # used just by the vnc server, if enabled
234 eb58f9b1 Guido Trotter
    kvm_cmd.extend(['-name', instance.name])
235 eb58f9b1 Guido Trotter
    kvm_cmd.extend(['-daemonize'])
236 6b5605e8 Iustin Pop
    if not instance.hvparams[constants.HV_ACPI]:
237 eb58f9b1 Guido Trotter
      kvm_cmd.extend(['-no-acpi'])
238 eb58f9b1 Guido Trotter
239 a985b417 Iustin Pop
    hvp = instance.hvparams
240 a985b417 Iustin Pop
    boot_disk = hvp[constants.HV_BOOT_ORDER] == "disk"
241 a985b417 Iustin Pop
    boot_cdrom = hvp[constants.HV_BOOT_ORDER] == "cdrom"
242 a985b417 Iustin Pop
    boot_network = hvp[constants.HV_BOOT_ORDER] == "network"
243 8745c3d7 Guido Trotter
244 8745c3d7 Guido Trotter
    if boot_network:
245 8745c3d7 Guido Trotter
      kvm_cmd.extend(['-boot', 'n'])
246 1213604d Guido Trotter
247 a985b417 Iustin Pop
    disk_type = hvp[constants.HV_DISK_TYPE]
248 1213604d Guido Trotter
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
249 1213604d Guido Trotter
      if_val = ',if=virtio'
250 1213604d Guido Trotter
    else:
251 1213604d Guido Trotter
      if_val = ',if=%s' % disk_type
252 069cfbf1 Iustin Pop
    for cfdev, dev_path in block_devices:
253 d34b16d7 Iustin Pop
      if cfdev.mode != constants.DISK_RDWR:
254 d34b16d7 Iustin Pop
        raise errors.HypervisorError("Instance has read-only disks which"
255 d34b16d7 Iustin Pop
                                     " are not supported by KVM")
256 eb58f9b1 Guido Trotter
      # TODO: handle FD_LOOP and FD_BLKTAP (?)
257 66d5dbef Guido Trotter
      if boot_disk:
258 9dd363eb Guido Trotter
        kvm_cmd.extend(['-boot', 'c'])
259 eb58f9b1 Guido Trotter
        boot_val = ',boot=on'
260 8745c3d7 Guido Trotter
        # We only boot from the first disk
261 66d5dbef Guido Trotter
        boot_disk = False
262 eb58f9b1 Guido Trotter
      else:
263 eb58f9b1 Guido Trotter
        boot_val = ''
264 eb58f9b1 Guido Trotter
265 069cfbf1 Iustin Pop
      drive_val = 'file=%s,format=raw%s%s' % (dev_path, if_val, boot_val)
266 eb58f9b1 Guido Trotter
      kvm_cmd.extend(['-drive', drive_val])
267 eb58f9b1 Guido Trotter
268 a985b417 Iustin Pop
    iso_image = hvp[constants.HV_CDROM_IMAGE_PATH]
269 66d5dbef Guido Trotter
    if iso_image:
270 9dd363eb Guido Trotter
      options = ',format=raw,media=cdrom'
271 66d5dbef Guido Trotter
      if boot_cdrom:
272 9dd363eb Guido Trotter
        kvm_cmd.extend(['-boot', 'd'])
273 66d5dbef Guido Trotter
        options = '%s,boot=on' % options
274 9dd363eb Guido Trotter
      else:
275 9dd363eb Guido Trotter
        options = '%s,if=virtio' % options
276 66d5dbef Guido Trotter
      drive_val = 'file=%s%s' % (iso_image, options)
277 66d5dbef Guido Trotter
      kvm_cmd.extend(['-drive', drive_val])
278 66d5dbef Guido Trotter
279 a985b417 Iustin Pop
    kernel_path = hvp[constants.HV_KERNEL_PATH]
280 df5ab9f0 Guido Trotter
    if kernel_path:
281 df5ab9f0 Guido Trotter
      kvm_cmd.extend(['-kernel', kernel_path])
282 a985b417 Iustin Pop
      initrd_path = hvp[constants.HV_INITRD_PATH]
283 df5ab9f0 Guido Trotter
      if initrd_path:
284 df5ab9f0 Guido Trotter
        kvm_cmd.extend(['-initrd', initrd_path])
285 07813a9e Iustin Pop
      root_append = ['root=%s' % hvp[constants.HV_ROOT_PATH],
286 07813a9e Iustin Pop
                     hvp[constants.HV_KERNEL_ARGS]]
287 07813a9e Iustin Pop
      if hvp[constants.HV_SERIAL_CONSOLE]:
288 07813a9e Iustin Pop
        root_append.append('console=ttyS0,38400')
289 07813a9e Iustin Pop
      kvm_cmd.extend(['-append', ' '.join(root_append)])
290 eb58f9b1 Guido Trotter
291 a985b417 Iustin Pop
    mouse_type = hvp[constants.HV_USB_MOUSE]
292 11344a50 Guido Trotter
    if mouse_type:
293 11344a50 Guido Trotter
      kvm_cmd.extend(['-usb'])
294 11344a50 Guido Trotter
      kvm_cmd.extend(['-usbdevice', mouse_type])
295 11344a50 Guido Trotter
296 8470c8db Guido Trotter
    # FIXME: handle vnc password
297 a985b417 Iustin Pop
    vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS]
298 8470c8db Guido Trotter
    if vnc_bind_address:
299 8447f52b Guido Trotter
      if utils.IsValidIP(vnc_bind_address):
300 377d74c9 Guido Trotter
        if instance.network_port > constants.VNC_BASE_PORT:
301 377d74c9 Guido Trotter
          display = instance.network_port - constants.VNC_BASE_PORT
302 8447f52b Guido Trotter
          if vnc_bind_address == '0.0.0.0':
303 8447f52b Guido Trotter
            vnc_arg = ':%d' % (display)
304 8447f52b Guido Trotter
          else:
305 8447f52b Guido Trotter
            vnc_arg = '%s:%d' % (constants.HV_VNC_BIND_ADDRESS, display)
306 8470c8db Guido Trotter
        else:
307 8447f52b Guido Trotter
          logging.error("Network port is not a valid VNC display (%d < %d)."
308 8447f52b Guido Trotter
                        " Not starting VNC" %
309 8447f52b Guido Trotter
                        (instance.network_port,
310 377d74c9 Guido Trotter
                         constants.VNC_BASE_PORT))
311 8447f52b Guido Trotter
          vnc_arg = 'none'
312 8b2d1013 Guido Trotter
313 8b2d1013 Guido Trotter
        # Only allow tls and other option when not binding to a file, for now.
314 8b2d1013 Guido Trotter
        # kvm/qemu gets confused otherwise about the filename to use.
315 8b2d1013 Guido Trotter
        vnc_append = ''
316 a985b417 Iustin Pop
        if hvp[constants.HV_VNC_TLS]:
317 8b2d1013 Guido Trotter
          vnc_append = '%s,tls' % vnc_append
318 a985b417 Iustin Pop
          if hvp[constants.HV_VNC_X509_VERIFY]:
319 8b2d1013 Guido Trotter
            vnc_append = '%s,x509verify=%s' % (vnc_append,
320 a985b417 Iustin Pop
                                               hvp[constants.HV_VNC_X509])
321 a985b417 Iustin Pop
          elif hvp[constants.HV_VNC_X509]:
322 8b2d1013 Guido Trotter
            vnc_append = '%s,x509=%s' % (vnc_append,
323 a985b417 Iustin Pop
                                         hvp[constants.HV_VNC_X509])
324 8b2d1013 Guido Trotter
        vnc_arg = '%s%s' % (vnc_arg, vnc_append)
325 8b2d1013 Guido Trotter
326 8470c8db Guido Trotter
      else:
327 8b2d1013 Guido Trotter
        vnc_arg = 'unix:%s/%s.vnc' % (vnc_bind_address, instance.name)
328 8b2d1013 Guido Trotter
329 8447f52b Guido Trotter
      kvm_cmd.extend(['-vnc', vnc_arg])
330 8470c8db Guido Trotter
    else:
331 8470c8db Guido Trotter
      kvm_cmd.extend(['-nographic'])
332 8470c8db Guido Trotter
333 c4fbefc8 Guido Trotter
    monitor_dev = 'unix:%s,server,nowait' % \
334 c4fbefc8 Guido Trotter
      self._InstanceMonitor(instance.name)
335 eb58f9b1 Guido Trotter
    kvm_cmd.extend(['-monitor', monitor_dev])
336 a985b417 Iustin Pop
    if hvp[constants.HV_SERIAL_CONSOLE]:
337 a985b417 Iustin Pop
      serial_dev = ('unix:%s,server,nowait' %
338 a985b417 Iustin Pop
                    self._InstanceSerial(instance.name))
339 a2faf9ee Guido Trotter
      kvm_cmd.extend(['-serial', serial_dev])
340 a2faf9ee Guido Trotter
    else:
341 a2faf9ee Guido Trotter
      kvm_cmd.extend(['-serial', 'none'])
342 eb58f9b1 Guido Trotter
343 ee5f20b0 Guido Trotter
    # Save the current instance nics, but defer their expansion as parameters,
344 ee5f20b0 Guido Trotter
    # as we'll need to generate executable temp files for them.
345 ee5f20b0 Guido Trotter
    kvm_nics = instance.nics
346 a985b417 Iustin Pop
    hvparams = hvp
347 ee5f20b0 Guido Trotter
348 c2672466 Guido Trotter
    return (kvm_cmd, kvm_nics, hvparams)
349 ee5f20b0 Guido Trotter
350 38e250ba Guido Trotter
  def _WriteKVMRuntime(self, instance_name, data):
351 38e250ba Guido Trotter
    """Write an instance's KVM runtime
352 38e250ba Guido Trotter

353 38e250ba Guido Trotter
    """
354 38e250ba Guido Trotter
    try:
355 38e250ba Guido Trotter
      utils.WriteFile(self._InstanceKVMRuntime(instance_name),
356 38e250ba Guido Trotter
                      data=data)
357 90c024f6 Guido Trotter
    except EnvironmentError, err:
358 38e250ba Guido Trotter
      raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
359 38e250ba Guido Trotter
360 38e250ba Guido Trotter
  def _ReadKVMRuntime(self, instance_name):
361 38e250ba Guido Trotter
    """Read an instance's KVM runtime
362 38e250ba Guido Trotter

363 38e250ba Guido Trotter
    """
364 38e250ba Guido Trotter
    try:
365 38e250ba Guido Trotter
      file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name))
366 90c024f6 Guido Trotter
    except EnvironmentError, err:
367 38e250ba Guido Trotter
      raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err)
368 38e250ba Guido Trotter
    return file_content
369 38e250ba Guido Trotter
370 38e250ba Guido Trotter
  def _SaveKVMRuntime(self, instance, kvm_runtime):
371 38e250ba Guido Trotter
    """Save an instance's KVM runtime
372 38e250ba Guido Trotter

373 38e250ba Guido Trotter
    """
374 c2672466 Guido Trotter
    kvm_cmd, kvm_nics, hvparams = kvm_runtime
375 38e250ba Guido Trotter
    serialized_nics = [nic.ToDict() for nic in kvm_nics]
376 c2672466 Guido Trotter
    serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams))
377 38e250ba Guido Trotter
    self._WriteKVMRuntime(instance.name, serialized_form)
378 38e250ba Guido Trotter
379 30e42c4e Guido Trotter
  def _LoadKVMRuntime(self, instance, serialized_runtime=None):
380 38e250ba Guido Trotter
    """Load an instance's KVM runtime
381 38e250ba Guido Trotter

382 38e250ba Guido Trotter
    """
383 30e42c4e Guido Trotter
    if not serialized_runtime:
384 30e42c4e Guido Trotter
      serialized_runtime = self._ReadKVMRuntime(instance.name)
385 30e42c4e Guido Trotter
    loaded_runtime = serializer.Load(serialized_runtime)
386 c2672466 Guido Trotter
    kvm_cmd, serialized_nics, hvparams = loaded_runtime
387 38e250ba Guido Trotter
    kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
388 c2672466 Guido Trotter
    return (kvm_cmd, kvm_nics, hvparams)
389 38e250ba Guido Trotter
390 30e42c4e Guido Trotter
  def _ExecuteKVMRuntime(self, instance, kvm_runtime, incoming=None):
391 ee5f20b0 Guido Trotter
    """Execute a KVM cmd, after completing it with some last minute data
392 ee5f20b0 Guido Trotter

393 30e42c4e Guido Trotter
    @type incoming: tuple of strings
394 30e42c4e Guido Trotter
    @param incoming: (target_host_ip, port)
395 30e42c4e Guido Trotter

396 ee5f20b0 Guido Trotter
    """
397 1f8b3a27 Guido Trotter
    pidfile, pid, alive = self._InstancePidAlive(instance.name)
398 1f8b3a27 Guido Trotter
    if alive:
399 ee5f20b0 Guido Trotter
      raise errors.HypervisorError("Failed to start instance %s: %s" %
400 ee5f20b0 Guido Trotter
                                   (instance.name, "already running"))
401 ee5f20b0 Guido Trotter
402 ee5f20b0 Guido Trotter
    temp_files = []
403 ee5f20b0 Guido Trotter
404 c2672466 Guido Trotter
    kvm_cmd, kvm_nics, hvparams = kvm_runtime
405 ee5f20b0 Guido Trotter
406 ee5f20b0 Guido Trotter
    if not kvm_nics:
407 ee5f20b0 Guido Trotter
      kvm_cmd.extend(['-net', 'none'])
408 ee5f20b0 Guido Trotter
    else:
409 37f88dc6 Guido Trotter
      nic_type = hvparams[constants.HV_NIC_TYPE]
410 37f88dc6 Guido Trotter
      if nic_type == constants.HT_NIC_PARAVIRTUAL:
411 37f88dc6 Guido Trotter
        nic_model = "model=virtio"
412 37f88dc6 Guido Trotter
      else:
413 37f88dc6 Guido Trotter
        nic_model = "model=%s" % nic_type
414 37f88dc6 Guido Trotter
415 ee5f20b0 Guido Trotter
      for nic_seq, nic in enumerate(kvm_nics):
416 37f88dc6 Guido Trotter
        nic_val = "nic,macaddr=%s,%s" % (nic.mac, nic_model)
417 ee5f20b0 Guido Trotter
        script = self._WriteNetScript(instance, nic_seq, nic)
418 ee5f20b0 Guido Trotter
        kvm_cmd.extend(['-net', nic_val])
419 ee5f20b0 Guido Trotter
        kvm_cmd.extend(['-net', 'tap,script=%s' % script])
420 ee5f20b0 Guido Trotter
        temp_files.append(script)
421 ee5f20b0 Guido Trotter
422 30e42c4e Guido Trotter
    if incoming:
423 30e42c4e Guido Trotter
      target, port = incoming
424 30e42c4e Guido Trotter
      kvm_cmd.extend(['-incoming', 'tcp:%s:%s' % (target, port)])
425 30e42c4e Guido Trotter
426 eb58f9b1 Guido Trotter
    result = utils.RunCmd(kvm_cmd)
427 eb58f9b1 Guido Trotter
    if result.failed:
428 eb58f9b1 Guido Trotter
      raise errors.HypervisorError("Failed to start instance %s: %s (%s)" %
429 eb58f9b1 Guido Trotter
                                   (instance.name, result.fail_reason,
430 eb58f9b1 Guido Trotter
                                    result.output))
431 eb58f9b1 Guido Trotter
432 eb58f9b1 Guido Trotter
    if not utils.IsProcessAlive(utils.ReadPidFile(pidfile)):
433 eb58f9b1 Guido Trotter
      raise errors.HypervisorError("Failed to start instance %s: %s" %
434 eb58f9b1 Guido Trotter
                                   (instance.name))
435 eb58f9b1 Guido Trotter
436 08137f9e Iustin Pop
    for filename in temp_files:
437 08137f9e Iustin Pop
      utils.RemoveFile(filename)
438 eb58f9b1 Guido Trotter
439 07813a9e Iustin Pop
  def StartInstance(self, instance, block_devices):
440 ee5f20b0 Guido Trotter
    """Start an instance.
441 ee5f20b0 Guido Trotter

442 ee5f20b0 Guido Trotter
    """
443 1f8b3a27 Guido Trotter
    pidfile, pid, alive = self._InstancePidAlive(instance.name)
444 1f8b3a27 Guido Trotter
    if alive:
445 ee5f20b0 Guido Trotter
      raise errors.HypervisorError("Failed to start instance %s: %s" %
446 ee5f20b0 Guido Trotter
                                   (instance.name, "already running"))
447 ee5f20b0 Guido Trotter
448 07813a9e Iustin Pop
    kvm_runtime = self._GenerateKVMRuntime(instance, block_devices)
449 38e250ba Guido Trotter
    self._SaveKVMRuntime(instance, kvm_runtime)
450 ee5f20b0 Guido Trotter
    self._ExecuteKVMRuntime(instance, kvm_runtime)
451 ee5f20b0 Guido Trotter
452 6567aff3 Guido Trotter
  def _CallMonitorCommand(self, instance_name, command):
453 6567aff3 Guido Trotter
    """Invoke a command on the instance monitor.
454 6567aff3 Guido Trotter

455 6567aff3 Guido Trotter
    """
456 6567aff3 Guido Trotter
    socat = ("echo %s | %s STDIO UNIX-CONNECT:%s" %
457 6567aff3 Guido Trotter
             (utils.ShellQuote(command),
458 6567aff3 Guido Trotter
              constants.SOCAT_PATH,
459 6567aff3 Guido Trotter
              utils.ShellQuote(self._InstanceMonitor(instance_name))))
460 6567aff3 Guido Trotter
    result = utils.RunCmd(socat)
461 6567aff3 Guido Trotter
    if result.failed:
462 6567aff3 Guido Trotter
      msg = ("Failed to send command '%s' to instance %s."
463 6567aff3 Guido Trotter
             " output: %s, error: %s, fail_reason: %s" %
464 9798fcae Guido Trotter
             (command, instance_name,
465 9798fcae Guido Trotter
              result.stdout, result.stderr, result.fail_reason))
466 6567aff3 Guido Trotter
      raise errors.HypervisorError(msg)
467 6567aff3 Guido Trotter
468 6567aff3 Guido Trotter
    return result
469 6567aff3 Guido Trotter
470 6567aff3 Guido Trotter
  def _RetryInstancePowerdown(self, instance, pid, timeout=30):
471 6567aff3 Guido Trotter
    """Wait for an instance  to power down.
472 6567aff3 Guido Trotter

473 6567aff3 Guido Trotter
    """
474 6567aff3 Guido Trotter
    # Wait up to $timeout seconds
475 6567aff3 Guido Trotter
    end = time.time() + timeout
476 6567aff3 Guido Trotter
    wait = 1
477 6567aff3 Guido Trotter
    while time.time() < end and utils.IsProcessAlive(pid):
478 6567aff3 Guido Trotter
      self._CallMonitorCommand(instance.name, 'system_powerdown')
479 6567aff3 Guido Trotter
      time.sleep(wait)
480 6567aff3 Guido Trotter
      # Make wait time longer for next try
481 6567aff3 Guido Trotter
      if wait < 5:
482 6567aff3 Guido Trotter
        wait *= 1.3
483 6567aff3 Guido Trotter
484 eb58f9b1 Guido Trotter
  def StopInstance(self, instance, force=False):
485 eb58f9b1 Guido Trotter
    """Stop an instance.
486 eb58f9b1 Guido Trotter

487 eb58f9b1 Guido Trotter
    """
488 1f8b3a27 Guido Trotter
    pidfile, pid, alive = self._InstancePidAlive(instance.name)
489 1f8b3a27 Guido Trotter
    if pid > 0 and alive:
490 6b5605e8 Iustin Pop
      if force or not instance.hvparams[constants.HV_ACPI]:
491 eb58f9b1 Guido Trotter
        utils.KillProcess(pid)
492 eb58f9b1 Guido Trotter
      else:
493 6567aff3 Guido Trotter
        self._RetryInstancePowerdown(instance, pid)
494 eb58f9b1 Guido Trotter
495 eb58f9b1 Guido Trotter
    if not utils.IsProcessAlive(pid):
496 1f8b3a27 Guido Trotter
      utils.RemoveFile(pidfile)
497 c4fbefc8 Guido Trotter
      utils.RemoveFile(self._InstanceMonitor(instance.name))
498 c4fbefc8 Guido Trotter
      utils.RemoveFile(self._InstanceSerial(instance.name))
499 38e250ba Guido Trotter
      utils.RemoveFile(self._InstanceKVMRuntime(instance.name))
500 6567aff3 Guido Trotter
      return True
501 6567aff3 Guido Trotter
    else:
502 6567aff3 Guido Trotter
      return False
503 eb58f9b1 Guido Trotter
504 eb58f9b1 Guido Trotter
  def RebootInstance(self, instance):
505 eb58f9b1 Guido Trotter
    """Reboot an instance.
506 eb58f9b1 Guido Trotter

507 eb58f9b1 Guido Trotter
    """
508 eb58f9b1 Guido Trotter
    # For some reason if we do a 'send-key ctrl-alt-delete' to the control
509 eb58f9b1 Guido Trotter
    # socket the instance will stop, but now power up again. So we'll resort
510 eb58f9b1 Guido Trotter
    # to shutdown and restart.
511 1f8b3a27 Guido Trotter
    pidfile, pid, alive = self._InstancePidAlive(instance.name)
512 1f8b3a27 Guido Trotter
    if not alive:
513 1f8b3a27 Guido Trotter
      raise errors.HypervisorError("Failed to reboot instance %s: not running" %
514 1f8b3a27 Guido Trotter
                                             (instance.name))
515 f02881e0 Guido Trotter
    # StopInstance will delete the saved KVM runtime so:
516 f02881e0 Guido Trotter
    # ...first load it...
517 f02881e0 Guido Trotter
    kvm_runtime = self._LoadKVMRuntime(instance)
518 f02881e0 Guido Trotter
    # ...now we can safely call StopInstance...
519 f02881e0 Guido Trotter
    if not self.StopInstance(instance):
520 f02881e0 Guido Trotter
      self.StopInstance(instance, force=True)
521 f02881e0 Guido Trotter
    # ...and finally we can save it again, and execute it...
522 f02881e0 Guido Trotter
    self._SaveKVMRuntime(instance, kvm_runtime)
523 f02881e0 Guido Trotter
    self._ExecuteKVMRuntime(instance, kvm_runtime)
524 eb58f9b1 Guido Trotter
525 30e42c4e Guido Trotter
  def MigrationInfo(self, instance):
526 30e42c4e Guido Trotter
    """Get instance information to perform a migration.
527 30e42c4e Guido Trotter

528 30e42c4e Guido Trotter
    @type instance: L{objects.Instance}
529 30e42c4e Guido Trotter
    @param instance: instance to be migrated
530 30e42c4e Guido Trotter
    @rtype: string
531 30e42c4e Guido Trotter
    @return: content of the KVM runtime file
532 30e42c4e Guido Trotter

533 30e42c4e Guido Trotter
    """
534 30e42c4e Guido Trotter
    return self._ReadKVMRuntime(instance.name)
535 30e42c4e Guido Trotter
536 30e42c4e Guido Trotter
  def AcceptInstance(self, instance, info, target):
537 30e42c4e Guido Trotter
    """Prepare to accept an instance.
538 30e42c4e Guido Trotter

539 30e42c4e Guido Trotter
    @type instance: L{objects.Instance}
540 30e42c4e Guido Trotter
    @param instance: instance to be accepted
541 30e42c4e Guido Trotter
    @type info: string
542 30e42c4e Guido Trotter
    @param info: content of the KVM runtime file on the source node
543 30e42c4e Guido Trotter
    @type target: string
544 30e42c4e Guido Trotter
    @param target: target host (usually ip), on this node
545 30e42c4e Guido Trotter

546 30e42c4e Guido Trotter
    """
547 30e42c4e Guido Trotter
    kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info)
548 30e42c4e Guido Trotter
    incoming_address = (target, constants.KVM_MIGRATION_PORT)
549 30e42c4e Guido Trotter
    self._ExecuteKVMRuntime(instance, kvm_runtime, incoming=incoming_address)
550 30e42c4e Guido Trotter
551 30e42c4e Guido Trotter
  def FinalizeMigration(self, instance, info, success):
552 30e42c4e Guido Trotter
    """Finalize an instance migration.
553 30e42c4e Guido Trotter

554 30e42c4e Guido Trotter
    Stop the incoming mode KVM.
555 30e42c4e Guido Trotter

556 30e42c4e Guido Trotter
    @type instance: L{objects.Instance}
557 30e42c4e Guido Trotter
    @param instance: instance whose migration is being aborted
558 30e42c4e Guido Trotter

559 30e42c4e Guido Trotter
    """
560 30e42c4e Guido Trotter
    if success:
561 30e42c4e Guido Trotter
      self._WriteKVMRuntime(instance.name, info)
562 30e42c4e Guido Trotter
    else:
563 30e42c4e Guido Trotter
      self.StopInstance(instance, force=True)
564 30e42c4e Guido Trotter
565 30e42c4e Guido Trotter
  def MigrateInstance(self, instance_name, target, live):
566 30e42c4e Guido Trotter
    """Migrate an instance to a target node.
567 30e42c4e Guido Trotter

568 30e42c4e Guido Trotter
    The migration will not be attempted if the instance is not
569 30e42c4e Guido Trotter
    currently running.
570 30e42c4e Guido Trotter

571 30e42c4e Guido Trotter
    @type instance_name: string
572 30e42c4e Guido Trotter
    @param instance_name: name of the instance to be migrated
573 30e42c4e Guido Trotter
    @type target: string
574 30e42c4e Guido Trotter
    @param target: ip address of the target node
575 30e42c4e Guido Trotter
    @type live: boolean
576 30e42c4e Guido Trotter
    @param live: perform a live migration
577 30e42c4e Guido Trotter

578 30e42c4e Guido Trotter
    """
579 30e42c4e Guido Trotter
    pidfile, pid, alive = self._InstancePidAlive(instance_name)
580 30e42c4e Guido Trotter
    if not alive:
581 30e42c4e Guido Trotter
      raise errors.HypervisorError("Instance not running, cannot migrate")
582 30e42c4e Guido Trotter
583 30e42c4e Guido Trotter
    if not live:
584 30e42c4e Guido Trotter
      self._CallMonitorCommand(instance_name, 'stop')
585 30e42c4e Guido Trotter
586 30e42c4e Guido Trotter
    migrate_command = ('migrate -d tcp:%s:%s' %
587 30e42c4e Guido Trotter
                       (target, constants.KVM_MIGRATION_PORT))
588 30e42c4e Guido Trotter
    self._CallMonitorCommand(instance_name, migrate_command)
589 30e42c4e Guido Trotter
590 30e42c4e Guido Trotter
    info_command = 'info migrate'
591 30e42c4e Guido Trotter
    done = False
592 30e42c4e Guido Trotter
    while not done:
593 30e42c4e Guido Trotter
      result = self._CallMonitorCommand(instance_name, info_command)
594 30e42c4e Guido Trotter
      match = self._MIGRATION_STATUS_RE.search(result.stdout)
595 30e42c4e Guido Trotter
      if not match:
596 30e42c4e Guido Trotter
        raise errors.HypervisorError("Unknown 'info migrate' result: %s" %
597 30e42c4e Guido Trotter
                                     result.stdout)
598 30e42c4e Guido Trotter
      else:
599 30e42c4e Guido Trotter
        status = match.group(1)
600 30e42c4e Guido Trotter
        if status == 'completed':
601 30e42c4e Guido Trotter
          done = True
602 30e42c4e Guido Trotter
        elif status == 'active':
603 30e42c4e Guido Trotter
          time.sleep(2)
604 c087266c Guido Trotter
        elif status == 'failed' or status == 'cancelled':
605 c087266c Guido Trotter
          if not live:
606 c087266c Guido Trotter
            self._CallMonitorCommand(instance_name, 'cont')
607 c087266c Guido Trotter
          raise errors.HypervisorError("Migration %s at the kvm level" %
608 c087266c Guido Trotter
                                       status)
609 30e42c4e Guido Trotter
        else:
610 30e42c4e Guido Trotter
          logging.info("KVM: unknown migration status '%s'" % status)
611 30e42c4e Guido Trotter
          time.sleep(2)
612 30e42c4e Guido Trotter
613 30e42c4e Guido Trotter
    utils.KillProcess(pid)
614 30e42c4e Guido Trotter
    utils.RemoveFile(pidfile)
615 30e42c4e Guido Trotter
    utils.RemoveFile(self._InstanceMonitor(instance_name))
616 30e42c4e Guido Trotter
    utils.RemoveFile(self._InstanceSerial(instance_name))
617 30e42c4e Guido Trotter
    utils.RemoveFile(self._InstanceKVMRuntime(instance_name))
618 30e42c4e Guido Trotter
619 eb58f9b1 Guido Trotter
  def GetNodeInfo(self):
620 eb58f9b1 Guido Trotter
    """Return information about the node.
621 eb58f9b1 Guido Trotter

622 c41eea6e Iustin Pop
    @return: a dict with the following keys (values in MiB):
623 c41eea6e Iustin Pop
          - memory_total: the total memory size on the node
624 c41eea6e Iustin Pop
          - memory_free: the available memory on the node for instances
625 c41eea6e Iustin Pop
          - memory_dom0: the memory used by the node itself, if available
626 eb58f9b1 Guido Trotter

627 eb58f9b1 Guido Trotter
    """
628 eb58f9b1 Guido Trotter
    # global ram usage from the xm info command
629 eb58f9b1 Guido Trotter
    # memory                 : 3583
630 eb58f9b1 Guido Trotter
    # free_memory            : 747
631 eb58f9b1 Guido Trotter
    # note: in xen 3, memory has changed to total_memory
632 eb58f9b1 Guido Trotter
    try:
633 eb58f9b1 Guido Trotter
      fh = file("/proc/meminfo")
634 eb58f9b1 Guido Trotter
      try:
635 eb58f9b1 Guido Trotter
        data = fh.readlines()
636 eb58f9b1 Guido Trotter
      finally:
637 eb58f9b1 Guido Trotter
        fh.close()
638 90c024f6 Guido Trotter
    except EnvironmentError, err:
639 eb58f9b1 Guido Trotter
      raise errors.HypervisorError("Failed to list node info: %s" % err)
640 eb58f9b1 Guido Trotter
641 eb58f9b1 Guido Trotter
    result = {}
642 eb58f9b1 Guido Trotter
    sum_free = 0
643 eb58f9b1 Guido Trotter
    for line in data:
644 eb58f9b1 Guido Trotter
      splitfields = line.split(":", 1)
645 eb58f9b1 Guido Trotter
646 eb58f9b1 Guido Trotter
      if len(splitfields) > 1:
647 eb58f9b1 Guido Trotter
        key = splitfields[0].strip()
648 eb58f9b1 Guido Trotter
        val = splitfields[1].strip()
649 eb58f9b1 Guido Trotter
        if key == 'MemTotal':
650 eb58f9b1 Guido Trotter
          result['memory_total'] = int(val.split()[0])/1024
651 eb58f9b1 Guido Trotter
        elif key in ('MemFree', 'Buffers', 'Cached'):
652 eb58f9b1 Guido Trotter
          sum_free += int(val.split()[0])/1024
653 eb58f9b1 Guido Trotter
        elif key == 'Active':
654 eb58f9b1 Guido Trotter
          result['memory_dom0'] = int(val.split()[0])/1024
655 eb58f9b1 Guido Trotter
    result['memory_free'] = sum_free
656 eb58f9b1 Guido Trotter
657 eb58f9b1 Guido Trotter
    cpu_total = 0
658 eb58f9b1 Guido Trotter
    try:
659 eb58f9b1 Guido Trotter
      fh = open("/proc/cpuinfo")
660 eb58f9b1 Guido Trotter
      try:
661 eb58f9b1 Guido Trotter
        cpu_total = len(re.findall("(?m)^processor\s*:\s*[0-9]+\s*$",
662 eb58f9b1 Guido Trotter
                                   fh.read()))
663 eb58f9b1 Guido Trotter
      finally:
664 eb58f9b1 Guido Trotter
        fh.close()
665 eb58f9b1 Guido Trotter
    except EnvironmentError, err:
666 eb58f9b1 Guido Trotter
      raise errors.HypervisorError("Failed to list node info: %s" % err)
667 eb58f9b1 Guido Trotter
    result['cpu_total'] = cpu_total
668 0105bad3 Iustin Pop
    # FIXME: export correct data here
669 0105bad3 Iustin Pop
    result['cpu_nodes'] = 1
670 0105bad3 Iustin Pop
    result['cpu_sockets'] = 1
671 eb58f9b1 Guido Trotter
672 eb58f9b1 Guido Trotter
    return result
673 eb58f9b1 Guido Trotter
674 637ce7f9 Guido Trotter
  @classmethod
675 5431b2e4 Guido Trotter
  def GetShellCommandForConsole(cls, instance, hvparams, beparams):
676 eb58f9b1 Guido Trotter
    """Return a command for connecting to the console of an instance.
677 eb58f9b1 Guido Trotter

678 eb58f9b1 Guido Trotter
    """
679 a2faf9ee Guido Trotter
    if hvparams[constants.HV_SERIAL_CONSOLE]:
680 a2faf9ee Guido Trotter
      # FIXME: The socat shell is not perfect. In particular the way we start
681 a2faf9ee Guido Trotter
      # it ctrl+c will close it, rather than being passed to the other end.
682 a2faf9ee Guido Trotter
      # On the other hand if we pass the option 'raw' (or ignbrk=1) there
683 a2faf9ee Guido Trotter
      # will be no way of exiting socat (except killing it from another shell)
684 a2faf9ee Guido Trotter
      # and ctrl+c doesn't work anyway, printing ^C rather than being
685 a2faf9ee Guido Trotter
      # interpreted by kvm. For now we'll leave it this way, which at least
686 a2faf9ee Guido Trotter
      # allows a minimal interaction and changes on the machine.
687 a2faf9ee Guido Trotter
      shell_command = ("%s STDIO,echo=0,icanon=0 UNIX-CONNECT:%s" %
688 a2faf9ee Guido Trotter
                       (constants.SOCAT_PATH,
689 a2faf9ee Guido Trotter
                        utils.ShellQuote(cls._InstanceSerial(instance.name))))
690 a2faf9ee Guido Trotter
    else:
691 a2faf9ee Guido Trotter
      shell_command = "echo 'No serial shell for instance %s'" % instance.name
692 3be34f57 Guido Trotter
693 3be34f57 Guido Trotter
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
694 3be34f57 Guido Trotter
    if vnc_bind_address:
695 377d74c9 Guido Trotter
      if instance.network_port > constants.VNC_BASE_PORT:
696 377d74c9 Guido Trotter
        display = instance.network_port - constants.VNC_BASE_PORT
697 3be34f57 Guido Trotter
        vnc_command = ("echo 'Instance has VNC listening on %s:%d"
698 3be34f57 Guido Trotter
                       " (display: %d)'" % (vnc_bind_address,
699 3be34f57 Guido Trotter
                                            instance.network_port,
700 3be34f57 Guido Trotter
                                            display))
701 3be34f57 Guido Trotter
        shell_command = "%s; %s" % (vnc_command, shell_command)
702 3be34f57 Guido Trotter
703 a2faf9ee Guido Trotter
    return shell_command
704 eb58f9b1 Guido Trotter
705 eb58f9b1 Guido Trotter
  def Verify(self):
706 eb58f9b1 Guido Trotter
    """Verify the hypervisor.
707 eb58f9b1 Guido Trotter

708 eb58f9b1 Guido Trotter
    Check that the binary exists.
709 eb58f9b1 Guido Trotter

710 eb58f9b1 Guido Trotter
    """
711 eb58f9b1 Guido Trotter
    if not os.path.exists(constants.KVM_PATH):
712 eb58f9b1 Guido Trotter
      return "The kvm binary ('%s') does not exist." % constants.KVM_PATH
713 14aa53cb Guido Trotter
    if not os.path.exists(constants.SOCAT_PATH):
714 14aa53cb Guido Trotter
      return "The socat binary ('%s') does not exist." % constants.SOCAT_PATH
715 14aa53cb Guido Trotter
716 6b5605e8 Iustin Pop
717 6b5605e8 Iustin Pop
  @classmethod
718 6b5605e8 Iustin Pop
  def CheckParameterSyntax(cls, hvparams):
719 6b5605e8 Iustin Pop
    """Check the given parameters for validity.
720 6b5605e8 Iustin Pop

721 6b5605e8 Iustin Pop
    @type hvparams:  dict
722 6b5605e8 Iustin Pop
    @param hvparams: dictionary with parameter names/value
723 6b5605e8 Iustin Pop
    @raise errors.HypervisorError: when a parameter is not valid
724 6b5605e8 Iustin Pop

725 6b5605e8 Iustin Pop
    """
726 47387b1e Guido Trotter
    super(KVMHypervisor, cls).CheckParameterSyntax(hvparams)
727 6b5605e8 Iustin Pop
728 df5ab9f0 Guido Trotter
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
729 df5ab9f0 Guido Trotter
    if kernel_path:
730 df5ab9f0 Guido Trotter
      if not os.path.isabs(hvparams[constants.HV_KERNEL_PATH]):
731 df5ab9f0 Guido Trotter
        raise errors.HypervisorError("The kernel path must be an absolute path"
732 df5ab9f0 Guido Trotter
                                     ", if defined")
733 6b5605e8 Iustin Pop
734 df5ab9f0 Guido Trotter
      if not hvparams[constants.HV_ROOT_PATH]:
735 df5ab9f0 Guido Trotter
        raise errors.HypervisorError("Need a root partition for the instance"
736 df5ab9f0 Guido Trotter
                                     ", if a kernel is defined")
737 074ca009 Guido Trotter
738 6b5605e8 Iustin Pop
    if hvparams[constants.HV_INITRD_PATH]:
739 6b5605e8 Iustin Pop
      if not os.path.isabs(hvparams[constants.HV_INITRD_PATH]):
740 df5ab9f0 Guido Trotter
        raise errors.HypervisorError("The initrd path must an absolute path"
741 6b5605e8 Iustin Pop
                                     ", if defined")
742 6b5605e8 Iustin Pop
743 56fee73b Guido Trotter
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
744 56fee73b Guido Trotter
    if vnc_bind_address:
745 56fee73b Guido Trotter
      if not utils.IsValidIP(vnc_bind_address):
746 8447f52b Guido Trotter
        if not os.path.isabs(vnc_bind_address):
747 8447f52b Guido Trotter
          raise errors.HypervisorError("The VNC bind address must be either"
748 8447f52b Guido Trotter
                                       " a valid IP address or an absolute"
749 8447f52b Guido Trotter
                                       " pathname. '%s' given" %
750 8447f52b Guido Trotter
                                       vnc_bind_address)
751 56fee73b Guido Trotter
752 8b2d1013 Guido Trotter
    if hvparams[constants.HV_VNC_X509_VERIFY] and \
753 8b2d1013 Guido Trotter
      not hvparams[constants.HV_VNC_X509]:
754 8b2d1013 Guido Trotter
        raise errors.HypervisorError("%s must be defined, if %s is" %
755 8b2d1013 Guido Trotter
                                     (constants.HV_VNC_X509,
756 8b2d1013 Guido Trotter
                                      constants.HV_VNC_X509_VERIFY))
757 8b2d1013 Guido Trotter
758 8b2d1013 Guido Trotter
    if hvparams[constants.HV_VNC_X509]:
759 8b2d1013 Guido Trotter
      if not os.path.isabs(hvparams[constants.HV_VNC_X509]):
760 8b2d1013 Guido Trotter
        raise errors.HypervisorError("The vnc x509 path must an absolute path"
761 8b2d1013 Guido Trotter
                                     ", if defined")
762 8b2d1013 Guido Trotter
763 66d5dbef Guido Trotter
    iso_path = hvparams[constants.HV_CDROM_IMAGE_PATH]
764 66d5dbef Guido Trotter
    if iso_path and not os.path.isabs(iso_path):
765 66d5dbef Guido Trotter
      raise errors.HypervisorError("The path to the CDROM image must be"
766 66d5dbef Guido Trotter
                                   " an absolute path, if defined")
767 66d5dbef Guido Trotter
768 66d5dbef Guido Trotter
    boot_order = hvparams[constants.HV_BOOT_ORDER]
769 8745c3d7 Guido Trotter
    if boot_order not in ('cdrom', 'disk', 'network'):
770 8745c3d7 Guido Trotter
      raise errors.HypervisorError("The boot order must be 'cdrom', 'disk' or"
771 8745c3d7 Guido Trotter
                                   " 'network'")
772 66d5dbef Guido Trotter
773 ec91c05d Guido Trotter
    if boot_order == 'cdrom' and not iso_path:
774 ec91c05d Guido Trotter
      raise errors.HypervisorError("Cannot boot from cdrom without an ISO path")
775 ec91c05d Guido Trotter
776 43440815 Guido Trotter
    nic_type = hvparams[constants.HV_NIC_TYPE]
777 43440815 Guido Trotter
    if nic_type not in constants.HT_KVM_VALID_NIC_TYPES:
778 43440815 Guido Trotter
      raise errors.HypervisorError("Invalid NIC type %s specified for the KVM"
779 43440815 Guido Trotter
                                   " hypervisor. Please choose one of: %s" %
780 43440815 Guido Trotter
                                   (nic_type,
781 43440815 Guido Trotter
                                    constants.HT_KVM_VALID_NIC_TYPES))
782 8745c3d7 Guido Trotter
    elif boot_order == 'network' and nic_type == constants.HT_NIC_PARAVIRTUAL:
783 8745c3d7 Guido Trotter
      raise errors.HypervisorError("Cannot boot from a paravirtual NIC. Please"
784 8745c3d7 Guido Trotter
                                   " change the nic type.")
785 43440815 Guido Trotter
786 43440815 Guido Trotter
    disk_type = hvparams[constants.HV_DISK_TYPE]
787 43440815 Guido Trotter
    if disk_type not in constants.HT_KVM_VALID_DISK_TYPES:
788 43440815 Guido Trotter
      raise errors.HypervisorError("Invalid disk type %s specified for the KVM"
789 43440815 Guido Trotter
                                   " hypervisor. Please choose one of: %s" %
790 43440815 Guido Trotter
                                   (disk_type,
791 43440815 Guido Trotter
                                    constants.HT_KVM_VALID_DISK_TYPES))
792 43440815 Guido Trotter
793 11344a50 Guido Trotter
    mouse_type = hvparams[constants.HV_USB_MOUSE]
794 11344a50 Guido Trotter
    if mouse_type and mouse_type not in ('mouse', 'tablet'):
795 11344a50 Guido Trotter
      raise errors.HypervisorError("Invalid usb mouse type %s specified for"
796 11344a50 Guido Trotter
                                   " the KVM hyervisor. Please choose"
797 11344a50 Guido Trotter
                                   " 'mouse' or 'tablet'" % mouse_type)
798 11344a50 Guido Trotter
799 6b5605e8 Iustin Pop
  def ValidateParameters(self, hvparams):
800 6b5605e8 Iustin Pop
    """Check the given parameters for validity.
801 6b5605e8 Iustin Pop

802 6b5605e8 Iustin Pop
    For the KVM hypervisor, this checks the existence of the
803 6b5605e8 Iustin Pop
    kernel.
804 6b5605e8 Iustin Pop

805 6b5605e8 Iustin Pop
    """
806 47387b1e Guido Trotter
    super(KVMHypervisor, self).ValidateParameters(hvparams)
807 6b5605e8 Iustin Pop
808 6b5605e8 Iustin Pop
    kernel_path = hvparams[constants.HV_KERNEL_PATH]
809 df5ab9f0 Guido Trotter
    if kernel_path and not os.path.isfile(kernel_path):
810 6b5605e8 Iustin Pop
      raise errors.HypervisorError("Instance kernel '%s' not found or"
811 6b5605e8 Iustin Pop
                                   " not a file" % kernel_path)
812 6b5605e8 Iustin Pop
    initrd_path = hvparams[constants.HV_INITRD_PATH]
813 6b5605e8 Iustin Pop
    if initrd_path and not os.path.isfile(initrd_path):
814 6b5605e8 Iustin Pop
      raise errors.HypervisorError("Instance initrd '%s' not found or"
815 6b5605e8 Iustin Pop
                                   " not a file" % initrd_path)
816 8b2d1013 Guido Trotter
817 8b2d1013 Guido Trotter
    vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS]
818 8b2d1013 Guido Trotter
    if vnc_bind_address and not utils.IsValidIP(vnc_bind_address) and \
819 8b2d1013 Guido Trotter
       not os.path.isdir(vnc_bind_address):
820 8b2d1013 Guido Trotter
       raise errors.HypervisorError("Instance vnc bind address must be either"
821 8b2d1013 Guido Trotter
                                    " an ip address or an existing directory")
822 8b2d1013 Guido Trotter
823 8b2d1013 Guido Trotter
    vnc_x509 = hvparams[constants.HV_VNC_X509]
824 8b2d1013 Guido Trotter
    if vnc_x509 and not os.path.isdir(vnc_x509):
825 8b2d1013 Guido Trotter
      raise errors.HypervisorError("Instance vnc x509 path '%s' not found"
826 8b2d1013 Guido Trotter
                                   " or not a directory" % vnc_x509)
827 8b2d1013 Guido Trotter
828 66d5dbef Guido Trotter
    iso_path = hvparams[constants.HV_CDROM_IMAGE_PATH]
829 66d5dbef Guido Trotter
    if iso_path and not os.path.isfile(iso_path):
830 66d5dbef Guido Trotter
      raise errors.HypervisorError("Instance cdrom image '%s' not found or"
831 66d5dbef Guido Trotter
                                   " not a file" % iso_path)