Allow to execute commands from inside a network namespace
Change-Id: I6aa499824bca146b6d2bf834b6565679cb423c4a
This commit is contained in:
parent
909dc7cf9b
commit
cc63ebb518
|
@ -67,7 +67,7 @@ def list_ip_addresses(ip_version=None, scope=None, **execute_params):
|
||||||
|
|
||||||
def list_network_namespaces(**execute_params):
|
def list_network_namespaces(**execute_params):
|
||||||
output = execute_ip(['-o', 'netns', 'list'], **execute_params)
|
output = execute_ip(['-o', 'netns', 'list'], **execute_params)
|
||||||
namespaces = list()
|
namespaces = tobiko.Selection()
|
||||||
if output:
|
if output:
|
||||||
for line in output.splitlines():
|
for line in output.splitlines():
|
||||||
fields = line.strip().split()
|
fields = line.strip().split()
|
||||||
|
@ -76,15 +76,10 @@ def list_network_namespaces(**execute_params):
|
||||||
return namespaces
|
return namespaces
|
||||||
|
|
||||||
|
|
||||||
def execute_ip(ifconfig_args, network_namespace=None, sudo=None,
|
def execute_ip(ifconfig_args, **execute_params):
|
||||||
**execute_params):
|
|
||||||
command = ['/sbin/ip'] + ifconfig_args
|
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,
|
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:
|
if result.exit_status:
|
||||||
raise IpError(error=result.stderr, exit_status=result.exit_status)
|
raise IpError(error=result.stderr, exit_status=result.exit_status)
|
||||||
return result.stdout
|
return result.stdout
|
||||||
|
|
|
@ -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,
|
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(
|
return LocalShellProcessFixture(
|
||||||
command=command, environment=environment, current_dir=current_dir,
|
command=command, environment=environment, current_dir=current_dir,
|
||||||
timeout=timeout, shell=shell, stdin=stdin, stdout=stdout,
|
timeout=timeout, shell=shell, stdin=stdin, stdout=stdout,
|
||||||
stderr=stderr, sudo=sudo)
|
stderr=stderr, sudo=sudo, network_namespace=network_namespace)
|
||||||
|
|
||||||
|
|
||||||
class LocalExecutePathFixture(_path.ExecutePathFixture):
|
class LocalExecutePathFixture(_path.ExecutePathFixture):
|
||||||
|
|
|
@ -79,6 +79,7 @@ class ShellProcessParameters(Parameters):
|
||||||
buffer_size = io.DEFAULT_BUFFER_SIZE
|
buffer_size = io.DEFAULT_BUFFER_SIZE
|
||||||
poll_interval = 1.
|
poll_interval = 1.
|
||||||
sudo = None
|
sudo = None
|
||||||
|
network_namespace = None
|
||||||
|
|
||||||
|
|
||||||
class ShellProcessFixture(tobiko.SharedFixture):
|
class ShellProcessFixture(tobiko.SharedFixture):
|
||||||
|
@ -121,6 +122,9 @@ class ShellProcessFixture(tobiko.SharedFixture):
|
||||||
|
|
||||||
def setup_command(self):
|
def setup_command(self):
|
||||||
command = _command.shell_command(self.parameters.command)
|
command = _command.shell_command(self.parameters.command)
|
||||||
|
network_namespace = self.parameters.network_namespace
|
||||||
|
sudo = self.parameters.sudo
|
||||||
|
|
||||||
shell = self.parameters.shell
|
shell = self.parameters.shell
|
||||||
if shell:
|
if shell:
|
||||||
if shell is True:
|
if shell is True:
|
||||||
|
@ -130,7 +134,12 @@ class ShellProcessFixture(tobiko.SharedFixture):
|
||||||
command = shell + [str(command)]
|
command = shell + [str(command)]
|
||||||
else:
|
else:
|
||||||
command = _command.shell_command(command)
|
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:
|
||||||
if sudo is True:
|
if sudo is True:
|
||||||
sudo = default_sudo_command()
|
sudo = default_sudo_command()
|
||||||
|
@ -495,3 +504,8 @@ def default_sudo_command():
|
||||||
from tobiko import config
|
from tobiko import config
|
||||||
CONF = config.CONF
|
CONF = config.CONF
|
||||||
return _command.shell_command(CONF.tobiko.shell.sudo)
|
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
|
||||||
|
|
|
@ -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,
|
def ssh_process(command, environment=None, current_dir=None, timeout=None,
|
||||||
shell=None, stdin=None, stdout=None, stderr=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:
|
if ssh_client is None:
|
||||||
ssh_client = ssh.ssh_proxy_client()
|
ssh_client = ssh.ssh_proxy_client()
|
||||||
if ssh_client:
|
if ssh_client:
|
||||||
return SSHShellProcessFixture(
|
return SSHShellProcessFixture(
|
||||||
command=command, environment=environment, current_dir=current_dir,
|
command=command, environment=environment, current_dir=current_dir,
|
||||||
timeout=timeout, shell=shell, stdin=stdin, stdout=stdout,
|
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:
|
else:
|
||||||
return _local.local_process(
|
return _local.local_process(
|
||||||
command=command, environment=environment, current_dir=current_dir,
|
command=command, environment=environment, current_dir=current_dir,
|
||||||
timeout=timeout, shell=shell, stdin=stdin, stdout=stdout,
|
timeout=timeout, shell=shell, stdin=stdin, stdout=stdout,
|
||||||
stderr=stderr, sudo=sudo)
|
stderr=stderr, sudo=sudo, network_namespace=network_namespace)
|
||||||
|
|
||||||
|
|
||||||
class SSHShellProcessParameters(_process.ShellProcessParameters):
|
class SSHShellProcessParameters(_process.ShellProcessParameters):
|
||||||
|
|
|
@ -20,9 +20,10 @@ import six
|
||||||
import testtools
|
import testtools
|
||||||
|
|
||||||
import tobiko
|
import tobiko
|
||||||
|
from tobiko.openstack import stacks
|
||||||
|
from tobiko.openstack import topology
|
||||||
from tobiko.shell import ip
|
from tobiko.shell import ip
|
||||||
from tobiko.shell import ssh
|
from tobiko.shell import ssh
|
||||||
from tobiko.openstack import stacks
|
|
||||||
|
|
||||||
|
|
||||||
class IpTest(testtools.TestCase):
|
class IpTest(testtools.TestCase):
|
||||||
|
@ -55,6 +56,7 @@ class IpTest(testtools.TestCase):
|
||||||
elif scope == 'global':
|
elif scope == 'global':
|
||||||
self.assertNotIn(netaddr.IPAddress('127.0.0.1'), ips)
|
self.assertNotIn(netaddr.IPAddress('127.0.0.1'), ips)
|
||||||
self.assertNotIn(netaddr.IPAddress('::1'), ips)
|
self.assertNotIn(netaddr.IPAddress('::1'), ips)
|
||||||
|
return ips
|
||||||
|
|
||||||
def test_list_ip_addresses_with_host_scope(self, **execute_params):
|
def test_list_ip_addresses_with_host_scope(self, **execute_params):
|
||||||
self.test_list_ip_addresses(scope='host', **execute_params)
|
self.test_list_ip_addresses(scope='host', **execute_params)
|
||||||
|
@ -98,6 +100,23 @@ class IpTest(testtools.TestCase):
|
||||||
self, **execute_params):
|
self, **execute_params):
|
||||||
self.test_list_ip_addresses(scope='global', **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):
|
def test_list_namespaces(self, **execute_params):
|
||||||
namespaces = ip.list_network_namespaces(**execute_params)
|
namespaces = ip.list_network_namespaces(**execute_params)
|
||||||
self.assertIsInstance(namespaces, list)
|
self.assertIsInstance(namespaces, list)
|
||||||
|
|
Loading…
Reference in New Issue