|
Server : Apache System : Linux server.mata-lashes.com 3.10.0-1160.90.1.el7.x86_64 #1 SMP Thu May 4 15:21:22 UTC 2023 x86_64 User : matalashes ( 1004) PHP Version : 8.1.29 Disable Function : NONE Directory : /usr/src/cloud-init/tests/integration_tests/datasources/ |
Upload File : |
import json
import pytest
from cloudinit import safeyaml
from cloudinit.subp import subp
from cloudinit.util import is_true
from tests.integration_tests.decorators import retry
from tests.integration_tests.instances import IntegrationInstance
from tests.integration_tests.integration_settings import PLATFORM
from tests.integration_tests.releases import CURRENT_RELEASE, JAMMY
from tests.integration_tests.util import (
get_feature_flag_value,
lxd_has_nocloud,
)
USER_DATA = """\
#cloud-config
updates:
network:
when: ["hotplug"]
"""
UPDATED_NETWORK_CONFIG = """\
version: 2
ethernets:
eth0:
dhcp4: true
eth2:
dhcp4: true
"""
@retry()
def ensure_hotplug_exited(client):
assert "cloud-init" not in client.execute("ps -A")
def get_parent_network(instance_name: str):
lxd_network = json.loads(
subp("lxc network list --format json".split()).stdout
)
for net in lxd_network:
if net["type"] == "bridge" and net["managed"]:
if f"/1.0/instances/{instance_name}" in net.get("used_by", []):
return net["name"]
return "lxdbr0"
def _prefer_lxd_datasource_over_nocloud(client: IntegrationInstance):
"""For hotplug support we need LXD datasource detected instead of NoCloud
Bionic and Focal still deliver nocloud-net seed files so override it
with /etc/cloud/cloud.cfg.d/99-detect-lxd-first.cfg
"""
client.write_to_file(
"/etc/cloud/cloud.cfg.d/99-detect-lxd-first.cfg",
"datasource_list: [LXD, NoCloud]\n",
)
client.execute("cloud-init clean --logs")
client.restart()
# TODO: Once LXD adds MACs to the devices endpoint, support LXD VMs here
# Currently the names are too unpredictable to be worth testing on VMs.
@pytest.mark.user_data(USER_DATA)
@pytest.mark.skipif(
PLATFORM != "lxd_container",
reason="Test is LXD specific",
)
class TestLxdHotplug:
@pytest.fixture(autouse=True, scope="class")
def class_teardown(self, class_client: IntegrationInstance):
# We need a teardown here because on IntegrationInstance teardown,
# if KEEP_INSTANCE=True, we grab the instance IP for logging, but
# we're currently running into
# https://github.com/canonical/pycloudlib/issues/220 .
# Once that issue is fixed, we can remove this teardown
yield
name = class_client.instance.name
subp(f"lxc config device remove {name} eth1".split())
subp(f"lxc config device remove {name} eth2".split())
subp("lxc network delete ci-test-br-eth1".split())
subp("lxc network delete ci-test-br-eth2".split())
def test_no_network_change_default(
self, class_client: IntegrationInstance
):
client = class_client
if lxd_has_nocloud(client):
_prefer_lxd_datasource_over_nocloud(client)
assert "eth1" not in client.execute("ip address")
pre_netplan = client.read_from_file("/etc/netplan/50-cloud-init.yaml")
networks = subp("lxc network list".split())
if "ci-test-br-eth1" not in networks.stdout:
subp(
"lxc network create ci-test-br-eth1 --type=bridge "
"ipv4.address=10.10.41.1/24 ipv4.nat=true".split()
)
subp(
f"lxc config device add {client.instance.name} eth1 nic name=eth1 "
f"nictype=bridged parent=ci-test-br-eth1".split()
)
ensure_hotplug_exited(client)
post_netplan = client.read_from_file("/etc/netplan/50-cloud-init.yaml")
assert pre_netplan == post_netplan
ip_info = json.loads(client.execute("ip --json address"))
eth1s = [i for i in ip_info if i["ifname"] == "eth1"]
assert len(eth1s) == 1
assert eth1s[0]["operstate"] == "DOWN"
def test_network_config_applied(self, class_client: IntegrationInstance):
client = class_client
if lxd_has_nocloud(client):
_prefer_lxd_datasource_over_nocloud(client)
assert "eth2" not in client.execute("ip address")
pre_netplan = client.read_from_file("/etc/netplan/50-cloud-init.yaml")
assert "eth2" not in pre_netplan
top_key = "user" if CURRENT_RELEASE < JAMMY else "cloud-init"
assert subp(
[
"lxc",
"config",
"set",
client.instance.name,
f"{top_key}.network-config={UPDATED_NETWORK_CONFIG}",
]
)
assert (
client.read_from_file("/etc/netplan/50-cloud-init.yaml")
== pre_netplan
)
networks = subp("lxc network list".split())
if "ci-test-br-eth2" not in networks.stdout:
assert subp(
"lxc network create ci-test-br-eth2 --type=bridge"
" ipv4.address=10.10.42.1/24 ipv4.nat=true".split()
)
assert subp(
f"lxc config device add {client.instance.name} eth2 nic name=eth2 "
f"nictype=bridged parent=ci-test-br-eth2".split()
)
ensure_hotplug_exited(client)
post_netplan = safeyaml.load(
client.read_from_file("/etc/netplan/50-cloud-init.yaml")
)
expected_netplan = safeyaml.load(UPDATED_NETWORK_CONFIG)
expected_netplan = {"network": expected_netplan}
assert post_netplan == expected_netplan, client.read_from_file(
"/var/log/cloud-init.log"
)
file_perms = class_client.execute(
"stat -c %a /etc/netplan/50-cloud-init.yaml"
)
assert file_perms.ok, "Unable to check perms on 50-cloud-init.yaml"
feature_netplan_root_only = is_true(
get_feature_flag_value(
class_client, "NETPLAN_CONFIG_ROOT_READ_ONLY"
)
)
config_perms = "600" if feature_netplan_root_only else "644"
assert config_perms == file_perms.stdout.strip()
ip_info = json.loads(client.execute("ip --json address"))
eth2s = [i for i in ip_info if i["ifname"] == "eth2"]
assert len(eth2s) == 1
assert eth2s[0]["operstate"] == "UP"