Skip to content
Closed
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
63 changes: 35 additions & 28 deletions cloudinit/sources/DataSourceScaleway.py
Original file line number Diff line number Diff line change
Expand Up @@ -322,12 +322,12 @@ def network_config(self):
if self._network_config != sources.UNSET:
return self._network_config

if self.metadata["private_ip"] is None:
if not self.metadata.get("private_ip"):
# New method of network configuration

netcfg = {}
ip_cfg = {}
for ip in self.metadata["public_ips"]:
for ip in self.metadata.get("public_ips", []):
# Use DHCP for primary address
if ip["address"] == self.ephemeral_fixed_address:
ip_cfg["dhcp4"] = True
Expand All @@ -342,15 +342,16 @@ def network_config(self):
else:
ip_cfg["routes"] = [route]
else:
address_cidr = ip["address"]
if ip.get("netmask"):
address_cidr += f"/{ip['netmask']}"

if "addresses" in ip_cfg.keys():
ip_cfg["addresses"] += (
f'{ip["address"]}/{ip["netmask"]}',
)
ip_cfg["addresses"] += (address_cidr,)
else:
ip_cfg["addresses"] = (
f'{ip["address"]}/{ip["netmask"]}',
)
if ip["family"] == "inet6":
ip_cfg["addresses"] = (address_cidr,)

if ip["family"] == "inet6" and ip.get("gateway"):
route = {"via": ip["gateway"], "to": "::/0"}
if "routes" in ip_cfg.keys():
ip_cfg["routes"] += [route]
Expand All @@ -365,22 +366,26 @@ def network_config(self):
"name": "%s" % self.distro.fallback_interface,
}
subnets = [{"type": "dhcp4"}]
if self.metadata["ipv6"]:
subnets += [
{
"type": "static",
"address": "%s" % self.metadata["ipv6"]["address"],
"netmask": "%s" % self.metadata["ipv6"]["netmask"],
"routes": [
{
"network": "::",
"prefix": "0",
"gateway": "%s"
% self.metadata["ipv6"]["gateway"],
}
],
}
]
ipv6 = self.metadata.get("ipv6")
if (
isinstance(ipv6, dict)
and "address" in ipv6
):
subnet = {
"type": "static",
"address": ipv6.get("address"),
}
if ipv6.get("netmask"):
subnet["netmask"] = ipv6.get("netmask")
if ipv6.get("gateway"):
subnet["routes"] = [
{
"network": "::",
"prefix": "0",
"gateway": ipv6.get("gateway"),
}
]
subnets.append(subnet)
netcfg["subnets"] = subnets
self._network_config = {"version": 1, "config": [netcfg]}
LOG.debug("network_config : %s", self._network_config)
Expand All @@ -391,10 +396,12 @@ def launch_index(self):
return None

def get_instance_id(self):
return self.metadata["id"]
return self.metadata.get("id")

def get_public_ssh_keys(self):
ssh_keys = [key["key"] for key in self.metadata["ssh_public_keys"]]
ssh_keys = [
key["key"] for key in self.metadata.get("ssh_public_keys", [])
]

akeypre = "AUTHORIZED_KEY="
plen = len(akeypre)
Expand All @@ -406,7 +413,7 @@ def get_public_ssh_keys(self):
return ssh_keys

def get_hostname(self, fqdn=False, resolve_ip=False, metadata_only=False):
return DataSourceHostname(self.metadata["hostname"], False)
return DataSourceHostname(self.metadata.get("hostname"), False)

@property
def availability_zone(self):
Expand Down
129 changes: 129 additions & 0 deletions tests/unittests/sources/test_scaleway.py
Original file line number Diff line number Diff line change
Expand Up @@ -741,6 +741,69 @@ def test_legacy_network_config_ipv6_ok(self, m_get_cmdline, fallback_nic):
}
assert netcfg == resp

@mock.patch("cloudinit.distros.net.find_fallback_nic")
@mock.patch("cloudinit.util.get_cmdline")
def test_legacy_network_config_ipv6_missing_key(
self, m_get_cmdline, fallback_nic
):
"""
network_config will include IPv6 config even if gateway is missing
"""
m_get_cmdline.return_value = "scaleway"
fallback_nic.return_value = "ens2"
self.datasource.metadata["private_ip"] = "10.10.10.10"
# Missing 'gateway'
self.datasource.metadata["ipv6"] = {
"address": "2000:abc:4444:9876::42:999",
"netmask": "127",
}

netcfg = self.datasource.network_config
resp = {
"version": 1,
"config": [
{
"type": "physical",
"name": "ens2",
"subnets": [
{"type": "dhcp4"},
{
"type": "static",
"address": "2000:abc:4444:9876::42:999",
"netmask": "127",
},
],
}
],
}
assert netcfg == resp

@mock.patch("cloudinit.distros.net.find_fallback_nic")
@mock.patch("cloudinit.util.get_cmdline")
def test_legacy_network_config_ipv6_empty_dict(
self, m_get_cmdline, fallback_nic
):
"""
network_config will ignore IPv6 config if it is an empty dict
"""
m_get_cmdline.return_value = "scaleway"
fallback_nic.return_value = "ens2"
self.datasource.metadata["private_ip"] = "10.10.10.10"
self.datasource.metadata["ipv6"] = {}

netcfg = self.datasource.network_config
resp = {
"version": 1,
"config": [
{
"type": "physical",
"name": "ens2",
"subnets": [{"type": "dhcp4"}],
}
],
}
assert netcfg == resp

@mock.patch("cloudinit.distros.net.find_fallback_nic")
@mock.patch("cloudinit.util.get_cmdline")
def test_legacy_network_config_existing(self, m_get_cmdline, fallback_nic):
Expand Down Expand Up @@ -848,6 +911,40 @@ def test_ipmob_primary_ipv4_config_ok(self, m_get_cmdline, fallback_nic):

assert netcfg == resp

@mock.patch("cloudinit.distros.net.find_fallback_nic")
@mock.patch("cloudinit.util.get_cmdline")
def test_ipmob_private_ip_unset(self, m_get_cmdline, fallback_nic):
"""
network_config will generate Version 2 config if 'private_ip' is unset
"""
m_get_cmdline.return_value = "scaleway"
fallback_nic.return_value = "ens2"
# Ensure private_ip is completely absent from metadata
if "private_ip" in self.datasource.metadata:
del self.datasource.metadata["private_ip"]
self.datasource.metadata["ipv6"] = None
self.datasource.ephemeral_fixed_address = "10.10.10.10"
self.datasource.metadata["public_ips"] = [{"address": "10.10.10.10"}]

netcfg = self.datasource.network_config
resp = {
"version": 2,
"ethernets": {
fallback_nic.return_value: {
"routes": [
{
"on-link": True,
"to": "169.254.42.42/32",
"via": "62.210.0.1",
}
],
"dhcp4": True,
},
},
}

assert netcfg == resp

@mock.patch("cloudinit.distros.net.find_fallback_nic")
@mock.patch("cloudinit.util.get_cmdline")
def test_ipmob_additional_ipv4_config_ok(
Expand Down Expand Up @@ -1033,3 +1130,35 @@ def test_ipmob_primary_ipv6_v4_config_ok(
}

assert netcfg == resp

@mock.patch("cloudinit.distros.net.find_fallback_nic")
@mock.patch("cloudinit.util.get_cmdline")
def test_ipmob_ipv6_missing_netmask_gateway(
self, m_get_cmdline, fallback_nic
):
"""
Generate network_config with IPv6 missing netmask and gateway
"""
m_get_cmdline.return_value = "scaleway"
fallback_nic.return_value = "ens2"
self.datasource.metadata["private_ip"] = None
self.datasource.metadata["ipv6"] = None
self.datasource.ephemeral_fixed_address = "10.10.10.10"
self.datasource.metadata["public_ips"] = [
{
"address": "2001:aaa:aaaa:a:aaaa:aaaa:aaaa:1",
"family": "inet6",
},
]

netcfg = self.datasource.network_config
resp = {
"version": 2,
"ethernets": {
fallback_nic.return_value: {
"addresses": ("2001:aaa:aaaa:a:aaaa:aaaa:aaaa:1",),
},
},
}

assert netcfg == resp
Loading