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"))