20a859
From a7727ecf117a2bc02f68405823796afe1d76d3e3 Mon Sep 17 00:00:00 2001
20a859
From: Junjie Wang <jingni.wjj@alibaba-inc.com>
20a859
Date: Fri, 21 Apr 2017 20:06:09 +0800
20a859
Subject: [PATCH 4/5] AliYun: Enable platform identification and enable by
20a859
 default.
20a859
20a859
AliYun cloud platform is now identifying themselves by setting the dmi
20a859
product id to the well known value "Alibaba Cloud ECS". The changes here
20a859
identify that properly in tools/ds-identify and in the DataSourceAliYun.
20a859
20a859
Since the 'get_data' for AliYun now identifies itself correctly, we can
20a859
enable AliYun by default.
20a859
20a859
LP: #1638931
20a859
(cherry picked from commit 4a60af54957634920e84a928aa22b4fc9a6dfd11)
20a859
20a859
Resolves: rhbz#1496113
20a859
20a859
Signed-off-by: Ryan McCabe <rmccabe@redhat.com>
20a859
---
20a859
 cloudinit/settings.py                          |  1 +
20a859
 cloudinit/sources/DataSourceAliYun.py          | 14 ++++++-
20a859
 cloudinit/sources/DataSourceEc2.py             |  7 ++++
20a859
 tests/unittests/test_datasource/test_aliyun.py | 51 +++++++++++++++++++++++++-
20a859
 tests/unittests/test_datasource/test_common.py |  1 +
20a859
 5 files changed, 71 insertions(+), 3 deletions(-)
20a859
20a859
diff --git a/cloudinit/settings.py b/cloudinit/settings.py
20a859
index 0d39aab7..d6046dc6 100644
20a859
--- a/cloudinit/settings.py
20a859
+++ b/cloudinit/settings.py
20a859
@@ -27,6 +27,7 @@ CFG_BUILTIN = {
20a859
         'MAAS',
20a859
         'GCE',
20a859
         'OpenStack',
20a859
+        'AliYun',
20a859
         'Ec2',
20a859
         'CloudSigma',
20a859
         'CloudStack',
20a859
diff --git a/cloudinit/sources/DataSourceAliYun.py b/cloudinit/sources/DataSourceAliYun.py
20a859
index 9debe947..380e27cb 100644
20a859
--- a/cloudinit/sources/DataSourceAliYun.py
20a859
+++ b/cloudinit/sources/DataSourceAliYun.py
20a859
@@ -4,8 +4,10 @@ import os
20a859
 
20a859
 from cloudinit import sources
20a859
 from cloudinit.sources import DataSourceEc2 as EC2
20a859
+from cloudinit import util
20a859
 
20a859
 DEF_MD_VERSION = "2016-01-01"
20a859
+ALIYUN_PRODUCT = "Alibaba Cloud ECS"
20a859
 
20a859
 
20a859
 class DataSourceAliYun(EC2.DataSourceEc2):
20a859
@@ -24,7 +26,17 @@ class DataSourceAliYun(EC2.DataSourceEc2):
20a859
 
20a859
     @property
20a859
     def cloud_platform(self):
20a859
-        return EC2.Platforms.ALIYUN
20a859
+        if self._cloud_platform is None:
20a859
+            if _is_aliyun():
20a859
+                self._cloud_platform = EC2.Platforms.ALIYUN
20a859
+            else:
20a859
+                self._cloud_platform = EC2.Platforms.NO_EC2_METADATA
20a859
+
20a859
+        return self._cloud_platform
20a859
+
20a859
+
20a859
+def _is_aliyun():
20a859
+    return util.read_dmi_data('system-product-name') == ALIYUN_PRODUCT
20a859
 
20a859
 
20a859
 def parse_public_keys(public_keys):
20a859
diff --git a/cloudinit/sources/DataSourceEc2.py b/cloudinit/sources/DataSourceEc2.py
20a859
index c7df8060..31825665 100644
20a859
--- a/cloudinit/sources/DataSourceEc2.py
20a859
+++ b/cloudinit/sources/DataSourceEc2.py
20a859
@@ -32,7 +32,12 @@ class Platforms(object):
20a859
     AWS = "AWS"
20a859
     BRIGHTBOX = "Brightbox"
20a859
     SEEDED = "Seeded"
20a859
+    # UNKNOWN indicates no positive id.  If strict_id is 'warn' or 'false',
20a859
+    # then an attempt at the Ec2 Metadata service will be made.
20a859
     UNKNOWN = "Unknown"
20a859
+    # NO_EC2_METADATA indicates this platform does not have a Ec2 metadata
20a859
+    # service available. No attempt at the Ec2 Metadata service will be made.
20a859
+    NO_EC2_METADATA = "No-EC2-Metadata"
20a859
 
20a859
 
20a859
 class DataSourceEc2(sources.DataSource):
20a859
@@ -65,6 +70,8 @@ class DataSourceEc2(sources.DataSource):
20a859
                   strict_mode, self.cloud_platform)
20a859
         if strict_mode == "true" and self.cloud_platform == Platforms.UNKNOWN:
20a859
             return False
20a859
+        elif self.cloud_platform == Platforms.NO_EC2_METADATA:
20a859
+            return False
20a859
 
20a859
         try:
20a859
             if not self.wait_for_metadata_service():
20a859
diff --git a/tests/unittests/test_datasource/test_aliyun.py b/tests/unittests/test_datasource/test_aliyun.py
20a859
index c16d1a6e..990bff2c 100644
20a859
--- a/tests/unittests/test_datasource/test_aliyun.py
20a859
+++ b/tests/unittests/test_datasource/test_aliyun.py
20a859
@@ -2,6 +2,7 @@
20a859
 
20a859
 import functools
20a859
 import httpretty
20a859
+import mock
20a859
 import os
20a859
 
20a859
 from .. import helpers as test_helpers
20a859
@@ -111,15 +112,29 @@ class TestAliYunDatasource(test_helpers.HttprettyTestCase):
20a859
         self.assertEqual(self.default_metadata['hostname'],
20a859
                          self.ds.get_hostname())
20a859
 
20a859
+    @mock.patch("cloudinit.sources.DataSourceAliYun._is_aliyun")
20a859
     @httpretty.activate
20a859
-    def test_with_mock_server(self):
20a859
+    def test_with_mock_server(self, m_is_aliyun):
20a859
+        m_is_aliyun.return_value = True
20a859
         self.regist_default_server()
20a859
-        self.ds.get_data()
20a859
+        ret = self.ds.get_data()
20a859
+        self.assertEqual(True, ret)
20a859
+        self.assertEqual(1, m_is_aliyun.call_count)
20a859
         self._test_get_data()
20a859
         self._test_get_sshkey()
20a859
         self._test_get_iid()
20a859
         self._test_host_name()
20a859
 
20a859
+    @mock.patch("cloudinit.sources.DataSourceAliYun._is_aliyun")
20a859
+    @httpretty.activate
20a859
+    def test_returns_false_when_not_on_aliyun(self, m_is_aliyun):
20a859
+        """If is_aliyun returns false, then get_data should return False."""
20a859
+        m_is_aliyun.return_value = False
20a859
+        self.regist_default_server()
20a859
+        ret = self.ds.get_data()
20a859
+        self.assertEqual(1, m_is_aliyun.call_count)
20a859
+        self.assertEqual(False, ret)
20a859
+
20a859
     def test_parse_public_keys(self):
20a859
         public_keys = {}
20a859
         self.assertEqual(ay.parse_public_keys(public_keys), [])
20a859
@@ -149,4 +164,36 @@ class TestAliYunDatasource(test_helpers.HttprettyTestCase):
20a859
         self.assertEqual(ay.parse_public_keys(public_keys),
20a859
                          public_keys['key-pair-0']['openssh-key'])
20a859
 
20a859
+
20a859
+class TestIsAliYun(test_helpers.CiTestCase):
20a859
+    ALIYUN_PRODUCT = 'Alibaba Cloud ECS'
20a859
+    read_dmi_data_expected = [mock.call('system-product-name')]
20a859
+
20a859
+    @mock.patch("cloudinit.sources.DataSourceAliYun.util.read_dmi_data")
20a859
+    def test_true_on_aliyun_product(self, m_read_dmi_data):
20a859
+        """Should return true if the dmi product data has expected value."""
20a859
+        m_read_dmi_data.return_value = self.ALIYUN_PRODUCT
20a859
+        ret = ay._is_aliyun()
20a859
+        self.assertEqual(self.read_dmi_data_expected,
20a859
+                         m_read_dmi_data.call_args_list)
20a859
+        self.assertEqual(True, ret)
20a859
+
20a859
+    @mock.patch("cloudinit.sources.DataSourceAliYun.util.read_dmi_data")
20a859
+    def test_false_on_empty_string(self, m_read_dmi_data):
20a859
+        """Should return false on empty value returned."""
20a859
+        m_read_dmi_data.return_value = ""
20a859
+        ret = ay._is_aliyun()
20a859
+        self.assertEqual(self.read_dmi_data_expected,
20a859
+                         m_read_dmi_data.call_args_list)
20a859
+        self.assertEqual(False, ret)
20a859
+
20a859
+    @mock.patch("cloudinit.sources.DataSourceAliYun.util.read_dmi_data")
20a859
+    def test_false_on_unknown_string(self, m_read_dmi_data):
20a859
+        """Should return false on an unrelated string."""
20a859
+        m_read_dmi_data.return_value = "cubs win"
20a859
+        ret = ay._is_aliyun()
20a859
+        self.assertEqual(self.read_dmi_data_expected,
20a859
+                         m_read_dmi_data.call_args_list)
20a859
+        self.assertEqual(False, ret)
20a859
+
20a859
 # vi: ts=4 expandtab
20a859
diff --git a/tests/unittests/test_datasource/test_common.py b/tests/unittests/test_datasource/test_common.py
20a859
index c08717f3..7649b9ae 100644
20a859
--- a/tests/unittests/test_datasource/test_common.py
20a859
+++ b/tests/unittests/test_datasource/test_common.py
20a859
@@ -36,6 +36,7 @@ DEFAULT_LOCAL = [
20a859
 ]
20a859
 
20a859
 DEFAULT_NETWORK = [
20a859
+    AliYun.DataSourceAliYun,
20a859
     AltCloud.DataSourceAltCloud,
20a859
     Azure.DataSourceAzureNet,
20a859
     Bigstep.DataSourceBigstep,
20a859
-- 
20a859
2.13.5
20a859