Запустите multiprocessing.process в пространстве имен

Я пытаюсь запустить новый процесс из уже созданного пространства имен (с именем '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, будут великолепны!

ТИА!

3 ответа

Проблема с 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,

Это работает, однако я не уверен в том, что 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)

После нахождения этого вопроса мы обновили python-nsenter, чтобы он теперь мог вводить пространства имен по произвольному пути в дополнение к предоставлению pid.

Например, если вы хотите ввести пространство имен, созданное ip netns add Теперь вы можете сделать что-то вроде:

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

Версия 0.2 теперь доступна через PyPi с этим обновлением.

Другие вопросы по тегам