воскресенье, 4 сентября 2016 г.

KVM qemu-agent настройка, выполнение команд (guest-exec)

qemu-agent это программа-демон, которая запускается внутри виртуальной машины для помощи в управлении.
Например: "замораживать\размораживать" файловую систему, приостанавливать выполнение, исполнять комманды, создавать\редактировать файлы и т.д.
Данные функции являются неотъемлемыми частями администрирования виртуальной инфраструктурой, такие как: создания снапшотов, миграции, включения\выключения, конфигурирования сети и т.д.

Подготовка.

Для того чтобы использовать нужно настроить взаимодействие хост-машины и VDS-ки через агента.
Исходные данные:
  • установленный на хост машине qemu-kvm (у меня он версии 1.2.5)
  • установленная и запущенная виртуалка с ubuntu 16
Приступим к настройке связи хост-агент, для этого установим на виртуальной машине агент:
root@ubuntu16:~# apt-get install qemu-guest-agent -y
Теперь остановим виртуальную машину:
root@host:~# virsh shutdown ubuntu16
Отредактируем конфиг:
root@host:~# virsh edit ubuntu16
Добавив в секцию devices следующие настройки:

   

Теперь запустим:
root@host:~# virsh start ubuntu16
Внутри виртуальной машины появится устройство:
root@ubuntu16:~# ls -al /dev/virtio-ports/org.qemu.guest_agent.0
lrwxrwxrwx 1 root root 11 Sep  4 06:47 /dev/virtio-ports/org.qemu.guest_agent.0 -> ../vport1p1
и процесс qemu-ga слушающий это устройство:
root@ubuntu16:~# pgrep -a qemu-ga
2165 /usr/sbin/qemu-ga --daemonize -m virtio-serial -p /dev/virtio-ports/org.qemu.guest_agent.0

Исполнение команд guest-exec

Теперь мы можем использовать агент и делать с виртуалкой "все что захотим".
Начнем с выполнения команд внутри данной виртуальной машины.
Например установим пакет dstat, в котором находится утилита dstat.
Для этого на хост машине выполним команду:
# virsh qemu-agent-command ubuntu16 '{"execute":"guest-exec", "arguments":{"path":"/usr/bin/apt","arg":["install", "dstat", "-y"]}}'
на вывод команда выдаст что-то вроде:
{"return":{"pid":2328}}
используя этот pid узнаем чем закончилось дело:
# virsh qemu-agent-command ubuntu16 '{"execute":"guest-exec-status", "arguments":{"pid":2328}}'
{"return":{"exitcode":0,"exited":true}}
  • exited:true - говорит о том что программа закончила свое выполнение
  • exitcode:0 - указывает код возврата программы (0 как правило говорит о успешном выполнении)
Обращаю внимание на то, что агрументы передавались каждый в отдельной строке
"arg":["install", "dstat", "-y"]
казалось бы - можно упростить и написать аргументы в одной строке не разделяя:
# virsh qemu-agent-command ubuntu16 '{"execute":"guest-exec", "arguments":{"path":"/usr/bin/apt","arg":["install snmpd -y"]}}'
{"return":{"pid":2333}}
но нет:
# virsh qemu-agent-command ubuntu16 '{"execute":"guest-exec-status", "arguments":{"pid":2333}}'
{"return":{"exitcode":100,"exited":true}}
Для получения помимо exitcode вывода команды (stdout), нужно добавить в arguments опцию capture-output и установить ее в true:
# virsh qemu-agent-command ubuntu16 '{"execute":"guest-exec", "arguments":{"path":"/bin/df","capture-output":true}}'
{"return":{"pid":2345}}
# virsh qemu-agent-command ubuntu16 '{"execute":"guest-exec-status", "arguments":{"pid":2345}}'
{"return":{"exitcode":0,"out-data":"RmlsZXN5c3RlbSAgICAgMUstYmxvY2tzICAgIFVzZWQgQXZhaWxhYmxlIFVzZSUgTW91bnRlZCBvbgp1ZGV2ICAgICAgICAgICAgIDIwMDM3MTIgICAgICAgMCAgIDIwMDM3MTIgICAwJSAvZGV2CnRtcGZzICAgICAgICAgICAgIDM2MjA4NCAgICA1MTU2ICAgIDM1NjkyOCAgIDIlIC9ydW4KL2Rldi9zZGExICAgICAgIDE2MzgxODY0IDE4NzM4MjggIDEzNjUyODQ0ICAxMyUgLwp0bXBmcyAgICAgICAgICAgICA5NzQzMjAgICAgICAgMCAgICA5NzQzMjAgICAwJSAvZGV2L3NobQp0bXBmcyAgICAgICAgICAgICAgIDUxMjAgICAgICAgMCAgICAgIDUxMjAgICAwJSAvcnVuL2xvY2sKdG1wZnMgICAgICAgICAgICAgOTc0MzIwICAgICAgIDAgICAgOTc0MzIwICAgMCUgL3N5cy9mcy9jZ3JvdXAKdG1wZnMgICAgICAgICAgICAgMTk0ODY4ICAgICAgIDAgICAgMTk0ODY4ICAgMCUgL3J1bi91c2VyLzAK","exited":true}}

Вывод команды находится в out-data, он закодирован в base64, для раскодирования можно воспользоваться любым онлайн сервисом, я использовал https://www.base64decode.org или утилитой base64 из состава пакета coreutils. Пример:
echo "RmlsZXN5c3RlbSAgICAgMUstYmxvY2tzICAgIFVzZWQgQXZhaWxhYmxlIFVzZSUgTW91bnRlZCBvbgp1ZGV2ICAgICAgICAgICAgIDIwMDM3MTIgICAgICAgMCAgIDIwMDM3MTIgICAwJSAvZGV2CnRtcGZzICAgICAgICAgICAgIDM2MjA4NCAgICA1MTU2ICAgIDM1NjkyOCAgIDIlIC9ydW4KL2Rldi9zZGExICAgICAgIDE2MzgxODY0IDE4NzM4MjggIDEzNjUyODQ0ICAxMyUgLwp0bXBmcyAgICAgICAgICAgICA5NzQzMjAgICAgICAgMCAgICA5NzQzMjAgICAwJSAvZGV2L3NobQp0bXBmcyAgICAgICAgICAgICAgIDUxMjAgICAgICAgMCAgICAgIDUxMjAgICAwJSAvcnVuL2xvY2sKdG1wZnMgICAgICAgICAgICAgOTc0MzIwICAgICAgIDAgICAgOTc0MzIwICAgMCUgL3N5cy9mcy9jZ3JvdXAKdG1wZnMgICAgICAgICAgICAgMTk0ODY4ICAgICAgIDAgICAgMTk0ODY4ICAgMCUgL3J1bi91c2VyLzAK" | base64 --decode
в обоих случаях получается примерно такой вывод:
Filesystem     1K-blocks    Used Available Use% Mounted on
udev             2003712       0   2003712   0% /dev
tmpfs             362084    5156    356928   2% /run
/dev/sda1       16381864 1873828  13652844  13% /
tmpfs             974320       0    974320   0% /dev/shm
tmpfs               5120       0      5120   0% /run/lock
tmpfs             974320       0    974320   0% /sys/fs/cgroup
tmpfs             194868       0    194868   0% /run/user/0

Теперь предлагаю рассмотреть вариант, когда скрипт или команда выполняется не мгновенно:
# virsh qemu-agent-command ubuntu16 '{"execute":"guest-exec", "arguments":{"path":"/bin/sleep","arg":["60"],"capture-output":true}}'
{"return":{"pid":2360}}
Если запросить статус такой команды, в процессе выполнения, то в ответе будет exited: false:
# virsh qemu-agent-command ubuntu16 '{"execute":"guest-exec-status", "arguments":{"pid":2360}}'
{"return":{"exited":false}}
Внутри виртуальной машины в этот момент ситуация выглядит примерно так:
root      2165  0.0  0.1  95760  3140 ?        Ssl  06:45   0:00 /usr/sbin/qemu-ga --daemonize -m virtio-serial -p /dev/virtio-ports/org.qemu.guest_agent.0
root      2360  0.0  0.0   6012   712 ?        S    08:05   0:00  \_ /bin/sleep 60
Т.е. qemu агент является родительским процессом для наших команд.
Выполним еще раз - ага, пока выполняется:
# virsh qemu-agent-command ubuntu16 '{"execute":"guest-exec-status", "arguments":{"pid":2360}}'
{"return":{"exited":false}}
И наконец, когда команда или скрипт завершаются, в ответе будет "стандартный" статус :
# virsh qemu-agent-command ubuntu16 '{"execute":"guest-exec-status", "arguments":{"pid":2360}}'
{"return":{"exitcode":0,"exited":true}}
Обращаю внимание, что пока команда не выполнилась, можно запрашивать ее статус по pid'у неограниченное кол-во раз.
Но после выполнения первый запрос к данным статуса, очищает эту информацию и повторное обращение выдаст ошибку:
# virsh qemu-agent-command ubuntu16 '{"execute":"guest-exec-status", "arguments":{"pid":2360}}'
error: internal error: unable to execute QEMU agent command 'guest-exec-status': Invalid parameter 'pid'
Этот момент очень важен для организации скриптов-обёрток или других систем, использользующих данные команды или их выводы.

Отлично, с этим разобрались. Теперь предлагаю посмотреть, что происходит если выполняемая программа завершается не успешно, например запуск sleep с опцией -1:
# virsh qemu-agent-command ubuntu16 '{"execute":"guest-exec", "arguments":{"path":"/bin/sleep","arg":["-1"],"capture-output":true}}'
{"return":{"pid":2389}}
Вывод ошибки помещается в err-data и кодируется base64:
# virsh qemu-agent-command ubuntu16 '{"execute":"guest-exec-status", "arguments":{"pid":2389}}'
{"return":{"exitcode":1,"err-data":"L2Jpbi9zbGVlcDogaW52YWxpZCBvcHRpb24gLS0gJzEnClRyeSAnL2Jpbi9zbGVlcCAtLWhlbHAnIGZvciBtb3JlIGluZm9ybWF0aW9uLgo=","exited":true}}
в err-data помещается все что попадает на stderr'a:
/bin/sleep: invalid option -- '1'
Try '/bin/sleep --help' for more information

Переменные out-data и err-data заполняются потоками stdout и stderr (если те не пустые), т.е. даже при успешном выполнении команды, которая что-то выводит на stderr, в status'e будет фигурировать err-data.
Например вывод статуса команды:
# virsh qemu-agent-command ubuntu16 '{"execute":"guest-exec", "arguments":{"path":"/usr/bin/curl","arg":["www.com"],"capture-output":true}}'
{"return":{"pid":3100}}
# virsh qemu-agent-command ubuntu16 '{"execute":"guest-exec-status", "arguments":{"pid":3100}}'
вернет нам заполненные err-data и out-data одновременно.

В следующий раз я расскажу о чтении\редактировании файлов и других возможностях qemu-agent.

1 комментарий: