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