Repository: Azure/WALinuxAgent
Pull request #1189 (2018-05-23 22:02:12)

fix unhandled errors
Took a look at the top unhandled errors which had a traceback, made some minor fixes.


Patch:
diff --git a/azurelinuxagent/common/osutil/default.py b/azurelinuxagent/common/osutil/default.py
index d08daea1..9c66ac21 100644
--- a/azurelinuxagent/common/osutil/default.py
+++ b/azurelinuxagent/common/osutil/default.py
@@ -1046,20 +1046,24 @@ class DefaultOSUtil(object):
         device = None
         path = "/sys/bus/vmbus/devices/"
         if os.path.exists(path):
-            for vmbus in os.listdir(path):
-                deviceid = fileutil.read_file(os.path.join(path, vmbus, "device_id"))
-                guid = deviceid.lstrip('{').split('-')
-                if guid[0] == g0 and guid[1] == "000" + ustr(port_id):
-                    for root, dirs, files in os.walk(path + vmbus):
-                        if root.endswith("/block"):
-                            device = dirs[0]
-                            break
-                        else : #older distros
-                            for d in dirs:
-                                if ':' in d and "block" == d.split(':')[0]:
-                                    device = d.split(':')[1]
-                                    break
-                    break
+            try:
+                for vmbus in os.listdir(path):
+                    deviceid = fileutil.read_file(os.path.join(path, vmbus, "device_id"))
+                    guid = deviceid.lstrip('{').split('-')
+                    if guid[0] == g0 and guid[1] == "000" + ustr(port_id):
+                        for root, dirs, files in os.walk(path + vmbus):
+                            if root.endswith("/block"):
+                                device = dirs[0]
+                                break
+                            else:
+                                # older distros
+                                for d in dirs:
+                                    if ':' in d and "block" == d.split(':')[0]:
+                                        device = d.split(':')[1]
+                                        break
+                        break
+            except OSError as oe:
+                logger.warn('Could not obtain device for IDE port {0}: {1}', port_id, ustr(oe))
         return device
 
     def set_hostname_record(self, hostname):
diff --git a/azurelinuxagent/common/protocol/imds.py b/azurelinuxagent/common/protocol/imds.py
index c0deb358..a46b198e 100644
--- a/azurelinuxagent/common/protocol/imds.py
+++ b/azurelinuxagent/common/protocol/imds.py
@@ -1,25 +1,169 @@
 # Copyright (c) Microsoft Corporation. All rights reserved.
 # Licensed under the Apache License, Version 2.0 (the "License");
 import json
+import re
 
 import azurelinuxagent.common.utils.restutil as restutil
-from azurelinuxagent.common.exception import HttpError, ProtocolError
+from azurelinuxagent.common.exception import HttpError
 from azurelinuxagent.common.future import ustr
+import azurelinuxagent.common.logger as logger
 from azurelinuxagent.common.protocol.restapi import DataContract, set_properties
+from azurelinuxagent.common.utils.flexible_version import FlexibleVersion
 
 IMDS_ENDPOINT = '169.254.169.254'
 APIVERSION = '2017-12-01'
 BASE_URI = "http://{0}/metadata/instance/{1}?api-version={2}"
 
+IMDS_IMAGE_ORIGIN_UNKNOWN = 0
+IMDS_IMAGE_ORIGIN_CUSTOM = 1
+IMDS_IMAGE_ORIGIN_ENDORSED = 2
+IMDS_IMAGE_ORIGIN_PLATFORM = 3
+
 
 def get_imds_client():
     return ImdsClient()
 
 
+# A *slightly* future proof list of endorsed distros.
+#  -> e.g. I have predicted the future and said that 20.04-LTS will exist
+#     and is endored.
+#
+# See https://docs.microsoft.com/en-us/azure/virtual-machines/linux/endorsed-distros for
+# more details.
+#
+# This is not an exhaustive list. This is a best attempt to mark images as
+# endorsed or not.  Image publishers do not encode all of the requisite information
+# in their publisher, offer, sku, and version to definitively mark something as
+# endorsed or not.  This is not perfect, but it is approximately 98% perfect.
+ENDORSED_IMAGE_INFO_MATCHER_JSON = """{
+    "CANONICAL": {
+        "UBUNTUSERVER": {
+            "List": [
+                "14.04.0-LTS",
+                "14.04.1-LTS",
+                "14.04.2-LTS",
+                "14.04.3-LTS",
+                "14.04.4-LTS",
+                "14.04.5-LTS",
+                "14.04.6-LTS",
+                "14.04.7-LTS",
+                "14.04.8-LTS",
+                
+                "16.04-LTS",
+                "16.04.0-LTS",
+                "18.04-LTS",
+                "20.04-LTS",
+                "22.04-LTS"
+            ]
+        }
+    },
+    "COREOS": {
+        "COREOS": {
+            "STABLE": { "Minimum": "494.4.0" }
+        }
+    },
+    "CREDATIV": {
+        "DEBIAN": { "Minimum": "7" }
+    },
+    "OPENLOGIC": {
+        "CENTOS": {
+            "Minimum": "6.3",
+            "List": [
+                "7-LVM",
+                "7-RAW"
+            ]
+        },
+        "CENTOS-HPC": { "Minimum": "6.3" }
+    },
+    "REDHAT": {
+        "RHEL": { 
+            "Minimum": "6.7",
+            "List": [
+                "7-LVM",
+                "7-RAW"
+            ]
+        },
+        "RHEL-HANA": { "Minimum": "6.7" },
+        "RHEL-SAP": { "Minimum": "6.7" },
+        "RHEL-SAP-APPS": { "Minimum": "6.7" },
+        "RHEL-SAP-HANA": { "Minimum": "6.7" }
+    },
+    "SUSE": {
+        "SLES": {
+            "List": [
+                "11-SP4",
+                "11-SP5",
+                "11-SP6",
+                "12-SP1",
+                "12-SP2",
+                "12-SP3",
+                "12-SP4",
+                "12-SP5",
+                "12-SP6"
+            ]
+        },
+        "SLES-BYOS": {
+            "List": [
+                "11-SP4",
+                "11-SP5",
+                "11-SP6",
+                "12-SP1",
+                "12-SP2",
+                "12-SP3",
+                "12-SP4",
+                "12-SP5",
+                "12-SP6"
+            ]
+        },
+        "SLES-SAP": {
+            "List": [
+                "11-SP4",
+                "11-SP5",
+                "11-SP6",
+                "12-SP1",
+                "12-SP2",
+                "12-SP3",
+                "12-SP4",
+                "12-SP5",
+                "12-SP6"
+            ]
+        }
+    }
+}"""
+
+
+class ImageInfoMatcher(object):
+    def __init__(self, doc):
+        self.doc = json.loads(doc)
+
+    def is_match(self, publisher, offer, sku, version):
+        def _is_match_walk(doci, keys):
+            key = keys.pop(0).upper()
+            if key is None:
+                return False
+
+            if key not in doci:
+                return False
+
+            if 'List' in doci[key] and keys[0] in doci[key]['List']:
+                return True
+
+            if 'Match' in doci[key] and re.match(doci[key]['Match'], keys[0]):
+                return True
+
+            if 'Minimum' in doci[key]:
+                try:
+                    return FlexibleVersion(keys[0]) >= FlexibleVersion(doci[key]['Minimum'])
+                except ValueError:
+                    pass
+
+            return _is_match_walk(doci[key], keys)
+
+        return _is_match_walk(self.doc, [ publisher, offer, sku, version ])
+
+
 class ComputeInfo(DataContract):
-    @property
-    def image_info(self):
-        return "{0}:{1}:{2}:{3}".format(self.publisher, self.offer, self.sku, self.version)
+    __matcher = ImageInfoMatcher(ENDORSED_IMAGE_INFO_MATCHER_JSON)
 
     def __init__(self,
                  location=None,
@@ -58,6 +202,35 @@ class ComputeInfo(DataContract):
         self.zone = zone
 
 
+    @property
+    def image_info(self):
+        return "{0}:{1}:{2}:{3}".format(self.publisher, self.offer, self.sku, self.version)
+
+    @property
+    def image_origin(self):
+        """
+        An integer value describing the origin of the image.
+
+          0 -> unknown
+          1 -> custom - user created image
+          2 -> endorsed - See https://docs.microsoft.com/en-us/azure/virtual-machines/linux/endorsed-distros
+          3 -> platform - non-endorsed image that is available in the Azure Marketplace.
+        """
+
+        try:
+            if self.publisher == "":
+                return IMDS_IMAGE_ORIGIN_CUSTOM
+
+            if ComputeInfo.__matcher.is_match(self.publisher, self.offer, self.sku, self.version):
+                return IMDS_IMAGE_ORIGIN_ENDORSED
+            else:
+                return IMDS_IMAGE_ORIGIN_PLATFORM
+
+        except Exception as e:
+            logger.warn("Could not determine the image origin from IMDS: {0}", str(e))
+            return IMDS_IMAGE_ORIGIN_UNKNOWN
+
+
 class ImdsClient(object):
     def __init__(self, version=APIVERSION):
         self._api_version = version
diff --git a/azurelinuxagent/daemon/resourcedisk/default.py b/azurelinuxagent/daemon/resourcedisk/default.py
index 97c67b2a..0f0925d7 100644
--- a/azurelinuxagent/daemon/resourcedisk/default.py
+++ b/azurelinuxagent/daemon/resourcedisk/default.py
@@ -305,13 +305,13 @@ class ResourceDiskHandler(object):
                 # Probable errors:
                 #  - OSError: Seen on Cygwin, libc notimpl?
                 #  - AttributeError: What if someone runs this under...
-                with open(filename, 'w') as f:
-                    try:
+                try:
+                    with open(filename, 'w') as f:
                         os.posix_fallocate(f.fileno(), 0, nbytes)
                         return 0
-                    except:
-                        # Not confident with this thing, just keep trying...
-                        pass
+                except:
+                    # Not confident with this thing, just keep trying...
+                    pass
 
             # fallocate command
             ret = shellutil.run(
diff --git a/azurelinuxagent/ga/monitor.py b/azurelinuxagent/ga/monitor.py
index a07d9a35..e1bfd2a6 100644
--- a/azurelinuxagent/ga/monitor.py
+++ b/azurelinuxagent/ga/monitor.py
@@ -154,6 +154,8 @@ class MonitorHandler(object):
                                                     vminfo.resourceGroupName))
             self.sysinfo.append(TelemetryEventParam('VMId',
                                                     vminfo.vmId))
+            self.sysinfo.append(TelemetryEventParam('ImageOrigin',
+                                                    vminfo.image_origin))
         except (HttpError, ValueError) as e:
             logger.warn("failed to get IMDS info: {0}", e)
 


Test patch:
diff --git a/tests/protocol/test_image_info_matcher.py b/tests/protocol/test_image_info_matcher.py
new file mode 100644
index 00000000..5cae2a6c
--- /dev/null
+++ b/tests/protocol/test_image_info_matcher.py
@@ -0,0 +1,129 @@
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the Apache License, Version 2.0 (the "License");
+import json
+
+from azurelinuxagent.common.exception import HttpError
+from azurelinuxagent.common.protocol.imds import ComputeInfo, ImdsClient, IMDS_IMAGE_ORIGIN_CUSTOM, \
+    IMDS_IMAGE_ORIGIN_ENDORSED, IMDS_IMAGE_ORIGIN_PLATFORM, ImageInfoMatcher
+from azurelinuxagent.common.protocol.restapi import set_properties
+from azurelinuxagent.common.utils import restutil
+from tests.ga.test_update import ResponseMock
+from tests.tools import *
+
+
+class TestImageInfoMatcher(unittest.TestCase):
+    def test_image_does_not_exist(self):
+        doc = '{}'
+
+        test_subject = ImageInfoMatcher(doc)
+        self.assertFalse(test_subject.is_match("Red Hat", "RHEL", "6.3", ""))
+
+    def test_image_exists_by_sku(self):
+        doc = '''{
+            "CANONICAL": {
+                "UBUNTUSERVER": {
+                    "16.04-LTS": { "Match": ".*" }
+                }
+            }
+        }'''
+
+        test_subject = ImageInfoMatcher(doc)
+        self.assertTrue(test_subject.is_match("Canonical", "UbuntuServer", "16.04-LTS", ""))
+        self.assertTrue(test_subject.is_match("Canonical", "UbuntuServer", "16.04-LTS", "16.04.201805090"))
+
+        self.assertFalse(test_subject.is_match("Canonical", "UbuntuServer", "14.04.0-LTS", "16.04.201805090"))
+
+    def test_image_exists_by_version(self):
+        doc = '''{
+            "REDHAT": {
+                "RHEL": {
+                    "Minimum": "6.3"
+                }
+            }
+        }'''
+
+        test_subject = ImageInfoMatcher(doc)
+        self.assertFalse(test_subject.is_match("RedHat", "RHEL", "6.1", ""))
+        self.assertFalse(test_subject.is_match("RedHat", "RHEL", "6.2", ""))
+
+        self.assertTrue(test_subject.is_match("RedHat", "RHEL", "6.3", ""))
+        self.assertTrue(test_subject.is_match("RedHat", "RHEL", "6.4", ""))
+        self.assertTrue(test_subject.is_match("RedHat", "RHEL", "6.5", ""))
+        self.assertTrue(test_subject.is_match("RedHat", "RHEL", "7.0", ""))
+        self.assertTrue(test_subject.is_match("RedHat", "RHEL", "7.1", ""))
+
+    def test_image_exists_by_version01(self):
+        """
+        Test case to ensure the matcher exhaustively searches all cases.
+
+        REDHAT/RHEL have a SKU >= 6.3 is less precise than
+        REDHAT/RHEL/7-LVM have a any version.
+
+        Both should return a successful match.
+        """
+        doc = '''{
+            "REDHAT": {
+                "RHEL": { 
+                    "Minimum": "6.3", 
+                    "7-LVM": { "Match": ".*" }
+                }
+            }
+        }'''
+
+        test_subject = ImageInfoMatcher(doc)
+
+        self.assertTrue(test_subject.is_match("RedHat", "RHEL", "6.3", ""))
+        self.assertTrue(test_subject.is_match("RedHat", "RHEL", "7-LVM", ""))
+
+    def test_ignores_case(self):
+        doc = '''{
+            "CANONICAL": {
+                "UBUNTUSERVER": {
+                    "16.04-LTS": { "Match": ".*" }
+                }
+            }
+        }'''
+
+        test_subject = ImageInfoMatcher(doc)
+        self.assertTrue(test_subject.is_match("canonical", "ubuntuserver", "16.04-lts", ""))
+        self.assertFalse(test_subject.is_match("canonical", "ubuntuserver", "14.04.0-lts", "16.04.201805090"))
+
+    def test_list_operator(self):
+        doc = '''{
+            "CANONICAL": {
+                "UBUNTUSERVER": {
+                    "List": [ "14.04.0-LTS", "14.04.1-LTS" ]
+                }
+            }
+        }'''
+
+        test_subject = ImageInfoMatcher(doc)
+        self.assertTrue(test_subject.is_match("Canonical", "UbuntuServer", "14.04.0-LTS", ""))
+        self.assertTrue(test_subject.is_match("Canonical", "UbuntuServer", "14.04.1-LTS", ""))
+
+        self.assertFalse(test_subject.is_match("Canonical", "UbuntuServer", "22.04-LTS", ""))
+
+    def test_invalid_version(self):
+        doc = '''{
+            "REDHAT": {
+                "RHEL": {
+                    "Minimum": "6.3"
+                }
+            }
+        }'''
+
+        test_subject = ImageInfoMatcher(doc)
+        self.assertFalse(test_subject.is_match("RedHat", "RHEL", "16.04-LTS", ""))
+
+        # This is *expected* behavior as opposed to desirable.  The specification is
+        # controlled by the agent, so there is no reason to use these values, but if
+        # one does this is expected behavior.
+        #
+        # FlexibleVersion chops off all leading zeros.
+        self.assertTrue(test_subject.is_match("RedHat", "RHEL", "6.04", ""))
+        # FlexibleVersion coerces everything to a string
+        self.assertTrue(test_subject.is_match("RedHat", "RHEL", 6.04, ""))
+
+
+if __name__ == '__main__':
+    unittest.main()
diff --git a/tests/protocol/test_imds.py b/tests/protocol/test_imds.py
index d0f65292..32512001 100644
--- a/tests/protocol/test_imds.py
+++ b/tests/protocol/test_imds.py
@@ -2,8 +2,9 @@
 # Licensed under the Apache License, Version 2.0 (the "License");
 import json
 
+import azurelinuxagent.common.protocol.imds as imds
+
 from azurelinuxagent.common.exception import HttpError
-from azurelinuxagent.common.protocol.imds import ComputeInfo, ImdsClient
 from azurelinuxagent.common.protocol.restapi import set_properties
 from azurelinuxagent.common.utils import restutil
 from tests.ga.test_update import ResponseMock
@@ -31,7 +32,7 @@ class TestImds(AgentTestCase):
         "vmSize": "Standard_D1_v2"
         }'''.encode('utf-8'))
 
-        test_subject = ImdsClient()
+        test_subject = imds.ImdsClient()
         test_subject.get_compute()
 
         self.assertEqual(1, mock_http_get.call_count)
@@ -46,14 +47,14 @@ class TestImds(AgentTestCase):
     def test_get_bad_request(self, mock_http_get):
         mock_http_get.return_value = ResponseMock(status=restutil.httpclient.BAD_REQUEST)
 
-        test_subject = ImdsClient()
+        test_subject = imds.ImdsClient()
         self.assertRaises(HttpError, test_subject.get_compute)
 
     @patch("azurelinuxagent.ga.update.restutil.http_get")
     def test_get_empty_response(self, mock_http_get):
         mock_http_get.return_value = ResponseMock(response=''.encode('utf-8'))
 
-        test_subject = ImdsClient()
+        test_subject = imds.ImdsClient()
         self.assertRaises(ValueError, test_subject.get_compute)
 
     def test_deserialize_ComputeInfo(self):
@@ -79,7 +80,7 @@ class TestImds(AgentTestCase):
 
         data = json.loads(s, encoding='utf-8')
 
-        compute_info = ComputeInfo()
+        compute_info = imds.ComputeInfo()
         set_properties("compute", compute_info, data)
 
         self.assertEqual('westcentralus', compute_info.location)
@@ -102,3 +103,136 @@ class TestImds(AgentTestCase):
 
         self.assertEqual('UnitPublisher:UnitOffer:UnitSku:UnitVersion', compute_info.image_info)
 
+    def test_is_custom_image(self):
+        image_origin = self._setup_image_origin_assert("", "", "", "")
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_CUSTOM, image_origin)
+
+    def test_is_endorsed_CentOS(self):
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("OpenLogic", "CentOS", "6.3", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("OpenLogic", "CentOS", "6.4", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("OpenLogic", "CentOS", "6.5", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("OpenLogic", "CentOS", "6.6", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("OpenLogic", "CentOS", "6.7", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("OpenLogic", "CentOS", "6.8", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("OpenLogic", "CentOS", "6.9", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("OpenLogic", "CentOS", "7.0", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("OpenLogic", "CentOS", "7.1", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("OpenLogic", "CentOS", "7.2", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("OpenLogic", "CentOS", "7.3", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("OpenLogic", "CentOS", "7.4", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("OpenLogic", "CentOS", "7-LVM", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("OpenLogic", "CentOS", "7-RAW", ""))
+
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("OpenLogic", "CentOS-HPC", "6.5", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("OpenLogic", "CentOS-HPC", "6.8", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("OpenLogic", "CentOS-HPC", "7.1", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("OpenLogic", "CentOS-HPC", "7.3", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("OpenLogic", "CentOS-HPC", "7.4", ""))
+
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_PLATFORM, self._setup_image_origin_assert("OpenLogic", "CentOS", "6.2", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_PLATFORM, self._setup_image_origin_assert("OpenLogic", "CentOS", "6.1", ""))
+
+    def test_is_endorsed_CoreOS(self):
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("CoreOS", "CoreOS", "stable", "494.4.0"))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("CoreOS", "CoreOS", "stable", "899.17.0"))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("CoreOS", "CoreOS", "stable", "1688.5.3"))
+
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_PLATFORM, self._setup_image_origin_assert("CoreOS", "CoreOS", "stable", "494.3.0"))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_PLATFORM, self._setup_image_origin_assert("CoreOS", "CoreOS", "alpha", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_PLATFORM, self._setup_image_origin_assert("CoreOS", "CoreOS", "beta", ""))
+
+    def test_is_endorsed_Debian(self):
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("credativ", "Debian", "7", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("credativ", "Debian", "8", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("credativ", "Debian", "9", ""))
+
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_PLATFORM, self._setup_image_origin_assert("credativ", "Debian", "9-DAILY", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_PLATFORM, self._setup_image_origin_assert("credativ", "Debian", "10-DAILY", ""))
+
+    def test_is_endorsed_Rhel(self):
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("RedHat", "RHEL", "6.7", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("RedHat", "RHEL", "6.8", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("RedHat", "RHEL", "6.9", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("RedHat", "RHEL", "7.0", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("RedHat", "RHEL", "7.1", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("RedHat", "RHEL", "7.2", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("RedHat", "RHEL", "7.3", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("RedHat", "RHEL", "7.4", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("RedHat", "RHEL", "7-LVM", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("RedHat", "RHEL", "7-RAW", ""))
+
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("RedHat", "RHEL-SAP-HANA", "7.2", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("RedHat", "RHEL-SAP-HANA", "7.3", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("RedHat", "RHEL-SAP-HANA", "7.4", ""))
+
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("RedHat", "RHEL-SAP", "7.2", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("RedHat", "RHEL-SAP", "7.3", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("RedHat", "RHEL-SAP", "7.4", ""))
+
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("RedHat", "RHEL-SAP-APPS", "7.2", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("RedHat", "RHEL-SAP-APPS", "7.3", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("RedHat", "RHEL-SAP-APPS", "7.4", ""))
+
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_PLATFORM, self._setup_image_origin_assert("RedHat", "RHEL", "6.6", ""))
+
+
+    def test_is_endorsed_SuSE(self):
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("SuSE", "SLES", "11-SP4", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("SuSE", "SLES-BYOS", "11-SP4", ""))
+
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("SuSE", "SLES", "12-SP1", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("SuSE", "SLES", "12-SP2", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("SuSE", "SLES", "12-SP3", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("SuSE", "SLES", "12-SP4", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("SuSE", "SLES", "12-SP5", ""))
+
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("SuSE", "SLES-BYOS", "12-SP1", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("SuSE", "SLES-BYOS", "12-SP2", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("SuSE", "SLES-BYOS", "12-SP3", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("SuSE", "SLES-BYOS", "12-SP4", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("SuSE", "SLES-BYOS", "12-SP5", ""))
+
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("SuSE", "SLES-SAP", "12-SP1", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("SuSE", "SLES-SAP", "12-SP2", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("SuSE", "SLES-SAP", "12-SP3", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("SuSE", "SLES-SAP", "12-SP4", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("SuSE", "SLES-SAP", "12-SP5", ""))
+
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_PLATFORM, self._setup_image_origin_assert("SuSE", "SLES", "11-SP3", ""))
+
+    def test_is_endorsed_UbuntuServer(self):
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("Canonical", "UbuntuServer", "14.04.0-LTS", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("Canonical", "UbuntuServer", "14.04.1-LTS", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("Canonical", "UbuntuServer", "14.04.2-LTS", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("Canonical", "UbuntuServer", "14.04.3-LTS", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("Canonical", "UbuntuServer", "14.04.4-LTS", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("Canonical", "UbuntuServer", "14.04.5-LTS", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("Canonical", "UbuntuServer", "14.04.6-LTS", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("Canonical", "UbuntuServer", "14.04.7-LTS", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("Canonical", "UbuntuServer", "14.04.8-LTS", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("Canonical", "UbuntuServer", "16.04-LTS", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("Canonical", "UbuntuServer", "18.04-LTS", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("Canonical", "UbuntuServer", "20.04-LTS", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_ENDORSED, self._setup_image_origin_assert("Canonical", "UbuntuServer", "22.04-LTS", ""))
+
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_PLATFORM, self._setup_image_origin_assert("Canonical", "UbuntuServer", "12.04-LTS", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_PLATFORM, self._setup_image_origin_assert("Canonical", "UbuntuServer", "17.10", ""))
+        self.assertEqual(imds.IMDS_IMAGE_ORIGIN_PLATFORM, self._setup_image_origin_assert("Canonical", "UbuntuServer", "18.04-DAILY-LTS", ""))
+
+    def _setup_image_origin_assert(self, publisher, offer, sku, version):
+        s = '''{{
+            "publisher": "{0}",
+            "offer": "{1}",
+            "sku": "{2}",
+            "version": "{3}"
+        }}'''.format(publisher, offer, sku, version)
+
+        data =json.loads(s, encoding='utf-8')
+        compute_info = imds.ComputeInfo()
+        set_properties("compute", compute_info, data)
+
+        return compute_info.image_origin
+
+
+if __name__ == '__main__':
+    unittest.main()