Merge "Specify network type in ``NetworkSegmentRangeTestJson``"
diff --git a/neutron_tempest_plugin/api/base.py b/neutron_tempest_plugin/api/base.py
index 4bcc6d2..178bf99 100644
--- a/neutron_tempest_plugin/api/base.py
+++ b/neutron_tempest_plugin/api/base.py
@@ -18,6 +18,7 @@
import time
import netaddr
+from neutron_lib._i18n import _
from neutron_lib import constants as const
from oslo_log import log
from tempest.common import utils as tutils
@@ -492,7 +493,7 @@
if ip_version:
if ip_version != gateway_ip.version:
raise ValueError(
- "Gateway IP version doesn't match IP version")
+ _("Gateway IP version doesn't match IP version"))
else:
ip_version = gateway_ip.version
else:
@@ -541,8 +542,8 @@
"""
if not cls.try_reserve_subnet_cidr(addr, **ipnetwork_kwargs):
- raise ValueError('Subnet CIDR already reserved: {0!r}'.format(
- addr))
+ raise ValueError(_('Subnet CIDR already reserved: {0!r}'.format(
+ addr)))
@classmethod
def try_reserve_subnet_cidr(cls, addr, **ipnetwork_kwargs):
@@ -601,7 +602,8 @@
mask_bits = CONF.network.project_network_v6_mask_bits
cidr = netaddr.IPNetwork(CONF.network.project_network_v6_cidr)
else:
- raise ValueError('Invalid IP version: {!r}'.format(ip_version))
+ raise ValueError(_(
+ 'Invalid IP version: {!r}'.format(ip_version)))
if mask_bits:
subnet_cidrs = cidr.subnet(mask_bits)
@@ -687,8 +689,9 @@
if port:
port_id = kwargs.setdefault('port_id', port['id'])
if port_id != port['id']:
- message = "Port ID specified twice: {!s} != {!s}".format(
- port_id, port['id'])
+ message = _(
+ "Port ID specified twice: {!s} != {!s}".format(
+ port_id, port['id']))
raise ValueError(message)
fip = client.create_floatingip(external_network_id,
@@ -985,7 +988,7 @@
project_id = kwargs.setdefault('project_id', project['id'])
tenant_id = kwargs.setdefault('tenant_id', project['id'])
if project_id != project['id'] or tenant_id != project['id']:
- raise ValueError('Project ID specified multiple times')
+ raise ValueError(_('Project ID specified multiple times'))
else:
client = client or cls.client
@@ -1008,7 +1011,7 @@
for security_group in security_groups:
if security_group['name'] == name:
return security_group
- raise ValueError("No such security group named {!r}".format(name))
+ raise ValueError(_("No such security group named {!r}".format(name)))
@classmethod
def create_security_group_rule(cls, security_group=None, project=None,
@@ -1018,7 +1021,7 @@
project_id = kwargs.setdefault('project_id', project['id'])
tenant_id = kwargs.setdefault('tenant_id', project['id'])
if project_id != project['id'] or tenant_id != project['id']:
- raise ValueError('Project ID specified multiple times')
+ raise ValueError(_('Project ID specified multiple times'))
if 'security_group_id' not in kwargs:
security_group = (security_group or
@@ -1029,7 +1032,8 @@
security_group_id = kwargs.setdefault('security_group_id',
security_group['id'])
if security_group_id != security_group['id']:
- raise ValueError('Security group ID specified multiple times.')
+ raise ValueError(
+ _('Security group ID specified multiple times.'))
ip_version = ip_version or cls._ip_version
default_params = (
diff --git a/neutron_tempest_plugin/api/test_networks.py b/neutron_tempest_plugin/api/test_networks.py
index d79b7ab..b9298c3 100644
--- a/neutron_tempest_plugin/api/test_networks.py
+++ b/neutron_tempest_plugin/api/test_networks.py
@@ -132,8 +132,6 @@
_check_list_networks_fields(['project_id', 'tenant_id'], True, True)
-# TODO(ihrachys): check that bad mtu is not allowed; current API extension
-# definition doesn't enforce values
# TODO(ihrachys): check that new segment reservation updates mtu, once
# https://review.opendev.org/#/c/353115/ is merged
class NetworksMtuTestJSON(base.BaseNetworkTest):
diff --git a/neutron_tempest_plugin/api/test_networks_negative.py b/neutron_tempest_plugin/api/test_networks_negative.py
index d4941e4..f0f6995 100644
--- a/neutron_tempest_plugin/api/test_networks_negative.py
+++ b/neutron_tempest_plugin/api/test_networks_negative.py
@@ -43,3 +43,37 @@
with testtools.ExpectedException(lib_exc.BadRequest):
self.client.create_network(
mtu=CONF.neutron_plugin_options.max_mtu + 1)
+
+ @decorators.attr(type='negative')
+ @decorators.idempotent_id('53537bba-d6c3-4a2e-bda4-ab5b009fb7d9')
+ def test_create_subnet_mtu_below_minimum_ipv4(self):
+ network = self.create_network(mtu=67)
+ with testtools.ExpectedException(lib_exc.Conflict):
+ self.create_subnet(network, ip_version=4, cidr='10.0.0.0/24')
+
+ @decorators.attr(type='negative')
+ @decorators.idempotent_id('1de68cb6-e6d4-47df-b820-c5048796f33a')
+ @testtools.skipUnless(config.CONF.network_feature_enabled.ipv6,
+ 'IPv6 is not enabled')
+ def test_create_subnet_mtu_below_minimum_ipv6(self):
+ network = self.create_network(mtu=1279)
+ with testtools.ExpectedException(lib_exc.Conflict):
+ self.create_subnet(network, ip_version=6, cidr='2001:db8:0:1::/64')
+
+ @decorators.attr(type='negative')
+ @decorators.idempotent_id('5213df6d-7141-40b2-90ea-a958d9bc97e5')
+ def test_update_network_mtu_below_minimum_ipv4(self):
+ network = self.create_network(mtu=1280)
+ self.create_subnet(network, ip_version=4, cidr='10.0.0.0/24')
+ with testtools.ExpectedException(lib_exc.Conflict):
+ self.client.update_network(network['id'], mtu=67)
+
+ @decorators.attr(type='negative')
+ @decorators.idempotent_id('1a714fc4-24b1-4c07-a005-d5c218672eab')
+ @testtools.skipUnless(config.CONF.network_feature_enabled.ipv6,
+ 'IPv6 is not enabled')
+ def test_update_network_mtu_below_minimum_ipv6(self):
+ network = self.create_network(mtu=1280)
+ self.create_subnet(network, ip_version=6, cidr='2001:db8:0:1::/64')
+ with testtools.ExpectedException(lib_exc.Conflict):
+ self.client.update_network(network['id'], mtu=1279)
diff --git a/neutron_tempest_plugin/bgpvpn/scenario/test_bgpvpn_basic.py b/neutron_tempest_plugin/bgpvpn/scenario/test_bgpvpn_basic.py
index 9cca602..c9f4bcc 100644
--- a/neutron_tempest_plugin/bgpvpn/scenario/test_bgpvpn_basic.py
+++ b/neutron_tempest_plugin/bgpvpn/scenario/test_bgpvpn_basic.py
@@ -17,6 +17,7 @@
import random
import netaddr
+from neutron_lib._i18n import _
from neutron_lib.utils import test
from oslo_concurrency import lockutils
from oslo_log import log as logging
@@ -42,8 +43,8 @@
if "SUBNETPOOL_PREFIX_V4" in os.environ:
subnet_base = netaddr.IPNetwork(os.environ['SUBNETPOOL_PREFIX_V4'])
if subnet_base.prefixlen > 21:
- raise Exception("if SUBNETPOOL_PREFIX_V4 is set, it needs to offer "
- "space for at least 8 /24 subnets")
+ raise Exception(_("if SUBNETPOOL_PREFIX_V4 is set, it needs to offer "
+ "space for at least 8 /24 subnets"))
else:
subnet_base = netaddr.IPNetwork("10.100.0.0/16")
diff --git a/neutron_tempest_plugin/common/ip.py b/neutron_tempest_plugin/common/ip.py
index e87219b..bab9064 100644
--- a/neutron_tempest_plugin/common/ip.py
+++ b/neutron_tempest_plugin/common/ip.py
@@ -19,6 +19,7 @@
import subprocess
import netaddr
+from neutron_lib._i18n import _
from neutron_lib import constants
from oslo_log import log
from oslo_utils import excutils
@@ -89,9 +90,9 @@
for ip, prefix_len in _get_ip_address_prefix_len_pairs(
port=subport, subnets=subnets)]
if not subport_ips:
- raise ValueError(
+ raise ValueError(_(
"Unable to get IP address and subnet prefix lengths for "
- "subport")
+ "subport"))
return self.configure_vlan(addresses, port, vlan_tag, subport_ips,
subport['mac_address'])
@@ -353,7 +354,7 @@
for address in list_ip_addresses(addresses=addresses, port=port):
return address.device.name
- msg = "Port {0!r} fixed IPs not found on server.".format(port['id'])
+ msg = _("Port {0!r} fixed IPs not found on server.".format(port['id']))
raise ValueError(msg)
@@ -362,7 +363,8 @@
ip_addresses=ip_addresses):
return address.device.name
- msg = "Fixed IPs {0!r} not found on server.".format(' '.join(ip_addresses))
+ msg = _(
+ "Fixed IPs {0!r} not found on server.".format(' '.join(ip_addresses)))
raise ValueError(msg)
diff --git a/neutron_tempest_plugin/common/shell.py b/neutron_tempest_plugin/common/shell.py
index 073bf55..723c30e 100644
--- a/neutron_tempest_plugin/common/shell.py
+++ b/neutron_tempest_plugin/common/shell.py
@@ -16,7 +16,6 @@
import collections
import subprocess
-import sys
from oslo_log import log
from tempest.lib import exceptions as lib_exc
@@ -131,12 +130,6 @@
stdout=subprocess.PIPE,
stderr=subprocess.PIPE)
- if timeout and sys.version_info < (3, 3):
- # TODO(fressi): re-implement to timeout support on older Pythons
- LOG.warning("Popen.communicate method doens't support for timeout "
- "on Python %r", sys.version)
- timeout = None
-
# Wait for process execution while reading STDERR and STDOUT streams
if timeout:
try:
diff --git a/neutron_tempest_plugin/common/ssh.py b/neutron_tempest_plugin/common/ssh.py
index 6e7e2c5..b0dd9c1 100644
--- a/neutron_tempest_plugin/common/ssh.py
+++ b/neutron_tempest_plugin/common/ssh.py
@@ -17,6 +17,7 @@
import socket
import time
+from neutron_lib._i18n import _
from oslo_log import log
import paramiko
from tempest.lib.common import ssh
@@ -70,8 +71,8 @@
host = cls.proxy_jump_host
if not host:
# proxy_jump_host string cannot be empty or None
- raise ValueError(
- "'proxy_jump_host' configuration option is empty.")
+ raise ValueError(_(
+ "'proxy_jump_host' configuration option is empty."))
# Let accept an empty string as a synonymous of default value on below
# options
@@ -82,9 +83,9 @@
# Port must be a positive integer
port = cls.proxy_jump_port
if port <= 0 or port > 65535:
- raise ValueError(
+ raise ValueError(_(
"Invalid value for 'proxy_jump_port' configuration option: "
- "{!r}".format(port))
+ "{!r}".format(port)))
login = "{username}@{host}:{port}".format(username=username, host=host,
port=port)
@@ -99,9 +100,9 @@
else:
# This message could help the user to identify a
# mis-configuration in tempest.conf
- raise ValueError(
+ raise ValueError(_(
"Cannot find file specified as 'proxy_jump_keyfile' "
- "option: {!r}".format(key_file))
+ "option: {!r}".format(key_file)))
elif password:
LOG.debug("Going to create SSH connection to %r using password.",
diff --git a/neutron_tempest_plugin/common/utils.py b/neutron_tempest_plugin/common/utils.py
index 62191bf..5d6a26a 100644
--- a/neutron_tempest_plugin/common/utils.py
+++ b/neutron_tempest_plugin/common/utils.py
@@ -25,8 +25,7 @@
except ImportError:
from urllib import parse as urlparse
-import eventlet
-
+from neutron_lib._i18n import _
from oslo_log import log
from tempest.lib import exceptions
@@ -79,15 +78,14 @@
:param exception: Exception instance to raise on timeout. If None is passed
(default) then WaitTimeout exception is raised.
"""
- try:
- with eventlet.Timeout(timeout):
- while not predicate():
- eventlet.sleep(sleep)
- except eventlet.Timeout:
- if exception is not None:
- # pylint: disable=raising-bad-type
- raise exception
- raise WaitTimeout("Timed out after %d seconds" % timeout)
+ start_time = time.time()
+ while not predicate():
+ elapsed_time = time.time() - start_time
+ if elapsed_time > timeout:
+ raise exception if exception else WaitTimeout(
+ _("Timed out after %d seconds") % timeout
+ )
+ time.sleep(sleep)
def override_class(overriden_class, overrider_class):
diff --git a/neutron_tempest_plugin/config.py b/neutron_tempest_plugin/config.py
index 880d3a6..1f5c34c 100644
--- a/neutron_tempest_plugin/config.py
+++ b/neutron_tempest_plugin/config.py
@@ -144,14 +144,12 @@
# while testing in parallel.
cfg.BoolOpt('create_shared_resources',
default=False,
- help='Allow creation of shared resources.'
- 'The default value is false.'),
+ help='Allow creation of shared resources.'),
cfg.BoolOpt('is_igmp_snooping_enabled',
default=False,
help='Indicates whether IGMP snooping is enabled or not. '
'If True, multicast test(s) will assert that multicast '
- 'traffic is not being flooded to all ports. Defaults '
- 'to False.'),
+ 'traffic is not being flooded to all ports.'),
# Option for scheduling BGP speakers to agents explicitly
# The default is false with automatic scheduling on creation
# happening with the default scheduler
diff --git a/neutron_tempest_plugin/scenario/base.py b/neutron_tempest_plugin/scenario/base.py
index d299c47..f7d08eb 100644
--- a/neutron_tempest_plugin/scenario/base.py
+++ b/neutron_tempest_plugin/scenario/base.py
@@ -18,6 +18,7 @@
from debtcollector import removals
import netaddr
+from neutron_lib._i18n import _
from neutron_lib.api import validators
from neutron_lib import constants as neutron_lib_constants
from oslo_log import log
@@ -680,8 +681,8 @@
router = client.update_router(router['id'], **kwargs)['router']
return router
else:
- raise Exception("Neither of 'public_router_id' or "
- "'public_network_id' has been defined.")
+ raise Exception(_("Neither of 'public_router_id' or "
+ "'public_network_id' has been defined."))
def _update_router_admin_state(self, router, admin_state_up):
kwargs = dict(admin_state_up=admin_state_up)
diff --git a/neutron_tempest_plugin/scenario/test_multicast.py b/neutron_tempest_plugin/scenario/test_multicast.py
index 390e0f0..a28328b 100644
--- a/neutron_tempest_plugin/scenario/test_multicast.py
+++ b/neutron_tempest_plugin/scenario/test_multicast.py
@@ -333,12 +333,20 @@
"Receiver {!r} didn't get multicast message".format(
receiver['id'])))
- # TODO(slaweq): add validation of answears on sended server
- replies_result = sender['ssh_client'].execute_script(
- "cat {path} || echo '{path} not exists yet'".format(
- path=self.sender_output_file))
- for receiver_id in receiver_ids:
- self.assertIn(receiver_id, replies_result)
+ def _sender_completed():
+ replies_result = sender['ssh_client'].execute_script(
+ "cat {path} 2>/dev/null || echo ''".format(
+ path=self.sender_output_file))
+ for receiver_id in receiver_ids:
+ expected_pattern = "received reply b'{}' from".format(
+ receiver_id)
+ if expected_pattern not in replies_result:
+ return False
+ return replies_result.count('received reply') == len(receiver_ids)
+
+ utils.wait_until_true(
+ _sender_completed,
+ exception=RuntimeError("Sender didn't complete properly"))
def check_unregistered_host():
unregistered_result = unregistered['ssh_client'].execute_script(
diff --git a/neutron_tempest_plugin/scenario/test_multiple_gws.py b/neutron_tempest_plugin/scenario/test_multiple_gws.py
index e4f1d3d..51d047a 100644
--- a/neutron_tempest_plugin/scenario/test_multiple_gws.py
+++ b/neutron_tempest_plugin/scenario/test_multiple_gws.py
@@ -12,7 +12,7 @@
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
-import json
+
import os
import subprocess
import time
@@ -29,6 +29,7 @@
from neutron_lib import constants as const
from oslo_log import log
+from oslo_serialization import jsonutils
from os_ken.tests.integrated.common import docker_base as ctn_base
@@ -288,7 +289,7 @@
)
def show_bfd_peer(self, peer: str) -> typing.Dict[str, typing.Any]:
- return json.loads(self.vtysh([f'show bfd peer {peer} json']))
+ return jsonutils.loads(self.vtysh([f'show bfd peer {peer} json']))
def wait_for_bfd_peer_status(
self, peer: str, status: str, try_times=30, interval=1
diff --git a/neutron_tempest_plugin/services/network/json/network_client.py b/neutron_tempest_plugin/services/network/json/network_client.py
index 289ef61..f5583f2 100644
--- a/neutron_tempest_plugin/services/network/json/network_client.py
+++ b/neutron_tempest_plugin/services/network/json/network_client.py
@@ -13,6 +13,7 @@
import time
from urllib import parse as urlparse
+from neutron_lib._i18n import _
from oslo_serialization import jsonutils
from tempest.lib.common import rest_client as service_client
from tempest.lib import exceptions as lib_exc
@@ -304,7 +305,7 @@
try:
getattr(self, method)(id)
except AttributeError:
- raise Exception("Unknown resource type %s " % resource_type)
+ raise Exception(_("Unknown resource type %s " % resource_type))
except lib_exc.NotFound:
return True
return False
diff --git a/requirements.txt b/requirements.txt
index 957f186..478c1fa 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -12,5 +12,4 @@
tenacity>=3.2.1 # Apache-2.0
ddt>=1.0.1 # MIT
testtools>=2.2.0 # MIT
-eventlet>=0.21.0 # MIT
debtcollector>=1.2.0 # Apache-2.0
diff --git a/tox.ini b/tox.ini
index 21574f4..5f4d1e9 100644
--- a/tox.ini
+++ b/tox.ini
@@ -62,6 +62,7 @@
# E129 visually indented line with same indent as next logical line
# I202 Additional newline in a group of imports.
# N530 direct neutron imports not allowed
+# N535 prevent eventlet library import
# W504 line break after binary operator
ignore = E126,E128,E129,I202,N530,W504
# H106: Don't put vim configuration in source files
diff --git a/zuul.d/2025_1_jobs.yaml b/zuul.d/2025_1_jobs.yaml
index f0c1da5..793d8e3 100644
--- a/zuul.d/2025_1_jobs.yaml
+++ b/zuul.d/2025_1_jobs.yaml
@@ -97,6 +97,7 @@
- trunk
- trunk-details
- uplink-status-propagation
+ - uplink-status-propagation-updatable
devstack_localrc:
NETWORK_API_EXTENSIONS: "{{ (network_api_extensions_common + network_api_extensions_openvswitch) | join(',') }}"
devstack_local_conf:
diff --git a/zuul.d/master_jobs.yaml b/zuul.d/master_jobs.yaml
index 4c2e400..4484768 100644
--- a/zuul.d/master_jobs.yaml
+++ b/zuul.d/master_jobs.yaml
@@ -34,8 +34,6 @@
ADVANCED_INSTANCE_USER: ubuntu
CUSTOMIZE_IMAGE: true
BUILD_TIMEOUT: 784
- # TODO(lucasagomes): Re-enable MOD_WSGI after
- # https://bugs.launchpad.net/neutron/+bug/1912359 is implemented
NEUTRON_DEPLOY_MOD_WSGI: true
devstack_plugins:
neutron: https://opendev.org/openstack/neutron.git
@@ -127,6 +125,7 @@
- trunk
- trunk-details
- uplink-status-propagation
+ - uplink-status-propagation-updatable
devstack_services:
tempest: true
neutron-dns: true
@@ -1024,7 +1023,6 @@
- ^neutron/privileged/.*$
- ^neutron/plugins/ml2/drivers/.*$
- ^neutron/scheduler/.*$
- - ^neutron/services/.*$
- ^neutron_tempest_plugin/api/test_.*$
- ^neutron_tempest_plugin/api/admin/test_.*$
- ^neutron_tempest_plugin/(bgpvpn|fwaas|neutron_dynamic_routing|sfc|tap_as_a_service|vpnaas).*$
diff --git a/zuul.d/project.yaml b/zuul.d/project.yaml
index 1720745..69a380c 100644
--- a/zuul.d/project.yaml
+++ b/zuul.d/project.yaml
@@ -213,14 +213,7 @@
- neutron-tempest-plugin-bgpvpn-bagpipe-2024-1
- neutron-tempest-plugin-bgpvpn-bagpipe-2024-2
- neutron-tempest-plugin-bgpvpn-bagpipe-2025-1
- - neutron-tempest-plugin-dynamic-routing:
- # TODO(ralonsoh): this job is temporarily disabled; it will be
- # restored once [1] is merged. This patch has been successfully
- # tested in [2]. This job is removed from the gate queue,
- # thus **remember to restore it in this queue too**.
- # [1]https://review.opendev.org/c/openstack/neutron/+/941202
- # [2]https://review.opendev.org/c/openstack/neutron-tempest-plugin/+/940906
- voting: false
+ - neutron-tempest-plugin-dynamic-routing
- neutron-tempest-plugin-dynamic-routing-2024-1
- neutron-tempest-plugin-dynamic-routing-2024-2
- neutron-tempest-plugin-dynamic-routing-2025-1
@@ -245,5 +238,6 @@
jobs:
- neutron-tempest-plugin-sfc
- neutron-tempest-plugin-bgpvpn-bagpipe
+ - neutron-tempest-plugin-dynamic-routing
- neutron-tempest-plugin-fwaas-ovn
- neutron-tempest-plugin-vpnaas-ovn