Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cloudinit/sources/DataSourceAliYun.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
class DataSourceAliYun(sources.DataSource):

dsname = "AliYun"
metadata_urls = ["http://100.100.100.200"]
metadata_urls = ["http://100.100.100.200", "http://[fd00:100::100:200]"]

# The minimum supported metadata_version from the ecs metadata apis
min_metadata_version = "2016-01-01"
Expand Down
7 changes: 6 additions & 1 deletion cloudinit/sources/helpers/aliyun.py
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,8 @@ def convert_ecs_metadata_network_config(
nic_metadata = macs_metadata.get(mac)
if nic_metadata.get("ipv6s"): # Any IPv6 addresses configured
dev_config["dhcp6"] = True
if not nic_metadata.get("private-ipv4s"): # No IPv4 addresses
dev_config["dhcp4"] = False
netcfg["ethernets"][nic_name] = dev_config
return netcfg
nic_name_2_mac_map = dict()
Expand Down Expand Up @@ -198,13 +200,16 @@ def convert_ecs_metadata_network_config(
if nic_metadata.get("ipv6s"): # Any IPv6 addresses configured
dev_config["dhcp6"] = True
dev_config["dhcp6-overrides"] = dhcp_override
if not nic_metadata.get("private-ipv4s"): # No IPv4 addresses
dev_config["dhcp4"] = False
dev_config.pop("dhcp4-overrides", None)

netcfg["ethernets"][nic_name] = dev_config
# Remove route-metric dhcp overrides and routes / routing-policy if only
# one nic configured
if len(netcfg["ethernets"]) == 1:
for nic_name in netcfg["ethernets"].keys():
netcfg["ethernets"][nic_name].pop("dhcp4-overrides")
netcfg["ethernets"][nic_name].pop("dhcp4-overrides", None)
netcfg["ethernets"][nic_name].pop("dhcp6-overrides", None)
netcfg["ethernets"][nic_name].pop("routes", None)
netcfg["ethernets"][nic_name].pop("routing-policy", None)
Expand Down
81 changes: 81 additions & 0 deletions tests/unittests/sources/test_aliyun.py
Original file line number Diff line number Diff line change
Expand Up @@ -332,11 +332,13 @@ def test_route_metric_calculated_with_multiple_network_cards(self):
"00:16:3e:14:59:58": {
"ipv6-gateway": "2408:xxxxx",
"ipv6s": "[2408:xxxxxx]",
"private-ipv4s": "172.16.101.100",
"network-interface-id": "eni-bp13i1xxxxx",
},
"00:16:3e:39:43:27": {
"gateway": "172.16.101.253",
"netmask": "255.255.255.0",
"private-ipv4s": "172.16.101.200",
"network-interface-id": "eni-bp13i2xxxx",
},
}
Expand Down Expand Up @@ -373,6 +375,7 @@ def test_route_metric_calculated_with_multiple_network_cards(self):
"00:16:3e:14:59:58": {
"gateway": "172.16.101.253",
"netmask": "255.255.255.0",
"private-ipv4s": "172.16.101.100",
"network-interface-id": "eni-bp13ixxxx",
}
}
Expand All @@ -384,6 +387,84 @@ def test_route_metric_calculated_with_multiple_network_cards(self):
# single network card would have no dhcp4-overrides
assert "dhcp4-overrides" not in met0

def test_dhcp4_disabled_when_no_private_ipv4s(self):
"""Test DHCPv4 is disabled when private-ipv4s is absent."""
# Multi-NIC: one NIC has private-ipv4s, other does not
netcfg = convert_ecs_metadata_network_config(
{
"interfaces": {
"macs": {
"00:16:3e:14:59:58": {
"private-ipv4s": "172.16.101.100",
"gateway": "172.16.101.253",
"netmask": "255.255.255.0",
"network-interface-id": "eni-bp13i1xxxxx",
},
"00:16:3e:39:43:27": {
"ipv6s": "[2408:xxxxxx]",
"network-interface-id": "eni-bp13i2xxxx",
},
}
}
},
macs_to_nics={
"00:16:3e:14:59:58": "eth0",
"00:16:3e:39:43:27": "eth1",
},
)

# eth0 has private-ipv4s, dhcp4 should be True
assert netcfg["ethernets"]["eth0"]["dhcp4"] is True
assert "dhcp4-overrides" in netcfg["ethernets"]["eth0"]

# eth1 has no private-ipv4s, dhcp4 should be False
assert netcfg["ethernets"]["eth1"]["dhcp4"] is False
assert "dhcp4-overrides" not in netcfg["ethernets"]["eth1"]
# eth1 has ipv6s, dhcp6 should be True
assert netcfg["ethernets"]["eth1"]["dhcp6"] is True

def test_dhcp6_enabled_when_ipv6s_present(self):
"""Test DHCPv6 is enabled when ipv6s field is present."""
# Single NIC with ipv6s and private-ipv4s
netcfg = convert_ecs_metadata_network_config(
{
"interfaces": {
"macs": {
"00:16:3e:14:59:58": {
"private-ipv4s": "172.16.101.100",
"ipv6s": "[2408:xxxxxx]",
"network-interface-id": "eni-bp13i1xxxxx",
}
}
}
},
macs_to_nics={"00:16:3e:14:59:58": "eth0"},
)

assert netcfg["ethernets"]["eth0"]["dhcp4"] is True
assert netcfg["ethernets"]["eth0"]["dhcp6"] is True

def test_ipv6_only_nic_config(self):
"""Test a NIC with only IPv6 (no private-ipv4s)."""
netcfg = convert_ecs_metadata_network_config(
{
"interfaces": {
"macs": {
"00:16:3e:14:59:58": {
"ipv6s": "[2408:xxxxxx]",
"network-interface-id": "eni-bp13i1xxxxx",
}
}
}
},
macs_to_nics={"00:16:3e:14:59:58": "eth0"},
)

# No private-ipv4s: dhcp4 disabled
assert netcfg["ethernets"]["eth0"]["dhcp4"] is False
# Has ipv6s: dhcp6 enabled
assert netcfg["ethernets"]["eth0"]["dhcp6"] is True


class TestIsAliYun:
ALIYUN_PRODUCT = "Alibaba Cloud ECS"
Expand Down