diff options
Diffstat (limited to 'tests/unittests/sources/test_azure.py')
-rw-r--r-- | tests/unittests/sources/test_azure.py | 892 |
1 files changed, 375 insertions, 517 deletions
diff --git a/tests/unittests/sources/test_azure.py b/tests/unittests/sources/test_azure.py index b7dae873..b1edf1f3 100644 --- a/tests/unittests/sources/test_azure.py +++ b/tests/unittests/sources/test_azure.py @@ -12,7 +12,6 @@ from pathlib import Path import httpretty import pytest import requests -import yaml from cloudinit import distros, helpers, subp, url_helper from cloudinit.net import dhcp @@ -23,7 +22,6 @@ from cloudinit.sources.helpers import netlink from cloudinit.util import ( MountFailedError, b64e, - decode_binary, json_dumps, load_file, load_json, @@ -87,6 +85,25 @@ def mock_azure_report_failure_to_fabric(): @pytest.fixture +def mock_device_driver(): + with mock.patch( + MOCKPATH + "device_driver", + autospec=True, + return_value=None, + ) as m: + yield m + + +@pytest.fixture +def mock_generate_fallback_config(): + with mock.patch( + MOCKPATH + "net.generate_fallback_config", + autospec=True, + ) as m: + yield m + + +@pytest.fixture def mock_time(): with mock.patch( MOCKPATH + "time", @@ -122,7 +139,7 @@ def mock_ephemeral_dhcp_v4(): @pytest.fixture def mock_net_dhcp_maybe_perform_dhcp_discovery(): with mock.patch( - "cloudinit.net.dhcp.maybe_perform_dhcp_discovery", + "cloudinit.net.ephemeral.maybe_perform_dhcp_discovery", return_value=[ { "unknown-245": "0a:0b:0c:0d", @@ -140,7 +157,7 @@ def mock_net_dhcp_maybe_perform_dhcp_discovery(): @pytest.fixture def mock_net_dhcp_EphemeralIPv4Network(): with mock.patch( - "cloudinit.net.dhcp.EphemeralIPv4Network", + "cloudinit.net.ephemeral.EphemeralIPv4Network", autospec=True, ) as m: yield m @@ -279,83 +296,101 @@ def patched_markers_dir_path(tmpdir): @pytest.fixture -def patched_reported_ready_marker_path(patched_markers_dir_path): +def patched_reported_ready_marker_path(azure_ds, patched_markers_dir_path): reported_ready_marker = patched_markers_dir_path / "reported_ready" - with mock.patch( - MOCKPATH + "REPORTED_READY_MARKER_FILE", str(reported_ready_marker) + with mock.patch.object( + azure_ds, "_reported_ready_marker_file", str(reported_ready_marker) ): yield reported_ready_marker -def construct_valid_ovf_env( - data=None, pubkeys=None, userdata=None, platform_settings=None +def construct_ovf_env( + *, + custom_data=None, + hostname="test-host", + username="test-user", + password=None, + public_keys=None, + disable_ssh_password_auth=None, + preprovisioned_vm=None, + preprovisioned_vm_type=None, ): - if data is None: - data = {"HostName": "FOOHOST"} - if pubkeys is None: - pubkeys = {} - - content = """<?xml version="1.0" encoding="utf-8"?> -<Environment xmlns="http://schemas.dmtf.org/ovf/environment/1" - xmlns:oe="http://schemas.dmtf.org/ovf/environment/1" - xmlns:wa="http://schemas.microsoft.com/windowsazure" - xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> - - <wa:ProvisioningSection><wa:Version>1.0</wa:Version> - <LinuxProvisioningConfigurationSet - xmlns="http://schemas.microsoft.com/windowsazure" - xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> - <ConfigurationSetType>LinuxProvisioningConfiguration</ConfigurationSetType> - """ - for key, dval in data.items(): - if isinstance(dval, dict): - val = dict(dval).get("text") - attrs = " " + " ".join( - [ - "%s='%s'" % (k, v) - for k, v in dict(dval).items() - if k != "text" - ] - ) - else: - val = dval - attrs = "" - content += "<%s%s>%s</%s>\n" % (key, attrs, val, key) - - if userdata: - content += "<UserData>%s</UserData>\n" % (b64e(userdata)) - - if pubkeys: - content += "<SSH><PublicKeys>\n" - for fp, path, value in pubkeys: - content += " <PublicKey>" - if fp and path: - content += "<Fingerprint>%s</Fingerprint><Path>%s</Path>" % ( - fp, - path, - ) - if value: - content += "<Value>%s</Value>" % value - content += "</PublicKey>\n" - content += "</PublicKeys></SSH>" - content += """ - </LinuxProvisioningConfigurationSet> - </wa:ProvisioningSection> - <wa:PlatformSettingsSection><wa:Version>1.0</wa:Version> - <PlatformSettings xmlns="http://schemas.microsoft.com/windowsazure" - xmlns:i="http://www.w3.org/2001/XMLSchema-instance"> - <KmsServerHostname>kms.core.windows.net</KmsServerHostname> - <ProvisionGuestAgent>false</ProvisionGuestAgent> - <GuestAgentPackageName i:nil="true" />""" - if platform_settings: - for k, v in platform_settings.items(): - content += "<%s>%s</%s>\n" % (k, v, k) - if "PreprovisionedVMType" not in platform_settings: - content += """<PreprovisionedVMType i:nil="true" />""" - content += """</PlatformSettings></wa:PlatformSettingsSection> -</Environment>""" - - return content + content = [ + '<?xml version="1.0" encoding="utf-8"?>', + '<ns0:Environment xmlns="http://schemas.dmtf.org/ovf/environment/1"', + 'xmlns:ns0="http://schemas.dmtf.org/ovf/environment/1"', + 'xmlns:ns1="http://schemas.microsoft.com/windowsazure"', + 'xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">', + "<ns1:ProvisioningSection>", + "<ns1:Version>1.0</ns1:Version>", + "<ns1:LinuxProvisioningConfigurationSet>", + "<ns1:ConfigurationSetType>" + "LinuxProvisioningConfiguration" + "</ns1:ConfigurationSetType>", + ] + if hostname is not None: + content.append("<ns1:HostName>%s</ns1:HostName>" % hostname) + if username is not None: + content.append("<ns1:UserName>%s</ns1:UserName>" % username) + if password is not None: + content.append("<ns1:UserPassword>%s</ns1:UserPassword>" % password) + if custom_data is not None: + content.append( + "<ns1:CustomData>%s</ns1:CustomData>" % (b64e(custom_data)) + ) + if disable_ssh_password_auth is not None: + content.append( + "<ns1:DisableSshPasswordAuthentication>%s" + % str(disable_ssh_password_auth).lower() + + "</ns1:DisableSshPasswordAuthentication>" + ) + if public_keys is not None: + content += ["<ns1:SSH>", "<ns1:PublicKeys>"] + for public_key in public_keys: + content.append("<ns1:PublicKey>") + fp = public_key.get("fingerprint") + if fp is not None: + content.append("<ns1:Fingerprint>%s</ns1:Fingerprint>" % fp) + path = public_key.get("path") + if path is not None: + content.append("<ns1:Path>%s</ns1:Path>" % path) + value = public_key.get("value") + if value is not None: + content.append("<ns1:Value>%s</ns1:Value>" % value) + content.append("</ns1:PublicKey>") + content += ["</ns1:PublicKeys>", "</ns1:SSH>"] + content += [ + "</ns1:LinuxProvisioningConfigurationSet>", + "</ns1:ProvisioningSection>", + "<ns1:PlatformSettingsSection>", + "<ns1:Version>1.0</ns1:Version>", + "<ns1:PlatformSettings>", + "<ns1:KmsServerHostname>" + "kms.core.windows.net" + "</ns1:KmsServerHostname>", + "<ns1:ProvisionGuestAgent>false</ns1:ProvisionGuestAgent>", + '<ns1:GuestAgentPackageName xsi:nil="true" />', + ] + if preprovisioned_vm is not None: + content.append( + "<ns1:PreprovisionedVm>%s</ns1:PreprovisionedVm>" + % str(preprovisioned_vm).lower() + ) + + if preprovisioned_vm_type is None: + content.append('<ns1:PreprovisionedVMType xsi:nil="true" />') + else: + content.append( + "<ns1:PreprovisionedVMType>%s</ns1:PreprovisionedVMType>" + % preprovisioned_vm_type + ) + content += [ + "</ns1:PlatformSettings>", + "</ns1:PlatformSettingsSection>", + "</ns0:Environment>", + ] + + return "\n".join(content) NETWORK_METADATA = { @@ -441,7 +476,7 @@ IMDS_NETWORK_METADATA = { EXAMPLE_UUID = "d0df4c54-4ecb-4a4b-9954-5bdf3ed5c3b8" -class TestParseNetworkConfig(CiTestCase): +class TestNetworkConfig: maxDiff = None fallback_config = { @@ -457,11 +492,8 @@ class TestParseNetworkConfig(CiTestCase): ], } - @mock.patch( - "cloudinit.sources.DataSourceAzure.device_driver", return_value=None - ) - def test_single_ipv4_nic_configuration(self, m_driver): - """parse_network_config emits dhcp on single nic with ipv4""" + def test_single_ipv4_nic_configuration(self, azure_ds, mock_device_driver): + """Network config emits dhcp on single nic with ipv4""" expected = { "ethernets": { "eth0": { @@ -474,13 +506,14 @@ class TestParseNetworkConfig(CiTestCase): }, "version": 2, } - self.assertEqual(expected, dsaz.parse_network_config(NETWORK_METADATA)) + azure_ds._metadata_imds = NETWORK_METADATA - @mock.patch( - "cloudinit.sources.DataSourceAzure.device_driver", return_value=None - ) - def test_increases_route_metric_for_non_primary_nics(self, m_driver): - """parse_network_config increases route-metric for each nic""" + assert azure_ds.network_config == expected + + def test_increases_route_metric_for_non_primary_nics( + self, azure_ds, mock_device_driver + ): + """Network config increases route-metric for each nic""" expected = { "ethernets": { "eth0": { @@ -514,70 +547,14 @@ class TestParseNetworkConfig(CiTestCase): third_intf["ipv4"]["subnet"][0]["address"] = "10.0.2.0" third_intf["ipv4"]["ipAddress"][0]["privateIpAddress"] = "10.0.2.6" imds_data["network"]["interface"].append(third_intf) - self.assertEqual(expected, dsaz.parse_network_config(imds_data)) - - @mock.patch( - "cloudinit.sources.DataSourceAzure.device_driver", return_value=None - ) - def test_ipv4_and_ipv6_route_metrics_match_for_nics(self, m_driver): - """parse_network_config emits matching ipv4 and ipv6 route-metrics.""" - expected = { - "ethernets": { - "eth0": { - "addresses": ["10.0.0.5/24", "2001:dead:beef::2/128"], - "dhcp4": True, - "dhcp4-overrides": {"route-metric": 100}, - "dhcp6": True, - "dhcp6-overrides": {"route-metric": 100}, - "match": {"macaddress": "00:0d:3a:04:75:98"}, - "set-name": "eth0", - }, - "eth1": { - "set-name": "eth1", - "match": {"macaddress": "22:0d:3a:04:75:98"}, - "dhcp4": True, - "dhcp6": False, - "dhcp4-overrides": {"route-metric": 200}, - }, - "eth2": { - "set-name": "eth2", - "match": {"macaddress": "33:0d:3a:04:75:98"}, - "dhcp4": True, - "dhcp4-overrides": {"route-metric": 300}, - "dhcp6": True, - "dhcp6-overrides": {"route-metric": 300}, - }, - }, - "version": 2, - } - imds_data = copy.deepcopy(NETWORK_METADATA) - nic1 = imds_data["network"]["interface"][0] - nic1["ipv4"]["ipAddress"].append({"privateIpAddress": "10.0.0.5"}) + azure_ds._metadata_imds = imds_data - nic1["ipv6"] = { - "subnet": [{"address": "2001:dead:beef::16"}], - "ipAddress": [ - {"privateIpAddress": "2001:dead:beef::1"}, - {"privateIpAddress": "2001:dead:beef::2"}, - ], - } - imds_data["network"]["interface"].append(SECONDARY_INTERFACE) - third_intf = copy.deepcopy(SECONDARY_INTERFACE) - third_intf["macAddress"] = third_intf["macAddress"].replace("22", "33") - third_intf["ipv4"]["subnet"][0]["address"] = "10.0.2.0" - third_intf["ipv4"]["ipAddress"][0]["privateIpAddress"] = "10.0.2.6" - third_intf["ipv6"] = { - "subnet": [{"prefix": "64", "address": "2001:dead:beef::2"}], - "ipAddress": [{"privateIpAddress": "2001:dead:beef::1"}], - } - imds_data["network"]["interface"].append(third_intf) - self.assertEqual(expected, dsaz.parse_network_config(imds_data)) + assert azure_ds.network_config == expected - @mock.patch( - "cloudinit.sources.DataSourceAzure.device_driver", return_value=None - ) - def test_ipv4_secondary_ips_will_be_static_addrs(self, m_driver): - """parse_network_config emits primary ipv4 as dhcp others are static""" + def test_ipv4_secondary_ips_will_be_static_addrs( + self, azure_ds, mock_device_driver + ): + """Network config emits primary ipv4 as dhcp others are static""" expected = { "ethernets": { "eth0": { @@ -600,13 +577,14 @@ class TestParseNetworkConfig(CiTestCase): "subnet": [{"prefix": "10", "address": "2001:dead:beef::16"}], "ipAddress": [{"privateIpAddress": "2001:dead:beef::1"}], } - self.assertEqual(expected, dsaz.parse_network_config(imds_data)) + azure_ds._metadata_imds = imds_data - @mock.patch( - "cloudinit.sources.DataSourceAzure.device_driver", return_value=None - ) - def test_ipv6_secondary_ips_will_be_static_cidrs(self, m_driver): - """parse_network_config emits primary ipv6 as dhcp others are static""" + assert azure_ds.network_config == expected + + def test_ipv6_secondary_ips_will_be_static_cidrs( + self, azure_ds, mock_device_driver + ): + """Network config emits primary ipv6 as dhcp others are static""" expected = { "ethernets": { "eth0": { @@ -633,14 +611,13 @@ class TestParseNetworkConfig(CiTestCase): {"privateIpAddress": "2001:dead:beef::2"}, ], } - self.assertEqual(expected, dsaz.parse_network_config(imds_data)) + azure_ds._metadata_imds = imds_data - @mock.patch( - "cloudinit.sources.DataSourceAzure.device_driver", - return_value="hv_netvsc", - ) - def test_match_driver_for_netvsc(self, m_driver): - """parse_network_config emits driver when using netvsc.""" + assert azure_ds.network_config == expected + + def test_match_driver_for_netvsc(self, azure_ds, mock_device_driver): + """Network config emits driver when using netvsc.""" + mock_device_driver.return_value = "hv_netvsc" expected = { "ethernets": { "eth0": { @@ -656,16 +633,31 @@ class TestParseNetworkConfig(CiTestCase): }, "version": 2, } - self.assertEqual(expected, dsaz.parse_network_config(NETWORK_METADATA)) + azure_ds._metadata_imds = NETWORK_METADATA - @mock.patch( - "cloudinit.sources.DataSourceAzure.device_driver", return_value=None - ) - @mock.patch("cloudinit.net.generate_fallback_config") - def test_parse_network_config_uses_fallback_cfg_when_no_network_metadata( - self, m_fallback_config, m_driver + assert azure_ds.network_config == expected + + def test_uses_fallback_cfg_when_apply_network_config_is_false( + self, azure_ds, mock_device_driver, mock_generate_fallback_config + ): + azure_ds.ds_cfg["apply_network_config"] = False + azure_ds._metadata_imds = NETWORK_METADATA + mock_generate_fallback_config.return_value = self.fallback_config + + assert azure_ds.network_config == self.fallback_config + + def test_uses_fallback_cfg_when_imds_metadata_unset( + self, azure_ds, mock_device_driver, mock_generate_fallback_config + ): + azure_ds._metadata_imds = UNSET + mock_generate_fallback_config.return_value = self.fallback_config + + assert azure_ds.network_config == self.fallback_config + + def test_uses_fallback_cfg_when_no_network_metadata( + self, azure_ds, mock_device_driver, mock_generate_fallback_config ): - """parse_network_config generates fallback network config when the + """Network config generates fallback network config when the IMDS instance metadata is corrupted/invalid, such as when network metadata is not present. """ @@ -673,20 +665,15 @@ class TestParseNetworkConfig(CiTestCase): NETWORK_METADATA ) del imds_metadata_missing_network_metadata["network"] - m_fallback_config.return_value = self.fallback_config - self.assertEqual( - self.fallback_config, - dsaz.parse_network_config(imds_metadata_missing_network_metadata), - ) + mock_generate_fallback_config.return_value = self.fallback_config + azure_ds._metadata_imds = imds_metadata_missing_network_metadata - @mock.patch( - "cloudinit.sources.DataSourceAzure.device_driver", return_value=None - ) - @mock.patch("cloudinit.net.generate_fallback_config") - def test_parse_network_config_uses_fallback_cfg_when_no_interface_metadata( - self, m_fallback_config, m_driver + assert azure_ds.network_config == self.fallback_config + + def test_uses_fallback_cfg_when_no_interface_metadata( + self, azure_ds, mock_device_driver, mock_generate_fallback_config ): - """parse_network_config generates fallback network config when the + """Network config generates fallback network config when the IMDS instance metadata is corrupted/invalid, such as when network interface metadata is not present. """ @@ -694,13 +681,10 @@ class TestParseNetworkConfig(CiTestCase): NETWORK_METADATA ) del imds_metadata_missing_interface_metadata["network"]["interface"] - m_fallback_config.return_value = self.fallback_config - self.assertEqual( - self.fallback_config, - dsaz.parse_network_config( - imds_metadata_missing_interface_metadata - ), - ) + mock_generate_fallback_config.return_value = self.fallback_config + azure_ds._metadata_imds = imds_metadata_missing_interface_metadata + + assert azure_ds.network_config == self.fallback_config class TestGetMetadataFromIMDS(HttprettyTestCase): @@ -1201,16 +1185,15 @@ scbus-1 on xpt0 bus 0 ) def test_basic_seed_dir(self): - odata = {"HostName": "myhost", "UserName": "myuser"} data = { - "ovfcontent": construct_valid_ovf_env(data=odata), + "ovfcontent": construct_ovf_env(hostname="myhost"), "sys_cfg": {}, } dsrc = self._get_ds(data) ret = dsrc.get_data() self.assertTrue(ret) self.assertEqual(dsrc.userdata_raw, "") - self.assertEqual(dsrc.metadata["local-hostname"], odata["HostName"]) + self.assertEqual(dsrc.metadata["local-hostname"], "myhost") self.assertTrue( os.path.isfile(os.path.join(self.waagent_d, "ovf-env.xml")) ) @@ -1221,9 +1204,8 @@ scbus-1 on xpt0 bus 0 ) def test_data_dir_without_imds_data(self): - odata = {"HostName": "myhost", "UserName": "myuser"} data = { - "ovfcontent": construct_valid_ovf_env(data=odata), + "ovfcontent": construct_ovf_env(hostname="myhost"), "sys_cfg": {}, } dsrc = self._get_ds( @@ -1240,7 +1222,7 @@ scbus-1 on xpt0 bus 0 self.assertTrue(ret) self.assertEqual(dsrc.userdata_raw, "") - self.assertEqual(dsrc.metadata["local-hostname"], odata["HostName"]) + self.assertEqual(dsrc.metadata["local-hostname"], "myhost") self.assertTrue( os.path.isfile(os.path.join(self.waagent_d, "ovf-env.xml")) ) @@ -1269,9 +1251,10 @@ scbus-1 on xpt0 bus 0 def test_get_data_non_ubuntu_will_not_remove_network_scripts(self): """get_data on non-Ubuntu will not remove ubuntu net scripts.""" - odata = {"HostName": "myhost", "UserName": "myuser"} data = { - "ovfcontent": construct_valid_ovf_env(data=odata), + "ovfcontent": construct_ovf_env( + hostname="myhost", username="myuser" + ), "sys_cfg": {}, } @@ -1282,9 +1265,8 @@ scbus-1 on xpt0 bus 0 def test_get_data_on_ubuntu_will_remove_network_scripts(self): """get_data will remove ubuntu net scripts on Ubuntu distro.""" sys_cfg = {"datasource": {"Azure": {"apply_network_config": True}}} - odata = {"HostName": "myhost", "UserName": "myuser"} data = { - "ovfcontent": construct_valid_ovf_env(data=odata), + "ovfcontent": construct_ovf_env(), "sys_cfg": sys_cfg, } @@ -1295,9 +1277,8 @@ scbus-1 on xpt0 bus 0 def test_get_data_on_ubuntu_will_not_remove_network_scripts_disabled(self): """When apply_network_config false, do not remove scripts on Ubuntu.""" sys_cfg = {"datasource": {"Azure": {"apply_network_config": False}}} - odata = {"HostName": "myhost", "UserName": "myuser"} data = { - "ovfcontent": construct_valid_ovf_env(data=odata), + "ovfcontent": construct_ovf_env(), "sys_cfg": sys_cfg, } @@ -1307,28 +1288,19 @@ scbus-1 on xpt0 bus 0 def test_crawl_metadata_returns_structured_data_and_caches_nothing(self): """Return all structured metadata and cache no class attributes.""" - yaml_cfg = "" - odata = { - "HostName": "myhost", - "UserName": "myuser", - "UserData": {"text": "FOOBAR", "encoding": "plain"}, - "dscfg": {"text": yaml_cfg, "encoding": "plain"}, - } data = { - "ovfcontent": construct_valid_ovf_env(data=odata), + "ovfcontent": construct_ovf_env( + hostname="myhost", username="myuser", custom_data="FOOBAR" + ), "sys_cfg": {}, } dsrc = self._get_ds(data) expected_cfg = { "PreprovisionedVMType": None, "PreprovisionedVm": False, - "datasource": {"Azure": {}}, "system_info": {"default_user": {"name": "myuser"}}, } expected_metadata = { - "azure_data": { - "configurationsettype": "LinuxProvisioningConfiguration" - }, "imds": NETWORK_METADATA, "instance-id": EXAMPLE_UUID, "local-hostname": "myhost", @@ -1346,11 +1318,11 @@ scbus-1 on xpt0 bus 0 list(crawled_metadata["files"].keys()), ["ovf-env.xml"] ) self.assertIn( - b"<HostName>myhost</HostName>", + b"<ns1:HostName>myhost</ns1:HostName>", crawled_metadata["files"]["ovf-env.xml"], ) self.assertEqual(crawled_metadata["metadata"], expected_metadata) - self.assertEqual(crawled_metadata["userdata_raw"], "FOOBAR") + self.assertEqual(crawled_metadata["userdata_raw"], b"FOOBAR") self.assertEqual(dsrc.userdata_raw, None) self.assertEqual(dsrc.metadata, {}) self.assertEqual(dsrc._metadata_imds, UNSET) @@ -1372,9 +1344,7 @@ scbus-1 on xpt0 bus 0 def test_crawl_metadata_call_imds_once_no_reprovision(self): """If reprovisioning, report ready at the end""" - ovfenv = construct_valid_ovf_env( - platform_settings={"PreprovisionedVm": "False"} - ) + ovfenv = construct_ovf_env(preprovisioned_vm=False) data = {"ovfcontent": ovfenv, "sys_cfg": {}} dsrc = self._get_ds(data) @@ -1390,9 +1360,7 @@ scbus-1 on xpt0 bus 0 self, poll_imds_func, m_report_ready, m_write ): """If reprovisioning, imds metadata will be fetched twice""" - ovfenv = construct_valid_ovf_env( - platform_settings={"PreprovisionedVm": "True"} - ) + ovfenv = construct_ovf_env(preprovisioned_vm=True) data = {"ovfcontent": ovfenv, "sys_cfg": {}} dsrc = self._get_ds(data) @@ -1409,9 +1377,7 @@ scbus-1 on xpt0 bus 0 self, poll_imds_func, m_report_ready, m_write ): """If reprovisioning, report ready at the end""" - ovfenv = construct_valid_ovf_env( - platform_settings={"PreprovisionedVm": "True"} - ) + ovfenv = construct_ovf_env(preprovisioned_vm=True) data = {"ovfcontent": ovfenv, "sys_cfg": {}} dsrc = self._get_ds(data) @@ -1432,11 +1398,8 @@ scbus-1 on xpt0 bus 0 self, detect_nics, poll_imds_func, report_ready_func, m_write ): """If reprovisioning, report ready at the end""" - ovfenv = construct_valid_ovf_env( - platform_settings={ - "PreprovisionedVMType": "Savable", - "PreprovisionedVm": "True", - } + ovfenv = construct_ovf_env( + preprovisioned_vm=True, preprovisioned_vm_type="Savable" ) data = {"ovfcontent": ovfenv, "sys_cfg": {}} @@ -1459,9 +1422,7 @@ scbus-1 on xpt0 bus 0 self, m_readurl, m_report_ready, m_media_switch, m_write ): """If reprovisioning, report ready using the obtained lease""" - ovfenv = construct_valid_ovf_env( - platform_settings={"PreprovisionedVm": "True"} - ) + ovfenv = construct_ovf_env(preprovisioned_vm=True) data = {"ovfcontent": ovfenv, "sys_cfg": {}} dsrc = self._get_ds(data) @@ -1476,7 +1437,7 @@ scbus-1 on xpt0 bus 0 self.m_dhcp.return_value.obtain_lease.return_value = lease m_media_switch.return_value = None - reprovision_ovfenv = construct_valid_ovf_env() + reprovision_ovfenv = construct_ovf_env() m_readurl.return_value = url_helper.StringResponse( reprovision_ovfenv.encode("utf-8") ) @@ -1490,7 +1451,7 @@ scbus-1 on xpt0 bus 0 def test_waagent_d_has_0700_perms(self): # we expect /var/lib/waagent to be created 0700 - dsrc = self._get_ds({"ovfcontent": construct_valid_ovf_env()}) + dsrc = self._get_ds({"ovfcontent": construct_ovf_env()}) ret = dsrc.get_data() self.assertTrue(ret) self.assertTrue(os.path.isdir(self.waagent_d)) @@ -1502,9 +1463,8 @@ scbus-1 on xpt0 bus 0 def test_network_config_set_from_imds(self, m_driver): """Datasource.network_config returns IMDS network data.""" sys_cfg = {"datasource": {"Azure": {"apply_network_config": True}}} - odata = {} data = { - "ovfcontent": construct_valid_ovf_env(data=odata), + "ovfcontent": construct_ovf_env(), "sys_cfg": sys_cfg, } expected_network_config = { @@ -1531,9 +1491,8 @@ scbus-1 on xpt0 bus 0 ): """Datasource.network_config adds route-metric to secondary nics.""" sys_cfg = {"datasource": {"Azure": {"apply_network_config": True}}} - odata = {} data = { - "ovfcontent": construct_valid_ovf_env(data=odata), + "ovfcontent": construct_ovf_env(), "sys_cfg": sys_cfg, } expected_network_config = { @@ -1583,9 +1542,8 @@ scbus-1 on xpt0 bus 0 ): """If an IP address is empty then there should no config for it.""" sys_cfg = {"datasource": {"Azure": {"apply_network_config": True}}} - odata = {} data = { - "ovfcontent": construct_valid_ovf_env(data=odata), + "ovfcontent": construct_ovf_env(), "sys_cfg": sys_cfg, } expected_network_config = { @@ -1610,9 +1568,8 @@ scbus-1 on xpt0 bus 0 def test_availability_zone_set_from_imds(self): """Datasource.availability returns IMDS platformFaultDomain.""" sys_cfg = {"datasource": {"Azure": {"apply_network_config": True}}} - odata = {} data = { - "ovfcontent": construct_valid_ovf_env(data=odata), + "ovfcontent": construct_ovf_env(), "sys_cfg": sys_cfg, } dsrc = self._get_ds(data) @@ -1622,9 +1579,8 @@ scbus-1 on xpt0 bus 0 def test_region_set_from_imds(self): """Datasource.region returns IMDS region location.""" sys_cfg = {"datasource": {"Azure": {"apply_network_config": True}}} - odata = {} data = { - "ovfcontent": construct_valid_ovf_env(data=odata), + "ovfcontent": construct_ovf_env(), "sys_cfg": sys_cfg, } dsrc = self._get_ds(data) @@ -1638,7 +1594,7 @@ scbus-1 on xpt0 bus 0 } } data = { - "ovfcontent": construct_valid_ovf_env(data={}), + "ovfcontent": construct_ovf_env(), "sys_cfg": sys_cfg, } @@ -1651,8 +1607,7 @@ scbus-1 on xpt0 bus 0 ) def test_username_used(self): - odata = {"HostName": "myhost", "UserName": "myuser"} - data = {"ovfcontent": construct_valid_ovf_env(data=odata)} + data = {"ovfcontent": construct_ovf_env(username="myuser")} dsrc = self._get_ds(data) ret = dsrc.get_data() @@ -1661,13 +1616,14 @@ scbus-1 on xpt0 bus 0 dsrc.cfg["system_info"]["default_user"]["name"], "myuser" ) + assert "ssh_pwauth" not in dsrc.cfg + def test_password_given(self): - odata = { - "HostName": "myhost", - "UserName": "myuser", - "UserPassword": "mypass", + data = { + "ovfcontent": construct_ovf_env( + username="myuser", password="mypass" + ) } - data = {"ovfcontent": construct_valid_ovf_env(data=odata)} dsrc = self._get_ds(data) ret = dsrc.get_data() @@ -1676,7 +1632,7 @@ scbus-1 on xpt0 bus 0 defuser = dsrc.cfg["system_info"]["default_user"] # default user should be updated username and should not be locked. - self.assertEqual(defuser["name"], odata["UserName"]) + self.assertEqual(defuser["name"], "myuser") self.assertFalse(defuser["lock_passwd"]) # passwd is crypt formated string $id$salt$encrypted # encrypting plaintext with salt value of everything up to final '$' @@ -1684,19 +1640,102 @@ scbus-1 on xpt0 bus 0 pos = defuser["passwd"].rfind("$") + 1 self.assertEqual( defuser["passwd"], - crypt.crypt(odata["UserPassword"], defuser["passwd"][0:pos]), + crypt.crypt("mypass", defuser["passwd"][0:pos]), ) # the same hashed value should also be present in cfg['password'] self.assertEqual(defuser["passwd"], dsrc.cfg["password"]) + assert dsrc.cfg["ssh_pwauth"] is True + + def test_password_with_disable_ssh_pw_auth_true(self): + data = { + "ovfcontent": construct_ovf_env( + username="myuser", + password="mypass", + disable_ssh_password_auth=True, + ) + } + + dsrc = self._get_ds(data) + dsrc.get_data() + + assert dsrc.cfg["ssh_pwauth"] is False + + def test_password_with_disable_ssh_pw_auth_false(self): + data = { + "ovfcontent": construct_ovf_env( + username="myuser", + password="mypass", + disable_ssh_password_auth=False, + ) + } + + dsrc = self._get_ds(data) + dsrc.get_data() + + assert dsrc.cfg["ssh_pwauth"] is True + + def test_password_with_disable_ssh_pw_auth_unspecified(self): + data = { + "ovfcontent": construct_ovf_env( + username="myuser", + password="mypass", + disable_ssh_password_auth=None, + ) + } + + dsrc = self._get_ds(data) + dsrc.get_data() + + assert dsrc.cfg["ssh_pwauth"] is True + + def test_no_password_with_disable_ssh_pw_auth_true(self): + data = { + "ovfcontent": construct_ovf_env( + username="myuser", + disable_ssh_password_auth=True, + ) + } + + dsrc = self._get_ds(data) + dsrc.get_data() + + assert dsrc.cfg["ssh_pwauth"] is False + + def test_no_password_with_disable_ssh_pw_auth_false(self): + data = { + "ovfcontent": construct_ovf_env( + username="myuser", + disable_ssh_password_auth=False, + ) + } + + dsrc = self._get_ds(data) + dsrc.get_data() + + assert dsrc.cfg["ssh_pwauth"] is True + + def test_no_password_with_disable_ssh_pw_auth_unspecified(self): + data = { + "ovfcontent": construct_ovf_env( + username="myuser", + disable_ssh_password_auth=None, + ) + } + + dsrc = self._get_ds(data) + dsrc.get_data() + + assert "ssh_pwauth" not in dsrc.cfg + def test_user_not_locked_if_password_redacted(self): - odata = { - "HostName": "myhost", - "UserName": "myuser", - "UserPassword": dsaz.DEF_PASSWD_REDACTION, + data = { + "ovfcontent": construct_ovf_env( + username="myuser", + password=dsaz.DEF_PASSWD_REDACTION, + ) } - data = {"ovfcontent": construct_valid_ovf_env(data=odata)} dsrc = self._get_ds(data) ret = dsrc.get_data() @@ -1705,24 +1744,13 @@ scbus-1 on xpt0 bus 0 defuser = dsrc.cfg["system_info"]["default_user"] # default user should be updated username and should not be locked. - self.assertEqual(defuser["name"], odata["UserName"]) + self.assertEqual(defuser["name"], "myuser") self.assertIn("lock_passwd", defuser) self.assertFalse(defuser["lock_passwd"]) - def test_userdata_plain(self): - mydata = "FOOBAR" - odata = {"UserData": {"text": mydata, "encoding": "plain"}} - data = {"ovfcontent": construct_valid_ovf_env(data=odata)} - - dsrc = self._get_ds(data) - ret = dsrc.get_data() - self.assertTrue(ret) - self.assertEqual(decode_binary(dsrc.userdata_raw), mydata) - def test_userdata_found(self): mydata = "FOOBAR" - odata = {"UserData": {"text": b64e(mydata), "encoding": "base64"}} - data = {"ovfcontent": construct_valid_ovf_env(data=odata)} + data = {"ovfcontent": construct_ovf_env(custom_data=mydata)} dsrc = self._get_ds(data) ret = dsrc.get_data() @@ -1731,9 +1759,8 @@ scbus-1 on xpt0 bus 0 def test_default_ephemeral_configs_ephemeral_exists(self): # make sure the ephemeral configs are correct if disk present - odata = {} data = { - "ovfcontent": construct_valid_ovf_env(data=odata), + "ovfcontent": construct_ovf_env(), "sys_cfg": {}, } @@ -1761,9 +1788,8 @@ scbus-1 on xpt0 bus 0 def test_default_ephemeral_configs_ephemeral_does_not_exist(self): # make sure the ephemeral configs are correct if disk not present - odata = {} data = { - "ovfcontent": construct_valid_ovf_env(data=odata), + "ovfcontent": construct_ovf_env(), "sys_cfg": {}, } @@ -1783,34 +1809,9 @@ scbus-1 on xpt0 bus 0 assert "disk_setup" not in cfg assert "fs_setup" not in cfg - def test_provide_disk_aliases(self): - # Make sure that user can affect disk aliases - dscfg = {"disk_aliases": {"ephemeral0": "/dev/sdc"}} - odata = { - "HostName": "myhost", - "UserName": "myuser", - "dscfg": {"text": b64e(yaml.dump(dscfg)), "encoding": "base64"}, - } - usercfg = { - "disk_setup": { - "/dev/sdc": {"something": "..."}, - "ephemeral0": False, - } - } - userdata = "#cloud-config" + yaml.dump(usercfg) + "\n" - - ovfcontent = construct_valid_ovf_env(data=odata, userdata=userdata) - data = {"ovfcontent": ovfcontent, "sys_cfg": {}} - - dsrc = self._get_ds(data) - ret = dsrc.get_data() - self.assertTrue(ret) - cfg = dsrc.get_config_obj() - self.assertTrue(cfg) - def test_userdata_arrives(self): userdata = "This is my user-data" - xml = construct_valid_ovf_env(data={}, userdata=userdata) + xml = construct_ovf_env(custom_data=userdata) data = {"ovfcontent": xml} dsrc = self._get_ds(data) dsrc.get_data() @@ -1818,12 +1819,11 @@ scbus-1 on xpt0 bus 0 self.assertEqual(userdata.encode("us-ascii"), dsrc.userdata_raw) def test_password_redacted_in_ovf(self): - odata = { - "HostName": "myhost", - "UserName": "myuser", - "UserPassword": "mypass", + data = { + "ovfcontent": construct_ovf_env( + username="myuser", password="mypass" + ) } - data = {"ovfcontent": construct_valid_ovf_env(data=odata)} dsrc = self._get_ds(data) ret = dsrc.get_data() @@ -1846,7 +1846,7 @@ scbus-1 on xpt0 bus 0 self.assertEqual(dsaz.DEF_PASSWD_REDACTION, elem.text) def test_ovf_env_arrives_in_waagent_dir(self): - xml = construct_valid_ovf_env(data={}, userdata="FOODATA") + xml = construct_ovf_env(custom_data="FOODATA") dsrc = self._get_ds({"ovfcontent": xml}) dsrc.get_data() @@ -1857,18 +1857,18 @@ scbus-1 on xpt0 bus 0 self.xml_equals(xml, load_file(ovf_env_path)) def test_ovf_can_include_unicode(self): - xml = construct_valid_ovf_env(data={}) + xml = construct_ovf_env() xml = "\ufeff{0}".format(xml) dsrc = self._get_ds({"ovfcontent": xml}) dsrc.get_data() def test_dsaz_report_ready_returns_true_when_report_succeeds(self): - dsrc = self._get_ds({"ovfcontent": construct_valid_ovf_env()}) + dsrc = self._get_ds({"ovfcontent": construct_ovf_env()}) assert dsrc._report_ready() == [] @mock.patch(MOCKPATH + "report_diagnostic_event") def test_dsaz_report_ready_failure_reports_telemetry(self, m_report_diag): - dsrc = self._get_ds({"ovfcontent": construct_valid_ovf_env()}) + dsrc = self._get_ds({"ovfcontent": construct_ovf_env()}) self.m_get_metadata_from_fabric.side_effect = Exception("foo") with pytest.raises(Exception): @@ -1883,7 +1883,7 @@ scbus-1 on xpt0 bus 0 ] def test_dsaz_report_failure_returns_true_when_report_succeeds(self): - dsrc = self._get_ds({"ovfcontent": construct_valid_ovf_env()}) + dsrc = self._get_ds({"ovfcontent": construct_ovf_env()}) with mock.patch.object(dsrc, "crawl_metadata") as m_crawl_metadata: # mock crawl metadata failure to cause report failure @@ -1895,7 +1895,7 @@ scbus-1 on xpt0 bus 0 def test_dsaz_report_failure_returns_false_and_does_not_propagate_exc( self, ): - dsrc = self._get_ds({"ovfcontent": construct_valid_ovf_env()}) + dsrc = self._get_ds({"ovfcontent": construct_ovf_env()}) with mock.patch.object( dsrc, "crawl_metadata" @@ -1923,7 +1923,7 @@ scbus-1 on xpt0 bus 0 self.assertEqual(2, self.m_report_failure_to_fabric.call_count) def test_dsaz_report_failure_description_msg(self): - dsrc = self._get_ds({"ovfcontent": construct_valid_ovf_env()}) + dsrc = self._get_ds({"ovfcontent": construct_ovf_env()}) with mock.patch.object(dsrc, "crawl_metadata") as m_crawl_metadata: # mock crawl metadata failure to cause report failure @@ -1936,7 +1936,7 @@ scbus-1 on xpt0 bus 0 ) def test_dsaz_report_failure_no_description_msg(self): - dsrc = self._get_ds({"ovfcontent": construct_valid_ovf_env()}) + dsrc = self._get_ds({"ovfcontent": construct_ovf_env()}) with mock.patch.object(dsrc, "crawl_metadata") as m_crawl_metadata: m_crawl_metadata.side_effect = Exception @@ -1947,7 +1947,7 @@ scbus-1 on xpt0 bus 0 ) def test_dsaz_report_failure_uses_cached_ephemeral_dhcp_ctx_lease(self): - dsrc = self._get_ds({"ovfcontent": construct_valid_ovf_env()}) + dsrc = self._get_ds({"ovfcontent": construct_ovf_env()}) with mock.patch.object( dsrc, "crawl_metadata" @@ -1965,7 +1965,7 @@ scbus-1 on xpt0 bus 0 ) def test_dsaz_report_failure_no_net_uses_new_ephemeral_dhcp_lease(self): - dsrc = self._get_ds({"ovfcontent": construct_valid_ovf_env()}) + dsrc = self._get_ds({"ovfcontent": construct_ovf_env()}) with mock.patch.object(dsrc, "crawl_metadata") as m_crawl_metadata: # mock crawl metadata failure to cause report failure @@ -1988,13 +1988,13 @@ scbus-1 on xpt0 bus 0 def test_exception_fetching_fabric_data_doesnt_propagate(self): """Errors communicating with fabric should warn, but return True.""" - dsrc = self._get_ds({"ovfcontent": construct_valid_ovf_env()}) + dsrc = self._get_ds({"ovfcontent": construct_ovf_env()}) self.m_get_metadata_from_fabric.side_effect = Exception ret = self._get_and_setup(dsrc) self.assertTrue(ret) def test_fabric_data_included_in_metadata(self): - dsrc = self._get_ds({"ovfcontent": construct_valid_ovf_env()}) + dsrc = self._get_ds({"ovfcontent": construct_ovf_env()}) self.m_get_metadata_from_fabric.return_value = ["ssh-key-value"] ret = self._get_and_setup(dsrc) self.assertTrue(ret) @@ -2006,7 +2006,7 @@ scbus-1 on xpt0 bus 0 upper_iid = EXAMPLE_UUID.upper() # lowercase current UUID ds = self._get_ds( - {"ovfcontent": construct_valid_ovf_env()}, instance_id=lower_iid + {"ovfcontent": construct_ovf_env()}, instance_id=lower_iid ) # UPPERCASE previous write_file( @@ -2018,7 +2018,7 @@ scbus-1 on xpt0 bus 0 # UPPERCASE current UUID ds = self._get_ds( - {"ovfcontent": construct_valid_ovf_env()}, instance_id=upper_iid + {"ovfcontent": construct_ovf_env()}, instance_id=upper_iid ) # lowercase previous write_file( @@ -2030,7 +2030,7 @@ scbus-1 on xpt0 bus 0 def test_instance_id_endianness(self): """Return the previous iid when dmi uuid is the byteswapped iid.""" - ds = self._get_ds({"ovfcontent": construct_valid_ovf_env()}) + ds = self._get_ds({"ovfcontent": construct_ovf_env()}) # byte-swapped previous write_file( os.path.join(self.paths.cloud_dir, "data", "instance-id"), @@ -2049,12 +2049,12 @@ scbus-1 on xpt0 bus 0 self.assertEqual(self.instance_id, ds.metadata["instance-id"]) def test_instance_id_from_dmidecode_used(self): - ds = self._get_ds({"ovfcontent": construct_valid_ovf_env()}) + ds = self._get_ds({"ovfcontent": construct_ovf_env()}) ds.get_data() self.assertEqual(self.instance_id, ds.metadata["instance-id"]) def test_instance_id_from_dmidecode_used_for_builtin(self): - ds = self._get_ds({"ovfcontent": construct_valid_ovf_env()}) + ds = self._get_ds({"ovfcontent": construct_ovf_env()}) ds.get_data() self.assertEqual(self.instance_id, ds.metadata["instance-id"]) @@ -2080,126 +2080,12 @@ scbus-1 on xpt0 bus 0 [mock.call("/dev/cd0")], m_check_fbsd_cdrom.call_args_list ) - @mock.patch( - "cloudinit.sources.DataSourceAzure.device_driver", return_value=None - ) - @mock.patch("cloudinit.net.generate_fallback_config") - def test_imds_network_config(self, mock_fallback, m_driver): - """Network config is generated from IMDS network data when present.""" - sys_cfg = {"datasource": {"Azure": {"apply_network_config": True}}} - odata = {"HostName": "myhost", "UserName": "myuser"} - data = { - "ovfcontent": construct_valid_ovf_env(data=odata), - "sys_cfg": sys_cfg, - } - - dsrc = self._get_ds(data) - ret = dsrc.get_data() - self.assertTrue(ret) - - expected_cfg = { - "ethernets": { - "eth0": { - "dhcp4": True, - "dhcp4-overrides": {"route-metric": 100}, - "dhcp6": False, - "match": {"macaddress": "00:0d:3a:04:75:98"}, - "set-name": "eth0", - } - }, - "version": 2, - } - - self.assertEqual(expected_cfg, dsrc.network_config) - mock_fallback.assert_not_called() - - @mock.patch("cloudinit.net.get_interface_mac") - @mock.patch("cloudinit.net.get_devicelist") - @mock.patch("cloudinit.net.device_driver") - @mock.patch("cloudinit.net.generate_fallback_config") - def test_imds_network_ignored_when_apply_network_config_false( - self, mock_fallback, mock_dd, mock_devlist, mock_get_mac - ): - """When apply_network_config is False, use fallback instead of IMDS.""" - sys_cfg = {"datasource": {"Azure": {"apply_network_config": False}}} - odata = {"HostName": "myhost", "UserName": "myuser"} - data = { - "ovfcontent": construct_valid_ovf_env(data=odata), - "sys_cfg": sys_cfg, - } - fallback_config = { - "version": 1, - "config": [ - { - "type": "physical", - "name": "eth0", - "mac_address": "00:11:22:33:44:55", - "params": {"driver": "hv_netsvc"}, - "subnets": [{"type": "dhcp"}], - } - ], - } - mock_fallback.return_value = fallback_config - - mock_devlist.return_value = ["eth0"] - mock_dd.return_value = ["hv_netsvc"] - mock_get_mac.return_value = "00:11:22:33:44:55" - - dsrc = self._get_ds(data) - self.assertTrue(dsrc.get_data()) - self.assertEqual(dsrc.network_config, fallback_config) - - @mock.patch("cloudinit.net.get_interface_mac") - @mock.patch("cloudinit.net.get_devicelist") - @mock.patch("cloudinit.net.device_driver") - @mock.patch("cloudinit.net.generate_fallback_config", autospec=True) - def test_fallback_network_config( - self, mock_fallback, mock_dd, mock_devlist, mock_get_mac - ): - """On absent IMDS network data, generate network fallback config.""" - odata = {"HostName": "myhost", "UserName": "myuser"} - data = { - "ovfcontent": construct_valid_ovf_env(data=odata), - "sys_cfg": {}, - } - - fallback_config = { - "version": 1, - "config": [ - { - "type": "physical", - "name": "eth0", - "mac_address": "00:11:22:33:44:55", - "params": {"driver": "hv_netsvc"}, - "subnets": [{"type": "dhcp"}], - } - ], - } - mock_fallback.return_value = fallback_config - - mock_devlist.return_value = ["eth0"] - mock_dd.return_value = ["hv_netsvc"] - mock_get_mac.return_value = "00:11:22:33:44:55" - - dsrc = self._get_ds(data) - # Represent empty response from network imds - self.m_get_metadata_from_imds.return_value = {} - ret = dsrc.get_data() - self.assertTrue(ret) - - netconfig = dsrc.network_config - self.assertEqual(netconfig, fallback_config) - mock_fallback.assert_called_with( - blacklist_drivers=["mlx4_core", "mlx5_core"], config_driver=True - ) - @mock.patch(MOCKPATH + "net.get_interfaces", autospec=True) def test_blacklist_through_distro(self, m_net_get_interfaces): """Verify Azure DS updates blacklist drivers in the distro's networking object.""" - odata = {"HostName": "myhost", "UserName": "myuser"} data = { - "ovfcontent": construct_valid_ovf_env(data=odata), + "ovfcontent": construct_ovf_env(), "sys_cfg": {}, } @@ -2221,9 +2107,8 @@ scbus-1 on xpt0 bus 0 ) def test_get_public_ssh_keys_with_imds(self, m_parse_certificates): sys_cfg = {"datasource": {"Azure": {"apply_network_config": True}}} - odata = {"HostName": "myhost", "UserName": "myuser"} data = { - "ovfcontent": construct_valid_ovf_env(data=odata), + "ovfcontent": construct_ovf_env(), "sys_cfg": sys_cfg, } dsrc = self._get_ds(data) @@ -2256,9 +2141,8 @@ scbus-1 on xpt0 bus 0 imds_data["compute"]["publicKeys"][0]["keyData"] = "no-openssh-format" m_get_metadata_from_imds.return_value = imds_data sys_cfg = {"datasource": {"Azure": {"apply_network_config": True}}} - odata = {"HostName": "myhost", "UserName": "myuser"} data = { - "ovfcontent": construct_valid_ovf_env(data=odata), + "ovfcontent": construct_ovf_env(), "sys_cfg": sys_cfg, } dsrc = self._get_ds(data) @@ -2272,9 +2156,8 @@ scbus-1 on xpt0 bus 0 def test_get_public_ssh_keys_without_imds(self, m_get_metadata_from_imds): m_get_metadata_from_imds.return_value = dict() sys_cfg = {"datasource": {"Azure": {"apply_network_config": True}}} - odata = {"HostName": "myhost", "UserName": "myuser"} data = { - "ovfcontent": construct_valid_ovf_env(data=odata), + "ovfcontent": construct_ovf_env(), "sys_cfg": sys_cfg, } dsrc = self._get_ds(data) @@ -2295,9 +2178,8 @@ scbus-1 on xpt0 bus 0 m_get_metadata_from_imds.side_effect = get_metadata_from_imds_side_eff sys_cfg = {"datasource": {"Azure": {"apply_network_config": True}}} - odata = {"HostName": "myhost", "UserName": "myuser"} data = { - "ovfcontent": construct_valid_ovf_env(data=odata), + "ovfcontent": construct_ovf_env(), "sys_cfg": sys_cfg, } dsrc = self._get_ds(data) @@ -2326,9 +2208,8 @@ scbus-1 on xpt0 bus 0 ) def test_imds_api_version_wanted_exists(self, m_get_metadata_from_imds): sys_cfg = {"datasource": {"Azure": {"apply_network_config": True}}} - odata = {"HostName": "myhost", "UserName": "myuser"} data = { - "ovfcontent": construct_valid_ovf_env(data=odata), + "ovfcontent": construct_ovf_env(), "sys_cfg": sys_cfg, } dsrc = self._get_ds(data) @@ -2348,9 +2229,8 @@ scbus-1 on xpt0 bus 0 @mock.patch(MOCKPATH + "get_metadata_from_imds") def test_hostname_from_imds(self, m_get_metadata_from_imds): sys_cfg = {"datasource": {"Azure": {"apply_network_config": True}}} - odata = {"HostName": "myhost", "UserName": "myuser"} data = { - "ovfcontent": construct_valid_ovf_env(data=odata), + "ovfcontent": construct_ovf_env(), "sys_cfg": sys_cfg, } imds_data_with_os_profile = copy.deepcopy(NETWORK_METADATA) @@ -2367,9 +2247,8 @@ scbus-1 on xpt0 bus 0 @mock.patch(MOCKPATH + "get_metadata_from_imds") def test_username_from_imds(self, m_get_metadata_from_imds): sys_cfg = {"datasource": {"Azure": {"apply_network_config": True}}} - odata = {"HostName": "myhost", "UserName": "myuser"} data = { - "ovfcontent": construct_valid_ovf_env(data=odata), + "ovfcontent": construct_ovf_env(), "sys_cfg": sys_cfg, } imds_data_with_os_profile = copy.deepcopy(NETWORK_METADATA) @@ -2388,9 +2267,8 @@ scbus-1 on xpt0 bus 0 @mock.patch(MOCKPATH + "get_metadata_from_imds") def test_disable_password_from_imds(self, m_get_metadata_from_imds): sys_cfg = {"datasource": {"Azure": {"apply_network_config": True}}} - odata = {"HostName": "myhost", "UserName": "myuser"} data = { - "ovfcontent": construct_valid_ovf_env(data=odata), + "ovfcontent": construct_ovf_env(), "sys_cfg": sys_cfg, } imds_data_with_os_profile = copy.deepcopy(NETWORK_METADATA) @@ -2407,9 +2285,8 @@ scbus-1 on xpt0 bus 0 @mock.patch(MOCKPATH + "get_metadata_from_imds") def test_userdata_from_imds(self, m_get_metadata_from_imds): sys_cfg = {"datasource": {"Azure": {"apply_network_config": True}}} - odata = {"HostName": "myhost", "UserName": "myuser"} data = { - "ovfcontent": construct_valid_ovf_env(data=odata), + "ovfcontent": construct_ovf_env(), "sys_cfg": sys_cfg, } userdata = "userdataImds" @@ -2431,14 +2308,9 @@ scbus-1 on xpt0 bus 0 self, m_get_metadata_from_imds ): userdataOVF = "userdataOVF" - odata = { - "HostName": "myhost", - "UserName": "myuser", - "UserData": {"text": b64e(userdataOVF), "encoding": "base64"}, - } sys_cfg = {"datasource": {"Azure": {"apply_network_config": True}}} data = { - "ovfcontent": construct_valid_ovf_env(data=odata), + "ovfcontent": construct_ovf_env(custom_data=userdataOVF), "sys_cfg": sys_cfg, } @@ -2487,18 +2359,17 @@ class TestLoadAzureDsDir(CiTestCase): class TestReadAzureOvf(CiTestCase): def test_invalid_xml_raises_non_azure_ds(self): - invalid_xml = "<foo>" + construct_valid_ovf_env(data={}) + invalid_xml = "<foo>" + construct_ovf_env() self.assertRaises( dsaz.BrokenAzureDataSource, dsaz.read_azure_ovf, invalid_xml ) def test_load_with_pubkeys(self): - mypklist = [{"fingerprint": "fp1", "path": "path1", "value": ""}] - pubkeys = [(x["fingerprint"], x["path"], x["value"]) for x in mypklist] - content = construct_valid_ovf_env(pubkeys=pubkeys) + public_keys = [{"fingerprint": "fp1", "path": "path1", "value": ""}] + content = construct_ovf_env(public_keys=public_keys) (_md, _ud, cfg) = dsaz.read_azure_ovf(content) - for mypk in mypklist: - self.assertIn(mypk, cfg["_pubkeys"]) + for pk in public_keys: + self.assertIn(pk, cfg["_pubkeys"]) class TestCanDevBeReformatted(CiTestCase): @@ -2866,9 +2737,7 @@ class TestPreprovisioningReadAzureOvfFlag(CiTestCase): def test_read_azure_ovf_with_true_flag(self): """The read_azure_ovf method should set the PreprovisionedVM cfg flag if the proper setting is present.""" - content = construct_valid_ovf_env( - platform_settings={"PreprovisionedVm": "True"} - ) + content = construct_ovf_env(preprovisioned_vm=True) ret = dsaz.read_azure_ovf(content) cfg = ret[2] self.assertTrue(cfg["PreprovisionedVm"]) @@ -2876,9 +2745,7 @@ class TestPreprovisioningReadAzureOvfFlag(CiTestCase): def test_read_azure_ovf_with_false_flag(self): """The read_azure_ovf method should set the PreprovisionedVM cfg flag to false if the proper setting is false.""" - content = construct_valid_ovf_env( - platform_settings={"PreprovisionedVm": "False"} - ) + content = construct_ovf_env(preprovisioned_vm=False) ret = dsaz.read_azure_ovf(content) cfg = ret[2] self.assertFalse(cfg["PreprovisionedVm"]) @@ -2886,7 +2753,7 @@ class TestPreprovisioningReadAzureOvfFlag(CiTestCase): def test_read_azure_ovf_without_flag(self): """The read_azure_ovf method should not set the PreprovisionedVM cfg flag.""" - content = construct_valid_ovf_env() + content = construct_ovf_env() ret = dsaz.read_azure_ovf(content) cfg = ret[2] self.assertFalse(cfg["PreprovisionedVm"]) @@ -2895,11 +2762,8 @@ class TestPreprovisioningReadAzureOvfFlag(CiTestCase): def test_read_azure_ovf_with_running_type(self): """The read_azure_ovf method should set PreprovisionedVMType cfg flag to Running.""" - content = construct_valid_ovf_env( - platform_settings={ - "PreprovisionedVMType": "Running", - "PreprovisionedVm": "True", - } + content = construct_ovf_env( + preprovisioned_vm=True, preprovisioned_vm_type="Running" ) ret = dsaz.read_azure_ovf(content) cfg = ret[2] @@ -2909,11 +2773,8 @@ class TestPreprovisioningReadAzureOvfFlag(CiTestCase): def test_read_azure_ovf_with_savable_type(self): """The read_azure_ovf method should set PreprovisionedVMType cfg flag to Savable.""" - content = construct_valid_ovf_env( - platform_settings={ - "PreprovisionedVMType": "Savable", - "PreprovisionedVm": "True", - } + content = construct_ovf_env( + preprovisioned_vm=True, preprovisioned_vm_type="Savable" ) ret = dsaz.read_azure_ovf(content) cfg = ret[2] @@ -2997,7 +2858,7 @@ class TestDeterminePPSTypeScenarios: == dsaz.PPSType.UNKNOWN ) assert is_file.mock_calls == [ - mock.call(dsaz.REPORTED_READY_MARKER_FILE) + mock.call(azure_ds._reported_ready_marker_file) ] @@ -3014,10 +2875,7 @@ class TestReprovision(CiTestCase): def test_reprovision_calls__poll_imds(self, _poll_imds, isfile): """_reprovision will poll IMDS.""" isfile.return_value = False - hostname = "myhost" - username = "myuser" - odata = {"HostName": hostname, "UserName": username} - _poll_imds.return_value = construct_valid_ovf_env(data=odata) + _poll_imds.return_value = construct_ovf_env() dsa = dsaz.DataSourceAzure({}, distro=mock.Mock(), paths=self.paths) dsa._reprovision() _poll_imds.assert_called_with() @@ -3053,7 +2911,7 @@ class TestPreprovisioningHotAttachNics(CiTestCase): self.assertEqual(1, m_detach.call_count) self.assertEqual(1, m_writefile.call_count) m_writefile.assert_called_with( - dsaz.REPORTED_READY_MARKER_FILE, mock.ANY + dsa._reported_ready_marker_file, mock.ANY ) @mock.patch(MOCKPATH + "util.write_file", autospec=True) @@ -3231,8 +3089,8 @@ class TestPreprovisioningHotAttachNics(CiTestCase): @mock.patch("cloudinit.net.find_fallback_nic", return_value="eth9") -@mock.patch("cloudinit.net.dhcp.EphemeralIPv4Network") -@mock.patch("cloudinit.net.dhcp.maybe_perform_dhcp_discovery") +@mock.patch("cloudinit.net.ephemeral.EphemeralIPv4Network") +@mock.patch("cloudinit.net.ephemeral.maybe_perform_dhcp_discovery") @mock.patch( "cloudinit.sources.helpers.netlink.wait_for_media_disconnect_connect" ) @@ -3288,7 +3146,9 @@ class TestPreprovisioningPollIMDS(CiTestCase): m_request.side_effect = fake_timeout_once dsa = dsaz.DataSourceAzure({}, distro=mock.Mock(), paths=self.paths) - with mock.patch(MOCKPATH + "REPORTED_READY_MARKER_FILE", report_file): + with mock.patch.object( + dsa, "_reported_ready_marker_file", report_file + ): dsa._poll_imds() assert m_report_ready.mock_calls == [mock.call()] @@ -3316,7 +3176,9 @@ class TestPreprovisioningPollIMDS(CiTestCase): m_isfile.return_value = True dsa = dsaz.DataSourceAzure({}, distro=None, paths=self.paths) dsa._ephemeral_dhcp_ctx = mock.Mock(lease={}) - with mock.patch(MOCKPATH + "REPORTED_READY_MARKER_FILE", report_file): + with mock.patch.object( + dsa, "_reported_ready_marker_file", report_file + ): dsa._poll_imds() self.assertEqual(0, m_dhcp.call_count) self.assertEqual(0, m_media_switch.call_count) @@ -3353,8 +3215,8 @@ class TestPreprovisioningPollIMDS(CiTestCase): report_file = self.tmp_path("report_marker", self.tmp) m_isfile.return_value = True dsa = dsaz.DataSourceAzure({}, distro=None, paths=self.paths) - with mock.patch( - MOCKPATH + "REPORTED_READY_MARKER_FILE", report_file + with mock.patch.object( + dsa, "_reported_ready_marker_file", report_file ), mock.patch.object(dsa, "_ephemeral_dhcp_ctx") as m_dhcp_ctx: m_dhcp_ctx.obtain_lease.return_value = "Dummy lease" dsa._ephemeral_dhcp_ctx = m_dhcp_ctx @@ -3388,7 +3250,9 @@ class TestPreprovisioningPollIMDS(CiTestCase): ] m_media_switch.return_value = None dsa = dsaz.DataSourceAzure({}, distro=mock.Mock(), paths=self.paths) - with mock.patch(MOCKPATH + "REPORTED_READY_MARKER_FILE", report_file): + with mock.patch.object( + dsa, "_reported_ready_marker_file", report_file + ): dsa._poll_imds() self.assertEqual(m_report_ready.call_count, 0) @@ -3416,7 +3280,9 @@ class TestPreprovisioningPollIMDS(CiTestCase): m_media_switch.return_value = None dsa = dsaz.DataSourceAzure({}, distro=None, paths=self.paths) self.assertFalse(os.path.exists(report_file)) - with mock.patch(MOCKPATH + "REPORTED_READY_MARKER_FILE", report_file): + with mock.patch.object( + dsa, "_reported_ready_marker_file", report_file + ): dsa._poll_imds() self.assertEqual(m_report_ready.call_count, 1) self.assertTrue(os.path.exists(report_file)) @@ -3446,7 +3312,9 @@ class TestPreprovisioningPollIMDS(CiTestCase): m_report_ready.side_effect = [Exception("fail")] dsa = dsaz.DataSourceAzure({}, distro=None, paths=self.paths) self.assertFalse(os.path.exists(report_file)) - with mock.patch(MOCKPATH + "REPORTED_READY_MARKER_FILE", report_file): + with mock.patch.object( + dsa, "_reported_ready_marker_file", report_file + ): self.assertRaises(InvalidMetaDataException, dsa._poll_imds) self.assertEqual(m_report_ready.call_count, 1) self.assertFalse(os.path.exists(report_file)) @@ -3458,8 +3326,8 @@ class TestPreprovisioningPollIMDS(CiTestCase): @mock.patch( "cloudinit.sources.helpers.netlink.wait_for_media_disconnect_connect" ) -@mock.patch("cloudinit.net.dhcp.EphemeralIPv4Network", autospec=True) -@mock.patch("cloudinit.net.dhcp.maybe_perform_dhcp_discovery") +@mock.patch("cloudinit.net.ephemeral.EphemeralIPv4Network", autospec=True) +@mock.patch("cloudinit.net.ephemeral.maybe_perform_dhcp_discovery") @mock.patch("requests.Session.request") class TestAzureDataSourcePreprovisioning(CiTestCase): def setUp(self): @@ -3535,8 +3403,7 @@ class TestAzureDataSourcePreprovisioning(CiTestCase): full_url = url.format(host) hostname = "myhost" username = "myuser" - odata = {"HostName": hostname, "UserName": username} - content = construct_valid_ovf_env(data=odata) + content = construct_ovf_env(username=username, hostname=hostname) m_request.return_value = mock.MagicMock( status_code=200, text=content, content=content ) @@ -4203,15 +4070,12 @@ class TestProvisioning: def test_running_pps(self): self.imds_md["extended"]["compute"]["ppsType"] = "Running" - ovf_data = {"HostName": "myhost", "UserName": "myuser"} nl_sock = mock.MagicMock() self.mock_netlink.create_bound_netlink_socket.return_value = nl_sock self.mock_readurl.side_effect = [ mock.MagicMock(contents=json.dumps(self.imds_md).encode()), - mock.MagicMock( - contents=construct_valid_ovf_env(data=ovf_data).encode() - ), + mock.MagicMock(contents=construct_ovf_env().encode()), mock.MagicMock(contents=json.dumps(self.imds_md).encode()), ] self.mock_azure_get_metadata_from_fabric.return_value = [] @@ -4293,7 +4157,6 @@ class TestProvisioning: def test_savable_pps(self): self.imds_md["extended"]["compute"]["ppsType"] = "Savable" - ovf_data = {"HostName": "myhost", "UserName": "myuser"} nl_sock = mock.MagicMock() self.mock_netlink.create_bound_netlink_socket.return_value = nl_sock @@ -4306,9 +4169,7 @@ class TestProvisioning: mock.MagicMock( contents=json.dumps(self.imds_md["network"]).encode() ), - mock.MagicMock( - contents=construct_valid_ovf_env(data=ovf_data).encode() - ), + mock.MagicMock(contents=construct_ovf_env().encode()), mock.MagicMock(contents=json.dumps(self.imds_md).encode()), ] self.mock_azure_get_metadata_from_fabric.return_value = [] @@ -4402,13 +4263,10 @@ class TestProvisioning: def test_recovery_pps(self, pps_type): self.patched_reported_ready_marker_path.write_text("") self.imds_md["extended"]["compute"]["ppsType"] = pps_type - ovf_data = {"HostName": "myhost", "UserName": "myuser"} self.mock_readurl.side_effect = [ mock.MagicMock(contents=json.dumps(self.imds_md).encode()), - mock.MagicMock( - contents=construct_valid_ovf_env(data=ovf_data).encode() - ), + mock.MagicMock(contents=construct_ovf_env().encode()), mock.MagicMock(contents=json.dumps(self.imds_md).encode()), ] self.mock_azure_get_metadata_from_fabric.return_value = [] |