在命名空间

时间:2015-05-08 15:31:16

标签: python namespaces ctypes nsenter

我尝试从已创建的命名空间(名为' 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路线走下去,类似于(尽管没有系统调用网络... ):

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())

OR(取自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没有setn!

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

TIA!

3 个答案:

答案 0 :(得分: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。

假设您有一个名为&#34; blue&#34;的命名空间。可用(ip netns add blue)你可以运行:

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

请注意,您必须将此代码作为root运行。

答案 1 :(得分: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)

答案 2 :(得分:0)

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

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

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

Version 0.2 is now available via PyPi此次更新。