diff options
-rw-r--r-- | cloudinit/sources/DataSourceEc2.py | 43 | ||||
-rw-r--r-- | tests/unittests/test_datasource/test_ec2.py | 29 |
2 files changed, 60 insertions, 12 deletions
diff --git a/cloudinit/sources/DataSourceEc2.py b/cloudinit/sources/DataSourceEc2.py index 07c12bb4..41367a8b 100644 --- a/cloudinit/sources/DataSourceEc2.py +++ b/cloudinit/sources/DataSourceEc2.py @@ -27,6 +27,8 @@ SKIP_METADATA_URL_CODES = frozenset([uhelp.NOT_FOUND]) STRICT_ID_PATH = ("datasource", "Ec2", "strict_id") STRICT_ID_DEFAULT = "warn" +_unset = "_unset" + class Platforms(object): ALIYUN = "AliYun" @@ -57,7 +59,7 @@ class DataSourceEc2(sources.DataSource): _cloud_platform = None - _network_config = None # Used for caching calculated network config v1 + _network_config = _unset # Used for caching calculated network config v1 # Whether we want to get network configuration from the metadata service. get_network_metadata = False @@ -284,10 +286,24 @@ class DataSourceEc2(sources.DataSource): @property def network_config(self): """Return a network config dict for rendering ENI or netplan files.""" - if self._network_config is None: - if self.metadata is not None: - self._network_config = convert_ec2_metadata_network_config( - self.metadata) + if self._network_config != _unset: + return self._network_config + + if self.metadata is None: + # this would happen if get_data hadn't been called. leave as _unset + LOG.warning( + "Unexpected call to network_config when metadata is None.") + return None + + result = None + net_md = self.metadata.get('network') + if isinstance(net_md, dict): + result = convert_ec2_metadata_network_config(net_md) + else: + LOG.warning("unexpected metadata 'network' key not valid: %s", + net_md) + self._network_config = result + return self._network_config def _crawl_metadata(self): @@ -321,6 +337,14 @@ class DataSourceEc2Local(DataSourceEc2): """ get_network_metadata = True # Get metadata network config if present + def get_data(self): + supported_platforms = (Platforms.AWS,) + if self.cloud_platform not in supported_platforms: + LOG.debug("Local Ec2 mode only supported on %s, not %s", + supported_platforms, self.cloud_platform) + return False + return super(DataSourceEc2Local, self).get_data() + def read_strict_mode(cfgval, default): try: @@ -434,10 +458,13 @@ def _collect_platform_data(): return data -def convert_ec2_metadata_network_config(metadata=None, macs_to_nics=None): +def convert_ec2_metadata_network_config(network_md, macs_to_nics=None): """Convert ec2 metadata to network config version 1 data dict. - @param: metadata: Dictionary of metadata crawled from EC2 metadata url. + @param: network_md: 'network' portion of EC2 metadata. + generally formed as {"interfaces": {"macs": {}} where + 'macs' is a dictionary with mac address as key and contents like: + {"device-number": "0", "interface-id": "...", "local-ipv4s": ...} @param: macs_to_name: Optional dict mac addresses and the nic name. If not provided, get_interfaces_by_mac is called to get it from the OS. @@ -446,7 +473,7 @@ def convert_ec2_metadata_network_config(metadata=None, macs_to_nics=None): netcfg = {'version': 1, 'config': []} if not macs_to_nics: macs_to_nics = net.get_interfaces_by_mac() - macs_metadata = metadata['network']['interfaces']['macs'] + macs_metadata = network_md['interfaces']['macs'] for mac, nic_name in macs_to_nics.items(): nic_metadata = macs_metadata.get(mac) if not nic_metadata: diff --git a/tests/unittests/test_datasource/test_ec2.py b/tests/unittests/test_datasource/test_ec2.py index 9fb90483..a7301dbf 100644 --- a/tests/unittests/test_datasource/test_ec2.py +++ b/tests/unittests/test_datasource/test_ec2.py @@ -279,6 +279,27 @@ class TestEc2(test_helpers.HttprettyTestCase): ret = ds.get_data() self.assertTrue(ret) + def test_ec2_local_returns_false_on_non_aws(self): + """DataSourceEc2Local returns False when platform is not AWS.""" + self.datasource = ec2.DataSourceEc2Local + ds = self._setup_ds( + platform_data=self.valid_platform_data, + sys_cfg={'datasource': {'Ec2': {'strict_id': False}}}, + md=DEFAULT_METADATA) + platform_attrs = [ + attr for attr in ec2.Platforms.__dict__.keys() + if not attr.startswith('__')] + for attr_name in platform_attrs: + platform_name = getattr(ec2.Platforms, attr_name) + if platform_name != 'AWS': + ds._cloud_platform = platform_name + ret = ds.get_data() + self.assertFalse(ret) + message = ( + "Local Ec2 mode only supported on ('AWS',)," + ' not {0}'.format(platform_name)) + self.assertIn(message, self.logs.getvalue()) + @httpretty.activate @mock.patch('cloudinit.sources.DataSourceEc2.util.is_FreeBSD') def test_ec2_local_returns_false_on_bsd(self, m_is_freebsd): @@ -336,8 +357,8 @@ class TestConvertEc2MetadataNetworkConfig(test_helpers.CiTestCase): super(TestConvertEc2MetadataNetworkConfig, self).setUp() self.mac1 = '06:17:04:d7:26:09' self.network_metadata = { - 'network': {'interfaces': {'macs': { - self.mac1: {'public-ipv4s': '172.31.2.16'}}}}} + 'interfaces': {'macs': { + self.mac1: {'public-ipv4s': '172.31.2.16'}}}} def test_convert_ec2_metadata_network_config_skips_absent_macs(self): """Any mac absent from metadata is skipped by network config.""" @@ -357,7 +378,7 @@ class TestConvertEc2MetadataNetworkConfig(test_helpers.CiTestCase): macs_to_nics = {self.mac1: 'eth9'} network_metadata_ipv6 = copy.deepcopy(self.network_metadata) nic1_metadata = ( - network_metadata_ipv6['network']['interfaces']['macs'][self.mac1]) + network_metadata_ipv6['interfaces']['macs'][self.mac1]) nic1_metadata['ipv6s'] = '2620:0:1009:fd00:e442:c88d:c04d:dc85/64' nic1_metadata.pop('public-ipv4s') expected = {'version': 1, 'config': [ @@ -373,7 +394,7 @@ class TestConvertEc2MetadataNetworkConfig(test_helpers.CiTestCase): macs_to_nics = {self.mac1: 'eth9'} network_metadata_both = copy.deepcopy(self.network_metadata) nic1_metadata = ( - network_metadata_both['network']['interfaces']['macs'][self.mac1]) + network_metadata_both['interfaces']['macs'][self.mac1]) nic1_metadata['ipv6s'] = '2620:0:1009:fd00:e442:c88d:c04d:dc85/64' expected = {'version': 1, 'config': [ {'mac_address': self.mac1, 'type': 'physical', |