Форум сайта python.su
Добрый день!
Копал в нескольких местах, но так и не нашёл чёткого решения проблемы. Итак, есть некая команда для запуска в шелле. Допустим, у меня она генерируется и помещается в переменную cmd. Затем я запускаю полученную команду, жду некоторое время, после чего мне нужно проверить, корректно ли запустилась эта команда, т.е. пуст ли поток вывода. Если он не пуст, мы выполняем одни действия, если всё хорошо, то соответственно другие. Логика проста.
# Запуск
cmd = subprocess.Popen(str(stcmd), shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
# Затем я пытаюсь прочитать поток ошибок:
cmderr = cmd.stderr.read()
if cmderr:
print 'ERROR: ', cmderr
else:
print 'All is fine.'
cmd = subprocess.Popen(str(stcmd+' &'), shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
print 'test1'
cmdout, cmderr = cmd.communicate()
if cmderr:
self.__sql__('update vm set status = \'error\', error = \' CMDERROR: ' + str(cmderr) + '\' where vid = ' + str(id) + ';', 0)
return self.error('There are some error, while starting VM:\n' + cmderr)
print 'test2'
Офлайн
можно попробовать использовать select: http://www.py-my.ru/post/4bfb3c691d41c846bc00006a
для mssql, можно использовать pyodbc, там выскакивает exception в случае ошибки
Офлайн
import subprocess
cmd = 'echo x > /etc/x.txt'
p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
print(p)
if p[1]:
print('err')
elif p[0]:
print('no err')
else:
print('no err, no output')
Отредактировано (Дек. 3, 2011 09:46:31)
Офлайн
Попробовал следующим образом:
print 'test0'
cmd = subprocess.Popen(str(stcmd), shell=True, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE).communicate()
print 'test1'
if cmd[1]:
print 'We have some error:\n', cmd[1]
elif cmd[0]:
print 'We have some output:\n', cmd[0]
print 'test2'
corpse@white:/opt/esvirt$ lsof -Pnl +M -i4
COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
qemu 1817 1000 13u IPv4 5367 0t0 TCP 192.168.2.201:5908 (LISTEN) # запущено руками
qemu 1817 1000 14u IPv4 5383 0t0 TCP 192.168.2.201:5908->192.168.2.19:50072 (ESTABLISHED) # запущено руками
esweb.py 1987 1000 3u IPv4 5659 0t0 TCP 192.168.2.201:8080->192.168.2.19:34314 (ESTABLISHED) # это я вишу на вебинтерфейсе
esweb.py 1987 1000 5u IPv4 5655 0t0 TCP 192.168.2.201:8080 (LISTEN) # это мы слушаем порт и ожидаем соединения от всех остальных
sh 2015 1000 3u IPv4 5659 0t0 TCP 192.168.2.201:8080->192.168.2.19:34314 (ESTABLISHED) # это собственно тот самый shell=True, насколько я понимаю. И cmd.pid я получаю именно от него.
sh 2015 1000 5u IPv4 5655 0t0 TCP 192.168.2.201:8080 (LISTEN) # мне только не совсем понятно, почему тут указываются эти порты и какое отношение имеет запущенный дочерний процесс к тому, что там было запущенно через webop
qemu 2016 1000 3u IPv4 5659 0t0 TCP 192.168.2.201:8080->192.168.2.19:34314 (ESTABLISHED) # Вот и процесс, запущенный из шелла делает вид, что он тоже висит на этих портах видимо это как раз происходит из-за открытых сокетов
qemu 2016 1000 5u IPv4 5655 0t0 TCP 192.168.2.201:8080 (LISTEN)
qemu 2016 1000 16u IPv4 5742 0t0 TCP 192.168.2.201:5901 (LISTEN) # ну а это vnc, который собственно открывает сам процесс qemu
corpse@white:/opt/esvirt$ ps aux | grep qemu
corpse 1817 29.6 3.6 589564 287556 pts/1 Sl 14:43 3:25 qemu --enable-kvm --usbdevice tablet -m 256 -net nic,model=rtl8139,macaddr=00:00:DE:AD:00:08 -net tap,ifname=tap0 -vnc 192.168.2.201:8,password -monitor vc -monitor unix:/opt/esvirt/run/tolstobokov_8.sock,server,nowait -hda images/tolstobokov.qcow2 # запущено руками
corpse 2015 0.0 0.0 3952 564 pts/1 S 14:49 0:00 /bin/sh -c qemu --enable-kvm --usbdevice tablet -m 256 -localtime -cdrom /mnt/share/files/images/other/kolibri.iso -net nic,model=rtl8139 -net tap,ifname=tap1 -vnc 192.168.2.201:01 -monitor vc -monitor unix:./run/kolibri.sock,server,nowait -boot d # Шелл, дёрнутый через subprocess
corpse 2016 2.9 0.3 572152 27896 pts/1 R 14:49 0:10 qemu --enable-kvm --usbdevice tablet -m 256 -localtime -cdrom /mnt/share/files/images/other/kolibri.iso -net nic,model=rtl8139 -net tap,ifname=tap1 -vnc 192.168.2.201:01 -monitor vc -monitor unix:./run/kolibri.sock,server,nowait -boot d # Сам процесс. Причём если убить шелл с пидом 2015, сам процесс с пидом 2016 будет благополучно жив и здоров.
# А это вывод при запуске:
serving on http://192.168.2.201:8080
test0
# На этом месте мы наглухо повисаем, пока жив процесс с пидом 2016
Офлайн
o7412369815963Это я попробую завтра, сегодня уже не успеваю. Вроде бы ведь говорят, что уже не кошерно использовать os.popen* и все рекомендуют вместо него использовать сабпроцесс?
можно попробовать использовать select: http://www.py-my.ru/post/4bfb3c691d41c846bc00006a
для mssql, можно использовать pyodbc, там выскакивает exception в случае ошибки
Офлайн
Не очень понял когда завершается ваш подпроцесс. Т.е. в случае ошибки он завершается или будет дальше висеть?
Может ваш подпроцесс действует разумно и в случае ошибок возвращает код ошибки? Тогда check_call вам поможет.
В противном случае приходит в голову только пожертвовать тредом - повесить его слушать ваш stderr в отдельном потоке для неблокирующего чтения см например
http://stackoverflow.com/questions/375427/non-blocking-read-on-a-subprocess-pipe-in-python
Просто перевести sterr в неблокирующий режим не очень надежное решение - вы ведь не знаете сколько времени надо ждать сообщения об ошибке.
Отредактировано (Дек. 3, 2011 11:48:51)
Офлайн
corpseДа, лучше сабпроцес, там просто пример по применению селектов.o7412369815963Немного не понял, при чём тут mssql. Я в данном случае ничего кроме sqlite не использую.
можно попробовать использовать select: http://www.py-my.ru/post/4bfb3c691d41c846bc00006a
Офлайн
doza_andВ случае ошибки - завершается сразу. Собственно, в этом-то случае никаких проблем нет. Я корректно обрабатываю ошибку и всё хорошо.
Не очень понял когда завершается ваш подпроцесс. Т.е. в случае ошибки он завершается или будет дальше висеть?
Может ваш подпроцесс действует разумно и в случае ошибок возвращает код ошибки? Тогда check_call вам поможет.
doza_andО тредах я думал. Хотя теперь у меня возникла мысль о том, что с идеологической точки зрения для этого приложения будет лучше при каждом запуске дочернего процесса делать два уникальных лога с указанием пида нужного процесса и даты - на stdout и stderr и хранить имена файлов в базе, при необходимости читая оттуда. Это будет правильнее, так как при краше приложения дочерние процессы должны выполняться автономно и желательно бы иметь информацию о их работе. Плюс файл с stdout можно будет легко дополнить по необходимости своими данными.
В противном случае приходит в голову только пожертвовать тредом - повесить его слушать ваш stderr в отдельном потоке для неблокирующего чтения см например
http://stackoverflow.com/questions/3754 … -in-python
doza_andПредположим, меня интересуют ошибки, происходящие исключительно в момент 0 - 0.5с относительно запуска. После 0.5с гори оно синим пламенем. :) Это можно сделать без тредов?
Просто перевести sterr в неблокирующий режим не очень надежное решение - вы ведь не знаете сколько времени надо ждать сообщения об ошибке.
Офлайн
corpseМожно выполнить чтение stderr, и оборвать через 0,5сек сигналом, но сигналы работают только в главном процессе.
Предположим, меня интересуют ошибки, происходящие исключительно в момент 0 - 0.5с относительно запуска. После 0.5с гори оно синим пламенем. :) Это можно сделать без тредов?
Офлайн
o74123698159632. Тут не клиент-сервер получается. Точнее не совсем так. Приложение является одновременно ещё и http сервером (использую webop), на котором реализована веб-мордочка.
Я б наверно сделал так:
2) на серверной части идет запуск python-оболчки, и назначение идентификатора задаче (хотя не обязательно), клиенту отсылается этот ид.
3) python-оболочка запускает процесс и через селекты, либо в разных потоках опрашивает вывод, складывая его в файлы/бд.
4) на клиенте таймер - раз в 5 сек опрашивает сервер на получение логов, сервер отдает логи по ид, клиент их отрисовывает.
если не нужно что-б python-оболочка висела, можно задать ей самоубийство через Х секунд, с помощью сигналов.
итого: в браузере кликаем кнопку старт, где динамически отрисовываются логи, время работы и пр. инфу.
Офлайн