Package ganeti :: Package hypervisor :: Package hv_kvm
[hide private]
[frames] | no frames]

Source Code for Package ganeti.hypervisor.hv_kvm

   1  # 
   2  # 
   3   
   4  # Copyright (C) 2008, 2009, 2010, 2011, 2012, 2013, 2014 Google Inc. 
   5  # All rights reserved. 
   6  # 
   7  # Redistribution and use in source and binary forms, with or without 
   8  # modification, are permitted provided that the following conditions are 
   9  # met: 
  10  # 
  11  # 1. Redistributions of source code must retain the above copyright notice, 
  12  # this list of conditions and the following disclaimer. 
  13  # 
  14  # 2. Redistributions in binary form must reproduce the above copyright 
  15  # notice, this list of conditions and the following disclaimer in the 
  16  # documentation and/or other materials provided with the distribution. 
  17  # 
  18  # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 
  19  # IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 
  20  # TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 
  21  # PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
  22  # CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 
  23  # EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
  24  # PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 
  25  # PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 
  26  # LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
  27  # NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
  28  # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
  29   
  30   
  31  """KVM hypervisor 
  32   
  33  """ 
  34   
  35  import errno 
  36  import os 
  37  import os.path 
  38  import re 
  39  import tempfile 
  40  import time 
  41  import logging 
  42  import pwd 
  43  import shutil 
  44  import urllib2 
  45  from bitarray import bitarray 
  46  try: 
  47    import psutil   # pylint: disable=F0401 
  48  except ImportError: 
  49    psutil = None 
  50  try: 
  51    import fdsend   # pylint: disable=F0401 
  52  except ImportError: 
  53    fdsend = None 
  54   
  55  from ganeti import utils 
  56  from ganeti import constants 
  57  from ganeti import errors 
  58  from ganeti import serializer 
  59  from ganeti import objects 
  60  from ganeti import uidpool 
  61  from ganeti import ssconf 
  62  from ganeti import netutils 
  63  from ganeti import pathutils 
  64  from ganeti.hypervisor import hv_base 
  65  from ganeti.utils import wrapper as utils_wrapper 
  66   
  67  from ganeti.hypervisor.hv_kvm.monitor import QmpConnection, QmpMessage, \ 
  68                                               MonitorSocket 
  69  from ganeti.hypervisor.hv_kvm.netdev import OpenTap 
  70   
  71   
  72  _KVM_NETWORK_SCRIPT = pathutils.CONF_DIR + "/kvm-vif-bridge" 
  73  _KVM_START_PAUSED_FLAG = "-S" 
  74   
  75  #: SPICE parameters which depend on L{constants.HV_KVM_SPICE_BIND} 
  76  _SPICE_ADDITIONAL_PARAMS = frozenset([ 
  77    constants.HV_KVM_SPICE_IP_VERSION, 
  78    constants.HV_KVM_SPICE_PASSWORD_FILE, 
  79    constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR, 
  80    constants.HV_KVM_SPICE_JPEG_IMG_COMPR, 
  81    constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR, 
  82    constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION, 
  83    constants.HV_KVM_SPICE_USE_TLS, 
  84    ]) 
  85   
  86  # Constant bitarray that reflects to a free pci slot 
  87  # Use it with bitarray.search() 
  88  _AVAILABLE_PCI_SLOT = bitarray("0") 
  89   
  90  # below constants show the format of runtime file 
  91  # the nics are in second possition, while the disks in 4th (last) 
  92  # moreover disk entries are stored as a list of in tuples 
  93  # (L{objects.Disk}, link_name, uri) 
  94  _KVM_NICS_RUNTIME_INDEX = 1 
  95  _KVM_DISKS_RUNTIME_INDEX = 3 
  96  _DEVICE_RUNTIME_INDEX = { 
  97    constants.HOTPLUG_TARGET_DISK: _KVM_DISKS_RUNTIME_INDEX, 
  98    constants.HOTPLUG_TARGET_NIC: _KVM_NICS_RUNTIME_INDEX 
  99    } 
 100  _FIND_RUNTIME_ENTRY = { 
 101    constants.HOTPLUG_TARGET_NIC: 
 102      lambda nic, kvm_nics: [n for n in kvm_nics if n.uuid == nic.uuid], 
 103    constants.HOTPLUG_TARGET_DISK: 
 104      lambda disk, kvm_disks: [(d, l, u) for (d, l, u) in kvm_disks 
 105                               if d.uuid == disk.uuid] 
 106    } 
 107  _RUNTIME_DEVICE = { 
 108    constants.HOTPLUG_TARGET_NIC: lambda d: d, 
 109    constants.HOTPLUG_TARGET_DISK: lambda (d, e, _): d 
 110    } 
 111  _RUNTIME_ENTRY = { 
 112    constants.HOTPLUG_TARGET_NIC: lambda d, e: d, 
 113    constants.HOTPLUG_TARGET_DISK: lambda d, e: (d, e[0], e[1]) 
 114    } 
 115   
 116  _MIGRATION_CAPS_DELIM = ":" 
117 118 119 -def _GetDriveURI(disk, link, uri):
120 """Helper function to get the drive uri to be used in --drive kvm option 121 122 @type disk: L{objects.Disk} 123 @param disk: A disk configuration object 124 @type link: string 125 @param link: The device link as returned by _SymlinkBlockDev() 126 @type uri: string 127 @param uri: The drive uri as returned by _CalculateDeviceURI() 128 129 """ 130 access_mode = disk.params.get(constants.LDP_ACCESS, 131 constants.DISK_KERNELSPACE) 132 if (uri and access_mode == constants.DISK_USERSPACE): 133 drive_uri = uri 134 else: 135 drive_uri = link 136 137 return drive_uri
138
139 140 -def _GenerateDeviceKVMId(dev_type, dev):
141 """Helper function to generate a unique device name used by KVM 142 143 QEMU monitor commands use names to identify devices. Here we use their pci 144 slot and a part of their UUID to name them. dev.pci might be None for old 145 devices in the cluster. 146 147 @type dev_type: sting 148 @param dev_type: device type of param dev 149 @type dev: L{objects.Disk} or L{objects.NIC} 150 @param dev: the device object for which we generate a kvm name 151 @raise errors.HotplugError: in case a device has no pci slot (old devices) 152 153 """ 154 155 if not dev.pci: 156 raise errors.HotplugError("Hotplug is not supported for %s with UUID %s" % 157 (dev_type, dev.uuid)) 158 159 return "%s-%s-pci-%d" % (dev_type.lower(), dev.uuid.split("-")[0], dev.pci)
160
161 162 -def _GetFreeSlot(slots, slot=None, reserve=False):
163 """Helper method to get first available slot in a bitarray 164 165 @type slots: bitarray 166 @param slots: the bitarray to operate on 167 @type slot: integer 168 @param slot: if given we check whether the slot is free 169 @type reserve: boolean 170 @param reserve: whether to reserve the first available slot or not 171 @return: the idx of the (first) available slot 172 @raise errors.HotplugError: If all slots in a bitarray are occupied 173 or the given slot is not free. 174 175 """ 176 if slot is not None: 177 assert slot < len(slots) 178 if slots[slot]: 179 raise errors.HypervisorError("Slots %d occupied" % slot) 180 181 else: 182 avail = slots.search(_AVAILABLE_PCI_SLOT, 1) 183 if not avail: 184 raise errors.HypervisorError("All slots occupied") 185 186 slot = int(avail[0]) 187 188 if reserve: 189 slots[slot] = True 190 191 return slot
192
193 194 -def _GetExistingDeviceInfo(dev_type, device, runtime):
195 """Helper function to get an existing device inside the runtime file 196 197 Used when an instance is running. Load kvm runtime file and search 198 for a device based on its type and uuid. 199 200 @type dev_type: sting 201 @param dev_type: device type of param dev 202 @type device: L{objects.Disk} or L{objects.NIC} 203 @param device: the device object for which we generate a kvm name 204 @type runtime: tuple (cmd, nics, hvparams, disks) 205 @param runtime: the runtime data to search for the device 206 @raise errors.HotplugError: in case the requested device does not 207 exist (e.g. device has been added without --hotplug option) or 208 device info has not pci slot (e.g. old devices in the cluster) 209 210 """ 211 index = _DEVICE_RUNTIME_INDEX[dev_type] 212 found = _FIND_RUNTIME_ENTRY[dev_type](device, runtime[index]) 213 if not found: 214 raise errors.HotplugError("Cannot find runtime info for %s with UUID %s" % 215 (dev_type, device.uuid)) 216 217 return found[0]
218
219 220 -def _UpgradeSerializedRuntime(serialized_runtime):
221 """Upgrade runtime data 222 223 Remove any deprecated fields or change the format of the data. 224 The runtime files are not upgraded when Ganeti is upgraded, so the required 225 modification have to be performed here. 226 227 @type serialized_runtime: string 228 @param serialized_runtime: raw text data read from actual runtime file 229 @return: (cmd, nic dicts, hvparams, bdev dicts) 230 @rtype: tuple 231 232 """ 233 loaded_runtime = serializer.Load(serialized_runtime) 234 kvm_cmd, serialized_nics, hvparams = loaded_runtime[:3] 235 if len(loaded_runtime) >= 4: 236 serialized_disks = loaded_runtime[3] 237 else: 238 serialized_disks = [] 239 240 for nic in serialized_nics: 241 # Add a dummy uuid slot if an pre-2.8 NIC is found 242 if "uuid" not in nic: 243 nic["uuid"] = utils.NewUUID() 244 245 return kvm_cmd, serialized_nics, hvparams, serialized_disks
246
247 248 -def _AnalyzeSerializedRuntime(serialized_runtime):
249 """Return runtime entries for a serialized runtime file 250 251 @type serialized_runtime: string 252 @param serialized_runtime: raw text data read from actual runtime file 253 @return: (cmd, nics, hvparams, bdevs) 254 @rtype: tuple 255 256 """ 257 kvm_cmd, serialized_nics, hvparams, serialized_disks = \ 258 _UpgradeSerializedRuntime(serialized_runtime) 259 kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics] 260 kvm_disks = [(objects.Disk.FromDict(sdisk), link, uri) 261 for sdisk, link, uri in serialized_disks] 262 263 return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
264
265 266 -class HeadRequest(urllib2.Request):
267 - def get_method(self):
268 return "HEAD"
269
270 271 -def _CheckUrl(url):
272 """Check if a given URL exists on the server 273 274 """ 275 try: 276 urllib2.urlopen(HeadRequest(url)) 277 return True 278 except urllib2.URLError: 279 return False
280
281 282 -class KVMHypervisor(hv_base.BaseHypervisor):
283 """KVM hypervisor interface 284 285 """ 286 CAN_MIGRATE = True 287 288 _ROOT_DIR = pathutils.RUN_DIR + "/kvm-hypervisor" 289 _PIDS_DIR = _ROOT_DIR + "/pid" # contains live instances pids 290 _UIDS_DIR = _ROOT_DIR + "/uid" # contains instances reserved uids 291 _CTRL_DIR = _ROOT_DIR + "/ctrl" # contains instances control sockets 292 _CONF_DIR = _ROOT_DIR + "/conf" # contains instances startup data 293 _NICS_DIR = _ROOT_DIR + "/nic" # contains instances nic <-> tap associations 294 _KEYMAP_DIR = _ROOT_DIR + "/keymap" # contains instances keymaps 295 # KVM instances with chroot enabled are started in empty chroot directories. 296 _CHROOT_DIR = _ROOT_DIR + "/chroot" # for empty chroot directories 297 # After an instance is stopped, its chroot directory is removed. 298 # If the chroot directory is not empty, it can't be removed. 299 # A non-empty chroot directory indicates a possible security incident. 300 # To support forensics, the non-empty chroot directory is quarantined in 301 # a separate directory, called 'chroot-quarantine'. 302 _CHROOT_QUARANTINE_DIR = _ROOT_DIR + "/chroot-quarantine" 303 _DIRS = [_ROOT_DIR, _PIDS_DIR, _UIDS_DIR, _CTRL_DIR, _CONF_DIR, _NICS_DIR, 304 _CHROOT_DIR, _CHROOT_QUARANTINE_DIR, _KEYMAP_DIR] 305 306 PARAMETERS = { 307 constants.HV_KVM_PATH: hv_base.REQ_FILE_CHECK, 308 constants.HV_KERNEL_PATH: hv_base.OPT_FILE_CHECK, 309 constants.HV_INITRD_PATH: hv_base.OPT_FILE_CHECK, 310 constants.HV_ROOT_PATH: hv_base.NO_CHECK, 311 constants.HV_KERNEL_ARGS: hv_base.NO_CHECK, 312 constants.HV_ACPI: hv_base.NO_CHECK, 313 constants.HV_SERIAL_CONSOLE: hv_base.NO_CHECK, 314 constants.HV_SERIAL_SPEED: hv_base.NO_CHECK, 315 constants.HV_VNC_BIND_ADDRESS: hv_base.NO_CHECK, # will be checked later 316 constants.HV_VNC_TLS: hv_base.NO_CHECK, 317 constants.HV_VNC_X509: hv_base.OPT_DIR_CHECK, 318 constants.HV_VNC_X509_VERIFY: hv_base.NO_CHECK, 319 constants.HV_VNC_PASSWORD_FILE: hv_base.OPT_FILE_CHECK, 320 constants.HV_KVM_SPICE_BIND: hv_base.NO_CHECK, # will be checked later 321 constants.HV_KVM_SPICE_IP_VERSION: 322 (False, lambda x: (x == constants.IFACE_NO_IP_VERSION_SPECIFIED or 323 x in constants.VALID_IP_VERSIONS), 324 "The SPICE IP version should be 4 or 6", 325 None, None), 326 constants.HV_KVM_SPICE_PASSWORD_FILE: hv_base.OPT_FILE_CHECK, 327 constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR: 328 hv_base.ParamInSet( 329 False, constants.HT_KVM_SPICE_VALID_LOSSLESS_IMG_COMPR_OPTIONS), 330 constants.HV_KVM_SPICE_JPEG_IMG_COMPR: 331 hv_base.ParamInSet( 332 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS), 333 constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR: 334 hv_base.ParamInSet( 335 False, constants.HT_KVM_SPICE_VALID_LOSSY_IMG_COMPR_OPTIONS), 336 constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION: 337 hv_base.ParamInSet( 338 False, constants.HT_KVM_SPICE_VALID_VIDEO_STREAM_DETECTION_OPTIONS), 339 constants.HV_KVM_SPICE_AUDIO_COMPR: hv_base.NO_CHECK, 340 constants.HV_KVM_SPICE_USE_TLS: hv_base.NO_CHECK, 341 constants.HV_KVM_SPICE_TLS_CIPHERS: hv_base.NO_CHECK, 342 constants.HV_KVM_SPICE_USE_VDAGENT: hv_base.NO_CHECK, 343 constants.HV_KVM_FLOPPY_IMAGE_PATH: hv_base.OPT_FILE_CHECK, 344 constants.HV_CDROM_IMAGE_PATH: hv_base.OPT_FILE_OR_URL_CHECK, 345 constants.HV_KVM_CDROM2_IMAGE_PATH: hv_base.OPT_FILE_OR_URL_CHECK, 346 constants.HV_BOOT_ORDER: 347 hv_base.ParamInSet(True, constants.HT_KVM_VALID_BO_TYPES), 348 constants.HV_NIC_TYPE: 349 hv_base.ParamInSet(True, constants.HT_KVM_VALID_NIC_TYPES), 350 constants.HV_DISK_TYPE: 351 hv_base.ParamInSet(True, constants.HT_KVM_VALID_DISK_TYPES), 352 constants.HV_KVM_CDROM_DISK_TYPE: 353 hv_base.ParamInSet(False, constants.HT_KVM_VALID_DISK_TYPES), 354 constants.HV_USB_MOUSE: 355 hv_base.ParamInSet(False, constants.HT_KVM_VALID_MOUSE_TYPES), 356 constants.HV_KEYMAP: hv_base.NO_CHECK, 357 constants.HV_MIGRATION_PORT: hv_base.REQ_NET_PORT_CHECK, 358 constants.HV_MIGRATION_BANDWIDTH: hv_base.REQ_NONNEGATIVE_INT_CHECK, 359 constants.HV_MIGRATION_DOWNTIME: hv_base.REQ_NONNEGATIVE_INT_CHECK, 360 constants.HV_MIGRATION_MODE: hv_base.MIGRATION_MODE_CHECK, 361 constants.HV_USE_LOCALTIME: hv_base.NO_CHECK, 362 constants.HV_DISK_CACHE: 363 hv_base.ParamInSet(True, constants.HT_VALID_CACHE_TYPES), 364 constants.HV_KVM_DISK_AIO: 365 hv_base.ParamInSet(False, constants.HT_KVM_VALID_AIO_TYPES), 366 constants.HV_SECURITY_MODEL: 367 hv_base.ParamInSet(True, constants.HT_KVM_VALID_SM_TYPES), 368 constants.HV_SECURITY_DOMAIN: hv_base.NO_CHECK, 369 constants.HV_KVM_FLAG: 370 hv_base.ParamInSet(False, constants.HT_KVM_FLAG_VALUES), 371 constants.HV_VHOST_NET: hv_base.NO_CHECK, 372 constants.HV_VIRTIO_NET_QUEUES: hv_base.OPT_VIRTIO_NET_QUEUES_CHECK, 373 constants.HV_KVM_USE_CHROOT: hv_base.NO_CHECK, 374 constants.HV_KVM_USER_SHUTDOWN: hv_base.NO_CHECK, 375 constants.HV_MEM_PATH: hv_base.OPT_DIR_CHECK, 376 constants.HV_REBOOT_BEHAVIOR: 377 hv_base.ParamInSet(True, constants.REBOOT_BEHAVIORS), 378 constants.HV_CPU_MASK: hv_base.OPT_MULTI_CPU_MASK_CHECK, 379 constants.HV_CPU_TYPE: hv_base.NO_CHECK, 380 constants.HV_CPU_CORES: hv_base.OPT_NONNEGATIVE_INT_CHECK, 381 constants.HV_CPU_THREADS: hv_base.OPT_NONNEGATIVE_INT_CHECK, 382 constants.HV_CPU_SOCKETS: hv_base.OPT_NONNEGATIVE_INT_CHECK, 383 constants.HV_SOUNDHW: hv_base.NO_CHECK, 384 constants.HV_USB_DEVICES: hv_base.NO_CHECK, 385 constants.HV_VGA: hv_base.NO_CHECK, 386 constants.HV_KVM_EXTRA: hv_base.NO_CHECK, 387 constants.HV_KVM_MACHINE_VERSION: hv_base.NO_CHECK, 388 constants.HV_KVM_MIGRATION_CAPS: hv_base.NO_CHECK, 389 constants.HV_VNET_HDR: hv_base.NO_CHECK, 390 } 391 392 _VIRTIO = "virtio" 393 _VIRTIO_NET_PCI = "virtio-net-pci" 394 _VIRTIO_BLK_PCI = "virtio-blk-pci" 395 396 _MIGRATION_STATUS_RE = re.compile(r"Migration\s+status:\s+(\w+)", 397 re.M | re.I) 398 _MIGRATION_PROGRESS_RE = \ 399 re.compile(r"\s*transferred\s+ram:\s+(?P<transferred>\d+)\s+kbytes\s*\n" 400 r"\s*remaining\s+ram:\s+(?P<remaining>\d+)\s+kbytes\s*\n" 401 r"\s*total\s+ram:\s+(?P<total>\d+)\s+kbytes\s*\n", re.I) 402 403 _MIGRATION_INFO_MAX_BAD_ANSWERS = 5 404 _MIGRATION_INFO_RETRY_DELAY = 2 405 406 _VERSION_RE = re.compile(r"\b(\d+)\.(\d+)(\.(\d+))?\b") 407 408 _CPU_INFO_RE = re.compile(r"cpu\s+\#(\d+).*thread_id\s*=\s*(\d+)", re.I) 409 _CPU_INFO_CMD = "info cpus" 410 _CONT_CMD = "cont" 411 412 _DEFAULT_MACHINE_VERSION_RE = re.compile(r"^(\S+).*\(default\)", re.M) 413 _CHECK_MACHINE_VERSION_RE = \ 414 staticmethod(lambda x: re.compile(r"^(%s)[ ]+.*PC" % x, re.M)) 415 416 _QMP_RE = re.compile(r"^-qmp\s", re.M) 417 _SPICE_RE = re.compile(r"^-spice\s", re.M) 418 _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M) 419 _VIRTIO_NET_QUEUES_RE = re.compile(r"^-net\s.*,fds=x:y:...:z", re.M) 420 _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M) 421 _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M) 422 _NETDEV_RE = re.compile(r"^-netdev\s", re.M) 423 _DISPLAY_RE = re.compile(r"^-display\s", re.M) 424 _MACHINE_RE = re.compile(r"^-machine\s", re.M) 425 _VIRTIO_NET_RE = re.compile(r"^name \"%s\"" % _VIRTIO_NET_PCI, re.M) 426 _VIRTIO_BLK_RE = re.compile(r"^name \"%s\"" % _VIRTIO_BLK_PCI, re.M) 427 # match -drive.*boot=on|off on different lines, but in between accept only 428 # dashes not preceeded by a new line (which would mean another option 429 # different than -drive is starting) 430 _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S) 431 _UUID_RE = re.compile(r"^-uuid\s", re.M) 432 433 _INFO_PCI_RE = re.compile(r'Bus.*device[ ]*(\d+).*') 434 _INFO_PCI_CMD = "info pci" 435 _FIND_PCI_DEVICE_RE = \ 436 staticmethod( 437 lambda pci, devid: re.compile(r'Bus.*device[ ]*%d,(.*\n){5,6}.*id "%s"' % 438 (pci, devid), re.M)) 439 440 _INFO_VERSION_RE = \ 441 re.compile(r'^QEMU (\d+)\.(\d+)(\.(\d+))?.*monitor.*', re.M) 442 _INFO_VERSION_CMD = "info version" 443 444 # Slot 0 for Host bridge, Slot 1 for ISA bridge, Slot 2 for VGA controller 445 _DEFAULT_PCI_RESERVATIONS = "11100000000000000000000000000000" 446 _SOUNDHW_WITH_PCI_SLOT = ["ac97", "es1370", "hda"] 447 448 ANCILLARY_FILES = [ 449 _KVM_NETWORK_SCRIPT, 450 ] 451 ANCILLARY_FILES_OPT = [ 452 _KVM_NETWORK_SCRIPT, 453 ] 454 455 # Supported kvm options to get output from 456 _KVMOPT_HELP = "help" 457 _KVMOPT_MLIST = "mlist" 458 _KVMOPT_DEVICELIST = "devicelist" 459 460 # Command to execute to get the output from kvm, and whether to 461 # accept the output even on failure. 462 _KVMOPTS_CMDS = { 463 _KVMOPT_HELP: (["--help"], False), 464 _KVMOPT_MLIST: (["-M", "?"], False), 465 _KVMOPT_DEVICELIST: (["-device", "?"], True), 466 } 467
468 - def __init__(self):
469 hv_base.BaseHypervisor.__init__(self) 470 # Let's make sure the directories we need exist, even if the RUN_DIR lives 471 # in a tmpfs filesystem or has been otherwise wiped out. 472 dirs = [(dname, constants.RUN_DIRS_MODE) for dname in self._DIRS] 473 utils.EnsureDirs(dirs)
474 475 @classmethod
476 - def _InstancePidFile(cls, instance_name):
477 """Returns the instance pidfile. 478 479 """ 480 return utils.PathJoin(cls._PIDS_DIR, instance_name)
481 482 @classmethod
483 - def _InstanceUidFile(cls, instance_name):
484 """Returns the instance uidfile. 485 486 """ 487 return utils.PathJoin(cls._UIDS_DIR, instance_name)
488 489 @classmethod
490 - def _InstancePidInfo(cls, pid):
491 """Check pid file for instance information. 492 493 Check that a pid file is associated with an instance, and retrieve 494 information from its command line. 495 496 @type pid: string or int 497 @param pid: process id of the instance to check 498 @rtype: tuple 499 @return: (instance_name, memory, vcpus) 500 @raise errors.HypervisorError: when an instance cannot be found 501 502 """ 503 alive = utils.IsProcessAlive(pid) 504 if not alive: 505 raise errors.HypervisorError("Cannot get info for pid %s" % pid) 506 507 cmdline_file = utils.PathJoin("/proc", str(pid), "cmdline") 508 try: 509 cmdline = utils.ReadFile(cmdline_file) 510 except EnvironmentError, err: 511 raise errors.HypervisorError("Can't open cmdline file for pid %s: %s" % 512 (pid, err)) 513 514 instance = None 515 memory = 0 516 vcpus = 0 517 518 arg_list = cmdline.split("\x00") 519 while arg_list: 520 arg = arg_list.pop(0) 521 if arg == "-name": 522 instance = arg_list.pop(0) 523 elif arg == "-m": 524 memory = int(arg_list.pop(0)) 525 elif arg == "-smp": 526 vcpus = int(arg_list.pop(0).split(",")[0]) 527 528 if instance is None: 529 raise errors.HypervisorError("Pid %s doesn't contain a ganeti kvm" 530 " instance" % pid) 531 532 return (instance, memory, vcpus)
533 534 @classmethod
535 - def _InstancePidAlive(cls, instance_name):
536 """Returns the instance pidfile, pid, and liveness. 537 538 @type instance_name: string 539 @param instance_name: instance name 540 @rtype: tuple 541 @return: (pid file name, pid, liveness) 542 543 """ 544 pidfile = cls._InstancePidFile(instance_name) 545 pid = utils.ReadPidFile(pidfile) 546 547 alive = False 548 try: 549 cmd_instance = cls._InstancePidInfo(pid)[0] 550 alive = (cmd_instance == instance_name) 551 except errors.HypervisorError: 552 pass 553 554 return (pidfile, pid, alive)
555 556 @classmethod
557 - def _CheckDown(cls, instance_name):
558 """Raises an error unless the given instance is down. 559 560 """ 561 alive = cls._InstancePidAlive(instance_name)[2] 562 if alive: 563 raise errors.HypervisorError("Failed to start instance %s: %s" % 564 (instance_name, "already running"))
565 566 @classmethod
567 - def _InstanceMonitor(cls, instance_name):
568 """Returns the instance monitor socket name 569 570 """ 571 return utils.PathJoin(cls._CTRL_DIR, "%s.monitor" % instance_name)
572 573 @classmethod
574 - def _InstanceSerial(cls, instance_name):
575 """Returns the instance serial socket name 576 577 """ 578 return utils.PathJoin(cls._CTRL_DIR, "%s.serial" % instance_name)
579 580 @classmethod
581 - def _InstanceQmpMonitor(cls, instance_name):
582 """Returns the instance serial QMP socket name 583 584 """ 585 return utils.PathJoin(cls._CTRL_DIR, "%s.qmp" % instance_name)
586 587 @classmethod
588 - def _InstanceKvmdMonitor(cls, instance_name):
589 """Returns the instance kvm daemon socket name 590 591 """ 592 return utils.PathJoin(cls._CTRL_DIR, "%s.kvmd" % instance_name)
593 594 @classmethod
595 - def _InstanceShutdownMonitor(cls, instance_name):
596 """Returns the instance QMP output filename 597 598 """ 599 return utils.PathJoin(cls._CTRL_DIR, "%s.shutdown" % instance_name)
600 601 @staticmethod
603 """Returns the correct parameters for socat 604 605 If we have a new-enough socat we can use raw mode with an escape character. 606 607 """ 608 if constants.SOCAT_USE_ESCAPE: 609 return "raw,echo=0,escape=%s" % constants.SOCAT_ESCAPE_CODE 610 else: 611 return "echo=0,icanon=0"
612 613 @classmethod
614 - def _InstanceKVMRuntime(cls, instance_name):
615 """Returns the instance KVM runtime filename 616 617 """ 618 return utils.PathJoin(cls._CONF_DIR, "%s.runtime" % instance_name)
619 620 @classmethod
621 - def _InstanceChrootDir(cls, instance_name):
622 """Returns the name of the KVM chroot dir of the instance 623 624 """ 625 return utils.PathJoin(cls._CHROOT_DIR, instance_name)
626 627 @classmethod
628 - def _InstanceNICDir(cls, instance_name):
629 """Returns the name of the directory holding the tap device files for a 630 given instance. 631 632 """ 633 return utils.PathJoin(cls._NICS_DIR, instance_name)
634 635 @classmethod
636 - def _InstanceNICFile(cls, instance_name, seq):
637 """Returns the name of the file containing the tap device for a given NIC 638 639 """ 640 return utils.PathJoin(cls._InstanceNICDir(instance_name), str(seq))
641 642 @classmethod
643 - def _InstanceKeymapFile(cls, instance_name):
644 """Returns the name of the file containing the keymap for a given instance 645 646 """ 647 return utils.PathJoin(cls._KEYMAP_DIR, instance_name)
648 649 @classmethod
650 - def _TryReadUidFile(cls, uid_file):
651 """Try to read a uid file 652 653 """ 654 if os.path.exists(uid_file): 655 try: 656 uid = int(utils.ReadOneLineFile(uid_file)) 657 return uid 658 except EnvironmentError: 659 logging.warning("Can't read uid file", exc_info=True) 660 except (TypeError, ValueError): 661 logging.warning("Can't parse uid file contents", exc_info=True) 662 return None
663 664 @classmethod
665 - def _RemoveInstanceRuntimeFiles(cls, pidfile, instance_name):
666 """Removes an instance's rutime sockets/files/dirs. 667 668 """ 669 utils.RemoveFile(pidfile) 670 utils.RemoveFile(cls._InstanceMonitor(instance_name)) 671 utils.RemoveFile(cls._InstanceSerial(instance_name)) 672 utils.RemoveFile(cls._InstanceQmpMonitor(instance_name)) 673 utils.RemoveFile(cls._InstanceKVMRuntime(instance_name)) 674 utils.RemoveFile(cls._InstanceKeymapFile(instance_name)) 675 uid_file = cls._InstanceUidFile(instance_name) 676 uid = cls._TryReadUidFile(uid_file) 677 utils.RemoveFile(uid_file) 678 if uid is not None: 679 uidpool.ReleaseUid(uid) 680 try: 681 shutil.rmtree(cls._InstanceNICDir(instance_name)) 682 except OSError, err: 683 if err.errno != errno.ENOENT: 684 raise 685 try: 686 chroot_dir = cls._InstanceChrootDir(instance_name) 687 utils.RemoveDir(chroot_dir) 688 except OSError, err: 689 if err.errno == errno.ENOTEMPTY: 690 # The chroot directory is expected to be empty, but it isn't. 691 new_chroot_dir = tempfile.mkdtemp(dir=cls._CHROOT_QUARANTINE_DIR, 692 prefix="%s-%s-" % 693 (instance_name, 694 utils.TimestampForFilename())) 695 logging.warning("The chroot directory of instance %s can not be" 696 " removed as it is not empty. Moving it to the" 697 " quarantine instead. Please investigate the" 698 " contents (%s) and clean up manually", 699 instance_name, new_chroot_dir) 700 utils.RenameFile(chroot_dir, new_chroot_dir) 701 else: 702 raise
703 704 @staticmethod
705 - def _ConfigureNIC(instance, seq, nic, tap):
706 """Run the network configuration script for a specified NIC 707 708 See L{hv_base.ConfigureNIC}. 709 710 @param instance: instance we're acting on 711 @type instance: instance object 712 @param seq: nic sequence number 713 @type seq: int 714 @param nic: nic we're acting on 715 @type nic: nic object 716 @param tap: the host's tap interface this NIC corresponds to 717 @type tap: str 718 719 """ 720 hv_base.ConfigureNIC([pathutils.KVM_IFUP, tap], instance, seq, nic, tap)
721 722 @classmethod
723 - def _SetProcessAffinity(cls, process_id, cpus):
724 """Sets the affinity of a process to the given CPUs. 725 726 @type process_id: int 727 @type cpus: list of int 728 @param cpus: The list of CPUs the process ID may use. 729 730 """ 731 if psutil is None: 732 raise errors.HypervisorError("psutil Python package not" 733 " found; cannot use CPU pinning under KVM") 734 735 target_process = psutil.Process(process_id) 736 if cpus == constants.CPU_PINNING_OFF: 737 target_process.set_cpu_affinity(range(psutil.cpu_count())) 738 else: 739 target_process.set_cpu_affinity(cpus)
740 741 @classmethod
742 - def _AssignCpuAffinity(cls, cpu_mask, process_id, thread_dict):
743 """Change CPU affinity for running VM according to given CPU mask. 744 745 @param cpu_mask: CPU mask as given by the user. e.g. "0-2,4:all:1,3" 746 @type cpu_mask: string 747 @param process_id: process ID of KVM process. Used to pin entire VM 748 to physical CPUs. 749 @type process_id: int 750 @param thread_dict: map of virtual CPUs to KVM thread IDs 751 @type thread_dict: dict int:int 752 753 """ 754 # Convert the string CPU mask to a list of list of int's 755 cpu_list = utils.ParseMultiCpuMask(cpu_mask) 756 757 if len(cpu_list) == 1: 758 all_cpu_mapping = cpu_list[0] 759 if all_cpu_mapping == constants.CPU_PINNING_OFF: 760 # If CPU pinning has 1 entry that's "all", then do nothing 761 pass 762 else: 763 # If CPU pinning has one non-all entry, map the entire VM to 764 # one set of physical CPUs 765 cls._SetProcessAffinity(process_id, all_cpu_mapping) 766 else: 767 # The number of vCPUs mapped should match the number of vCPUs 768 # reported by KVM. This was already verified earlier, so 769 # here only as a sanity check. 770 assert len(thread_dict) == len(cpu_list) 771 772 # For each vCPU, map it to the proper list of physical CPUs 773 for i, vcpu in enumerate(cpu_list): 774 cls._SetProcessAffinity(thread_dict[i], vcpu)
775
776 - def _GetVcpuThreadIds(self, instance_name):
777 """Get a mapping of vCPU no. to thread IDs for the instance 778 779 @type instance_name: string 780 @param instance_name: instance in question 781 @rtype: dictionary of int:int 782 @return: a dictionary mapping vCPU numbers to thread IDs 783 784 """ 785 result = {} 786 output = self._CallMonitorCommand(instance_name, self._CPU_INFO_CMD) 787 for line in output.stdout.splitlines(): 788 match = self._CPU_INFO_RE.search(line) 789 if not match: 790 continue 791 grp = map(int, match.groups()) 792 result[grp[0]] = grp[1] 793 794 return result
795
796 - def _ExecuteCpuAffinity(self, instance_name, cpu_mask):
797 """Complete CPU pinning. 798 799 @type instance_name: string 800 @param instance_name: name of instance 801 @type cpu_mask: string 802 @param cpu_mask: CPU pinning mask as entered by user 803 804 """ 805 # Get KVM process ID, to be used if need to pin entire VM 806 _, pid, _ = self._InstancePidAlive(instance_name) 807 # Get vCPU thread IDs, to be used if need to pin vCPUs separately 808 thread_dict = self._GetVcpuThreadIds(instance_name) 809 # Run CPU pinning, based on configured mask 810 self._AssignCpuAffinity(cpu_mask, pid, thread_dict)
811
812 - def ListInstances(self, hvparams=None):
813 """Get the list of running instances. 814 815 We can do this by listing our live instances directory and 816 checking whether the associated kvm process is still alive. 817 818 """ 819 result = [] 820 for name in os.listdir(self._PIDS_DIR): 821 if self._InstancePidAlive(name)[2]: 822 result.append(name) 823 return result
824 825 @classmethod
826 - def _IsUserShutdown(cls, instance_name):
827 return os.path.exists(cls._InstanceShutdownMonitor(instance_name))
828 829 @classmethod
830 - def _ClearUserShutdown(cls, instance_name):
831 utils.RemoveFile(cls._InstanceShutdownMonitor(instance_name))
832
833 - def GetInstanceInfo(self, instance_name, hvparams=None):
834 """Get instance properties. 835 836 @type instance_name: string 837 @param instance_name: the instance name 838 @type hvparams: dict of strings 839 @param hvparams: hypervisor parameters to be used with this instance 840 @rtype: tuple of strings 841 @return: (name, id, memory, vcpus, stat, times) 842 843 """ 844 _, pid, alive = self._InstancePidAlive(instance_name) 845 if not alive: 846 if self._IsUserShutdown(instance_name): 847 return (instance_name, -1, 0, 0, hv_base.HvInstanceState.SHUTDOWN, 0) 848 else: 849 return None 850 851 _, memory, vcpus = self._InstancePidInfo(pid) 852 istat = hv_base.HvInstanceState.RUNNING 853 times = 0 854 855 try: 856 qmp = QmpConnection(self._InstanceQmpMonitor(instance_name)) 857 qmp.connect() 858 vcpus = len(qmp.Execute("query-cpus")) 859 # Will fail if ballooning is not enabled, but we can then just resort to 860 # the value above. 861 mem_bytes = qmp.Execute("query-balloon")[qmp.ACTUAL_KEY] 862 memory = mem_bytes / 1048576 863 except errors.HypervisorError: 864 pass 865 866 return (instance_name, pid, memory, vcpus, istat, times)
867
868 - def GetAllInstancesInfo(self, hvparams=None):
869 """Get properties of all instances. 870 871 @type hvparams: dict of strings 872 @param hvparams: hypervisor parameters 873 @return: list of tuples (name, id, memory, vcpus, stat, times) 874 875 """ 876 data = [] 877 for name in os.listdir(self._PIDS_DIR): 878 try: 879 info = self.GetInstanceInfo(name) 880 except errors.HypervisorError: 881 # Ignore exceptions due to instances being shut down 882 continue 883 if info: 884 data.append(info) 885 return data
886
887 - def _GenerateKVMBlockDevicesOptions(self, instance, up_hvp, kvm_disks, 888 kvmhelp, devlist):
889 """Generate KVM options regarding instance's block devices. 890 891 @type instance: L{objects.Instance} 892 @param instance: the instance object 893 @type up_hvp: dict 894 @param up_hvp: the instance's runtime hypervisor parameters 895 @type kvm_disks: list of tuples 896 @param kvm_disks: list of tuples [(disk, link_name, uri)..] 897 @type kvmhelp: string 898 @param kvmhelp: output of kvm --help 899 @type devlist: string 900 @param devlist: output of kvm -device ? 901 @rtype: list 902 @return: list of command line options eventually used by kvm executable 903 904 """ 905 kernel_path = up_hvp[constants.HV_KERNEL_PATH] 906 if kernel_path: 907 boot_disk = False 908 else: 909 boot_disk = up_hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK 910 911 # whether this is an older KVM version that uses the boot=on flag 912 # on devices 913 needs_boot_flag = self._BOOT_RE.search(kvmhelp) 914 915 dev_opts = [] 916 device_driver = None 917 disk_type = up_hvp[constants.HV_DISK_TYPE] 918 if disk_type == constants.HT_DISK_PARAVIRTUAL: 919 if_val = ",if=%s" % self._VIRTIO 920 try: 921 if self._VIRTIO_BLK_RE.search(devlist): 922 if_val = ",if=none" 923 # will be passed in -device option as driver 924 device_driver = self._VIRTIO_BLK_PCI 925 except errors.HypervisorError, _: 926 pass 927 else: 928 if_val = ",if=%s" % disk_type 929 # AIO mode 930 aio_mode = up_hvp[constants.HV_KVM_DISK_AIO] 931 if aio_mode == constants.HT_KVM_AIO_NATIVE: 932 aio_val = ",aio=%s" % aio_mode 933 else: 934 aio_val = "" 935 # Cache mode 936 disk_cache = up_hvp[constants.HV_DISK_CACHE] 937 if instance.disk_template in constants.DTS_EXT_MIRROR: 938 if disk_cache != "none": 939 # TODO: make this a hard error, instead of a silent overwrite 940 logging.warning("KVM: overriding disk_cache setting '%s' with 'none'" 941 " to prevent shared storage corruption on migration", 942 disk_cache) 943 cache_val = ",cache=none" 944 elif disk_cache != constants.HT_CACHE_DEFAULT: 945 cache_val = ",cache=%s" % disk_cache 946 else: 947 cache_val = "" 948 for cfdev, link_name, uri in kvm_disks: 949 if cfdev.mode != constants.DISK_RDWR: 950 raise errors.HypervisorError("Instance has read-only disks which" 951 " are not supported by KVM") 952 # TODO: handle FD_LOOP and FD_BLKTAP (?) 953 boot_val = "" 954 if boot_disk: 955 dev_opts.extend(["-boot", "c"]) 956 boot_disk = False 957 if needs_boot_flag and disk_type != constants.HT_DISK_IDE: 958 boot_val = ",boot=on" 959 960 drive_uri = _GetDriveURI(cfdev, link_name, uri) 961 962 drive_val = "file=%s,format=raw%s%s%s%s" % \ 963 (drive_uri, if_val, boot_val, cache_val, aio_val) 964 965 if device_driver: 966 # kvm_disks are the 4th entry of runtime file that did not exist in 967 # the past. That means that cfdev should always have pci slot and 968 # _GenerateDeviceKVMId() will not raise a exception. 969 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_DISK, cfdev) 970 drive_val += (",id=%s" % kvm_devid) 971 drive_val += (",bus=0,unit=%d" % cfdev.pci) 972 dev_val = ("%s,drive=%s,id=%s" % 973 (device_driver, kvm_devid, kvm_devid)) 974 dev_val += ",bus=pci.0,addr=%s" % hex(cfdev.pci) 975 dev_opts.extend(["-device", dev_val]) 976 977 dev_opts.extend(["-drive", drive_val]) 978 979 return dev_opts
980 981 @staticmethod
982 - def _CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image, cdrom_boot, 983 needs_boot_flag):
984 """Extends L{kvm_cmd} with the '-drive' option for a cdrom, and 985 optionally the '-boot' option. 986 987 Example: -drive file=cdrom.iso,media=cdrom,format=raw,if=ide -boot d 988 989 Example: -drive file=cdrom.iso,media=cdrom,format=raw,if=ide,boot=on 990 991 Example: -drive file=http://hostname.com/cdrom.iso,media=cdrom 992 993 @type kvm_cmd: string 994 @param kvm_cmd: KVM command line 995 996 @type cdrom_disk_type: 997 @param cdrom_disk_type: 998 999 @type cdrom_image: 1000 @param cdrom_image: 1001 1002 @type cdrom_boot: 1003 @param cdrom_boot: 1004 1005 @type needs_boot_flag: 1006 @param needs_boot_flag: 1007 1008 """ 1009 # Check that the ISO image is accessible 1010 # See https://bugs.launchpad.net/qemu/+bug/597575 1011 if utils.IsUrl(cdrom_image) and not _CheckUrl(cdrom_image): 1012 raise errors.HypervisorError("Cdrom ISO image '%s' is not accessible" % 1013 cdrom_image) 1014 1015 # set cdrom 'media' and 'format', if needed 1016 if utils.IsUrl(cdrom_image): 1017 options = ",media=cdrom" 1018 else: 1019 options = ",media=cdrom,format=raw" 1020 1021 # set cdrom 'if' type 1022 if cdrom_boot: 1023 if_val = ",if=" + constants.HT_DISK_IDE 1024 elif cdrom_disk_type == constants.HT_DISK_PARAVIRTUAL: 1025 if_val = ",if=virtio" 1026 else: 1027 if_val = ",if=" + cdrom_disk_type 1028 1029 # set boot flag, if needed 1030 boot_val = "" 1031 if cdrom_boot: 1032 kvm_cmd.extend(["-boot", "d"]) 1033 1034 # whether this is an older KVM version that requires the 'boot=on' flag 1035 # on devices 1036 if needs_boot_flag: 1037 boot_val = ",boot=on" 1038 1039 # build '-drive' option 1040 drive_val = "file=%s%s%s%s" % (cdrom_image, options, if_val, boot_val) 1041 kvm_cmd.extend(["-drive", drive_val])
1042
1043 - def _GenerateKVMRuntime(self, instance, block_devices, startup_paused, 1044 kvmhelp):
1045 """Generate KVM information to start an instance. 1046 1047 @type kvmhelp: string 1048 @param kvmhelp: output of kvm --help 1049 @attention: this function must not have any side-effects; for 1050 example, it must not write to the filesystem, or read values 1051 from the current system the are expected to differ between 1052 nodes, since it is only run once at instance startup; 1053 actions/kvm arguments that can vary between systems should be 1054 done in L{_ExecuteKVMRuntime} 1055 1056 """ 1057 # pylint: disable=R0912,R0914,R0915 1058 hvp = instance.hvparams 1059 self.ValidateParameters(hvp) 1060 1061 pidfile = self._InstancePidFile(instance.name) 1062 kvm = hvp[constants.HV_KVM_PATH] 1063 kvm_cmd = [kvm] 1064 # used just by the vnc server, if enabled 1065 kvm_cmd.extend(["-name", instance.name]) 1066 kvm_cmd.extend(["-m", instance.beparams[constants.BE_MAXMEM]]) 1067 1068 smp_list = ["%s" % instance.beparams[constants.BE_VCPUS]] 1069 if hvp[constants.HV_CPU_CORES]: 1070 smp_list.append("cores=%s" % hvp[constants.HV_CPU_CORES]) 1071 if hvp[constants.HV_CPU_THREADS]: 1072 smp_list.append("threads=%s" % hvp[constants.HV_CPU_THREADS]) 1073 if hvp[constants.HV_CPU_SOCKETS]: 1074 smp_list.append("sockets=%s" % hvp[constants.HV_CPU_SOCKETS]) 1075 1076 kvm_cmd.extend(["-smp", ",".join(smp_list)]) 1077 1078 kvm_cmd.extend(["-pidfile", pidfile]) 1079 1080 pci_reservations = bitarray(self._DEFAULT_PCI_RESERVATIONS) 1081 1082 # As requested by music lovers 1083 if hvp[constants.HV_SOUNDHW]: 1084 soundhw = hvp[constants.HV_SOUNDHW] 1085 # For some reason only few sound devices require a PCI slot 1086 # while the Audio controller *must* be in slot 3. 1087 # That's why we bridge this option early in command line 1088 if soundhw in self._SOUNDHW_WITH_PCI_SLOT: 1089 _ = _GetFreeSlot(pci_reservations, reserve=True) 1090 kvm_cmd.extend(["-soundhw", soundhw]) 1091 1092 if hvp[constants.HV_DISK_TYPE] == constants.HT_DISK_SCSI: 1093 # The SCSI controller requires another PCI slot. 1094 _ = _GetFreeSlot(pci_reservations, reserve=True) 1095 1096 # Add id to ballon and place to the first available slot (3 or 4) 1097 addr = _GetFreeSlot(pci_reservations, reserve=True) 1098 pci_info = ",bus=pci.0,addr=%s" % hex(addr) 1099 kvm_cmd.extend(["-balloon", "virtio,id=balloon%s" % pci_info]) 1100 kvm_cmd.extend(["-daemonize"]) 1101 if not instance.hvparams[constants.HV_ACPI]: 1102 kvm_cmd.extend(["-no-acpi"]) 1103 if instance.hvparams[constants.HV_REBOOT_BEHAVIOR] == \ 1104 constants.INSTANCE_REBOOT_EXIT: 1105 kvm_cmd.extend(["-no-reboot"]) 1106 1107 mversion = hvp[constants.HV_KVM_MACHINE_VERSION] 1108 if not mversion: 1109 mversion = self._GetDefaultMachineVersion(kvm) 1110 if self._MACHINE_RE.search(kvmhelp): 1111 # TODO (2.8): kernel_irqchip and kvm_shadow_mem machine properties, as 1112 # extra hypervisor parameters. We should also investigate whether and how 1113 # shadow_mem should be considered for the resource model. 1114 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED): 1115 specprop = ",accel=kvm" 1116 else: 1117 specprop = "" 1118 machinespec = "%s%s" % (mversion, specprop) 1119 kvm_cmd.extend(["-machine", machinespec]) 1120 else: 1121 kvm_cmd.extend(["-M", mversion]) 1122 if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and 1123 self._ENABLE_KVM_RE.search(kvmhelp)): 1124 kvm_cmd.extend(["-enable-kvm"]) 1125 elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and 1126 self._DISABLE_KVM_RE.search(kvmhelp)): 1127 kvm_cmd.extend(["-disable-kvm"]) 1128 1129 kernel_path = hvp[constants.HV_KERNEL_PATH] 1130 if kernel_path: 1131 boot_cdrom = boot_floppy = boot_network = False 1132 else: 1133 boot_cdrom = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_CDROM 1134 boot_floppy = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_FLOPPY 1135 boot_network = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_NETWORK 1136 1137 if startup_paused: 1138 kvm_cmd.extend([_KVM_START_PAUSED_FLAG]) 1139 1140 if boot_network: 1141 kvm_cmd.extend(["-boot", "n"]) 1142 1143 disk_type = hvp[constants.HV_DISK_TYPE] 1144 1145 # Now we can specify a different device type for CDROM devices. 1146 cdrom_disk_type = hvp[constants.HV_KVM_CDROM_DISK_TYPE] 1147 if not cdrom_disk_type: 1148 cdrom_disk_type = disk_type 1149 1150 cdrom_image1 = hvp[constants.HV_CDROM_IMAGE_PATH] 1151 if cdrom_image1: 1152 needs_boot_flag = self._BOOT_RE.search(kvmhelp) 1153 self._CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image1, boot_cdrom, 1154 needs_boot_flag) 1155 1156 cdrom_image2 = hvp[constants.HV_KVM_CDROM2_IMAGE_PATH] 1157 if cdrom_image2: 1158 self._CdromOption(kvm_cmd, cdrom_disk_type, cdrom_image2, False, False) 1159 1160 floppy_image = hvp[constants.HV_KVM_FLOPPY_IMAGE_PATH] 1161 if floppy_image: 1162 options = ",format=raw,media=disk" 1163 if boot_floppy: 1164 kvm_cmd.extend(["-boot", "a"]) 1165 options = "%s,boot=on" % options 1166 if_val = ",if=floppy" 1167 options = "%s%s" % (options, if_val) 1168 drive_val = "file=%s%s" % (floppy_image, options) 1169 kvm_cmd.extend(["-drive", drive_val]) 1170 1171 if kernel_path: 1172 kvm_cmd.extend(["-kernel", kernel_path]) 1173 initrd_path = hvp[constants.HV_INITRD_PATH] 1174 if initrd_path: 1175 kvm_cmd.extend(["-initrd", initrd_path]) 1176 root_append = ["root=%s" % hvp[constants.HV_ROOT_PATH], 1177 hvp[constants.HV_KERNEL_ARGS]] 1178 if hvp[constants.HV_SERIAL_CONSOLE]: 1179 serial_speed = hvp[constants.HV_SERIAL_SPEED] 1180 root_append.append("console=ttyS0,%s" % serial_speed) 1181 kvm_cmd.extend(["-append", " ".join(root_append)]) 1182 1183 mem_path = hvp[constants.HV_MEM_PATH] 1184 if mem_path: 1185 kvm_cmd.extend(["-mem-path", mem_path, "-mem-prealloc"]) 1186 1187 monitor_dev = ("unix:%s,server,nowait" % 1188 self._InstanceMonitor(instance.name)) 1189 kvm_cmd.extend(["-monitor", monitor_dev]) 1190 if hvp[constants.HV_SERIAL_CONSOLE]: 1191 serial_dev = ("unix:%s,server,nowait" % 1192 self._InstanceSerial(instance.name)) 1193 kvm_cmd.extend(["-serial", serial_dev]) 1194 else: 1195 kvm_cmd.extend(["-serial", "none"]) 1196 1197 mouse_type = hvp[constants.HV_USB_MOUSE] 1198 vnc_bind_address = hvp[constants.HV_VNC_BIND_ADDRESS] 1199 spice_bind = hvp[constants.HV_KVM_SPICE_BIND] 1200 spice_ip_version = None 1201 1202 kvm_cmd.extend(["-usb"]) 1203 1204 if mouse_type: 1205 kvm_cmd.extend(["-usbdevice", mouse_type]) 1206 elif vnc_bind_address: 1207 kvm_cmd.extend(["-usbdevice", constants.HT_MOUSE_TABLET]) 1208 1209 if vnc_bind_address: 1210 if netutils.IsValidInterface(vnc_bind_address): 1211 if_addresses = netutils.GetInterfaceIpAddresses(vnc_bind_address) 1212 if_ip4_addresses = if_addresses[constants.IP4_VERSION] 1213 if len(if_ip4_addresses) < 1: 1214 logging.error("Could not determine IPv4 address of interface %s", 1215 vnc_bind_address) 1216 else: 1217 vnc_bind_address = if_ip4_addresses[0] 1218 if netutils.IP4Address.IsValid(vnc_bind_address): 1219 if instance.network_port > constants.VNC_BASE_PORT: 1220 display = instance.network_port - constants.VNC_BASE_PORT 1221 if vnc_bind_address == constants.IP4_ADDRESS_ANY: 1222 vnc_arg = ":%d" % (display) 1223 else: 1224 vnc_arg = "%s:%d" % (vnc_bind_address, display) 1225 else: 1226 logging.error("Network port is not a valid VNC display (%d < %d)," 1227 " not starting VNC", 1228 instance.network_port, constants.VNC_BASE_PORT) 1229 vnc_arg = "none" 1230 1231 # Only allow tls and other option when not binding to a file, for now. 1232 # kvm/qemu gets confused otherwise about the filename to use. 1233 vnc_append = "" 1234 if hvp[constants.HV_VNC_TLS]: 1235 vnc_append = "%s,tls" % vnc_append 1236 if hvp[constants.HV_VNC_X509_VERIFY]: 1237 vnc_append = "%s,x509verify=%s" % (vnc_append, 1238 hvp[constants.HV_VNC_X509]) 1239 elif hvp[constants.HV_VNC_X509]: 1240 vnc_append = "%s,x509=%s" % (vnc_append, 1241 hvp[constants.HV_VNC_X509]) 1242 if hvp[constants.HV_VNC_PASSWORD_FILE]: 1243 vnc_append = "%s,password" % vnc_append 1244 1245 vnc_arg = "%s%s" % (vnc_arg, vnc_append) 1246 1247 else: 1248 vnc_arg = "unix:%s/%s.vnc" % (vnc_bind_address, instance.name) 1249 1250 kvm_cmd.extend(["-vnc", vnc_arg]) 1251 elif spice_bind: 1252 # FIXME: this is wrong here; the iface ip address differs 1253 # between systems, so it should be done in _ExecuteKVMRuntime 1254 if netutils.IsValidInterface(spice_bind): 1255 # The user specified a network interface, we have to figure out the IP 1256 # address. 1257 addresses = netutils.GetInterfaceIpAddresses(spice_bind) 1258 spice_ip_version = hvp[constants.HV_KVM_SPICE_IP_VERSION] 1259 1260 # if the user specified an IP version and the interface does not 1261 # have that kind of IP addresses, throw an exception 1262 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED: 1263 if not addresses[spice_ip_version]: 1264 raise errors.HypervisorError("SPICE: Unable to get an IPv%s address" 1265 " for %s" % (spice_ip_version, 1266 spice_bind)) 1267 1268 # the user did not specify an IP version, we have to figure it out 1269 elif (addresses[constants.IP4_VERSION] and 1270 addresses[constants.IP6_VERSION]): 1271 # we have both ipv4 and ipv6, let's use the cluster default IP 1272 # version 1273 cluster_family = ssconf.SimpleStore().GetPrimaryIPFamily() 1274 spice_ip_version = \ 1275 netutils.IPAddress.GetVersionFromAddressFamily(cluster_family) 1276 elif addresses[constants.IP4_VERSION]: 1277 spice_ip_version = constants.IP4_VERSION 1278 elif addresses[constants.IP6_VERSION]: 1279 spice_ip_version = constants.IP6_VERSION 1280 else: 1281 raise errors.HypervisorError("SPICE: Unable to get an IP address" 1282 " for %s" % (spice_bind)) 1283 1284 spice_address = addresses[spice_ip_version][0] 1285 1286 else: 1287 # spice_bind is known to be a valid IP address, because 1288 # ValidateParameters checked it. 1289 spice_address = spice_bind 1290 1291 spice_arg = "addr=%s" % spice_address 1292 if hvp[constants.HV_KVM_SPICE_USE_TLS]: 1293 spice_arg = ("%s,tls-port=%s,x509-cacert-file=%s" % 1294 (spice_arg, instance.network_port, 1295 pathutils.SPICE_CACERT_FILE)) 1296 spice_arg = ("%s,x509-key-file=%s,x509-cert-file=%s" % 1297 (spice_arg, pathutils.SPICE_CERT_FILE, 1298 pathutils.SPICE_CERT_FILE)) 1299 tls_ciphers = hvp[constants.HV_KVM_SPICE_TLS_CIPHERS] 1300 if tls_ciphers: 1301 spice_arg = "%s,tls-ciphers=%s" % (spice_arg, tls_ciphers) 1302 else: 1303 spice_arg = "%s,port=%s" % (spice_arg, instance.network_port) 1304 1305 if not hvp[constants.HV_KVM_SPICE_PASSWORD_FILE]: 1306 spice_arg = "%s,disable-ticketing" % spice_arg 1307 1308 if spice_ip_version: 1309 spice_arg = "%s,ipv%s" % (spice_arg, spice_ip_version) 1310 1311 # Image compression options 1312 img_lossless = hvp[constants.HV_KVM_SPICE_LOSSLESS_IMG_COMPR] 1313 img_jpeg = hvp[constants.HV_KVM_SPICE_JPEG_IMG_COMPR] 1314 img_zlib_glz = hvp[constants.HV_KVM_SPICE_ZLIB_GLZ_IMG_COMPR] 1315 if img_lossless: 1316 spice_arg = "%s,image-compression=%s" % (spice_arg, img_lossless) 1317 if img_jpeg: 1318 spice_arg = "%s,jpeg-wan-compression=%s" % (spice_arg, img_jpeg) 1319 if img_zlib_glz: 1320 spice_arg = "%s,zlib-glz-wan-compression=%s" % (spice_arg, img_zlib_glz) 1321 1322 # Video stream detection 1323 video_streaming = hvp[constants.HV_KVM_SPICE_STREAMING_VIDEO_DETECTION] 1324 if video_streaming: 1325 spice_arg = "%s,streaming-video=%s" % (spice_arg, video_streaming) 1326 1327 # Audio compression, by default in qemu-kvm it is on 1328 if not hvp[constants.HV_KVM_SPICE_AUDIO_COMPR]: 1329 spice_arg = "%s,playback-compression=off" % spice_arg 1330 if not hvp[constants.HV_KVM_SPICE_USE_VDAGENT]: 1331 spice_arg = "%s,agent-mouse=off" % spice_arg 1332 else: 1333 # Enable the spice agent communication channel between the host and the 1334 # agent. 1335 addr = _GetFreeSlot(pci_reservations, reserve=True) 1336 pci_info = ",bus=pci.0,addr=%s" % hex(addr) 1337 kvm_cmd.extend(["-device", "virtio-serial-pci,id=spice%s" % pci_info]) 1338 kvm_cmd.extend([ 1339 "-device", 1340 "virtserialport,chardev=spicechannel0,name=com.redhat.spice.0", 1341 ]) 1342 kvm_cmd.extend(["-chardev", "spicevmc,id=spicechannel0,name=vdagent"]) 1343 1344 logging.info("KVM: SPICE will listen on port %s", instance.network_port) 1345 kvm_cmd.extend(["-spice", spice_arg]) 1346 1347 else: 1348 # From qemu 1.4 -nographic is incompatible with -daemonize. The new way 1349 # also works in earlier versions though (tested with 1.1 and 1.3) 1350 if self._DISPLAY_RE.search(kvmhelp): 1351 kvm_cmd.extend(["-display", "none"]) 1352 else: 1353 kvm_cmd.extend(["-nographic"]) 1354 1355 if hvp[constants.HV_USE_LOCALTIME]: 1356 kvm_cmd.extend(["-localtime"]) 1357 1358 if hvp[constants.HV_KVM_USE_CHROOT]: 1359 kvm_cmd.extend(["-chroot", self._InstanceChrootDir(instance.name)]) 1360 1361 # Add qemu-KVM -cpu param 1362 if hvp[constants.HV_CPU_TYPE]: 1363 kvm_cmd.extend(["-cpu", hvp[constants.HV_CPU_TYPE]]) 1364 1365 # Pass a -vga option if requested, or if spice is used, for backwards 1366 # compatibility. 1367 if hvp[constants.HV_VGA]: 1368 kvm_cmd.extend(["-vga", hvp[constants.HV_VGA]]) 1369 elif spice_bind: 1370 kvm_cmd.extend(["-vga", "qxl"]) 1371 1372 # Various types of usb devices, comma separated 1373 if hvp[constants.HV_USB_DEVICES]: 1374 for dev in hvp[constants.HV_USB_DEVICES].split(","): 1375 kvm_cmd.extend(["-usbdevice", dev]) 1376 1377 # Set system UUID to instance UUID 1378 if self._UUID_RE.search(kvmhelp): 1379 kvm_cmd.extend(["-uuid", instance.uuid]) 1380 1381 if hvp[constants.HV_KVM_EXTRA]: 1382 kvm_cmd.extend(hvp[constants.HV_KVM_EXTRA].split(" ")) 1383 1384 kvm_disks = [] 1385 for disk, link_name, uri in block_devices: 1386 disk.pci = _GetFreeSlot(pci_reservations, disk.pci, True) 1387 kvm_disks.append((disk, link_name, uri)) 1388 1389 kvm_nics = [] 1390 for nic in instance.nics: 1391 nic.pci = _GetFreeSlot(pci_reservations, nic.pci, True) 1392 kvm_nics.append(nic) 1393 1394 hvparams = hvp 1395 1396 return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
1397
1398 - def _WriteKVMRuntime(self, instance_name, data):
1399 """Write an instance's KVM runtime 1400 1401 """ 1402 try: 1403 utils.WriteFile(self._InstanceKVMRuntime(instance_name), 1404 data=data) 1405 except EnvironmentError, err: 1406 raise errors.HypervisorError("Failed to save KVM runtime file: %s" % err)
1407
1408 - def _ReadKVMRuntime(self, instance_name):
1409 """Read an instance's KVM runtime 1410 1411 """ 1412 try: 1413 file_content = utils.ReadFile(self._InstanceKVMRuntime(instance_name)) 1414 except EnvironmentError, err: 1415 raise errors.HypervisorError("Failed to load KVM runtime file: %s" % err) 1416 return file_content
1417
1418 - def _SaveKVMRuntime(self, instance, kvm_runtime):
1419 """Save an instance's KVM runtime 1420 1421 """ 1422 kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime 1423 1424 serialized_nics = [nic.ToDict() for nic in kvm_nics] 1425 serialized_disks = [(blk.ToDict(), link, uri) 1426 for blk, link, uri in kvm_disks] 1427 serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams, 1428 serialized_disks)) 1429 1430 self._WriteKVMRuntime(instance.name, serialized_form)
1431
1432 - def _LoadKVMRuntime(self, instance, serialized_runtime=None):
1433 """Load an instance's KVM runtime 1434 1435 """ 1436 if not serialized_runtime: 1437 serialized_runtime = self._ReadKVMRuntime(instance.name) 1438 1439 return _AnalyzeSerializedRuntime(serialized_runtime)
1440
1441 - def _RunKVMCmd(self, name, kvm_cmd, tap_fds=None):
1442 """Run the KVM cmd and check for errors 1443 1444 @type name: string 1445 @param name: instance name 1446 @type kvm_cmd: list of strings 1447 @param kvm_cmd: runcmd input for kvm 1448 @type tap_fds: list of int 1449 @param tap_fds: fds of tap devices opened by Ganeti 1450 1451 """ 1452 try: 1453 result = utils.RunCmd(kvm_cmd, noclose_fds=tap_fds) 1454 finally: 1455 for fd in tap_fds: 1456 utils_wrapper.CloseFdNoError(fd) 1457 1458 if result.failed: 1459 raise errors.HypervisorError("Failed to start instance %s: %s (%s)" % 1460 (name, result.fail_reason, result.output)) 1461 if not self._InstancePidAlive(name)[2]: 1462 raise errors.HypervisorError("Failed to start instance %s" % name)
1463 1464 @staticmethod
1465 - def _GenerateKvmTapName(nic):
1466 """Generate a TAP network interface name for a NIC. 1467 1468 See L{hv_base.GenerateTapName}. 1469 1470 For the case of the empty string, see L{OpenTap} 1471 1472 @type nic: ganeti.objects.NIC 1473 @param nic: NIC object for the name should be generated 1474 1475 @rtype: string 1476 @return: TAP network interface name, or the empty string if the 1477 NIC is not used in instance communication 1478 1479 """ 1480 if nic.name is None or not \ 1481 nic.name.startswith(constants.INSTANCE_COMMUNICATION_NIC_PREFIX): 1482 return "" 1483 1484 return hv_base.GenerateTapName()
1485
1486 - def _GetNetworkDeviceFeatures(self, up_hvp, devlist, kvmhelp):
1487 """Get network device options to properly enable supported features. 1488 1489 Return tuple of supported and enabled tap features with nic_model. 1490 This function is called before opening a new tap device. 1491 1492 @return: (nic_model, vnet_hdr, virtio_net_queues, tap_extra, nic_extra) 1493 @rtype: tuple 1494 1495 """ 1496 virtio_net_queues = 1 1497 nic_extra = "" 1498 nic_type = up_hvp[constants.HV_NIC_TYPE] 1499 tap_extra = "" 1500 vnet_hdr = False 1501 if nic_type == constants.HT_NIC_PARAVIRTUAL: 1502 nic_model = self._VIRTIO 1503 try: 1504 if self._VIRTIO_NET_RE.search(devlist): 1505 nic_model = self._VIRTIO_NET_PCI 1506 vnet_hdr = up_hvp[constants.HV_VNET_HDR] 1507 except errors.HypervisorError, _: 1508 # Older versions of kvm don't support DEVICE_LIST, but they don't 1509 # have new virtio syntax either. 1510 pass 1511 1512 if up_hvp[constants.HV_VHOST_NET]: 1513 # Check for vhost_net support. 1514 if self._VHOST_RE.search(kvmhelp): 1515 tap_extra = ",vhost=on" 1516 else: 1517 raise errors.HypervisorError("vhost_net is configured" 1518 " but it is not available") 1519 if up_hvp[constants.HV_VIRTIO_NET_QUEUES] > 1: 1520 # Check for multiqueue virtio-net support. 1521 if self._VIRTIO_NET_QUEUES_RE.search(kvmhelp): 1522 virtio_net_queues = up_hvp[constants.HV_VIRTIO_NET_QUEUES] 1523 # As advised at http://www.linux-kvm.org/page/Multiqueue formula 1524 # for calculating vector size is: vectors=2*N+1 where N is the 1525 # number of queues (HV_VIRTIO_NET_QUEUES). 1526 nic_extra = ",mq=on,vectors=%d" % (2 * virtio_net_queues + 1) 1527 else: 1528 raise errors.HypervisorError("virtio_net_queues is configured" 1529 " but it is not available") 1530 else: 1531 nic_model = nic_type 1532 1533 return (nic_model, vnet_hdr, virtio_net_queues, tap_extra, nic_extra)
1534 1535 # too many local variables 1536 # pylint: disable=R0914
1537 - def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
1538 """Execute a KVM cmd, after completing it with some last minute data. 1539 1540 @type incoming: tuple of strings 1541 @param incoming: (target_host_ip, port) 1542 @type kvmhelp: string 1543 @param kvmhelp: output of kvm --help 1544 1545 """ 1546 # Small _ExecuteKVMRuntime hv parameters programming howto: 1547 # - conf_hvp contains the parameters as configured on ganeti. they might 1548 # have changed since the instance started; only use them if the change 1549 # won't affect the inside of the instance (which hasn't been rebooted). 1550 # - up_hvp contains the parameters as they were when the instance was 1551 # started, plus any new parameter which has been added between ganeti 1552 # versions: it is paramount that those default to a value which won't 1553 # affect the inside of the instance as well. 1554 conf_hvp = instance.hvparams 1555 name = instance.name 1556 self._CheckDown(name) 1557 1558 self._ClearUserShutdown(instance.name) 1559 self._StartKvmd(instance.hvparams) 1560 1561 temp_files = [] 1562 1563 kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime 1564 # the first element of kvm_cmd is always the path to the kvm binary 1565 kvm_path = kvm_cmd[0] 1566 up_hvp = objects.FillDict(conf_hvp, up_hvp) 1567 1568 # We know it's safe to run as a different user upon migration, so we'll use 1569 # the latest conf, from conf_hvp. 1570 security_model = conf_hvp[constants.HV_SECURITY_MODEL] 1571 if security_model == constants.HT_SM_USER: 1572 kvm_cmd.extend(["-runas", conf_hvp[constants.HV_SECURITY_DOMAIN]]) 1573 1574 keymap = conf_hvp[constants.HV_KEYMAP] 1575 if keymap: 1576 keymap_path = self._InstanceKeymapFile(name) 1577 # If a keymap file is specified, KVM won't use its internal defaults. By 1578 # first including the "en-us" layout, an error on loading the actual 1579 # layout (e.g. because it can't be found) won't lead to a non-functional 1580 # keyboard. A keyboard with incorrect keys is still better than none. 1581 utils.WriteFile(keymap_path, data="include en-us\ninclude %s\n" % keymap) 1582 kvm_cmd.extend(["-k", keymap_path]) 1583 1584 # We have reasons to believe changing something like the nic driver/type 1585 # upon migration won't exactly fly with the instance kernel, so for nic 1586 # related parameters we'll use up_hvp 1587 tapfds = [] 1588 taps = [] 1589 devlist = self._GetKVMOutput(kvm_path, self._KVMOPT_DEVICELIST) 1590 if not kvm_nics: 1591 kvm_cmd.extend(["-net", "none"]) 1592 else: 1593 (nic_model, vnet_hdr, 1594 virtio_net_queues, tap_extra, 1595 nic_extra) = self._GetNetworkDeviceFeatures(up_hvp, devlist, kvmhelp) 1596 kvm_supports_netdev = self._NETDEV_RE.search(kvmhelp) 1597 for nic_seq, nic in enumerate(kvm_nics): 1598 tapname, nic_tapfds = OpenTap(vnet_hdr=vnet_hdr, 1599 virtio_net_queues=virtio_net_queues, 1600 name=self._GenerateKvmTapName(nic)) 1601 tapfds.extend(nic_tapfds) 1602 taps.append(tapname) 1603 tapfd = "%s%s" % ("fds=" if len(nic_tapfds) > 1 else "fd=", 1604 ":".join(str(fd) for fd in nic_tapfds)) 1605 if kvm_supports_netdev: 1606 nic_val = "%s,mac=%s" % (nic_model, nic.mac) 1607 try: 1608 # kvm_nics already exist in old runtime files and thus there might 1609 # be some entries without pci slot (therefore try: except:) 1610 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic) 1611 netdev = kvm_devid 1612 nic_val += (",id=%s,bus=pci.0,addr=%s" % (kvm_devid, hex(nic.pci))) 1613 except errors.HotplugError: 1614 netdev = "netdev%d" % nic_seq 1615 nic_val += (",netdev=%s%s" % (netdev, nic_extra)) 1616 tap_val = ("type=tap,id=%s,%s%s" % 1617 (netdev, tapfd, tap_extra)) 1618 kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val]) 1619 else: 1620 nic_val = "nic,vlan=%s,macaddr=%s,model=%s" % (nic_seq, 1621 nic.mac, nic_model) 1622 tap_val = "tap,vlan=%s,%s" % (nic_seq, tapfd) 1623 kvm_cmd.extend(["-net", tap_val, "-net", nic_val]) 1624 1625 if incoming: 1626 target, port = incoming 1627 kvm_cmd.extend(["-incoming", "tcp:%s:%s" % (target, port)]) 1628 1629 # Changing the vnc password doesn't bother the guest that much. At most it 1630 # will surprise people who connect to it. Whether positively or negatively 1631 # it's debatable. 1632 vnc_pwd_file = conf_hvp[constants.HV_VNC_PASSWORD_FILE] 1633 vnc_pwd = None 1634 if vnc_pwd_file: 1635 try: 1636 vnc_pwd = utils.ReadOneLineFile(vnc_pwd_file, strict=True) 1637 except EnvironmentError, err: 1638 raise errors.HypervisorError("Failed to open VNC password file %s: %s" 1639 % (vnc_pwd_file, err)) 1640 1641 if conf_hvp[constants.HV_KVM_USE_CHROOT]: 1642 utils.EnsureDirs([(self._InstanceChrootDir(name), 1643 constants.SECURE_DIR_MODE)]) 1644 1645 # Automatically enable QMP if version is >= 0.14 1646 if self._QMP_RE.search(kvmhelp): 1647 logging.debug("Enabling QMP") 1648 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" % 1649 self._InstanceQmpMonitor(instance.name)]) 1650 # Add a second monitor for kvmd 1651 kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" % 1652 self._InstanceKvmdMonitor(instance.name)]) 1653 1654 # Configure the network now for starting instances and bridged/OVS 1655 # interfaces, during FinalizeMigration for incoming instances' routed 1656 # interfaces. 1657 for nic_seq, nic in enumerate(kvm_nics): 1658 if (incoming and 1659 nic.nicparams[constants.NIC_MODE] == constants.NIC_MODE_ROUTED): 1660 continue 1661 self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq]) 1662 1663 bdev_opts = self._GenerateKVMBlockDevicesOptions(instance, 1664 up_hvp, 1665 kvm_disks, 1666 kvmhelp, 1667 devlist) 1668 kvm_cmd.extend(bdev_opts) 1669 # CPU affinity requires kvm to start paused, so we set this flag if the 1670 # instance is not already paused and if we are not going to accept a 1671 # migrating instance. In the latter case, pausing is not needed. 1672 start_kvm_paused = not (_KVM_START_PAUSED_FLAG in kvm_cmd) and not incoming 1673 if start_kvm_paused: 1674 kvm_cmd.extend([_KVM_START_PAUSED_FLAG]) 1675 1676 # Note: CPU pinning is using up_hvp since changes take effect 1677 # during instance startup anyway, and to avoid problems when soft 1678 # rebooting the instance. 1679 cpu_pinning = False 1680 if up_hvp.get(constants.HV_CPU_MASK, None): 1681 cpu_pinning = True 1682 1683 if security_model == constants.HT_SM_POOL: 1684 ss = ssconf.SimpleStore() 1685 uid_pool = uidpool.ParseUidPool(ss.GetUidPool(), separator="\n") 1686 all_uids = set(uidpool.ExpandUidPool(uid_pool)) 1687 uid = uidpool.RequestUnusedUid(all_uids) 1688 try: 1689 username = pwd.getpwuid(uid.GetUid()).pw_name 1690 kvm_cmd.extend(["-runas", username]) 1691 self._RunKVMCmd(name, kvm_cmd, tapfds) 1692 except: 1693 uidpool.ReleaseUid(uid) 1694 raise 1695 else: 1696 uid.Unlock() 1697 utils.WriteFile(self._InstanceUidFile(name), data=uid.AsStr()) 1698 else: 1699 self._RunKVMCmd(name, kvm_cmd, tapfds) 1700 1701 utils.EnsureDirs([(self._InstanceNICDir(instance.name), 1702 constants.RUN_DIRS_MODE)]) 1703 for nic_seq, tap in enumerate(taps): 1704 utils.WriteFile(self._InstanceNICFile(instance.name, nic_seq), 1705 data=tap) 1706 1707 if vnc_pwd: 1708 change_cmd = "change vnc password %s" % vnc_pwd 1709 self._CallMonitorCommand(instance.name, change_cmd) 1710 1711 # Setting SPICE password. We are not vulnerable to malicious passwordless 1712 # connection attempts because SPICE by default does not allow connections 1713 # if neither a password nor the "disable_ticketing" options are specified. 1714 # As soon as we send the password via QMP, that password is a valid ticket 1715 # for connection. 1716 spice_password_file = conf_hvp[constants.HV_KVM_SPICE_PASSWORD_FILE] 1717 if spice_password_file: 1718 spice_pwd = "" 1719 try: 1720 spice_pwd = utils.ReadOneLineFile(spice_password_file, strict=True) 1721 except EnvironmentError, err: 1722 raise errors.HypervisorError("Failed to open SPICE password file %s: %s" 1723 % (spice_password_file, err)) 1724 1725 qmp = QmpConnection(self._InstanceQmpMonitor(instance.name)) 1726 qmp.connect() 1727 arguments = { 1728 "protocol": "spice", 1729 "password": spice_pwd, 1730 } 1731 qmp.Execute("set_password", arguments) 1732 1733 for filename in temp_files: 1734 utils.RemoveFile(filename) 1735 1736 # If requested, set CPU affinity and resume instance execution 1737 if cpu_pinning: 1738 self._ExecuteCpuAffinity(instance.name, up_hvp[constants.HV_CPU_MASK]) 1739 1740 start_memory = self._InstanceStartupMemory(instance) 1741 if start_memory < instance.beparams[constants.BE_MAXMEM]: 1742 self.BalloonInstanceMemory(instance, start_memory) 1743 1744 if start_kvm_paused: 1745 # To control CPU pinning, ballooning, and vnc/spice passwords 1746 # the VM was started in a frozen state. If freezing was not 1747 # explicitly requested resume the vm status. 1748 self._CallMonitorCommand(instance.name, self._CONT_CMD)
1749 1750 @staticmethod
1751 - def _StartKvmd(hvparams):
1752 """Ensure that the Kvm daemon is running. 1753 1754 @type hvparams: dict of strings 1755 @param hvparams: hypervisor parameters 1756 1757 """ 1758 if hvparams is None \ 1759 or not hvparams[constants.HV_KVM_USER_SHUTDOWN] \ 1760 or utils.IsDaemonAlive(constants.KVMD): 1761 return 1762 1763 result = utils.RunCmd([pathutils.DAEMON_UTIL, "start", constants.KVMD]) 1764 1765 if result.failed: 1766 raise errors.HypervisorError("Failed to start KVM daemon")
1767
1768 - def StartInstance(self, instance, block_devices, startup_paused):
1769 """Start an instance. 1770 1771 """ 1772 self._CheckDown(instance.name) 1773 kvmpath = instance.hvparams[constants.HV_KVM_PATH] 1774 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP) 1775 kvm_runtime = self._GenerateKVMRuntime(instance, block_devices, 1776 startup_paused, kvmhelp) 1777 self._SaveKVMRuntime(instance, kvm_runtime) 1778 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
1779 1780 @classmethod
1781 - def _CallMonitorCommand(cls, instance_name, command, timeout=None):
1782 """Invoke a command on the instance monitor. 1783 1784 """ 1785 if timeout is not None: 1786 timeout_cmd = "timeout %s" % (timeout, ) 1787 else: 1788 timeout_cmd = "" 1789 1790 # TODO: Replace monitor calls with QMP once KVM >= 0.14 is the minimum 1791 # version. The monitor protocol is designed for human consumption, whereas 1792 # QMP is made for programmatic usage. In the worst case QMP can also 1793 # execute monitor commands. As it is, all calls to socat take at least 1794 # 500ms and likely more: socat can't detect the end of the reply and waits 1795 # for 500ms of no data received before exiting (500 ms is the default for 1796 # the "-t" parameter). 1797 socat = ("echo %s | %s %s STDIO UNIX-CONNECT:%s" % 1798 (utils.ShellQuote(command), 1799 timeout_cmd, 1800 constants.SOCAT_PATH, 1801 utils.ShellQuote(cls._InstanceMonitor(instance_name)))) 1802 result = utils.RunCmd(socat) 1803 if result.failed: 1804 msg = ("Failed to send command '%s' to instance '%s', reason '%s'," 1805 " output: %s" % 1806 (command, instance_name, result.fail_reason, result.output)) 1807 raise errors.HypervisorError(msg) 1808 1809 return result
1810
1811 - def _GetFreePCISlot(self, instance, dev):
1812 """Get the first available pci slot of a runnung instance. 1813 1814 """ 1815 slots = bitarray(32) 1816 slots.setall(False) # pylint: disable=E1101 1817 output = self._CallMonitorCommand(instance.name, self._INFO_PCI_CMD) 1818 for line in output.stdout.splitlines(): 1819 match = self._INFO_PCI_RE.search(line) 1820 if match: 1821 slot = int(match.group(1)) 1822 slots[slot] = True 1823 1824 dev.pci = _GetFreeSlot(slots)
1825
1826 - def VerifyHotplugSupport(self, instance, action, dev_type):
1827 """Verifies that hotplug is supported. 1828 1829 Hotplug is *not* supported in case of: 1830 - security models and chroot (disk hotplug) 1831 - fdsend module is missing (nic hot-add) 1832 1833 @raise errors.HypervisorError: in one of the previous cases 1834 1835 """ 1836 if dev_type == constants.HOTPLUG_TARGET_DISK: 1837 hvp = instance.hvparams 1838 security_model = hvp[constants.HV_SECURITY_MODEL] 1839 use_chroot = hvp[constants.HV_KVM_USE_CHROOT] 1840 if action == constants.HOTPLUG_ACTION_ADD: 1841 if use_chroot: 1842 raise errors.HotplugError("Disk hotplug is not supported" 1843 " in case of chroot.") 1844 if security_model != constants.HT_SM_NONE: 1845 raise errors.HotplugError("Disk Hotplug is not supported in case" 1846 " security models are used.") 1847 1848 if (dev_type == constants.HOTPLUG_TARGET_NIC and 1849 action == constants.HOTPLUG_ACTION_ADD and not fdsend): 1850 raise errors.HotplugError("Cannot hot-add NIC." 1851 " fdsend python module is missing.")
1852
1853 - def HotplugSupported(self, instance):
1854 """Checks if hotplug is generally supported. 1855 1856 Hotplug is *not* supported in case of: 1857 - qemu versions < 1.0 1858 - for stopped instances 1859 1860 @raise errors.HypervisorError: in one of the previous cases 1861 1862 """ 1863 try: 1864 output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD) 1865 except errors.HypervisorError: 1866 raise errors.HotplugError("Instance is probably down") 1867 1868 # TODO: search for netdev_add, drive_add, device_add..... 1869 match = self._INFO_VERSION_RE.search(output.stdout) 1870 if not match: 1871 raise errors.HotplugError("Cannot parse qemu version via monitor") 1872 1873 v_major, v_min, _, _ = match.groups() 1874 if (int(v_major), int(v_min)) < (1, 0): 1875 raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
1876
1877 - def _CallHotplugCommands(self, name, cmds):
1878 for c in cmds: 1879 self._CallMonitorCommand(name, c) 1880 time.sleep(1)
1881
1882 - def _VerifyHotplugCommand(self, instance_name, device, dev_type, 1883 should_exist):
1884 """Checks if a previous hotplug command has succeeded. 1885 1886 It issues info pci monitor command and checks depending on should_exist 1887 value if an entry with PCI slot and device ID is found or not. 1888 1889 @raise errors.HypervisorError: if result is not the expected one 1890 1891 """ 1892 output = self._CallMonitorCommand(instance_name, self._INFO_PCI_CMD) 1893 kvm_devid = _GenerateDeviceKVMId(dev_type, device) 1894 match = \ 1895 self._FIND_PCI_DEVICE_RE(device.pci, kvm_devid).search(output.stdout) 1896 if match and not should_exist: 1897 msg = "Device %s should have been removed but is still there" % kvm_devid 1898 raise errors.HypervisorError(msg) 1899 1900 if not match and should_exist: 1901 msg = "Device %s should have been added but is missing" % kvm_devid 1902 raise errors.HypervisorError(msg) 1903 1904 logging.info("Device %s has been correctly hot-plugged", kvm_devid)
1905
1906 - def HotAddDevice(self, instance, dev_type, device, extra, seq):
1907 """ Helper method to hot-add a new device 1908 1909 It gets free pci slot generates the device name and invokes the 1910 device specific method. 1911 1912 """ 1913 # in case of hot-mod this is given 1914 if device.pci is None: 1915 self._GetFreePCISlot(instance, device) 1916 kvm_devid = _GenerateDeviceKVMId(dev_type, device) 1917 runtime = self._LoadKVMRuntime(instance) 1918 if dev_type == constants.HOTPLUG_TARGET_DISK: 1919 drive_uri = _GetDriveURI(device, extra[0], extra[1]) 1920 cmds = ["drive_add dummy file=%s,if=none,id=%s,format=raw" % 1921 (drive_uri, kvm_devid)] 1922 cmds += ["device_add virtio-blk-pci,bus=pci.0,addr=%s,drive=%s,id=%s" % 1923 (hex(device.pci), kvm_devid, kvm_devid)] 1924 elif dev_type == constants.HOTPLUG_TARGET_NIC: 1925 kvmpath = instance.hvparams[constants.HV_KVM_PATH] 1926 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP) 1927 devlist = self._GetKVMOutput(kvmpath, self._KVMOPT_DEVICELIST) 1928 up_hvp = runtime[2] 1929 (_, vnet_hdr, 1930 virtio_net_queues, tap_extra, 1931 nic_extra) = self._GetNetworkDeviceFeatures(up_hvp, devlist, kvmhelp) 1932 (tap, fds) = OpenTap(vnet_hdr=vnet_hdr, 1933 virtio_net_queues=virtio_net_queues) 1934 # netdev_add don't support "fds=" when multiple fds are 1935 # requested, generate separate "fd=" string for every fd 1936 tapfd = ",".join(["fd=%s" % fd for fd in fds]) 1937 self._ConfigureNIC(instance, seq, device, tap) 1938 self._PassTapFd(instance, fds, device) 1939 cmds = ["netdev_add tap,id=%s,%s%s" % (kvm_devid, tapfd, tap_extra)] 1940 args = "virtio-net-pci,bus=pci.0,addr=%s,mac=%s,netdev=%s,id=%s%s" % \ 1941 (hex(device.pci), device.mac, kvm_devid, kvm_devid, nic_extra) 1942 cmds += ["device_add %s" % args] 1943 utils.WriteFile(self._InstanceNICFile(instance.name, seq), data=tap) 1944 1945 self._CallHotplugCommands(instance.name, cmds) 1946 self._VerifyHotplugCommand(instance.name, device, dev_type, True) 1947 # update relevant entries in runtime file 1948 index = _DEVICE_RUNTIME_INDEX[dev_type] 1949 entry = _RUNTIME_ENTRY[dev_type](device, extra) 1950 runtime[index].append(entry) 1951 self._SaveKVMRuntime(instance, runtime)
1952
1953 - def HotDelDevice(self, instance, dev_type, device, _, seq):
1954 """ Helper method for hot-del device 1955 1956 It gets device info from runtime file, generates the device name and 1957 invokes the device specific method. 1958 1959 """ 1960 runtime = self._LoadKVMRuntime(instance) 1961 entry = _GetExistingDeviceInfo(dev_type, device, runtime) 1962 kvm_device = _RUNTIME_DEVICE[dev_type](entry) 1963 kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device) 1964 if dev_type == constants.HOTPLUG_TARGET_DISK: 1965 cmds = ["device_del %s" % kvm_devid] 1966 cmds += ["drive_del %s" % kvm_devid] 1967 elif dev_type == constants.HOTPLUG_TARGET_NIC: 1968 cmds = ["device_del %s" % kvm_devid] 1969 cmds += ["netdev_del %s" % kvm_devid] 1970 utils.RemoveFile(self._InstanceNICFile(instance.name, seq)) 1971 self._CallHotplugCommands(instance.name, cmds) 1972 self._VerifyHotplugCommand(instance.name, kvm_device, dev_type, False) 1973 index = _DEVICE_RUNTIME_INDEX[dev_type] 1974 runtime[index].remove(entry) 1975 self._SaveKVMRuntime(instance, runtime) 1976 1977 return kvm_device.pci
1978
1979 - def HotModDevice(self, instance, dev_type, device, _, seq):
1980 """ Helper method for hot-mod device 1981 1982 It gets device info from runtime file, generates the device name and 1983 invokes the device specific method. Currently only NICs support hot-mod 1984 1985 """ 1986 if dev_type == constants.HOTPLUG_TARGET_NIC: 1987 # putting it back in the same pci slot 1988 device.pci = self.HotDelDevice(instance, dev_type, device, _, seq) 1989 self.HotAddDevice(instance, dev_type, device, _, seq)
1990
1991 - def _PassTapFd(self, instance, fds, nic):
1992 """Pass file descriptor to kvm process via monitor socket using SCM_RIGHTS 1993 1994 """ 1995 # TODO: factor out code related to unix sockets. 1996 # squash common parts between monitor and qmp 1997 kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_NIC, nic) 1998 command = "getfd %s\n" % kvm_devid 1999 logging.info("%s", fds) 2000 try: 2001 monsock = MonitorSocket(self._InstanceMonitor(instance.name)) 2002 monsock.connect() 2003 fdsend.sendfds(monsock.sock, command, fds=fds) 2004 finally: 2005 monsock.close()
2006 2007 @classmethod
2008 - def _ParseKVMVersion(cls, text):
2009 """Parse the KVM version from the --help output. 2010 2011 @type text: string 2012 @param text: output of kvm --help 2013 @return: (version, v_maj, v_min, v_rev) 2014 @raise errors.HypervisorError: when the KVM version cannot be retrieved 2015 2016 """ 2017 match = cls._VERSION_RE.search(text.splitlines()[0]) 2018 if not match: 2019 raise errors.HypervisorError("Unable to get KVM version") 2020 2021 v_all = match.group(0) 2022 v_maj = int(match.group(1)) 2023 v_min = int(match.group(2)) 2024 if match.group(4): 2025 v_rev = int(match.group(4)) 2026 else: 2027 v_rev = 0 2028 return (v_all, v_maj, v_min, v_rev)
2029 2030 @classmethod
2031 - def _GetKVMOutput(cls, kvm_path, option):
2032 """Return the output of a kvm invocation 2033 2034 @type kvm_path: string 2035 @param kvm_path: path to the kvm executable 2036 @type option: a key of _KVMOPTS_CMDS 2037 @param option: kvm option to fetch the output from 2038 @return: output a supported kvm invocation 2039 @raise errors.HypervisorError: when the KVM help output cannot be retrieved 2040 2041 """ 2042 assert option in cls._KVMOPTS_CMDS, "Invalid output option" 2043 2044 optlist, can_fail = cls._KVMOPTS_CMDS[option] 2045 2046 result = utils.RunCmd([kvm_path] + optlist) 2047 if result.failed and not can_fail: 2048 raise errors.HypervisorError("Unable to get KVM %s output" % 2049 " ".join(optlist)) 2050 return result.output
2051 2052 @classmethod
2053 - def _GetKVMVersion(cls, kvm_path):
2054 """Return the installed KVM version. 2055 2056 @return: (version, v_maj, v_min, v_rev) 2057 @raise errors.HypervisorError: when the KVM version cannot be retrieved 2058 2059 """ 2060 return cls._ParseKVMVersion(cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP))
2061 2062 @classmethod
2063 - def _GetDefaultMachineVersion(cls, kvm_path):
2064 """Return the default hardware revision (e.g. pc-1.1) 2065 2066 """ 2067 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST) 2068 match = cls._DEFAULT_MACHINE_VERSION_RE.search(output) 2069 if match: 2070 return match.group(1) 2071 else: 2072 return "pc"
2073 2074 @classmethod
2075 - def _StopInstance(cls, instance, force=False, name=None, timeout=None):
2076 """Stop an instance. 2077 2078 """ 2079 assert(timeout is None or force is not None) 2080 2081 if name is not None and not force: 2082 raise errors.HypervisorError("Cannot shutdown cleanly by name only") 2083 if name is None: 2084 name = instance.name 2085 acpi = instance.hvparams[constants.HV_ACPI] 2086 else: 2087 acpi = False 2088 _, pid, alive = cls._InstancePidAlive(name) 2089 if pid > 0 and alive: 2090 if force or not acpi: 2091 utils.KillProcess(pid) 2092 else: 2093 cls._CallMonitorCommand(name, "system_powerdown", timeout) 2094 cls._ClearUserShutdown(instance.name)
2095
2096 - def StopInstance(self, instance, force=False, retry=False, name=None, 2097 timeout=None):
2098 """Stop an instance. 2099 2100 """ 2101 self._StopInstance(instance, force, name=name, timeout=timeout)
2102
2103 - def CleanupInstance(self, instance_name):
2104 """Cleanup after a stopped instance 2105 2106 """ 2107 pidfile, pid, alive = self._InstancePidAlive(instance_name) 2108 if pid > 0 and alive: 2109 raise errors.HypervisorError("Cannot cleanup a live instance") 2110 self._RemoveInstanceRuntimeFiles(pidfile, instance_name) 2111 self._ClearUserShutdown(instance_name)
2112
2113 - def RebootInstance(self, instance):
2114 """Reboot an instance. 2115 2116 """ 2117 # For some reason if we do a 'send-key ctrl-alt-delete' to the control 2118 # socket the instance will stop, but now power up again. So we'll resort 2119 # to shutdown and restart. 2120 _, _, alive = self._InstancePidAlive(instance.name) 2121 if not alive: 2122 raise errors.HypervisorError("Failed to reboot instance %s:" 2123 " not running" % instance.name) 2124 # StopInstance will delete the saved KVM runtime so: 2125 # ...first load it... 2126 kvm_runtime = self._LoadKVMRuntime(instance) 2127 # ...now we can safely call StopInstance... 2128 if not self.StopInstance(instance): 2129 self.StopInstance(instance, force=True) 2130 # ...and finally we can save it again, and execute it... 2131 self._SaveKVMRuntime(instance, kvm_runtime) 2132 kvmpath = instance.hvparams[constants.HV_KVM_PATH] 2133 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP) 2134 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp)
2135
2136 - def MigrationInfo(self, instance):
2137 """Get instance information to perform a migration. 2138 2139 @type instance: L{objects.Instance} 2140 @param instance: instance to be migrated 2141 @rtype: string 2142 @return: content of the KVM runtime file 2143 2144 """ 2145 return self._ReadKVMRuntime(instance.name)
2146
2147 - def AcceptInstance(self, instance, info, target):
2148 """Prepare to accept an instance. 2149 2150 @type instance: L{objects.Instance} 2151 @param instance: instance to be accepted 2152 @type info: string 2153 @param info: content of the KVM runtime file on the source node 2154 @type target: string 2155 @param target: target host (usually ip), on this node 2156 2157 """ 2158 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info) 2159 incoming_address = (target, instance.hvparams[constants.HV_MIGRATION_PORT]) 2160 kvmpath = instance.hvparams[constants.HV_KVM_PATH] 2161 kvmhelp = self._GetKVMOutput(kvmpath, self._KVMOPT_HELP) 2162 self._ExecuteKVMRuntime(instance, kvm_runtime, kvmhelp, 2163 incoming=incoming_address)
2164
2165 - def FinalizeMigrationDst(self, instance, info, success):
2166 """Finalize the instance migration on the target node. 2167 2168 Stop the incoming mode KVM. 2169 2170 @type instance: L{objects.Instance} 2171 @param instance: instance whose migration is being finalized 2172 2173 """ 2174 if success: 2175 kvm_runtime = self._LoadKVMRuntime(instance, serialized_runtime=info) 2176 kvm_nics = kvm_runtime[1] 2177 2178 for nic_seq, nic in enumerate(kvm_nics): 2179 if nic.nicparams[constants.NIC_MODE] != constants.NIC_MODE_ROUTED: 2180 # Bridged/OVS interfaces have already been configured 2181 continue 2182 try: 2183 tap = utils.ReadFile(self._InstanceNICFile(instance.name, nic_seq)) 2184 except EnvironmentError, err: 2185 logging.warning("Failed to find host interface for %s NIC #%d: %s", 2186 instance.name, nic_seq, str(err)) 2187 continue 2188 try: 2189 self._ConfigureNIC(instance, nic_seq, nic, tap) 2190 except errors.HypervisorError, err: 2191 logging.warning(str(err)) 2192 2193 self._WriteKVMRuntime(instance.name, info) 2194 else: 2195 self.StopInstance(instance, force=True)
2196
2197 - def MigrateInstance(self, cluster_name, instance, target, live):
2198 """Migrate an instance to a target node. 2199 2200 The migration will not be attempted if the instance is not 2201 currently running. 2202 2203 @type cluster_name: string 2204 @param cluster_name: name of the cluster 2205 @type instance: L{objects.Instance} 2206 @param instance: the instance to be migrated 2207 @type target: string 2208 @param target: ip address of the target node 2209 @type live: boolean 2210 @param live: perform a live migration 2211 2212 """ 2213 instance_name = instance.name 2214 port = instance.hvparams[constants.HV_MIGRATION_PORT] 2215 _, _, alive = self._InstancePidAlive(instance_name) 2216 if not alive: 2217 raise errors.HypervisorError("Instance not running, cannot migrate") 2218 2219 if not live: 2220 self._CallMonitorCommand(instance_name, "stop") 2221 2222 migrate_command = ("migrate_set_speed %dm" % 2223 instance.hvparams[constants.HV_MIGRATION_BANDWIDTH]) 2224 self._CallMonitorCommand(instance_name, migrate_command) 2225 2226 migrate_command = ("migrate_set_downtime %dms" % 2227 instance.hvparams[constants.HV_MIGRATION_DOWNTIME]) 2228 self._CallMonitorCommand(instance_name, migrate_command) 2229 2230 migration_caps = instance.hvparams[constants.HV_KVM_MIGRATION_CAPS] 2231 if migration_caps: 2232 for c in migration_caps.split(_MIGRATION_CAPS_DELIM): 2233 migrate_command = ("migrate_set_capability %s on" % c) 2234 self._CallMonitorCommand(instance_name, migrate_command) 2235 2236 migrate_command = "migrate -d tcp:%s:%s" % (target, port) 2237 self._CallMonitorCommand(instance_name, migrate_command)
2238
2239 - def FinalizeMigrationSource(self, instance, success, live):
2240 """Finalize the instance migration on the source node. 2241 2242 @type instance: L{objects.Instance} 2243 @param instance: the instance that was migrated 2244 @type success: bool 2245 @param success: whether the migration succeeded or not 2246 @type live: bool 2247 @param live: whether the user requested a live migration or not 2248 2249 """ 2250 if success: 2251 pidfile, pid, _ = self._InstancePidAlive(instance.name) 2252 utils.KillProcess(pid) 2253 self._RemoveInstanceRuntimeFiles(pidfile, instance.name) 2254 elif live: 2255 self._CallMonitorCommand(instance.name, self._CONT_CMD) 2256 self._ClearUserShutdown(instance.name)
2257
2258 - def GetMigrationStatus(self, instance):
2259 """Get the migration status 2260 2261 @type instance: L{objects.Instance} 2262 @param instance: the instance that is being migrated 2263 @rtype: L{objects.MigrationStatus} 2264 @return: the status of the current migration (one of 2265 L{constants.HV_MIGRATION_VALID_STATUSES}), plus any additional 2266 progress info that can be retrieved from the hypervisor 2267 2268 """ 2269 info_command = "info migrate" 2270 for _ in range(self._MIGRATION_INFO_MAX_BAD_ANSWERS): 2271 result = self._CallMonitorCommand(instance.name, info_command) 2272 match = self._MIGRATION_STATUS_RE.search(result.stdout) 2273 if not match: 2274 if not result.stdout: 2275 logging.info("KVM: empty 'info migrate' result") 2276 else: 2277 logging.warning("KVM: unknown 'info migrate' result: %s", 2278 result.stdout) 2279 else: 2280 status = match.group(1) 2281 if status in constants.HV_KVM_MIGRATION_VALID_STATUSES: 2282 migration_status = objects.MigrationStatus(status=status) 2283 match = self._MIGRATION_PROGRESS_RE.search(result.stdout) 2284 if match: 2285 migration_status.transferred_ram = match.group("transferred") 2286 migration_status.total_ram = match.group("total") 2287 2288 return migration_status 2289 2290 logging.warning("KVM: unknown migration status '%s'", status) 2291 2292 time.sleep(self._MIGRATION_INFO_RETRY_DELAY) 2293 2294 return objects.MigrationStatus(status=constants.HV_MIGRATION_FAILED)
2295
2296 - def BalloonInstanceMemory(self, instance, mem):
2297 """Balloon an instance memory to a certain value. 2298 2299 @type instance: L{objects.Instance} 2300 @param instance: instance to be accepted 2301 @type mem: int 2302 @param mem: actual memory size to use for instance runtime 2303 2304 """ 2305 self._CallMonitorCommand(instance.name, "balloon %d" % mem)
2306
2307 - def GetNodeInfo(self, hvparams=None):
2308 """Return information about the node. 2309 2310 @type hvparams: dict of strings 2311 @param hvparams: hypervisor parameters, not used in this class 2312 2313 @return: a dict as returned by L{BaseHypervisor.GetLinuxNodeInfo} plus 2314 the following keys: 2315 - hv_version: the hypervisor version in the form (major, minor, 2316 revision) 2317 2318 """ 2319 result = self.GetLinuxNodeInfo() 2320 kvmpath = constants.KVM_PATH 2321 if hvparams is not None: 2322 kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH) 2323 _, v_major, v_min, v_rev = self._GetKVMVersion(kvmpath) 2324 result[constants.HV_NODEINFO_KEY_VERSION] = (v_major, v_min, v_rev) 2325 return result
2326 2327 @classmethod
2328 - def GetInstanceConsole(cls, instance, primary_node, node_group, 2329 hvparams, beparams):
2330 """Return a command for connecting to the console of an instance. 2331 2332 """ 2333 if hvparams[constants.HV_SERIAL_CONSOLE]: 2334 cmd = [pathutils.KVM_CONSOLE_WRAPPER, 2335 constants.SOCAT_PATH, utils.ShellQuote(instance.name), 2336 utils.ShellQuote(cls._InstanceMonitor(instance.name)), 2337 "STDIO,%s" % cls._SocatUnixConsoleParams(), 2338 "UNIX-CONNECT:%s" % cls._InstanceSerial(instance.name)] 2339 ndparams = node_group.FillND(primary_node) 2340 return objects.InstanceConsole(instance=instance.name, 2341 kind=constants.CONS_SSH, 2342 host=primary_node.name, 2343 port=ndparams.get(constants.ND_SSH_PORT), 2344 user=constants.SSH_CONSOLE_USER, 2345 command=cmd) 2346 2347 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS] 2348 if vnc_bind_address and instance.network_port > constants.VNC_BASE_PORT: 2349 display = instance.network_port - constants.VNC_BASE_PORT 2350 return objects.InstanceConsole(instance=instance.name, 2351 kind=constants.CONS_VNC, 2352 host=vnc_bind_address, 2353 port=instance.network_port, 2354 display=display) 2355 2356 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND] 2357 if spice_bind: 2358 return objects.InstanceConsole(instance=instance.name, 2359 kind=constants.CONS_SPICE, 2360 host=spice_bind, 2361 port=instance.network_port) 2362 2363 return objects.InstanceConsole(instance=instance.name, 2364 kind=constants.CONS_MESSAGE, 2365 message=("No serial shell for instance %s" % 2366 instance.name))
2367
2368 - def Verify(self, hvparams=None):
2369 """Verify the hypervisor. 2370 2371 Check that the required binaries exist. 2372 2373 @type hvparams: dict of strings 2374 @param hvparams: hypervisor parameters to be verified against, not used here 2375 2376 @return: Problem description if something is wrong, C{None} otherwise 2377 2378 """ 2379 msgs = [] 2380 kvmpath = constants.KVM_PATH 2381 if hvparams is not None: 2382 kvmpath = hvparams.get(constants.HV_KVM_PATH, constants.KVM_PATH) 2383 if not os.path.exists(kvmpath): 2384 msgs.append("The KVM binary ('%s') does not exist" % kvmpath) 2385 if not os.path.exists(constants.SOCAT_PATH): 2386 msgs.append("The socat binary ('%s') does not exist" % 2387 constants.SOCAT_PATH) 2388 2389 return self._FormatVerifyResults(msgs)
2390 2391 @classmethod
2392 - def CheckParameterSyntax(cls, hvparams):
2393 """Check the given parameters for validity. 2394 2395 @type hvparams: dict of strings 2396 @param hvparams: hypervisor parameters 2397 @raise errors.HypervisorError: when a parameter is not valid 2398 2399 """ 2400 super(KVMHypervisor, cls).CheckParameterSyntax(hvparams) 2401 2402 kernel_path = hvparams[constants.HV_KERNEL_PATH] 2403 if kernel_path: 2404 if not hvparams[constants.HV_ROOT_PATH]: 2405 raise errors.HypervisorError("Need a root partition for the instance," 2406 " if a kernel is defined") 2407 2408 if (hvparams[constants.HV_VNC_X509_VERIFY] and 2409 not hvparams[constants.HV_VNC_X509]): 2410 raise errors.HypervisorError("%s must be defined, if %s is" % 2411 (constants.HV_VNC_X509, 2412 constants.HV_VNC_X509_VERIFY)) 2413 2414 if hvparams[constants.HV_SERIAL_CONSOLE]: 2415 serial_speed = hvparams[constants.HV_SERIAL_SPEED] 2416 valid_speeds = constants.VALID_SERIAL_SPEEDS 2417 if not serial_speed or serial_speed not in valid_speeds: 2418 raise errors.HypervisorError("Invalid serial console speed, must be" 2419 " one of: %s" % 2420 utils.CommaJoin(valid_speeds)) 2421 2422 boot_order = hvparams[constants.HV_BOOT_ORDER] 2423 if (boot_order == constants.HT_BO_CDROM and 2424 not hvparams[constants.HV_CDROM_IMAGE_PATH]): 2425 raise errors.HypervisorError("Cannot boot from cdrom without an" 2426 " ISO path") 2427 2428 security_model = hvparams[constants.HV_SECURITY_MODEL] 2429 if security_model == constants.HT_SM_USER: 2430 if not hvparams[constants.HV_SECURITY_DOMAIN]: 2431 raise errors.HypervisorError("A security domain (user to run kvm as)" 2432 " must be specified") 2433 elif (security_model == constants.HT_SM_NONE or 2434 security_model == constants.HT_SM_POOL): 2435 if hvparams[constants.HV_SECURITY_DOMAIN]: 2436 raise errors.HypervisorError("Cannot have a security domain when the" 2437 " security model is 'none' or 'pool'") 2438 2439 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND] 2440 spice_ip_version = hvparams[constants.HV_KVM_SPICE_IP_VERSION] 2441 if spice_bind: 2442 if spice_ip_version != constants.IFACE_NO_IP_VERSION_SPECIFIED: 2443 # if an IP version is specified, the spice_bind parameter must be an 2444 # IP of that family 2445 if (netutils.IP4Address.IsValid(spice_bind) and 2446 spice_ip_version != constants.IP4_VERSION): 2447 raise errors.HypervisorError("SPICE: Got an IPv4 address (%s), but" 2448 " the specified IP version is %s" % 2449 (spice_bind, spice_ip_version)) 2450 2451 if (netutils.IP6Address.IsValid(spice_bind) and 2452 spice_ip_version != constants.IP6_VERSION): 2453 raise errors.HypervisorError("SPICE: Got an IPv6 address (%s), but" 2454 " the specified IP version is %s" % 2455 (spice_bind, spice_ip_version)) 2456 else: 2457 # All the other SPICE parameters depend on spice_bind being set. Raise an 2458 # error if any of them is set without it. 2459 for param in _SPICE_ADDITIONAL_PARAMS: 2460 if hvparams[param]: 2461 raise errors.HypervisorError("SPICE: %s requires %s to be set" % 2462 (param, constants.HV_KVM_SPICE_BIND))
2463 2464 @classmethod
2465 - def ValidateParameters(cls, hvparams):
2466 """Check the given parameters for validity. 2467 2468 @type hvparams: dict of strings 2469 @param hvparams: hypervisor parameters 2470 @raise errors.HypervisorError: when a parameter is not valid 2471 2472 """ 2473 super(KVMHypervisor, cls).ValidateParameters(hvparams) 2474 2475 kvm_path = hvparams[constants.HV_KVM_PATH] 2476 2477 security_model = hvparams[constants.HV_SECURITY_MODEL] 2478 if security_model == constants.HT_SM_USER: 2479 username = hvparams[constants.HV_SECURITY_DOMAIN] 2480 try: 2481 pwd.getpwnam(username) 2482 except KeyError: 2483 raise errors.HypervisorError("Unknown security domain user %s" 2484 % username) 2485 vnc_bind_address = hvparams[constants.HV_VNC_BIND_ADDRESS] 2486 if vnc_bind_address: 2487 bound_to_addr = netutils.IP4Address.IsValid(vnc_bind_address) 2488 is_interface = netutils.IsValidInterface(vnc_bind_address) 2489 is_path = utils.IsNormAbsPath(vnc_bind_address) 2490 if not bound_to_addr and not is_interface and not is_path: 2491 raise errors.HypervisorError("VNC: The %s parameter must be either" 2492 " a valid IP address, an interface name," 2493 " or an absolute path" % 2494 constants.HV_KVM_SPICE_BIND) 2495 2496 spice_bind = hvparams[constants.HV_KVM_SPICE_BIND] 2497 if spice_bind: 2498 # only one of VNC and SPICE can be used currently. 2499 if hvparams[constants.HV_VNC_BIND_ADDRESS]: 2500 raise errors.HypervisorError("Both SPICE and VNC are configured, but" 2501 " only one of them can be used at a" 2502 " given time") 2503 2504 # check that KVM supports SPICE 2505 kvmhelp = cls._GetKVMOutput(kvm_path, cls._KVMOPT_HELP) 2506 if not cls._SPICE_RE.search(kvmhelp): 2507 raise errors.HypervisorError("SPICE is configured, but it is not" 2508 " supported according to 'kvm --help'") 2509 2510 # if spice_bind is not an IP address, it must be a valid interface 2511 bound_to_addr = (netutils.IP4Address.IsValid(spice_bind) or 2512 netutils.IP6Address.IsValid(spice_bind)) 2513 if not bound_to_addr and not netutils.IsValidInterface(spice_bind): 2514 raise errors.HypervisorError("SPICE: The %s parameter must be either" 2515 " a valid IP address or interface name" % 2516 constants.HV_KVM_SPICE_BIND) 2517 2518 machine_version = hvparams[constants.HV_KVM_MACHINE_VERSION] 2519 if machine_version: 2520 output = cls._GetKVMOutput(kvm_path, cls._KVMOPT_MLIST) 2521 if not cls._CHECK_MACHINE_VERSION_RE(machine_version).search(output): 2522 raise errors.HypervisorError("Unsupported machine version: %s" % 2523 machine_version)
2524 2525 @classmethod
2526 - def PowercycleNode(cls, hvparams=None):
2527 """KVM powercycle, just a wrapper over Linux powercycle. 2528 2529 @type hvparams: dict of strings 2530 @param hvparams: hypervisor parameters to be used on this node 2531 2532 """ 2533 cls.LinuxPowercycle()
2534