Глава 7. Применение Python для построения экземпляров KVM и управления ими
Содержание
- Глава 7. Применение Python для построения экземпляров KVM и управления ими
В этой глве мы собираемся обсудить такие темы:
-
Установку и применение имеющейся библиотеки libvirt Python
-
Определение экземпляров KVM при помощи Python
-
Запуск, останов и удаление экземпляров KVM при помощи Python
-
Инспектирование экземпляров KVM при помощи Python
-
Построение простого сервера REST API при помощи libvirt и bottle
Библиотека libvirt
выставляет не зависящий от виртуализации интерфейс для
управления полным жизненным циклом экземпляров KVM (и прочих технологий, таких как XEN и LXC). Используя имеющиеся
компоновки Python мы можем определять, запускать, уничтожать и удалять виртуальных гостей совместно со всем что ещё
реализуется инструментарием пространства пользователя virsh
. В действительности
мы можем обнаружить, что наша команда virsh
применяет различные совместно
используемые библиотеки libvirt, исполнив следующее:
root@kvm:~# ldd /usr/bin/virsh | grep libvirt
libvirt-lxc.so.0 => /usr/lib/x86_64-linux-gnu/libvirt-lxc.so.0 (0x00007fd050d88000)
libvirt-qemu.so.0 => /usr/lib/x86_64-linux-gnu/libvirt-qemu.so.0 (0x00007fd050b84000)
libvirt.so.0 => /usr/lib/x86_64-linux-gnu/libvirt.so.0 (0x00007fd050394000)
root@kvm:~#
Модуль Python libvirt также предоставляет методы для мониторинга и вывода отчетов по использованию ЦПУ, памяти, хранилища и сетевых ресурсов в самом узле гипервизора и прочие возможности зависящие от используемого типа драйвера гипервизора.
В этой главе мы собираемся воспользоваться небольшим подмножеством API libvirt Pyton для определения, запуска, инспекции и останова некого экземпляра KVM.
Замечание | |
---|---|
Для полного списка функций, классов и методов, предоставляемых модулем libvirt Python выполните:
|
В этом рецепте мы собираемся установить модуль libvirt Python и его зависимости, создать некую новую виртуальную
среду и установить оболочку командных строк iPython
для интерактивных вычислений.
Для этого рецепта нам понадобится следующее:
-
Некий хост Ubuntu с установленными и настроенными libvirt и QEMU
-
Файл сырого образа
debian.img
, который мы построили в рецепте Установка пользовательской ОС в образ при помощи debootstrap из Главы 1 -
Интерпретатор Python 2.7, обычно предоставляемый пакетом
python2.7
Для установки модуля libvirt Python, утилиты iPython
и создания новой
виртуальной среды для проверок выполните следующие шаги:
-
Установите пакеты разработки Python
pip
иvirtualenv
:root@kvm:~# apt-get install python-pip python-dev pkg-config build-essential autoconf libvirt-dev root@kvm:~# pip install virtualenv Downloading/unpacking virtualenv Downloading virtualenv-15.1.0-py2.py3-none-any.whl (1.8MB): 1.8MB downloaded Installing collected packages: virtualenv Successfully installed virtualenv Cleaning up... root@kvm:~#
-
Создайте некую новую среду Python и активируйте её:
root@kvm:~# mkdir kvm_python root@kvm:~# virtualenv kvm_python/ New python executable in /root/kvm_python/bin/python Installing setuptools, pip, wheel...done. root@kvm:~# source kvm_python/bin/activate (kvm_python) root@kvm:~# cd kvm_python/ (kvm_python) root@kvm:~/kvm_python# ls -la total 28 drwxr-xr-x 6 root root 4096 May 9 17:28 . drwx------ 8 root root 4096 May 9 17:28 .. drwxr-xr-x 2 root root 4096 May 9 17:28 bin drwxr-xr-x 2 root root 4096 May 9 17:28 include drwxr-xr-x 3 root root 4096 May 9 17:28 lib drwxr-xr-x 2 root root 4096 May 9 17:28 local -rw-r--r-- 1 root root 60 May 9 17:28 pip-selfcheck.json (kvm_python) root@kvm:~/kvm_python#
-
Установите необходимый нам модуль
libvirt
:(kvm_python) root@kvm:~/kvm_python# pip install libvirt-python Collecting libvirt-python Using cached libvirt-python-3.3.0.tar.gz Building wheels for collected packages: libvirt-python Running setup.py bdist_wheel for libvirt-python ... done Stored in directory: /root/.cache/pip/wheels/67/f0/5c/c939bf8fcce5387a36efca53eab34ba8e94a28f244fd1757c1 Successfully built libvirt-python Installing collected packages: libvirt-python Successfully installed libvirt-python-3.3.0 (kvm_python) root@kvm:~/kvm_python# pip freeze appdirs==1.4.3 libvirt-python==3.3.0 packaging==16.8 pyparsing==2.2.0 six==1.10.0 (kvm_python) root@kvm:~/kvm_python# python --version Python 2.7.6 (kvm_python) root@kvm:~/kvm_python#
-
Установите
iPython
и запустите его:(kvm_python) root@kvm:~/kvm_python# apt-get install ipython ... (kvm_python) root@kvm:~/kvm_python# ipython Python 2.7.6 (default, Oct 26 2016, 20:30:19) Type "copyright", "credits" or "license" for more information. IPython 1.2.1 -- An enhanced Interactive Python. ? -> Introduction and overview of IPython's features. %quickref -> Quick reference. help -> Python's own help system. object? -> Details about 'object', use 'object??' for extra details. In [1]:
На шаге 1 мы начали с установки необходимых пакетов зависимостей. Поскольку для своих разработок мы собираемся применять некую
виртуальную среду Python, мы также установили и пакет virtualenv
. Сам модуль libvirt
Python мы намерены установить в полученной виртуальной среде с помощью диспетчера пакетов pip
,
поскольку мы не хотим перепачкать свой хост избыточными пакетами.
На шаге 2 мы создали и активировали некую новую виртуальную среду, а на шаге 3 установили нужный нам модуль libvirt Python.
Наконец, на шаге 4 мы установили и запустили инструментарий разработки iPython
,
которым мы намерены пользоваться на протяжении данной главы.
В этом рецепте мы намерены определить некий новый экземпляр при помощи модуля libvirt Python, который мы установили в
своём предыдущем рецепте. Для последующих примеров мы намерены применять виртуальную среду и инструментарий разработки
iPython
.
Для этого рецепта нам понадобится следующее:
-
Некий хост Ubuntu с установленными и настроенными libvirt и QEMU
-
Файл сырого образа
debian.img
, который мы построили в рецепте Установка пользовательской ОС в образ при помощи debootstrap из Главы 1 -
Python 2.7, набор инструментов
iPython
и виртуальная среда, которую мы создали в рецепте данной главы Установка и применение библиотеки libvirt Python
Для определения некоего нового экземпляра KVM при помощи модуля libvirt Python следуйте приводимым далее инструкциям:
-
В своём интерпретаторе iPython импортируйте модуль
libvirt
:In [1]: import libvirt In [2]:
-
Создайте необходимую строку определения экземпляра:
In [2]: xmlconfig = """ <domain type='kvm' id='1'> <name>kvm_python</name> <memory unit='KiB'>1048576</memory> <currentMemory unit='KiB'>1048576</currentMemory> <vcpu placement='static'>1</vcpu> <resource> <partition>/machine</partition> </resource> <os> <type arch='x86_64' machine='pc-i440fx-trusty'>hvm</type> <boot dev='hd'/> </os> <features> <acpi/> <apic/> <pae/> </features> <clock offset='utc'/> <on_poweroff>destroy</on_poweroff> <on_reboot>restart</on_reboot> <on_crash>restart</on_crash> <devices> <emulator>/usr/bin/qemu-system-x86_64</emulator> <disk type='file' device='disk'> <driver name='qemu' type='raw'/> <source file='/tmp/debian.img'/> <backingStore/> <target dev='hda' bus='ide'/> <alias name='ide0-0-0'/> <address type='drive' controller='0' bus='0' target='0' unit='0'/> </disk> <controller type='usb' index='0'> <alias name='usb'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/> </controller> <controller type='pci' index='0' model='pci-root'> <alias name='pci.0'/> </controller> <controller type='ide' index='0'> <alias name='ide'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/> </controller> <interface type='network'> <mac address='52:54:00:da:02:01'/> <source network='default' bridge='virbr0'/> <target dev='vnet0'/> <model type='rtl8139'/> <alias name='net0'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/> </interface> <serial type='pty'> <source path='/dev/pts/5'/> <target port='0'/> <alias name='serial0'/> </serial> <console type='pty' tty='/dev/pts/5'> <source path='/dev/pts/5'/> <target type='serial' port='0'/> <alias name='serial0'/> </console> <input type='mouse' bus='ps2'/> <input type='keyboard' bus='ps2'/> <graphics type='vnc' port='5900' autoport='yes' listen='0.0.0.0'> <listen type='address' address='0.0.0.0'/> </graphics> <video> <model type='cirrus' vram='16384' heads='1'/> <alias name='video0'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/> </video> <memballoon model='virtio'> <alias name='balloon0'/> <address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/> </memballoon> </devices> </domain> """ In [3]:
-
Получите некое подключение к своему гипервизору:
In [3]: conn = libvirt.open('qemu:///system') In [4]:
-
Определите некий новый экземпляр без его запуска:
In [4]: instance = conn.defineXML(xmlconfig) In [5]:
-
Перечислите все определённые в этом хосте экземпляры:
In [5]: instances = conn.listDefinedDomains() In [6]: print 'Defined instances: {}'.format(instances) Defined instances: ['kvm_python'] In [7]:
-
Проверьте что ваш экземпляр был создан с помощью команды
virsh
:(kvm_python) root@kvm:~/kvm_python# virsh list --all Id Name State ---------------------------------------------------- - kvm_python shut off (kvm_python) root@kvm:~/kvm_python#
В этом рецепте мы воспользовались предварительно имевшимся у нас сырым образом Debian, который мы создали в Главе 1, Начало работы с QEMU и KVM для определения необходимого экземпляра KVM.
На шаге 1 мы импортировали пакет libvirt и продолжили определять свой новый экземпляр KVM. На шаге 2 своей переменной
xmlconfig
мы назначили соответствующую форматированную строку XML.
Обратите внимание, что это определение содержит соответствующие название и местоположение необходимого файла образа.
На шаге 3 мы получили некий объект подключения и назначили его переменной conn
.
Теперь мы можем применять доступные методы для определения своей гостевой KVM.
Совет | |
---|---|
Для перечисления всех доступных методов для некоторого объекта в iPython наберите соответствующее название переменной
с последующей
Для получения подсказки по некоторому методу, добавьте символ вопроса в самом конце интересующего вас метода:
Некоторые гипервизоры могут препятствовать данной операции если существует некая текущая операция блочного
копирования в неустановившемся определяемом домене; в таком случае вначале воспользуйтесь
Для освобождения ресурсов после того как объект домена больше не требуется, следует воспользоваться
|
На шаге 4 мы воспользовались методом defineXML()
для объекта подключения
libvirt.virConnect
, передав соответствующую строку определения XML и назначив
её своей переменной экземпляра. Мы можем определить значение типа своего нового объекта выполним следующее:
n [7]: type(instance)
Out[7]: libvirt.virDomain
In [8]:
На шаге 5 мы вывели перечень всех определённых в этом хосте экземпляров воспользовавшись методом
listDefinedDomains()
и подтвердили полученный результат применив на шаге 6
команду virsh
.
Давайте добавим в свой предыдущий код Python некую простейшую проверку ошибок и запишем всё это в некий новый файл. Мы намерены выполнять добавления к этому файлу в последующих рецептах:
(kvm_python) root@kvm:~/kvm_python# cat kvm.py
import libvirt
xmlconfig = """
<domain type='kvm' id='1'>
<name>kvm_python</name>
<memory unit='KiB'>1048576</memory>
<currentMemory unit='KiB'>1048576</currentMemory>
<vcpu placement='static'>1</vcpu>
<resource>
<partition>/machine</partition>
</resource>
<os>
<type arch='x86_64' machine='pc-i440fx-trusty'>hvm</type>
<boot dev='hd'/>
</os>
<features>
<acpi/>
<apic/>
<pae/>
</features>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<devices>
<emulator>/usr/bin/qemu-system-x86_64</emulator>
<disk type='file' device='disk'>
<driver name='qemu' type='raw'/>
<source file='/tmp/debian.img'/>
<backingStore/>
<target dev='hda' bus='ide'/>
<alias name='ide0-0-0'/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>
<controller type='usb' index='0'>
<alias name='usb'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
</controller>
<controller type='pci' index='0' model='pci-root'>
<alias name='pci.0'/>
</controller>
<controller type='ide' index='0'>
<alias name='ide'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
</controller>
<interface type='network'>
<mac address='52:54:00:da:02:01'/>
<source network='default' bridge='virbr0'/>
<target dev='vnet0'/>
<model type='rtl8139'/>
<alias name='net0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
<serial type='pty'>
<source path='/dev/pts/5'/>
<target port='0'/>
<alias name='serial0'/>
</serial>
<console type='pty' tty='/dev/pts/5'>
<source path='/dev/pts/5'/>
<target type='serial' port='0'/>
<alias name='serial0'/>
</console>
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<graphics type='vnc' port='5900' autoport='yes' listen='0.0.0.0'>
<listen type='address' address='0.0.0.0'/>
</graphics>
<video>
<model type='cirrus' vram='16384' heads='1'/>
<alias name='video0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</video>
<memballoon model='virtio'>
<alias name='balloon0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
</memballoon>
</devices>
</domain>
"""
conn = libvirt.open('qemu:///system')
if conn == None:
print 'Failed to connecto to the hypervizor'
exit(1)
instance = conn.defineXML(xmlconfig)
if instance == None:
print 'Failed to define the instance'
exit(1)
instances = conn.listDefinedDomains()
print 'Defined instances: {}'.format(instances)
conn.close()
(kvm_python) root@kvm:~/kvm_python#
Для исполнения данного сценария вначале убедитесь что отменили определение своего экземпляра
python_kmv
, затем исполните:
(kvm_python) root@kvm:~/kvm_python# python kvm.py
Defined instances: ['kvm_python']
(kvm_python) root@kvm:~/kvm_python#
В этом рецепте мы намерены воспользоваться методом create()
для объекта
своего экземпляра, который мы определили в своём предыдущем рецепте для его запуска и методом
destroy()
для его останова.
Для получения информации относительно метода create()
исполните:
In [1]: instance.create?
Type: instancemethod
String Form:<bound method virDomain.create of <libvirt.virDomain object at 0x7fc5d9b97d90>>
File: /root/kvm_python/lib/python2.7/site-packages/libvirt.py
Definition: instance.create(self)
Docstring:
Launch a defined domain. If the call succeeds the domain moves from the
defined to the running domains pools. The domain will be paused only
if restoring from managed state created from a paused domain. For more
control, see virDomainCreateWithFlags().
In [2]:
Для этого рецепта нам понадобится следующее:
-
Некий хост Ubuntu с установленными и настроенными libvirt и QEMU
-
Файл сырого образа
debian.img
, который мы построили в рецепте Установка пользовательской ОС в образ при помощи debootstrap из Главы 1 -
Python 2.7, набор инструментов
iPython
и виртуальная среда, которую мы создали в рецепте данной главы Установка и применение библиотеки libvirt PythonОбъект экземпляра, созданный нами в рецепте данной главы Определение экземпляров KVM с помощью Python
Для запуска определённого нами ранее экземпляра KVM, получения его состояния и, наконец, его останова, воспользуйтесь следующим кодом Python:
-
Для своего объекта экземпляра вызовите метод
create()
:In [1]: instance.create() Out[1]: 0 In [2]:
-
Убедитесь что этот экземпляр пребывает в запущенном состоянии вызвав для объекта этого экземпляра метод
isActive()
:In [2]: instance.isActive() Out[2]: 1 In [3]:
-
Проверьте состояние этого экземпляра KVM из ОС его хоста:
(kvm_python) root@kvm:~/kvm_python# virsh list --all Id Name State ---------------------------------------------------- 5 kvm_python running (kvm_python) root@kvm:~/kvm_python#
-
остановите это экземпляр при помощи метода
destroy()
:In [3]: instance.destroy() Out[3]: 0 In [4]:
-
Убедитесь что этот экземпляр был ликвидирован:
In [4]: instance.isActive() Out[4]: 0 In [5]:
-
Удалите определение экземпляра и перечислите всех определённых гостей:
In [5]: instance.undefine() Out[5]: 0 In [6]: conn.listDefinedDomains() Out[6]: [] In [7]:
На шаге 1 мы вызвали метод create()
для запуска своего определённого экземпляра.
В случае успеха этот гость перейдёт из выключенного состояния в рабочее, что мы и наблюдаем в выводе своей команды на шаге 3.
На шаге 2 мы применяем метод isActive()
для проверки значения состояния этого
экземпляра. Вывод 1 указывает что этот экземпляр запущен.
На шаге 4 мы останавливаем свой экземпляр при помощи метода destroy()
и подтверждаем это на шаге 5.
Наконец, на шаге 6 мы удаляем этот экземпляр при помощи метода undefine()
и выводим перечень всех определённых экземпляров с помощью вызова
listDefinedDomains()
.
Давайте добавим новый код в тот сценарий Python, который мы начали в своём рецепте Определение экземпляров KVM с помощью Python. Наш обновлённый сценарий должен теперь выглядеть так:
(kvm_python) root@kvm:~/kvm_python# cat kvm.py
import libvirt
import time
xmlconfig = """
<domain type='kvm' id='1'>
<name>kvm_python</name>
<memory unit='KiB'>1048576</memory>
<currentMemory unit='KiB'>1048576</currentMemory>
<vcpu placement='static'>1</vcpu>
<resource>
<partition>/machine</partition>
</resource>
<os>
<type arch='x86_64' machine='pc-i440fx-trusty'>hvm</type>
<boot dev='hd'/>
</os>
<features>
<acpi/>
<apic/>
<pae/>
</features>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<devices>
<emulator>/usr/bin/qemu-system-x86_64</emulator>
<disk type='file' device='disk'>
<driver name='qemu' type='raw'/>
<source file='/tmp/debian.img'/>
<backingStore/>
<target dev='hda' bus='ide'/>
<alias name='ide0-0-0'/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>
<controller type='usb' index='0'>
<alias name='usb'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
</controller>
<controller type='pci' index='0' model='pci-root'>
<alias name='pci.0'/>
</controller>
<controller type='ide' index='0'>
<alias name='ide'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
</controller>
<interface type='network'>
<mac address='52:54:00:da:02:01'/>
<source network='default' bridge='virbr0'/>
<target dev='vnet0'/>
<model type='rtl8139'/>
<alias name='net0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
<serial type='pty'>
<source path='/dev/pts/5'/>
<target port='0'/>
<alias name='serial0'/>
</serial>
<console type='pty' tty='/dev/pts/5'>
<source path='/dev/pts/5'/>
<target type='serial' port='0'/>
<alias name='serial0'/>
</console>
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<graphics type='vnc' port='5900' autoport='yes' listen='0.0.0.0'>
<listen type='address' address='0.0.0.0'/>
</graphics>
<video>
<model type='cirrus' vram='16384' heads='1'/>
<alias name='video0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</video>
<memballoon model='virtio'>
<alias name='balloon0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
</memballoon>
</devices>
</domain>
"""
conn = libvirt.open('qemu:///system')
if conn == None:
print 'Failed to connecto to the hypervizor'
exit(1)
instance = conn.defineXML(xmlconfig)
if instance == None:
print 'Failed to define the instance'
exit(1)
instances = conn.listDefinedDomains()
print 'Defined instances: {}'.format(instances)
time.sleep(5)
if instance.create() < 0:
print 'Failed to start the {} instance'.format(instance.name())
exit(1)
if instance.isActive():
print 'The instance {} is running'.format(instance.name())
else:
print 'The instance {} is not running'.format(instance.name())
time.sleep(5)
if instance.destroy() < 0:
print 'Failed to stop the {} instance'.format(instance.name())
exit(1)
else:
print 'The instance {} has been destroyed'.format(instance.name())
if instance.undefine() < 0:
print 'Failed to remove the {} instance'.format(instance.name())
exit(1)
else:
print 'The instance {} has been undefined'.format(instance.name())
conn.close()
(kvm_python) root@kvm:~/kvm_python#
Запуск этого сценария должен определить некий новый экземпляр, запустить его, остановить его и, наконец, удалить его:
(kvm_python) root@kvm:~/kvm_python# python kvm.py
Defined instances: ['kvm1', 'kvm_python']
The instance kvm_python is running
The instance kvm_python has been destroyed
The instance kvm_python has been undefined
(kvm_python) root@kvm:~/kvm_python#
В своём предыдущем сценарии мы воспользовались методом instance.name()
для
получения установленного названия вашей гостевой KVM и его вывода на печать. Мы также выполняем очистку, закрывая
установленное подключение к своему гипервизору при помощи вызова conn.close()
.
В этом рецепте мы намерены собрать информацию об экземпляре при помощи методов из класса
libvirt.virDomain
.
Замечание | |
---|---|
Для получения дополнительных сведений относительно API libvirt Python обратитссь, пожалуйста, к официальной документации. |
Для этого рецепта нам понадобится следующее:
-
Некий хост Ubuntu с установленными и настроенными libvirt и QEMU
-
Файл сырого образа
debian.img
, который мы построили в рецепте Установка пользовательской ОС в образ при помощи debootstrap из Главы 1 -
Python 2.7, набор инструментов
iPython
и виртуальная среда, которую мы создали в рецепте данной главы Установка и применение библиотеки libvirt PythonОбъект экземпляра, созданный нами в рецепте данной главы Определение экземпляров KVM с помощью Python, который представляет соответствующую гостевую KVM.
Для сбора информации о ЦПУ, памяти и состоянии для исполняемого экземпляра воспользуйтесь следующими методами Python:
-
Получите название своего экземпляра:
In [1]: instance.name() Out[1]: 'kvm_python' In [2]:
-
Убедитесь что ваш экземпляр запущен:
In [2]: instance.isActive() Out[2]: 1 In [3]:
-
Соберите статистические данные по своему экземпляру KVM:
In [3]: instance.info() Out[3]: [1, 1048576L, 1048576L, 1, 10910000000L] In [4]:
-
Получите максимальный объём физической памяти выделенной данному экземпляру:
In [4]: instance.maxMemory() Out[4]: 1048576L In [5]:
-
Выделите статистические данные по ЦПУ этого экземпляра:
In [5]: instance.getCPUStats(1) Out[5]: [{'cpu_time': 10911545901L, 'system_time': 1760000000L, 'user_time': 1560000000L}] In [6]:
-
Убедитесь что ваша виртуальная машина применяет аппаратное ускорение:
In [6]: instance.OSType() Out[6]: 'hvm' In [7]:
-
Соберите значнения состояний экземпляра:
In [82]: state, reason = instance.state() In [83]: if state == libvirt.VIR_DOMAIN_NOSTATE: ....: print('The state is nostate') ....: elif state == libvirt.VIR_DOMAIN_RUNNING: ....: print('The state is running') ....: elif state == libvirt.VIR_DOMAIN_BLOCKED: ....: print('The state is blocked') ....: elif state == libvirt.VIR_DOMAIN_PAUSED: ....: print('The state is paused') ....: elif state == libvirt.VIR_DOMAIN_SHUTDOWN: ....: print('The state is shutdown') ....: elif state == libvirt.VIR_DOMAIN_SHUTOFF: ....: print('The state is shutoff') ....: elif state == libvirt.VIR_DOMAIN_CRASHED: ....: print('The state is crashed') ....: elif state == libvirt.VIR_DOMAIN_PMSUSPENDED: ....: print('The state is suspended') ....: else: ....: print('The state is unknown') ....: The state is running In [84]:
В этом рецепте мы пользуемся рядом методов из класса libvirt.virDomain
.
Давайте рассмотрим более подробно что они делают и затем добавим их в пример своего сценария
kvm.py
, который мы начали в своём рецепте
Определение экземпляров KVM с помощью Python.
На шагах 1 и 2 мы получили название своего экземпляра KVM и проверили что он находится в запущенном состоянии.
На шаге 3 мы собрали следующую информацию о своём экземпляре, возвращённую в виде списка Python:
-
state: Значение состояния данного экземпляра, который определён в перечислимом типе virDomainState
-
maxMemory: Максимальный размер памяти применяемый данным гостем
-
memory: Текущий объём памяти, используемой данным экземпляром
-
nbVirtCPU: Общее число выделенных виртуальных ЦПУ
-
cpuTime: Значение времени, использованного данным экземпляром (в наносекундах)
На шаге 4 мы собрали значение памяти, выделенной нашему экземпляру. Обратите внимание как устанавливается соответствие с выводом соответствующей функции на шаге 3.
На шаге 5 мы получили информацию о ЦПУ своего гостевого экземпляра. Мы можем видеть значение времени ЦПУ системы и пользователя.
Вывод hvm
из метода OSType()
на шаге 6
указывает что наша гостевая ОС разработана для работы на голом железе, требуя полной виртуализации, например, KVM.
На самом последнем шаге данного рецепта мы вызываем метод state()
для
возврата всех текущих состояний экземпляра.
Давайте завершим данную главу полным примером сценария, содержащим все те методы, которые мы применяли вплоть до настоящего момента:
(kvm_python) root@kvm:~/kvm_python# cat kvm.py
import libvirt
import time
def main():
xmlconfig = """
<domain type='kvm' id='1'>
<name>kvm_python</name>
<memory unit='KiB'>1048576</memory>
<currentMemory unit='KiB'>1048576</currentMemory>
<vcpu placement='static'>1</vcpu>
<resource>
<partition>/machine</partition>
</resource>
<os>
<type arch='x86_64' machine='pc-i440fx-trusty'>hvm</type>
<boot dev='hd'/>
</os>
<features>
<acpi/>
<apic/>
<pae/>
</features>
<clock offset='utc'/>
<on_poweroff>destroy</on_poweroff>
<on_reboot>restart</on_reboot>
<on_crash>restart</on_crash>
<devices>
<emulator>/usr/bin/qemu-system-x86_64</emulator>
<disk type='file' device='disk'>
<driver name='qemu' type='raw'/>
<source file='/tmp/debian.img'/>
<backingStore/>
<target dev='hda' bus='ide'/>
<alias name='ide0-0-0'/>
<address type='drive' controller='0' bus='0' target='0' unit='0'/>
</disk>
<controller type='usb' index='0'>
<alias name='usb'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x2'/>
</controller>
<controller type='pci' index='0' model='pci-root'>
<alias name='pci.0'/>
</controller>
<controller type='ide' index='0'>
<alias name='ide'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x01' function='0x1'/>
</controller>
<interface type='network'>
<mac address='52:54:00:da:02:01'/>
<source network='default' bridge='virbr0'/>
<target dev='vnet0'/>
<model type='rtl8139'/>
<alias name='net0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x03' function='0x0'/>
</interface>
<serial type='pty'>
<source path='/dev/pts/5'/>
<target port='0'/>
<alias name='serial0'/>
</serial>
<console type='pty' tty='/dev/pts/5'>
<source path='/dev/pts/5'/>
<target type='serial' port='0'/>
<alias name='serial0'/>
</console>
<input type='mouse' bus='ps2'/>
<input type='keyboard' bus='ps2'/>
<graphics type='vnc' port='5900' autoport='yes' listen='0.0.0.0'>
<listen type='address' address='0.0.0.0'/>
</graphics>
<video>
<model type='cirrus' vram='16384' heads='1'/>
<alias name='video0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x02' function='0x0'/>
</video>
<memballoon model='virtio'>
<alias name='balloon0'/>
<address type='pci' domain='0x0000' bus='0x00' slot='0x04' function='0x0'/>
</memballoon>
</devices>
</domain>
"""
conn = libvirt.open('qemu:///system')
if conn == None:
print 'Failed to connecto to the hypervizor'
exit(1)
instance = conn.defineXML(xmlconfig)
if instance == None:
print 'Failed to define the instance'
exit(1)
instances = conn.listDefinedDomains()
print 'Defined instances: {}'.format(instances)
time.sleep(5)
if instance.create() < 0:
print 'Failed to start the {} instance'.format(instance.name())
exit(1)
if instance.isActive():
print 'The instance {} is running'.format(instance.name())
else:
print 'The instance {} is not running'.format(instance.name())
print 'The instance state, max memory, current memory, CPUs and time is {}'.format(instance.info())
print 'The CPU, system and user times are {}'.format(instance.getCPUStats(1))
print 'The OS type for the {} instance is {}'.format(instance.name(), instance.OSType())
time.sleep(5)
if instance.destroy() < 0:
print 'Failed to stop the {} instance'.format(instance.name())
exit(1)
else:
print 'The instance {} has been destroyed'.format(instance.name())
if instance.undefine() < 0:
print 'Failed to remove the {} instance'.format(instance.name())
exit(1)
else:
print 'The instance {} has been undefined'.format(instance.name())
conn.close()
if __name__ == "__main__":
main()
(kvm_python) root@kvm:~/kvm_python#
Его исполнение предоставляет следующий вывод, в предположении что предварительно было удалено определение экземпляра
kvm_python
:
(kvm_python) root@kvm:~/kvm_python# python kvm.py
Defined instances: ['kvm_python']
The instance kvm_python is running
The instance state, max memory, current memory, CPUs and time is [1, 1048576L, 1048576L, 1, 40000000L]
The CPU, system and user times are [{'cpu_time': 42349077L, 'system_time': 0L, 'user_time': 30000000L}]
The OS type for the kvm_python instance is hvm
The instance kvm_python has been destroyed
The instance kvm_python has been undefined
(kvm_python) root@kvm:~/kvm_python#
В этом рецепте мы намерены все те методы libvirt, которые мы видели в предыдущих рецептах для построения образца сервера RESTfull API, воспользовавшись микро инструментарием bottle для Python.
Bottle описывается как быстрая и простая микро инфраструктура WSGI ( Web Server Gateway Interface) для Python, которая распределяется как некий отдельный файл модуля.
Замечание | |
---|---|
Для получения дополнительной информации относительно микро инфраструктуры bottle посетите, пожалуйста, её официальный сайт. |
Тот простой сервер API, который мы реализовываем, будет принимать такие запросы:
-
list: метод
get
, который перечисляет все определённые экземпляры libvirt. -
define: метод
post
, применяемый для определения какого- то нового экземпляра KVM. Мы собираемся предоставлять необходимое определение XML в качестве заголовка в этом запросе post. -
start: метод
post
для запуска некого экземпляра. Название запускаемого экземпляра буде представлено в самом заголовке данного запроса. -
stop: метод
post
останова некого экземпляра KVM. -
undefine: метод
post
удаления данного экземпляра.
Для этого рецепта нам понадобится следующее:
-
Некий хост Ubuntu с установленными и настроенными libvirt и QEMU
-
Файл сырого образа
debian.img
, который мы построили в рецепте Установка пользовательской ОС в образ при помощи debootstrap из Главы 1 -
Python 2.7, набор инструментов
iPython
и виртуальная среда, которую мы создали в рецепте данной главы Установка и применение библиотеки libvirt PythonИнструмент командной строки
curl
для обмена данными с URL синтаксисом, который обычно предоставляется соответствующим пакетом curl.
Последующие шаги описывают как установить необходимый модуль bottle и наш простой сервер REST API, написанный на Python:
-
Установите модуль
bottle
:(kvm_python) root@kvm:~/kvm_python# pip install bottle Collecting bottle ... Downloading bottle-0.12.13.tar.gz (70kB) 100% |████████████████████████████████| 71kB 4.5MB/s ... Successfully installed bottle-0.12.13 (kvm_python) root@kvm:~/kvm_python#
-
Создайте некий новый файл, импортируйте модули libvirt и bottle и напишите метод подключения libvirt:
(kvm_python) root@kvm:~/kvm_python# vim kvm_api.py import libvirt from bottle import run, request, get, post, HTTPResponse def libvirtConnect(): try: conn = libvirt.open('qemu:///system') except libvirt.libvirtError: conn = None return conn
-
Реализуйте маршрут и функцию
/define
:def defineKVMInstance(template): conn = libvirtConnect() if conn == None: return HTTPResponse(status=500, body='Error defining instance\n') else: try: conn.defineXML(template) return HTTPResponse(status=200, body='Instance defined\n') except libvirt.libvirtError: return HTTPResponse(status=500, body='Error defining instance\n') @post('/define') def build(): template = str(request.headers.get('X-KVM-Definition')) status = defineKVMInstance(template) return status
-
Реализуйте маршрут и функцию
/undefine
:def undefineKVMInstance(name): conn = libvirtConnect() if conn == None: return HTTPResponse(status=500, body='Error undefining instance\n') else: try: instance = conn.lookupByName(name) instance.undefine() return HTTPResponse(status=200, body='Instance undefined\n') except libvirt.libvirtError: return HTTPResponse(status=500, body='Error undefining instance\n') @post('/undefine') def build(): name = str(request.headers.get('X-KVM-Name')) status = undefineKVMInstance(name) return status
-
Реализуйте маршрут и функцию
/start
:def startKVMInstance(name): conn = libvirtConnect() if conn == None: return HTTPResponse(status=500, body='Error starting instance\n') else: try: instance = conn.lookupByName(name) instance.create() return HTTPResponse(status=200, body='Instance started\n') except libvirt.libvirtError: return HTTPResponse(status=500, body='Error starting instance\n') @post('/start') def build(): name = str(request.headers.get('X-KVM-Name')) status = startKVMInstance(name) return status
-
Реализуйте маршрут и функцию
/stop
:def stopKVMInstance(name): conn = libvirtConnect() if conn == None: return HTTPResponse(status=500, body='Error stopping instance\n') else: try: instance = conn.lookupByName(name) instance.destroy() return HTTPResponse(status=200, body='Instance stopped\n') except libvirt.libvirtError: return HTTPResponse(status=500, body='Error stopping instance\n') @post('/stop') def build(): name = str(request.headers.get('X-KVM-Name')) status = stopKVMInstance(name) return status
-
Реализуйте маршрут и функцию
/list
:def getLibvirtInstances(): conn = libvirtConnect() if conn == None: return HTTPResponse(status=500, body='Error listing instances\n') else: try: instances = conn.listDefinedDomains() return instances except libvirt.libvirtError: return HTTPResponse(status=500, body='Error listing instances\n') @get('/list') def list(): kvm_list = getLibvirtInstances() return "List of KVM instances: {}\n".format(kvm_list)
-
Вызовите метод
run()
для запуска своего сервера WSGI после исполнения данного сценария:run(host='localhost', port=8080, debug=True)
Давайте более детально рассмотрим свой код. Для начала сохраните все предыдущие изменения в некий файл и исполните этот сценарий:
kvm_python) root@kvm:~/kvm_python# python kvm_api.py
Bottle v0.12.13 server starting up (using WSGIRefServer())...
Listening on http://localhost:8080/
Hit Ctrl-C to quit.
В неком отдельном терминале определите какой- то новый экземпляр, передав соответствующее необходимое определение XMLв виде заголовка:
(kvm_python) root@kvm:~/kvm_python# curl -s -i -XPOST localhost:8080/define --header "X-KVM-Definition: <domain type='kvm'><name>kvm_api</name><memory unit='KiB'>1048576</memory><vcpu >1</vcpu><os><type arch='x86_64' machine='pc-i440fx-trusty'>hvm</type></os><devices><emulator>/usr/bin/qemu-system-x86_64</emulator><disk type='file' device='disk'><driver name='qemu' type='raw'/><source file='/tmp/debian.img'/><target dev='hda' bus='ide'/></disk><interface type='network'><mac address='52:54:00:da:02:01'/><source network='default' bridge='virbr0'/><target dev='vnet0'/></interface><graphics type='vnc' port='5900' autoport='yes' listen='0.0.0.0'><listen type='address' address='0.0.0.0'/></graphics></devices></domain>"
HTTP/1.0 200 OK
Date: Fri, 12 May 2017 20:29:14 GMT
Server: WSGIServer/0.1 Python/2.7.6
Content-Length: 17
Content-Type: text/html; charset=UTF-8
Instance defined
(kvm_python) root@kvm:~/kvm_python#
Мы применяем тот сырой образ Debian, который мы создали в рецепте Установка пользовательской ОС в образ при помощи debootstrap из Главы 1. Соответствующее определение также должно выглядеть знакомым; мы применяли его в большинстве рецептов данной главы.
Теперь мы должны получить определённым некий новый экземпляр KVM. Давайте воспользуемся маршрутом
/list
для перечисления всех экземпляров и проверим при помощи команды
virsh
:
(kvm_python) root@kvm:~/kvm_python# curl localhost:8080/list
List of KVM instances: ['kvm_api']
(kvm_python) root@kvm:~/kvm_python# virsh list --all
Id Name State
----------------------------------------------------
- kvm_api shut off
(kvm_python) root@kvm:~/kvm_python#
Теперь, когда у нас имеется определённым экземпляр, давайте запустим его при помощи маршрута
/start
и убедимся что он исполняется:
(kvm_python) root@kvm:~/kvm_python# curl -s -i -XPOST localhost:8080/start --header "X-KVM-Name: kvm_api"
HTTP/1.0 200 OK
Date: Fri, 12 May 2017 20:29:38 GMT
Server: WSGIServer/0.1 Python/2.7.6
Content-Length: 17
Content-Type: text/html; charset=UTF-8
Instance started
(kvm_python) root@kvm:~/kvm_python# virsh list --all
Id Name State
----------------------------------------------------
1 kvm_api running
(kvm_python) root@kvm:~/kvm_python#
Чтобы остановить этот экземпляр и полностью его удалить мы применим маршруты
/stop
и /undefine
из своего сценария:
(kvm_python) root@kvm:~/kvm_python# curl -s -i -XPOST localhost:8080/stop --header "X-KVM-Name: kvm_api"
HTTP/1.0 200 OK
Date: Fri, 12 May 2017 20:29:52 GMT
Server: WSGIServer/0.1 Python/2.7.6
Content-Length: 17
Content-Type: text/html; charset=UTF-8
Instance stopped
(kvm_python) root@kvm:~/kvm_python#
(kvm_python) root@kvm:~/kvm_python# virsh list --all
Id Name State
----------------------------------------------------
- kvm_api shut off
(kvm_python) root@kvm:~/kvm_python#
(kvm_python) root@kvm:~/kvm_python# curl -s -i -XPOST localhost:8080/undefine --header "X-KVM-Name: kvm_api"
HTTP/1.0 200 OK
Date: Fri, 12 May 2017 20:30:09 GMT
Server: WSGIServer/0.1 Python/2.7.6
Content-Length: 19
Content-Type: text/html; charset=UTF-8
Instance undefined
(kvm_python) root@kvm:~/kvm_python#
(kvm_python) root@kvm:~/kvm_python# virsh list --all
Id Name State
----------------------------------------------------
(kvm_python) root@kvm:~/kvm_python#
Давайте пройдёмся по своему коду более подробно.
На шаге 1 мы установили модуль bottle в своей виртуальной среде Python.
После импорта пакетов libvirt и bottle на шаге 2 мы определили свой метод libvirtConnect()
/
Все функции из нашей программы будут применять его для подключения к своему гипервизору.
На шаге 3 мы реализовали маршрут /define
и его функциональность. Наш декоратор
@post
связывает имеющийся код из нашей следующей функции с неким путём URL. В
нашем примере данный маршрут /define
связывается с определённой функцией
build()
. Передача маршрута /define
в соответствующую команду curl исполнит данную функцию, которая в свою очередь вызовет метод
efineKVMInstance()
для определения необходимого экземпляра.
В шагах 4,5 и 6 мы применяем аналогичный шаблон кодирования для запуска, останова и удаления определения своего экземпляра.
На шаге 7 мы применяем декоратор @get
для реализации некой функции перечисления
всех определённых в этом хосте экземпляров.
На шаге 8 мы применяем класс run
, который предоставляет соответствующий метод
run()
, применяемый нами для запуска встроенного сервера. В нашем примере этот
сервер будет выполнять ожидание в локальном хосте по порту 8080
.
Как мы уже видели ранее, исполнение данного сценария начнёт процесс ожидания в сокете по порту
8080
, с которым мы можем взаимодействовать при помощи команды
curl
.
Вот наш полный код реализации:
import libvirt
from bottle import run, request, get, post, HTTPResponse
def libvirtConnect():
try:
conn = libvirt.open('qemu:///system')
except libvirt.libvirtError:
conn = None
return conn
def getLibvirtInstances():
conn = libvirtConnect()
if conn == None:
return HTTPResponse(status=500, body='Error listing instances\n')
else:
try:
instances = conn.listDefinedDomains()
return instances
except libvirt.libvirtError:
return HTTPResponse(status=500, body='Error listing instances\n')
def defineKVMInstance(template):
conn = libvirtConnect()
if conn == None:
return HTTPResponse(status=500, body='Error defining instance\n')
else:
try:
conn.defineXML(template)
return HTTPResponse(status=200, body='Instance defined\n')
except libvirt.libvirtError:
return HTTPResponse(status=500, body='Error defining instance\n')
def undefineKVMInstance(name):
conn = libvirtConnect()
if conn == None:
return HTTPResponse(status=500, body='Error undefining instance\n')
else:
try:
instance = conn.lookupByName(name)
instance.undefine()
return HTTPResponse(status=200, body='Instance undefined\n')
except libvirt.libvirtError:
return HTTPResponse(status=500, body='Error undefining instance\n')
def startKVMInstance(name):
conn = libvirtConnect()
if conn == None:
return HTTPResponse(status=500, body='Error starting instance\n')
else:
try:
instance = conn.lookupByName(name)
instance.create()
return HTTPResponse(status=200, body='Instance started\n')
except libvirt.libvirtError:
return HTTPResponse(status=500, body='Error starting instance\n')
def stopKVMInstance(name):
conn = libvirtConnect()
if conn == None:
return HTTPResponse(status=500, body='Error stopping instance\n')
else:
try:
instance = conn.lookupByName(name)
instance.destroy()
return HTTPResponse(status=200, body='Instance stopped\n')
except libvirt.libvirtError:
return HTTPResponse(status=500, body='Error stopping instance\n')
@post('/define')
def build():
template = str(request.headers.get('X-KVM-Definition'))
status = defineKVMInstance(template)
return status
@post('/undefine')
def build():
name = str(request.headers.get('X-KVM-Name'))
status = undefineKVMInstance(name)
return status
@get('/list')
def list():
kvm_list = getLibvirtInstances()
return "List of KVM instances: {}\n".format(kvm_list)
@post('/start')
def build():
name = str(request.headers.get('X-KVM-Name'))
status = startKVMInstance(name)
return status
@post('/stop')
def build():
name = str(request.headers.get('X-KVM-Name'))
status = stopKVMInstance(name)
return status
run(host='localhost', port=8080, debug=True)