From ff17c6fd898403da58c30672fe0276be75f410e3 Mon Sep 17 00:00:00 2001 From: Mate Lakat Date: Tue, 14 Aug 2012 14:50:50 +0100 Subject: XCP-XAPI version fix Fixes bug 1033933. On an Kronos installation (Ubuntu + XCP-XAPI), the reported software_version dictionary did not contain both product_version and product_brand. This caused a KeyError. With this fix, the session's product_version and product_brand will default to None in such cases. The resize operation's name in these cases will default to VDI.resize. Change-Id: Ic0db4128a7b27c08c24461562423bcecd1373e58 --- nova/tests/test_xenapi.py | 63 ++++++++++++++++++++++++++++++++++++++++++++++ nova/virt/xenapi/driver.py | 19 ++++++++++---- nova/virt/xenapi/vmops.py | 29 ++++++++++++++------- 3 files changed, 97 insertions(+), 14 deletions(-) diff --git a/nova/tests/test_xenapi.py b/nova/tests/test_xenapi.py index 5ab059d07..7dab9bbc1 100644 --- a/nova/tests/test_xenapi.py +++ b/nova/tests/test_xenapi.py @@ -2534,3 +2534,66 @@ class XenAPIInjectMetadataTestCase(stubs.XenAPITestBase): 'vm-data/user-metadata/c': '3', }, }) + + +class VMOpsTestCase(test.TestCase): + def _get_mock_session(self, product_brand, product_version): + class Mock(object): + pass + + mock_session = Mock() + mock_session.product_brand = product_brand + mock_session.product_version = product_version + + return mock_session + + def test_check_resize_func_name_defaults_to_VDI_resize(self): + session = self._get_mock_session(None, None) + ops = vmops.VMOps(session) + + self.assertEquals( + 'VDI.resize', + ops.check_resize_func_name()) + + +class XenAPISessionTestCase(test.TestCase): + def _get_mock_xapisession(self, software_version): + class XcpXapiSession(xenapi_conn.XenAPISession): + def __init__(_ignore): + "Skip the superclass's dirty init" + + def _get_software_version(_ignore): + return software_version + + return XcpXapiSession() + + def test_get_product_version_product_brand_does_not_fail(self): + session = self._get_mock_xapisession({ + 'build_number': '0', + 'date': '2012-08-03', + 'hostname': 'komainu', + 'linux': '3.2.0-27-generic', + 'network_backend': 'bridge', + 'platform_name': 'XCP_Kronos', + 'platform_version': '1.6.0', + 'xapi': '1.3', + 'xen': '4.1.2', + 'xencenter_max': '1.10', + 'xencenter_min': '1.10' + }) + + self.assertEquals( + (None, None), + session._get_product_version_and_brand() + ) + + def test_get_product_version_product_brand_xs_6(self): + session = self._get_mock_xapisession({ + 'product_brand': 'XenServer', + 'product_version': '6.0.50' + }) + + self.assertEquals( + ((6, 0, 50), 'XenServer'), + session._get_product_version_and_brand() + ) diff --git a/nova/virt/xenapi/driver.py b/nova/virt/xenapi/driver.py index 6eb39e2b7..644f598ca 100644 --- a/nova/virt/xenapi/driver.py +++ b/nova/virt/xenapi/driver.py @@ -652,14 +652,23 @@ class XenAPISession(object): def _get_product_version_and_brand(self): """Return a tuple of (major, minor, rev) for the host version and a string of the product brand""" - host = self.get_xenapi_host() - software_version = self.call_xenapi('host.get_software_version', - host) + software_version = self._get_software_version() + + product_version_str = software_version.get('product_version') + product_brand = software_version.get('product_brand') + + if None in (product_version_str, product_brand): + return (None, None) + product_version = tuple(int(part) for part in - software_version['product_version'].split('.')) - product_brand = software_version['product_brand'] + product_version_str.split('.')) + return product_version, product_brand + def _get_software_version(self): + host = self.get_xenapi_host() + return self.call_xenapi('host.get_software_version', host) + def get_session_id(self): """Return a string session_id. Used for vnc consoles.""" with self._get_session() as session: diff --git a/nova/virt/xenapi/vmops.py b/nova/virt/xenapi/vmops.py index 41e1f6dd6..81f368c91 100644 --- a/nova/virt/xenapi/vmops.py +++ b/nova/virt/xenapi/vmops.py @@ -787,17 +787,28 @@ class VMOps(object): def check_resize_func_name(self): """Check the function name used to resize an instance based on product_brand and product_version.""" - if (self._session.product_brand == 'XCP' and - ((self._session.product_version[0] == 1 and - self._session.product_version[1] > 1) or - self._session.product_version[0] > 1)): - return 'VDI.resize' - if (self._session.product_brand == 'XenServer' and - self._session.product_version[0] > 5): - return 'VDI.resize' + brand = self._session.product_brand + version = self._session.product_version - return 'VDI.resize_online' + # To maintain backwards compatibility. All recent versions + # should use VDI.resize + if bool(version) and bool(brand): + xcp = brand == 'XCP' + r1_2_or_above = ( + ( + version[0] == 1 + and version[1] > 1 + ) + or version[0] > 1) + + xenserver = brand == 'XenServer' + r6_or_above = version[0] > 5 + + if (xcp and not r1_2_or_above) or (xenserver and not r6_or_above): + return 'VDI.resize_online' + + return 'VDI.resize' def reboot(self, instance, reboot_type): """Reboot VM instance.""" -- cgit