From 685f9901b820a457912959bdd4f389835e965524 Mon Sep 17 00:00:00 2001 From: Chad Smith Date: Tue, 20 Mar 2018 16:37:36 -0600 Subject: datasources: fix DataSource subclass get_hostname method signature DataSource.get_hostname call signature changed to allow for metadata_only parameter. The metadata_only=True parameter is passed to get_hostname during init-local stage in order to set the system hostname if present in metadata prior to initial network bring up. Fix subclasses of DataSource which have overridden get_hostname to allow for metadata_only param. LP: #1757176 --- cloudinit/sources/DataSourceAliYun.py | 2 +- cloudinit/sources/DataSourceCloudSigma.py | 2 +- cloudinit/sources/DataSourceGCE.py | 2 +- cloudinit/sources/DataSourceOpenNebula.py | 2 +- cloudinit/sources/DataSourceScaleway.py | 2 +- cloudinit/sources/tests/test_init.py | 28 ++++++++++++++++++++++++++++ 6 files changed, 33 insertions(+), 5 deletions(-) (limited to 'cloudinit') diff --git a/cloudinit/sources/DataSourceAliYun.py b/cloudinit/sources/DataSourceAliYun.py index 7ac8288d..22279d09 100644 --- a/cloudinit/sources/DataSourceAliYun.py +++ b/cloudinit/sources/DataSourceAliYun.py @@ -22,7 +22,7 @@ class DataSourceAliYun(EC2.DataSourceEc2): super(DataSourceAliYun, self).__init__(sys_cfg, distro, paths) self.seed_dir = os.path.join(paths.seed_dir, "AliYun") - def get_hostname(self, fqdn=False, _resolve_ip=False): + def get_hostname(self, fqdn=False, resolve_ip=False, metadata_only=False): return self.metadata.get('hostname', 'localhost.localdomain') def get_public_ssh_keys(self): diff --git a/cloudinit/sources/DataSourceCloudSigma.py b/cloudinit/sources/DataSourceCloudSigma.py index 4eaad475..c816f349 100644 --- a/cloudinit/sources/DataSourceCloudSigma.py +++ b/cloudinit/sources/DataSourceCloudSigma.py @@ -84,7 +84,7 @@ class DataSourceCloudSigma(sources.DataSource): return True - def get_hostname(self, fqdn=False, resolve_ip=False): + def get_hostname(self, fqdn=False, resolve_ip=False, metadata_only=False): """ Cleans up and uses the server's name if the latter is set. Otherwise the first part from uuid is being used. diff --git a/cloudinit/sources/DataSourceGCE.py b/cloudinit/sources/DataSourceGCE.py index bebc9918..d8162623 100644 --- a/cloudinit/sources/DataSourceGCE.py +++ b/cloudinit/sources/DataSourceGCE.py @@ -90,7 +90,7 @@ class DataSourceGCE(sources.DataSource): public_keys_data = self.metadata['public-keys-data'] return _parse_public_keys(public_keys_data, self.default_user) - def get_hostname(self, fqdn=False, resolve_ip=False): + def get_hostname(self, fqdn=False, resolve_ip=False, metadata_only=False): # GCE has long FDQN's and has asked for short hostnames. return self.metadata['local-hostname'].split('.')[0] diff --git a/cloudinit/sources/DataSourceOpenNebula.py b/cloudinit/sources/DataSourceOpenNebula.py index 02cb98f7..d4a41116 100644 --- a/cloudinit/sources/DataSourceOpenNebula.py +++ b/cloudinit/sources/DataSourceOpenNebula.py @@ -102,7 +102,7 @@ class DataSourceOpenNebula(sources.DataSource): else: return None - def get_hostname(self, fqdn=False, resolve_ip=None): + def get_hostname(self, fqdn=False, resolve_ip=False, metadata_only=False): if resolve_ip is None: if self.dsmode == sources.DSMODE_NETWORK: resolve_ip = True diff --git a/cloudinit/sources/DataSourceScaleway.py b/cloudinit/sources/DataSourceScaleway.py index b0b19c93..90056249 100644 --- a/cloudinit/sources/DataSourceScaleway.py +++ b/cloudinit/sources/DataSourceScaleway.py @@ -215,7 +215,7 @@ class DataSourceScaleway(sources.DataSource): def get_public_ssh_keys(self): return [key['key'] for key in self.metadata['ssh_public_keys']] - def get_hostname(self, fqdn=False, resolve_ip=False): + def get_hostname(self, fqdn=False, resolve_ip=False, metadata_only=False): return self.metadata['hostname'] @property diff --git a/cloudinit/sources/tests/test_init.py b/cloudinit/sources/tests/test_init.py index 5065083c..e7fda22a 100644 --- a/cloudinit/sources/tests/test_init.py +++ b/cloudinit/sources/tests/test_init.py @@ -1,10 +1,12 @@ # This file is part of cloud-init. See LICENSE file for license information. +import inspect import os import six import stat from cloudinit.helpers import Paths +from cloudinit import importer from cloudinit.sources import ( INSTANCE_JSON_FILE, DataSource) from cloudinit.tests.helpers import CiTestCase, skipIf, mock @@ -268,3 +270,29 @@ class TestDataSource(CiTestCase): "WARNING: Error persisting instance-data.json: 'utf8' codec can't" " decode byte 0xaa in position 2: invalid start byte", self.logs.getvalue()) + + def test_get_hostname_subclass_support(self): + """Validate get_hostname signature on all subclasses of DataSource.""" + # Use inspect.getfullargspec when we drop py2.6 and py2.7 + get_args = inspect.getargspec # pylint: disable=W1505 + base_args = get_args(DataSource.get_hostname) # pylint: disable=W1505 + # Import all DataSource subclasses so we can inspect them. + modules = util.find_modules(os.path.dirname(os.path.dirname(__file__))) + for loc, name in modules.items(): + mod_locs, _ = importer.find_module(name, ['cloudinit.sources'], []) + if mod_locs: + importer.import_module(mod_locs[0]) + for child in DataSource.__subclasses__(): + if 'Test' in child.dsname: + continue + self.assertEqual( + base_args, + get_args(child.get_hostname), # pylint: disable=W1505 + '%s does not implement DataSource.get_hostname params' + % child) + for grandchild in child.__subclasses__(): + self.assertEqual( + base_args, + get_args(grandchild.get_hostname), # pylint: disable=W1505 + '%s does not implement DataSource.get_hostname params' + % grandchild) -- cgit v1.2.3