From 6c834770edaa19a2754c79dcee5652fca1b9534e Mon Sep 17 00:00:00 2001 From: coreycb Date: Fri, 8 Oct 2021 10:05:36 -0400 Subject: [PATCH] Add neutron setup for VLAN provider network (#639) This adds a new setup function that will setup a VLAN provider network. It can be called by tests.yaml after basic_overcloud_network: - zaza.openstack.charm_tests.neutron.setup.basic_overcloud_network - zaza.openstack.charm_tests.neutron.setup.vlan_provider_overcloud_network --- .../test_zaza_utilities_openstack.py | 17 ++--- zaza/openstack/charm_tests/neutron/setup.py | 30 ++++++++- zaza/openstack/configure/network.py | 63 +++++++++++++++++-- zaza/openstack/utilities/openstack.py | 43 ++++++++----- 4 files changed, 126 insertions(+), 27 deletions(-) diff --git a/unit_tests/utilities/test_zaza_utilities_openstack.py b/unit_tests/utilities/test_zaza_utilities_openstack.py index 2dd3fcd..472b35b 100644 --- a/unit_tests/utilities/test_zaza_utilities_openstack.py +++ b/unit_tests/utilities/test_zaza_utilities_openstack.py @@ -58,11 +58,12 @@ class TestOpenStackUtils(ut_utils.BaseTestCase): self.network = { "network": {"id": "network_id", - "name": self.ext_net, - "tenant_id": self.project_id, - "router:external": True, - "provider:physical_network": "physnet1", - "provider:network_type": "flat"}} + "name": self.ext_net, + "router:external": True, + "shared": False, + "tenant_id": self.project_id, + "provider:physical_network": "physnet1", + "provider:network_type": "flat"}} self.networks = { "networks": [self.network["network"]]} @@ -157,12 +158,12 @@ class TestOpenStackUtils(ut_utils.BaseTestCase): self.neutronclient.create_address_scope.assert_called_once_with( address_scope_msg) - def test_create_external_network(self): + def test_create_provider_network(self): self.patch_object(openstack_utils, "get_net_uuid") self.get_net_uuid.return_value = self.net_uuid # Already exists - network = openstack_utils.create_external_network( + network = openstack_utils.create_provider_network( self.neutronclient, self.project_id) self.assertEqual(network, self.network["network"]) self.neutronclient.create_network.assert_not_called() @@ -172,7 +173,7 @@ class TestOpenStackUtils(ut_utils.BaseTestCase): "networks": []} network_msg = copy.deepcopy(self.network) network_msg["network"].pop("id") - network = openstack_utils.create_external_network( + network = openstack_utils.create_provider_network( self.neutronclient, self.project_id) self.assertEqual(network, self.network["network"]) self.neutronclient.create_network.assert_called_once_with( diff --git a/zaza/openstack/charm_tests/neutron/setup.py b/zaza/openstack/charm_tests/neutron/setup.py index 11a01bc..174c51d 100644 --- a/zaza/openstack/charm_tests/neutron/setup.py +++ b/zaza/openstack/charm_tests/neutron/setup.py @@ -44,6 +44,13 @@ OVERCLOUD_NETWORK_CONFIG = { "subnetpool_prefix": "192.168.0.0/16", } +OVERCLOUD_PROVIDER_VLAN_NETWORK_CONFIG = { + "provider_vlan_net_name": "provider_vlan", + "provider_vlan_subnet_name": "provider_vlan_subnet", + "provider_vlan_cidr": "10.42.33.0/24", + "provider_vlan_id": "2933", +} + # The undercloud network configuration settings are substrate specific to # the environment where the tests are being executed. These settings may be # overridden by environment variables. See the doc string documentation for @@ -110,10 +117,31 @@ def basic_overcloud_network(limit_gws=None): ' charm network configuration.' .format(provider_type)) - # Confugre the overcloud network + # Configure the overcloud network network.setup_sdn(network_config, keystone_session=keystone_session) +def vlan_provider_overcloud_network(): + """Run setup to create a VLAN provider network.""" + cli_utils.setup_logging() + + # Get network configuration settings + network_config = {} + # Declared overcloud settings + network_config.update(OVERCLOUD_NETWORK_CONFIG) + # Declared provider vlan overcloud settings + network_config.update(OVERCLOUD_PROVIDER_VLAN_NETWORK_CONFIG) + # Environment specific settings + network_config.update(generic_utils.get_undercloud_env_vars()) + + # Get keystone session + keystone_session = openstack_utils.get_overcloud_keystone_session() + + # Configure the overcloud network + network.setup_sdn_provider_vlan(network_config, + keystone_session=keystone_session) + + # Configure function to get one gateway with external network overcloud_network_one_gw = functools.partial( basic_overcloud_network, diff --git a/zaza/openstack/configure/network.py b/zaza/openstack/configure/network.py index ad1a07b..5d3a2f8 100755 --- a/zaza/openstack/configure/network.py +++ b/zaza/openstack/configure/network.py @@ -126,19 +126,19 @@ def setup_sdn(network_config, keystone_session=None): logging.info("Configuring overcloud network") # Create the external network - ext_network = openstack_utils.create_external_network( + ext_network = openstack_utils.create_provider_network( neutron_client, project_id, network_config["external_net_name"]) - openstack_utils.create_external_subnet( + openstack_utils.create_provider_subnet( neutron_client, project_id, ext_network, + network_config["external_subnet_name"], network_config["default_gateway"], network_config["external_net_cidr"], network_config["start_floating_ip"], - network_config["end_floating_ip"], - network_config["external_subnet_name"]) + network_config["end_floating_ip"]) provider_router = ( openstack_utils.create_provider_router(neutron_client, project_id)) openstack_utils.plug_extnet_into_router( @@ -183,6 +183,61 @@ def setup_sdn(network_config, keystone_session=None): openstack_utils.add_neutron_secgroup_rules(neutron_client, project_id) +def setup_sdn_provider_vlan(network_config, keystone_session=None): + """Perform setup for Software Defined Network, specifically a provider VLAN. + + :param network_config: Network configuration settings dictionary + :type network_config: dict + :param keystone_session: Keystone session object for overcloud + :type keystone_session: keystoneauth1.session.Session object + :returns: None + :rtype: None + """ + # If a session has not been provided, acquire one + if not keystone_session: + keystone_session = openstack_utils.get_overcloud_keystone_session() + + # Get authenticated clients + keystone_client = openstack_utils.get_keystone_session_client( + keystone_session) + neutron_client = openstack_utils.get_neutron_session_client( + keystone_session) + + admin_domain = None + if openstack_utils.get_keystone_api_version() > 2: + admin_domain = "admin_domain" + # Resolve the project name from the overcloud openrc into a project id + project_id = openstack_utils.get_project_id( + keystone_client, + "admin", + domain_name=admin_domain, + ) + + logging.info("Configuring VLAN provider network") + # Create the external network + provider_vlan_network = openstack_utils.create_provider_network( + neutron_client, + project_id, + net_name=network_config["provider_vlan_net_name"], + external=False, + shared=True, + network_type='vlan', + vlan_id=network_config["provider_vlan_id"]) + provider_vlan_subnet = openstack_utils.create_provider_subnet( + neutron_client, + project_id, + provider_vlan_network, + network_config["provider_vlan_subnet_name"], + cidr=network_config["provider_vlan_cidr"], + dhcp=True) + openstack_utils.plug_subnet_into_router( + neutron_client, + network_config["router_name"], + provider_vlan_network, + provider_vlan_subnet) + openstack_utils.add_neutron_secgroup_rules(neutron_client, project_id) + + def setup_gateway_ext_port(network_config, keystone_session=None, limit_gws=None, use_juju_wait=True): diff --git a/zaza/openstack/utilities/openstack.py b/zaza/openstack/utilities/openstack.py index ce57157..2f19905 100644 --- a/zaza/openstack/utilities/openstack.py +++ b/zaza/openstack/utilities/openstack.py @@ -1139,8 +1139,10 @@ def create_project_network(neutron_client, project_id, net_name='private', return network -def create_external_network(neutron_client, project_id, net_name='ext_net'): - """Create the external network. +def create_provider_network(neutron_client, project_id, net_name='ext_net', + external=True, shared=False, network_type='flat', + vlan_id=None): + """Create a provider network. :param neutron_client: Authenticated neutronclient :type neutron_client: neutronclient.Client object @@ -1148,25 +1150,35 @@ def create_external_network(neutron_client, project_id, net_name='ext_net'): :type project_id: string :param net_name: Network name :type net_name: string + :param shared: The network should be external + :type shared: boolean + :param shared: The network should be shared between projects + :type shared: boolean + :param net_type: Network type: GRE, VXLAN, local, VLAN + :type net_type: string + :param net_name: VLAN ID + :type net_name: string :returns: Network object :rtype: dict """ networks = neutron_client.list_networks(name=net_name) if len(networks['networks']) == 0: - logging.info('Configuring external network') + logging.info('Creating %s %s network: %s', network_type, + 'external' if external else 'provider', net_name) network_msg = { 'name': net_name, - 'router:external': True, + 'router:external': external, + 'shared': shared, 'tenant_id': project_id, 'provider:physical_network': 'physnet1', - 'provider:network_type': 'flat', + 'provider:network_type': network_type, } - logging.info('Creating new external network definition: %s', - net_name) + if network_type == 'vlan': + network_msg['provider:segmentation_id'] = int(vlan_id) network = neutron_client.create_network( {'network': network_msg})['network'] - logging.info('New external network created: %s', network['id']) + logging.info('Network %s created: %s', net_name, network['id']) else: logging.warning('Network %s already exists.', net_name) network = networks['networks'][0] @@ -1226,11 +1238,12 @@ def create_project_subnet(neutron_client, project_id, network, cidr, dhcp=True, return subnet -def create_external_subnet(neutron_client, project_id, network, +def create_provider_subnet(neutron_client, project_id, network, + subnet_name='ext_net_subnet', default_gateway=None, cidr=None, start_floating_ip=None, end_floating_ip=None, - subnet_name='ext_net_subnet'): - """Create the external subnet. + dhcp=False): + """Create the provider subnet. :param neutron_client: Authenticated neutronclient :type neutron_client: neutronclient.Client object @@ -1240,14 +1253,16 @@ def create_external_subnet(neutron_client, project_id, network, :type network: dict :param default_gateway: Deafault gateway IP address :type default_gateway: string + :param subnet_name: Subnet name + :type subnet_name: string :param cidr: Network CIDR :type cidr: string :param start_floating_ip: Start of floating IP range: IP address :type start_floating_ip: string or None :param end_floating_ip: End of floating IP range: IP address :type end_floating_ip: string or None - :param subnet_name: Subnet name - :type subnet_name: string + :param dhcp: Run DHCP on this subnet + :type dhcp: boolean :returns: Subnet object :rtype: dict """ @@ -1256,7 +1271,7 @@ def create_external_subnet(neutron_client, project_id, network, subnet_msg = { 'name': subnet_name, 'network_id': network['id'], - 'enable_dhcp': False, + 'enable_dhcp': dhcp, 'ip_version': 4, 'tenant_id': project_id }