diff --git a/zaza/openstack/charm_tests/neutron/setup.py b/zaza/openstack/charm_tests/neutron/setup.py index f81590dfe..2210e1192 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", } # For Neutron Dynamic Tests it is useful to avoid relying on the directly @@ -116,6 +117,9 @@ 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": + 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 fa33771bb..515aa0a21 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 cc0a2ae38..46e8ee738 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 @@ -1169,6 +1170,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):