Merge "Tap Mirror API and scenario tests"
This commit is contained in:
218
neutron_tempest_plugin/tap_as_a_service/api/test_tap_mirror.py
Normal file
218
neutron_tempest_plugin/tap_as_a_service/api/test_tap_mirror.py
Normal file
@@ -0,0 +1,218 @@
|
||||
# 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_utils import uuidutils
|
||||
|
||||
from tempest.common import utils
|
||||
from tempest.lib import decorators
|
||||
from tempest.lib import exceptions as lib_exc
|
||||
|
||||
from neutron_tempest_plugin.tap_as_a_service import base
|
||||
|
||||
|
||||
class TapMirrorTestJSON(base.BaseTaasTest):
|
||||
|
||||
@classmethod
|
||||
@utils.requires_ext(extension='tap-mirror', service='network')
|
||||
def skip_checks(cls):
|
||||
super().skip_checks()
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super().resource_setup()
|
||||
cls.network = cls.create_network()
|
||||
cls.tap_mirror_port = cls.create_port(cls.network)
|
||||
cls.in_direction = {'IN': 101}
|
||||
cls.out_direction = {'OUT': 102}
|
||||
cls.both_direction = cls.in_direction | cls.out_direction
|
||||
cls.remote_ip = '192.101.0.42'
|
||||
cls.remote_ip2 = '192.101.3.43'
|
||||
cls.gre = 'gre'
|
||||
cls.erspan = 'erspanv1'
|
||||
|
||||
@decorators.idempotent_id('628f202c-ed0a-4eb1-8547-4954f67a84b7')
|
||||
def test_create_tap_mirror(self):
|
||||
tap_mirror = self.create_tap_mirror(
|
||||
port_id=self.tap_mirror_port['id'],
|
||||
directions=self.in_direction,
|
||||
remote_ip=self.remote_ip,
|
||||
mirror_type=self.gre
|
||||
)
|
||||
self.assertEqual(self.tap_mirror_port['id'], tap_mirror['port_id'])
|
||||
self.assertEqual('gre', tap_mirror['mirror_type'])
|
||||
self.assertEqual(self.in_direction, tap_mirror['directions'])
|
||||
self.tap_mirrors_client.delete_tap_mirror(tap_mirror['id'])
|
||||
|
||||
tap_mirror = self.create_tap_mirror(
|
||||
port_id=self.tap_mirror_port['id'],
|
||||
directions=self.both_direction,
|
||||
remote_ip=self.remote_ip,
|
||||
mirror_type=self.erspan
|
||||
)
|
||||
self.assertEqual(self.tap_mirror_port['id'], tap_mirror['port_id'])
|
||||
self.assertEqual(self.erspan, tap_mirror['mirror_type'])
|
||||
self.assertEqual(self.both_direction, tap_mirror['directions'])
|
||||
|
||||
@decorators.idempotent_id('299c251b-e0bc-4449-98db-959a5d8038c2')
|
||||
def test_list_show_tap_mirror(self):
|
||||
tap_mirror = self.create_tap_mirror(
|
||||
port_id=self.tap_mirror_port['id'],
|
||||
directions=self.out_direction,
|
||||
remote_ip=self.remote_ip,
|
||||
mirror_type=self.gre
|
||||
)
|
||||
tap_mirrors = self.tap_mirrors_client.list_tap_mirrors()
|
||||
is_t_m_found = False
|
||||
for t_m in tap_mirrors['tap_mirrors']:
|
||||
if t_m['id'] == tap_mirror['id']:
|
||||
is_t_m_found = True
|
||||
break
|
||||
self.assertTrue(is_t_m_found)
|
||||
tap_mirror_show_res = self.tap_mirrors_client.show_tap_mirror(
|
||||
tap_mirror['id'])['tap_mirror']
|
||||
self.assertEqual(tap_mirror['id'], tap_mirror_show_res['id'])
|
||||
self.assertEqual(self.gre, tap_mirror_show_res['mirror_type'])
|
||||
self.assertEqual(self.remote_ip,
|
||||
tap_mirror_show_res['remote_ip'])
|
||||
self.assertEqual(self.out_direction,
|
||||
tap_mirror_show_res['directions'])
|
||||
|
||||
@decorators.idempotent_id('19c40379-bda5-48c9-8873-fc990739d1b5')
|
||||
def test_update_tap_mirror(self):
|
||||
tap_mirror = self.create_tap_mirror(
|
||||
port_id=self.tap_mirror_port['id'],
|
||||
directions=self.in_direction,
|
||||
remote_ip=self.remote_ip,
|
||||
mirror_type=self.gre
|
||||
)
|
||||
self.tap_mirrors_client.update_tap_mirror(
|
||||
tap_mirror_id=tap_mirror['id'],
|
||||
name='new_name',
|
||||
description='My fancy Tap Mirror'
|
||||
)
|
||||
tap_mirror_show_res = self.tap_mirrors_client.show_tap_mirror(
|
||||
tap_mirror['id'])['tap_mirror']
|
||||
self.assertEqual('new_name', tap_mirror_show_res['name'])
|
||||
self.assertEqual('My fancy Tap Mirror',
|
||||
tap_mirror_show_res['description'])
|
||||
|
||||
@decorators.idempotent_id('9ed165af-7c54-43ac-b14f-077e8f9601f6')
|
||||
def test_delete_mirror_port_deletes_tap_mirror(self):
|
||||
port1 = self.create_port(self.network)
|
||||
tap_mirror = self.create_tap_mirror(
|
||||
port_id=port1['id'],
|
||||
directions=self.out_direction,
|
||||
remote_ip=self.remote_ip,
|
||||
mirror_type=self.gre
|
||||
)
|
||||
# Delete port will result in deteltion of the tap_mirror
|
||||
self.ports_client.delete_port(port1['id'])
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.tap_mirrors_client.show_tap_mirror,
|
||||
tap_mirror['id'])
|
||||
|
||||
@decorators.idempotent_id('abdd4451-bd9d-4f1e-ab7f-e949b9246714')
|
||||
def test_delete_tap_mirror_port_remains(self):
|
||||
port1 = self.create_port(self.network)
|
||||
tap_mirror = self.create_tap_mirror(
|
||||
port_id=port1['id'],
|
||||
directions=self.out_direction,
|
||||
remote_ip=self.remote_ip,
|
||||
mirror_type=self.gre
|
||||
)
|
||||
# Delete tap_mirror will keep the port
|
||||
self.tap_mirrors_client.delete_tap_mirror(tap_mirror['id'])
|
||||
port_res = self.ports_client.show_port(port1['id'])['port']
|
||||
self.assertEqual(port1['name'], port_res['name'])
|
||||
|
||||
@decorators.idempotent_id('1d8b68fc-a600-4b9e-bd17-9469c3a6c95b')
|
||||
def test_create_tap_mirror_negative(self):
|
||||
# directions keys' valid values are IN and OUT
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.create_tap_mirror,
|
||||
port_id=self.tap_mirror_port['id'],
|
||||
directions={'something': 101},
|
||||
remote_ip=self.remote_ip,
|
||||
mirror_type=self.gre)
|
||||
# mirror_type valid values are erspanv1 and gre
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.create_tap_mirror,
|
||||
port_id=self.tap_mirror_port['id'],
|
||||
directions=self.out_direction,
|
||||
remote_ip=self.remote_ip,
|
||||
mirror_type='erspanv2')
|
||||
# remote_ip must be a valid IP
|
||||
self.assertRaises(lib_exc.BadRequest,
|
||||
self.create_tap_mirror,
|
||||
port_id=self.tap_mirror_port['id'],
|
||||
directions=self.in_direction,
|
||||
remote_ip='192.101.0.420',
|
||||
mirror_type=self.gre)
|
||||
|
||||
@decorators.idempotent_id('2b7850b3-3920-4f16-96b7-05e2efd96877')
|
||||
def test_create_tap_service_tunnel_id_conflict(self):
|
||||
self.create_tap_mirror(
|
||||
port_id=self.tap_mirror_port['id'],
|
||||
directions=self.in_direction,
|
||||
remote_ip=self.remote_ip,
|
||||
mirror_type=self.gre
|
||||
)
|
||||
|
||||
port2 = self.create_port(self.network)
|
||||
self.addCleanup(self.ports_client.delete_port, port2['id'])
|
||||
self.assertRaises(lib_exc.Conflict,
|
||||
self.create_tap_mirror,
|
||||
port_id=port2['id'],
|
||||
directions=self.in_direction,
|
||||
remote_ip='192.101.0.4',
|
||||
mirror_type=self.gre)
|
||||
|
||||
@decorators.idempotent_id('95ef1cc1-cd57-4193-a88e-716795e39ebf')
|
||||
def test_create_tap_mirror_non_existing_port(self):
|
||||
not_exists = uuidutils.generate_uuid()
|
||||
self.assertRaises(lib_exc.NotFound,
|
||||
self.create_tap_mirror,
|
||||
port_id=not_exists,
|
||||
directions=self.out_direction,
|
||||
remote_ip=self.remote_ip,
|
||||
mirror_type=self.gre)
|
||||
|
||||
@decorators.idempotent_id('123202cd-d810-4c15-bae7-26d69b24a1a4')
|
||||
def test_multiple_mirrors_for_port(self):
|
||||
port1 = self.create_port(self.network)
|
||||
tap_mirror = self.create_tap_mirror(
|
||||
port_id=port1['id'],
|
||||
directions=self.out_direction,
|
||||
remote_ip=self.remote_ip,
|
||||
mirror_type=self.gre
|
||||
)
|
||||
self.addCleanup(self.tap_mirrors_client.delete_tap_mirror,
|
||||
tap_mirror['id'])
|
||||
|
||||
# Creation of the 2nd mirror in case the direction: tunnel_id dict
|
||||
# is different.
|
||||
tap_mirror2 = self.create_tap_mirror(
|
||||
port_id=port1['id'],
|
||||
directions={'OUT': 103},
|
||||
remote_ip=self.remote_ip2,
|
||||
mirror_type=self.gre
|
||||
)
|
||||
|
||||
# We have a conflict if the direction: tunnel_id dict is the
|
||||
# same
|
||||
self.tap_mirrors_client.delete_tap_mirror(tap_mirror2['id'])
|
||||
self.assertRaises(lib_exc.Conflict,
|
||||
self.create_tap_mirror,
|
||||
port_id=port1['id'],
|
||||
directions=self.out_direction,
|
||||
remote_ip='192.101.0.4',
|
||||
mirror_type=self.gre)
|
@@ -42,6 +42,14 @@ class BaseTaasTest(test.BaseAdminNetworkTest):
|
||||
build_interval=CONF.network.build_interval,
|
||||
build_timeout=CONF.network.build_timeout,
|
||||
**os_primary.default_params)
|
||||
cls.tap_mirrors_client = taas_client.TapMirrorsClient(
|
||||
os_primary.auth_provider,
|
||||
CONF.network.catalog_type,
|
||||
CONF.network.region or CONF.identity.region,
|
||||
endpoint_type=CONF.network.endpoint_type,
|
||||
build_interval=CONF.network.build_interval,
|
||||
build_timeout=CONF.network.build_timeout,
|
||||
**os_primary.default_params)
|
||||
|
||||
def create_tap_service(self, **kwargs):
|
||||
body = self.tap_services_client.create_tap_service(
|
||||
@@ -80,3 +88,22 @@ class BaseTaasTest(test.BaseAdminNetworkTest):
|
||||
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
|
||||
self.tap_flows_client.delete_tap_flow,
|
||||
tap_flow['id'])
|
||||
|
||||
def create_tap_mirror(self, **kwargs):
|
||||
body = self.tap_mirrors_client.create_tap_mirror(
|
||||
name=data_utils.rand_name("tap_mirror"),
|
||||
**kwargs)
|
||||
tap_mirror = body['tap_mirror']
|
||||
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
|
||||
self.tap_mirrors_client.delete_tap_mirror,
|
||||
tap_mirror['id'])
|
||||
return tap_mirror
|
||||
|
||||
def update_tap_mirror(self, tap_mirror_id, **kwargs):
|
||||
body = self.tap_mirrors_client.update_tap_mirror(
|
||||
tap_mirror_id,
|
||||
**kwargs)
|
||||
tap_mirror = body['tap_mirror']
|
||||
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
|
||||
self.tap_mirrors_client.delete_tap_mirror,
|
||||
tap_mirror['id'])
|
||||
|
@@ -59,6 +59,14 @@ class BaseTaasScenarioTests(base.BaseTempestTestCase):
|
||||
build_interval=CONF.network.build_interval,
|
||||
build_timeout=CONF.network.build_timeout,
|
||||
**cls.os_primary.default_params)
|
||||
cls.tap_mirrors_client = taas_client.TapMirrorsClient(
|
||||
cls.os_primary.auth_provider,
|
||||
CONF.network.catalog_type,
|
||||
CONF.network.region or CONF.identity.region,
|
||||
endpoint_type=CONF.network.endpoint_type,
|
||||
build_interval=CONF.network.build_interval,
|
||||
build_timeout=CONF.network.build_timeout,
|
||||
**cls.os_primary.default_params)
|
||||
|
||||
def _create_subnet(self, network, subnets_client=None,
|
||||
namestart='subnet-smoke', **kwargs):
|
||||
@@ -214,8 +222,10 @@ class BaseTaasScenarioTests(base.BaseTempestTestCase):
|
||||
return network, subnet, router
|
||||
|
||||
def _create_server_with_floatingip(self, use_taas_cloud_image=False,
|
||||
provider_net=False, **kwargs):
|
||||
network = self.network
|
||||
provider_net=False, network=None,
|
||||
**kwargs):
|
||||
if not network:
|
||||
network = self.network
|
||||
if use_taas_cloud_image:
|
||||
image = CONF.neutron_plugin_options.advanced_image_ref
|
||||
flavor = CONF.neutron_plugin_options.advanced_image_flavor_ref
|
||||
@@ -226,17 +236,26 @@ class BaseTaasScenarioTests(base.BaseTempestTestCase):
|
||||
if provider_net:
|
||||
network = self.provider_network
|
||||
|
||||
port = self.create_port(
|
||||
network=network, security_groups=[self.secgroup['id']], **kwargs)
|
||||
server_params = {
|
||||
'flavor_ref': flavor,
|
||||
'image_ref': image,
|
||||
'key_name': self.keypair['name'],
|
||||
}
|
||||
if 'security_group' in kwargs:
|
||||
server_params['security_groups'] = [
|
||||
{'name': kwargs.pop('security_group')}]
|
||||
|
||||
if kwargs.get('port_security_enabled', None) is False:
|
||||
port = self.create_port(network=network, **kwargs)
|
||||
else:
|
||||
port = self.create_port(
|
||||
network=network, security_groups=[self.secgroup['id']],
|
||||
**kwargs)
|
||||
self.addCleanup(test_utils.call_and_ignore_notfound_exc,
|
||||
self.client.delete_port, port['id'])
|
||||
|
||||
params = {
|
||||
'flavor_ref': flavor,
|
||||
'image_ref': image,
|
||||
'key_name': self.keypair['name']
|
||||
}
|
||||
vm = self.create_server(networks=[{'port': port['id']}], **params)
|
||||
vm = self.create_server(networks=[{'port': port['id']}],
|
||||
**server_params)
|
||||
self.wait_for_server_active(vm['server'])
|
||||
self.wait_for_guest_os_ready(vm['server'])
|
||||
|
||||
@@ -291,3 +310,40 @@ class BaseTaasScenarioTests(base.BaseTempestTestCase):
|
||||
test_utils.call_and_ignore_notfound_exc,
|
||||
self.admin_network_client.remove_router_interface_with_subnet_id,
|
||||
self.router['id'], subnet_id=result['subnet']['id'])
|
||||
|
||||
def _check_icmp_traffic(self, monitor_client, left_client,
|
||||
left_port, right_port,
|
||||
tcpdump_cmd=None):
|
||||
log_location = "/tmp/tcpdumplog"
|
||||
|
||||
right_ip = right_port['fixed_ips'][0]['ip_address']
|
||||
left_ip = left_port['fixed_ips'][0]['ip_address']
|
||||
|
||||
# Run tcpdump in background
|
||||
if tcpdump_cmd:
|
||||
self._run_in_background(monitor_client, tcpdump_cmd % log_location)
|
||||
else:
|
||||
self._run_in_background(monitor_client,
|
||||
"sudo tcpdump -n -nn > %s" % log_location)
|
||||
|
||||
# Ensure tcpdump is up and running
|
||||
psax = monitor_client.exec_command("ps -ax")
|
||||
self.assertIn("tcpdump", psax)
|
||||
|
||||
# Run traffic from left_vm to right_vm
|
||||
LOG.debug('Check ICMP traffic: ping %s ', right_ip)
|
||||
self.check_remote_connectivity(left_client, right_ip,
|
||||
ping_count=50)
|
||||
|
||||
# Collect tcpdump results
|
||||
output = self.monitor_client.exec_command("cat %s" % log_location)
|
||||
self.assertLess(0, len(output))
|
||||
|
||||
looking_for = ["%s > %s: ICMP echo request" % (left_ip, right_ip),
|
||||
"%s > %s: ICMP echo reply" % (right_ip, left_ip)]
|
||||
|
||||
results = []
|
||||
for tcpdump_line in looking_for:
|
||||
results.append(tcpdump_line in output)
|
||||
|
||||
return all(results), output
|
||||
|
@@ -0,0 +1,141 @@
|
||||
# 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 tempest.common import utils
|
||||
from tempest import config
|
||||
from tempest.lib.common.utils import data_utils
|
||||
from tempest.lib.common.utils.linux import remote_client
|
||||
from tempest.lib.common.utils import test_utils
|
||||
from tempest.lib import decorators
|
||||
|
||||
from neutron_tempest_plugin.tap_as_a_service.scenario import manager
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
class TestTapMirror(manager.BaseTaasScenarioTests):
|
||||
|
||||
@classmethod
|
||||
@utils.requires_ext(extension='security-group', service='network')
|
||||
@utils.requires_ext(extension='tap-mirror', service='network')
|
||||
def skip_checks(cls):
|
||||
super().skip_checks()
|
||||
|
||||
@classmethod
|
||||
def resource_setup(cls):
|
||||
super().resource_setup()
|
||||
cls.keypair = cls.create_keypair()
|
||||
cls.secgroup = cls.create_security_group(
|
||||
name=data_utils.rand_name('secgroup'))
|
||||
cls.create_loginable_secgroup_rule(secgroup_id=cls.secgroup['id'])
|
||||
cls.create_pingable_secgroup_rule(secgroup_id=cls.secgroup['id'])
|
||||
|
||||
@decorators.idempotent_id('d9cfca96-fa83-417a-b111-1c02f6fe2796')
|
||||
def test_tap_mirror_connectivity(self):
|
||||
"""Test that traffic between 2 VMs mirrored to a FIP
|
||||
|
||||
.. code-block:: HTML
|
||||
|
||||
+------------+
|
||||
| Monitor VM |
|
||||
| FIP |
|
||||
+-----+------+
|
||||
|
|
||||
|
|
||||
+-----+------+
|
||||
| NetMon |
|
||||
+------------+
|
||||
|
||||
+---------------+
|
||||
| Net0 |
|
||||
+---+---------+-+
|
||||
| |
|
||||
| |
|
||||
+---+-+ +-+---+
|
||||
| VM0 | | VM1 |
|
||||
+-----+ +-----+
|
||||
|
||||
This is a simplified scenario adapted to the CI machinery.
|
||||
The mirroring destination should be outside of the cloud.
|
||||
"""
|
||||
|
||||
# Create the topology for the 2 VMs of which the traffic
|
||||
# will be mirrored
|
||||
self.network, self.subnet, self.router = self.create_networks()
|
||||
|
||||
vm0_port, vm0_fip = self._create_server_with_floatingip(
|
||||
security_group=self.secgroup['name']
|
||||
)
|
||||
vm1_port, vm1_fip = self._create_server_with_floatingip(
|
||||
security_group=self.secgroup['name']
|
||||
)
|
||||
vm1_ip = vm1_port['fixed_ips'][0]['ip_address']
|
||||
|
||||
vm0_client = remote_client.RemoteClient(
|
||||
vm0_fip['floating_ip_address'],
|
||||
CONF.validation.image_ssh_user,
|
||||
pkey=self.keypair['private_key'],
|
||||
ssh_key_type=CONF.validation.ssh_key_type)
|
||||
vm0_client.validate_authentication()
|
||||
vm1_client = remote_client.RemoteClient(
|
||||
vm1_fip['floating_ip_address'],
|
||||
CONF.validation.image_ssh_user,
|
||||
pkey=self.keypair['private_key'],
|
||||
ssh_key_type=CONF.validation.ssh_key_type)
|
||||
vm1_client.validate_authentication()
|
||||
|
||||
self.check_remote_connectivity(vm0_client, vm1_ip, ping_count=5)
|
||||
|
||||
# Create the VM which will be the destination of the mirror
|
||||
netmon, _, _ = self.create_networks()
|
||||
_, vm_mon_fip = self._create_server_with_floatingip(
|
||||
use_taas_cloud_image=True, network=netmon,
|
||||
security_group=self.secgroup['name'],
|
||||
port_security_enabled=False,
|
||||
)
|
||||
|
||||
user = CONF.neutron_plugin_options.advanced_image_ssh_user
|
||||
self.monitor_client = remote_client.RemoteClient(
|
||||
vm_mon_fip['floating_ip_address'], user,
|
||||
pkey=self.keypair['private_key'],
|
||||
ssh_key_type=CONF.validation.ssh_key_type)
|
||||
self.monitor_client.validate_authentication()
|
||||
|
||||
r_ip = vm_mon_fip['floating_ip_address']
|
||||
# Create GRE mirror, as tcpdump cant extract ERSPAN
|
||||
# it is just visible as a type of GRE traffic.
|
||||
# direction IN and that the test pings from vm0 to vm1
|
||||
# means that ICMP echo request will be in the dump.
|
||||
# 101 as tunnel id means that we will see 0x65 as key
|
||||
tap_mirror = self.tap_mirrors_client.create_tap_mirror(
|
||||
name=data_utils.rand_name("tap_mirror"),
|
||||
port_id=vm1_port['id'],
|
||||
directions={'IN': '101', 'OUT': '102'},
|
||||
remote_ip=r_ip,
|
||||
mirror_type='gre',
|
||||
)
|
||||
self.addCleanup(
|
||||
test_utils.call_and_ignore_notfound_exc,
|
||||
self.tap_mirrors_client.delete_tap_mirror,
|
||||
tap_mirror['tap_mirror']['id']
|
||||
)
|
||||
|
||||
res, output = self._check_icmp_traffic(
|
||||
self.monitor_client,
|
||||
vm0_client, vm0_port, vm1_port,
|
||||
tcpdump_cmd="sudo tcpdump -vvv -n -nn proto GRE > %s")
|
||||
|
||||
self.assertTrue(res)
|
||||
# GRE Key for Direction IN:101
|
||||
self.assertIn('key=0x65', output)
|
||||
# GRE Key for Direction OUT:102
|
||||
self.assertIn('key=0x66', output)
|
@@ -138,40 +138,6 @@ class TestTaaSTrafficScenarios(manager.BaseTaasScenarioTests):
|
||||
self.right_client.validate_authentication()
|
||||
yield
|
||||
|
||||
def _check_icmp_traffic(self):
|
||||
log_location = "/tmp/tcpdumplog"
|
||||
|
||||
right_ip = self.right_port['fixed_ips'][0]['ip_address']
|
||||
left_ip = self.left_port['fixed_ips'][0]['ip_address']
|
||||
|
||||
# Run tcpdump in background
|
||||
self._run_in_background(self.monitor_client,
|
||||
"sudo tcpdump -n -nn > %s" % log_location)
|
||||
|
||||
# Ensure tcpdump is up and running
|
||||
psax = self.monitor_client.exec_command("ps -ax")
|
||||
self.assertIn("tcpdump", psax)
|
||||
|
||||
# Run traffic from left_vm to right_vm
|
||||
LOG.debug('Check ICMP traffic: ping %s ', right_ip)
|
||||
# self.left_client.exec_command(
|
||||
# "ping -c 50 %s" % self.right_fip['floating_ip_address'])
|
||||
self.check_remote_connectivity(self.left_client, right_ip,
|
||||
ping_count=50)
|
||||
|
||||
# Collect tcpdump results
|
||||
output = self.monitor_client.exec_command("cat %s" % log_location)
|
||||
self.assertLess(0, len(output))
|
||||
|
||||
looking_for = ["IP %s > %s: ICMP echo request" % (left_ip, right_ip),
|
||||
"IP %s > %s: ICMP echo reply" % (right_ip, left_ip)]
|
||||
|
||||
results = []
|
||||
for tcpdump_line in looking_for:
|
||||
results.append(tcpdump_line in output)
|
||||
|
||||
return all(results)
|
||||
|
||||
def _test_taas_connectivity(self, use_provider_net=False):
|
||||
"""Ensure TAAS doesn't break connectivity
|
||||
|
||||
@@ -222,7 +188,9 @@ class TestTaaSTrafficScenarios(manager.BaseTaasScenarioTests):
|
||||
|
||||
with self._setup_topology(use_taas_cloud_image=True):
|
||||
# Check that traffic was forwarded to TAAS service
|
||||
self.assertTrue(self._check_icmp_traffic())
|
||||
self.assertTrue(self._check_icmp_traffic(
|
||||
self.monitor_client, self.left_client,
|
||||
self.left_port, self.right_port)[0])
|
||||
|
||||
@decorators.idempotent_id('6c54d9c5-075a-4a1f-bbe6-12c3c9abf1e2')
|
||||
@testtools.skipUnless(CONF.neutron_plugin_options.advanced_image_ref,
|
||||
@@ -234,7 +202,9 @@ class TestTaaSTrafficScenarios(manager.BaseTaasScenarioTests):
|
||||
|
||||
with self._setup_topology(taas=False, use_taas_cloud_image=True):
|
||||
# Check that traffic was NOT forwarded to TAAS service
|
||||
self.assertFalse(self._check_icmp_traffic())
|
||||
self.assertFalse(self._check_icmp_traffic(
|
||||
self.monitor_client, self.left_client,
|
||||
self.left_port, self.right_port)[0])
|
||||
|
||||
@decorators.idempotent_id('fcb15ca3-ef61-11e9-9792-f45c89c47e12')
|
||||
@testtools.skipUnless(CONF.neutron_plugin_options.advanced_image_ref,
|
||||
@@ -247,7 +217,9 @@ class TestTaaSTrafficScenarios(manager.BaseTaasScenarioTests):
|
||||
with self._setup_topology(use_taas_cloud_image=True,
|
||||
provider_net=True):
|
||||
# Check that traffic was forwarded to TAAS service
|
||||
self.assertTrue(self._check_icmp_traffic())
|
||||
self.assertTrue(self._check_icmp_traffic(
|
||||
self.monitor_client, self.left_client,
|
||||
self.left_port, self.right_port)[0])
|
||||
|
||||
@decorators.idempotent_id('6c54d9c5-075a-4a1f-bbe6-12c3c9abf1e3')
|
||||
@testtools.skipUnless(CONF.neutron_plugin_options.advanced_image_ref,
|
||||
@@ -260,4 +232,6 @@ class TestTaaSTrafficScenarios(manager.BaseTaasScenarioTests):
|
||||
with self._setup_topology(taas=False, use_taas_cloud_image=True,
|
||||
provider_net=True):
|
||||
# Check that traffic was NOT forwarded to TAAS service
|
||||
self.assertFalse(self._check_icmp_traffic())
|
||||
self.assertFalse(self._check_icmp_traffic(
|
||||
self.monitor_client, self.left_client,
|
||||
self.left_port, self.right_port)[0])
|
||||
|
@@ -61,3 +61,27 @@ class TapFlowsClient(base.BaseNetworkClient):
|
||||
def list_tap_flows(self, **filters):
|
||||
uri = '/taas/tap_flows'
|
||||
return self.list_resources(uri, **filters)
|
||||
|
||||
|
||||
class TapMirrorsClient(base.BaseNetworkClient):
|
||||
def create_tap_mirror(self, **kwargs):
|
||||
uri = '/taas/tap_mirrors'
|
||||
post_data = {'tap_mirror': kwargs}
|
||||
return self.create_resource(uri, post_data)
|
||||
|
||||
def update_tap_mirror(self, tap_mirror_id, **kwargs):
|
||||
uri = '/taas/tap_mirrors/%s' % tap_mirror_id
|
||||
post_data = {'tap_mirror': kwargs}
|
||||
return self.update_resource(uri, post_data)
|
||||
|
||||
def show_tap_mirror(self, tap_mirror_id, **fields):
|
||||
uri = '/taas/tap_mirrors/%s' % tap_mirror_id
|
||||
return self.show_resource(uri, **fields)
|
||||
|
||||
def delete_tap_mirror(self, tap_mirror_id):
|
||||
uri = '/taas/tap_mirrors/%s' % tap_mirror_id
|
||||
return self.delete_resource(uri)
|
||||
|
||||
def list_tap_mirrors(self, **filters):
|
||||
uri = '/taas/tap_mirrors'
|
||||
return self.list_resources(uri, **filters)
|
||||
|
@@ -326,5 +326,9 @@
|
||||
nodeset: openstack-single-node-jammy
|
||||
required-projects: *required-projects-2023-1
|
||||
vars:
|
||||
network_api_extensions_common: *api_extensions
|
||||
network_api_extensions_tempest:
|
||||
- taas
|
||||
- taas-vlan-filter
|
||||
devstack_localrc:
|
||||
NEUTRON_DEPLOY_MOD_WSGI: false
|
||||
|
@@ -301,5 +301,9 @@
|
||||
nodeset: openstack-single-node-jammy
|
||||
override-checkout: stable/2024.1
|
||||
vars:
|
||||
network_api_extensions_common: *api_extensions
|
||||
network_api_extensions_tempest:
|
||||
- taas
|
||||
- taas-vlan-filter
|
||||
devstack_localrc:
|
||||
NEUTRON_DEPLOY_MOD_WSGI: false
|
||||
|
@@ -287,3 +287,10 @@
|
||||
parent: neutron-tempest-plugin-tap-as-a-service
|
||||
nodeset: openstack-single-node-jammy
|
||||
override-checkout: stable/2024.2
|
||||
vars:
|
||||
network_api_extensions_common: *api_extensions
|
||||
network_api_extensions_tempest:
|
||||
- taas
|
||||
- taas-vlan-filter
|
||||
devstack_localrc:
|
||||
NEUTRON_DEPLOY_MOD_WSGI: false
|
||||
|
@@ -252,3 +252,9 @@
|
||||
parent: neutron-tempest-plugin-tap-as-a-service
|
||||
nodeset: openstack-single-node-noble
|
||||
override-checkout: stable/2025.1
|
||||
|
||||
- job:
|
||||
name: neutron-tempest-plugin-tap-as-a-service-ovn-2025-1
|
||||
parent: neutron-tempest-plugin-tap-as-a-service-ovn
|
||||
nodeset: openstack-single-node-noble
|
||||
override-checkout: stable/2025.1
|
||||
|
@@ -1512,12 +1512,14 @@
|
||||
network_api_extensions_tempest:
|
||||
- taas
|
||||
- taas-vlan-filter
|
||||
- tap-mirror
|
||||
devstack_localrc:
|
||||
NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_tempest) | join(',') }}"
|
||||
BUILD_TIMEOUT: 784
|
||||
Q_AGENT: openvswitch
|
||||
Q_ML2_TENANT_NETWORK_TYPE: vxlan,vlan
|
||||
Q_ML2_PLUGIN_MECHANISM_DRIVERS: openvswitch
|
||||
OVS_BRANCH: "branch-3.3"
|
||||
devstack_local_conf:
|
||||
post-config:
|
||||
/$NEUTRON_CORE_PLUGIN_CONF:
|
||||
@@ -1569,10 +1571,11 @@
|
||||
q-svc: true
|
||||
neutron: true
|
||||
taas: true
|
||||
tap_mirror: true
|
||||
taas_openvswitch_agent: true
|
||||
tempest: true
|
||||
dstat: true
|
||||
irrelevant-files:
|
||||
irrelevant-files: &taas_irrelevant_files
|
||||
- ^\.pylintrc$
|
||||
- ^(test-|)requirements.txt$
|
||||
- ^lower-constraints.txt$
|
||||
@@ -1604,3 +1607,52 @@
|
||||
# Ignore everything except for zuul.d/project.yaml
|
||||
- ^zuul.d/.*_jobs\.yaml$
|
||||
- ^zuul.d/base-nested-switch.yaml
|
||||
|
||||
- job:
|
||||
name: neutron-tempest-plugin-tap-as-a-service-ovn
|
||||
parent: neutron-tempest-plugin-base
|
||||
description: |
|
||||
Test tap-mirrors with OVN
|
||||
roles:
|
||||
- zuul: openstack/devstack
|
||||
required-projects:
|
||||
- openstack/neutron
|
||||
- openstack/neutron-tempest-plugin
|
||||
- openstack/tap-as-a-service
|
||||
- openstack/tempest
|
||||
vars:
|
||||
tempest_concurrency: 4
|
||||
tempest_test_regex: ^neutron_tempest_plugin\.tap_as_a_service
|
||||
tox_envlist: all
|
||||
network_api_extensions_tempest:
|
||||
- taas
|
||||
- tap-mirror
|
||||
devstack_localrc:
|
||||
Q_AGENT: ovn
|
||||
NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_tempest) | join(',') }}"
|
||||
BUILD_TIMEOUT: 784
|
||||
TAAS_SERVICE_DRIVER: "TAAS:TAAS:neutron_taas.services.taas.service_drivers.ovn.taas_ovn.TaasOvnDriver:default"
|
||||
# mirroring is available from OVN 22.12.0 and use OVS 3.2.1 that also have this
|
||||
# feature and builds with the above OVN
|
||||
OVN_BRANCH: "branch-24.03"
|
||||
OVS_BRANCH: "branch-3.3"
|
||||
devstack_local_conf:
|
||||
test-config:
|
||||
$TEMPEST_CONFIG:
|
||||
neutron_plugin_options:
|
||||
image_is_advanced: true
|
||||
advanced_image_flavor_ref: d1
|
||||
taas:
|
||||
provider_physical_network: public
|
||||
provider_segmentation_id: 100
|
||||
image_feature_enabled:
|
||||
api_v2: true
|
||||
devstack_plugins:
|
||||
neutron: git://opendev.org/openstack/neutron.git
|
||||
neutron-tempest-plugin: https://opendev.org/openstack/neutron-tempest-plugin.git
|
||||
tap-as-a-service: git://opendev.org/openstack/tap-as-a-service.git
|
||||
devstack_services:
|
||||
tap_mirror: true
|
||||
taas: true
|
||||
tempest: true
|
||||
irrelevant-files: *taas_irrelevant_files
|
||||
|
@@ -235,9 +235,11 @@
|
||||
- neutron-tempest-plugin-vpnaas-2024-2
|
||||
- neutron-tempest-plugin-vpnaas-2025-1
|
||||
- neutron-tempest-plugin-tap-as-a-service
|
||||
- neutron-tempest-plugin-tap-as-a-service-ovn
|
||||
- neutron-tempest-plugin-tap-as-a-service-2024-1
|
||||
- neutron-tempest-plugin-tap-as-a-service-2024-2
|
||||
- neutron-tempest-plugin-tap-as-a-service-2025-1
|
||||
- neutron-tempest-plugin-tap-as-a-service-ovn-2025-1
|
||||
|
||||
gate:
|
||||
jobs:
|
||||
|
@@ -284,5 +284,8 @@
|
||||
required-projects: *required-projects-xena
|
||||
vars:
|
||||
network_api_extensions_common: *api_extensions
|
||||
network_api_extensions_tempest:
|
||||
- taas
|
||||
- taas-vlan-filter
|
||||
devstack_localrc:
|
||||
NEUTRON_DEPLOY_MOD_WSGI: false
|
||||
|
@@ -306,5 +306,8 @@
|
||||
required-projects: *required-projects-yoga
|
||||
vars:
|
||||
network_api_extensions_common: *api_extensions
|
||||
network_api_extensions_tempest:
|
||||
- taas
|
||||
- taas-vlan-filter
|
||||
devstack_localrc:
|
||||
NEUTRON_DEPLOY_MOD_WSGI: false
|
||||
|
@@ -327,5 +327,8 @@
|
||||
required-projects: *required-projects-zed
|
||||
vars:
|
||||
network_api_extensions_common: *api_extensions
|
||||
network_api_extensions_tempest:
|
||||
- taas
|
||||
- taas-vlan-filter
|
||||
devstack_localrc:
|
||||
NEUTRON_DEPLOY_MOD_WSGI: false
|
||||
|
Reference in New Issue
Block a user