(2.10) Export tags via GetTags() to network scripts
[ganeti-local] / lib / hypervisor / hv_kvm.py
index 19b8a81..4551164 100644 (file)
@@ -90,7 +90,8 @@ _AVAILABLE_PCI_SLOT = bitarray("0")
 
 # below constants show the format of runtime file
 # the nics are in second possition, while the disks in 4th (last)
-# moreover disk entries are stored in tupples of L{objects.Disk}, dev_path
+# moreover disk entries are stored as a list of in tuples
+# (L{objects.Disk}, link_name)
 _KVM_NICS_RUNTIME_INDEX = 1
 _KVM_DISKS_RUNTIME_INDEX = 3
 _DEVICE_RUNTIME_INDEX = {
@@ -198,16 +199,16 @@ def _AnalyzeSerializedRuntime(serialized_runtime):
   """
   loaded_runtime = serializer.Load(serialized_runtime)
   if len(loaded_runtime) == 3:
-    serialized_blockdevs = []
+    serialized_disks = []
     kvm_cmd, serialized_nics, hvparams = loaded_runtime
   else:
-    kvm_cmd, serialized_nics, hvparams, serialized_blockdevs = loaded_runtime
+    kvm_cmd, serialized_nics, hvparams, serialized_disks = loaded_runtime
 
   kvm_nics = [objects.NIC.FromDict(snic) for snic in serialized_nics]
-  block_devices = [(objects.Disk.FromDict(sdisk), link)
-                   for sdisk, link in serialized_blockdevs]
+  kvm_disks = [(objects.Disk.FromDict(sdisk), link)
+               for sdisk, link in serialized_disks]
 
-  return (kvm_cmd, kvm_nics, hvparams, block_devices)
+  return (kvm_cmd, kvm_nics, hvparams, kvm_disks)
 
 
 def _GetTunFeatures(fd, _ioctl=fcntl.ioctl):
@@ -990,11 +991,6 @@ class KVMHypervisor(hv_base.BaseHypervisor):
     @type tap: str
 
     """
-    if instance.tags:
-      tags = " ".join(instance.tags)
-    else:
-      tags = ""
-
     env = {
       "PATH": "%s:/sbin:/usr/sbin" % os.environ["PATH"],
       "INSTANCE": instance.name,
@@ -1002,7 +998,7 @@ class KVMHypervisor(hv_base.BaseHypervisor):
       "MODE": nic.nicparams[constants.NIC_MODE],
       "INTERFACE": tap,
       "INTERFACE_INDEX": str(seq),
-      "TAGS": tags,
+      "TAGS": " ".join(instance.GetTags()),
     }
 
     if nic.ip:
@@ -1184,14 +1180,14 @@ class KVMHypervisor(hv_base.BaseHypervisor):
         data.append(info)
     return data
 
-  def _GenerateKVMBlockDevicesOptions(self, instance, block_devices,
+  def _GenerateKVMBlockDevicesOptions(self, instance, kvm_disks,
                                       kvmhelp, devlist):
     """Generate KVM options regarding instance's block devices.
 
     @type instance: L{objects.Instance}
     @param instance: the instance object
-    @type block_devices: list of tuples
-    @param block_devices: list of tuples [(disk, link_name, uri)..]
+    @type kvm_disks: list of tuples
+    @param kvm_disks: list of tuples [(disk, link_name)..]
     @type kvmhelp: string
     @param kvmhelp: output of kvm --help
     @type devlist: string
@@ -1206,7 +1202,6 @@ class KVMHypervisor(hv_base.BaseHypervisor):
       boot_disk = False
     else:
       boot_disk = hvp[constants.HV_BOOT_ORDER] == constants.HT_BO_DISK
-    kvm_path = hvp[constants.HV_KVM_PATH]
 
     # whether this is an older KVM version that uses the boot=on flag
     # on devices
@@ -1239,7 +1234,7 @@ class KVMHypervisor(hv_base.BaseHypervisor):
       cache_val = ",cache=%s" % disk_cache
     else:
       cache_val = ""
-    for cfdev, dev_path in block_devices:
+    for cfdev, link_name in kvm_disks:
       if cfdev.mode != constants.DISK_RDWR:
         raise errors.HypervisorError("Instance has read-only disks which"
                                      " are not supported by KVM")
@@ -1254,7 +1249,7 @@ class KVMHypervisor(hv_base.BaseHypervisor):
                   (dev_path, if_val, boot_val, cache_val)
 
       if device_driver:
-        # block_devices are the 4th entry of runtime file that did not exist in
+        # kvm_disks are the 4th entry of runtime file that did not exist in
         # the past. That means that cfdev should always have pci slot and
         # _GenerateDeviceKVMId() will not raise a exception.
         kvm_devid = _GenerateDeviceKVMId(constants.HOTPLUG_TARGET_DISK, cfdev)
@@ -1644,13 +1639,13 @@ class KVMHypervisor(hv_base.BaseHypervisor):
     """Save an instance's KVM runtime
 
     """
-    kvm_cmd, kvm_nics, hvparams, block_devices = kvm_runtime
+    kvm_cmd, kvm_nics, hvparams, kvm_disks = kvm_runtime
 
     serialized_nics = [nic.ToDict() for nic in kvm_nics]
-    serialized_blockdevs = [(blk.ToDict(), link)
-                            for blk, link in block_devices]
+    serialized_disks = [(blk.ToDict(), link)
+                            for blk, link in kvm_disks]
     serialized_form = serializer.Dump((kvm_cmd, serialized_nics, hvparams,
-                                      serialized_blockdevs))
+                                      serialized_disks))
 
     self._WriteKVMRuntime(instance.name, serialized_form)
 
@@ -1686,7 +1681,7 @@ class KVMHypervisor(hv_base.BaseHypervisor):
     if not self._InstancePidAlive(name)[2]:
       raise errors.HypervisorError("Failed to start instance %s" % name)
 
-  # 52/50 local variables
+  # too many local variables
   # pylint: disable=R0914
   def _ExecuteKVMRuntime(self, instance, kvm_runtime, kvmhelp, incoming=None):
     """Execute a KVM cmd, after completing it with some last minute data.
@@ -1711,7 +1706,7 @@ class KVMHypervisor(hv_base.BaseHypervisor):
 
     temp_files = []
 
-    kvm_cmd, kvm_nics, up_hvp, block_devices = kvm_runtime
+    kvm_cmd, kvm_nics, up_hvp, kvm_disks = kvm_runtime
     # the first element of kvm_cmd is always the path to the kvm binary
     kvm_path = kvm_cmd[0]
     up_hvp = objects.FillDict(conf_hvp, up_hvp)
@@ -1826,7 +1821,7 @@ class KVMHypervisor(hv_base.BaseHypervisor):
       self._ConfigureNIC(instance, nic_seq, nic, taps[nic_seq])
 
     bdev_opts = self._GenerateKVMBlockDevicesOptions(instance,
-                                                     block_devices,
+                                                     kvm_disks,
                                                      kvmhelp,
                                                      devlist)
     kvm_cmd.extend(bdev_opts)
@@ -1966,26 +1961,16 @@ class KVMHypervisor(hv_base.BaseHypervisor):
 
     dev.pci = int(free)
 
-  def HotplugSupported(self, instance, action, dev_type):
-    """Check if hotplug is supported.
+  def VerifyHotplugSupport(self, instance, action, dev_type):
+    """Verifies that hotplug is supported.
 
     Hotplug is *not* supported in case of:
-     - qemu versions < 1.0
      - security models and chroot (disk hotplug)
      - fdsend module is missing (nic hot-add)
 
-    @raise errors.HypervisorError: in previous cases
+    @raise errors.HypervisorError: in one of the previous cases
 
     """
-    output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
-    # TODO: search for netdev_add, drive_add, device_add.....
-    match = self._INFO_VERSION_RE.search(output.stdout)
-    if not match:
-      raise errors.HotplugError("Try hotplug only in running instances.")
-    v_major, v_min, _, _ = match.groups()
-    if (int(v_major), int(v_min)) < (1, 0):
-      raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
-
     if dev_type == constants.HOTPLUG_TARGET_DISK:
       hvp = instance.hvparams
       security_model = hvp[constants.HV_SECURITY_MODEL]
@@ -2001,7 +1986,30 @@ class KVMHypervisor(hv_base.BaseHypervisor):
         action == constants.HOTPLUG_ACTION_ADD and not fdsend):
       raise errors.HotplugError("Cannot hot-add NIC."
                                 " fdsend python module is missing.")
-    return True
+
+  def HotplugSupported(self, instance):
+    """Checks if hotplug is generally supported.
+
+    Hotplug is *not* supported in case of:
+     - qemu versions < 1.0
+     - for stopped instances
+
+    @raise errors.HypervisorError: in one of the previous cases
+
+    """
+    try:
+      output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
+    except errors.HypervisorError:
+      raise errors.HotplugError("Instance is probably down")
+
+    # TODO: search for netdev_add, drive_add, device_add.....
+    match = self._INFO_VERSION_RE.search(output.stdout)
+    if not match:
+      raise errors.HotplugError("Cannot parse qemu version via monitor")
+
+    v_major, v_min, _, _ = match.groups()
+    if (int(v_major), int(v_min)) < (1, 0):
+      raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
 
   def _CallHotplugCommand(self, name, cmd):
     output = self._CallMonitorCommand(name, cmd)
@@ -2055,7 +2063,8 @@ class KVMHypervisor(hv_base.BaseHypervisor):
     kvm_device = _RUNTIME_DEVICE[dev_type](entry)
     kvm_devid = _GenerateDeviceKVMId(dev_type, kvm_device)
     if dev_type == constants.HOTPLUG_TARGET_DISK:
-      command = "device_del %s" % kvm_devid
+      command = "device_del %s\n" % kvm_devid
+      command += "drive_del %s" % kvm_devid
     elif dev_type == constants.HOTPLUG_TARGET_NIC:
       command = "device_del %s\n" % kvm_devid
       command += "netdev_del %s" % kvm_devid