Фоновый процесс поверх скрипта Python, выполняемого удаленно с помощью Fabric

Контекст

Я добавляю несколько штук к существующей, работающей системе. Существует управляющая машина (локальный компьютер с Linux), на которой выполняются некоторые тестовые сценарии, которые включают отправку большого количества команд на несколько разных машин удаленно через SSH. Платформа тестирования написана на Python и использует Fabric для доступа к различным машинам.

Все команды обрабатываются с помощью общей функции вызова, упрощенной ниже:

def cmd(host, cmd, args):
    ...
    with fabric.api.settings(host_string=..., user='root', use_ssh_config=True, disable_known_hosts=True):
        return fabric.api.run('%s %s' % (cmd, args))

Фактические команды, отправляемые на каждую машину, обычно включают запуск существующего скрипта Python на удаленной стороне. Эти сценарии python выполняют некоторые задания, включая вызов внешних команд (с использованием system и subprocess). Команда run(), вызванная на тестовом ПК, вернется, когда удаленный скрипт python будет выполнен.

В какой-то момент мне понадобился один из этих удаленных скриптов Python для запуска фоновой задачи: запуск сервера и клиента openvon с помощью openvpn --config /path/to/config.openvpn. В обычном скрипте Python я бы просто использовал &:

system('openvpn --config /path/to/config.openvpn > /var/log/openvpn.log 2>&1 &')

Когда этот сценарий вызывается удаленно через Fabric, необходимо явно использовать nohup, dtach, screen и т.п. для запуска задания в фоновом режиме. Я работал с:

system("nohup openvpn --config /path/to/config.openvpn > /var/log/openvpn.log 2>&1 < /dev/null &"

Подробнее об этом можно узнать в FAQ по Fabric. Он отлично работает с некоторыми фоновыми командами.

Проблема: не работает для всех типов фоновых команд

Этот метод работает не со всеми необходимыми мне командами. В некоторых сценариях мне нужно запустить фоновую команду atop (это top на стероидах) и перенаправить ее стандартный вывод в файл.

Мой код (примечание: использование atop -P для синтаксического анализа):

system('nohup atop -P%s 1 < /dev/null | grep %s > %s 2>&1 &' % (dataset, grep_options, filename))

Когда сценарий, содержащий эту команду, вызывается удаленно через Fabric, верхний процесс немедленно завершается. Выходной файл создается, но он пуст. Вызов того же сценария при входе на удаленный компьютер по SSH работает нормально, команда atop периодически выгружает данные в мой выходной файл.

Некоторый поиск в Google и поиск привели меня к интересной информации о фоновых заданиях с использованием Fabric, но моя проблема, похоже, специфична только для определенных типов фоновых заданий. Я пробовал:

Похоже, у меня заканчиваются идеи.

Ткань кажется излишней для того, что мы делаем. Мы даже не используем метод "fabfile", потому что он интегрирован в nose фреймворк, и я запускаю их, вызывая nosetests. Может быть, мне следует отказаться от Fabric в пользу ручных команд SSH, хотя мне не нравится идея менять рабочую систему из-за того, что она не поддерживает один из моих новых модулей.


person Sébastien Dawans    schedule 12.07.2013    source источник


Ответы (1)


В моем окружении похоже, что он работает

from fabric.api import sudo

def atop():
    sudo('nohup atop -Pcpu 1 </dev/null '
        '| grep cpu > /tmp/log --line-buffered 2>&1 &',
        pty=False)

результат:

fabric:~$ fab atop -H web01
>>>[web01] Executing task 'atop'
>>>[web01] sudo: nohup atop -Pcpu 1 </dev/null | grep cpu > /tmp/log --line-buffered 2>&1 &
>>>
>>>Done.

web01:~$ cat /tmp/log 
>>>cpu web01 1374246222 2013/07/20 00:03:42 361905 100 0 5486 6968 0 9344927 3146 0 302 555 0 2494 100
>>>cpu web01 1374246223 2013/07/20 00:03:43 1 100 0 1 0 0 99 0 0 0 0 0 2494 100
>>>cpu web01 1374246224 2013/07/20 00:03:44 1 100 0 1 0 0 99 0 0 0 0 0 2494 100
...

Для команды atop может потребоваться суперпользователь. Это не работает

from fabric.api import run

def atop():
    run('nohup atop -Pcpu 1 </dev/null '
        '| grep cpu > /tmp/log --line-buffered 2>&1 &',
        pty=False)

С другой стороны это работа.

from fabric.api import run

def atop():
    run('sudo nohup atop -Pcpu 1 </dev/null '
        '| grep cpu > /tmp/log --line-buffered 2>&1 &',
        pty=False)
person Yuichiro    schedule 19.07.2013