From 1b1c9d3cc6e1f38b13dc2da4350d8d9e466ffbba Mon Sep 17 00:00:00 2001 From: Nurmatov Mamatisa Date: Mon, 27 Dec 2021 15:37:03 +0300 Subject: [PATCH] Add local ip scenario tests With Local IP static_nat set to True (for work with ovs firewall) - back ICMP traffic from VM with Local IP assigned will have source IP substituted with local IP. To overcome this new parameter was added to check_remote_connectivity - check_responce_ip Depends-On: https://review.opendev.org/c/openstack/neutron/+/818228 Depends-On: https://review.opendev.org/c/openstack/neutron/+/824363 Change-Id: I85b4c07a623443e3fd856b9218024773125f20eb --- neutron_tempest_plugin/scenario/base.py | 13 ++- .../scenario/test_local_ip.py | 103 ++++++++++++++++++ zuul.d/master_jobs.yaml | 10 +- 3 files changed, 120 insertions(+), 6 deletions(-) create mode 100644 neutron_tempest_plugin/scenario/test_local_ip.py diff --git a/neutron_tempest_plugin/scenario/base.py b/neutron_tempest_plugin/scenario/base.py index 8591c893..a1a054a3 100644 --- a/neutron_tempest_plugin/scenario/base.py +++ b/neutron_tempest_plugin/scenario/base.py @@ -367,7 +367,8 @@ class BaseTempestTestCase(base_api.BaseNetworkTest): should_succeed=True, nic=None, mtu=None, fragmentation=True, timeout=None, pattern=None, - forbid_packet_loss=False): + forbid_packet_loss=False, + check_response_ip=True): """check ping server via source ssh connection :param source: RemoteClient: an ssh connection from which to ping @@ -380,6 +381,7 @@ class BaseTempestTestCase(base_api.BaseNetworkTest): :param timeout: Timeout for all ping packet(s) to succeed :param pattern: hex digits included in ICMP messages :param forbid_packet_loss: forbid or allow some lost packets + :param check_response_ip: check response ip :returns: boolean -- should_succeed == ping :returns: ping is false if ping failed """ @@ -422,7 +424,8 @@ class BaseTempestTestCase(base_api.BaseNetworkTest): LOG.debug('Packet loss detected') return not should_succeed - if validators.validate_ip_address(dest) is None: + if (check_response_ip and + validators.validate_ip_address(dest) is None): # Assert that the return traffic was from the correct # source address. from_source = 'from %s' % dest @@ -436,13 +439,15 @@ class BaseTempestTestCase(base_api.BaseNetworkTest): nic=None, mtu=None, fragmentation=True, servers=None, timeout=None, ping_count=CONF.validation.ping_count, - pattern=None, forbid_packet_loss=False): + pattern=None, forbid_packet_loss=False, + check_response_ip=True): try: self.assertTrue(self._check_remote_connectivity( source, dest, ping_count, should_succeed, nic, mtu, fragmentation, timeout=timeout, pattern=pattern, - forbid_packet_loss=forbid_packet_loss)) + forbid_packet_loss=forbid_packet_loss, + check_response_ip=check_response_ip)) except (lib_exc.SSHTimeout, ssh_exc.AuthenticationException) as ssh_e: LOG.debug(ssh_e) self._log_console_output(servers) diff --git a/neutron_tempest_plugin/scenario/test_local_ip.py b/neutron_tempest_plugin/scenario/test_local_ip.py new file mode 100644 index 00000000..0cc9de1e --- /dev/null +++ b/neutron_tempest_plugin/scenario/test_local_ip.py @@ -0,0 +1,103 @@ +# Copyright 2021 Huawei, Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. +# + +from oslo_log import log as logging +from tempest.common import utils +from tempest.common import waiters +from tempest.lib.common.utils import data_utils +from tempest.lib import decorators + +from neutron_tempest_plugin.common import ssh +from neutron_tempest_plugin import config +from neutron_tempest_plugin.scenario import base +from neutron_tempest_plugin.scenario import constants as const + +LOG = logging.getLogger(__name__) +CONF = config.CONF + + +class LocalIPTest(base.BaseTempestTestCase): + credentials = ['primary', 'admin'] + + @classmethod + @utils.requires_ext(extension="local_ip", service="network") + def resource_setup(cls): + super(LocalIPTest, cls).resource_setup() + cls.network = cls.create_network() + cls.subnet = cls.create_subnet(cls.network) + cls.keypair = cls.create_keypair() + + # Create security group with admin privileges + cls.secgroup = cls.create_security_group( + name=data_utils.rand_name('secgroup')) + + # Execute funcs to achieve ssh and ICMP capabilities + cls.create_loginable_secgroup_rule(secgroup_id=cls.secgroup['id']) + cls.create_pingable_secgroup_rule(secgroup_id=cls.secgroup['id']) + + # Create router + cls.router = cls.create_router( + router_name=data_utils.rand_name("router-test"), + admin_state_up=True, + external_network_id=CONF.network.public_network_id) + cls.create_router_interface(cls.router['id'], cls.subnet['id']) + + def _create_server(self, name=None): + port = self.create_port( + self.network, security_groups=[self.secgroup['id']]) + server = self.create_server( + flavor_ref=CONF.compute.flavor_ref, + image_ref=CONF.compute.image_ref, + key_name=self.keypair['name'], name=name, + networks=[{'port': port['id']}])['server'] + waiters.wait_for_server_status(self.os_primary.servers_client, + server['id'], + const.SERVER_STATUS_ACTIVE) + + return {'port': port, 'server': server} + + @decorators.idempotent_id('3aa4b288-011a-4aa2-9024-19ad2ce40bfd') + def test_local_ip_connectivity(self): + server1 = self._create_server(name='local_ip_vm1') + server2 = self._create_server(name='local_ip_vm2') + + fip = self.create_and_associate_floatingip(server1['port']['id']) + ssh_client = ssh.Client( + fip['floating_ip_address'], + CONF.validation.image_ssh_user, + pkey=self.keypair['private_key']) + + servers = [server1['server'], server2['server']] + + # first check basic connectivity + self.check_remote_connectivity( + ssh_client, + server2['port']['fixed_ips'][0]['ip_address'], + servers=servers) + + local_ip = self.create_local_ip(network_id=self.network['id']) + self.create_local_ip_association(local_ip['id'], + fixed_port_id=server2['port']['id']) + # check connectivity with local ip address + self.check_remote_connectivity( + ssh_client, local_ip['local_ip_address'], + servers=servers, check_response_ip=False) + + # check basic connectivity after local ip association + self.check_remote_connectivity( + ssh_client, + server2['port']['fixed_ips'][0]['ip_address'], + servers=servers, + check_response_ip=False) diff --git a/zuul.d/master_jobs.yaml b/zuul.d/master_jobs.yaml index b1676894..6cddf0e5 100644 --- a/zuul.d/master_jobs.yaml +++ b/zuul.d/master_jobs.yaml @@ -139,18 +139,21 @@ ovsdb-server: false q-ovn-metadata-agent: false # Neutron services + neutron-local-ip-static: true q-agt: true q-dhcp: true q-l3: true q-meta: true q-metering: true network_api_extensions: *api_extensions + network_api_extensions_openvswitch: + - local_ip network_available_features: *available_features devstack_localrc: Q_AGENT: openvswitch Q_ML2_TENANT_NETWORK_TYPE: vxlan Q_ML2_PLUGIN_MECHANISM_DRIVERS: openvswitch - NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}" + NETWORK_API_EXTENSIONS: "{{ (network_api_extensions + network_api_extensions_openvswitch) | join(',') }}" devstack_local_conf: post-config: $NEUTRON_CONF: @@ -205,12 +208,15 @@ ovsdb-server: false q-ovn-metadata-agent: false # Neutron services + neutron-local-ip: true q-agt: true q-dhcp: true q-l3: true q-meta: true q-metering: true network_api_extensions: *api_extensions + network_api_extensions_openvswitch: + - local_ip network_available_features: *available_features # TODO(slaweq): remove trunks subport_connectivity test from blacklist # when bug https://bugs.launchpad.net/neutron/+bug/1838760 will be fixed @@ -223,7 +229,7 @@ Q_AGENT: openvswitch Q_ML2_TENANT_NETWORK_TYPE: vxlan Q_ML2_PLUGIN_MECHANISM_DRIVERS: openvswitch - NETWORK_API_EXTENSIONS: "{{ network_api_extensions | join(',') }}" + NETWORK_API_EXTENSIONS: "{{ (network_api_extensions + network_api_extensions_openvswitch) | join(',') }}" devstack_local_conf: post-config: $NEUTRON_CONF: