From 71ca08dfa63cd0879cd6c27ab7488dbd91c1c0fd Mon Sep 17 00:00:00 2001 From: Dong Liu Date: Wed, 3 Feb 2016 17:27:15 +0800 Subject: [PATCH] Internal version extension should not be chosen when autoupgrade is true, add test cases for autoupgrade. --- azurelinuxagent/distro/default/extension.py | 9 +- azurelinuxagent/protocol/restapi.py | 2 + azurelinuxagent/protocol/wire.py | 14 ++- tests/data/wire/ext_conf.xml | 4 +- tests/data/wire/ext_conf_autoupgrade.xml | 28 +++++ .../ext_conf_autoupgrade_internalversion.xml | 28 +++++ tests/data/wire/ext_conf_internalversion.xml | 28 +++++ tests/data/wire/manifest.xml | 49 +++++++- tests/distro/test_extension.py | 107 +++++++++++++++--- tests/protocol/mockwiredata.py | 9 ++ 10 files changed, 250 insertions(+), 28 deletions(-) create mode 100644 tests/data/wire/ext_conf_autoupgrade.xml create mode 100644 tests/data/wire/ext_conf_autoupgrade_internalversion.xml create mode 100644 tests/data/wire/ext_conf_internalversion.xml diff --git a/azurelinuxagent/distro/default/extension.py b/azurelinuxagent/distro/default/extension.py index 82cdfed..262b01b 100644 --- a/azurelinuxagent/distro/default/extension.py +++ b/azurelinuxagent/distro/default/extension.py @@ -300,11 +300,12 @@ class ExtHandlerInstance(object): else: version_prefix = "{0}.{1}.".format(version_frag[0], version_frag[1]) - packages = [x for x in pkg_list.versions \ - if x.version.startswith(version_prefix) or \ - x.version == version] + packages = [x for x in pkg_list.versions + if x.version.startswith(version_prefix) and + Version(x.version) >= Version(version) or + x.version == version] - packages = sorted(packages, key=lambda x: Version(x.version), + packages = sorted(packages, key=lambda x: (not x.isinternal, Version(x.version)), reverse=True) if len(packages) <= 0: diff --git a/azurelinuxagent/protocol/restapi.py b/azurelinuxagent/protocol/restapi.py index fbd29ed..2778dc4 100644 --- a/azurelinuxagent/protocol/restapi.py +++ b/azurelinuxagent/protocol/restapi.py @@ -140,6 +140,8 @@ class ExtHandlerPackage(DataContract): def __init__(self, version = None): self.version = version self.uris = DataContractList(ExtHandlerPackageUri) + # TODO update the naming to align with metadata protocol + self.isinternal = False class ExtHandlerPackageList(DataContract): def __init__(self): diff --git a/azurelinuxagent/protocol/wire.py b/azurelinuxagent/protocol/wire.py index 7b5ffe8..caf83fb 100644 --- a/azurelinuxagent/protocol/wire.py +++ b/azurelinuxagent/protocol/wire.py @@ -1139,17 +1139,21 @@ class ExtensionManifest(object): def parse(self, xml_text): xml_doc = parse_doc(xml_text) - packages = findall(xml_doc, "Plugin") + self._handle_packages(findall(find(xml_doc, "Plugins"), "Plugin"), False) + self._handle_packages(findall(find(xml_doc, "InternalPlugins"), "Plugin"), True) + + def _handle_packages(self, packages, isinternal): for package in packages: version = findtext(package, "Version") uris = find(package, "Uris") uri_list = findall(uris, "Uri") uri_list = [gettext(x) for x in uri_list] - package = ExtHandlerPackage() - package.version = version + pkg = ExtHandlerPackage() + pkg.version = version for uri in uri_list: pkg_uri = ExtHandlerVersionUri() pkg_uri.uri = uri - package.uris.append(pkg_uri) - self.pkg_list.versions.append(package) + pkg.uris.append(pkg_uri) + pkg.isinternal = isinternal + self.pkg_list.versions.append(pkg) diff --git a/tests/data/wire/ext_conf.xml b/tests/data/wire/ext_conf.xml index 725271d..aded2dd 100644 --- a/tests/data/wire/ext_conf.xml +++ b/tests/data/wire/ext_conf.xml @@ -35,10 +35,10 @@ - + - + {"runtimeSettings":[{"handlerSettings":{"protectedSettingsCertThumbprint":"4037FBF5F1F3014F99B5D6C7799E9B20E6871CB3","protectedSettings":"MIICWgYJK","publicSettings":{"foo":"bar"}}}]} diff --git a/tests/data/wire/ext_conf_autoupgrade.xml b/tests/data/wire/ext_conf_autoupgrade.xml new file mode 100644 index 0000000..1d6919e --- /dev/null +++ b/tests/data/wire/ext_conf_autoupgrade.xml @@ -0,0 +1,28 @@ + + + + Win8 + + http://rdfepirv2hknprdstr03.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml + http://rdfepirv2hknprdstr04.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml + + + + Win7 + + http://rdfepirv2hknprdstr03.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml + http://rdfepirv2hknprdstr04.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml + + + + + + + + + + {"runtimeSettings":[{"handlerSettings":{"protectedSettingsCertThumbprint":"4037FBF5F1F3014F99B5D6C7799E9B20E6871CB3","protectedSettings":"MIICWgYJK","publicSettings":{"foo":"bar"}}}]} + + +https://yuezhatest.blob.core.windows.net/vhds/test-cs12.test-cs12.test-cs12.status?sr=b&sp=rw&se=9999-01-01&sk=key1&sv=2014-02-14&sig=hfRh7gzUE7sUtYwke78IOlZOrTRCYvkec4hGZ9zZzXo%3D + diff --git a/tests/data/wire/ext_conf_autoupgrade_internalversion.xml b/tests/data/wire/ext_conf_autoupgrade_internalversion.xml new file mode 100644 index 0000000..1e613ea --- /dev/null +++ b/tests/data/wire/ext_conf_autoupgrade_internalversion.xml @@ -0,0 +1,28 @@ + + + + Win8 + + http://rdfepirv2hknprdstr03.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml + http://rdfepirv2hknprdstr04.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml + + + + Win7 + + http://rdfepirv2hknprdstr03.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml + http://rdfepirv2hknprdstr04.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml + + + + + + + + + + {"runtimeSettings":[{"handlerSettings":{"protectedSettingsCertThumbprint":"4037FBF5F1F3014F99B5D6C7799E9B20E6871CB3","protectedSettings":"MIICWgYJK","publicSettings":{"foo":"bar"}}}]} + + +https://yuezhatest.blob.core.windows.net/vhds/test-cs12.test-cs12.test-cs12.status?sr=b&sp=rw&se=9999-01-01&sk=key1&sv=2014-02-14&sig=hfRh7gzUE7sUtYwke78IOlZOrTRCYvkec4hGZ9zZzXo%3D + diff --git a/tests/data/wire/ext_conf_internalversion.xml b/tests/data/wire/ext_conf_internalversion.xml new file mode 100644 index 0000000..1e613ea --- /dev/null +++ b/tests/data/wire/ext_conf_internalversion.xml @@ -0,0 +1,28 @@ + + + + Win8 + + http://rdfepirv2hknprdstr03.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml + http://rdfepirv2hknprdstr04.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win8_asiaeast_manifest.xml + + + + Win7 + + http://rdfepirv2hknprdstr03.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml + http://rdfepirv2hknprdstr04.blob.core.windows.net/bfd5c281a7dc4e4b84381eb0b47e3aaf/Microsoft.WindowsAzure.GuestAgent_Win7_asiaeast_manifest.xml + + + + + + + + + + {"runtimeSettings":[{"handlerSettings":{"protectedSettingsCertThumbprint":"4037FBF5F1F3014F99B5D6C7799E9B20E6871CB3","protectedSettings":"MIICWgYJK","publicSettings":{"foo":"bar"}}}]} + + +https://yuezhatest.blob.core.windows.net/vhds/test-cs12.test-cs12.test-cs12.status?sr=b&sp=rw&se=9999-01-01&sk=key1&sv=2014-02-14&sig=hfRh7gzUE7sUtYwke78IOlZOrTRCYvkec4hGZ9zZzXo%3D + diff --git a/tests/data/wire/manifest.xml b/tests/data/wire/manifest.xml index 943755a..c538aac 100644 --- a/tests/data/wire/manifest.xml +++ b/tests/data/wire/manifest.xml @@ -2,17 +2,58 @@ - 1.0 + 1.0.0 - http://foo.bar/zar/OSTCExtensions.ExampleHandlerLinux + http://foo.bar/zar/OSTCExtensions.ExampleHandlerLinux__1.0.0 - 1.1 + 1.1.0 - http://foo.bar/zar/OSTCExtensions.ExampleHandlerLinux + http://foo.bar/zar/OSTCExtensions.ExampleHandlerLinux__1.1.0 + + 2.0.0http://host/OSTCExtensions.ExampleHandlerLinux__2.0.0 + + + 2.1.0http://host/OSTCExtensions.ExampleHandlerLinux__2.1.0 + + + 2.1.1http://host/OSTCExtensions.ExampleHandlerLinux__2.1.1 + + + 2.2.0http://host/OSTCExtensions.ExampleHandlerLinux__2.2.0 + + + 3.0http://host/OSTCExtensions.ExampleHandlerLinux__3.0 + + + 3.1http://host/OSTCExtensions.ExampleHandlerLinux__3.1 + + + 4.0.0.0http://host/OSTCExtensions.ExampleHandlerLinux__3.0 + + + 4.0.0.1http://host/OSTCExtensions.ExampleHandlerLinux__3.1 + + + 4.1.0.0http://host/OSTCExtensions.ExampleHandlerLinux__3.1 + + + + 1.2.0 + + http://foo.bar/zar/OSTCExtensions.ExampleHandlerLinux__1.2.0 + + + + 2.3.0http://host/OSTCExtensions.ExampleHandlerLinux__2.3.0 + + + 2.4.0http://host/OSTCExtensions.ExampleHandlerLinux__2.3.0 + + diff --git a/tests/distro/test_extension.py b/tests/distro/test_extension.py index d0b631f..5905c39 100644 --- a/tests/distro/test_extension.py +++ b/tests/distro/test_extension.py @@ -18,12 +18,11 @@ # http://msdn.microsoft.com/en-us/library/cc227282%28PROT.10%29.aspx # http://msdn.microsoft.com/en-us/library/cc227259%28PROT.13%29.aspx -from tests.tools import * from tests.protocol.mockwiredata import * from azurelinuxagent.exception import * from azurelinuxagent.distro.loader import get_distro -from azurelinuxagent.protocol.restapi import get_properties from azurelinuxagent.protocol.wire import WireProtocol +from azurelinuxagent.distro.default.extension import ExtHandlerInstance @patch("time.sleep") @patch("azurelinuxagent.protocol.wire.CryptUtil") @@ -71,12 +70,12 @@ class TestExtension(AgentTestCase): #Test enable scenario. distro.ext_handlers_handler.run() - self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0") + self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0.0") self._assert_ext_status(protocol.report_ext_status, "success", 0) #Test goal state not changed distro.ext_handlers_handler.run() - self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0") + self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0.0") #Test goal state changed test_data.goal_state = test_data.goal_state.replace("1<", @@ -84,17 +83,17 @@ class TestExtension(AgentTestCase): test_data.ext_conf = test_data.ext_conf.replace("seqNo=\"0\"", "seqNo=\"1\"") distro.ext_handlers_handler.run() - self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0") + self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0.0") self._assert_ext_status(protocol.report_ext_status, "success", 1) #Test upgrade test_data.goal_state = test_data.goal_state.replace("2<", "3<") - test_data.ext_conf = test_data.ext_conf.replace("1.0", "1.1") + test_data.ext_conf = test_data.ext_conf.replace("1.0.0", "1.1.0") test_data.ext_conf = test_data.ext_conf.replace("seqNo=\"1\"", "seqNo=\"2\"") distro.ext_handlers_handler.run() - self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.1") + self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.1.0") self._assert_ext_status(protocol.report_ext_status, "success", 2) #Test disable @@ -103,7 +102,7 @@ class TestExtension(AgentTestCase): test_data.ext_conf = test_data.ext_conf.replace("enabled", "disabled") distro.ext_handlers_handler.run() self._assert_handler_status(protocol.report_vm_status, "NotReady", - 1, "1.1") + 1, "1.1.0") #Test uninstall test_data.goal_state = test_data.goal_state.replace("4<", @@ -123,14 +122,14 @@ class TestExtension(AgentTestCase): distro, protocol = self._create_mock(test_data, *args) distro.ext_handlers_handler.run() - self._assert_handler_status(protocol.report_vm_status, "Ready", 0, "1.0") + self._assert_handler_status(protocol.report_vm_status, "Ready", 0, "1.0.0") def test_ext_handler_no_public_settings(self, *args): test_data = WireProtocolData(DATA_FILE_EXT_NO_PUBLIC) distro, protocol = self._create_mock(test_data, *args) distro.ext_handlers_handler.run() - self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0") + self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0.0") def test_ext_handler_no_ext(self, *args): test_data = WireProtocolData(DATA_FILE_NO_EXT) @@ -172,19 +171,101 @@ class TestExtension(AgentTestCase): test_data = WireProtocolData(DATA_FILE) distro, protocol = self._create_mock(test_data, *args) distro.ext_handlers_handler.run() - self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0") + self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0.0") #Remove status file and re-run collecting extension status status_file = os.path.join(self.tmp_dir, - "OSTCExtensions.ExampleHandlerLinux-1.0", + "OSTCExtensions.ExampleHandlerLinux-1.0.0", "status", "0.status") self.assertTrue(os.path.isfile(status_file)) os.remove(status_file) distro.ext_handlers_handler.run() - self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0") + self._assert_handler_status(protocol.report_vm_status, "Ready", 1, "1.0.0") self._assert_ext_status(protocol.report_ext_status, "error", 0) + def test_ext_handler_version_decide_autoupgrade_internalversion(self, *args): + for internal in [False, True]: + for autoupgrade in [False, True]: + with self.subTest(autoupgrade=autoupgrade, internal=internal): + if internal: + config_version = '1.2.0' + decision_version = '1.2.0' + if autoupgrade: + datafile = DATA_FILE_EXT_AUTOUPGRADE_INTERNALVERSION + else: + datafile = DATA_FILE_EXT_INTERNALVERSION + else: + config_version = '1.0.0' + if autoupgrade: + datafile = DATA_FILE_EXT_AUTOUPGRADE + decision_version = '1.1.0' + else: + datafile = DATA_FILE + decision_version = '1.0.0' + + _, protocol = self._create_mock(WireProtocolData(datafile), *args) + ext_handlers, _ = protocol.get_ext_handlers() + self.assertEqual(1, len(ext_handlers.extHandlers)) + ext_handler = ext_handlers.extHandlers[0] + self.assertEqual('OSTCExtensions.ExampleHandlerLinux', ext_handler.name) + self.assertEqual(config_version, ext_handler.properties.version, "config version.") + ExtHandlerInstance(ext_handler, protocol).decide_version() + self.assertEqual(decision_version, ext_handler.properties.version, "decision version.") + + def test_ext_handler_version_decide_between_minor_versions(self, *args): + """ + Using v2.x~v4.x for unit testing + Available versions via manifest XML (I stands for internal): + 2.0.0, 2.1.0, 2.1.1, 2.2.0, 2.3.0(I), 2.4.0(I), 3.0, 3.1, 4.0.0.0, 4.0.0.1, 4.1.0.0 + """ + + # (config_version, exptected_version, autoupgrade_expected_version) + cases = [ + ('2.0', '2.0.0', '2.2.0'), + ('2.0.0', '2.0.0', '2.2.0'), + ('2.1.0', '2.1.1', '2.2.0'), + ('2.2.0', '2.2.0', '2.2.0'), + ('2.3.0', '2.3.0', '2.4.0'), + ('2.4.0', '2.4.0', '2.4.0'), + ('3.0', '3.0', '3.1'), + ('4.0', '4.0.0.1', '4.1.0.0'), + ] + + _, protocol = self._create_mock(WireProtocolData(DATA_FILE), *args) + version_uri = Mock() + version_uri.uri = 'http://some/Microsoft.OSTCExtensions_ExampleHandlerLinux_asiaeast_manifest.xml' + + for (config_version, expected_version, autoupgrade_expected_version) in cases: + ext_handler = Mock() + ext_handler.properties = Mock() + ext_handler.name = 'OSTCExtensions.ExampleHandlerLinux' + ext_handler.versionUris = [version_uri] + ext_handler.properties.version = config_version + ExtHandlerInstance(ext_handler, protocol).decide_version() + self.assertEqual(expected_version, ext_handler.properties.version) + + ext_handler.properties.version = config_version + ext_handler.properties.upgradePolicy = 'auto' + ExtHandlerInstance(ext_handler, protocol).decide_version() + self.assertEqual(autoupgrade_expected_version, ext_handler.properties.version) + + def test_ext_handler_version_invalid_versions(self, *args): + cases = ['2', '2.5', '2.0.1'] + + _, protocol = self._create_mock(WireProtocolData(DATA_FILE), *args) + version_uri = Mock() + version_uri.uri = 'http://some/Microsoft.OSTCExtensions_ExampleHandlerLinux_asiaeast_manifest.xml' + + for config_version in cases: + ext_handler = Mock() + ext_handler.properties = Mock() + ext_handler.name = 'OSTCExtensions.ExampleHandlerLinux' + ext_handler.versionUris = [version_uri] + ext_handler.properties.version = config_version + with self.assertRaises(ExtensionError): + ExtHandlerInstance(ext_handler, protocol).decide_version() + if __name__ == '__main__': unittest.main() diff --git a/tests/protocol/mockwiredata.py b/tests/protocol/mockwiredata.py index 6ffd19c..2bfb0e9 100644 --- a/tests/protocol/mockwiredata.py +++ b/tests/protocol/mockwiredata.py @@ -44,6 +44,15 @@ DATA_FILE_EXT_NO_SETTINGS["ext_conf"] = "wire/ext_conf_no_settings.xml" DATA_FILE_EXT_NO_PUBLIC = DATA_FILE.copy() DATA_FILE_EXT_NO_PUBLIC["ext_conf"] = "wire/ext_conf_no_public.xml" +DATA_FILE_EXT_AUTOUPGRADE = DATA_FILE.copy() +DATA_FILE_EXT_AUTOUPGRADE["ext_conf"] = "wire/ext_conf_autoupgrade.xml" + +DATA_FILE_EXT_INTERNALVERSION = DATA_FILE.copy() +DATA_FILE_EXT_INTERNALVERSION["ext_conf"] = "wire/ext_conf_internalversion.xml" + +DATA_FILE_EXT_AUTOUPGRADE_INTERNALVERSION = DATA_FILE.copy() +DATA_FILE_EXT_AUTOUPGRADE_INTERNALVERSION["ext_conf"] = "wire/ext_conf_autoupgrade_internalversion.xml" + class WireProtocolData(object): def __init__(self, data_files=DATA_FILE): self.version_info = load_data(data_files.get("version_info"))