Skip to content

Commit

Permalink
azure: add option to enable/disable secondary ip config (#4432)
Browse files Browse the repository at this point in the history
Currently cloud-init attempts to configure all IP addresses for all
interfaces whose configurations are available in IMDS. 

To allow users more control over VM network configuration, add an option
for cloud-init to enable/disable configuration of secondary IP
addresses.

This PR also introduces the datasource option
apply_network_config_for_secondary_ips for DataSourceAzure,
which leverages the new network config above.
Default is set to True to maintain compatibility.
  • Loading branch information
KsenijaS authored Sep 26, 2023
1 parent 226ba25 commit dfe6170
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 5 deletions.
3 changes: 2 additions & 1 deletion cloudinit/cmd/devel/net_convert.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,8 @@ def handle_args(name, args):
)
elif args.kind == "azure-imds":
pre_ns = azure.generate_network_config_from_instance_network_metadata(
json.loads(net_data)["network"]
json.loads(net_data)["network"],
apply_network_config_for_secondary_ips=True,
)
elif args.kind == "vmware-imc":
config = guestcust_util.Config(
Expand Down
12 changes: 11 additions & 1 deletion cloudinit/sources/DataSourceAzure.py
Original file line number Diff line number Diff line change
Expand Up @@ -286,6 +286,7 @@ def get_resource_disk_on_freebsd(port_id) -> Optional[str]:
"data_dir": AGENT_SEED_DIR,
"disk_aliases": {"ephemeral0": RESOURCE_DISK_PATH},
"apply_network_config": True, # Use IMDS published network configuration
"apply_network_config_for_secondary_ips": True, # Configure secondary ips
}

BUILTIN_CLOUD_EPHEMERAL_DISK_CONFIG = {
Expand Down Expand Up @@ -1413,7 +1414,10 @@ def _generate_network_config(self):
):
try:
return generate_network_config_from_instance_network_metadata(
self._metadata_imds["network"]
self._metadata_imds["network"],
apply_network_config_for_secondary_ips=self.ds_cfg.get(
"apply_network_config_for_secondary_ips"
),
)
except Exception as e:
LOG.error(
Expand Down Expand Up @@ -1863,6 +1867,8 @@ def load_azure_ds_dir(source_dir):
@azure_ds_telemetry_reporter
def generate_network_config_from_instance_network_metadata(
network_metadata: dict,
*,
apply_network_config_for_secondary_ips: bool,
) -> dict:
"""Convert imds network metadata dictionary to network v2 configuration.
Expand Down Expand Up @@ -1901,6 +1907,10 @@ def generate_network_config_from_instance_network_metadata(
# route-metric (cost) so default routes prefer
# primary nic due to lower route-metric value
dev_config["dhcp6-overrides"] = dhcp_override

if not apply_network_config_for_secondary_ips:
continue

for addr in addresses[1:]:
# Append static address config for ip > 1
netPrefix = intf[addr_type]["subnet"][0].get(
Expand Down
5 changes: 5 additions & 0 deletions doc/rtd/reference/datasources/azure.rst
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ The settings that may be configured are:
Boolean set to True to use network configuration described by Azure's IMDS
endpoint instead of fallback network config of DHCP on eth0. Default is
True.
* :command:`apply_network_config_for_secondary_ips`

Boolean to configure secondary IP address(es) for each NIC per IMDS
configuration. Default is True.
* :command:`data_dir`

Path used to read metadata files and write crawled data.
Expand All @@ -62,6 +66,7 @@ An example configuration with the default values is provided below:
datasource:
Azure:
apply_network_config: true
apply_network_config_for_secondary_ips: true
data_dir: /var/lib/waagent
disk_aliases:
ephemeral0: /dev/disk/cloud/azure_resource
Expand Down
103 changes: 100 additions & 3 deletions tests/unittests/sources/test_azure.py
Original file line number Diff line number Diff line change
Expand Up @@ -520,11 +520,12 @@ def construct_ovf_env(

class TestGenerateNetworkConfig:
@pytest.mark.parametrize(
"label,metadata,expected",
"label,metadata,ip_config,expected",
[
(
"simple interface",
NETWORK_METADATA["network"],
True,
{
"ethernets": {
"eth0": {
Expand Down Expand Up @@ -559,6 +560,7 @@ class TestGenerateNetworkConfig:
}
]
},
True,
{
"ethernets": {
"eth0": {
Expand Down Expand Up @@ -596,6 +598,7 @@ class TestGenerateNetworkConfig:
}
]
},
True,
{
"ethernets": {
"eth0": {
Expand Down Expand Up @@ -633,6 +636,7 @@ class TestGenerateNetworkConfig:
}
]
},
True,
{
"ethernets": {
"eth0": {
Expand Down Expand Up @@ -670,6 +674,7 @@ class TestGenerateNetworkConfig:
]
* 3
},
True,
{
"ethernets": {
"eth0": {
Expand Down Expand Up @@ -736,6 +741,7 @@ class TestGenerateNetworkConfig:
}
]
},
True,
{
"ethernets": {
"eth0": {
Expand All @@ -751,6 +757,60 @@ class TestGenerateNetworkConfig:
"version": 2,
},
),
(
"secondary IPv4s are not configured",
{
"interface": [
{
"macAddress": "000D3A047598",
"ipv6": {
"subnet": [
{
"prefix": "10",
"address": "2001:dead:beef::16",
}
],
"ipAddress": [
{"privateIpAddress": "2001:dead:beef::1"}
],
},
"ipv4": {
"subnet": [
{"prefix": "24", "address": "10.0.0.0"},
],
"ipAddress": [
{
"privateIpAddress": "10.0.0.4",
"publicIpAddress": "104.46.124.81",
},
{
"privateIpAddress": "11.0.0.5",
"publicIpAddress": "104.46.124.82",
},
{
"privateIpAddress": "12.0.0.6",
"publicIpAddress": "104.46.124.83",
},
],
},
}
]
},
False,
{
"ethernets": {
"eth0": {
"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",
}
},
"version": 2,
},
),
(
"ipv6 secondaries",
{
Expand All @@ -772,6 +832,7 @@ class TestGenerateNetworkConfig:
}
]
},
True,
{
"ethernets": {
"eth0": {
Expand All @@ -787,14 +848,50 @@ class TestGenerateNetworkConfig:
"version": 2,
},
),
(
"ipv6 secondaries not configured",
{
"interface": [
{
"macAddress": "000D3A047598",
"ipv6": {
"subnet": [
{
"prefix": "10",
"address": "2001:dead:beef::16",
}
],
"ipAddress": [
{"privateIpAddress": "2001:dead:beef::1"},
{"privateIpAddress": "2001:dead:beef::2"},
],
},
}
]
},
False,
{
"ethernets": {
"eth0": {
"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",
}
},
"version": 2,
},
),
],
)
def test_parsing_scenarios(
self, label, mock_get_interfaces, metadata, expected
self, label, mock_get_interfaces, metadata, ip_config, expected
):
assert (
dsaz.generate_network_config_from_instance_network_metadata(
metadata
metadata, apply_network_config_for_secondary_ips=ip_config
)
== expected
)
Expand Down

0 comments on commit dfe6170

Please sign in to comment.