From a33447344eed897010603b3e8ea1fd122052de76 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Thu, 16 Mar 2017 14:30:15 -0400 Subject: render_network_state: switch arguments around, do not require target render_network_state should default to rendering on /. The changes here just make it so render_network_state does not require a target, but defaults to None, and uses target_path to handle that. --- tests/unittests/test_datasource/test_configdrive.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'tests/unittests/test_datasource') diff --git a/tests/unittests/test_datasource/test_configdrive.py b/tests/unittests/test_datasource/test_configdrive.py index 55153357..337be667 100644 --- a/tests/unittests/test_datasource/test_configdrive.py +++ b/tests/unittests/test_datasource/test_configdrive.py @@ -645,7 +645,7 @@ class TestConvertNetworkData(TestCase): routes) eni_renderer = eni.Renderer() eni_renderer.render_network_state( - self.tmp, network_state.parse_net_config_data(ncfg)) + network_state.parse_net_config_data(ncfg), self.tmp) with open(os.path.join(self.tmp, "etc", "network", "interfaces"), 'r') as f: eni_rendering = f.read() @@ -665,8 +665,9 @@ class TestConvertNetworkData(TestCase): ncfg = openstack.convert_net_json(NETWORK_DATA_BOND, known_macs=KNOWN_MACS) eni_renderer = eni.Renderer() + eni_renderer.render_network_state( - self.tmp, network_state.parse_net_config_data(ncfg)) + network_state.parse_net_config_data(ncfg), self.tmp) with open(os.path.join(self.tmp, "etc", "network", "interfaces"), 'r') as f: eni_rendering = f.read() @@ -697,7 +698,7 @@ class TestConvertNetworkData(TestCase): known_macs=KNOWN_MACS) eni_renderer = eni.Renderer() eni_renderer.render_network_state( - self.tmp, network_state.parse_net_config_data(ncfg)) + network_state.parse_net_config_data(ncfg), self.tmp) with open(os.path.join(self.tmp, "etc", "network", "interfaces"), 'r') as f: eni_rendering = f.read() -- cgit v1.2.3 From 328fe5ab399b1f5b48d1985f41fc2ef66e368922 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Mon, 27 Mar 2017 12:43:15 -0400 Subject: GCE: Search GCE in ds-identify, consider serial number in check. While documentation indicates that the smbios product name should contain 'Google Compute Engine', experimentation and bug reports indicate that is not always the case. The change here is to change the check for GCE to also consider a serial number that starts with 'GoogleCompute-'. Also, ds-identify was not currently searching for GCE if no config of datasource_list was found. Most images have a datasource_list defined. So update the list to include GCE. LP: #1674861 --- cloudinit/sources/DataSourceGCE.py | 18 ++++++++++++++++++ tests/unittests/test_datasource/test_gce.py | 14 +++++++++++++- tools/ds-identify | 14 +++++++++++++- 3 files changed, 44 insertions(+), 2 deletions(-) (limited to 'tests/unittests/test_datasource') diff --git a/cloudinit/sources/DataSourceGCE.py b/cloudinit/sources/DataSourceGCE.py index b1a1c8f2..637c9505 100644 --- a/cloudinit/sources/DataSourceGCE.py +++ b/cloudinit/sources/DataSourceGCE.py @@ -62,6 +62,9 @@ class DataSourceGCE(sources.DataSource): return public_key def get_data(self): + if not platform_reports_gce(): + return False + # url_map: (our-key, path, required, is_text) url_map = [ ('instance-id', ('instance/id',), True, True), @@ -144,6 +147,21 @@ class DataSourceGCE(sources.DataSource): return self.availability_zone.rsplit('-', 1)[0] +def platform_reports_gce(): + pname = util.read_dmi_data('system-product-name') or "N/A" + if pname == "Google Compute Engine": + return True + + # system-product-name is not always guaranteed (LP: #1674861) + serial = util.read_dmi_data('system-serial-number') or "N/A" + if serial.startswith("GoogleCloud-"): + return True + + LOG.debug("Not running on google cloud. product-name=%s serial=%s", + pname, serial) + return False + + # Used to match classes to dependencies datasources = [ (DataSourceGCE, (sources.DEP_FILESYSTEM, sources.DEP_NETWORK)), diff --git a/tests/unittests/test_datasource/test_gce.py b/tests/unittests/test_datasource/test_gce.py index 4f83454e..3eaa58e3 100644 --- a/tests/unittests/test_datasource/test_gce.py +++ b/tests/unittests/test_datasource/test_gce.py @@ -5,6 +5,7 @@ # This file is part of cloud-init. See LICENSE file for license information. import httpretty +import mock import re from base64 import b64encode, b64decode @@ -71,6 +72,11 @@ class TestDataSourceGCE(test_helpers.HttprettyTestCase): self.ds = DataSourceGCE.DataSourceGCE( settings.CFG_BUILTIN, None, helpers.Paths({})) + self.m_platform_reports_gce = mock.patch( + 'cloudinit.sources.DataSourceGCE.platform_reports_gce', + return_value=True) + self.m_platform_reports_gce.start() + self.addCleanup(self.m_platform_reports_gce.stop) super(TestDataSourceGCE, self).setUp() def test_connection(self): @@ -153,7 +159,13 @@ class TestDataSourceGCE(test_helpers.HttprettyTestCase): def test_only_last_part_of_zone_used_for_availability_zone(self): _set_mock_metadata() - self.ds.get_data() + r = self.ds.get_data() + self.assertEqual(True, r) self.assertEqual('bar', self.ds.availability_zone) + def test_get_data_returns_false_if_not_on_gce(self): + self.m_platform_reports_gce.return_value = False + self.assertEqual(False, self.ds.get_data()) + + # vi: ts=4 expandtab diff --git a/tools/ds-identify b/tools/ds-identify index bf09a3ad..15d6600e 100755 --- a/tools/ds-identify +++ b/tools/ds-identify @@ -108,7 +108,7 @@ 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 OpenNebula OpenStack OVF SmartOS" +CloudSigma CloudStack DigitalOcean Ec2 GCE OpenNebula OpenStack OVF SmartOS" DI_DSLIST="" DI_MODE="" DI_ON_FOUND="" @@ -383,6 +383,14 @@ dmi_product_name_matches() { return 1 } +dmi_product_serial_matches() { + is_container && return 1 + case "${DI_DMI_PRODUCT_SERIAL}" in + $1) return 0;; + esac + return 1 +} + dmi_product_name_is() { is_container && return 1 [ "${DI_DMI_PRODUCT_NAME}" = "$1" ] @@ -770,6 +778,10 @@ dscheck_GCE() { if dmi_product_name_is "Google Compute Engine"; then return ${DS_FOUND} fi + # product name is not guaranteed (LP: #1674861) + if dmi_product_serial_matches "GoogleCloud-*"; then + return ${DS_FOUND} + fi return ${DS_NOT_FOUND} } -- cgit v1.2.3 From 5442b517ebe5508159a46d11d500fbc6ad854ba0 Mon Sep 17 00:00:00 2001 From: Scott Moser Date: Fri, 31 Mar 2017 13:55:27 -0400 Subject: tests: update OpenNebula and Digital Ocean to not rely on host interfaces. Mock the use use of get_interfaces_by_mac in Digital Ocean and OpenNebula. Its best to mock this for the tests as the results aren't expecting it to fail. Note, as it stands, OpenNebula relies on devices named 'eth0'. The metadata (context) does not provide mac addresses. --- tests/unittests/test_datasource/test_digitalocean.py | 14 ++++++++++++-- tests/unittests/test_datasource/test_opennebula.py | 9 +++++++-- 2 files changed, 19 insertions(+), 4 deletions(-) (limited to 'tests/unittests/test_datasource') diff --git a/tests/unittests/test_datasource/test_digitalocean.py b/tests/unittests/test_datasource/test_digitalocean.py index 9be6bc19..61d6e001 100644 --- a/tests/unittests/test_datasource/test_digitalocean.py +++ b/tests/unittests/test_datasource/test_digitalocean.py @@ -194,7 +194,12 @@ class TestDataSourceDigitalOcean(TestCase): class TestNetworkConvert(TestCase): - def _get_networking(self): + @mock.patch('cloudinit.net.get_interfaces_by_mac') + def _get_networking(self, m_get_by_mac): + m_get_by_mac.return_value = { + '04:01:57:d1:9e:01': 'ens1', '04:01:57:d1:9e:02': 'ens2', + 'b8:ae:ed:75:5f:9a': 'enp0s25', + 'ae:cc:08:7c:88:00': 'meta2p1'} netcfg = digitalocean.convert_network_configuration( DO_META['interfaces'], DO_META['dns']['nameservers']) self.assertIn('config', netcfg) @@ -302,10 +307,15 @@ class TestNetworkConvert(TestCase): self.assertEqual(ipv4_def.get('netmask'), subn_def.get('netmask')) self.assertNotIn('gateway', subn_def) - def test_convert_without_private(self): + @mock.patch('cloudinit.net.get_interfaces_by_mac') + def test_convert_without_private(self, m_get_by_mac): + m_get_by_mac.return_value = { + 'b8:ae:ed:75:5f:9a': 'enp0s25', + 'ae:cc:08:7c:88:00': 'meta2p1'} netcfg = digitalocean.convert_network_configuration( DO_META_2['interfaces'], DO_META_2['dns']['nameservers']) + # print(netcfg) byname = {} for i in netcfg['config']: if 'name' in i: diff --git a/tests/unittests/test_datasource/test_opennebula.py b/tests/unittests/test_datasource/test_opennebula.py index a266e952..bce66125 100644 --- a/tests/unittests/test_datasource/test_opennebula.py +++ b/tests/unittests/test_datasource/test_opennebula.py @@ -195,7 +195,9 @@ class TestOpenNebulaDataSource(TestCase): self.assertTrue('userdata' in results) self.assertEqual(USER_DATA, results['userdata']) - def test_hostname(self): + @mock.patch(DS_PATH + ".get_physical_nics_by_mac") + def test_hostname(self, m_get_phys_by_mac): + m_get_phys_by_mac.return_value = {'02:00:0a:12:01:01': 'eth0'} for k in ('HOSTNAME', 'PUBLIC_IP', 'IP_PUBLIC', 'ETH0_IP'): my_d = os.path.join(self.tmp, k) populate_context_dir(my_d, {k: PUBLIC_IP}) @@ -205,11 +207,14 @@ class TestOpenNebulaDataSource(TestCase): self.assertTrue('local-hostname' in results['metadata']) self.assertEqual(PUBLIC_IP, results['metadata']['local-hostname']) - def test_network_interfaces(self): + @mock.patch(DS_PATH + ".get_physical_nics_by_mac") + def test_network_interfaces(self, m_get_phys_by_mac): + m_get_phys_by_mac.return_value = {'02:00:0a:12:01:01': 'eth0'} populate_context_dir(self.seed_dir, {'ETH0_IP': '1.2.3.4'}) results = ds.read_context_disk_dir(self.seed_dir) self.assertTrue('network-interfaces' in results) + self.assertTrue('1.2.3.4' in results['network-interfaces']) def test_find_candidates(self): def my_devs_with(criteria): -- cgit v1.2.3