我尝试从已创建的命名空间(名为' 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!
答案 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