Merge "Fix intermittent port_forwarding test failures"
diff --git a/.zuul.yaml b/.zuul.yaml
index ceb7bc2..c7cd10e 100644
--- a/.zuul.yaml
+++ b/.zuul.yaml
@@ -110,7 +110,7 @@
QUOTAS:
quota_router: 100
quota_floatingip: 500
- quota_security_group: 100
+ quota_security_group: 150
quota_security_group_rule: 1000
# NOTE(slaweq): We can get rid of this hardcoded absolute path when
# devstack-tempest job will be switched to use lib/neutron instead of
@@ -1079,6 +1079,8 @@
- openstack/neutron
- name: openstack/neutron-tempest-plugin
override-checkout: 0.3.0
+ - name: openstack/designate-tempest-plugin
+ override-checkout: 0.7.0
- openstack/tempest
vars:
branch_override: stable/queens
@@ -1098,6 +1100,13 @@
This job run on py2 for stable/rocky gate.
nodeset: openstack-single-node-xenial
override-checkout: stable/rocky
+ required-projects:
+ - openstack/devstack-gate
+ - openstack/neutron
+ - openstack/neutron-tempest-plugin
+ - name: openstack/designate-tempest-plugin
+ override-checkout: 0.7.0
+ - openstack/tempest
vars: &designate_scenario_vars_rocky
branch_override: stable/rocky
network_api_extensions_common: *api_extensions_rocky
@@ -1113,7 +1122,7 @@
nodeset: openstack-single-node-xenial
description: |
This job run on py3 for other than stable/rocky gate
- which is nothing but neutron-tempest-pluign master gate.
+ which is nothing but neutron-tempest-plugin master gate.
override-checkout: stable/rocky
vars:
<<: *designate_scenario_vars_rocky
@@ -1125,6 +1134,13 @@
name: neutron-tempest-plugin-designate-scenario-stein
parent: neutron-tempest-plugin-designate-scenario
override-checkout: stable/stein
+ required-projects:
+ - openstack/devstack-gate
+ - openstack/neutron
+ - openstack/neutron-tempest-plugin
+ - name: openstack/designate-tempest-plugin
+ override-checkout: 0.7.0
+ - openstack/tempest
vars:
branch_override: stable/stein
network_api_extensions_common: *api_extensions_stein
@@ -1375,7 +1391,10 @@
jobs:
- neutron-tempest-plugin-sfc
- neutron-tempest-plugin-sfc-train
- - neutron-tempest-plugin-bgpvpn-bagpipe
+ - neutron-tempest-plugin-bgpvpn-bagpipe:
+ # TODO(bcafarel): switch back to voting when
+ # https://review.opendev.org/708648 is merged
+ voting: false
- neutron-tempest-plugin-bgpvpn-bagpipe-train
- neutron-tempest-plugin-fwaas:
# TODO(slaweq): switch it to be voting when bug
@@ -1391,7 +1410,9 @@
gate:
jobs:
- neutron-tempest-plugin-sfc
- - neutron-tempest-plugin-bgpvpn-bagpipe
+ # TODO(bcafarel): bring back to gate queue when
+ # https://review.opendev.org/708648 is merged
+ # - neutron-tempest-plugin-bgpvpn-bagpipe
# TODO(slaweq): bring it back to gate queue
# https://bugs.launchpad.net/neutron/+bug/1858645 will be fixed
# - neutron-tempest-plugin-fwaas
diff --git a/neutron_tempest_plugin/common/utils.py b/neutron_tempest_plugin/common/utils.py
index 631f75b..c8ff194 100644
--- a/neutron_tempest_plugin/common/utils.py
+++ b/neutron_tempest_plugin/common/utils.py
@@ -26,6 +26,7 @@
from urllib import parse as urlparse
import eventlet
+from tempest.lib import exceptions
SCHEMA_PORT_MAPPING = {
"http": 80,
@@ -106,3 +107,22 @@
if scheme in SCHEMA_PORT_MAPPING and not port:
netloc = netloc + ":" + str(SCHEMA_PORT_MAPPING[scheme])
return urlparse.urlunparse((scheme, netloc, url, params, query, fragment))
+
+
+def kill_nc_process(ssh_client):
+ cmd = "killall -q nc"
+ try:
+ ssh_client.exec_command(cmd)
+ except exceptions.SSHExecCommandFailed:
+ pass
+
+
+def spawn_http_server(ssh_client, port, message):
+ cmd = ("(echo -e 'HTTP/1.1 200 OK\r\n'; echo '%(msg)s') "
+ "| sudo nc -lp %(port)d &" % {'msg': message, 'port': port})
+ ssh_client.exec_command(cmd)
+
+
+def call_url_remote(ssh_client, url):
+ cmd = "curl %s --retry 3 --connect-timeout 2" % url
+ return ssh_client.exec_command(cmd)
diff --git a/neutron_tempest_plugin/scenario/test_qos.py b/neutron_tempest_plugin/scenario/test_qos.py
index ba8cc88..f8f1b03 100644
--- a/neutron_tempest_plugin/scenario/test_qos.py
+++ b/neutron_tempest_plugin/scenario/test_qos.py
@@ -20,7 +20,6 @@
from oslo_log import log as logging
from tempest.common import utils as tutils
from tempest.lib import decorators
-from tempest.lib import exceptions
from neutron_tempest_plugin.api import base as base_api
from neutron_tempest_plugin.common import ssh
@@ -92,16 +91,8 @@
raise sc_exceptions.FileCreationFailedException(
file=self.FILE_PATH)
- @staticmethod
- def _kill_nc_process(ssh_client):
- cmd = "killall -q nc"
- try:
- ssh_client.exec_command(cmd, timeout=5)
- except exceptions.SSHExecCommandFailed:
- pass
-
def _check_bw(self, ssh_client, host, port, expected_bw=LIMIT_BYTES_SEC):
- self._kill_nc_process(ssh_client)
+ utils.kill_nc_process(ssh_client)
cmd = ("(nc -ll -p %(port)d < %(file_path)s > /dev/null &)" % {
'port': port, 'file_path': self.FILE_PATH})
ssh_client.exec_command(cmd, timeout=5)
@@ -130,7 +121,7 @@
except socket.timeout:
LOG.warning('Socket timeout while reading the remote file, bytes '
'read: %s', total_bytes_read)
- self._kill_nc_process(ssh_client)
+ utils.kill_nc_process(ssh_client)
return False
finally:
client_socket.close()
diff --git a/neutron_tempest_plugin/scenario/test_security_groups.py b/neutron_tempest_plugin/scenario/test_security_groups.py
index 7b43a7e..83bb55c 100644
--- a/neutron_tempest_plugin/scenario/test_security_groups.py
+++ b/neutron_tempest_plugin/scenario/test_security_groups.py
@@ -19,6 +19,7 @@
from tempest.lib import decorators
from neutron_tempest_plugin.common import ssh
+from neutron_tempest_plugin.common import utils
from neutron_tempest_plugin import config
from neutron_tempest_plugin.scenario import base
from neutron_tempest_plugin.scenario import constants as const
@@ -30,6 +31,33 @@
credentials = ['primary', 'admin']
required_extensions = ['router', 'security-group']
+ def _verify_http_connection(self, ssh_client, ssh_server,
+ test_ip, test_port, should_pass=True):
+ """Verify if HTTP connection works using remote hosts.
+
+ :param ssh.Client ssh_client: The client host active SSH client.
+ :param ssh.Client ssh_server: The HTTP server host active SSH client.
+ :param string test_ip: IP address of HTTP server
+ :param string test_port: Port of HTTP server
+ :param bool should_pass: Wheter test should pass or not.
+
+ :return: if passed or not
+ :rtype: bool
+ """
+ utils.kill_nc_process(ssh_server)
+ url = 'http://%s:%d' % (test_ip, test_port)
+ utils.spawn_http_server(ssh_server, port=test_port, message='foo_ok')
+ try:
+ ret = utils.call_url_remote(ssh_client, url)
+ if should_pass:
+ self.assertIn('foo_ok', ret)
+ return
+ self.assertNotIn('foo_ok', ret)
+ except Exception as e:
+ if not should_pass:
+ return
+ raise e
+
@classmethod
def resource_setup(cls):
super(NetworkSecGroupTest, cls).resource_setup()
@@ -293,3 +321,65 @@
self.check_connectivity(fip['floating_ip_address'],
CONF.validation.image_ssh_user,
self.keypair['private_key'])
+
+ @decorators.idempotent_id('f07d0159-8f9e-4faa-87f5-a869ab0ad489')
+ def test_multiple_ports_portrange_remote(self):
+ ssh_clients, fips, servers = self.create_vm_testing_sec_grp(
+ num_servers=3)
+ secgroups = []
+ ports = []
+
+ # Create remote and test security groups
+ for i in range(0, 2):
+ secgroups.append(
+ self.create_security_group(name='secgrp-%d' % i))
+ # configure sec groups to support SSH connectivity
+ self.create_loginable_secgroup_rule(
+ secgroup_id=secgroups[-1]['id'])
+
+ # Configure security groups, first two servers as remotes
+ for i, server in enumerate(servers):
+ port = self.client.list_ports(
+ network_id=self.network['id'], device_id=server['server'][
+ 'id'])['ports'][0]
+ ports.append(port)
+ secgroup = secgroups[0 if i in range(0, 2) else 1]
+ self.client.update_port(port['id'], security_groups=[
+ secgroup['id']])
+
+ # verify SSH functionality
+ for fip in fips:
+ self.check_connectivity(fip['floating_ip_address'],
+ CONF.validation.image_ssh_user,
+ self.keypair['private_key'])
+
+ test_ip = ports[2]['fixed_ips'][0]['ip_address']
+
+ # verify that conections are not working
+ for port in range(80, 84):
+ self._verify_http_connection(
+ ssh_clients[0],
+ ssh_clients[2],
+ test_ip, port,
+ should_pass=False)
+
+ # add two remote-group rules with port-ranges
+ rule_list = [{'protocol': constants.PROTO_NUM_TCP,
+ 'direction': constants.INGRESS_DIRECTION,
+ 'port_range_min': '80',
+ 'port_range_max': '81',
+ 'remote_group_id': secgroups[0]['id']},
+ {'protocol': constants.PROTO_NUM_TCP,
+ 'direction': constants.INGRESS_DIRECTION,
+ 'port_range_min': '82',
+ 'port_range_max': '83',
+ 'remote_group_id': secgroups[0]['id']}]
+ self.create_secgroup_rules(
+ rule_list, secgroup_id=secgroups[1]['id'])
+
+ # verify that conections are working
+ for port in range(80, 84):
+ self._verify_http_connection(
+ ssh_clients[0],
+ ssh_clients[2],
+ test_ip, port)