0

我正在尝试从已创建的命名空间(名为“test”)中启动一个新进程。

我研究了一些方法,包括 nsenter:

import subprocess
from nsenter import Namespace

with Namespace(mypid, 'net'):
    # output network interfaces as seen from within the mypid's net NS:
    subprocess.check_output(['ip', 'a'])

但我似乎无法找到在哪里可以找到 var、mypid 的参考......!

理想情况下,我想将 nsenter 之类的依赖项保持在最低限度(为了可移植性),所以我可能想沿着 ctypes 路线走下去,比如(尽管 netns 没有系统调用......):

nsname = 'test'
netnspath = '%s%s' % ('/run/netns/', nsname)
netnspath = netnspath.encode('ascii')

libc = ctypes.CDLL('libc.so.6')

printdir(libc)

fd = open(netnspath)
print libc.syscall(???, fd.fileno())

或(取自http://tech.zalando.com/posts/entering-kernel-namespaces-with-python.html

import ctypes
libc = ctypes.CDLL('libc.so.6')
# replace MYPID with the container's PID
fd = open('/proc/<MYPID>/ns/net')
libc.setns(fd.fileno(), 0)
# we are now inside MYPID's network namespace

但是,我仍然必须知道 PID,再加上我的 libc 没有 setns!

关于如何获得 PID 的任何想法都会很棒!

蒂亚!

4

3 回答 3

2

nsenter模块的问题是您需要向它提供已在目标命名空间内运行的进程的 PID。这意味着您实际上不能使用此模块来使用您使用类似ip netns add.

内核的setns()系统调用采用文件描述符而不是 PID。如果你愿意用 解决它ctypes,你可以这样做:

from ctypes import cdll
libc = cdll.LoadLibrary('libc.so.6')
_setns = libc.setns

CLONE_NEWIPC = 0x08000000
CLONE_NEWNET = 0x40000000
CLONE_NEWUTS = 0x04000000

def setns(fd, nstype):
    if hasattr(fd, 'fileno'):
        fd = fd.fileno()

    _setns(fd, nstype)

def get_netns_path(nspath=None, nsname=None, nspid=None):
    '''Generate a filesystem path from a namespace name or pid,
    and return a filesystem path to the appropriate file.  Returns
    the nspath argument if both nsname and nspid are None.'''

    if nsname:
        nspath = '/var/run/netns/%s' % nsname
    elif nspid:
        nspath = '/proc/%d/ns/net' % nspid

    return nspath

如果您的 libc 没有setns()调用,您可能不走运(尽管您在哪里运行,您有一个足够新的内核来支持网络名称空间,但一个 libc 没有?)。

假设您有一个名为“blue”的命名空间可用 ( ip netns add blue),您可以运行:

with open(get_netns_path(nsname="blue")) as fd:
    setns(fd, CLONE_NEWNET)
    subprocess.check_call(['ip', 'a'])

请注意,您必须将此代码作为root.

于 2015-05-08T16:20:57.877 回答
0

这可行,但是我不确定 0 作为系统调用的一部分做了什么。因此,如果有人可以启发我,那就太好了!

import ctypes

nsname = 'test'
netnspath = '%s%s' % ('/run/netns/', nsname)
netnspath = netnspath.encode('ascii')

libc = ctypes.CDLL('libc.so.6')

fd = open(netnspath)
print libc.syscall(308, fd.fileno(), 0)
于 2015-05-08T17:07:43.157 回答
0

找到这个问题后,我们更新了python-nsenter,现在除了提供 pid 之外,它还可以通过任意路径进入命名空间。

例如,如果您想输入由ip netns add您创建的命名空间,您现在可以执行以下操作:

with Namespace('/var/run/netns/foo', 'net'):
    # do something in the namespace
    pass

0.2 版现在可通过 PyPi获得此更新。

于 2016-01-08T15:12:37.243 回答