summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cloudinit/settings.py1
-rw-r--r--cloudinit/sources/DataSourceAliYun.py14
-rw-r--r--cloudinit/sources/DataSourceEc2.py7
-rw-r--r--tests/unittests/test_datasource/test_aliyun.py51
-rw-r--r--tests/unittests/test_datasource/test_common.py1
-rw-r--r--tests/unittests/test_ds_identify.py18
-rwxr-xr-xtools/ds-identify12
7 files changed, 96 insertions, 8 deletions
diff --git a/cloudinit/settings.py b/cloudinit/settings.py
index 411960d8..0abd8a4a 100644
--- a/cloudinit/settings.py
+++ b/cloudinit/settings.py
@@ -29,6 +29,7 @@ CFG_BUILTIN = {
'MAAS',
'GCE',
'OpenStack',
+ 'AliYun',
'Ec2',
'CloudSigma',
'CloudStack',
diff --git a/cloudinit/sources/DataSourceAliYun.py b/cloudinit/sources/DataSourceAliYun.py
index 9debe947..380e27cb 100644
--- a/cloudinit/sources/DataSourceAliYun.py
+++ b/cloudinit/sources/DataSourceAliYun.py
@@ -4,8 +4,10 @@ import os
from cloudinit import sources
from cloudinit.sources import DataSourceEc2 as EC2
+from cloudinit import util
DEF_MD_VERSION = "2016-01-01"
+ALIYUN_PRODUCT = "Alibaba Cloud ECS"
class DataSourceAliYun(EC2.DataSourceEc2):
@@ -24,7 +26,17 @@ class DataSourceAliYun(EC2.DataSourceEc2):
@property
def cloud_platform(self):
- return EC2.Platforms.ALIYUN
+ if self._cloud_platform is None:
+ if _is_aliyun():
+ self._cloud_platform = EC2.Platforms.ALIYUN
+ else:
+ self._cloud_platform = EC2.Platforms.NO_EC2_METADATA
+
+ return self._cloud_platform
+
+
+def _is_aliyun():
+ return util.read_dmi_data('system-product-name') == ALIYUN_PRODUCT
def parse_public_keys(public_keys):
diff --git a/cloudinit/sources/DataSourceEc2.py b/cloudinit/sources/DataSourceEc2.py
index 2f9c7edf..9e2fdc0a 100644
--- a/cloudinit/sources/DataSourceEc2.py
+++ b/cloudinit/sources/DataSourceEc2.py
@@ -32,7 +32,12 @@ class Platforms(object):
AWS = "AWS"
BRIGHTBOX = "Brightbox"
SEEDED = "Seeded"
+ # UNKNOWN indicates no positive id. If strict_id is 'warn' or 'false',
+ # then an attempt at the Ec2 Metadata service will be made.
UNKNOWN = "Unknown"
+ # NO_EC2_METADATA indicates this platform does not have a Ec2 metadata
+ # service available. No attempt at the Ec2 Metadata service will be made.
+ NO_EC2_METADATA = "No-EC2-Metadata"
class DataSourceEc2(sources.DataSource):
@@ -65,6 +70,8 @@ class DataSourceEc2(sources.DataSource):
strict_mode, self.cloud_platform)
if strict_mode == "true" and self.cloud_platform == Platforms.UNKNOWN:
return False
+ elif self.cloud_platform == Platforms.NO_EC2_METADATA:
+ return False
try:
if not self.wait_for_metadata_service():
diff --git a/tests/unittests/test_datasource/test_aliyun.py b/tests/unittests/test_datasource/test_aliyun.py
index c16d1a6e..990bff2c 100644
--- a/tests/unittests/test_datasource/test_aliyun.py
+++ b/tests/unittests/test_datasource/test_aliyun.py
@@ -2,6 +2,7 @@
import functools
import httpretty
+import mock
import os
from .. import helpers as test_helpers
@@ -111,15 +112,29 @@ class TestAliYunDatasource(test_helpers.HttprettyTestCase):
self.assertEqual(self.default_metadata['hostname'],
self.ds.get_hostname())
+ @mock.patch("cloudinit.sources.DataSourceAliYun._is_aliyun")
@httpretty.activate
- def test_with_mock_server(self):
+ def test_with_mock_server(self, m_is_aliyun):
+ m_is_aliyun.return_value = True
self.regist_default_server()
- self.ds.get_data()
+ ret = self.ds.get_data()
+ self.assertEqual(True, ret)
+ self.assertEqual(1, m_is_aliyun.call_count)
self._test_get_data()
self._test_get_sshkey()
self._test_get_iid()
self._test_host_name()
+ @mock.patch("cloudinit.sources.DataSourceAliYun._is_aliyun")
+ @httpretty.activate
+ def test_returns_false_when_not_on_aliyun(self, m_is_aliyun):
+ """If is_aliyun returns false, then get_data should return False."""
+ m_is_aliyun.return_value = False
+ self.regist_default_server()
+ ret = self.ds.get_data()
+ self.assertEqual(1, m_is_aliyun.call_count)
+ self.assertEqual(False, ret)
+
def test_parse_public_keys(self):
public_keys = {}
self.assertEqual(ay.parse_public_keys(public_keys), [])
@@ -149,4 +164,36 @@ class TestAliYunDatasource(test_helpers.HttprettyTestCase):
self.assertEqual(ay.parse_public_keys(public_keys),
public_keys['key-pair-0']['openssh-key'])
+
+class TestIsAliYun(test_helpers.CiTestCase):
+ ALIYUN_PRODUCT = 'Alibaba Cloud ECS'
+ read_dmi_data_expected = [mock.call('system-product-name')]
+
+ @mock.patch("cloudinit.sources.DataSourceAliYun.util.read_dmi_data")
+ def test_true_on_aliyun_product(self, m_read_dmi_data):
+ """Should return true if the dmi product data has expected value."""
+ m_read_dmi_data.return_value = self.ALIYUN_PRODUCT
+ ret = ay._is_aliyun()
+ self.assertEqual(self.read_dmi_data_expected,
+ m_read_dmi_data.call_args_list)
+ self.assertEqual(True, ret)
+
+ @mock.patch("cloudinit.sources.DataSourceAliYun.util.read_dmi_data")
+ def test_false_on_empty_string(self, m_read_dmi_data):
+ """Should return false on empty value returned."""
+ m_read_dmi_data.return_value = ""
+ ret = ay._is_aliyun()
+ self.assertEqual(self.read_dmi_data_expected,
+ m_read_dmi_data.call_args_list)
+ self.assertEqual(False, ret)
+
+ @mock.patch("cloudinit.sources.DataSourceAliYun.util.read_dmi_data")
+ def test_false_on_unknown_string(self, m_read_dmi_data):
+ """Should return false on an unrelated string."""
+ m_read_dmi_data.return_value = "cubs win"
+ ret = ay._is_aliyun()
+ self.assertEqual(self.read_dmi_data_expected,
+ m_read_dmi_data.call_args_list)
+ self.assertEqual(False, ret)
+
# vi: ts=4 expandtab
diff --git a/tests/unittests/test_datasource/test_common.py b/tests/unittests/test_datasource/test_common.py
index c08717f3..7649b9ae 100644
--- a/tests/unittests/test_datasource/test_common.py
+++ b/tests/unittests/test_datasource/test_common.py
@@ -36,6 +36,7 @@ DEFAULT_LOCAL = [
]
DEFAULT_NETWORK = [
+ AliYun.DataSourceAliYun,
AltCloud.DataSourceAltCloud,
Azure.DataSourceAzureNet,
Bigstep.DataSourceBigstep,
diff --git a/tests/unittests/test_ds_identify.py b/tests/unittests/test_ds_identify.py
index f5694b26..5c26e65f 100644
--- a/tests/unittests/test_ds_identify.py
+++ b/tests/unittests/test_ds_identify.py
@@ -220,6 +220,20 @@ class TestDsIdentify(CiTestCase):
mydata['files'][cfgpath] = 'datasource_list: ["Ec2", "None"]\n'
self._check_via_dict(mydata, rc=RC_FOUND, dslist=['Ec2', DS_NONE])
+ def test_aliyun_identified(self):
+ """Test that Aliyun cloud is identified by product id."""
+ self._test_ds_found('AliYun')
+
+ def test_aliyun_over_ec2(self):
+ """Even if all other factors identified Ec2, AliYun should be used."""
+ mydata = copy.deepcopy(VALID_CFG['Ec2-xen'])
+ self._test_ds_found('AliYun')
+ prod_name = VALID_CFG['AliYun']['files'][P_PRODUCT_NAME]
+ mydata['files'][P_PRODUCT_NAME] = prod_name
+ policy = "search,found=first,maybe=none,notfound=disabled"
+ self._check_via_dict(mydata, rc=RC_FOUND, dslist=['AliYun', DS_NONE],
+ policy_dmi=policy)
+
def blkid_out(disks=None):
"""Convert a list of disk dictionaries into blkid content."""
@@ -254,6 +268,10 @@ def _print_run_output(rc, out, err, cfg, files):
VALID_CFG = {
+ 'AliYun': {
+ 'ds': 'AliYun',
+ 'files': {P_PRODUCT_NAME: 'Alibaba Cloud ECS\n'},
+ },
'Ec2-hvm': {
'ds': 'Ec2',
'mocks': [{'name': 'detect_virt', 'RET': 'kvm', 'ret': 0}],
diff --git a/tools/ds-identify b/tools/ds-identify
index 74d26537..5fc500b9 100755
--- a/tools/ds-identify
+++ b/tools/ds-identify
@@ -110,7 +110,8 @@ DI_DSNAME=""
# this has to match the builtin list in cloud-init, it is what will
# be searched if there is no setting found in config.
DI_DSLIST_DEFAULT="MAAS ConfigDrive NoCloud AltCloud Azure Bigstep \
-CloudSigma CloudStack DigitalOcean Ec2 GCE OpenNebula OpenStack OVF SmartOS"
+CloudSigma CloudStack DigitalOcean AliYun Ec2 GCE OpenNebula OpenStack \
+OVF SmartOS"
DI_DSLIST=""
DI_MODE=""
DI_ON_FOUND=""
@@ -821,10 +822,11 @@ dscheck_OpenStack() {
}
dscheck_AliYun() {
- # aliyun is not enabled by default (LP: #1638931)
- # so if we are here, it is because the datasource_list was
- # set to include it. Thus, 'maybe'.
- return $DS_MAYBE
+ check_seed_dir "AliYun" meta-data user-data && return ${DS_FOUND}
+ if dmi_product_name_is "Alibaba Cloud ECS"; then
+ return $DS_FOUND
+ fi
+ return $DS_NOT_FOUND
}
dscheck_AltCloud() {