Merge "Workaround issue with disappearing namespaces on OSP nodes"

This commit is contained in:
Zuul 2022-07-08 10:58:18 +00:00 committed by Gerrit Code Review
commit 21ae2a1bd8
4 changed files with 71 additions and 30 deletions

View File

@ -102,8 +102,8 @@ def parse_ip_address(text: str) -> typing.Tuple[netaddr.IPAddress, int]:
return netaddr.IPAddress(address), prefix_len
def list_network_namespaces(**execute_params) -> typing.List[str]:
namespaces: typing.List[str] = []
def list_network_namespaces(**execute_params) -> tobiko.Selection[str]:
namespaces = tobiko.Selection[str]()
output = execute_ip(['-o', 'netns', 'list'], **execute_params)
if output:
for line in output.splitlines():
@ -113,8 +113,8 @@ def list_network_namespaces(**execute_params) -> typing.List[str]:
return namespaces
def list_network_interfaces(**execute_params) -> typing.List[str]:
interfaces: typing.List[str] = []
def list_network_interfaces(**execute_params) -> tobiko.Selection[str]:
interfaces = tobiko.Selection[str]()
output = execute_ip(['--brief', 'address', 'list'], **execute_params)
if output:
for line in output.splitlines():

View File

@ -1,22 +1,46 @@
from __future__ import absolute_import
import testtools
from oslo_log import log
import tobiko
from tobiko.openstack import keystone
from tobiko.openstack import topology
from tobiko.shell import ip
from tobiko.shell import ssh
LOG = log.getLogger(__name__)
@keystone.skip_unless_has_keystone_credentials()
class NetworkNamespaceFixture(tobiko.SharedFixture):
network_namespace = None
ssh_client = None
def __init__(self,
network_namespace: str = None,
ssh_client: ssh.SSHClientType = None):
super().__init__()
self.network_namespace = network_namespace
self.ssh_client = ssh_client
def setup_fixture(self):
errors = []
for node in topology.list_openstack_nodes():
network_namespaces = ip.list_network_namespaces(
ignore_errors=True,
ssh_client=node.ssh_client)
if network_namespaces:
self.network_namespace = network_namespaces[0]
try:
namespace: str = ip.list_network_namespaces(
ignore_errors=True,
ssh_client=node.ssh_client).first
except tobiko.ObjectNotFound:
LOG.debug(f'No such namespace on host {node.name}',
exc_info=1)
except Exception:
LOG.debug(f'Error listing namespace on host {node.name}',
exc_info=1)
errors.append(tobiko.exc_info())
else:
self.network_namespace = namespace
self.ssh_client = node.ssh_client
break
else:
if errors:
raise testtools.MultipleExceptions(*errors)
else:
tobiko.skip_test(reason='Network namespace not found')

View File

@ -15,14 +15,14 @@
# under the License.
from __future__ import absolute_import
import os
import netaddr
import pytest
import testtools
import tobiko
from tobiko.openstack import stacks
from tobiko.shell import ip
from tobiko.shell import sh
from tobiko.shell import ssh
from tobiko.tests.functional.shell import _fixtures
@ -44,11 +44,15 @@ class IpTest(testtools.TestCase):
namespace = tobiko.required_fixture(
_fixtures.NetworkNamespaceFixture)
def test_list_ip_addresses(self, ip_version=None, scope=None,
def test_list_ip_addresses(self,
ip_version=None,
scope=None,
ssh_client: ssh.SSHClientType = None,
**execute_params):
if not os.path.isfile('/bin/ip'):
self.skipTest("'bin/ip' command not found")
ips = ip.list_ip_addresses(ip_version=ip_version, scope=scope,
sh.find_command('ip', sudo=True, ssh_client=ssh_client, skip=True)
ips = ip.list_ip_addresses(ip_version=ip_version,
scope=scope,
ssh_client=ssh_client,
**execute_params)
self.assertIsInstance(ips, tobiko.Selection)
for ip_address in ips:
@ -112,6 +116,7 @@ class IpTest(testtools.TestCase):
self, **execute_params):
self.test_list_ip_addresses(scope='global', **execute_params)
@pytest.mark.flaky(reruns=3, reruns_delay=5)
def test_list_ip_addresses_with_namespace(self, **params):
namespace_ips = ip.list_ip_addresses(
ssh_client=self.namespace.ssh_client,
@ -122,9 +127,11 @@ class IpTest(testtools.TestCase):
**params)
self.assertNotEqual(host_ips, namespace_ips)
@pytest.mark.flaky(reruns=3, reruns_delay=5)
def test_list_ip_addresses_with_namespace_and_scope(self):
self.test_list_ip_addresses_with_namespace(scope='global')
@pytest.mark.flaky(reruns=3, reruns_delay=5)
def test_list_ip_addresses_with_failing_command(self):
self.assertRaises(ip.IpError, ip.list_ip_addresses,
ip_command=['false'],
@ -134,35 +141,46 @@ class IpTest(testtools.TestCase):
self.test_list_ip_addresses(ignore_errors=True, ip_command='false',
**execute_params)
def test_list_namespaces(self, **execute_params):
if not os.path.isfile('/bin/ip'):
self.skipTest("'bin/ip' command not found")
namespaces = ip.list_network_namespaces(**execute_params)
@pytest.mark.flaky(reruns=3, reruns_delay=5)
def test_list_namespaces(self,
ignore_errors=False,
ssh_client: ssh.SSHClientType = None,
**execute_params):
sh.find_command('ip', sudo=True, ssh_client=ssh_client, skip=True)
namespaces = ip.list_network_namespaces(ignore_errors=ignore_errors,
ssh_client=ssh_client,
**execute_params)
self.assertIsInstance(namespaces, list)
for namespace in namespaces:
self.assertIsInstance(namespace, str)
self.test_list_ip_addresses(network_namespace=namespace)
@pytest.mark.flaky(reruns=3, reruns_delay=5)
def test_list_namespaces_with_centos_server(self):
self.test_list_namespaces(ssh_client=self.centos_stack.ssh_client)
@pytest.mark.flaky(reruns=3, reruns_delay=5)
def test_list_namespaces_with_fedora_server(self):
self.test_list_namespaces(ssh_client=self.fedora_stack.ssh_client)
@pytest.mark.flaky(reruns=3, reruns_delay=5)
def test_list_namespaces_with_ubuntu_server(self):
self.test_list_namespaces(ssh_client=self.ubuntu_stack.ssh_client)
@pytest.mark.flaky(reruns=3, reruns_delay=5)
def test_list_namespaces_with_proxy_ssh_client(self):
ssh_client = ssh.ssh_proxy_client()
if ssh_client is None:
self.skipTest('SSH proxy server not configured')
self.test_list_namespaces(ssh_client=ssh_client)
@pytest.mark.flaky(reruns=3, reruns_delay=5)
def test_list_namespaces_with_failing_command(self):
self.assertRaises(ip.IpError, ip.list_network_namespaces,
ip_command=['false'],
ssh_client=self.namespace.ssh_client)
@pytest.mark.flaky(reruns=3, reruns_delay=5)
def test_list_namespaces_with_ignore_errors(self, **execute_params):
self.test_list_namespaces(ignore_errors=True, ip_command='false',
**execute_params)

View File

@ -15,9 +15,10 @@
# under the License.
from __future__ import absolute_import
import typing # noqa
import typing
import netaddr
import pytest
import testtools
import tobiko
@ -145,10 +146,8 @@ class PingTest(testtools.TestCase):
self.assertEqual('transmitted', ex.message_type)
def test_ping_hosts(self):
try:
sh.execute('[ -x /sbin/ip ]', ssh_client=self.ssh_client)
except sh.ShellCommandFailed:
self.skipTest("'/sbin/ip' command not found")
sh.find_command('ip', sudo=True, ssh_client=self.ssh_client,
skip=True)
ips = ip.list_ip_addresses(**self.execute_params)
reachable_ips, unreachable_ips = ping.ping_hosts(
ips, **self.execute_params)
@ -194,10 +193,10 @@ class ProxyPingTest(PingTest):
ssh_client = None
@pytest.mark.flaky(reruns=3, reruns_delay=5)
class NamespacePingTest(PingTest):
namespace = tobiko.required_fixture(
_fixtures.NetworkNamespaceFixture)
namespace = tobiko.required_fixture(_fixtures.NetworkNamespaceFixture)
@property
def ssh_client(self):