From e4d3be55e31d803e0ee960f54c1c1540c8b9fe70 Mon Sep 17 00:00:00 2001 From: Frode Nordahl Date: Fri, 11 Oct 2024 22:52:18 +0200 Subject: [PATCH] undercloud_and_charm_setup: Add support for LXD. This adds basic LXD support that allows adding second NIC to instances hosting networking charms as well as populating said charms configuration with the second NIC MAC address. Signed-off-by: Frode Nordahl (cherry picked from commit a5ad00acf1b54d0461f6a288484e69b4d890a91c) Signed-off-by: Martin Kalcok --- zaza/openstack/charm_tests/neutron/setup.py | 7 +++ zaza/openstack/utilities/generic.py | 4 +- zaza/openstack/utilities/openstack.py | 65 +++++++++++++++++++++ 3 files changed, 75 insertions(+), 1 deletion(-) diff --git a/zaza/openstack/charm_tests/neutron/setup.py b/zaza/openstack/charm_tests/neutron/setup.py index 1402c8fef..20e969b61 100644 --- a/zaza/openstack/charm_tests/neutron/setup.py +++ b/zaza/openstack/charm_tests/neutron/setup.py @@ -66,6 +66,7 @@ "external_dns": "10.5.0.2", "external_net_cidr": "10.5.0.0/16", "default_gateway": "10.5.0.1", + "lxd_network_name": "second", } @@ -105,6 +106,12 @@ def undercloud_and_charm_setup(limit_gws=None): # Perform charm based OVS configuration openstack_utils.configure_charmed_openstack_on_maas( network_config, limit_gws=limit_gws) + elif provider_type == "lxd" or provider_type is None: + # NOTE(fnordahl): When juju is bootstrapped towards the special + # `localhost` LXD cloud, get_provider_type() has no `clouds.yaml` to + # inspect and returns None. + openstack_utils.configure_charmed_openstack_on_lxd( + network_config, limit_gws=limit_gws) else: logging.warning('Unknown Juju provider type, "{}", will not perform' ' charm network configuration.' diff --git a/zaza/openstack/utilities/generic.py b/zaza/openstack/utilities/generic.py index 126ef824d..cc3d19458 100644 --- a/zaza/openstack/utilities/generic.py +++ b/zaza/openstack/utilities/generic.py @@ -190,6 +190,7 @@ def get_undercloud_env_vars(): _vars['external_dns'] = os.environ.get('TEST_NAME_SERVER') _vars['default_gateway'] = os.environ.get('TEST_GATEWAY') _vars['external_net_cidr'] = os.environ.get('TEST_CIDR_EXT') + _vars['lxd_network_name'] = os.environ.get('TEST_LXD_NETWORK_NAME') # Take FIP_RANGE and create start and end floating ips _fip_range = os.environ.get('TEST_FIP_RANGE') @@ -205,7 +206,8 @@ def get_undercloud_env_vars(): 'start_floating_ip', 'end_floating_ip', 'external_dns', - 'external_net_cidr'] + 'external_net_cidr', + 'lxd_network_name'] for _key in _keys: _val = os.environ.get(_key) if _val: diff --git a/zaza/openstack/utilities/openstack.py b/zaza/openstack/utilities/openstack.py index 65bfdbb99..791dc151f 100644 --- a/zaza/openstack/utilities/openstack.py +++ b/zaza/openstack/utilities/openstack.py @@ -25,6 +25,7 @@ import json import juju_wait import logging +import netaddr import os import paramiko import pathlib @@ -1104,6 +1105,70 @@ def configure_charmed_openstack_on_maas(network_config, limit_gws=None): networking_data, macs, use_juju_wait=False) +def lxd_maybe_add_nic(instance, ifname, network): + """Add NIC to instance. + + :param instance: Name of instance. + :type instance: str + :param ifname: Name of interface inside instance, note that name is only + preserved in containers, interfaces in virtual machines are + subject to udev rules inside the instance. + :type: ifname: str + :param network: Name of network. + :type network: str + """ + try: + subprocess.check_call([ + "lxc", "config", "device", "add", instance, + ifname, "nic", "name={}".format(ifname), + "network={}".format(network)]) + except subprocess.CalledProcessError: + logging.info("Unable to add device {} to {}, already added?" + .format(ifname, instance)) + + +def lxd_get_nic_hwaddr(instance, device_name): + """Add NIC to instance. + + :param instance: Name of instance. + :type instance: str + :param device_name: Name of device config. + :type device_name: str + :rtype: netaddr.EUI + :raises: netaddr.core.AddrFormatError in the event nic does not exist. + """ + # lxc config get succeeds even for non-existing keys. + output = subprocess.check_output([ + "lxc", "config", "get", instance, + "volatile.{}.hwaddr".format(device_name)], + universal_newlines=True) + + mac = netaddr.EUI(output) + mac.dialect = netaddr.mac_unix_expanded + return mac + + +def configure_charmed_openstack_on_lxd(network_config, limit_gws=None): + """Configure networking charms for charm-based OVS config on LXD provider. + + :param network_config: Network configuration as provided in environment. + :type network_config: Dict[str] + :param limit_gws: Limit the number of gateways that get a port attached + :type limit_gws: Optional[int] + """ + networking_data = get_charm_networking_data(limit_gws=limit_gws) + ifname = "eth1" + macs = [] + for instance in networking_data.unit_machine_ids: + lxd_maybe_add_nic(instance, ifname, + network_config.get("lxd_network_name")) + macs.append(str(lxd_get_nic_hwaddr(instance, ifname))) + + if macs: + configure_networking_charms( + networking_data, macs, use_juju_wait=False) + + @tenacity.retry(wait=tenacity.wait_exponential(multiplier=1, max=60), reraise=True, retry=tenacity.retry_if_exception_type(KeyError)) def get_mac_from_port(port, neutronclient):