Revision 0ad7f5d8

b/lib/hypervisor/hv_kvm.py
555 555

  
556 556
  _DEFAULT_MACHINE_VERSION_RE = re.compile(r"(\S+).*\(default\)")
557 557

  
558
  _QMP_RE = re.compile(r"^-qmp\s", re.M)
559
  _SPICE_RE = re.compile(r"^-spice\s", re.M)
560
  _VHOST_RE = re.compile(r"^-net\s.*,vhost=on|off", re.M)
561
  _ENABLE_KVM_RE = re.compile(r"^-enable-kvm\s", re.M)
562
  _DISABLE_KVM_RE = re.compile(r"^-disable-kvm\s", re.M)
563
  _NETDEV_RE = re.compile(r"^-netdev\s", re.M)
564
  # match  -drive.*boot=on|off on different lines, but in between accept only
565
  # dashes not preceeded by a new line (which would mean another option
566
  # different than -drive is starting)
567
  _BOOT_RE = re.compile(r"^-drive\s([^-]|(?<!^)-)*,boot=on\|off", re.M | re.S)
568

  
558 569
  ANCILLARY_FILES = [
559 570
    _KVM_NETWORK_SCRIPT,
560 571
    ]
......
1004 1015

  
1005 1016
    """
1006 1017
    # pylint: disable=R0912,R0914,R0915
1007
    _, v_major, v_min, _ = self._GetKVMVersion()
1018
    kvmhelp = self._GetKVMHelpOutput()
1008 1019
    hvp = instance.hvparams
1009 1020

  
1010 1021
    pidfile = self._InstancePidFile(instance.name)
......
1048 1059
    if startup_paused:
1049 1060
      kvm_cmd.extend([_KVM_START_PAUSED_FLAG])
1050 1061

  
1051
    if hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED:
1062
    if (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_ENABLED and
1063
        self._ENABLE_KVM_RE.search(kvmhelp)):
1052 1064
      kvm_cmd.extend(["-enable-kvm"])
1053
    elif hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED:
1065
    elif (hvp[constants.HV_KVM_FLAG] == constants.HT_KVM_DISABLED and
1066
          self._DISABLE_KVM_RE.search(kvmhelp)):
1054 1067
      kvm_cmd.extend(["-disable-kvm"])
1055 1068

  
1056 1069
    if boot_network:
......
1058 1071

  
1059 1072
    # whether this is an older KVM version that uses the boot=on flag
1060 1073
    # on devices
1061
    needs_boot_flag = (v_major, v_min) < (0, 14)
1074
    needs_boot_flag = self._BOOT_RE.search(kvmhelp)
1062 1075

  
1063 1076
    disk_type = hvp[constants.HV_DISK_TYPE]
1064 1077
    if disk_type == constants.HT_DISK_PARAVIRTUAL:
......
1415 1428
    kvm_cmd, kvm_nics, up_hvp = kvm_runtime
1416 1429
    up_hvp = objects.FillDict(conf_hvp, up_hvp)
1417 1430

  
1418
    _, v_major, v_min, _ = self._GetKVMVersion()
1431
    kvmhelp = self._GetKVMHelpOutput()
1432
    _, v_major, v_min, _ = self._ParseKVMVersion(kvmhelp)
1419 1433

  
1420 1434
    # We know it's safe to run as a different user upon migration, so we'll use
1421 1435
    # the latest conf, from conf_hvp.
......
1454 1468

  
1455 1469
        if up_hvp[constants.HV_VHOST_NET]:
1456 1470
          # vhost_net is only available from version 0.13.0 or newer
1457
          if (v_major, v_min) >= (0, 13):
1471
          if self._VHOST_RE.search(kvmhelp):
1458 1472
            tap_extra = ",vhost=on"
1459 1473
          else:
1460 1474
            raise errors.HypervisorError("vhost_net is configured"
......
1466 1480
        tapname, tapfd = _OpenTap(vnet_hdr)
1467 1481
        tapfds.append(tapfd)
1468 1482
        taps.append(tapname)
1469
        if (v_major, v_min) >= (0, 12):
1483
        if self._NETDEV_RE.search(kvmhelp):
1470 1484
          nic_val = "%s,mac=%s,netdev=netdev%s" % (nic_model, nic.mac, nic_seq)
1471 1485
          tap_val = "type=tap,id=netdev%s,fd=%d%s" % (nic_seq, tapfd, tap_extra)
1472 1486
          kvm_cmd.extend(["-netdev", tap_val, "-device", nic_val])
......
1497 1511
                         constants.SECURE_DIR_MODE)])
1498 1512

  
1499 1513
    # Automatically enable QMP if version is >= 0.14
1500
    if (v_major, v_min) >= (0, 14):
1514
    if self._QMP_RE.search(kvmhelp):
1501 1515
      logging.debug("Enabling QMP")
1502 1516
      kvm_cmd.extend(["-qmp", "unix:%s,server,nowait" %
1503 1517
                      self._InstanceQmpMonitor(instance.name)])
......
2054 2068
                                     " given time.")
2055 2069

  
2056 2070
      # KVM version should be >= 0.14.0
2057
      _, v_major, v_min, _ = cls._GetKVMVersion()
2058
      if (v_major, v_min) < (0, 14):
2071
      kvmhelp = cls._GetKVMHelpOutput()
2072
      if not cls._SPICE_RE.search(kvmhelp):
2059 2073
        raise errors.HypervisorError("spice is configured, but it is not"
2060
                                     " available in versions of KVM < 0.14")
2074
                                     " supported according to kvm --help")
2061 2075

  
2062 2076
      # if spice_bind is not an IP address, it must be a valid interface
2063 2077
      bound_to_addr = (netutils.IP4Address.IsValid(spice_bind)
b/test/py/ganeti.hypervisor.hv_kvm_unittest.py
289 289
    self.assertEqual(hv_kvm._SPICE_ADDITIONAL_PARAMS, params)
290 290

  
291 291

  
292
class TestHelpRegexps(testutils.GanetiTestCase):
293
  def testBootRe(self):
294
    """Check _BOOT_RE
295

  
296
    It has too match -drive.*boot=on|off except if there is another dash-option
297
    at the beginning of the line.
298

  
299
    """
300
    boot_re = hv_kvm.KVMHypervisor._BOOT_RE
301
    help_10 = utils.ReadFile(self._TestDataFilename("kvm_1.0_help.txt"))
302
    help_01590 = utils.ReadFile(self._TestDataFilename("kvm_0.15.90_help.txt"))
303
    help_0125 = utils.ReadFile(self._TestDataFilename("kvm_0.12.5_help.txt"))
304
    help_091 = utils.ReadFile(self._TestDataFilename("kvm_0.9.1_help.txt"))
305

  
306
    self.assertTrue(boot_re.search(help_091))
307
    self.assertTrue(boot_re.search(help_0125))
308
    self.assertFalse(boot_re.search(help_10))
309
    self.assertFalse(boot_re.search(help_01590))
310

  
311

  
292 312
if __name__ == "__main__":
293 313
  testutils.GanetiTestProgram()

Also available in: Unified diff