summaryrefslogtreecommitdiff
path: root/tests/unittests/sources
diff options
context:
space:
mode:
authorJames Falcon <james.falcon@canonical.com>2022-07-01 10:07:15 -0500
committergit-ubuntu importer <ubuntu-devel-discuss@lists.ubuntu.com>2022-07-01 16:34:09 +0000
commitcff8a8b47acf7048ad08bd121e677fb86e73635b (patch)
tree011f38ddb27b3df74d78115ebe59be951558edea /tests/unittests/sources
parent15d691e3b0b32c67b0589665b49e9d2755296d1b (diff)
downloadcloud-init-git-cff8a8b47acf7048ad08bd121e677fb86e73635b.tar.gz
22.2-64-g1fcd55d6-0ubuntu1~22.10.1 (patches unapplied)
Imported using git-ubuntu import.
Diffstat (limited to 'tests/unittests/sources')
-rw-r--r--tests/unittests/sources/test_aliyun.py2
-rw-r--r--tests/unittests/sources/test_azure.py892
-rw-r--r--tests/unittests/sources/test_bigstep.py46
-rw-r--r--tests/unittests/sources/test_cloudsigma.py8
-rw-r--r--tests/unittests/sources/test_cloudstack.py5
-rw-r--r--tests/unittests/sources/test_digitalocean.py2
-rw-r--r--tests/unittests/sources/test_ec2.py13
-rw-r--r--tests/unittests/sources/test_gce.py4
-rw-r--r--tests/unittests/sources/test_hetzner.py2
-rw-r--r--tests/unittests/sources/test_init.py33
-rw-r--r--tests/unittests/sources/test_lxd.py77
-rw-r--r--tests/unittests/sources/test_opennebula.py8
-rw-r--r--tests/unittests/sources/test_openstack.py8
-rw-r--r--tests/unittests/sources/test_oracle.py758
-rw-r--r--tests/unittests/sources/test_ovf.py3
-rw-r--r--tests/unittests/sources/test_scaleway.py2
-rw-r--r--tests/unittests/sources/test_smartos.py12
-rw-r--r--tests/unittests/sources/test_upcloud.py4
-rw-r--r--tests/unittests/sources/test_vmware.py4
-rw-r--r--tests/unittests/sources/test_vultr.py23
20 files changed, 1061 insertions, 845 deletions
diff --git a/tests/unittests/sources/test_aliyun.py b/tests/unittests/sources/test_aliyun.py
index 8a61d5ee..e628dc02 100644
--- a/tests/unittests/sources/test_aliyun.py
+++ b/tests/unittests/sources/test_aliyun.py
@@ -149,7 +149,7 @@ class TestAliYunDatasource(test_helpers.HttprettyTestCase):
def _test_host_name(self):
self.assertEqual(
- self.default_metadata["hostname"], self.ds.get_hostname()
+ self.default_metadata["hostname"], self.ds.get_hostname().hostname
)
@mock.patch("cloudinit.sources.DataSourceAliYun._is_aliyun")
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 = []
diff --git a/tests/unittests/sources/test_bigstep.py b/tests/unittests/sources/test_bigstep.py
new file mode 100644
index 00000000..148cfa0b
--- /dev/null
+++ b/tests/unittests/sources/test_bigstep.py
@@ -0,0 +1,46 @@
+import json
+import os
+
+import httpretty
+import pytest
+
+from cloudinit import helpers
+from cloudinit.sources import DataSourceBigstep as bigstep
+from tests.unittests.helpers import mock
+
+M_PATH = "cloudinit.sources.DataSourceBigstep."
+
+IMDS_URL = "http://bigstep.com"
+METADATA_BODY = json.dumps(
+ {
+ "metadata": "metadata",
+ "vendordata_raw": "vendordata_raw",
+ "userdata_raw": "userdata_raw",
+ }
+)
+
+
+class TestBigstep:
+ @httpretty.activate
+ @pytest.mark.parametrize("custom_paths", [False, True])
+ @mock.patch(M_PATH + "util.load_file", return_value=IMDS_URL)
+ def test_get_data_honor_cloud_dir(self, m_load_file, custom_paths, tmpdir):
+ httpretty.register_uri(httpretty.GET, IMDS_URL, body=METADATA_BODY)
+
+ paths = {}
+ url_file = "/var/lib/cloud/data/seed/bigstep/url"
+ if custom_paths:
+ paths = {
+ "cloud_dir": tmpdir.join("cloud"),
+ "run_dir": tmpdir,
+ "templates_dir": tmpdir,
+ }
+ url_file = os.path.join(
+ paths["cloud_dir"], "data", "seed", "bigstep", "url"
+ )
+
+ ds = bigstep.DataSourceBigstep(
+ sys_cfg={}, distro=mock.Mock(), paths=helpers.Paths(paths)
+ )
+ assert ds._get_data()
+ assert [mock.call(url_file)] == m_load_file.call_args_list
diff --git a/tests/unittests/sources/test_cloudsigma.py b/tests/unittests/sources/test_cloudsigma.py
index 8cd58c96..b92c3723 100644
--- a/tests/unittests/sources/test_cloudsigma.py
+++ b/tests/unittests/sources/test_cloudsigma.py
@@ -58,12 +58,14 @@ class DataSourceCloudSigmaTest(test_helpers.CiTestCase):
def test_get_hostname(self):
self.datasource.get_data()
- self.assertEqual("test_server", self.datasource.get_hostname())
+ self.assertEqual(
+ "test_server", self.datasource.get_hostname().hostname
+ )
self.datasource.metadata["name"] = ""
- self.assertEqual("65b2fb23", self.datasource.get_hostname())
+ self.assertEqual("65b2fb23", self.datasource.get_hostname().hostname)
utf8_hostname = b"\xd1\x82\xd0\xb5\xd1\x81\xd1\x82".decode("utf-8")
self.datasource.metadata["name"] = utf8_hostname
- self.assertEqual("65b2fb23", self.datasource.get_hostname())
+ self.assertEqual("65b2fb23", self.datasource.get_hostname().hostname)
def test_get_public_ssh_keys(self):
self.datasource.get_data()
diff --git a/tests/unittests/sources/test_cloudstack.py b/tests/unittests/sources/test_cloudstack.py
index f7c69f91..b37400d3 100644
--- a/tests/unittests/sources/test_cloudstack.py
+++ b/tests/unittests/sources/test_cloudstack.py
@@ -40,6 +40,11 @@ class TestCloudStackPasswordFetching(CiTestCase):
get_networkd_server_address,
)
)
+ get_data_server = mock.MagicMock(return_value=None)
+ self.patches.enter_context(
+ mock.patch(mod_name + ".get_data_server", get_data_server)
+ )
+
self.tmp = self.tmp_dir()
def _set_password_server_response(self, response_string):
diff --git a/tests/unittests/sources/test_digitalocean.py b/tests/unittests/sources/test_digitalocean.py
index f3e6224e..47e46c66 100644
--- a/tests/unittests/sources/test_digitalocean.py
+++ b/tests/unittests/sources/test_digitalocean.py
@@ -178,7 +178,7 @@ class TestDataSourceDigitalOcean(CiTestCase):
self.assertEqual(DO_META.get("vendor_data"), ds.get_vendordata_raw())
self.assertEqual(DO_META.get("region"), ds.availability_zone)
self.assertEqual(DO_META.get("droplet_id"), ds.get_instance_id())
- self.assertEqual(DO_META.get("hostname"), ds.get_hostname())
+ self.assertEqual(DO_META.get("hostname"), ds.get_hostname().hostname)
# Single key
self.assertEqual(
diff --git a/tests/unittests/sources/test_ec2.py b/tests/unittests/sources/test_ec2.py
index e5648007..b7476391 100644
--- a/tests/unittests/sources/test_ec2.py
+++ b/tests/unittests/sources/test_ec2.py
@@ -211,7 +211,7 @@ SECONDARY_IP_METADATA_2018_09_24 = {
M_PATH_NET = "cloudinit.sources.DataSourceEc2.net."
-TAGS_METADATA_2021_03_23 = {
+TAGS_METADATA_2021_03_23: dict = {
**DEFAULT_METADATA,
"tags": {
"instance": {
@@ -837,13 +837,14 @@ class TestEc2(test_helpers.HttprettyTestCase):
self.logs.getvalue(),
)
- @mock.patch("cloudinit.net.dhcp.EphemeralIPv4Network")
+ @mock.patch("cloudinit.net.ephemeral.EphemeralIPv6Network")
+ @mock.patch("cloudinit.net.ephemeral.EphemeralIPv4Network")
@mock.patch("cloudinit.net.find_fallback_nic")
- @mock.patch("cloudinit.net.dhcp.maybe_perform_dhcp_discovery")
+ @mock.patch("cloudinit.net.ephemeral.maybe_perform_dhcp_discovery")
@mock.patch("cloudinit.sources.DataSourceEc2.util.is_FreeBSD")
@responses.activate
def test_ec2_local_performs_dhcp_on_non_bsd(
- self, m_is_bsd, m_dhcp, m_fallback_nic, m_net
+ self, m_is_bsd, m_dhcp, m_fallback_nic, m_net4, m_net6
):
"""Ec2Local returns True for valid platform data on non-BSD with dhcp.
@@ -873,7 +874,7 @@ class TestEc2(test_helpers.HttprettyTestCase):
ret = ds.get_data()
self.assertTrue(ret)
m_dhcp.assert_called_once_with("eth9", None)
- m_net.assert_called_once_with(
+ m_net4.assert_called_once_with(
broadcast="192.168.2.255",
interface="eth9",
ip="192.168.2.9",
@@ -881,7 +882,7 @@ class TestEc2(test_helpers.HttprettyTestCase):
router="192.168.2.1",
static_routes=None,
)
- self.assertIn("Crawl of metadata service took", self.logs.getvalue())
+ self.assertIn("Crawl of metadata service ", self.logs.getvalue())
@responses.activate
def test_get_instance_tags(self):
diff --git a/tests/unittests/sources/test_gce.py b/tests/unittests/sources/test_gce.py
index e030931b..1ce0c6ec 100644
--- a/tests/unittests/sources/test_gce.py
+++ b/tests/unittests/sources/test_gce.py
@@ -126,7 +126,7 @@ class TestDataSourceGCE(test_helpers.HttprettyTestCase):
self.ds.get_data()
shostname = GCE_META.get("instance/hostname").split(".")[0]
- self.assertEqual(shostname, self.ds.get_hostname())
+ self.assertEqual(shostname, self.ds.get_hostname().hostname)
self.assertEqual(
GCE_META.get("instance/id"), self.ds.get_instance_id()
@@ -147,7 +147,7 @@ class TestDataSourceGCE(test_helpers.HttprettyTestCase):
)
shostname = GCE_META_PARTIAL.get("instance/hostname").split(".")[0]
- self.assertEqual(shostname, self.ds.get_hostname())
+ self.assertEqual(shostname, self.ds.get_hostname().hostname)
def test_userdata_no_encoding(self):
"""check that user-data is read."""
diff --git a/tests/unittests/sources/test_hetzner.py b/tests/unittests/sources/test_hetzner.py
index f80ed45f..193b7e42 100644
--- a/tests/unittests/sources/test_hetzner.py
+++ b/tests/unittests/sources/test_hetzner.py
@@ -116,7 +116,7 @@ class TestDataSourceHetzner(CiTestCase):
self.assertTrue(m_readmd.called)
- self.assertEqual(METADATA.get("hostname"), ds.get_hostname())
+ self.assertEqual(METADATA.get("hostname"), ds.get_hostname().hostname)
self.assertEqual(METADATA.get("public-keys"), ds.get_public_ssh_keys())
diff --git a/tests/unittests/sources/test_init.py b/tests/unittests/sources/test_init.py
index ce8fc970..a42c6a72 100644
--- a/tests/unittests/sources/test_init.py
+++ b/tests/unittests/sources/test_init.py
@@ -272,9 +272,11 @@ class TestDataSource(CiTestCase):
self.assertEqual(
"test-subclass-hostname", datasource.metadata["local-hostname"]
)
- self.assertEqual("test-subclass-hostname", datasource.get_hostname())
+ self.assertEqual(
+ "test-subclass-hostname", datasource.get_hostname().hostname
+ )
datasource.metadata["local-hostname"] = "hostname.my.domain.com"
- self.assertEqual("hostname", datasource.get_hostname())
+ self.assertEqual("hostname", datasource.get_hostname().hostname)
def test_get_hostname_with_fqdn_returns_local_hostname_with_domain(self):
"""Datasource.get_hostname with fqdn set gets qualified hostname."""
@@ -285,7 +287,8 @@ class TestDataSource(CiTestCase):
self.assertTrue(datasource.get_data())
datasource.metadata["local-hostname"] = "hostname.my.domain.com"
self.assertEqual(
- "hostname.my.domain.com", datasource.get_hostname(fqdn=True)
+ "hostname.my.domain.com",
+ datasource.get_hostname(fqdn=True).hostname,
)
def test_get_hostname_without_metadata_uses_system_hostname(self):
@@ -300,10 +303,12 @@ class TestDataSource(CiTestCase):
with mock.patch(mock_fqdn) as m_fqdn:
m_gethost.return_value = "systemhostname.domain.com"
m_fqdn.return_value = None # No maching fqdn in /etc/hosts
- self.assertEqual("systemhostname", datasource.get_hostname())
+ self.assertEqual(
+ "systemhostname", datasource.get_hostname().hostname
+ )
self.assertEqual(
"systemhostname.domain.com",
- datasource.get_hostname(fqdn=True),
+ datasource.get_hostname(fqdn=True).hostname,
)
def test_get_hostname_without_metadata_returns_none(self):
@@ -316,9 +321,13 @@ class TestDataSource(CiTestCase):
mock_fqdn = "cloudinit.sources.util.get_fqdn_from_hosts"
with mock.patch("cloudinit.sources.util.get_hostname") as m_gethost:
with mock.patch(mock_fqdn) as m_fqdn:
- self.assertIsNone(datasource.get_hostname(metadata_only=True))
self.assertIsNone(
- datasource.get_hostname(fqdn=True, metadata_only=True)
+ datasource.get_hostname(metadata_only=True).hostname
+ )
+ self.assertIsNone(
+ datasource.get_hostname(
+ fqdn=True, metadata_only=True
+ ).hostname
)
self.assertEqual([], m_gethost.call_args_list)
self.assertEqual([], m_fqdn.call_args_list)
@@ -335,10 +344,12 @@ class TestDataSource(CiTestCase):
with mock.patch(mock_fqdn) as m_fqdn:
m_gethost.return_value = "systemhostname.domain.com"
m_fqdn.return_value = "fqdnhostname.domain.com"
- self.assertEqual("fqdnhostname", datasource.get_hostname())
+ self.assertEqual(
+ "fqdnhostname", datasource.get_hostname().hostname
+ )
self.assertEqual(
"fqdnhostname.domain.com",
- datasource.get_hostname(fqdn=True),
+ datasource.get_hostname(fqdn=True).hostname,
)
def test_get_data_does_not_write_instance_data_on_failure(self):
@@ -750,7 +761,9 @@ class TestDataSource(CiTestCase):
"""Validate get_hostname signature on all subclasses of DataSource."""
base_args = inspect.getfullargspec(DataSource.get_hostname)
# Import all DataSource subclasses so we can inspect them.
- modules = util.find_modules(os.path.dirname(os.path.dirname(__file__)))
+ modules = util.get_modules_from_dir(
+ os.path.dirname(os.path.dirname(__file__))
+ )
for _loc, name in modules.items():
mod_locs, _ = importer.find_module(name, ["cloudinit.sources"], [])
if mod_locs:
diff --git a/tests/unittests/sources/test_lxd.py b/tests/unittests/sources/test_lxd.py
index e11c3746..e60bb71f 100644
--- a/tests/unittests/sources/test_lxd.py
+++ b/tests/unittests/sources/test_lxd.py
@@ -17,7 +17,7 @@ from cloudinit.sources import InvalidMetaDataException
DS_PATH = "cloudinit.sources.DataSourceLXD."
-LStatResponse = namedtuple("lstatresponse", "st_mode")
+LStatResponse = namedtuple("LStatResponse", "st_mode")
NETWORK_V1 = {
@@ -34,7 +34,7 @@ NETWORK_V1 = {
def _add_network_v1_device(devname) -> dict:
"""Helper to inject device name into default network v1 config."""
- network_cfg = deepcopy(NETWORK_V1)
+ network_cfg: dict = deepcopy(NETWORK_V1)
network_cfg["config"][0]["name"] = devname
return network_cfg
@@ -51,14 +51,27 @@ LXD_V1_METADATA = {
},
}
+LXD_V1_METADATA_NO_NETWORK_CONFIG = {
+ "meta-data": "instance-id: my-lxc\nlocal-hostname: my-lxc\n\n",
+ "user-data": "#cloud-config\npackages: [sl]\n",
+ "vendor-data": "#cloud-config\nruncmd: ['echo vendor-data']\n",
+ "config": {
+ "user.user-data": "instance-id: my-lxc\nlocal-hostname: my-lxc\n\n",
+ "user.vendor-data": "#cloud-config\nruncmd: ['echo vendor-data']\n",
+ },
+}
+
-@pytest.fixture
def lxd_metadata():
return LXD_V1_METADATA
+def lxd_metadata_no_network_config():
+ return LXD_V1_METADATA_NO_NETWORK_CONFIG
+
+
@pytest.fixture
-def lxd_ds(request, paths, lxd_metadata):
+def lxd_ds(request, paths):
"""
Return an instantiated DataSourceLXD.
@@ -69,7 +82,30 @@ def lxd_ds(request, paths, lxd_metadata):
(This uses the paths fixture for the required helpers.Paths object)
"""
with mock.patch(DS_PATH + "is_platform_viable", return_value=True):
- with mock.patch(DS_PATH + "read_metadata", return_value=lxd_metadata):
+ with mock.patch(
+ DS_PATH + "read_metadata", return_value=lxd_metadata()
+ ):
+ yield lxd.DataSourceLXD(
+ sys_cfg={}, distro=mock.Mock(), paths=paths
+ )
+
+
+@pytest.fixture
+def lxd_ds_no_network_config(request, paths):
+ """
+ Return an instantiated DataSourceLXD.
+
+ This also performs the mocking required for the default test case:
+ * ``is_platform_viable`` returns True,
+ * ``read_metadata`` returns ``LXD_V1_METADATA_NO_NETWORK_CONFIG``
+
+ (This uses the paths fixture for the required helpers.Paths object)
+ """
+ with mock.patch(DS_PATH + "is_platform_viable", return_value=True):
+ with mock.patch(
+ DS_PATH + "read_metadata",
+ return_value=lxd_metadata_no_network_config(),
+ ):
yield lxd.DataSourceLXD(
sys_cfg={}, distro=mock.Mock(), paths=paths
)
@@ -142,6 +178,37 @@ class TestDataSourceLXD:
assert LXD_V1_METADATA["user-data"] == lxd_ds.userdata_raw
assert LXD_V1_METADATA["vendor-data"] == lxd_ds.vendordata_raw
+ def test_network_config_when_unset(self, lxd_ds):
+ """network_config is correctly computed when _network_config and
+ _crawled_metadata are unset.
+ """
+ assert UNSET == lxd_ds._crawled_metadata
+ assert UNSET == lxd_ds._network_config
+ assert None is lxd_ds.userdata_raw
+ # network-config is dumped from YAML
+ assert NETWORK_V1 == lxd_ds.network_config
+ assert LXD_V1_METADATA == lxd_ds._crawled_metadata
+
+ def test_network_config_crawled_metadata_no_network_config(
+ self, lxd_ds_no_network_config
+ ):
+ """network_config is correctly computed when _network_config is unset
+ and _crawled_metadata does not contain network_config.
+ """
+ lxd.generate_fallback_network_config = mock.Mock(
+ return_value=NETWORK_V1
+ )
+ assert UNSET == lxd_ds_no_network_config._crawled_metadata
+ assert UNSET == lxd_ds_no_network_config._network_config
+ assert None is lxd_ds_no_network_config.userdata_raw
+ # network-config is dumped from YAML
+ assert NETWORK_V1 == lxd_ds_no_network_config.network_config
+ assert (
+ LXD_V1_METADATA_NO_NETWORK_CONFIG
+ == lxd_ds_no_network_config._crawled_metadata
+ )
+ assert 1 == lxd.generate_fallback_network_config.call_count
+
class TestIsPlatformViable:
@pytest.mark.parametrize(
diff --git a/tests/unittests/sources/test_opennebula.py b/tests/unittests/sources/test_opennebula.py
index e05c4749..af1c45b8 100644
--- a/tests/unittests/sources/test_opennebula.py
+++ b/tests/unittests/sources/test_opennebula.py
@@ -73,7 +73,7 @@ class TestOpenNebulaDataSource(CiTestCase):
orig_find_devs_with = util.find_devs_with
try:
# dont' try to lookup for CDs
- util.find_devs_with = lambda n: []
+ util.find_devs_with = lambda n: [] # type: ignore
dsrc = self.ds(sys_cfg=self.sys_cfg, distro=None, paths=self.paths)
ret = dsrc.get_data()
self.assertFalse(ret)
@@ -84,7 +84,7 @@ class TestOpenNebulaDataSource(CiTestCase):
orig_find_devs_with = util.find_devs_with
try:
# dont' try to lookup for CDs
- util.find_devs_with = lambda n: []
+ util.find_devs_with = lambda n: [] # type: ignore
populate_dir(self.seed_dir, {"context.sh": INVALID_CONTEXT})
dsrc = self.ds(sys_cfg=self.sys_cfg, distro=None, paths=self.paths)
self.assertRaises(ds.BrokenContextDiskDir, dsrc.get_data)
@@ -107,7 +107,7 @@ class TestOpenNebulaDataSource(CiTestCase):
] = invalid_user
# dont' try to lookup for CDs
- util.find_devs_with = lambda n: []
+ util.find_devs_with = lambda n: [] # type: ignore
populate_context_dir(self.seed_dir, {"KEY1": "val1"})
dsrc = self.ds(sys_cfg=sys_cfg, distro=None, paths=self.paths)
self.assertRaises(ds.BrokenContextDiskDir, dsrc.get_data)
@@ -118,7 +118,7 @@ class TestOpenNebulaDataSource(CiTestCase):
orig_find_devs_with = util.find_devs_with
try:
# dont' try to lookup for CDs
- util.find_devs_with = lambda n: []
+ util.find_devs_with = lambda n: [] # type: ignore
populate_context_dir(self.seed_dir, {"KEY1": "val1"})
dsrc = self.ds(sys_cfg=self.sys_cfg, distro=None, paths=self.paths)
ret = dsrc.get_data()
diff --git a/tests/unittests/sources/test_openstack.py b/tests/unittests/sources/test_openstack.py
index c111bbcd..f65aab8b 100644
--- a/tests/unittests/sources/test_openstack.py
+++ b/tests/unittests/sources/test_openstack.py
@@ -39,7 +39,7 @@ USER_DATA = b"#!/bin/sh\necho This is user data\n"
VENDOR_DATA = {
"magic": "",
}
-VENDOR_DATA2 = {"static": {}}
+VENDOR_DATA2: dict = {"static": {}}
OSTACK_META = {
"availability_zone": "nova",
"files": [
@@ -284,8 +284,10 @@ class TestOpenStackDataSource(test_helpers.HttprettyTestCase):
m_dhcp.assert_not_called()
@hp.activate
- @test_helpers.mock.patch("cloudinit.net.dhcp.EphemeralIPv4Network")
- @test_helpers.mock.patch("cloudinit.net.dhcp.maybe_perform_dhcp_discovery")
+ @test_helpers.mock.patch("cloudinit.net.ephemeral.EphemeralIPv4Network")
+ @test_helpers.mock.patch(
+ "cloudinit.net.ephemeral.maybe_perform_dhcp_discovery"
+ )
def test_local_datasource(self, m_dhcp, m_net):
"""OpenStackLocal calls EphemeralDHCPNetwork and gets instance data."""
_register_uris(self.VERSION, EC2_FILES, EC2_META, OS_FILES)
diff --git a/tests/unittests/sources/test_oracle.py b/tests/unittests/sources/test_oracle.py
index b7b16952..7cd55be0 100644
--- a/tests/unittests/sources/test_oracle.py
+++ b/tests/unittests/sources/test_oracle.py
@@ -3,7 +3,7 @@
import base64
import copy
import json
-from contextlib import ExitStack
+import logging
from unittest import mock
import pytest
@@ -13,6 +13,7 @@ from cloudinit.sources import NetworkConfigSource
from cloudinit.sources.DataSourceOracle import OpcMetadata
from cloudinit.url_helper import UrlError
from tests.unittests import helpers as test_helpers
+from tests.unittests.helpers import does_not_raise
DS_PATH = "cloudinit.sources.DataSourceOracle"
@@ -87,6 +88,25 @@ OPC_V2_METADATA = """\
# Just a small meaningless change to differentiate the two metadatas
OPC_V1_METADATA = OPC_V2_METADATA.replace("ocid1.instance", "ocid2.instance")
+MAC_ADDR = "00:00:17:02:2b:b1"
+
+DHCP = {
+ "name": "eth0",
+ "type": "physical",
+ "subnets": [
+ {
+ "broadcast": "192.168.122.255",
+ "control": "manual",
+ "gateway": "192.168.122.1",
+ "dns_search": ["foo.com"],
+ "type": "dhcp",
+ "netmask": "255.255.255.0",
+ "dns_nameservers": ["192.168.122.1"],
+ }
+ ],
+}
+KLIBC_NET_CFG = {"version": 1, "config": [DHCP]}
+
@pytest.fixture
def metadata_version():
@@ -94,15 +114,20 @@ def metadata_version():
@pytest.fixture
-def oracle_ds(request, fixture_utils, paths, metadata_version):
+def oracle_ds(request, fixture_utils, paths, metadata_version, mocker):
"""
Return an instantiated DataSourceOracle.
- This also performs the mocking required for the default test case:
+ This also performs the mocking required:
* ``_read_system_uuid`` returns something,
* ``_is_platform_viable`` returns True,
- * ``_is_iscsi_root`` returns True (the simpler code path),
- * ``read_opc_metadata`` returns ``OPC_V1_METADATA``
+ * ``DataSourceOracle._is_iscsi_root`` returns True by default or what
+ pytest.mark.is_iscsi gives as first param,
+ * ``DataSourceOracle._get_iscsi_config`` returns a network cfg if
+ is_iscsi else an empty network config,
+ * ``read_opc_metadata`` returns ``OPC_V1_METADATA``,
+ * ``ephemeral.EphemeralDHCPv4`` and ``net.find_fallback_nic`` mocked to
+ avoid subp calls
(This uses the paths fixture for the required helpers.Paths object, and the
fixture_utils fixture for fetching markers.)
@@ -110,19 +135,29 @@ def oracle_ds(request, fixture_utils, paths, metadata_version):
sys_cfg = fixture_utils.closest_marker_first_arg_or(
request, "ds_sys_cfg", mock.MagicMock()
)
+ is_iscsi = fixture_utils.closest_marker_first_arg_or(
+ request, "is_iscsi", True
+ )
metadata = OpcMetadata(metadata_version, json.loads(OPC_V2_METADATA), None)
- with mock.patch(DS_PATH + "._read_system_uuid", return_value="someuuid"):
- with mock.patch(DS_PATH + "._is_platform_viable", return_value=True):
- with mock.patch(DS_PATH + "._is_iscsi_root", return_value=True):
- with mock.patch(
- DS_PATH + ".read_opc_metadata",
- return_value=metadata,
- ):
- yield oracle.DataSourceOracle(
- sys_cfg=sys_cfg,
- distro=mock.Mock(),
- paths=paths,
- )
+
+ mocker.patch(DS_PATH + ".net.find_fallback_nic")
+ mocker.patch(DS_PATH + ".ephemeral.EphemeralDHCPv4")
+ mocker.patch(DS_PATH + "._read_system_uuid", return_value="someuuid")
+ mocker.patch(DS_PATH + "._is_platform_viable", return_value=True)
+ mocker.patch(DS_PATH + ".read_opc_metadata", return_value=metadata)
+ mocker.patch(DS_PATH + ".KlibcOracleNetworkConfigSource")
+ ds = oracle.DataSourceOracle(
+ sys_cfg=sys_cfg,
+ distro=mock.Mock(),
+ paths=paths,
+ )
+ mocker.patch.object(ds, "_is_iscsi_root", return_value=is_iscsi)
+ if is_iscsi:
+ iscsi_config = copy.deepcopy(KLIBC_NET_CFG)
+ else:
+ iscsi_config = {"version": 1, "config": []}
+ mocker.patch.object(ds, "_get_iscsi_config", return_value=iscsi_config)
+ yield ds
class TestDataSourceOracle:
@@ -158,28 +193,27 @@ class TestDataSourceOracle:
assert oracle_ds.ds_cfg["configure_secondary_nics"]
-class TestIsPlatformViable(test_helpers.CiTestCase):
- @mock.patch(
- DS_PATH + ".dmi.read_dmi_data", return_value=oracle.CHASSIS_ASSET_TAG
+class TestIsPlatformViable:
+ @pytest.mark.parametrize(
+ "dmi_data, platform_viable",
+ [
+ # System with known chassis tag is viable.
+ (oracle.CHASSIS_ASSET_TAG, True),
+ # System without known chassis tag is not viable.
+ (None, False),
+ # System with unknown chassis tag is not viable.
+ ("LetsGoCubs", False),
+ ],
)
- def test_expected_viable(self, m_read_dmi_data):
- """System with known chassis tag is viable."""
- self.assertTrue(oracle._is_platform_viable())
- m_read_dmi_data.assert_has_calls([mock.call("chassis-asset-tag")])
-
- @mock.patch(DS_PATH + ".dmi.read_dmi_data", return_value=None)
- def test_expected_not_viable_dmi_data_none(self, m_read_dmi_data):
- """System without known chassis tag is not viable."""
- self.assertFalse(oracle._is_platform_viable())
- m_read_dmi_data.assert_has_calls([mock.call("chassis-asset-tag")])
-
- @mock.patch(DS_PATH + ".dmi.read_dmi_data", return_value="LetsGoCubs")
- def test_expected_not_viable_other(self, m_read_dmi_data):
- """System with unnown chassis tag is not viable."""
- self.assertFalse(oracle._is_platform_viable())
+ def test_is_platform_viable(self, dmi_data, platform_viable):
+ with mock.patch(
+ DS_PATH + ".dmi.read_dmi_data", return_value=dmi_data
+ ) as m_read_dmi_data:
+ assert platform_viable == oracle._is_platform_viable()
m_read_dmi_data.assert_has_calls([mock.call("chassis-asset-tag")])
+@pytest.mark.is_iscsi(False)
@mock.patch(
"cloudinit.net.is_openvswitch_internal_interface",
mock.Mock(return_value=False),
@@ -190,7 +224,7 @@ class TestNetworkConfigFromOpcImds:
# We test this by using in a non-dict to ensure that no dict
# operations are used; failure would be seen as exceptions
oracle_ds._network_config = object()
- oracle_ds._add_network_config_from_opc_imds()
+ oracle_ds._add_network_config_from_opc_imds(set_primary=False)
def test_bare_metal_machine_skipped(self, oracle_ds, caplog):
# nicIndex in the first entry indicates a bare metal machine
@@ -198,40 +232,47 @@ class TestNetworkConfigFromOpcImds:
# We test this by using a non-dict to ensure that no dict
# operations are used
oracle_ds._network_config = object()
- oracle_ds._add_network_config_from_opc_imds()
+ oracle_ds._add_network_config_from_opc_imds(set_primary=False)
assert "bare metal machine" in caplog.text
- def test_missing_mac_skipped(self, oracle_ds, caplog):
- oracle_ds._vnics_data = json.loads(OPC_VM_SECONDARY_VNIC_RESPONSE)
-
- oracle_ds._network_config = {
- "version": 1,
- "config": [{"primary": "nic"}],
- }
- with mock.patch(DS_PATH + ".get_interfaces_by_mac", return_value={}):
- oracle_ds._add_network_config_from_opc_imds()
-
- assert 1 == len(oracle_ds.network_config["config"])
- assert (
- "Interface with MAC 00:00:17:02:2b:b1 not found; skipping"
- in caplog.text
- )
-
- def test_missing_mac_skipped_v2(self, oracle_ds, caplog):
+ @pytest.mark.parametrize(
+ "network_config, network_config_key",
+ [
+ pytest.param(
+ {
+ "version": 1,
+ "config": [{"primary": "nic"}],
+ },
+ "config",
+ id="v1",
+ ),
+ pytest.param(
+ {
+ "version": 2,
+ "ethernets": {"primary": {"nic": {}}},
+ },
+ "ethernets",
+ id="v2",
+ ),
+ ],
+ )
+ def test_missing_mac_skipped(
+ self,
+ oracle_ds,
+ network_config,
+ network_config_key,
+ caplog,
+ ):
oracle_ds._vnics_data = json.loads(OPC_VM_SECONDARY_VNIC_RESPONSE)
-
- oracle_ds._network_config = {
- "version": 2,
- "ethernets": {"primary": {"nic": {}}},
- }
+ oracle_ds._network_config = network_config
with mock.patch(DS_PATH + ".get_interfaces_by_mac", return_value={}):
- oracle_ds._add_network_config_from_opc_imds()
+ oracle_ds._add_network_config_from_opc_imds(set_primary=False)
- assert 1 == len(oracle_ds.network_config["ethernets"])
+ assert 1 == len(oracle_ds._network_config[network_config_key])
assert (
- "Interface with MAC 00:00:17:02:2b:b1 not found; skipping"
- in caplog.text
+ f"Interface with MAC {MAC_ADDR} not found; skipping" in caplog.text
)
+ assert 1 == caplog.text.count(" not found; skipping")
def test_secondary_nic(self, oracle_ds):
oracle_ds._vnics_data = json.loads(OPC_VM_SECONDARY_VNIC_RESPONSE)
@@ -239,12 +280,12 @@ class TestNetworkConfigFromOpcImds:
"version": 1,
"config": [{"primary": "nic"}],
}
- mac_addr, nic_name = "00:00:17:02:2b:b1", "ens3"
+ mac_addr, nic_name = MAC_ADDR, "ens3"
with mock.patch(
DS_PATH + ".get_interfaces_by_mac",
return_value={mac_addr: nic_name},
):
- oracle_ds._add_network_config_from_opc_imds()
+ oracle_ds._add_network_config_from_opc_imds(set_primary=False)
# The input is mutated
assert 2 == len(oracle_ds.network_config["config"])
@@ -266,12 +307,12 @@ class TestNetworkConfigFromOpcImds:
"version": 2,
"ethernets": {"primary": {"nic": {}}},
}
- mac_addr, nic_name = "00:00:17:02:2b:b1", "ens3"
+ mac_addr, nic_name = MAC_ADDR, "ens3"
with mock.patch(
DS_PATH + ".get_interfaces_by_mac",
return_value={mac_addr: nic_name},
):
- oracle_ds._add_network_config_from_opc_imds()
+ oracle_ds._add_network_config_from_opc_imds(set_primary=False)
# The input is mutated
assert 2 == len(oracle_ds.network_config["ethernets"])
@@ -286,77 +327,180 @@ class TestNetworkConfigFromOpcImds:
# These values are hard-coded in OPC_VM_SECONDARY_VNIC_RESPONSE
assert "10.0.0.231" == secondary_nic_cfg["addresses"][0]
+ @pytest.mark.parametrize("error_add_network", [None, Exception])
+ @pytest.mark.parametrize(
+ "configure_secondary_nics",
+ [False, True],
+ )
+ @mock.patch(DS_PATH + "._ensure_netfailover_safe")
+ def test_network_config_log_errors(
+ self,
+ m_ensure_netfailover_safe,
+ configure_secondary_nics,
+ error_add_network,
+ oracle_ds,
+ caplog,
+ capsys,
+ ):
+ assert not oracle_ds._has_network_config()
+ oracle_ds.ds_cfg["configure_secondary_nics"] = configure_secondary_nics
+ with mock.patch.object(
+ oracle.DataSourceOracle,
+ "_add_network_config_from_opc_imds",
+ ) as m_add_network_config_from_opc_imds:
+ if error_add_network:
+ m_add_network_config_from_opc_imds.side_effect = (
+ error_add_network
+ )
+ oracle_ds.network_config # pylint: disable=pointless-statement # noqa: E501
+ assert [
+ mock.call(True, False)
+ == m_add_network_config_from_opc_imds.call_args_list
+ ]
+ assert 1 == oracle_ds._is_iscsi_root.call_count
+ assert 1 == m_ensure_netfailover_safe.call_count
+
+ assert ("", "") == capsys.readouterr()
+ if not error_add_network:
+ log_initramfs_index = -1
+ else:
+ log_initramfs_index = -3
+ # Primary
+ assert (
+ logging.WARNING,
+ "Failed to parse IMDS network configuration!",
+ ) == caplog.record_tuples[-2][1:]
+ # Secondary
+ assert (
+ logging.DEBUG,
+ "Failed to parse IMDS network configuration!",
+ ) == caplog.record_tuples[-1][1:]
-class TestNetworkConfigFiltersNetFailover(test_helpers.CiTestCase):
- def setUp(self):
- super(TestNetworkConfigFiltersNetFailover, self).setUp()
- self.add_patch(
- DS_PATH + ".get_interfaces_by_mac", "m_get_interfaces_by_mac"
- )
- self.add_patch(DS_PATH + ".is_netfail_master", "m_netfail_master")
+ assert (
+ logging.WARNING,
+ "Could not obtain network configuration from initramfs."
+ " Falling back to IMDS.",
+ ) == caplog.record_tuples[log_initramfs_index][1:]
- def test_ignore_bogus_network_config(self):
- netcfg = {"something": "here"}
- passed_netcfg = copy.copy(netcfg)
- oracle._ensure_netfailover_safe(passed_netcfg)
- self.assertEqual(netcfg, passed_netcfg)
- def test_ignore_network_config_unknown_versions(self):
- netcfg = {"something": "here", "version": 3}
+@mock.patch(DS_PATH + ".get_interfaces_by_mac")
+@mock.patch(DS_PATH + ".is_netfail_master")
+class TestNetworkConfigFiltersNetFailover:
+ @pytest.mark.parametrize(
+ "netcfg",
+ [
+ pytest.param({"something": "here"}, id="bogus"),
+ pytest.param(
+ {"something": "here", "version": 3}, id="unknown_version"
+ ),
+ ],
+ )
+ def test_ignore_network_config(
+ self, m_netfail_master, m_get_interfaces_by_mac, netcfg
+ ):
passed_netcfg = copy.copy(netcfg)
oracle._ensure_netfailover_safe(passed_netcfg)
- self.assertEqual(netcfg, passed_netcfg)
+ assert netcfg == passed_netcfg
- def test_checks_v1_type_physical_interfaces(self):
- mac_addr, nic_name = "00:00:17:02:2b:b1", "ens3"
- self.m_get_interfaces_by_mac.return_value = {
- mac_addr: nic_name,
- }
- netcfg = {
- "version": 1,
- "config": [
+ @pytest.mark.parametrize(
+ "nic_name, netcfg, netfail_master_return, call_args_list",
+ [
+ pytest.param(
+ "ens3",
{
- "type": "physical",
- "name": nic_name,
- "mac_address": mac_addr,
- "subnets": [{"type": "dhcp4"}],
- }
- ],
- }
- passed_netcfg = copy.copy(netcfg)
- self.m_netfail_master.return_value = False
- oracle._ensure_netfailover_safe(passed_netcfg)
- self.assertEqual(netcfg, passed_netcfg)
- self.assertEqual(
- [mock.call(nic_name)], self.m_netfail_master.call_args_list
- )
-
- def test_checks_v1_skips_non_phys_interfaces(self):
- mac_addr, nic_name = "00:00:17:02:2b:b1", "bond0"
- self.m_get_interfaces_by_mac.return_value = {
- mac_addr: nic_name,
- }
- netcfg = {
- "version": 1,
- "config": [
+ "version": 1,
+ "config": [
+ {
+ "type": "physical",
+ "name": "ens3",
+ "mac_address": MAC_ADDR,
+ "subnets": [{"type": "dhcp4"}],
+ }
+ ],
+ },
+ False,
+ [mock.call("ens3")],
+ id="checks_v1_type_physical_interfaces",
+ ),
+ pytest.param(
+ "bond0",
{
- "type": "bond",
- "name": nic_name,
- "mac_address": mac_addr,
- "subnets": [{"type": "dhcp4"}],
- }
- ],
+ "version": 1,
+ "config": [
+ {
+ "type": "bond",
+ "name": "bond0",
+ "mac_address": MAC_ADDR,
+ "subnets": [{"type": "dhcp4"}],
+ }
+ ],
+ },
+ None,
+ [],
+ id="skips_v1_non_phys_interfaces",
+ ),
+ pytest.param(
+ "ens3",
+ {
+ "version": 2,
+ "ethernets": {
+ "ens3": {
+ "dhcp4": True,
+ "critical": True,
+ "set-name": "ens3",
+ "match": {"macaddress": MAC_ADDR},
+ }
+ },
+ },
+ False,
+ [mock.call("ens3")],
+ id="checks_v2_type_ethernet_interfaces",
+ ),
+ pytest.param(
+ "wlps0",
+ {
+ "version": 2,
+ "ethernets": {
+ "wlps0": {
+ "dhcp4": True,
+ "critical": True,
+ "set-name": "wlps0",
+ "match": {"macaddress": MAC_ADDR},
+ }
+ },
+ },
+ None,
+ [mock.call("wlps0")],
+ id="skips_v2_non_ethernet_interfaces",
+ ),
+ ],
+ )
+ def test__ensure_netfailover_safe(
+ self,
+ m_netfail_master,
+ m_get_interfaces_by_mac,
+ nic_name,
+ netcfg,
+ netfail_master_return,
+ call_args_list,
+ ):
+ m_get_interfaces_by_mac.return_value = {
+ MAC_ADDR: nic_name,
}
passed_netcfg = copy.copy(netcfg)
+ if netfail_master_return is not None:
+ m_netfail_master.return_value = netfail_master_return
oracle._ensure_netfailover_safe(passed_netcfg)
- self.assertEqual(netcfg, passed_netcfg)
- self.assertEqual(0, self.m_netfail_master.call_count)
-
- def test_removes_master_mac_property_v1(self):
- nic_master, mac_master = "ens3", self.random_string()
- nic_other, mac_other = "ens7", self.random_string()
- nic_extra, mac_extra = "enp0s1f2", self.random_string()
- self.m_get_interfaces_by_mac.return_value = {
+ assert netcfg == passed_netcfg
+ assert call_args_list == m_netfail_master.call_args_list
+
+ def test_removes_master_mac_property_v1(
+ self, m_netfail_master, m_get_interfaces_by_mac
+ ):
+ nic_master, mac_master = "ens3", test_helpers.random_string()
+ nic_other, mac_other = "ens7", test_helpers.random_string()
+ nic_extra, mac_extra = "enp0s1f2", test_helpers.random_string()
+ m_get_interfaces_by_mac.return_value = {
mac_master: nic_master,
mac_other: nic_other,
mac_extra: nic_extra,
@@ -387,7 +531,7 @@ class TestNetworkConfigFiltersNetFailover(test_helpers.CiTestCase):
return True
return False
- self.m_netfail_master.side_effect = _is_netfail_master
+ m_netfail_master.side_effect = _is_netfail_master
expected_cfg = {
"version": 1,
"config": [
@@ -405,58 +549,15 @@ class TestNetworkConfigFiltersNetFailover(test_helpers.CiTestCase):
],
}
oracle._ensure_netfailover_safe(netcfg)
- self.assertEqual(expected_cfg, netcfg)
-
- def test_checks_v2_type_ethernet_interfaces(self):
- mac_addr, nic_name = "00:00:17:02:2b:b1", "ens3"
- self.m_get_interfaces_by_mac.return_value = {
- mac_addr: nic_name,
- }
- netcfg = {
- "version": 2,
- "ethernets": {
- nic_name: {
- "dhcp4": True,
- "critical": True,
- "set-name": nic_name,
- "match": {"macaddress": mac_addr},
- }
- },
- }
- passed_netcfg = copy.copy(netcfg)
- self.m_netfail_master.return_value = False
- oracle._ensure_netfailover_safe(passed_netcfg)
- self.assertEqual(netcfg, passed_netcfg)
- self.assertEqual(
- [mock.call(nic_name)], self.m_netfail_master.call_args_list
- )
+ assert expected_cfg == netcfg
- def test_skips_v2_non_ethernet_interfaces(self):
- mac_addr, nic_name = "00:00:17:02:2b:b1", "wlps0"
- self.m_get_interfaces_by_mac.return_value = {
- mac_addr: nic_name,
- }
- netcfg = {
- "version": 2,
- "wifis": {
- nic_name: {
- "dhcp4": True,
- "critical": True,
- "set-name": nic_name,
- "match": {"macaddress": mac_addr},
- }
- },
- }
- passed_netcfg = copy.copy(netcfg)
- oracle._ensure_netfailover_safe(passed_netcfg)
- self.assertEqual(netcfg, passed_netcfg)
- self.assertEqual(0, self.m_netfail_master.call_count)
-
- def test_removes_master_mac_property_v2(self):
- nic_master, mac_master = "ens3", self.random_string()
- nic_other, mac_other = "ens7", self.random_string()
- nic_extra, mac_extra = "enp0s1f2", self.random_string()
- self.m_get_interfaces_by_mac.return_value = {
+ def test_removes_master_mac_property_v2(
+ self, m_netfail_master, m_get_interfaces_by_mac
+ ):
+ nic_master, mac_master = "ens3", test_helpers.random_string()
+ nic_other, mac_other = "ens7", test_helpers.random_string()
+ nic_extra, mac_extra = "enp0s1f2", test_helpers.random_string()
+ m_get_interfaces_by_mac.return_value = {
mac_master: nic_master,
mac_other: nic_other,
mac_extra: nic_extra,
@@ -487,7 +588,7 @@ class TestNetworkConfigFiltersNetFailover(test_helpers.CiTestCase):
return True
return False
- self.m_netfail_master.side_effect = _is_netfail_master
+ m_netfail_master.side_effect = _is_netfail_master
expected_cfg = {
"version": 2,
@@ -511,7 +612,7 @@ class TestNetworkConfigFiltersNetFailover(test_helpers.CiTestCase):
pprint.pprint(netcfg)
print("---- ^^ modified ^^ ---- vv original vv ----")
pprint.pprint(expected_cfg)
- self.assertEqual(expected_cfg, netcfg)
+ assert expected_cfg == netcfg
def _mock_v2_urls(httpretty):
@@ -557,7 +658,6 @@ def _mock_no_v2_urls(httpretty):
class TestReadOpcMetadata:
# See https://docs.pytest.org/en/stable/example
# /parametrize.html#parametrizing-conditional-raising
- does_not_raise = ExitStack
@mock.patch("cloudinit.url_helper.time.sleep", lambda _: None)
@pytest.mark.parametrize(
@@ -636,7 +736,29 @@ class TestReadOpcMetadata:
with expectation:
assert expected_body == oracle.read_opc_metadata().instance_data
+ # No need to actually wait between retries in the tests
+ @mock.patch("cloudinit.url_helper.time.sleep", lambda _: None)
+ def test_fetch_vnics_error(self, caplog):
+ def mocked_fetch(*args, path="instance", **kwargs):
+ if path == "vnics":
+ raise UrlError("cause")
+
+ with mock.patch(DS_PATH + "._fetch", side_effect=mocked_fetch):
+ opc_metadata = oracle.read_opc_metadata(fetch_vnics_data=True)
+ assert None is opc_metadata.vnics_data
+ assert (
+ logging.WARNING,
+ "Failed to fetch IMDS network configuration!",
+ ) == caplog.record_tuples[-2][1:]
+
+@pytest.mark.parametrize(
+ "",
+ [
+ pytest.param(marks=pytest.mark.is_iscsi(True), id="iscsi"),
+ pytest.param(marks=pytest.mark.is_iscsi(False), id="non-iscsi"),
+ ],
+)
class TestCommon_GetDataBehaviour:
"""This test class tests behaviour common to iSCSI and non-iSCSI root.
@@ -649,33 +771,14 @@ class TestCommon_GetDataBehaviour:
separate class for that case.)
"""
- @pytest.fixture(params=[True, False])
- def parameterized_oracle_ds(self, request, oracle_ds):
- """oracle_ds parameterized for iSCSI and non-iSCSI root respectively"""
- is_iscsi_root = request.param
- with ExitStack() as stack:
- stack.enter_context(
- mock.patch(
- DS_PATH + "._is_iscsi_root", return_value=is_iscsi_root
- )
- )
- if not is_iscsi_root:
- stack.enter_context(
- mock.patch(DS_PATH + ".net.find_fallback_nic")
- )
- stack.enter_context(
- mock.patch(DS_PATH + ".dhcp.EphemeralDHCPv4")
- )
- yield oracle_ds
-
@mock.patch(
DS_PATH + "._is_platform_viable", mock.Mock(return_value=False)
)
def test_false_if_platform_not_viable(
self,
- parameterized_oracle_ds,
+ oracle_ds,
):
- assert not parameterized_oracle_ds._get_data()
+ assert not oracle_ds._get_data()
@pytest.mark.parametrize(
"keyname,expected_value",
@@ -699,10 +802,10 @@ class TestCommon_GetDataBehaviour:
self,
keyname,
expected_value,
- parameterized_oracle_ds,
+ oracle_ds,
):
- assert parameterized_oracle_ds._get_data()
- assert expected_value == parameterized_oracle_ds.metadata[keyname]
+ assert oracle_ds._get_data()
+ assert expected_value == oracle_ds.metadata[keyname]
@pytest.mark.parametrize(
"attribute_name,expected_value",
@@ -722,12 +825,10 @@ class TestCommon_GetDataBehaviour:
self,
attribute_name,
expected_value,
- parameterized_oracle_ds,
+ oracle_ds,
):
- assert parameterized_oracle_ds._get_data()
- assert expected_value == getattr(
- parameterized_oracle_ds, attribute_name
- )
+ assert oracle_ds._get_data()
+ assert expected_value == getattr(oracle_ds, attribute_name)
@pytest.mark.parametrize(
"ssh_keys,expected_value",
@@ -746,7 +847,7 @@ class TestCommon_GetDataBehaviour:
],
)
def test_public_keys_handled_correctly(
- self, ssh_keys, expected_value, parameterized_oracle_ds
+ self, ssh_keys, expected_value, oracle_ds
):
instance_data = json.loads(OPC_V1_METADATA)
if ssh_keys is None:
@@ -758,14 +859,10 @@ class TestCommon_GetDataBehaviour:
DS_PATH + ".read_opc_metadata",
mock.Mock(return_value=metadata),
):
- assert parameterized_oracle_ds._get_data()
- assert (
- expected_value == parameterized_oracle_ds.get_public_ssh_keys()
- )
+ assert oracle_ds._get_data()
+ assert expected_value == oracle_ds.get_public_ssh_keys()
- def test_missing_user_data_handled_gracefully(
- self, parameterized_oracle_ds
- ):
+ def test_missing_user_data_handled_gracefully(self, oracle_ds):
instance_data = json.loads(OPC_V1_METADATA)
del instance_data["metadata"]["user_data"]
metadata = OpcMetadata(None, instance_data, None)
@@ -773,13 +870,11 @@ class TestCommon_GetDataBehaviour:
DS_PATH + ".read_opc_metadata",
mock.Mock(return_value=metadata),
):
- assert parameterized_oracle_ds._get_data()
+ assert oracle_ds._get_data()
- assert parameterized_oracle_ds.userdata_raw is None
+ assert oracle_ds.userdata_raw is None
- def test_missing_metadata_handled_gracefully(
- self, parameterized_oracle_ds
- ):
+ def test_missing_metadata_handled_gracefully(self, oracle_ds):
instance_data = json.loads(OPC_V1_METADATA)
del instance_data["metadata"]
metadata = OpcMetadata(None, instance_data, None)
@@ -787,17 +882,17 @@ class TestCommon_GetDataBehaviour:
DS_PATH + ".read_opc_metadata",
mock.Mock(return_value=metadata),
):
- assert parameterized_oracle_ds._get_data()
+ assert oracle_ds._get_data()
- assert parameterized_oracle_ds.userdata_raw is None
- assert [] == parameterized_oracle_ds.get_public_ssh_keys()
+ assert oracle_ds.userdata_raw is None
+ assert [] == oracle_ds.get_public_ssh_keys()
-@mock.patch(DS_PATH + "._is_iscsi_root", lambda: False)
+@pytest.mark.is_iscsi(False)
class TestNonIscsiRoot_GetDataBehaviour:
- @mock.patch(DS_PATH + ".dhcp.EphemeralDHCPv4")
+ @mock.patch(DS_PATH + ".ephemeral.EphemeralDHCPv4")
@mock.patch(DS_PATH + ".net.find_fallback_nic")
- def test_read_opc_metadata_called_with_ephemeral_dhcp(
+ def test_run_net_files(
self, m_find_fallback_nic, m_EphemeralDHCPv4, oracle_ds
):
in_context_manager = False
@@ -837,74 +932,122 @@ class TestNonIscsiRoot_GetDataBehaviour:
)
] == m_EphemeralDHCPv4.call_args_list
+ @mock.patch(DS_PATH + ".ephemeral.EphemeralDHCPv4")
+ @mock.patch(DS_PATH + ".net.find_fallback_nic")
+ def test_read_opc_metadata_called_with_ephemeral_dhcp(
+ self, m_find_fallback_nic, m_EphemeralDHCPv4, oracle_ds
+ ):
+ in_context_manager = False
-@mock.patch(DS_PATH + ".get_interfaces_by_mac", lambda: {})
-@mock.patch(DS_PATH + ".cmdline.read_initramfs_config")
-class TestNetworkConfig:
- def test_network_config_cached(self, m_read_initramfs_config, oracle_ds):
- """.network_config should be cached"""
- assert 0 == m_read_initramfs_config.call_count
- oracle_ds.network_config # pylint: disable=pointless-statement
- assert 1 == m_read_initramfs_config.call_count
- oracle_ds.network_config # pylint: disable=pointless-statement
- assert 1 == m_read_initramfs_config.call_count
+ def enter_context_manager():
+ nonlocal in_context_manager
+ in_context_manager = True
- def test_network_cmdline(self, m_read_initramfs_config, oracle_ds):
- """network_config should prefer initramfs config over fallback"""
- ncfg = {"version": 1, "config": [{"a": "b"}]}
- m_read_initramfs_config.return_value = copy.deepcopy(ncfg)
+ def exit_context_manager(*args):
+ nonlocal in_context_manager
+ in_context_manager = False
- assert ncfg == oracle_ds.network_config
- assert 0 == oracle_ds.distro.generate_fallback_config.call_count
+ m_EphemeralDHCPv4.return_value.__enter__.side_effect = (
+ enter_context_manager
+ )
+ m_EphemeralDHCPv4.return_value.__exit__.side_effect = (
+ exit_context_manager
+ )
- def test_network_fallback(self, m_read_initramfs_config, oracle_ds):
- """network_config should prefer initramfs config over fallback"""
- ncfg = {"version": 1, "config": [{"a": "b"}]}
+ def assert_in_context_manager(**kwargs):
+ assert in_context_manager
+ return mock.MagicMock()
- m_read_initramfs_config.return_value = None
- oracle_ds.distro.generate_fallback_config.return_value = copy.deepcopy(
- ncfg
- )
+ with mock.patch(
+ DS_PATH + ".read_opc_metadata",
+ mock.Mock(side_effect=assert_in_context_manager),
+ ):
+ assert oracle_ds._get_data()
+
+ assert [
+ mock.call(
+ iface=m_find_fallback_nic.return_value,
+ connectivity_url_data={
+ "headers": {"Authorization": "Bearer Oracle"},
+ "url": "http://169.254.169.254/opc/v2/instance/",
+ },
+ )
+ ] == m_EphemeralDHCPv4.call_args_list
- assert ncfg == oracle_ds.network_config
+
+@mock.patch(DS_PATH + ".get_interfaces_by_mac", return_value={})
+class TestNetworkConfig:
+ def test_network_config_cached(self, m_get_interfaces_by_mac, oracle_ds):
+ """.network_config should be cached"""
+ assert 0 == oracle_ds._get_iscsi_config.call_count
+ oracle_ds.network_config # pylint: disable=pointless-statement
+ assert 1 == oracle_ds._get_iscsi_config.call_count
+ oracle_ds.network_config # pylint: disable=pointless-statement
+ assert 1 == oracle_ds._get_iscsi_config.call_count
@pytest.mark.parametrize(
- "configure_secondary_nics,expect_secondary_nics",
- [(True, True), (False, False), (None, False)],
+ "configure_secondary_nics,is_iscsi,expected_set_primary",
+ [
+ pytest.param(
+ True,
+ True,
+ [mock.call(False)],
+ marks=pytest.mark.is_iscsi(True),
+ ),
+ pytest.param(
+ True,
+ False,
+ [mock.call(True)],
+ marks=pytest.mark.is_iscsi(False),
+ ),
+ pytest.param(False, True, [], marks=pytest.mark.is_iscsi(True)),
+ pytest.param(
+ False,
+ False,
+ [mock.call(True)],
+ marks=pytest.mark.is_iscsi(False),
+ ),
+ pytest.param(None, True, [], marks=pytest.mark.is_iscsi(True)),
+ pytest.param(
+ None,
+ False,
+ [mock.call(True)],
+ marks=pytest.mark.is_iscsi(False),
+ ),
+ ],
)
def test_secondary_nic_addition(
self,
- m_read_initramfs_config,
+ m_get_interfaces_by_mac,
configure_secondary_nics,
- expect_secondary_nics,
+ is_iscsi,
+ expected_set_primary,
oracle_ds,
):
"""Test that _add_network_config_from_opc_imds is called as expected
(configure_secondary_nics=None is used to test the default behaviour.)
"""
- m_read_initramfs_config.return_value = {"version": 1, "config": []}
if configure_secondary_nics is not None:
oracle_ds.ds_cfg[
"configure_secondary_nics"
] = configure_secondary_nics
- def side_effect(self):
- self._network_config["secondary_added"] = mock.sentinel.needle
-
oracle_ds._vnics_data = "DummyData"
with mock.patch.object(
- oracle.DataSourceOracle,
+ oracle_ds,
"_add_network_config_from_opc_imds",
- new=side_effect,
- ):
- was_secondary_added = "secondary_added" in oracle_ds.network_config
- assert expect_secondary_nics == was_secondary_added
+ ) as m_add_network_config_from_opc_imds:
+ oracle_ds.network_config # pylint: disable=pointless-statement
+ assert (
+ expected_set_primary
+ == m_add_network_config_from_opc_imds.call_args_list
+ )
def test_secondary_nic_failure_isnt_blocking(
self,
- m_read_initramfs_config,
+ m_get_interfaces_by_mac,
caplog,
oracle_ds,
):
@@ -917,15 +1060,88 @@ class TestNetworkConfig:
side_effect=Exception(),
):
network_config = oracle_ds.network_config
- assert network_config == m_read_initramfs_config.return_value
- assert "Failed to parse secondary network configuration" in caplog.text
+ assert network_config == oracle_ds._get_iscsi_config.return_value
+ assert 2 == caplog.text.count(
+ "Failed to parse IMDS network configuration"
+ )
- def test_ds_network_cfg_preferred_over_initramfs(self, _m):
+ def test_ds_network_cfg_preferred_over_initramfs(
+ self, m_get_interfaces_by_mac
+ ):
"""Ensure that DS net config is preferred over initramfs config"""
config_sources = oracle.DataSourceOracle.network_config_sources
ds_idx = config_sources.index(NetworkConfigSource.DS)
initramfs_idx = config_sources.index(NetworkConfigSource.INITRAMFS)
assert ds_idx < initramfs_idx
+ @pytest.mark.parametrize("set_primary", [True, False])
+ def test__add_network_config_from_opc_imds_no_vnics_data(
+ self,
+ m_get_interfaces_by_mac,
+ set_primary,
+ oracle_ds,
+ caplog,
+ ):
+ assert not oracle_ds._has_network_config()
+ with mock.patch.object(oracle_ds, "_vnics_data", None):
+ oracle_ds._add_network_config_from_opc_imds(set_primary)
+ assert not oracle_ds._has_network_config()
+ assert (
+ logging.WARNING,
+ "NIC data is UNSET but should not be",
+ ) == caplog.record_tuples[-1][1:]
+
+ def test_missing_mac_skipped(
+ self,
+ m_get_interfaces_by_mac,
+ oracle_ds,
+ caplog,
+ ):
+ """If no intefaces by mac found, then _network_config not setted and
+ correct logs.
+ """
+ vnics_data = json.loads(OPC_VM_SECONDARY_VNIC_RESPONSE)
+ assert not oracle_ds._has_network_config()
+ with mock.patch.object(oracle_ds, "_vnics_data", vnics_data):
+ oracle_ds._add_network_config_from_opc_imds(set_primary=True)
+ assert not oracle_ds._has_network_config()
+ assert (
+ logging.WARNING,
+ "Interface with MAC 02:00:17:05:d1:db not found; skipping",
+ ) == caplog.record_tuples[-2][1:]
+ assert (
+ logging.WARNING,
+ f"Interface with MAC {MAC_ADDR} not found; skipping",
+ ) == caplog.record_tuples[-1][1:]
+
+ @pytest.mark.parametrize("set_primary", [True, False])
+ def test_nics(
+ self,
+ m_get_interfaces_by_mac,
+ set_primary,
+ oracle_ds,
+ caplog,
+ mocker,
+ ):
+ """Correct number of configs added"""
+ vnics_data = json.loads(OPC_VM_SECONDARY_VNIC_RESPONSE)
+ if set_primary:
+ assert not oracle_ds._has_network_config()
+ else:
+ # Simulate primary config was taken from iscsi
+ oracle_ds._network_config = copy.deepcopy(KLIBC_NET_CFG)
+
+ mocker.patch(
+ DS_PATH + ".get_interfaces_by_mac",
+ return_value={"02:00:17:05:d1:db": "eth_0", MAC_ADDR: "name_1"},
+ )
+ mocker.patch.object(oracle_ds, "_vnics_data", vnics_data)
+
+ oracle_ds._add_network_config_from_opc_imds(set_primary)
+ assert 2 == len(
+ oracle_ds._network_config["config"]
+ ), "Config not added"
+ assert "" == caplog.text
+
# vi: ts=4 expandtab
diff --git a/tests/unittests/sources/test_ovf.py b/tests/unittests/sources/test_ovf.py
index c2c87f12..1fbd564f 100644
--- a/tests/unittests/sources/test_ovf.py
+++ b/tests/unittests/sources/test_ovf.py
@@ -13,6 +13,7 @@ from cloudinit import subp, util
from cloudinit.helpers import Paths
from cloudinit.safeyaml import YAMLError
from cloudinit.sources import DataSourceOVF as dsovf
+from cloudinit.sources.DataSourceOVF import GuestCustScriptDisabled
from cloudinit.sources.helpers.vmware.imc.config_custom_script import (
CustomScriptNotFound,
)
@@ -447,7 +448,7 @@ class TestDatasourceOVF(CiTestCase):
with mock.patch(
MPATH + "set_customization_status", return_value=("msg", b"")
):
- with self.assertRaises(RuntimeError) as context:
+ with self.assertRaises(GuestCustScriptDisabled) as context:
wrap_and_call(
"cloudinit.sources.DataSourceOVF",
{
diff --git a/tests/unittests/sources/test_scaleway.py b/tests/unittests/sources/test_scaleway.py
index 52bcbc17..64c785d6 100644
--- a/tests/unittests/sources/test_scaleway.py
+++ b/tests/unittests/sources/test_scaleway.py
@@ -236,7 +236,7 @@ class TestDataSourceScaleway(HttprettyTestCase):
].sort(),
)
self.assertEqual(
- self.datasource.get_hostname(),
+ self.datasource.get_hostname().hostname,
MetadataResponses.FAKE_METADATA["hostname"],
)
self.assertEqual(
diff --git a/tests/unittests/sources/test_smartos.py b/tests/unittests/sources/test_smartos.py
index 55239c4e..702a67f7 100644
--- a/tests/unittests/sources/test_smartos.py
+++ b/tests/unittests/sources/test_smartos.py
@@ -23,8 +23,9 @@ import unittest
import uuid
from binascii import crc32
+import serial
+
from cloudinit import helpers as c_helpers
-from cloudinit import serial
from cloudinit.event import EventScope, EventType
from cloudinit.sources import DataSourceSmartOS
from cloudinit.sources.DataSourceSmartOS import SERIAL_DEVICE, SMARTOS_ENV_KVM
@@ -44,14 +45,6 @@ from tests.unittests.helpers import (
skipIf,
)
-try:
- import serial as _pyserial
-
- assert _pyserial # avoid pyflakes error F401: import unused
- HAS_PYSERIAL = True
-except ImportError:
- HAS_PYSERIAL = False
-
DSMOS = "cloudinit.sources.DataSourceSmartOS"
SDC_NICS = json.loads(
"""
@@ -1357,7 +1350,6 @@ class TestNetworkConversion(CiTestCase):
os.access(SERIAL_DEVICE, os.W_OK),
"Requires write access to " + SERIAL_DEVICE,
)
-@unittest.skipUnless(HAS_PYSERIAL is True, "pyserial not available")
class TestSerialConcurrency(CiTestCase):
"""
This class tests locking on an actual serial port, and as such can only
diff --git a/tests/unittests/sources/test_upcloud.py b/tests/unittests/sources/test_upcloud.py
index e1125b65..317cb638 100644
--- a/tests/unittests/sources/test_upcloud.py
+++ b/tests/unittests/sources/test_upcloud.py
@@ -216,8 +216,8 @@ class TestUpCloudNetworkSetup(CiTestCase):
@mock.patch("cloudinit.sources.helpers.upcloud.read_metadata")
@mock.patch("cloudinit.net.find_fallback_nic")
- @mock.patch("cloudinit.net.dhcp.maybe_perform_dhcp_discovery")
- @mock.patch("cloudinit.net.dhcp.EphemeralIPv4Network")
+ @mock.patch("cloudinit.net.ephemeral.maybe_perform_dhcp_discovery")
+ @mock.patch("cloudinit.net.ephemeral.EphemeralIPv4Network")
def test_network_configured_metadata(
self, m_net, m_dhcp, m_fallback_nic, mock_readmd
):
diff --git a/tests/unittests/sources/test_vmware.py b/tests/unittests/sources/test_vmware.py
index 3579041a..37a1f259 100644
--- a/tests/unittests/sources/test_vmware.py
+++ b/tests/unittests/sources/test_vmware.py
@@ -418,7 +418,9 @@ class TestDataSourceVMwareGuestInfo_InvalidPlatform(FilesystemMockingTestCase):
def assert_metadata(test_obj, ds, metadata):
test_obj.assertEqual(metadata.get("instance-id"), ds.get_instance_id())
- test_obj.assertEqual(metadata.get("local-hostname"), ds.get_hostname())
+ test_obj.assertEqual(
+ metadata.get("local-hostname"), ds.get_hostname().hostname
+ )
expected_public_keys = metadata.get("public_keys")
if not isinstance(expected_public_keys, list):
diff --git a/tests/unittests/sources/test_vultr.py b/tests/unittests/sources/test_vultr.py
index c8398579..5f2ccd4a 100644
--- a/tests/unittests/sources/test_vultr.py
+++ b/tests/unittests/sources/test_vultr.py
@@ -344,9 +344,15 @@ class TestDataSourceVultr(CiTestCase):
return
# Test interface seeking to ensure we are able to find the correct one
- @mock.patch("cloudinit.net.dhcp.EphemeralDHCPv4.__init__", ephemeral_init)
- @mock.patch("cloudinit.net.dhcp.EphemeralDHCPv4.__enter__", override_enter)
- @mock.patch("cloudinit.net.dhcp.EphemeralDHCPv4.__exit__", override_exit)
+ @mock.patch(
+ "cloudinit.net.ephemeral.EphemeralDHCPv4.__init__", ephemeral_init
+ )
+ @mock.patch(
+ "cloudinit.net.ephemeral.EphemeralDHCPv4.__enter__", override_enter
+ )
+ @mock.patch(
+ "cloudinit.net.ephemeral.EphemeralDHCPv4.__exit__", override_exit
+ )
@mock.patch("cloudinit.sources.helpers.vultr.check_route")
@mock.patch("cloudinit.sources.helpers.vultr.is_vultr")
@mock.patch("cloudinit.sources.helpers.vultr.read_metadata")
@@ -377,10 +383,15 @@ class TestDataSourceVultr(CiTestCase):
# Test route checking sucessful DHCPs
@mock.patch("cloudinit.sources.helpers.vultr.check_route", check_route)
@mock.patch(
- "cloudinit.net.dhcp.EphemeralDHCPv4.__init__", ephemeral_init_always
+ "cloudinit.net.ephemeral.EphemeralDHCPv4.__init__",
+ ephemeral_init_always,
+ )
+ @mock.patch(
+ "cloudinit.net.ephemeral.EphemeralDHCPv4.__enter__", override_enter
+ )
+ @mock.patch(
+ "cloudinit.net.ephemeral.EphemeralDHCPv4.__exit__", override_exit
)
- @mock.patch("cloudinit.net.dhcp.EphemeralDHCPv4.__enter__", override_enter)
- @mock.patch("cloudinit.net.dhcp.EphemeralDHCPv4.__exit__", override_exit)
@mock.patch("cloudinit.sources.helpers.vultr.get_interface_list")
@mock.patch("cloudinit.sources.helpers.vultr.is_vultr")
@mock.patch("cloudinit.sources.helpers.vultr.read_metadata")