diff options
author | Jenkins <jenkins@review.openstack.org> | 2015-01-17 00:34:18 +0000 |
---|---|---|
committer | Gerrit Code Review <review@openstack.org> | 2015-01-17 00:34:18 +0000 |
commit | 5903ce2e4db6897e43fcad9e7d38e2d909c42c1a (patch) | |
tree | 4cf322021ca74947c6f885d23852bda51681df19 /nova | |
parent | b4a809240cd8f6ab33468f95c701348c9b66f6d3 (diff) | |
parent | cc5a473cfad54b5a38f5ed8c2d3d930ea6ebb421 (diff) | |
download | nova-5903ce2e4db6897e43fcad9e7d38e2d909c42c1a.tar.gz |
Merge "libvirt: move capabilities helper into host.py"
Diffstat (limited to 'nova')
-rw-r--r-- | nova/tests/unit/virt/libvirt/fakelibvirt.py | 15 | ||||
-rw-r--r-- | nova/tests/unit/virt/libvirt/test_driver.py | 143 | ||||
-rw-r--r-- | nova/tests/unit/virt/libvirt/test_host.py | 83 | ||||
-rw-r--r-- | nova/virt/libvirt/driver.py | 43 | ||||
-rw-r--r-- | nova/virt/libvirt/host.py | 33 |
5 files changed, 160 insertions, 157 deletions
diff --git a/nova/tests/unit/virt/libvirt/fakelibvirt.py b/nova/tests/unit/virt/libvirt/fakelibvirt.py index 1aebc0b49b..10f499f07a 100644 --- a/nova/tests/unit/virt/libvirt/fakelibvirt.py +++ b/nova/tests/unit/virt/libvirt/fakelibvirt.py @@ -1050,8 +1050,21 @@ class Connection(object): def baselineCPU(self, cpu, flag): """Add new libvirt API.""" return """<cpu mode='custom' match='exact'> - <model fallback='allow'>Westmere</model> + <model>Penryn</model> <vendor>Intel</vendor> + <feature name='xtpr'/> + <feature name='tm2'/> + <feature name='est'/> + <feature name='vmx'/> + <feature name='ds_cpl'/> + <feature name='monitor'/> + <feature name='pbe'/> + <feature name='tm'/> + <feature name='ht'/> + <feature name='ss'/> + <feature name='acpi'/> + <feature name='ds'/> + <feature name='vme'/> <feature policy='require' name='aes'/> </cpu>""" diff --git a/nova/tests/unit/virt/libvirt/test_driver.py b/nova/tests/unit/virt/libvirt/test_driver.py index cf75814417..31b95fbeeb 100644 --- a/nova/tests/unit/virt/libvirt/test_driver.py +++ b/nova/tests/unit/virt/libvirt/test_driver.py @@ -917,8 +917,7 @@ class LibvirtConnTestCase(test.NoDBTestCase): @mock.patch.object(libvirt, 'registerErrorHandler', side_effect=fake_registerErrorHandler) - @mock.patch.object(libvirt_driver.LibvirtDriver, - '_get_host_capabilities', + @mock.patch.object(host.Host, "get_capabilities", side_effect=fake_get_host_capabilities) def test_init_host(get_host_capabilities, register_error_handler): conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) @@ -958,89 +957,6 @@ class LibvirtConnTestCase(test.NoDBTestCase): # our stub method is called which asserts the password is scrubbed self.assertTrue(debug_mock.called) - def test_cpu_features_bug_1217630(self): - conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) - - # Test old version of libvirt, it shouldn't see the `aes' feature - with mock.patch('nova.virt.libvirt.driver.libvirt') as mock_libvirt: - del mock_libvirt.VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES - caps = conn._get_host_capabilities() - self.assertNotIn('aes', [x.name for x in caps.host.cpu.features]) - - # Test new verion of libvirt, should find the `aes' feature - with mock.patch('nova.virt.libvirt.driver.libvirt') as mock_libvirt: - mock_libvirt['VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES'] = 1 - # Cleanup the capabilities cache firstly - conn._caps = None - caps = conn._get_host_capabilities() - self.assertIn('aes', [x.name for x in caps.host.cpu.features]) - - def test_cpu_features_are_not_duplicated(self): - conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) - - # Test old version of libvirt. Should return single 'hypervisor' - with mock.patch('nova.virt.libvirt.driver.libvirt') as mock_libvirt: - del mock_libvirt.VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES - caps = conn._get_host_capabilities() - cnt = [x.name for x in caps.host.cpu.features].count('hypervisor') - self.assertEqual(1, cnt) - - # Test new version of libvirt. Should still return single 'hypervisor' - with mock.patch('nova.virt.libvirt.driver.libvirt') as mock_libvirt: - mock_libvirt['VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES'] = 1 - # Cleanup the capabilities cache firstly - conn._caps = None - caps = conn._get_host_capabilities() - cnt = [x.name for x in caps.host.cpu.features].count('hypervisor') - self.assertEqual(1, cnt) - - def test_baseline_cpu_not_supported(self): - conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) - - # `mock` has trouble stubbing attributes that don't exist yet, so - # fallback to plain-Python attribute setting/deleting - cap_str = 'VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES' - if not hasattr(libvirt_driver.libvirt, cap_str): - setattr(libvirt_driver.libvirt, cap_str, True) - self.addCleanup(delattr, libvirt_driver.libvirt, cap_str) - - # Handle just the NO_SUPPORT error - not_supported_exc = fakelibvirt.make_libvirtError( - libvirt.libvirtError, - 'this function is not supported by the connection driver:' - ' virConnectBaselineCPU', - error_code=libvirt.VIR_ERR_NO_SUPPORT) - - with mock.patch.object(conn._conn, 'baselineCPU', - side_effect=not_supported_exc): - caps = conn._get_host_capabilities() - self.assertEqual(vconfig.LibvirtConfigCaps, type(caps)) - self.assertNotIn('aes', [x.name for x in caps.host.cpu.features]) - - # Clear cached result so we can test again... - conn._caps = None - - # Other errors should not be caught - other_exc = fakelibvirt.make_libvirtError( - libvirt.libvirtError, - 'other exc', - error_code=libvirt.VIR_ERR_NO_DOMAIN) - - with mock.patch.object(conn._conn, 'baselineCPU', - side_effect=other_exc): - self.assertRaises(libvirt.libvirtError, - conn._get_host_capabilities) - - def test_lxc_get_host_capabilities_failed(self): - conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) - - with mock.patch.object(conn._conn, 'baselineCPU', return_value=-1): - setattr(libvirt, 'VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES', 1) - caps = conn._get_host_capabilities() - delattr(libvirt, 'VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES') - self.assertEqual(vconfig.LibvirtConfigCaps, type(caps)) - self.assertNotIn('aes', [x.name for x in caps.host.cpu.features]) - @mock.patch.object(time, "time") def test_get_guest_config(self, time_mock): time_mock.return_value = 1234567.89 @@ -1220,8 +1136,8 @@ class LibvirtConnTestCase(test.NoDBTestCase): with contextlib.nested( mock.patch.object(host.Host, 'has_min_version', return_value=True), - mock.patch.object( - conn, "_get_host_capabilities", return_value=caps), + mock.patch.object(host.Host, "get_capabilities", + return_value=caps), mock.patch.object( random, 'choice', side_effect=lambda cells: cells[0])): cfg = conn._get_guest_config(instance_ref, [], {}, disk_info) @@ -1248,8 +1164,8 @@ class LibvirtConnTestCase(test.NoDBTestCase): instance_ref) with contextlib.nested( - mock.patch.object( - conn, "_get_host_capabilities", return_value=caps), + mock.patch.object(host.Host, "get_capabilities", + return_value=caps), mock.patch.object( hardware, 'get_vcpu_pin_set', return_value=set([3])), mock.patch.object(random, 'choice') @@ -1319,8 +1235,8 @@ class LibvirtConnTestCase(test.NoDBTestCase): with contextlib.nested( mock.patch.object(host.Host, 'has_min_version', return_value=True), - mock.patch.object( - conn, "_get_host_capabilities", return_value=caps), + mock.patch.object(host.Host, "get_capabilities", + return_value=caps), mock.patch.object( hardware, 'get_vcpu_pin_set', return_value=set([2, 3])), mock.patch.object( @@ -1365,8 +1281,8 @@ class LibvirtConnTestCase(test.NoDBTestCase): return_value=instance_topology), mock.patch.object(host.Host, 'has_min_version', return_value=True), - mock.patch.object( - conn, "_get_host_capabilities", return_value=caps)): + mock.patch.object(host.Host, "get_capabilities", + return_value=caps)): cfg = conn._get_guest_config(instance_ref, [], {}, disk_info) self.assertIsNone(cfg.cpuset) self.assertEqual(0, len(cfg.cputune.vcpupin)) @@ -1412,8 +1328,8 @@ class LibvirtConnTestCase(test.NoDBTestCase): return_value=instance_topology), mock.patch.object(host.Host, 'has_min_version', return_value=True), - mock.patch.object( - conn, "_get_host_capabilities", return_value=caps), + mock.patch.object(host.Host, "get_capabilities", + return_value=caps), mock.patch.object( hardware, 'get_vcpu_pin_set', return_value=set([2, 3, 4, 5])) @@ -1489,8 +1405,8 @@ class LibvirtConnTestCase(test.NoDBTestCase): return_value=instance_topology), mock.patch.object(host.Host, 'has_min_version', return_value=True), - mock.patch.object( - conn, "_get_host_capabilities", return_value=caps), + mock.patch.object(host.Host, "get_capabilities", + return_value=caps), ): cfg = conn._get_guest_config(instance_ref, [], {}, disk_info) self.assertIsNone(cfg.cpuset) @@ -2483,8 +2399,7 @@ class LibvirtConnTestCase(test.NoDBTestCase): caps.host.cpu = cpu return caps - self.stubs.Set(libvirt_driver.LibvirtDriver, - "_get_host_capabilities", + self.stubs.Set(host.Host, "get_capabilities", get_host_capabilities_stub) def _stub_guest_cpu_config_arch(self, cpu_arch): @@ -3621,8 +3536,7 @@ class LibvirtConnTestCase(test.NoDBTestCase): disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type, instance_ref) - self.stubs.Set(libvirt_driver.LibvirtDriver, - "_get_host_capabilities", + self.stubs.Set(host.Host, "get_capabilities", get_host_capabilities_stub) conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) @@ -3653,8 +3567,7 @@ class LibvirtConnTestCase(test.NoDBTestCase): disk_info = blockinfo.get_disk_info(CONF.libvirt.virt_type, instance_ref) - self.stubs.Set(libvirt_driver.LibvirtDriver, - "_get_host_capabilities", + self.stubs.Set(host.Host, "get_capabilities", get_host_capabilities_stub) conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), True) @@ -8651,8 +8564,7 @@ class LibvirtConnTestCase(test.NoDBTestCase): return caps - self.stubs.Set(libvirt_driver.LibvirtDriver, - '_get_host_capabilities', + self.stubs.Set(host.Host, "get_capabilities", get_host_capabilities_stub) want = {"vendor": "AMD", @@ -8845,8 +8757,8 @@ class LibvirtConnTestCase(test.NoDBTestCase): with contextlib.nested( mock.patch.object(host.Host, 'has_min_version', return_value=True), - mock.patch.object( - conn, '_get_host_capabilities', return_value=caps), + mock.patch.object(host.Host, "get_capabilities", + return_value=caps), mock.patch.object( hardware, 'get_vcpu_pin_set', return_value=set([0, 1, 3])) ): @@ -8873,7 +8785,7 @@ class LibvirtConnTestCase(test.NoDBTestCase): conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) with contextlib.nested( mock.patch.object(host.Host, 'has_min_version', return_value=True), - mock.patch.object(conn, '_get_host_capabilities', + mock.patch.object(host.Host, "get_capabilities", return_value=caps) ) as (has_min_version, get_caps): self.assertIsNone(conn._get_host_numa_topology()) @@ -9606,8 +9518,7 @@ Active: 8381604 kB return caps - self.stubs.Set(libvirt_driver.LibvirtDriver, - '_get_host_capabilities', + self.stubs.Set(host.Host, "get_capabilities", get_host_capabilities_stub) want = [(arch.X86_64, 'kvm', 'hvm'), @@ -10235,21 +10146,15 @@ Active: 8381604 kB network_info = _fake_network_info(self.stubs, 1) self.create_fake_libvirt_mock(getLibVersion=fake_getLibVersion, getCapabilities=fake_getCapabilities, - getVersion=lambda: 1005001) + getVersion=lambda: 1005001, + listDefinedDomains=lambda: [], + baselineCPU=fake_baselineCPU) instance_ref = self.test_instance instance_ref['image_ref'] = 123456 # we send an int to test sha1 call instance = objects.Instance(**instance_ref) flavor = instance.get_flavor() flavor.extra_specs = {} - self.mox.StubOutWithMock(libvirt_driver.LibvirtDriver, '_conn') - libvirt_driver.LibvirtDriver._conn.listDefinedDomains = lambda: [] - libvirt_driver.LibvirtDriver._conn.getCapabilities = \ - fake_getCapabilities - libvirt_driver.LibvirtDriver._conn.getVersion = lambda: 1005001 - libvirt_driver.LibvirtDriver._conn.defineXML = fake_defineXML - libvirt_driver.LibvirtDriver._conn.baselineCPU = fake_baselineCPU - self.mox.ReplayAll() conn = libvirt_driver.LibvirtDriver(fake.FakeVirtAPI(), False) diff --git a/nova/tests/unit/virt/libvirt/test_host.py b/nova/tests/unit/virt/libvirt/test_host.py index 04b2bccfa0..21d72d8397 100644 --- a/nova/tests/unit/virt/libvirt/test_host.py +++ b/nova/tests/unit/virt/libvirt/test_host.py @@ -25,6 +25,7 @@ from nova import objects from nova import test from nova.tests.unit.virt.libvirt import fakelibvirt from nova.virt import event +from nova.virt.libvirt import config as vconfig from nova.virt.libvirt import host try: @@ -551,3 +552,85 @@ class HostTestCase(test.NoDBTestCase): self.assertEqual(doms[1].name(), vm1.name()) self.assertEqual(doms[2].name(), vm2.name()) mock_list.assert_called_with(True) + + def test_cpu_features_bug_1217630(self): + self.host.get_connection() + + # Test old version of libvirt, it shouldn't see the `aes' feature + with mock.patch('nova.virt.libvirt.host.libvirt') as mock_libvirt: + del mock_libvirt.VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES + caps = self.host.get_capabilities() + self.assertNotIn('aes', [x.name for x in caps.host.cpu.features]) + + # Cleanup the capabilities cache firstly + self.host._caps = None + + # Test new version of libvirt, should find the `aes' feature + with mock.patch('nova.virt.libvirt.host.libvirt') as mock_libvirt: + mock_libvirt['VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES'] = 1 + caps = self.host.get_capabilities() + self.assertIn('aes', [x.name for x in caps.host.cpu.features]) + + def test_cpu_features_are_not_duplicated(self): + self.host.get_connection() + + # Test old version of libvirt. Should return single 'hypervisor' + with mock.patch('nova.virt.libvirt.host.libvirt') as mock_libvirt: + del mock_libvirt.VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES + caps = self.host.get_capabilities() + cnt = [x.name for x in caps.host.cpu.features].count('xtpr') + self.assertEqual(1, cnt) + + # Cleanup the capabilities cache firstly + self.host._caps = None + + # Test new version of libvirt. Should still return single 'hypervisor' + with mock.patch('nova.virt.libvirt.host.libvirt') as mock_libvirt: + mock_libvirt['VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES'] = 1 + caps = self.host.get_capabilities() + cnt = [x.name for x in caps.host.cpu.features].count('xtpr') + self.assertEqual(1, cnt) + + def test_baseline_cpu_not_supported(self): + # `mock` has trouble stubbing attributes that don't exist yet, so + # fallback to plain-Python attribute setting/deleting + cap_str = 'VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES' + if not hasattr(host.libvirt, cap_str): + setattr(host.libvirt, cap_str, True) + self.addCleanup(delattr, host.libvirt, cap_str) + + # Handle just the NO_SUPPORT error + not_supported_exc = fakelibvirt.make_libvirtError( + libvirt.libvirtError, + 'this function is not supported by the connection driver:' + ' virConnectBaselineCPU', + error_code=libvirt.VIR_ERR_NO_SUPPORT) + + with mock.patch.object(fakelibvirt.virConnect, 'baselineCPU', + side_effect=not_supported_exc): + caps = self.host.get_capabilities() + self.assertEqual(vconfig.LibvirtConfigCaps, type(caps)) + self.assertNotIn('aes', [x.name for x in caps.host.cpu.features]) + + # Clear cached result so we can test again... + self.host._caps = None + + # Other errors should not be caught + other_exc = fakelibvirt.make_libvirtError( + libvirt.libvirtError, + 'other exc', + error_code=libvirt.VIR_ERR_NO_DOMAIN) + + with mock.patch.object(fakelibvirt.virConnect, 'baselineCPU', + side_effect=other_exc): + self.assertRaises(libvirt.libvirtError, + self.host.get_capabilities) + + def test_lxc_get_host_capabilities_failed(self): + with mock.patch.object(fakelibvirt.virConnect, 'baselineCPU', + return_value=-1): + setattr(libvirt, 'VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES', 1) + caps = self.host.get_capabilities() + delattr(libvirt, 'VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES') + self.assertEqual(vconfig.LibvirtConfigCaps, type(caps)) + self.assertNotIn('aes', [x.name for x in caps.host.cpu.features]) diff --git a/nova/virt/libvirt/driver.py b/nova/virt/libvirt/driver.py index f4223a3128..9d4bb95f09 100644 --- a/nova/virt/libvirt/driver.py +++ b/nova/virt/libvirt/driver.py @@ -495,7 +495,7 @@ class LibvirtDriver(driver.ComputeDriver): unknown. Currently, only qemu or kvm on intel 32- or 64-bit systems is tested upstream. """ - caps = self._get_host_capabilities() + caps = self._host.get_capabilities() hostarch = caps.host.cpu.arch if (CONF.libvirt.virt_type not in ('qemu', 'kvm') or hostarch not in (arch.I686, arch.X86_64)): @@ -2991,37 +2991,6 @@ class LibvirtDriver(driver.ComputeDriver): 'due to an unexpected exception.'), CONF.host, exc_info=True) - def _get_host_capabilities(self): - """Returns an instance of config.LibvirtConfigCaps representing - the capabilities of the host. - """ - if not self._caps: - xmlstr = self._conn.getCapabilities() - self._caps = vconfig.LibvirtConfigCaps() - self._caps.parse_str(xmlstr) - if hasattr(libvirt, 'VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES'): - try: - features = self._conn.baselineCPU( - [self._caps.host.cpu.to_xml()], - libvirt.VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES) - # FIXME(wangpan): the return value of baselineCPU should be - # None or xml string, but libvirt has a bug - # of it from 1.1.2 which is fixed in 1.2.0, - # this -1 checking should be removed later. - if features and features != -1: - cpu = vconfig.LibvirtConfigCPU() - cpu.parse_str(features) - self._caps.host.cpu.features = cpu.features - except libvirt.libvirtError as ex: - error_code = ex.get_error_code() - if error_code == libvirt.VIR_ERR_NO_SUPPORT: - LOG.warn(_LW("URI %(uri)s does not support full set" - " of host capabilities: " "%(error)s"), - {'uri': self.uri(), 'error': ex}) - else: - raise - return self._caps - def _get_guest_cpu_model_config(self): mode = CONF.libvirt.cpu_mode model = CONF.libvirt.cpu_model @@ -3204,7 +3173,7 @@ class LibvirtDriver(driver.ComputeDriver): This is typically from the SMBIOS data, unless it has been overridden in /etc/libvirt/libvirtd.conf """ - caps = self._get_host_capabilities() + caps = self._host.get_capabilities() return caps.host.uuid def _get_host_sysinfo_serial_os(self): @@ -3820,7 +3789,7 @@ class LibvirtDriver(driver.ComputeDriver): if guest.os_type is None: guest.os_type = self._get_guest_os_type(virt_type) - caps = self._get_host_capabilities() + caps = self._host.get_capabilities() if virt_type == "xen": if guest.os_type == vm_mode.HVM: @@ -4476,7 +4445,7 @@ class LibvirtDriver(driver.ComputeDriver): :returns: List of tuples describing instance capabilities """ - caps = self._get_host_capabilities() + caps = self._host.get_capabilities() instance_caps = list() for g in caps.guests: for dt in g.domtype: @@ -4498,7 +4467,7 @@ class LibvirtDriver(driver.ComputeDriver): """ - caps = self._get_host_capabilities() + caps = self._host.get_capabilities() cpu_info = dict() cpu_info['arch'] = caps.host.cpu.arch @@ -4624,7 +4593,7 @@ class LibvirtDriver(driver.ComputeDriver): if not self._host.has_min_version(MIN_LIBVIRT_NUMA_TOPOLOGY_VERSION): return - caps = self._get_host_capabilities() + caps = self._host.get_capabilities() topology = caps.host.topology if topology is None or not topology.cells: diff --git a/nova/virt/libvirt/host.py b/nova/virt/libvirt/host.py index 037197c131..9f8e45bea7 100644 --- a/nova/virt/libvirt/host.py +++ b/nova/virt/libvirt/host.py @@ -48,6 +48,7 @@ from nova.openstack.common import log as logging from nova import rpc from nova import utils from nova.virt import event as virtevent +from nova.virt.libvirt import config as vconfig libvirt = None @@ -77,6 +78,7 @@ class Host(object): self._conn_event_handler = conn_event_handler self._lifecycle_event_handler = lifecycle_event_handler self._skip_list_all_domains = False + self._caps = None self._wrapped_conn = None self._wrapped_conn_lock = threading.Lock() @@ -573,3 +575,34 @@ class Host(object): doms.append(dom) return doms + + def get_capabilities(self): + """Returns an instance of config.LibvirtConfigCaps representing + the capabilities of the host. + """ + if not self._caps: + xmlstr = self.get_connection().getCapabilities() + self._caps = vconfig.LibvirtConfigCaps() + self._caps.parse_str(xmlstr) + if hasattr(libvirt, 'VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES'): + try: + features = self.get_connection().baselineCPU( + [self._caps.host.cpu.to_xml()], + libvirt.VIR_CONNECT_BASELINE_CPU_EXPAND_FEATURES) + # FIXME(wangpan): the return value of baselineCPU should be + # None or xml string, but libvirt has a bug + # of it from 1.1.2 which is fixed in 1.2.0, + # this -1 checking should be removed later. + if features and features != -1: + cpu = vconfig.LibvirtConfigCPU() + cpu.parse_str(features) + self._caps.host.cpu.features = cpu.features + except libvirt.libvirtError as ex: + error_code = ex.get_error_code() + if error_code == libvirt.VIR_ERR_NO_SUPPORT: + LOG.warn(_LW("URI %(uri)s does not support full set" + " of host capabilities: " "%(error)s"), + {'uri': self._uri, 'error': ex}) + else: + raise + return self._caps |