cloud-init-dev team mailing list archive
-
cloud-init-dev team
-
Mailing list archive
-
Message #06689
[Merge] ~ruansx/cloud-init:add-zstack-datasource1 into cloud-init:master
Steve Ruan has proposed merging ~ruansx/cloud-init:add-zstack-datasource1 into cloud-init:master.
Commit message:
Add datastore for ZStack platfrom
AWS EC2 datasource is used by lots of cloud operator, ZStack platform will provide the cloud-init service same as AWS.
ZStack will identify their platform to the guest by setting the 'dmidecode -s chassis-asset-tag' to a string that ends with '.zstack.io'.
LP: #1841181
Requested reviews:
cloud-init Commiters (cloud-init-dev)
Related bugs:
Bug #1841181 in cloud-init: "add datasource for ZStack"
https://bugs.launchpad.net/cloud-init/+bug/1841181
For more details, see:
https://code.launchpad.net/~ruansx/cloud-init/+git/cloud-init/+merge/372830
--
Your team cloud-init Commiters is requested to review the proposed merge of ~ruansx/cloud-init:add-zstack-datasource1 into cloud-init:master.
diff --git a/cloudinit/apport.py b/cloudinit/apport.py
index 003ff1f..fde1f75 100644
--- a/cloudinit/apport.py
+++ b/cloudinit/apport.py
@@ -37,6 +37,7 @@ KNOWN_CLOUD_NAMES = [
'Scaleway',
'SmartOS',
'VMware',
+ 'ZStack',
'Other']
# Potentially clear text collected logs
diff --git a/cloudinit/sources/DataSourceEc2.py b/cloudinit/sources/DataSourceEc2.py
index 1010745..6c72ace 100644
--- a/cloudinit/sources/DataSourceEc2.py
+++ b/cloudinit/sources/DataSourceEc2.py
@@ -33,6 +33,7 @@ class CloudNames(object):
ALIYUN = "aliyun"
AWS = "aws"
BRIGHTBOX = "brightbox"
+ ZSTACK = "zstack"
# 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"
@@ -477,10 +478,16 @@ def identify_brightbox(data):
return CloudNames.BRIGHTBOX
+def identify_zstack(data):
+ if data['asset_tag'].endswith('.zstack.io'):
+ return CloudNames.ZSTACK
+
+
def identify_platform():
# identify the platform and return an entry in CloudNames.
data = _collect_platform_data()
- checks = (identify_aws, identify_brightbox, lambda x: CloudNames.UNKNOWN)
+ checks = (identify_aws, identify_brightbox, identify_zstack,
+ lambda x: CloudNames.UNKNOWN)
for checker in checks:
try:
result = checker(data)
@@ -498,6 +505,7 @@ def _collect_platform_data():
uuid: system-uuid from dmi or /sys/hypervisor
uuid_source: 'hypervisor' (/sys/hypervisor/uuid) or 'dmi'
serial: dmi 'system-serial-number' (/sys/.../product_serial)
+ asset_tag: 'dmidecode -s chassis-asset-tag'
On Ec2 instances experimentation is that product_serial is upper case,
and product_uuid is lower case. This returns lower case values for both.
@@ -520,6 +528,12 @@ def _collect_platform_data():
data['serial'] = serial.lower()
+ asset_tag = util.read_dmi_data('chassis-asset-tag')
+ if asset_tag is None:
+ asset_tag = ''
+
+ data['asset_tag'] = asset_tag.lower()
+
return data
diff --git a/doc/rtd/topics/datasources.rst b/doc/rtd/topics/datasources.rst
index 8e58be9..0872c5b 100644
--- a/doc/rtd/topics/datasources.rst
+++ b/doc/rtd/topics/datasources.rst
@@ -112,6 +112,7 @@ API
The current interface that a datasource object must provide is the following:
+<<<<<<< doc/rtd/topics/datasources.rst
.. sourcecode:: python
# returns a mime multipart message that contains
@@ -163,5 +164,26 @@ The current interface that a datasource object must provide is the following:
def get_hostname(self, fqdn=False)
def get_package_mirror_info(self)
+=======
+ datasources/aliyun.rst
+ datasources/altcloud.rst
+ datasources/azure.rst
+ datasources/cloudsigma.rst
+ datasources/cloudstack.rst
+ datasources/configdrive.rst
+ datasources/digitalocean.rst
+ datasources/ec2.rst
+ datasources/exoscale.rst
+ datasources/maas.rst
+ datasources/nocloud.rst
+ datasources/opennebula.rst
+ datasources/openstack.rst
+ datasources/oracle.rst
+ datasources/ovf.rst
+ datasources/smartos.rst
+ datasources/fallback.rst
+ datasources/gce.rst
+ datasources/zstack.rst
+>>>>>>> doc/rtd/topics/datasources.rst
.. vi: textwidth=79
diff --git a/doc/rtd/topics/datasources/zstack.rst b/doc/rtd/topics/datasources/zstack.rst
new file mode 100644
index 0000000..36e60ff
--- /dev/null
+++ b/doc/rtd/topics/datasources/zstack.rst
@@ -0,0 +1,36 @@
+.. _datasource_zstack:
+
+ZStack
+======
+ZStack platform provides a AWS Ec2 metadata service, but with different datasource identity.
+More information about ZStack can be found at `ZStack <https://www.zstack.io>`__.
+
+Discovery
+---------
+To determine whether a vm running on ZStack platform, cloud-init checks DMI information
+by 'dmidecode -s chassis-asset-tag', if the output ends with '.zstack.io', it's running
+on ZStack platform:
+
+
+Metadata
+^^^^^^^^
+Same as EC2, instance metadata can be queried at
+
+::
+
+ GET http://169.254.169.254/2009-04-04/meta-data/
+ instance-id
+ local-hostname
+
+Userdata
+^^^^^^^^
+Same as EC2, instance userdata can be queried at
+
+::
+
+ GET http://169.254.169.254/2009-04-04/user-data/
+ meta_data.json
+ user_data
+ password
+
+.. vi: textwidth=78
diff --git a/tests/unittests/test_datasource/test_ec2.py b/tests/unittests/test_datasource/test_ec2.py
index 1ec8e00..daa4532 100644
--- a/tests/unittests/test_datasource/test_ec2.py
+++ b/tests/unittests/test_datasource/test_ec2.py
@@ -662,4 +662,29 @@ class TestConvertEc2MetadataNetworkConfig(test_helpers.CiTestCase):
expected,
ec2.convert_ec2_metadata_network_config(self.network_metadata))
+class TesIdentifyPlatform(test_helpers.CiTestCase):
+
+ def collmock(self, **kwargs):
+ """return non-special _collect_platform_data updated with changes."""
+ unspecial = {
+ 'asset_tag': '3857-0037-2746-7462-1818-3997-77',
+ 'serial': 'H23-C4J3JV-R6',
+ 'uuid': '81c7e555-6471-4833-9551-1ab366c4cfd2',
+ 'uuid_source': 'dmi',
+ }
+ unspecial.update(**kwargs)
+ return unspecial
+
+ @mock.patch('cloudinit.sources.DataSourceEc2._collect_platform_data')
+ def test_identify_zstack(self, m_collect):
+ """zstack should be identified if cassis-asset-tag ends in .zstack.io."""
+ m_collect.return_value = self.collmock(asset_tag='123456.zstack.io')
+ self.assertEqual(ec2.CloudNames.ZSTACK, ec2.identify_platform())
+
+ @mock.patch('cloudinit.sources.DataSourceEc2._collect_platform_data')
+ def test_identify_zstack_full_domain_only(self, m_collect):
+ """zstack asset-tag matching should match only on full domain boundary."""
+ m_collect.return_value = self.collmock(asset_tag='123456.buzzstack.io')
+ self.assertEqual(ec2.CloudNames.UNKNOWN, ec2.identify_platform())
+
# vi: ts=4 expandtab
diff --git a/tests/unittests/test_ds_identify.py b/tests/unittests/test_ds_identify.py
index de87be2..7aeeb91 100644
--- a/tests/unittests/test_ds_identify.py
+++ b/tests/unittests/test_ds_identify.py
@@ -609,6 +609,10 @@ class TestDsIdentify(DsIdentifyBase):
self.assertEqual(expected, [p for p in expected if p in toks],
"path did not have expected tokens")
+ def test_zstack_is_ec2(self):
+ """EC2: chassis asset tag ends with 'zstack.io'"""
+ self._test_ds_found('Ec2-ZStack')
+
class TestIsIBMProvisioning(DsIdentifyBase):
"""Test the is_ibm_provisioning method in ds-identify."""
@@ -971,8 +975,11 @@ VALID_CFG = {
{'name': 'blkid', 'ret': 2, 'out': ''},
],
'files': {ds_smartos.METADATA_SOCKFILE: 'would be a socket\n'},
+ },
+ 'Ec2-ZStack': {
+ 'ds': 'Ec2',
+ 'files': {P_CHASSIS_ASSET_TAG: '123456.zstack.io\n'},
}
-
}
# vi: ts=4 expandtab
diff --git a/tools/ds-identify b/tools/ds-identify
index 2447d14..f76f2a6 100755
--- a/tools/ds-identify
+++ b/tools/ds-identify
@@ -895,6 +895,11 @@ ec2_identify_platform() {
*.brightbox.com) _RET="Brightbox"; return 0;;
esac
+ local asset_tag="${DI_DMI_CHASSIS_ASSET_TAG}"
+ case "$asset_tag" in
+ *.zstack.io) _RET="ZStack"; return 0;;
+ esac
+
# AWS http://docs.aws.amazon.com/AWSEC2/
# latest/UserGuide/identify_ec2_instances.html
local uuid="" hvuuid="${PATH_SYS_HYPERVISOR}/uuid"