Merge "Zuul: do not use USE_PYTHON3"
diff --git a/neutron_tempest_plugin/api/admin/test_networks.py b/neutron_tempest_plugin/api/admin/test_networks.py
index 17a8990..a67afa3 100644
--- a/neutron_tempest_plugin/api/admin/test_networks.py
+++ b/neutron_tempest_plugin/api/admin/test_networks.py
@@ -86,3 +86,55 @@
network = self.admin_client.show_network(
network['id'])['network']
self.assertEqual('vxlan', network['provider:network_type'])
+
+ @decorators.idempotent_id('bbb9a2be-c9a7-4693-ac8e-d51b5371b68d')
+ def test_list_network_filter_provider_attributes(self):
+ if not config.CONF.neutron_plugin_options.provider_vlans:
+ raise self.skipException("No provider VLAN networks available")
+ project_id = self.client.project_id
+ physnet_name = config.CONF.neutron_plugin_options.provider_vlans[0]
+ # Check project networks pre-created.
+ body = self.client.list_networks(project_id=project_id)['networks']
+ num_networks_precreated = len(body)
+
+ networks = []
+ num_networks = 5
+ for _ in range(num_networks):
+ networks.append(self.create_network(
+ provider_network_type='vlan',
+ provider_physical_network=physnet_name,
+ project_id=project_id))
+
+ # Check new project networks created.
+ body = self.client.list_networks(project_id=project_id)['networks']
+ self.assertEqual(num_networks + num_networks_precreated, len(body))
+
+ vlan_ids = [net['provider:segmentation_id'] for net in networks]
+
+ # List networks with limit (from 1 to num_networks).
+ # Each filter (except from the 'provider:segmentation_id'), uses the
+ # value directly and in a list.
+ for idx in range(1, num_networks + 1):
+ # Filter by 'provider:network_type'
+ kwargs = {'provider:network_type': 'vlan',
+ 'project_id': project_id, 'limit': idx}
+ body = self.client.list_networks(**kwargs)['networks']
+ self.assertEqual(idx, len(body))
+ kwargs['provider:network_type'] = ['vlan']
+ body = self.client.list_networks(**kwargs)['networks']
+ self.assertEqual(idx, len(body))
+
+ # Filter by 'provider:physical_network'.
+ kwargs = {'provider:physical_network': physnet_name,
+ 'project_id': project_id, 'limit': idx}
+ body = self.client.list_networks(**kwargs)['networks']
+ self.assertEqual(idx, len(body))
+ kwargs['provider:physical_network'] = [physnet_name]
+ body = self.client.list_networks(**kwargs)['networks']
+ self.assertEqual(idx, len(body))
+
+ # Filter by 'provider:segmentation_id'
+ kwargs = {'provider:segmentation_id': vlan_ids,
+ 'project_id': project_id, 'limit': idx}
+ body = self.client.list_networks(**kwargs)['networks']
+ self.assertEqual(idx, len(body))
diff --git a/neutron_tempest_plugin/api/test_routers.py b/neutron_tempest_plugin/api/test_routers.py
index 1470a7b..0012ffe 100644
--- a/neutron_tempest_plugin/api/test_routers.py
+++ b/neutron_tempest_plugin/api/test_routers.py
@@ -506,9 +506,17 @@
remove_gateways[0])
external_gateways[1] = remove_gateways[0]
- res_update_gws = self.admin_client.router_update_external_gateways(
- router['id'],
- external_gateways)
+ try:
+ res_update_gws = self.admin_client.router_update_external_gateways(
+ router['id'],
+ external_gateways)
+ except lib_exc.Conflict as exc:
+ if 'IpAddressAlreadyAllocated' in str(exc):
+ self.skipTest(
+ 'The IP address of the removed gateway port is already '
+ 'used by other test, thus this exception is dismissed and '
+ 'the rest of the test skipped')
+ raise exc
self.assertEqual(len(res_update_gws['router']['external_gateways']), 2)
for n in range(0, 2):
diff --git a/neutron_tempest_plugin/bgpvpn/base.py b/neutron_tempest_plugin/bgpvpn/base.py
index b436a5d..aeecbfc 100644
--- a/neutron_tempest_plugin/bgpvpn/base.py
+++ b/neutron_tempest_plugin/bgpvpn/base.py
@@ -72,13 +72,8 @@
@classmethod
def skip_checks(cls):
super(BaseBgpvpnTest, cls).skip_checks()
- msg = None
if not utils.is_extension_enabled('bgpvpn', 'network'):
msg = "Bgpvpn extension not enabled."
- elif not CONF.bgpvpn.run_bgpvpn_tests:
- msg = ("Running of bgpvpn related tests is disabled in "
- "plugin configuration.")
- if msg:
raise cls.skipException(msg)
def create_bgpvpn(self, client, **kwargs):
diff --git a/neutron_tempest_plugin/common/ip.py b/neutron_tempest_plugin/common/ip.py
index 5335219..e87219b 100644
--- a/neutron_tempest_plugin/common/ip.py
+++ b/neutron_tempest_plugin/common/ip.py
@@ -159,21 +159,22 @@
# ip addr del 192.168.1.1/24 dev em1
return self.execute('address', 'del', address, 'dev', device)
- def add_route(self, address, device, gateway=None):
+ def add_route(self, address, device, gateway=None, ip_version=4):
if gateway:
- # ip route add 192.168.1.0/24 via 192.168.22.1 dev em1
return self.execute(
'route', 'add', address, 'via', gateway, 'dev', device)
else:
- # ip route add 192.168.1.0/24 dev em1
- return self.execute('route', 'add', address, 'dev', device)
+ return self.execute(
+ f'-{ip_version}', 'route', 'add', address, 'dev', device)
- def delete_route(self, address, device):
- # ip route del 192.168.1.0/24 dev em1
- return self.execute('route', 'del', address, 'dev', device)
+ def delete_route(self, address, device, ip_version=4):
+ return self.execute(
+ f'-{ip_version}', 'route', 'del', address, 'dev', device)
- def list_routes(self, *args):
- output = self.execute('route', 'show', *args)
+ def list_routes(self, *args, device=None, ip_version=4):
+ if not args and device:
+ args = ("dev", device)
+ output = self.execute(f'-{ip_version}', 'route', 'show', *args)
return list(parse_routes(output))
def get_nic_name_by_mac(self, mac_address):
diff --git a/neutron_tempest_plugin/config.py b/neutron_tempest_plugin/config.py
index 38d6ac6..880d3a6 100644
--- a/neutron_tempest_plugin/config.py
+++ b/neutron_tempest_plugin/config.py
@@ -100,6 +100,7 @@
help='User name used to connect to "ssh_proxy_jump_host".'),
cfg.StrOpt('ssh_proxy_jump_password',
default=None,
+ secret=True,
help='Password used to connect to "ssh_proxy_jump_host".'),
cfg.StrOpt('ssh_proxy_jump_keyfile',
default=None,
@@ -158,22 +159,11 @@
default=False,
help='Schedule BGP speakers to agents explicitly.'),
]
+neutron_group = cfg.OptGroup(name="neutron_plugin_options",
+ title="Neutron Plugin Options")
-# TODO(amuller): Redo configuration options registration as part of the planned
-# transition to the Tempest plugin architecture
-for opt in NeutronPluginOptions:
- CONF.register_opt(opt, 'neutron_plugin_options')
BgpvpnGroup = [
- # TODO(tkajinam): This has been required since the plugin tests was merged
- # into neutron-tempest-plugin in Train. Remove this after 2025.1 release.
- cfg.BoolOpt('run_bgpvpn_tests',
- default=True,
- help=("If it is set to False bgpvpn api and scenario tests "
- "will be skipped"),
- deprecated_for_removal=True,
- deprecated_reason='Tests are skipped according to '
- 'the available extensions.'),
cfg.IntOpt('min_asn',
default=100,
help=("Minimum number for the range of "
@@ -191,48 +181,17 @@
help=("Maximum number for the range of "
"assigned number for distinguishers.")),
]
-
bgpvpn_group = cfg.OptGroup(name="bgpvpn", title=("Networking-Bgpvpn Service "
"Options"))
-CONF.register_group(bgpvpn_group)
-CONF.register_opts(BgpvpnGroup, group="bgpvpn")
FwaasGroup = [
- # TODO(tkajinam): This has been required since the plugin tests was merged
- # into neutron-tempest-plugin in Train. Remove this after 2025.1 release.
- cfg.BoolOpt('run_fwaas_tests',
- default=True,
- help=("If it is set to False fwaas api and scenario tests "
- "will be skipped"),
- deprecated_for_removal=True,
- deprecated_reason='Tests are skipped according to '
- 'the available extensions.'),
cfg.StrOpt('driver',
default=None,
choices=['openvswitch', 'ovn'],
help='Driver used by the FWaaS plugin.'),
]
-
fwaas_group = cfg.OptGroup(
name="fwaas", title=("Neutron-fwaas Service Options"))
-CONF.register_group(fwaas_group)
-CONF.register_opts(FwaasGroup, group="fwaas")
-
-SfcGroup = [
- # TODO(tkajinam): This has been required since the plugin tests was merged
- # into neutron-tempest-plugin in Train. Remove this after 2025.1 release.
- cfg.BoolOpt('run_sfc_tests',
- default=True,
- help=("If it is set to False SFC api and scenario tests "
- "will be skipped"),
- deprecated_for_removal=True,
- deprecated_reason='Tests are skipped according to '
- 'the available extensions.'),
-]
-
-sfc_group = cfg.OptGroup(name="sfc", title=("Networking-sfc Service Options"))
-CONF.register_group(sfc_group)
-CONF.register_opts(SfcGroup, group="sfc")
TaasGroup = [
@@ -249,8 +208,6 @@
]
taas_group = cfg.OptGroup(name='taas',
title='TaaS Tempest Options')
-CONF.register_group(taas_group)
-CONF.register_opts(TaasGroup, group="taas")
DynamicRoutingGroup = [
@@ -259,12 +216,9 @@
help=('Base image used to build the image for connectivity '
'check')),
]
-
dynamic_routing_group = cfg.OptGroup(
name="dynamic_routing",
title=("Neutron-Dynamic-Routing Service Options"))
-CONF.register_group(dynamic_routing_group)
-CONF.register_opts(DynamicRoutingGroup, group="dynamic_routing")
# DNS Integration with an External Service
@@ -276,5 +230,3 @@
]
dns_feature_group = cfg.OptGroup(
name='designate_feature_enabled', title='Enabled Designate Features')
-CONF.register_group(dns_feature_group)
-CONF.register_opts(DnsFeatureGroup, group="designate_feature_enabled")
diff --git a/neutron_tempest_plugin/fwaas/api/fwaas_v2_base.py b/neutron_tempest_plugin/fwaas/api/fwaas_v2_base.py
index f4f63ec..e54c643 100644
--- a/neutron_tempest_plugin/fwaas/api/fwaas_v2_base.py
+++ b/neutron_tempest_plugin/fwaas/api/fwaas_v2_base.py
@@ -21,13 +21,4 @@
class BaseFWaaSTest(fwaas_v2_client.FWaaSClientMixin, base.BaseNetworkTest):
-
- @classmethod
- def skip_checks(cls):
- super(BaseFWaaSTest, cls).skip_checks()
- msg = None
- if not CONF.fwaas.run_fwaas_tests:
- msg = ("Running of fwaas related tests is disabled in "
- "plugin configuration.")
- if msg:
- raise cls.skipException(msg)
+ pass
diff --git a/neutron_tempest_plugin/fwaas/scenario/fwaas_v2_manager.py b/neutron_tempest_plugin/fwaas/scenario/fwaas_v2_manager.py
index 9cc0a6a..371a186 100644
--- a/neutron_tempest_plugin/fwaas/scenario/fwaas_v2_manager.py
+++ b/neutron_tempest_plugin/fwaas/scenario/fwaas_v2_manager.py
@@ -31,16 +31,6 @@
credentials = ['primary']
- @classmethod
- def skip_checks(cls):
- super(ScenarioTest, cls).skip_checks()
- msg = None
- if not CONF.fwaas.run_fwaas_tests:
- msg = ("Running of fwaas related tests is disabled in "
- "plugin configuration.")
- if msg:
- raise cls.skipException(msg)
-
class NetworkScenarioTest(ScenarioTest):
"""Base class for network scenario tests.
diff --git a/neutron_tempest_plugin/plugin.py b/neutron_tempest_plugin/plugin.py
index fc41bdd..029fdab 100644
--- a/neutron_tempest_plugin/plugin.py
+++ b/neutron_tempest_plugin/plugin.py
@@ -16,8 +16,11 @@
import os
+from tempest import config
from tempest.test_discover import plugins
+from neutron_tempest_plugin import config as neutron_config
+
class NeutronTempestPlugin(plugins.TempestPlugin):
def load_tests(self):
@@ -28,7 +31,31 @@
return full_test_dir, base_path
def register_opts(self, conf):
- pass
+ config.register_opt_group(conf, neutron_config.neutron_group,
+ neutron_config.NeutronPluginOptions)
+ config.register_opt_group(conf, neutron_config.bgpvpn_group,
+ neutron_config.BgpvpnGroup)
+ config.register_opt_group(conf, neutron_config.fwaas_group,
+ neutron_config.FwaasGroup)
+ config.register_opt_group(conf, neutron_config.taas_group,
+ neutron_config.TaasGroup)
+ config.register_opt_group(conf, neutron_config.dynamic_routing_group,
+ neutron_config.DynamicRoutingGroup)
+ config.register_opt_group(conf, neutron_config.dns_feature_group,
+ neutron_config.DnsFeatureGroup)
def get_opt_lists(self):
- pass
+ return [
+ (neutron_config.neutron_group.name,
+ neutron_config.NeutronPluginOptions),
+ (neutron_config.bgpvpn_group.name,
+ neutron_config.BgpvpnGroup),
+ (neutron_config.fwaas_group.name,
+ neutron_config.FwaasGroup),
+ (neutron_config.taas_group.name,
+ neutron_config.TaasGroup),
+ (neutron_config.dynamic_routing_group.name,
+ neutron_config.DynamicRoutingGroup),
+ (neutron_config.dns_feature_group.name,
+ neutron_config.DnsFeatureGroup)
+ ]
diff --git a/neutron_tempest_plugin/scenario/test_vlan_transparency.py b/neutron_tempest_plugin/scenario/test_vlan_transparency.py
index 85648bc..11ff510 100644
--- a/neutron_tempest_plugin/scenario/test_vlan_transparency.py
+++ b/neutron_tempest_plugin/scenario/test_vlan_transparency.py
@@ -123,8 +123,8 @@
self, port_security=True, use_allowed_address_pairs=False):
self._ensure_ethtype()
vlan_tag = data_utils.rand_int_id(start=MIN_VLAN_ID, end=MAX_VLAN_ID)
- vlan_ipmask_template = '192.168.%d.{ip_last_byte}/24' % (vlan_tag %
- 256)
+ vtag = vlan_tag % 256
+ vlan_ipmask_template = '192.%d.%d.{ip_last_byte}/24' % (vtag, vtag)
vms = []
vlan_ipmasks = []
floating_ips = []
diff --git a/neutron_tempest_plugin/sfc/tests/api/base.py b/neutron_tempest_plugin/sfc/tests/api/base.py
index 606aed6..329bed8 100644
--- a/neutron_tempest_plugin/sfc/tests/api/base.py
+++ b/neutron_tempest_plugin/sfc/tests/api/base.py
@@ -34,16 +34,6 @@
):
@classmethod
- def skip_checks(cls):
- super(BaseFlowClassifierTest, cls).skip_checks()
- msg = None
- if not CONF.sfc.run_sfc_tests:
- msg = ("Running of SFC related tests is disabled in "
- "plugin configuration.")
- if msg:
- raise cls.skipException(msg)
-
- @classmethod
def resource_setup(cls):
super(BaseFlowClassifierTest, cls).resource_setup()
if not utils.is_extension_enabled('flow_classifier', 'network'):
diff --git a/neutron_tempest_plugin/sfc/tests/scenario/base.py b/neutron_tempest_plugin/sfc/tests/scenario/base.py
index 44b5cd2..5945aef 100644
--- a/neutron_tempest_plugin/sfc/tests/scenario/base.py
+++ b/neutron_tempest_plugin/sfc/tests/scenario/base.py
@@ -31,16 +31,6 @@
manager.NetworkScenarioTest
):
- @classmethod
- def skip_checks(cls):
- super(SfcScenarioTest, cls).skip_checks()
- msg = None
- if not CONF.sfc.run_sfc_tests:
- msg = ("Running of SFC related tests is disabled in "
- "plugin configuration.")
- if msg:
- raise cls.skipException(msg)
-
def _check_connectivity(
self, source_ip, destination_ip, routes=None,
username=None, private_key=None
diff --git a/neutron_tempest_plugin/tap_as_a_service/api/test_tap_mirror.py b/neutron_tempest_plugin/tap_as_a_service/api/test_tap_mirror.py
new file mode 100644
index 0000000..85c37c6
--- /dev/null
+++ b/neutron_tempest_plugin/tap_as_a_service/api/test_tap_mirror.py
@@ -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)
diff --git a/neutron_tempest_plugin/tap_as_a_service/base.py b/neutron_tempest_plugin/tap_as_a_service/base.py
index 3ddc797..99bd3cd 100644
--- a/neutron_tempest_plugin/tap_as_a_service/base.py
+++ b/neutron_tempest_plugin/tap_as_a_service/base.py
@@ -42,6 +42,14 @@
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 @@
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'])
diff --git a/neutron_tempest_plugin/tap_as_a_service/scenario/manager.py b/neutron_tempest_plugin/tap_as_a_service/scenario/manager.py
index 80389c1..d3c0d8b 100644
--- a/neutron_tempest_plugin/tap_as_a_service/scenario/manager.py
+++ b/neutron_tempest_plugin/tap_as_a_service/scenario/manager.py
@@ -59,6 +59,14 @@
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 @@
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 @@
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 @@
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
diff --git a/neutron_tempest_plugin/tap_as_a_service/scenario/test_tap_mirror.py b/neutron_tempest_plugin/tap_as_a_service/scenario/test_tap_mirror.py
new file mode 100644
index 0000000..d4a482c
--- /dev/null
+++ b/neutron_tempest_plugin/tap_as_a_service/scenario/test_tap_mirror.py
@@ -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)
diff --git a/neutron_tempest_plugin/tap_as_a_service/scenario/test_traffic_impact.py b/neutron_tempest_plugin/tap_as_a_service/scenario/test_traffic_impact.py
index 904335d..6eaeb6b 100644
--- a/neutron_tempest_plugin/tap_as_a_service/scenario/test_traffic_impact.py
+++ b/neutron_tempest_plugin/tap_as_a_service/scenario/test_traffic_impact.py
@@ -138,40 +138,6 @@
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 @@
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 @@
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 @@
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 @@
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])
diff --git a/neutron_tempest_plugin/tap_as_a_service/services/taas_client.py b/neutron_tempest_plugin/tap_as_a_service/services/taas_client.py
index 7230cbb..8998f1c 100644
--- a/neutron_tempest_plugin/tap_as_a_service/services/taas_client.py
+++ b/neutron_tempest_plugin/tap_as_a_service/services/taas_client.py
@@ -61,3 +61,27 @@
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)
diff --git a/releasenotes/notes/remove-run-tests-opts-152c092bee1dc81d.yaml b/releasenotes/notes/remove-run-tests-opts-152c092bee1dc81d.yaml
new file mode 100644
index 0000000..bd3fb45
--- /dev/null
+++ b/releasenotes/notes/remove-run-tests-opts-152c092bee1dc81d.yaml
@@ -0,0 +1,8 @@
+---
+upgrade:
+ - |
+ The following options have been removed.
+
+ - ``[bgpvpn] run_bgpvpn_tests``
+ - ``[fwaas] run_fwaas_tests``
+ - ``[sfc] run_sfc_tests``
diff --git a/tools/customize_ubuntu_image b/tools/customize_ubuntu_image
index 34b22fe..438d97e 100755
--- a/tools/customize_ubuntu_image
+++ b/tools/customize_ubuntu_image
@@ -69,14 +69,19 @@
bind_dir "/sys" "${mount_dir}/sys"
if [ -f /etc/apt/sources.list ]; then
mirror=$(grep -oP 'https?://\K[^/ ]+' /etc/apt/sources.list|head -1)
- if [ -f ${mount_dir}/etc/apt/sources.list ]; then
- source ${mount_dir}/etc/os-release
- sudo tee ${mount_dir}/etc/apt/sources.list <<EOF
- deb [ trusted=yes ] https://${mirror}/ubuntu ${UBUNTU_CODENAME} main universe
- deb [ trusted=yes ] https://${mirror}/ubuntu ${UBUNTU_CODENAME}-updates main universe
- deb [ trusted=yes ] https://${mirror}/ubuntu ${UBUNTU_CODENAME}-backports main universe
- deb [ trusted=yes ] https://${mirror}/ubuntu ${UBUNTU_CODENAME}-security main universe
+ if [ -n "${mirror}" ]; then
+ if sudo test -f ${mount_dir}/etc/apt/sources.list.d/ubuntu.sources; then
+ sudo sed -Ei "s|(http[s]?://)([^/]+)|\1${mirror}|g" ${mount_dir}/etc/apt/sources.list.d/ubuntu.sources
+ sudo sed -i "/URIs:/a Trusted: yes" ${mount_dir}/etc/apt/sources.list.d/ubuntu.sources
+ elif sudo test -f ${mount_dir}/etc/apt/sources.list; then
+ source <(sudo cat ${mount_dir}/etc/os-release)
+ sudo tee ${mount_dir}/etc/apt/sources.list <<EOF
+ deb [ trusted=yes ] https://${mirror}/ubuntu ${UBUNTU_CODENAME} main universe
+ deb [ trusted=yes ] https://${mirror}/ubuntu ${UBUNTU_CODENAME}-updates main universe
+ deb [ trusted=yes ] https://${mirror}/ubuntu ${UBUNTU_CODENAME}-backports main universe
+ deb [ trusted=yes ] https://${mirror}/ubuntu ${UBUNTU_CODENAME}-security main universe
EOF
+ fi
fi
fi
diff --git a/zuul.d/2023_1_jobs.yaml b/zuul.d/2023_1_jobs.yaml
index d69054c..824c4b2 100644
--- a/zuul.d/2023_1_jobs.yaml
+++ b/zuul.d/2023_1_jobs.yaml
@@ -2,7 +2,11 @@
name: neutron-tempest-plugin-openvswitch-2023-1
parent: neutron-tempest-plugin-openvswitch
nodeset: neutron-nested-virt-ubuntu-jammy
- override-checkout: stable/2023.1
+ required-projects: &required-projects-2023-1
+ - openstack/neutron
+ - name: openstack/neutron-tempest-plugin
+ override-checkout: 2023.1-last
+ - openstack/tempest
vars:
network_api_extensions_openvswitch:
- dhcp_agent_scheduler
@@ -107,7 +111,7 @@
name: neutron-tempest-plugin-openvswitch-iptables_hybrid-2023-1
parent: neutron-tempest-plugin-openvswitch-iptables_hybrid
nodeset: neutron-nested-virt-ubuntu-jammy
- override-checkout: stable/2023.1
+ required-projects: *required-projects-2023-1
vars:
network_api_extensions_common: *api_extensions
network_api_extensions_openvswitch:
@@ -146,7 +150,7 @@
name: neutron-tempest-plugin-openvswitch-enforce-scope-new-defaults-2023-1
parent: neutron-tempest-plugin-openvswitch-2023-1
nodeset: neutron-nested-virt-ubuntu-jammy
- override-checkout: stable/2023.1
+ required-projects: *required-projects-2023-1
vars:
devstack_localrc:
# Enabeling the scope and new defaults for services.
@@ -164,7 +168,7 @@
name: neutron-tempest-plugin-linuxbridge-2023-1
parent: neutron-tempest-plugin-linuxbridge
nodeset: neutron-nested-virt-ubuntu-jammy
- override-checkout: stable/2023.1
+ required-projects: *required-projects-2023-1
vars:
network_api_extensions_common: *api_extensions
network_api_extensions_linuxbridge:
@@ -207,7 +211,7 @@
name: neutron-tempest-plugin-ovn-2023-1
parent: neutron-tempest-plugin-ovn
nodeset: neutron-nested-virt-ubuntu-jammy
- override-checkout: stable/2023.1
+ required-projects: *required-projects-2023-1
vars:
network_api_extensions_ovn:
- vlan-transparent
@@ -218,9 +222,13 @@
(^tempest.api.compute.servers.test_multiple_create)"
# NOTE(liushy): This branch of Neutron does not support
# the address_group feature for the OVN driver.
+ # NOTE(ralonsoh): The advance image used "ubuntu-22.04-minimal" has a reported issue (LP#2110520)
+ # with the IGMP report messages. Because of that and because ML2/OVN has "igmp_snooping_enable"
+ # set, the receiver VM cannot subscribe to the IGMP group nor receive any IGMP message.
tempest_exclude_regex: "\
(^neutron_tempest_plugin.scenario.test_security_groups.StatefulNetworkSecGroupTest.test_remote_group_and_remote_address_group)|\
- (^neutron_tempest_plugin.scenario.test_security_groups.StatelessNetworkSecGroupIPv4Test.test_remote_group_and_remote_address_group)"
+ (^neutron_tempest_plugin.scenario.test_security_groups.StatelessNetworkSecGroupIPv4Test.test_remote_group_and_remote_address_group)|\
+ (^neutron_tempest_plugin.scenario.test_multicast.MulticastTestIPv4.test_multicast_between_vms_on_same_network)"
devstack_localrc:
NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_ovn) | join(',') }}"
NEUTRON_DEPLOY_MOD_WSGI: false
@@ -241,7 +249,7 @@
name: neutron-tempest-plugin-dvr-multinode-scenario-2023-1
parent: neutron-tempest-plugin-dvr-multinode-scenario
nodeset: openstack-two-node-jammy
- override-checkout: stable/2023.1
+ required-projects: *required-projects-2023-1
vars:
network_api_extensions_common: *api_extensions
network_api_extensions_dvr:
@@ -255,7 +263,7 @@
name: neutron-tempest-plugin-designate-scenario-2023-1
parent: neutron-tempest-plugin-designate-scenario
nodeset: neutron-nested-virt-ubuntu-jammy
- override-checkout: stable/2023.1
+ required-projects: *required-projects-2023-1
vars:
network_api_extensions_common: *api_extensions
devstack_localrc:
@@ -265,7 +273,7 @@
name: neutron-tempest-plugin-sfc-2023-1
parent: neutron-tempest-plugin-sfc
nodeset: openstack-single-node-jammy
- override-checkout: stable/2023.1
+ required-projects: *required-projects-2023-1
vars:
devstack_localrc:
NEUTRON_DEPLOY_MOD_WSGI: false
@@ -274,7 +282,7 @@
name: neutron-tempest-plugin-bgpvpn-bagpipe-2023-1
parent: neutron-tempest-plugin-bgpvpn-bagpipe
nodeset: openstack-single-node-jammy
- override-checkout: stable/2023.1
+ required-projects: *required-projects-2023-1
vars:
devstack_localrc:
NEUTRON_DEPLOY_MOD_WSGI: false
@@ -283,7 +291,7 @@
name: neutron-tempest-plugin-dynamic-routing-2023-1
parent: neutron-tempest-plugin-dynamic-routing
nodeset: openstack-single-node-jammy
- override-checkout: stable/2023.1
+ required-projects: *required-projects-2023-1
vars:
devstack_localrc:
NEUTRON_DEPLOY_MOD_WSGI: false
@@ -298,7 +306,7 @@
name: neutron-tempest-plugin-fwaas-2023-1
parent: neutron-tempest-plugin-fwaas-openvswitch
nodeset: openstack-single-node-jammy
- override-checkout: stable/2023.1
+ required-projects: *required-projects-2023-1
vars:
devstack_localrc:
NEUTRON_DEPLOY_MOD_WSGI: false
@@ -307,7 +315,7 @@
name: neutron-tempest-plugin-vpnaas-2023-1
parent: neutron-tempest-plugin-vpnaas
nodeset: openstack-single-node-jammy
- override-checkout: stable/2023.1
+ required-projects: *required-projects-2023-1
vars:
devstack_localrc:
NEUTRON_DEPLOY_MOD_WSGI: false
@@ -316,7 +324,11 @@
name: neutron-tempest-plugin-tap-as-a-service-2023-1
parent: neutron-tempest-plugin-tap-as-a-service
nodeset: openstack-single-node-jammy
- override-checkout: stable/2023.1
+ 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
diff --git a/zuul.d/2024_1_jobs.yaml b/zuul.d/2024_1_jobs.yaml
index 674d1ab..65fa585 100644
--- a/zuul.d/2024_1_jobs.yaml
+++ b/zuul.d/2024_1_jobs.yaml
@@ -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
diff --git a/zuul.d/2024_2_jobs.yaml b/zuul.d/2024_2_jobs.yaml
index e19767c..d54cf35 100644
--- a/zuul.d/2024_2_jobs.yaml
+++ b/zuul.d/2024_2_jobs.yaml
@@ -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
diff --git a/zuul.d/2025_1_jobs.yaml b/zuul.d/2025_1_jobs.yaml
index d4093f0..f0c1da5 100644
--- a/zuul.d/2025_1_jobs.yaml
+++ b/zuul.d/2025_1_jobs.yaml
@@ -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
diff --git a/zuul.d/master_jobs.yaml b/zuul.d/master_jobs.yaml
index d604c80..4f7a08e 100644
--- a/zuul.d/master_jobs.yaml
+++ b/zuul.d/master_jobs.yaml
@@ -1509,12 +1509,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:
@@ -1566,10 +1568,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$
@@ -1601,3 +1604,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
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
index f9f70dd..1720745 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -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:
diff --git a/zuul.d/xena_jobs.yaml b/zuul.d/xena_jobs.yaml
index 847c611..7d58efa 100644
--- a/zuul.d/xena_jobs.yaml
+++ b/zuul.d/xena_jobs.yaml
@@ -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
diff --git a/zuul.d/yoga_jobs.yaml b/zuul.d/yoga_jobs.yaml
index 2c18450..72a659e 100644
--- a/zuul.d/yoga_jobs.yaml
+++ b/zuul.d/yoga_jobs.yaml
@@ -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
diff --git a/zuul.d/zed_jobs.yaml b/zuul.d/zed_jobs.yaml
index fe98935..9c40f76 100644
--- a/zuul.d/zed_jobs.yaml
+++ b/zuul.d/zed_jobs.yaml
@@ -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