Revision 24711492

b/lib/backend.py
2003 2003
  return fn(instance, dev_type, device, extra, seq)
2004 2004

  
2005 2005

  
2006
def HotplugSupported(instance):
2007
  """Checks if hotplug is generally supported.
2008

  
2009
  """
2010
  hyper = hypervisor.GetHypervisor(instance.hypervisor)
2011
  try:
2012
    hyper.HotplugSupported(instance)
2013
  except errors.HotplugError, err:
2014
    _Fail("Hotplug is not supported: %s", err)
2015

  
2016

  
2006 2017
def BlockdevCreate(disk, size, owner, on_primary, info, excl_stor):
2007 2018
  """Creates a block device for an instance.
2008 2019

  
b/lib/cmdlib/instance.py
2843 2843
    # dictionary with instance information after the modification
2844 2844
    ispec = {}
2845 2845

  
2846
    if self.op.hotplug:
2847
      result = self.rpc.call_hotplug_supported(self.instance.primary_node,
2848
                                               self.instance)
2849
      result.Raise("Hotplug is not supported.")
2850

  
2846 2851
    # Prepare NIC modifications
2847 2852
    self.nicmod = _PrepareContainerMods(self.op.nics, _InstNicModPrivate)
2848 2853

  
b/lib/hypervisor/hv_base.py
589 589
  def VerifyHotplugSupport(self, instance, action, dev_type):
590 590
    """Verifies that hotplug is supported.
591 591

  
592
    Hotplug is not supported by default. If a hypervisor wants to support
593
    it it should override this method.
592
    Given the target device and hotplug action checks if hotplug is
593
    actually supported.
594 594

  
595 595
    @type instance: L{objects.Instance}
596 596
    @param instance: the instance object
......
601 601
    @raise errors.HotplugError: if hotplugging is not supported
602 602

  
603 603
    """
604
    raise errors.HotplugError("Hotplug is not supported.")
605

  
606
  def HotplugSupported(self, instance):
607
    """Checks if hotplug is supported.
608

  
609
    By default is not. Currently only KVM hypervisor supports it.
610

  
611
    """
604 612
    raise errors.HotplugError("Hotplug is not supported by this hypervisor")
b/lib/hypervisor/hv_kvm.py
2003 2003
    """Verifies that hotplug is supported.
2004 2004

  
2005 2005
    Hotplug is *not* supported in case of:
2006
     - qemu versions < 1.0
2007 2006
     - security models and chroot (disk hotplug)
2008 2007
     - fdsend module is missing (nic hot-add)
2009 2008

  
2010 2009
    @raise errors.HypervisorError: in one of the previous cases
2011 2010

  
2012 2011
    """
2013
    output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2014
    # TODO: search for netdev_add, drive_add, device_add.....
2015
    match = self._INFO_VERSION_RE.search(output.stdout)
2016
    if not match:
2017
      raise errors.HotplugError("Try hotplug only in running instances.")
2018
    v_major, v_min, _, _ = match.groups()
2019
    if (int(v_major), int(v_min)) < (1, 0):
2020
      raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2021

  
2022 2012
    if dev_type == constants.HOTPLUG_TARGET_DISK:
2023 2013
      hvp = instance.hvparams
2024 2014
      security_model = hvp[constants.HV_SECURITY_MODEL]
......
2035 2025
      raise errors.HotplugError("Cannot hot-add NIC."
2036 2026
                                " fdsend python module is missing.")
2037 2027

  
2028
  def HotplugSupported(self, instance):
2029
    """Checks if hotplug is generally supported.
2030

  
2031
    Hotplug is *not* supported in case of:
2032
     - qemu versions < 1.0
2033
     - for stopped instances
2034

  
2035
    @raise errors.HypervisorError: in one of the previous cases
2036

  
2037
    """
2038
    output = self._CallMonitorCommand(instance.name, self._INFO_VERSION_CMD)
2039
    # TODO: search for netdev_add, drive_add, device_add.....
2040
    match = self._INFO_VERSION_RE.search(output.stdout)
2041
    if not match:
2042
      raise errors.HotplugError("Try hotplug only in running instances.")
2043
    v_major, v_min, _, _ = match.groups()
2044
    if (int(v_major), int(v_min)) < (1, 0):
2045
      raise errors.HotplugError("Hotplug not supported for qemu versions < 1.0")
2046

  
2038 2047
  def _CallHotplugCommand(self, name, cmd):
2039 2048
    output = self._CallMonitorCommand(name, cmd)
2040 2049
    # TODO: parse output and check if succeeded
b/lib/rpc_defs.py
300 300
    ("extra", None, "Extra info for device (dev_path for disk)"),
301 301
    ("seq", None, "Device seq"),
302 302
    ], None, None, "Hoplug a device to a running instance"),
303
  ("hotplug_supported", SINGLE, None, constants.RPC_TMO_NORMAL, [
304
    ("instance", ED_INST_DICT, "Instance object"),
305
    ], None, None, "Check if hotplug is supported"),
303 306
  ]
304 307

  
305 308
_IMPEXP_CALLS = [
b/lib/server/noded.py
631 631
    return backend.HotplugDevice(instance, action, dev_type, device, extra, seq)
632 632

  
633 633
  @staticmethod
634
  def perspective_hotplug_supported(params):
635
    """Checks if hotplug is supported.
636

  
637
    """
638
    instance = objects.Instance.FromDict(params[0])
639
    return backend.HotplugSupported(instance)
640

  
641
  @staticmethod
634 642
  def perspective_migration_info(params):
635 643
    """Gather information about an instance to be migrated.
636 644

  
b/test/py/cmdlib/instance_unittest.py
1975 1975
                         nics=[(constants.DDM_ADD, -1, {})],
1976 1976
                         hotplug=True)
1977 1977
    self.ExecOpCode(op)
1978
    self.assertTrue(self.rpc.call_hotplug_supported.called)
1978 1979
    self.assertTrue(self.rpc.call_hotplug_device.called)
1979 1980

  
1980 1981
  def testAddNicWithIp(self):
......
2065 2066
                         nics=[(constants.DDM_MODIFY, 0, {})],
2066 2067
                         hotplug=True)
2067 2068
    self.ExecOpCode(op)
2069
    self.assertTrue(self.rpc.call_hotplug_supported.called)
2068 2070
    self.assertTrue(self.rpc.call_hotplug_device.called)
2069 2071

  
2070 2072
  def testRemoveLastNic(self):
......
2089 2091
                         nics=[(constants.DDM_REMOVE, 0, {})],
2090 2092
                         hotplug=True)
2091 2093
    self.ExecOpCode(op)
2094
    self.assertTrue(self.rpc.call_hotplug_supported.called)
2092 2095
    self.assertTrue(self.rpc.call_hotplug_device.called)
2093 2096

  
2094 2097
  def testSetOffline(self):
......
2177 2180
                                 }]],
2178 2181
                         hotplug=True)
2179 2182
    self.ExecOpCode(op)
2183
    self.assertTrue(self.rpc.call_hotplug_supported.called)
2180 2184
    self.assertTrue(self.rpc.call_blockdev_create.called)
2181 2185
    self.assertTrue(self.rpc.call_blockdev_assemble.called)
2182 2186
    self.assertTrue(self.rpc.call_hotplug_device.called)
......
2190 2194
                                 {}]],
2191 2195
                         hotplug=True)
2192 2196
    self.ExecOpCode(op)
2197
    self.assertTrue(self.rpc.call_hotplug_supported.called)
2193 2198
    self.assertTrue(self.rpc.call_hotplug_device.called)
2194 2199
    self.assertTrue(self.rpc.call_blockdev_shutdown.called)
2195 2200
    self.assertTrue(self.rpc.call_blockdev_remove.called)

Also available in: Unified diff