Allow to execute commands from inside a network namespace

Change-Id: I6aa499824bca146b6d2bf834b6565679cb423c4a
This commit is contained in:
Federico Ressi 2019-10-31 20:18:56 +01:00
parent 909dc7cf9b
commit cc63ebb518
5 changed files with 45 additions and 15 deletions

View File

@ -67,7 +67,7 @@ def list_ip_addresses(ip_version=None, scope=None, **execute_params):
def list_network_namespaces(**execute_params):
output = execute_ip(['-o', 'netns', 'list'], **execute_params)
namespaces = list()
namespaces = tobiko.Selection()
if output:
for line in output.splitlines():
fields = line.strip().split()
@ -76,15 +76,10 @@ def list_network_namespaces(**execute_params):
return namespaces
def execute_ip(ifconfig_args, network_namespace=None, sudo=None,
**execute_params):
def execute_ip(ifconfig_args, **execute_params):
command = ['/sbin/ip'] + ifconfig_args
if network_namespace:
if sudo is None:
sudo = True
command = ['/sbin/ip', 'netns', 'exec', network_namespace] + command
result = sh.execute(command, stdin=False, stdout=True, stderr=True,
expect_exit_status=None, sudo=sudo, **execute_params)
expect_exit_status=None, **execute_params)
if result.exit_status:
raise IpError(error=result.stderr, exit_status=result.exit_status)
return result.stdout

View File

@ -54,11 +54,12 @@ def local_execute(command, environment=None, timeout=None, shell=None,
def local_process(command, environment=None, current_dir=None, timeout=None,
shell=None, stdin=None, stdout=None, stderr=True, sudo=None):
shell=None, stdin=None, stdout=None, stderr=True, sudo=None,
network_namespace=None):
return LocalShellProcessFixture(
command=command, environment=environment, current_dir=current_dir,
timeout=timeout, shell=shell, stdin=stdin, stdout=stdout,
stderr=stderr, sudo=sudo)
stderr=stderr, sudo=sudo, network_namespace=network_namespace)
class LocalExecutePathFixture(_path.ExecutePathFixture):

View File

@ -79,6 +79,7 @@ class ShellProcessParameters(Parameters):
buffer_size = io.DEFAULT_BUFFER_SIZE
poll_interval = 1.
sudo = None
network_namespace = None
class ShellProcessFixture(tobiko.SharedFixture):
@ -121,6 +122,9 @@ class ShellProcessFixture(tobiko.SharedFixture):
def setup_command(self):
command = _command.shell_command(self.parameters.command)
network_namespace = self.parameters.network_namespace
sudo = self.parameters.sudo
shell = self.parameters.shell
if shell:
if shell is True:
@ -130,7 +134,12 @@ class ShellProcessFixture(tobiko.SharedFixture):
command = shell + [str(command)]
else:
command = _command.shell_command(command)
sudo = self.parameters.sudo
if network_namespace:
if sudo is None:
sudo = True
command = network_namespace_command(network_namespace, command)
if sudo:
if sudo is True:
sudo = default_sudo_command()
@ -495,3 +504,8 @@ def default_sudo_command():
from tobiko import config
CONF = config.CONF
return _command.shell_command(CONF.tobiko.shell.sudo)
def network_namespace_command(network_namespace, command):
return _command.shell_command(['/sbin/ip', 'netns', 'exec',
network_namespace]) + command

View File

@ -48,19 +48,20 @@ def ssh_execute(ssh_client, command, environment=None, timeout=None,
def ssh_process(command, environment=None, current_dir=None, timeout=None,
shell=None, stdin=None, stdout=None, stderr=None,
ssh_client=None, sudo=None):
ssh_client=None, sudo=None, network_namespace=None):
if ssh_client is None:
ssh_client = ssh.ssh_proxy_client()
if ssh_client:
return SSHShellProcessFixture(
command=command, environment=environment, current_dir=current_dir,
timeout=timeout, shell=shell, stdin=stdin, stdout=stdout,
stderr=stderr, ssh_client=ssh_client, sudo=sudo)
stderr=stderr, ssh_client=ssh_client, sudo=sudo,
network_namespace=network_namespace)
else:
return _local.local_process(
command=command, environment=environment, current_dir=current_dir,
timeout=timeout, shell=shell, stdin=stdin, stdout=stdout,
stderr=stderr, sudo=sudo)
stderr=stderr, sudo=sudo, network_namespace=network_namespace)
class SSHShellProcessParameters(_process.ShellProcessParameters):

View File

@ -20,9 +20,10 @@ import six
import testtools
import tobiko
from tobiko.openstack import stacks
from tobiko.openstack import topology
from tobiko.shell import ip
from tobiko.shell import ssh
from tobiko.openstack import stacks
class IpTest(testtools.TestCase):
@ -55,6 +56,7 @@ class IpTest(testtools.TestCase):
elif scope == 'global':
self.assertNotIn(netaddr.IPAddress('127.0.0.1'), ips)
self.assertNotIn(netaddr.IPAddress('::1'), ips)
return ips
def test_list_ip_addresses_with_host_scope(self, **execute_params):
self.test_list_ip_addresses(scope='host', **execute_params)
@ -98,6 +100,23 @@ class IpTest(testtools.TestCase):
self, **execute_params):
self.test_list_ip_addresses(scope='global', **execute_params)
def test_list_ip_addresses_with_namespace(self):
for node in topology.list_openstack_nodes():
network_namespaces = ip.list_network_namespaces(
ssh_client=node.ssh_client)
if network_namespaces:
network_namespace = network_namespaces.first
ssh_client = node.ssh_client
break
namespace_ips = ip.list_ip_addresses(
ssh_client=ssh_client, scope='global',
network_namespace=network_namespace)
self.assertNotEqual([], namespace_ips)
host_ips = ip.list_ip_addresses(ssh_client=ssh_client, scope='global')
self.assertNotEqual(host_ips, namespace_ips)
def test_list_namespaces(self, **execute_params):
namespaces = ip.list_network_namespaces(**execute_params)
self.assertIsInstance(namespaces, list)