Глава 4. Гостевые домены

Содержание

Глава 4. Гостевые домены
Обзор домена
Перечень доменов
Получение информации состояния домена
Извлечение идентификатора домена
Извлечение UUID домена
Извлечение тпа ОС домена
Определение имеет ли данный домен текущий снимок
Определение имеет ли данный домен управляемые хранимые образы
Извлечение имени хоста домена
Получение информации об оборудовании домена
Определение того запущен ли домен
Определение того постоянен ли домен
Определение того обновлён ли домен
Определение максимальной памяти домена
Определение максимального числа VCPU домена
Извлечение значения названия домена
Извлечение значения состояния домена
Извлечение значения информации времени домена
Извлечение значения адресов сетевого интефейса домена
Управление жизненным циклом
Предоставление и запуск
Методы предоставления
Загрузка недолговечного гостевого домена
Определение и загрузка постоянного гостевого домена
Технологии предоставления нового гостевого домена
Предоставление образа CD-ROM/ ISO
Предоставление загрузки PXE
Предоставление загрузки напрямую из ядра
Останов
Приостановка/ возабновление и сохранение/ восстановление
Миграция
Автоматичекий запуск
Настройка домена
Режимы загрузки
Ресурсы памяти/ ЦПУ
Мониторинг производительности
Производительность блочного устройства домена
Производительность vCPU
Статистика памяти
Статистика ввода/ вывода
Настройка устройства
Эмулятор
Диски
Сети
Мышь, клавиатура и планшеты
Проброс устройств USB
Проброс устройств PCI
Задания блочного устройства
Выводы

Неким доменом именуется исполняемая или не исполняемая виртуальная операционная система под libvirt. В libvirt можно создать/ установить столько доменов, сколько требуется вплоть до того предела, который выставляется дибо системным администратором, либо до того числа, которое может поддерживаться данной системой хостинга без снижения её производительности. Общее число может разниться в зависимости от возможностей производительности данной системы хостинга.

Не запущенный домен не добавляет никакого снижения производительности к данной машине хостинга; для этой машины хоста оказывают влияние на снижение производительности только запущенные домены. Таким образом, имеющийся системный администратор может устанавливать некий предел общего числа исполняемых доменов вместо общего числа доменов.

Обзор домена

Как уже упоминалось в Главе 2, некий домен является каким- то экземпляром операционной системы, запущенной в виртуальной машине. Конкретный объект соединения предоставляет методы для нумерации всех гостевых доменов, создания новых гостевых доменов, а также для управления имеющимися доменами. Некий гостевой домен представляется каким- то экземпляром класса virDomain и имеет целый ряд уникальных идентификаторов.

  • ID: Это положительное целое, причём уникальное среди всех запущенных гостевых доменов в неком обособленном хосте. Неактивный домен не имеет никакого идентификатора.

  • Name: Представляет короткую строку, уникальную для всех гостевых доменов в неком обособленном хосте, как запущенных, так и неактивных. Для обеспечения максимальной совместимости между гипервизорами такие названия могут содержать лишь алфавитноцифровые (a–Z, 0–9) символы, символ тире (-) и символ подчёркивания (_).

  • UUID: Данное значение содержит 16 байт без знака, гарантирующих уникальность по всем гостевым доменам в любом из хостов. RFC 4122 определяет сам формат для UUID и предоставляет рекомендуемый алгоритм для выработки UUID с обеспечением уникальности.

Некий гостевой домен может быть недолговечным (transient) или постоянным (persistent). Недолговечный гостевой домен может управляться только когда он запущен в определённом хосте. После того как он выключен все его отслеживания пропадут. Постоянный гостевой домен имеет свои конфигурации сопровождаемыми в неком хранилище данных в том хосте, в котором расположен гипервизор в неком определяемом реализацией формате. Таким образом, когда какой- то постоянно существующий гость выключен, всё ещё имеется возможность управлять его неактивной конфигурацией. Некий недолговечный гость может быть превращён в постоянного гостя во время его исполнения путём задания его конфигурации.

Когда некое приложение имеет для домена какой- то уникальный идентификатор, часто будет желательно получить соответствующий объект virDomain. Для поиска имеющихся доменов имеются три метода: lookupByID, lookupByName и lookupByUUID. Каждый из них получает идентификатор домена в качестве параметра. Они будут возвращать None если нет имеющегося соответствующего домена. Если имеется необходимость, можно запросить значение объекта ошибки для поиска определённых подробностей. Листинг 4-1 показывает некий образец того как запросить такую ошибку.

 

Листинг 4-1. Извлечение объекта домена по идентификатору


# Example-1.py
from __future__ import print_function
import sys
import libvirt

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

domainID = 6
dom = conn.lookupByID(domainID)

if dom == None:
    print('Failed to get the domain object', file=sys.stderr)

conn.close()
exit(0)
 	   
[Совет]Совет

Листинг 4-1 может преждевременно завершить работу если не найден domainid, так как вместо того чтобы возвращать некую ошибку в Python, для libvirt допустимо прервать такой процесс.

Следует отметить, что данный метод lookupByID не будет работать когда данный домен не активен. Все неактивные домены имеют значением идентификатора -1.

Листинг 4-2 показывает как выбрать некий домен при помощи его названия libvirt.

 

Листинг 4-2. Извлечение объекта домена по имени


# Example-2.py
from __future__ import print_function
import sys
import libvirt

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

domainName = 'someguest'
dom = conn.lookupByName(domainName)
if dom == None:
    print('Failed to get the domain object', file=sys.stderr)

conn.close()
exit(0)
 	   
[Совет]Совет

Листинг 4-2 может преждевременно завершить работу если не найден domainName, так как вместо того чтобы возвращать некую ошибку в Python, для libvirt допустимо прервать такой процесс.

Листинг 4-3 показывает как извлечь некий домен по UUID этого домена.

 

Листинг 4-3. Извлечение объекта домена по UUID


# Example-3.py
from __future__ import print_function
import sys
import libvirt

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

domainUUID = '00311636-7767-71d2-e94a-26e7b8bad250'
dom = conn.lookupByUUID(domainUUID)
if dom == None:
    print('Failed to get the domain object', file=sys.stderr)

conn.close()
exit(0)
 	   
[Совет]Совет

Листинг 4-3 может преждевременно завершить работу если не найден domainUUID, так как вместо того чтобы возвращать некую ошибку в Python, для libvirt допустимо прервать такой процесс.

Наш предыдущий пример UUID применяет формат UUID, пригодный для печати. Python не поддерживает его эквивалент сырых байт.

Перечень доменов

Классы libvirt выставляют два списка доменов: причём первый содержит исполняемые домены, в то время как второй включает в свой состав не активные домены, постоянные домены. Эти списки предназначены быть неперекрывающимися, исключающими набоарми, хотя всегда существует небольшая вероятность что некий домен может быть остановлен или запущен между соответствующими запросами каждого из наборов. Имеющийся класс событий, описываемый позднее в этом разделе, предоставляет некий способ отслеживания всех изменений жизненного цикла, избегая такое потенциальное условие состязательности. {Прим. пер.: подробнее о состязательности в наших переводах Asyncio в Python 3 Цалеба Хаттингха и Полного руководства параллельного программирования на Python Куана Нгуена.}

Имеющийся метод для перечисления активных доменов возвращает некий список идентификаторов домена. Все запущенные домены имеют некий положительный целочисленный идентификатор, который уникально указывает на его среди всех запущенных в данном хосте доменов. Сам метод для перечисления активных доменов, listDomainsID, не требует параметров. Возвращаемым им значением будет None в случае возникновения ошибки или некий list Python соответствующих идентификаторов, представленных в виде ints. Листинг 4-4 отображает как получать некий список всех исполняемых (активных) доменов.

 

Листинг 4-4. Список активных доменов


# Example-4.py
from __future__ import print_function
import sys
import libvirt

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

domainIDs = conn.listDomainsID()
if domainIDs == None:
    print('Failed to get a list of domain IDs', \
          file=sys.stderr)

print("Active domain IDs:")
if len(domainIDs) == 0:
    print('  None')
else:
    for domainID in domainIDs:
        print('  '+str(domainID))

conn.close()
exit(0)
 	   

Дополнительно к запущенным доменам могут также иметься некоторые постоянные не активные конфигурации доменов, хранимые в данном хосте. Так как некий не активный домен не имеет никакого идентификатора ID, получаемый перечень не активных доменов выставляется как какой- то список строк названий. В случае ошибки будет возвращено None в случае возникновения ошибки или некий list Python элементов, заполненных названиями (строками). Листинг 4-5 отображает как получать некий список всех не активных доменов.

 

Листинг 4-5. Список активных доменов


# Example-5.py
from __future__ import print_function
import sys
import libvirt

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

domainNames = conn.listDefinedDomains()
if conn == None:
    print('Failed to get a list of domain names', file=sys.stderr)

domainIDs = conn.listDomainsID()
if domainIDs == None:
    print('Failed to get a list of domain IDs', file=sys.stderr)
if len(domainIDs) != 0:
    for domainID in domainIDs:
        domain = conn.lookupByID(domainID)
        domainNames.append(domain.name)

print("All (active and inactive domain names:")
if len(domainNames) == 0:
    print('  None')
else:
    for domainName in domainNames:
        print('  '+domainName)

conn.close()
exit(0)
 	   

Приведённые методы для перечисления доменов напрямую не возвращают необходимые объекты virDomain, так как это может вызывать снижение производительности для тех приложений, которые пожелают запрашивать полный перечень доменов на постоянной основе. Тем не менее, модуль libvirt Python предоставляет необходимый метод listAllDomains, который возвращает все имеющиеся домены, активные и не активные. Он возвращает некий list Python всех экземпляров virDomain или None в случае ошибки. Когда в аличии нет никаких постоянных доменов, данный list может быть пустым.

Метод listAllDomains получает некий единственный параметр, который является флагом, определяющим фильтр для подлежащих перечислению доменов. Если его значение определено как 0, тогда будут перечислены все домены. В противном случае могут добавляться совместно следующие константы для создания некого фильтра для подлежащих перечислению доменов:


VIR_CONNECT_LIST_DOMAINS_ACTIVE
VIR_CONNECT_LIST_DOMAINS_INACTIVE
VIR_CONNECT_LIST_DOMAINS_PERSISTENT
VIR_CONNECT_LIST_DOMAINS_TRANSIENT
VIR_CONNECT_LIST_DOMAINS_RUNNING
VIR_CONNECT_LIST_DOMAINS_PAUSED
VIR_CONNECT_LIST_DOMAINS_SHUTOFF
VIR_CONNECT_LIST_DOMAINS_OTHER
VIR_CONNECT_LIST_DOMAINS_MANAGEDSAVE
VIR_CONNECT_LIST_DOMAINS_NO_MANAGEDSAVE
VIR_CONNECT_LIST_DOMAINS_AUTOSTART
VIR_CONNECT_LIST_DOMAINS_NO_AUTOSTART
VIR_CONNECT_LIST_DOMAINS_HAS_SNAPSHOT
VIR_CONNECT_LIST_DOMAINS_NO_SNAPSHOT
 	   

Листинг 4-6 отображает как получать некий список активных и не активных доменов методом listAllDomains.

 

Листинг 4-6. Извлечение всех объектов доменов


# Example-6.py
from __future__ import print_function
import sys
import libvirt

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

print("All (active and inactive) domain names:")
domains = conn.listAllDomains(0)
if len(domains) != 0:
    for domain in domains:
        print('  '+domain.name())
else:
    print('  None')

conn.close()
exit(0)
 	   

Получение информации состояния домена

После того как был получен некий экземпляр домена, появляется возможность извлечения сведений относительно собственно состояния домена, например, тип подлежащей хостингу ОС, состояние исполнения, ID, UUID и тому подобное. Приводимые ниже методы демонстрируют как осуществлять извлечение такой информации.

Извлечение идентификатора домена

Значение ID некого домена может быть получено при помощи метода ID. Некий ID имеют только запущенные домены; извлечение значения ID незапущенного домена всегда возвращает -1. Листинг 4-7 показывает как получать значение ID некого домена из значения названия домена libvirt.

 

Листинг 4-7. Извлечение ID домена


# Example-7.py
from __future__ import print_function
import sys
import libvirt

from xml.dom import minidom

domName = 'CentOS7'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByName(domName)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

id = dom.ID()
if id == -1:
    print('The domain is not running so has no ID.')
else:
    print('The ID of the domain is ' + str(id))

conn.close()
exit(0)
 	   

Извлечение UUID домена

Значение UUID некого домена можно получить с применением метода UUID или UUIDString. Значением метода UUID является вовсе не то что будет полезно программам на Python, так как это некое двоичное значение. Значение метода UUIDString намоного более полезно, так как он возвращает некую форматированную строку значения, для которой можно запросто выполнить синтаксический разбор.

Значение UUID не зависит от состояния исполнения данного домена и всегда возвращает некий допустимый UUID. Листинг 4-8 показывает как извлекать значение UUID некого домена при помощи значения имени домена.

 

Листинг 4-8. Извлечение ID домена


# Example-8.py
from __future__ import print_function
import sys
import libvirt

from xml.dom import minidom

domName = 'CentOS7'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByName(domName)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

uuid = dom.UUIDString()
print('The UUID of the domain is ' + uuid)

conn.close()
exit(0)
 	   

Извлечение типа ОС домена

Извлечение типа ОС, размещаемой неким доменом также является доступным. Некий ID имеют только запущенные домены; извлечение значения ID незапущенного домена всегда возвращает -1. Ту же самую информацию можно выбрать через метод info Листинг 4-9 показывает как извлекать значение типа операционной системы из некого исполняемого домена.

 

Листинг 4-9. Извлечение UUID домена


# Example-9.py
from __future__ import print_function
import sys
import libvirt

from xml.dom import minidom

domName = 'CentOS7'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByName(domName)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

type = dom.OSType()
print('The OS type of the domain is "' + type + '"')

conn.close()
exit(0)
 	   

Определение имеет ли данный домен текущий снимок

Метод hasCurrentSnapshot возвращает некое Булево значение, указывающее на то что некий текщий моментальный снимок доступен. Этот метод всегда возвращает некое допустимое значение и оно не зависит от состояния исполнения данного домена. Листинг 4-10 показывает как определить имеет ли некоторый домен текущий моментальный снимок.

 

Листинг 4-10. Определение того имеет ли некоторый домен текущий моментальный снимок


# Example-10.py
rom __future__ import print_function
import sys
import libvirt
from xml.dom import minidom

domName = 'CentOS7'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByName(domName)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

flag = dom.hasCurrentSnapshot()
print('The value of the current snapshot flag is ' + str(flag))

conn.close()
exit(0)
 	   

Определение имеет ли данный домен управляемые хранимые образы

Метод hasManagedSaveImages возвращает некое Булево значение, указывающее на то что некий домен имеет управляемый сохранённый образ. Собранный образ создаётся на основе возникновения такой потребности самим пользователем.

Обратите внимание, что некий запущенный домен никогда не должен иметь сохранённого домена, так как этот образ подлежит удалению при перезапуске данного домена. Листинг 4-11 показывает как определить имеет ли данный домен некий управляемый хранимый образ.

 

Листинг 4-11. Определение того имеет ли данный домен управляемый хранимый образ


# Example-11.py
from __future__ import print_function
import sys
import libvirt
from xml.dom import minidom

domName = 'CentOS7'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByName(domName)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

flag = dom.hasManagedSaveImage()

print('The value of the manaed save images flag is ' + str(flag))

conn.close()
exit(0)
 	   

Извлечение имени хоста домена

Метод hostname возвращает значение имени хоста данного домена. Данный метод hostname в высшей степени зависит от самого гипервизора и/ или qemu-guest-agent. Он может выставлять некую ошибку если метод не способен завершиться успешно. Листинг 4-12 возвратит значение имени хоста данного домена (если он доступен).

 

Листинг 4-12. Извлечение имени хоста определённого домена


# Example-12.py
from __future__ import print_function
import sys
import libvirt
from xml.dom import minidom

domName = 'CentOS7'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByName(domName)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

name = dom.hostname()
print('The hostname of the domain  is ' + str(name))

conn.close()
exit(0)
 	   

Получение информации об оборудовании домена

Метод info возвращает некую общую информацию относительно имеющегося оборудования домена. Имеются пять логических элементов, возвращаемых в неком list Python: значение состояния, максимальный объём памяти, память, ЦПУ и время ЦПУ для данного домена. Листинг 4-13 получает общую информацию из некого домена.

 

Листинг 4-13. Получение информации домена


# Example-13.py
from __future__ import print_function
import sys
import libvirt
from xml.dom import minidom

domName = 'CentOS7'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByName(domName)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

state, maxmem, mem, cpus, cput = dom.info()
print('The state is ' + str(state))
print('The max memory is ' + str(maxmem))
print('The memory is ' + str(mem))
print('The number of cpus is ' + str(cpus))
print('The cpu time is ' + str(cput))

conn.close()
exit(0)
 	   

Определение того запущен ли домен

Метод isActive возвращает некий Булев флаг, указывающий на то является ли данный домен активным (исполняемым). Листинг 4-14 возвращает некое Булево значение указывающее значение состояние исполнения данного домена.

 

Листинг 4-14. Определение того запущен ли домен


# Example-14.py
from __future__ import print_function
import sys
import libvirt
from xml.dom import minidom

domName = 'CentOS7'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByName(domName)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

flag = dom.isActive()
if flag == True:
    print('The domain is active.')
else:
    print('The domain is not active.')

conn.close()
exit(0)
 	   

Определение того постоянен ли домен

Метод isPersistent возвращает некий Булев флаг, который указывет является ли данный домен постоянным (этот домен сохранится после некой перезагрузки). Листинг 4-15 определяет будет ли некий запущенный домен постоянным.

 

Листинг 4-15. Определение того будет ли данный домен постоянным


# Example-15.py
from __future__ import print_function
import sys
import libvirt
from xml.dom import minidom

domName = 'CentOS7'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByName(domName)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

flag = dom.isPersistent()
if flag == 1:
    print('The domain is persistent.')
elif flag == 0:
    print('The domain is not persistent.')
else:
    print('There was an error.')

conn.close()
exit(0)
 	   

Определение того обновлён ли домен

Метод isUpdated возвращает некий Булев флаг, который указывет был ли данный домен обновлён после его создания. Некое обновление данного домена может быть всего лишь изменением конфигурации данного домена. Листинг 4-16 возвращает некий флаг, который указывает факт изменения состояния данного домена.

 

Листинг 4-16. Определение того был ли данный домен обновлён


# Example-16.py
from __future__ import print_function
import sys
import libvirt
from xml.dom import minidom

domName = 'CentOS7'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByName(domName)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

flag = dom.isUpdated()
if flag == 1:
    print('The domain is updated.')
elif flag == 0:
    print('The domain is not updated.')
else:
    print('There was an error.')

conn.close()
exit(0)
 	   

Определение максимальной памяти домена

Метод maxMemory возвращает значение максимального объёма памати выделенной данному домену. Это та же самая информация, которая может быть выбрана через метод info. Листинг 4-17 возвращает максимальный объём памяти, выделенный данному домену.

 

Листинг 4-17. Определение значения максимального объёма памяти данного домена


# Example-17.py
from __future__ import print_function
import sys
import libvirt
from xml.dom import minidom

domName = 'CentOS7'
conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByName(domName)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

mem = dom.maxMemory()
if mem > 0:
    print('The max memory for domain is ' + str(mem) + 'MB')
else:
    print('There was an error.')

conn.close()
exit(0)
 	   

Определение максимального числа VCPU домена

Метод maxVcpus возвращает значение максимального числа виртуальных ЦПУ, выделяемых данному домену. Та же самая информация может быть извлечена через метод info. Это работает лишь для активных доменов. Листинг 4-18 возвращает максимальное значение VCPU, выдленных данному домену.

 

Листинг 4-18. Определение того имеет ли некоторый домен текущий моментальный снимок


# Example-18.py
from __future__ import print_function
import sys
import libvirt
from xml.dom import minidom

domName = 'CentOS7'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByName(domName)
if dom == None:
    print('Failed to find the domain '+domName, \
          file=sys.stderr)
    exit(1)

cpus = dom.maxVcpus()
if cpus != -1:
    print('The max Vcpus for domain is ' + str(cpus))
else:
    print('There was an error.')

conn.close()
exit(0)
 	   

Извлечение значения названия домена

Метод name возвращает значение названия данного домена. Листинг 4-19 возвращает значение название домена.

 

Листинг 4-19. Извлечение названия домена


# Example-19.py
from __future__ import print_function
import sys
import libvirt
from xml.dom import minidom

domName = 'CentOS7'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByName(domName)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

name = dom.name()
print('Thename of the domain is "' + name +'".')

conn.close()
exit(0)
 	   

Извлечение значения состояния домена

Метод state возвращает значение состояния данного домена. Листинг 4-20 возвращает значение состояния данного домена.

 

Листинг 4-20. Извлечение значения состояния данного домена


# Example-20.py
from __future__ import print_function
import sys
import libvirt
from xml.dom import minidom

domName = 'CentOS7'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByName(domName)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

state, reason = dom.state()

if state == libvirt.VIR_DOMAIN_NOSTATE:
    print('The state is VIR_DOMAIN_NOSTATE')
elif state == libvirt.VIR_DOMAIN_RUNNING:
    print('The state is VIR_DOMAIN_RUNNING')
elif state == libvirt.VIR_DOMAIN_BLOCKED:
    print('The state is VIR_DOMAIN_BLOCKED')
elif state == libvirt.VIR_DOMAIN_PAUSED:
    print('The state is VIR_DOMAIN_PAUSED')
elif state == libvirt.VIR_DOMAIN_SHUTDOWN:
    print('The state is VIR_DOMAIN_SHUTDOWN')
elif state == libvirt.VIR_DOMAIN_SHUTOFF:
    print('The state is VIR_DOMAIN_SHUTOFF')
elif state == libvirt.VIR_DOMAIN_CRASHED:
    print('The state is VIR_DOMAIN_CRASHED')
elif state == libvirt.VIR_DOMAIN_PMSUSPENDED:
    print('The state is VIR_DOMAIN_PMSUSPENDED')
else:
    print(' The state is unknown.')
print('The reason code is ' + str(reason))

conn.close()
exit(0)
 	   

Извлечение значения информации времени домена

Метод getTime выделяет значение текущего временного штампа данного домена. Этот метод возвращает то же самое значение что и функция Python time.struct_time. Листинг 4-21 извлекает значение текущего времени, как оно известно данному домену.

 

Листинг 4-21. Извлечение информации времени определённого домена


# Example-21.py
from __future__ import print_function
import sys, time
import libvirt
from xml.dom import minidom

domName = 'CentOS7'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByName(domName)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

struct = dom.getTime()
timestamp = time.ctime(float(struct['seconds']))
print('The domain current time is ' + timestamp)

conn.close()
exit(0)
 	   

Извлечение значения адресов сетевого интефейса домена

Метод interfaceAddresses выделяет значение адреса текущего сетевого интерфейса. Эта информация является динамической по своей природе, поскольку она может быть изменена системным администратором некого гостевого домена. Таким образом, вам не следует полагаться на эту информацию как остающуюся статичной. Определённый гостевой агент QEMU запрашивается самой библиотекой libvirt для получения такой информации, а тем самым такой агент должен быть запущен в самом гостевом домене для любой возвращаемой информации.

Листинг 4-22 будет возвращать полный список IP адресов назначенных некому интерфейсу.

 

Листинг 4-22. Определение того имеет ли некоторый домен текущий моментальный снимок


# Example-22.py
from __future__ import print_function
import libvirt

# setup
"""List network interface IP Addresses for a guest domain.
"""

domName = 'CentOS7'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

domain = conn.lookupByName(domName)
if domain == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

# make sure the domain is running
if domain.isActive() == False:
    print('Error: Domain is not active or never started.')
    exit(1)

# get and list the ip addresses, use QEMU as the source information
ifaces = domain.interfaceAddresses(libvirt. \
                VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT, 0)
for (name, val) in ifaces.iteritems():
    if val['addrs']:
        for ipaddr in val['addrs']:
            print(name+' '+str(ipaddr))

conn.close()
exit(0)
 	   
[Совет]Совет

Данная программа завершится отказом если данный гостевой агент QEMU не поддерживает данную функцию.

Управление жизненным циклом

libvirt способен управлять всем жизненным циклом гостевых доменов (см. Рисунок 4-1). Готсетвые домены перемещаются на протяжении своего жизненного цикла по различным состояниям.

  1. Undefined: Это состояние базового уровня. Некий не определённый гостевой домепн не был задан или создан ни коим образом.

  2. Defined: Уже определённый домен был задан, но пока не запущен. Данное состояние может также быть определено как Stopped.

  3. Running: Запущенный домен является определённым и исполняется неким гипервизором.

  4. Paused: приостановленный гостевой домен пребывает в неком подвешенном состоянии из состояния Running. Его образ в памяти был временно сохранён и он может быть восстановлен в состояние Running без того что его гостевая операционная система домена даже не будет уведомлена о произошедшей приостановке.

  5. Saved: Сохранённый домен получил свой образ памяти, как перехваченный в состоянии Paused, причём сохранённым в постоянном хранилище. Он также может быть восстановлен в состояние Running без того что его гостевая операционная система домена даже не будет уведомлена о произошедшей приостановке.

 

Рисунок 4-1


Жизненный цикл гостевого домена

Все переходы между этими состояниями разбиваются на ряд категорий; для дополнительных сведений ознакомьтесь с последующими разделами.

Предоставление и запуск

Предоставлением (provisioning) именуется задача создания новых гостевых доменов, обычно с применением некого вида носителя установки операционной системы. Существует большое разнообразие способов которым может быть выполнено предоставление, однако эти доступные варианты разнятся в соответствии с применяемым гипервизором и типом подлежащего предоставлению гостевого домена. Поддержка нескольких различных методов предоставления не является чем- то необычным для приложения. Запуском (starting) именуется исполнение предоставленного гостевого домена неким гипервизором.

 

Методы предоставления

Имеются три метода вовлечённые в предоставление гостей. Метод createXML создаст и немедленно загрузит некий новый недолговечный гостевой домен. После того как этот домен будет остановлен, все его следу будут утрачены. Метод defineXML сохранит определённую конфигурацию для некого постоянного гостевого домена. Метод create загрузит предварительно определённый гостевой домен из своей постоянной конфигурацией. Следует отметить один важный момент, состоящий в том, что команда defineXML может применяться для превращения предварительно загруженного недолговечного гостевого домена в постоянный домен. Это может оказаться полезным для некоторых сценариев предоставления, которые будут проиллюстрированы позднее.

 

Загрузка недолговечного гостевого домена

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

Если установлен флаг VIR_DOMAIN_START_PAUSED, данный гостевой домен будет зарущен, но его ЦПУ будут оставаться приостановленными. Эти ЦПУ могут быть впоследствии запущены вручную при помощи метода resume.

Когда установлен флаг VIR_DOMAIN_START_AUTODESTROY, этот гостевой домен будет автоматически уничтожен после окончательного высвобождения объекта virConnect. Это также произойдёт когда данное клиентское приложение завершится крушением или утратит своё соединение с соответствующим демоном libvirtd. Для всех помеченных на автоматическое уничтожения доменов будут блокироваться попытки миграции доменов, сохранения в некий файл или получения моментального снимка.

Листинг 4-23 показывает как создавать некий домен из некого имеющегося файла XML. Файлы XML мы рассмотрим в этой главе позднее.

 

Листинг 4-23. Предоставление недолговечного гостевого домена


# Example-23.py
from __future__ import print_function
import sys
import libvirt
xmlconfig = '........'
conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)
dom = conn.createXML(xmlconfig, 0)
if dom == None:
    print('Failed to create a domain from an XML definition.', \
          file=sys.stderr)
    exit(1)
print('Guest '+dom.name()+' has booted', file=sys.stderr)
conn.close()
exit(0)
 	   
[Совет]Совет

Листинг 4-23 это всего лишь образец и сам XML не представлен в примерах предлагаемого кода.

Если данная попытка создания домена завершилась успешно, тогда будет возвращён полученный экземпляр virDomain; в противном случае будет возвращёно None. Хотя этот домен и был успешно загружен, это не гарантирует что такой домен всё ешё исполняется. Вполне вероятно что такой гостевой домен претерпел крушение и в таком случае попытки применения возвращаемого объекта virDomain выработают некую ошибку, так как недолговечные гости перестали существовать после своего останова (будь то плановый останов либо крушение). Управление подобным сценарием требует применение постоянного гостя.

 

Определение и загрузка постоянного гостевого домена

Прежде чем некий постоянный домен может быть загружен, он должен иметь определённой свою конфигурацию. Это опять же требует некого соединения с libvirt и строки, содержащей документ XML с описанием требуемой конфигурации этого гостя. Соответствующий объект virDomain, получаемый из определения этого гостя впоследствии может применяться для его загрузки.

В настоящее время метод defineDomain задаёт некий параметр flags, который не применяется. Для этого параметра следует всегда применять значение 0. В последующих версиях данного метода такое поведение может быть изменено. Листинг 4-24 является образцом того как создать некий домен. Это не завершённая программа, поскольку необходимый XML для этой программы всё ещё не представлен.

 

Листинг 4-24. Определение и загрузка постоянного гостевого домена


# Example-24.py
from __future__ import print_function
import sys
import libvirt

xmlconfig = '<domain>........</domain>'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.defineXML(xmlconfig, 0)
if dom == None:
    print('Failed to define a domain from an XML definition.', \
          file=sys.stderr)
    exit(1)

if dom.create(dom) > 0:
    print('Can not boot guest domain.', file=sys.stderr)
    exit(1)

print('Guest '+dom.name()+' has booted', file=sys.stderr)

conn.close()
exit(0)
 	   
 

Технологии предоставления нового гостевого домена

Этот раздел вначале проиллюстрирует две конфигурации, которые делают возможным подход предоставления, который совместим с имеющимся для физических машин. Затем приводится третья возможность которая является специфичной именно для виртуального оборудования, но имеет некие интересные преимущества. Для целей данной иллюстрации последующие примеры будут применять некую конфигурацию XML, которая настраивает полного виртуального гостя KVM, причём с единственными диском и сетевым интерфейсом, а также некой видео картой, применяемой для отображения VNC.

Ниже приводится пример конфигурации XML. Обратите внимание, что необходимый файл demo.img не существует.


<domain type="kvm">
  <name>demo</name>
  <os>
    <type arch=’i686’ machine=’pc’>hvm</type>
    <boot> dec=’hd’/>
  </os>
  <uuid>c7a5fdbd-cdaf-9455-926a-d65c16db1809</uuid>
  <memory>500000</memory>
  <vcpu>1</vcpu>
  .... the <os> block will vary per approach ...
  <clock offset="utc"/>
  <on_poweroff>destroy</on_poweroff>
  <on_reboot>restart</on_reboot>
  <on_crash>destroy</on_crash>
  <devices>
    <emulator>/usr/bin/qemu-kvm</emulator>
    <disk type="file" device="disk">
      <source file='/var/lib/libvirt/images/demo.img'/>
      <driver name="qemu" type="raw"/>
      <target dev="hda"/>
    </disk>
    <interface type="bridge">
      <mac address='52:54:00:d8:65:c9'/>
      <source bridge="br0"/>
    </interface>
    <input type="mouse" bus="ps2"/>
    <graphics type="vnc" port='-1' listen='127.0.0.1'/>
  </devices>
</domain>
 	   
[Замечание]Замечание

Будьте внимательными при выборе первоначального выделения памяти. Слишком низкое значение может вызвать мистически выглядящие падения и отказы в установке. Неким операционным системам требуется не менее 600М памяти для начальной установки, хотя это значение и может быть понижено после установки.

 

Предоставление образа CD-ROM/ ISO

Все технологии полной виртуализации имеют поддержку эмуляции некого устройства CD-ROM в гостевом домене, что делает данный вариант очевидным для предоставления новых гостевых доменов. Тем не менее, достаточно редко встречаются гипервизоры, которые предоставляют CD-ROM устройства для гостей с паравиртуализацией.

Самым первым очевидным изменением для имеющейся конфигурации с целью поддержки CD-ROM может быть либо указание некого CD-ROM устройства хоста, либо некий файл образа ISO. Следующий вариант состоит в определении того каким именно должен быть устанавливаемый порядок загрузки в BIOS и тут имеются две возможности. Если ваш жёсткий диск перечисляется перед имеющимся устройством CD-ROM, тогда ваш носитель CD-ROM не будет желать загружаться до тех пор, пока самый первый сектор на этом жёстком диске остаётся пустым. Если же имеющиеся устройство CD-ROM перечисляется перед таким жёстким диском, тогда необходимо будет изменить имеющуюся конфигурацию гостя после установки, чтобы загружаться с установленного диска. Хотя оба варианта можно сделать работающими, самый первый вариант более прост для реализации.

Наша показанная ранее конфигурация будет иметь вставленным следующий фрагмент XML:


<os>
  <type arch='x86_64' machine='pc'>hvm</type>
  <boot dev='hd'/>
  <boot dev='cdrom'/>
</os>
 	   

Он предполагает, что имеющийся сектор загрузки жёсткого диска первоначально пустой, а потому самая первая попытка загрузки завершится неудачно и перейдёт к устройству CD-ROM. Также требуется добавить некое устройство считывания CD-ROM.


<disk type='file' device='cdrom'>
  <source file='/var/lib/libvirt/images/rhel5-x86_64-dvd.iso'/>
  <target dev='hdc' bus='ide'/>
</disk>
 	   

Получив заданной данную конфигурацию, теперь имеется возможность предоставить необходимого гостя. Это некий простой процесс, всего лишь требующий определения некого постоянного гостя и его последующей загрузки. Листинг 4-25 показывает как определить и загрузить некий домен. Обратите внимание, что если сам XML будет пропущен, а потому это всего лишь образец некой программы, которая не будет полностью рабочей.

 

Листинг 4-25. Предоставление загрузки CD-ROM


# Example-25.py
from __future__ import print_function
import sys
import libvirt

xmlconfig = '<domain>........</domain>'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.defineXML(xmlconfig, 0)
if dom == None:
    print('Failed to define a domain from an XML definition.', \
          file=sys.stderr)
    exit(1)

if dom.create(dom) < 0:
    print('Can not boot guest domain.', file=sys.stderr)
    exit(1)

print('Guest '+dom.name()+' has booted', file=sys.stderr)

conn.close()
exit(0)
 	   

Если нет возможности гарантировать чтобы имеющийся на жёстком диске сектор загрузки был пустым, тогда предоставление будет представлять собой процесс из двух этапов. Вначале некий непостоянный гость будет загружен с применением в качестве первичного устройства загрузки некого устройства CD-ROM. После выполнения такой загрузки для загрузки с жёсткого диска будет определена некая постоянная конфигурация для этого гостя.

Дополнительно к методу defineXML, также доступен и альтернативный метод defineXMLFlags.

 

Предоставление загрузки PXE

Некоторые более новые технологии полной виртуализации предоставляют некий BIOS, который способен применять протокол загрузки PXE для загрузки из сетевой среды. Если некая среда уже имеет некий развёрнутый сервер предоставления загрузки PXE, здесь мы опишем метод его применения для гостевых доменов.

Очевидно, что загрузка PXE требует чтобы такой гость имел настроенным некое сетевое устройство. Та локальная сеть, к которой подключена данная сетевая карта также требует доступным некий сервер PXE/ TFTP. Следующее изменение состоит в определении того каким именно должен быть установленным порядок загрузки BIOS, причём имеются два возможных варианта. Если имеющийся жёсткий диск перечисляется перед таким сетевым устройством, тогда эта сетевая карта не сможет получить возможность загрузки пока самый первый сектор на этом диске не будет пустым. Если же это сетевое устройство перечисляется перед имеющимся жёстким диском, тогда будет необходимо изменить после установки имеющуюся настройку гостя чтобы загружаться с установленного диска. Хотя оба метода могут быть рабочими, самый первый вариант проще в своей реализации.

Показанная ранее конфигурация гостя будет иметь вставленным следующий фрагмент XML:


<os>
  <type arch='x86_64' machine='pc'>hvm</type>
  <boot dev='hd'/>
  <boot dev='network'/>
</os>
 	   

Он предполагает, что изначально загрузочный сектор вашего жёсткого диска пустой, поэтому самая первая попытка завершается неудачей и передаётся в NIC. При таким образом заданной конфигурации теперь имеется возможность предоставления необходимого гостя. Это достаточно простой процесс, который всего лишь требует определения некого постоянного гостя и его последующей загрузки.

Листинг 4-26 показывает как определить и загрузить некий PXE домен. Обратите внимание, что если сам XML будет пропущен, а потому это всего лишь образец некой программы, которая не будет полностью рабочей.

 

Листинг 4-26. Предоставление загрузки PXE


# Example-26.py
from __future__ import print_function
import sys
import libvirt

xmlconfig = '<domain>........</domain>'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.defineXML(xmlconfig, 0)
if dom == None:
    print('Failed to define a domain from an XML definition.', \
          file=sys.stderr)
    exit(1)

if dom.create(dom) < 0:
    print('Can not boot guest domain.', file=sys.stderr)
    exit(1)

print('Guest '+dom.name()+' has booted', file=sys.stderr)

conn.close()
exit(0)
 	   

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

 

Предоставление загрузки напрямую из ядра

Технологии паравиртуализации эмулируют достаточно ограниченный набор оборудования, что зачастую делает невозможным применение имеющихся предоставляемых вариантов в точности как предписано. Для таких случаев часто имеется возможность загрузки некого гостевого домена напрямую из некого ядра и образа initrd, хранимого в файловой системе самого хоста. Это имеет одно интересное преимущество, которое состоит в том, что имеется возможность напрямую устанавливать аргументы загрузки командной строки ядра, что упрощает полностью автоматизированную установку. Это преимущество может быть достаточно интригующим когда данная техника применяется даже для полностью виртуальных гостевых доменов с поддержкой CD-ROM устройств/ PXE.

Одна из сложностей состоит в том что при загрузке напрямую из ядра его предоставление становится двухэтапным процессом. Для самого первого этапа требуется настроить необходимую конфигурацию гостевого XML на указание ядра/ initrd. Листинг 4-27 показывает как определить некую конфигурацию загрузки из ядра.

 

Листинг 4-27. Предоставление XML загрузки из ядра


# Example-27.py
<os>
  <type arch='x86_64' machine='pc'>hvm</type>
  <kernel>/var/lib/libvirt/boot/f11-x86_64-vmlinuz</kernel>
  <initrd>/var/lib/libvirt/boot/f11-x86_64-initrd.img</initrd>
  <cmdline>method=http://download.fedoraproject.org/pub/fedora/linux/releases/11/x86_64/os console=ttyS0 console=tty</cmdline>
</os>
 	   

Обратите внимание как снабжается командная строка ядра значением URL для того сайта выгрузки, который содержит необходимый для установки дистрибутива дерева соответствия ядру/ initrd. Это позволяет самому установщику автоматически выгружать все его ресурсы без запроса у своего пользователя некого URL установки. Это также можно применять для предоставления некого файла стартёра при полностью автоматической установке. Наконец, эта командная строка также может запросить у ядра активацию как самого первого последовательного порта, так и имеющейся карты VGA в качестве консоли, причём в последующем они выступают устройствами по умолчанию. Таким образом дублирование сообщений ядра в последовательный порт может быть полезным вариантом отладки. Естественно, допустимые параметры командной строки разнятся в зависимости от конкретного ядра загрузки. Относительно допустимых вариантов проконсультируйтесь с документацией производителя/ дистрибьютора ядра.

Самая последняя подробность настройки XML перед запуском необходимого гостя состоит в изменении значения элемента действия on_reboot в значение destroy. Это гарантирует что по завершению установщика гостя и запроса на перезагрузку такой гость вместо этого будет отключён. Это позволит вашему приложению управления приложением изменить данную конфигурацию чтобы она следующий раз устанавливалась с только что установленного диска. Такой процесс предоставления теперь может быть запущен через создание некого временного гостя с самой первой конфигурацией XML.

Листинг 4-28 показывает как создать некий домен загрузки из ядра. Обратите внимание, что сам XML опущен, поэтому данная программа не буде работать пока не будет предоставлен необходимый XML.

 

Листинг 4-28. Предоставление загрузки из ядра


# Example-28.py
from __future__ import print_function
import sys
import libvirt
xmlconfig = '<domain>........</domain>'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.createXML(xmlconfig, 0)
if dom == None:
    print('Unable to boot transient guest configuration.', \
          file=sys.stderr)
    exit(1)

print('Guest '+dom.name()+' has booted', file=sys.stderr)

conn.close()
exit(0)
 	   

После останова данного гостя можно начать второй этап процесса инициализации. На этой фазе элемент OS будет иметь значения удаляемых элементов kernel/initrd/cmdline, который либо заменяются ссылками на некий начальный загрузчик стороны хоста, либо на настройку начальной загрузки BIOS. Изначально это применялось для паравиртуальных гостей Xen, хотя позднее это используется и для полностью виртуальных гостей.

Описываемый второй этап конфигурации для некого паравиртуального гостя Xen мог бы выглядеть как- то так:


<bootloader>/usr/bin/pygrub</bootloader>
<os>
  <type arch="x86_64" machine="pc">hvm</type>
  <boot dev="hd"/>
</os>
 	   

Полностью виртуальный гость мог бы воспользоваться следующим:


<bootloader>/usr/bin/pygrub</bootloader>
<os>
  <type arch="x86_64" machine="pc">hvm</type>
  <boot dev="hd"/>
</os>
 	   

Получив определение для конфигурации второй фазы, такой гость может быть создан повторно, причём на этот раз с некой постоянной конфигурацией. Листинг 4-29 показывает как создать некий постоянный домен загрузки из ядра.

 

Листинг 4-29. Предоставление загрузки из ядра для постоянного гостевого домена


# Example-29.py
from __future__ import print_function
import sys
import libvirt
xmlconfig = '<domain>........</domain>'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.createXML(xmlconfig, 0)
if dom == None:
    print('Unable to define persistent guest configuration.', \
          file=sys.stderr)
    exit(1)

if dom.create(dom) < 0:
    print('Can not boot guest domain.', file=sys.stderr)
    exit(1)

print('Guest '+dom.name()+' has booted', file=sys.stderr)

conn.close()
exit(0)
 	   

Дополнительно к методу createXML также имеется и альтернативный метод createXMLFlags.

Останов

Стопом (stopping) именуется процесс полного останова (halting) некого исполняемого процесса. Гость может останавливаться двумя методами: shutdown и destroy.

Метод shutdown является чистым процессом отсанова, который отправляет некий сигнал операционной системы гостевого домена, запрашивая у неё немедленный останов. Такой гость будет остановлен только после того как его операционная система будет успешно остановлена. Данный процесс shutdown аналогичен команде shutdown в некой физической машине. Также существует метод shutdownFlags который способен, в зависимости от того что поддерживает ОС данного гостя, выключить этот домен и оставить его объект в некотором состоянии, допускающим его использование.

Методы destroy и destroyFlags немедленно прекращают свой гостевой домен. Такой процесс destroy аналогичен выемке разъёмов в некой физической машине.

Приостановка/ возобновление и сохранение/ восстановление

Методы suspend и resume относятся к числу тех процессов, которые получают некого исполняемого гостя и временно запоминают состояние его памяти. Позднее по времени имеется возможность возобновить (resume) такого гостя в его первоначальное состояние исполнения, продолжив работу с того места где он был приостановлен. Приостановка (suspend) не сохраняет некий постоянный образ имеющейся у гостя памяти. Для этого применяется save.

Методы save и restore относятся к тем процессам, которые получают некий запущенный процесс гостя и сохраняют его состояние памяти в какой- то файл. Через определённый промежуток времени имеется возможность восстановить (restore) этого гостя в его первоначальное состояние выполнения, продолжив выполнение с места остановки.

Важно обратить внимание на то, что методы save/ restore сохраняют только само состояние памяти; никакое состояние хранилища не консервируется. Следовательно, когда данный гость восстанавливается, лежащее в его основе хранилища гостя обязано быть в том же самом состоянии, в котором оно пребывало в момент начального сохранения этого гостя. Для применения на базовом уровне это подразумевает что некий гость может быть восстановлен только один раз из некого определённого сохранённого состояния образа. Для того чтобы иметь возможность многократного восстановления некого гостя из одного и того же сохранённого состояния, такое приложение должно также обладать неким моментальным снимком самого хранилища этого гостя на момент его сохранения и в явном виде преобразовывать этот снимок хранилища при восстановлении. Последующее развитие libvirt позволит автоматизировать возможности получения моментального снимка, которые сохранят и состояние памяти и состояние хранилища в единой операции.

Операции сохранения требуется полностью описанный путь к некому файлу в котором будет сохранено состояние памяти рассматриваемого гостевого домена. Такое имя пути/ файла должно располагаться в файловой системе его гипервизора, а не в вашем клиентском приложении libvirt. Нет никакой разницы между ними при управлении неким локальным гипервизором, однако имеющееся различие становится критически важным при удалённом соединении к гипервизору в вашей сетевой среде. Пример из Листинга 4-30 демонстрирует сохранение некого гостя с названием demo-guest в файл. Перед сохранением он выполняет проверку того что гость запущен, хотя с технической точки зрения это избыточно, поскольку имеющийся драйвер гипервизора выполнит эту проверку самостоятельно.

Листинг 4-30 показывает как сохранить некий гостевой домен, а затем остановить его за один шаг.

 

Листинг 4-30. Сохранение гостевого домена


# Example-30.py
from __future__ import print_function
import sys
import libvirt

filename = '/var/lib/libvirt/save/demo-guest.img'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByName('demo-guest')
if dom == None:
    print('Cannot find guest to be saved.', file=sys.stderr)
    exit(1)

info = dom.info()
if info == None:
    print('Cannot check guest state', file=sys.stderr)
    exit(1)

if info.state == VIR_DOMAIN_SHUTOFF:
    print('Not saving guest that is not running', file=sys.stderr)
    exit(1)

if dom.save(filename) < 0:
    print('Unable to save guest to '+filename, file=sys.stderr)

print('Guest state saved to '+filename, file=sys.stderr)

conn.close()
exit(0)
 	   

Позднее, через некий промежуток времени этот файл сохранённого состояния может быть затем применён для повторного запуска этого гостя с места его остановки при помощи метода restore. Имеющийся драйвер гипервизора возвратит некую ошибку если такой гость уже запущен; однако это не препятствует попыткам выполнения восстановления множество раз из того же самого файла состояния. Как уже упоминалось ранее, именно само приложение выступает ответственным за гарантию того чтобы обеспечить что хранилище гостя пребывает в том же самом состоянии, когда был создан этот образ сохранения.

Помимо этого метод saveFlags позволяет сохранять выбранный домен и в то же самое время изменить саму конфигурацию его сохраняемого образа. При восстановлении такого домена к такому запущенному домену будет применена полученная в результате изменения конфигурация.

Имеется также и иной способ сохранения домена. Такой метод managedSave способен сохранять состояние некого исполняемого домена; однако в этом случае ваша система выбирает местоположение для своего сохраняемого образа. Кроме того, такой домен будет восстановлен в своё сохранённое состояние после перезапуска этого домена.

Листинг 4-31 показывает как восстановить некий домен в рабочее состояние из какого- то сохранённого образа. Обратите внимание, что в данном случае сам файл образа может отсутствовать, а следовательно эта программа может завершиться неудачей когда вы попробуете её выполнить.

 

Листинг 4-31. Восстановление гостевого домена


# Example-31.py
from __future__ import print_function
import sys
import libvirt

filename = '/var/lib/libvirt/save/demo-guest.img'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

if id = conn.restore(filename) < 0:
    print('Unable to restore guest from '+filename, \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByID(id);
if dom == None:
    print('Cannot find guest that was restored', file=sys.stderr)
    exit(1)

print('Guest state restored from '+filename, file=sys.stderr)

conn.close()
exit(0)
 	   
[Предостережение]Предостережение

Восстановление некого гостевого домена не обновляет текущие значения даты/ времени.

После своего восстановления, гостевой домен возвращается в то же самое состояние, в котором он был сохранён. Это будет относиться и к значениям даты и времени, которые будут восстановлены из сохранённых. Такой гостевой домен обычно не будет иметь возможности определять промежуток времени, прошедший с момента его сохранения. Это означает, что значение текущего времени не будет автоматически обновлено ни в процессе операции восстановления, ни по её завершению.

Это предостережение остаётся справедливым даже если настроен некий NTP.

Дополнительно к методу restore также доступен и альтернативный метод restoreFlags.

Миграция

Миграцией именуется процесс получения некого образа гостевого домена и его перемещения куда- либо, обычно с гипервизора в одном узле в гипервизор другого узла. Существуют два метода миграции. Метод migrate получает некое установленное соединение с гипервизором и выдаёт инструкции своему домену мигрировать в такое подключение. Метод migrateToUri получает некий URI, определяющий подключение к какому- то гипервизору, открывает это соединение, а затем инструктирует свой домен для выполнения миграции к данному подключению. Для успешного выполнения миграции требуется совместное применение хранилища гипервизорами источника и получателя.

Самый первый параметр метода migrate определяет значение соединения для его применения в качестве цели данной миграции. Этот параметр является обязательным.

Второй параметр метода migrate описывает некий набор флагов, которые управляют тем как происходит данная миграция поверх указанного соединения. Если не требуются никакие флаги, тогда этот параметр должен быть установленным в ноль.

Флаги могут быть одним или более из следующих:


VIR_MIGRATE_LIVE
VIR_MIGRATE_PEER2PEER
VIR_MIGRATE_TUNNELLED
VIR_MIGRATE_PERSIST_DEST
VIR_MIGRATE_UNDEFINE_SOURCE
VIR_MIGRATE_PAUSED
VIR_MIGRATE_NON_SHARED_DISK
VIR_MIGRATE_NON_SHARED_INC
VIR_MIGRATE_CHANGE_PROTECTION
VIR_MIGRATE_UNSAFE
VIR_MIGRATE_OFFLINE
 	   

Третий параметр метода migrate определяет новое название для данного домена в его цели миграции. Этот параметр поддерживают не все гипервизоры. Если не требуется переименование данного домена, тогда этот параметр следует установить в None.

Четвёртый параметр метода migrate определяет значение URI, которое будет применяться в качестве самой цели миграциию Некий URI требуется только когда ваша целевая система поддерживает множество гипервизоров. Если в такой целевой системе имеется лишь единственный гипервизор, тогда этот параметр может быть установлен в None.

Пятый и последний параметр рассматриваемого метода migrate определяет значение полосы пропускания в MiB/s для своего применения. Если такой максимум не требуется, тогда установите этот параметр в ноль.

Миграция достаточно хитроумна когда ваш домен запущен и применяется. Ваш пользователь может испытывать задержки, или даже терять подключение в случае некой удалённой миграции. Для обеспечения гарантии того что ваши пользователи не ощутят воздействия при его выполнении вам следует гарантировать чтобы он по крайней мере не использовался.

для миграции некого гостевого домена в какое- то соединение, которое уже открыто, воспользуйтесь методом migrate. Листинг 4-32 показывает как осуществлять миграцию домена.

 

Листинг 4-32. Миграция домена в некое открытое соединение


# Example-32.py
from __future__ import print_function
import sys
import libvirt

domName = 'Fedora22-x86_64-1'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dest_conn = libvirt.open('qemu+ssh://desthost/system')
if dest_conn == None:
    print('Failed to open connection to qemu+ssh://desthost/system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByName(domName)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

new_dom = dom.migrate(dest_conn, 0, None, None, 0)
if new_dom == None:
    print('Could not migrate to the new domain', file=sys.stderr)
    exit(1)

print('Domain was migrated successfully.', file=sys.stderr)

destconn.close()
conn.close()
exit(0)
 	   

Метод migrateToUri является аналогичным за исключением того, что вместо некого имеющегося соединения самым первым параметром выступает целевое значение URI. Для миграции гостевого домена в некий URI воспользуйтесь методом migrateToUri. Листинг 4-33 показывает как выполнить миграцию домена в какой- то URI.

 

Листинг 4-33. Миграция домена в реальном времени в некий URI


# Example-33.py
from __future__ import print_function
import sys
import libvirt

domName = 'Fedora22-x86_64-1'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByName(domName)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

new_dom = dom.migrateToURI('qemu+ssh://desthost/system', 0, None, 0)
if new_dom == None:
    print('Could not migrate to the new domain', file=sys.stderr)
    exit(1)

print('Domain was migrated successfully.', file=sys.stderr)

conn.close()
exit(0)
 	   

Для миграции гостевого домена в реальном масштабе в некий URI воспользуйтесь методом migrate или migrateToUri с установленным набором флага VIR_MIGRATE_LIVE. Листинг 4-34 показывает как выполнить миграцию в реальном времени (с запущенным) доменом в некий URI.

 

Листинг 4-34. Миграция домена в реальном времени в некий URI


# Example-34.py
from __future__ import print_function
import sys
import libvirt

domName = 'Fedora22-x86_64-1'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dest_conn = libvirt.open('qemu+ssh://desthost/system')
if conn == None:
    print('Failed to open connection to qemu+ssh://desthost/system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByID(6)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

new_dom = dom.migrate(dest_conn, libvirt.VIR_MIGRATE_LIVE, None, \
                      None, 0)
if new_dom == None:
    print('Could not migrate to the new domain', file=sys.stderr)
    exit(1)

print('Domain was migrated successfully.', file=sys.stderr)

destconn.close()
conn.close()
exit(0)
 	   

Дополнительно к методу migrate имеются альтернативные методы с названиями migrate2, migrate3, migrateToUri, migrateToUri2 и migrateToUri3 для миграции поверх прочих типов соединений.

Автоматический запуск

Некий гостевой домен может быть настроенным на автоматический запуск в каком- то определённым гипервизором, причём либо самим по себе этим гипервизором, либо посредством libvirt. В сочетании с неким управляемым сохранением это позволяет имеющейся в неком гостевом домене операционной системе принимать на себя перезагрузки хоста без какого бы то ни было рассмотрения вариантов собственной перезагрузки. Когда выполняется перезапуск libvirt, такой гостевой домен будет автоматически восстановлен. Это обрабатывается неким API, отличающимся от операций save и restore, так как для libvirt требуется знание значения пути без его задания во входных параметрах пользователем. Листинг 4-35 показывает как установить автоматический запуск некого домена при загрузке его основного хоста.

 

Листинг 4-35. Настройка автоматического запуска домена


# Example-35.py
from __future__ import print_function
import sys
import libvirt

domName = 'Fedora22-x86_64-1'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByID(6)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

dom.setAutostart(1)  # turn on autostart

conn.close()
exit(0)
 	   

Настройка домена

Домены в libvirt определяются с помощью XML. Всё относится только к самому домену, например, к задаваемым в данном XML домена памяти и ЦПУ. Сам формат XML домена определён в http://libvirt.org/formatdomain.html. Когда у вас установлен пакет libvirt-devel, к нему можно получить доступ локально в /usr/share/doc/libvirt-devel-version/.

Режимы загрузки

Загрузка через BIOS доступна для гипервизоров с поддержкой полной виртуализации. В этом случае ваш BIOS обладает неким порядком приоритетов (флоппи- диск, жёсткий диск, CD-ROM, сеть), который определяет где получать/ обнаруживать сам образ загрузки (Листинг 4-36).

 

Листинг 4-36. Настройка режима загрузки


...
  <os>
    <type>hvm</type>
    <loader readonly="yes" type="rom">
        /usr/lib/xen/boot/hvmloader
    </loader>
    <nvram template='/usr/share/OVMF/OVMF_VARS.fd'>
        /var/lib/libvirt/nvram/guest_VARS.fd
    </nvram>
    <boot dev="hd"/>
    <boot dev="cdrom"/>
    <bootmenu enable="yes" timeout="3000"/>
    <smbios mode="sysinfo"/>
    <bios useserial="yes" rebootTimeout="0"/>
  </os>
  ...
 	   

Ресурсы памяти/ ЦПУ

Ресурсы ЦПУ и памяти могут быть установлены на момент создания самого домена или динамически в то время когда этот домен пребывает в активном или не активном состоянии.

Ресурсы ЦПУ устанавливаются в момент создания домена при помощи тегов в самом определении XML этого домена. Его гипервизор определяет некий предел общего числа виртуальных ЦПУ, которое не может быть превышено либо на момент создания домена, либо в последующее время. Этот максимум может зависеть от объёма ресурсов и пределов гипервизора. Некий пример для определения XML ЦПУ может выглядеть так:


<domain>
  ...
  <vcpu placement="static" cpuset="1-4,^3,6" current="1">2</vcpu>
  ...
</domain>
 	   

Ресурсы памяти также могут устанавливаться в момент создания домена при помощи тегов в самом определении этого домена. Должны быть настроенными как максимальное, так и текущее выделения памяти. Вот некий пример определения XML памяти домена:


<domain>
  ...
  <maxMemory slots="16" unit="KiB">1524288</maxMemory>
  <memory unit="KiB">524288</memory>
  <currentMemory unit="KiB">524288</currentMemory>
  ...
</domain>
 	   

После того как конкретный домен создан, значение числа виртуальных ЦПУ может быть увеличено методом setVcpus или setVcpusFlags. Значение числа ЦПУ не может превышать обсуждавшегося ранее максимума для его гипервизора. Листинг 4-37 устанавливает значение максимального числа виртуальных ЦПУ для своего домена. Это может быть выполнено как для активного, так и для не активного доменов. Если данный домен активен, тогда установленное новое число не вступит в действие до его перезагрузки.

 

Листинг 4-37. Установка максимального числа виртуальных ЦПУ для домена


# Example-37.py
from __future__ import print_function
import sys
import libvirt

domName = 'Fedora22-x86_64-1'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByID(6)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

dom.setVcpus(2)

conn.close()
exit(0)
 	   

Кроме того, после того как ваш домен был создан, может быть изменён и его объём памяти через методы setMemory и setMemoryFlags. Объём памяти должен выражаться в килоБайтах. Листинг 4-38 устанавливает максимальный объём памяти для своего домена.

 

Листинг 4-38. Установка максимального объёма памяти для домена


# Example-38.py
from __future__ import print_function
import sys
import libvirt

domName = 'Fedora22-x86_64-1'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByName(domName)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

dom.setMemory(4096) # 4 GigaBytes

conn.close()
exit(0)

 	   

Дополнительно к методу setMemory доступен и альтернативный метод setMemoryFlags.

Мониторинг производительности

Статистические измерения доступны для отслеживания соотношений загруженности доменов, vCPU, памяти, блочных устройств и сетевых интерфейсов.

Производительность блочного устройства домена

Статистические данные загруженности диска предоставляются методом blockStats. Листинг 4-39 показывает как выполнять выборку статистических данных работающего домена. Заметим, что статистические данные могут быть возвращены и от не активного домена.

 

Листинг 4-39. Получение статистических данных ввода/ вывода блочного диска


# Example-39.py
from __future__ import print_function
import sys
import libvirt

domName = 'Fedora22-x86_64-1'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByID(6)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

rd_req, rd_bytes, wr_req, wr_bytes, err = \
dom.blockStats('/path/to/linux-0.2.img')
print('Read requests issued:  '+str(rd_req))
print('Bytes read:            '+str(rd_bytes))
print('Write requests issued: '+str(wr_req))
print('Bytes written:         '+str(wr_bytes))
print('Number of errors:      '+str(err))

conn.close()
exit(0)
 	   

Получаемый в результате кортеж содержит значение числа вызванных запросов чтения (записи), а также реальное число переданных байт. Некое блочное устройство определяется значением пути к файлу образа или значением шины устройства, устанавливаемого содержимым элемента devices/disk/target[@dev] в XML конкретного домена.

Дополнительно к методу blockStats также доступен альтернативный метод blockStatsFlags.

Производительность vCPU

Для получения индивидуальных статистических данных vCPU воспользуйтесь методом getCPUStats. Листинг 4-40 показывает как отображать статистические данные vCPU.

 

Листинг 4-40. Получение индивидуальных статистических данных ЦПУ


# Example-40.py
from __future__ import print_function
import sys
import libvirt

domName = 'Fedora22-x86_64-1'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByID(5)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

cpu_stats = dom.getCPUStats(False)
for (i, cpu) in enumerate(cpu_stats):
   print('CPU '+str(i)+' Time: '+ \
         str(cpu['cpu_time'] / 1000000000.))

conn.close()
exit(0)
 	   

getCPUStats получает единственный параметр, Булево значение. Когда применяется False, все статистические данные выдаются в виде некого отчёта агрегированных данных всех имеющихся ЦПУ. При использовании True каждый ЦПУ выдаёт отчет индивидуальных статистических данных. В любом случае возвращается некий list. Все статистические данные выдаются в отчёте в наносекундах. Если некий хост имеет четыре ЦПУ, в получаемом списке cpu_stats будет четыре логических элемента.

getCPUStats(True) агрегирует получаемые статистические данные для всех ЦПУ данного хоста. Листинг 4-41 отображает значения агрегированных статистических данных некого домена.

 

Листинг 4-41. Получение агрегированных статистических данных ЦПУ


# Example-41.py
from __future__ import print_function
import sys
import libvirt

domName = 'Fedora22-x86_64-1'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByID(5)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

stats = dom.getCPUStats(True)
print('cpu_time:    '+str(stats[0]['cpu_time']))
print('system_time: '+str(stats[0]['system_time']))
print('user_time:   '+str(stats[0]['user_time']))

conn.close()
exit(0)
 	   

Статистика памяти

Для получения используемого в данный момент времени объёма памяти вы можете воспользоваться методом memoryStats. Листинг 4-42 показывает как отображать используемую доменом память. Обратите внимание на различные виды отображаемой памяти, включая применение подкачки (swap).

 

Листинг 4-42. Получение агрегированных статистических данных памяти


# Example-42.py
from __future__ import print_function
import sys
import libvirt

domName = 'Fedora22-x86_64-1'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByID(5)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

stats  = dom.memoryStats()
print('memory used:')
for name in stats:
    print('  '+str(stats[name])+' ('+name+')')

conn.close()
exit(0)
 	   

Отметим, что memoryStats возвращает некий оъект словаря. Такой объект будет содержать различное число логических элементов в зависимости от возможностей смого гипервизора и гостевого домена.

Статистика ввода/ вывода

Для получения статистических данных сетевой среды вам требуется значение названия соответствующего интерфейса хоста, через который подключается этот домен (vnetX). Для его обнаружения выполните выборку соответствующего описания XML домена (libvirt видоизменяет его во время исполнения). Затем отыщите значения элементов devices/interface/target[@dev]. Листинг 4-43 показывает как отображать значения статистических данных ввода/ вывода для конкретного домена.

 

Листинг 4-43. Получение агрегированных статистических данных сетевого ввода/ вывода


# Example-43.py
from __future__ import print_function
import sys
import libvirt
from xml.etree import ElementTree

domName = 'Fedora22-x86_64-1'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByID(5)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

tree = ElementTree.fromstring(dom.XMLDesc())
iface = tree.find('devices/interface/target').get('dev')
stats = dom.interfaceStats(iface)
print('read bytes:    '+str(stats[0]))
print('read packets:  '+str(stats[1]))
print('read errors:   '+str(stats[2]))
print('read drops:    '+str(stats[3]))
print('write bytes:   '+str(stats[4]))
print('write packets: '+str(stats[5]))
print('write errors:  '+str(stats[6]))
print('write drops:   '+str(stats[7]))

conn.close()
exit(0)
 	   

Применяемый метод interfaceStats возвращает общее число полученных (отправленных) байт (пакетов) и значение числа ошибок приёма/ передачи.

Настройка устройства

Информацию о конфигурации для некого гостевого домена можно получить при помощи соответствующего метода XMLDesc. Данный метод возвращает значение текущего описания домена в виде некого потока данных XML. Этот поток затем может быть синтаксически проанализирован для получения подробных сведений обо всех составляющих этот домен частях.

Значение параметра flags может содержать любое число следующих констант:


VIR_DOMAIN_XML_SECURE
VIR_DOMAIN_XML_INACTIVE
VIR_DOMAIN_XML_UPDATE_CPU
VIR_DOMAIN_XML_MIGRATABLE
 	   

Листинг 4-44 показывает как отображать информацию об XML домена.

 

Листинг 4-44. Получение основной информации из описания XML определённого домена


# Example-44.py
from __future__ import print_function
import sys
import libvirt
from xml.dom import minidom

domName = 'Fedora22-x86_64-1'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByID(5)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

raw_xml = dom.XMLDesc(0)
xml = minidom.parseString(raw_xml)
domainTypes = xml.getElementsByTagName('type')
for domainType in domainTypes:
    print(domainType.getAttribute('machine'))
    print(domainType.getAttribute('arch'))

conn.close()
exit(0)
 	   

Эмулятор

Для выявления значения эмулятора гостевого домена отыщите и отобразите содержимое тега XML emulator. Листинг 4-45 показывает как применяется отображение значения эмулятора определённого домена. Для этого имеется ряд возможностей, но их слишком много для отображения здесь.

 

Листинг 4-45. Получение информации об эмуляторе определённого домена


# Example-45.py
from __future__ import print_function
import sys
import libvirt
from xml.dom import minidom

domName = 'Fedora22-x86_64-1'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByID(5)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

raw_xml = dom.XMLDesc(0)
xml = minidom.parseString(raw_xml)
domainEmulator = xml.getElementsByTagName('emulator')
print('emulator: '+domainEmulator[0].firstChild.data)

conn.close()
exit(0)
 	   

Листинг 4-46 показывает содержимое конфигурации XML для этого эмулятора.

 

Листинг 4-46. Информация XML эмулятора домена


<domain type="kvm">
    ...
    <emulator>/usr/libexec/qemu-kvm</emulator>
    ...
</domain>
 	   

Диски

Для обнаружения диска (или дисков) гостевого домена отыщите и отобразите содержимое тега (или тегов) XML disk. Листинг 4-47 показывает все настроенные диски в определённом домене.

 

Листинг 4-47. Получение информации о диске определённого домена


# Example-47.py
from __future__ import print_function
import sys
import libvirt
from xml.dom import minidom

domName = 'Fedora22-x86_64-1'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByID(1)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

raw_xml = dom.XMLDesc(0)
xml = minidom.parseString(raw_xml)
diskTypes = xml.getElementsByTagName('disk')
for diskType in diskTypes:
    print('disk: type='+diskType.getAttribute('type')+' device='+ \
          diskType.getAttribute('device'))
    diskNodes = diskType.childNodes
    for diskNode in diskNodes:
        if diskNode.nodeName[0:1] != '#':
            print('  '+diskNode.nodeName)
            for attr in diskNode.attributes.keys():
                print('    '+diskNode.attributes[attr].name+' = '+
                 diskNode.attributes[attr].value)

conn.close()
exit(0)
 	   

Листинг 4-48 показывает содержимое конфигурации XML для дисков.

 

Листинг 4-48. Информация XML о дисках домена


<domain type="kvm">
    ...
    <disk type="file" device="disk">
      <driver name="qemu" type="qcow2" cache="none"/>
      <source file='/var/lib/libvirt/images/RHEL7.1-x86_64-1.img'/>
      <target dev="vda" bus="virtio"/>
      <address type="pci" domain="0x0000" bus="0x00" slot="0x06"
               function='0x0'/>
    </disk>
    <disk type="file" device="cdrom">
      <driver name="qemu" type="raw"/>
      <target dev="hdc" bus="ide"/>
      <readonly/>
      <address type="drive" controller="0" bus="1" target="0"
               unit='0'/>
    </disk>
    ...
</domain>
 	   

Сети

Для обнаружения сетевых интерфейсов гостевого домена отыщите и отобразите содержимое тега (или тегов) XML interface. Листинг 4-49 показывает все имеющиеся в определённом домене сетевые интерфейсы.

 

Листинг 4-49. Получение информации о сетевых интерфейсах определённого домена


# Example-49.py
from __future__ import print_function
import sys
import libvirt
from xml.dom import minidom

domName = 'Fedora22-x86_64-1'

conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)

dom = conn.lookupByID(1)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)

raw_xml = dom.XMLDesc(0)
xml = minidom.parseString(raw_xml)
interfaceTypes = xml.getElementsByTagName('interface')
for interfaceType in interfaceTypes:
    print('interface: type='+interfaceType.getAttribute('type'))
    interfaceNodes = interfaceType.childNodes
    for interfaceNode in interfaceNodes:
        if interfaceNode.nodeName[0:1] != '#':
            print('  '+interfaceNode.nodeName)
            for attr in interfaceNode.attributes.keys():
                print('    '+interfaceNode.attributes[attr].name+' = '+
                 interfaceNode.attributes[attr].value)

conn.close()
exit(0)
 	   

Листинг 4-50 показывает содержимое конфигурации XML для сетевых интерфейсов.

 

Листинг 4-50. Информация XML о сетевых интерфейсах домена


<domain type="kvm">
    ...
    <interface type="network">
      <mac address='52:54:00:94:f0:a4'/>
      <source network="default"/>
      <model type="virtio"/>
      <address type="pci" domain="0x0000" bus="0x00"
               slot='0x03' function="0x0"/>
    </interface>
    ...
</domain>
 	   

Мышь, клавиатура и планшеты

Для обнаружения устройств ввода гостевого домена отыщите и отобразите содержимое тега (или тегов) XML input. Листинг 4-51 показывает как перечислить те сведения XML, которые относятся к мыши, клавиатуре и сенсорной панели.

 

Листинг 4-51. Получение информации о сетевых интерфейсах определённого домена


# Example-51.py
from __future__ import print_function
import sys
import libvirt
from xml.dom import minidom
domName = 'Fedora22-x86_64-1'
conn = libvirt.open('qemu:///system')
if conn == None:
    print('Failed to open connection to qemu:///system', \
          file=sys.stderr)
    exit(1)
dom = conn.lookupByID(1)
if dom == None:
    print('Failed to find the domain '+domName, file=sys.stderr)
    exit(1)
raw_xml = dom.XMLDesc(0)
xml = minidom.parseString(raw_xml)
devicesTypes = xml.getElementsByTagName('input')
for inputType in devicesTypes:
    print('input: type='+inputType.getAttribute('type')+' bus='+ \
          inputType.getAttribute('bus'))
    inputNodes = inputType.childNodes
    for inputNode in inputNodes:
        if inputNode.nodeName[0:1] != '#':
            print('  '+inputNode.nodeName)
            for attr in inputNode.attributes.keys():
                print('    '+inputNode.attributes[attr].name+' = '+
                 inputNode.attributes[attr].value)
conn.close()
exit(0)
 	   

Листинг 4-52 показывает содержимое конфигурации XML для мыши, клавиатуры и сенсорной панели.

 

Листинг 4-52. Информация XML о мыши, клавиатуре и сенсорной панели домена


<domain type="kvm">
    ...
    <input type="tablet" bus="usb"/>
    <input type="mouse" bus="ps2"/>
    ...
</domain> 	   

Проброс устройств USB

Возможность проброса устройства USB делает возможным назначение физического устройства USB напрямую гостевой машине. Драйвер гостевой ОС может применять оборудование этого устройства напрямую без того чтобы полагаться на какие- либо возможности драйвера ОС самого хоста.

[Замечание]Замечание

USB устройства наследуются определённым гостевым доменом только в момент загрузки. Вновь активированные устройства USB не могут наследоваться с этого хоста после того как этот гостевой домен был загружен.

При использовании пробрасываемого устройства применяются некоторые предостережения. После того как USB устройство напрямую назначено некоторому гостю, выполнение миграции будет невозможной без предварительного отключения в горячем режиме устройства от данного гостя. помимо этого libvirt не предоставляет гарантий что прямое назначение устройств является безопасным, оставляя принятие решения о политике безопасности лежащей в основе технологии безопасности.

Проброс устройств PCI

Проброс определённого устройства PCI делает возможным некому физическому устройсву PCIмашине хоста быть назначенным непосредственно гостевой машине. Драйвер этой гостевой ОС может применять полученное оборудование устройства напрямую без того чтобы полагаться на какие бы то ни было возможности драйвера ОС хоста.

при использовании устройства PCI применяются некие предосторожности. После того как некое устройство PCI напрямую назначается некому гостю, миграция будет невозможна без предварительного отключения этого устройства в горячем режиме от данного гостя. Кроме того, libvirt не гарантирует что такое непосредственное назначение устройства является безопасным, политика безопасности отдаётся на откуп лежащей в основе технологии виртуализации. Безопасный проброс устройства PCI обычно требует особых возможностей оборудования, например, свойств VT-d для наборов микросхем Intel, либо IOMMU для микросхем AMD.

Существует два режима в которых может выполняться подключение некого устройства PCI, а именно, управляемый и не управляемый режимы, хотя на момент написания книги управляемый режим подключения поддерживал только KVM. При управляемом режиме данное настроенное устройство будет автоматически отключено от драйверов ОС своего хоста в то время как этот гость запускается и затем повторно подключается после останова данного гостя. При неуправляемом режиме данное устройство должно быть заранее в явном виде отключено перед загрузкой данного гостя. Этот гость отклонит запуск если рассматриваемое устройство всё ещё подключено к ОС своего хоста. API устройства узла libvirt предоставляет некое средство отключения/ повторного подключения устройств PCI от/ к драйверам хоста. В качестве альтернативы ОС данного хоста может быть настроена на занесении в чёрный список этих применяемых для гостей устройств PCI с тем, чтобы они никогда не подключались к драйверам ОС хоста.

В обоих режимах сама технология виртуализации всегда будет выполнять некий сброс в устройстве перед запуском гостя и после останова гостя. Для гарантии изоляции между самим хостом и ОС гостей это критически важно. Существуют разнообразные способы выполнения сброса устройства PCI. Некоторые технологии сброса ограничены сферой отдельного устройства/ функции, в то время как прочие могут оказывать за раз воздействие на множество устройств. В этом последнем варианте будет необходимо совместно назначить все подвергающиеся воздействию устройства одному и тому же гостю; в противном случае не будет возможности выполнить безопасным образом сброс. Для определения того требуется ли некому устройству совместное назначение вручную для отключения данного устройства с последующей попыткой выполнения необходимой операции сброса можно применять API определённого устройства узла. Если это удастся, тогда будет иметься возможность самостоятельного назначения устройства гостю. В случае сбоя будет необходимо совместно назначить это устройство совместно с прочими в той же самой шине PCI.

Некое устройство PCI назначается гостю с применением элемента hostdevice. Режим mode всегда должен быть установленным в значение subsystem, а его атрибут type должен быть установлен в значение pci. Значением managed может быть либо yes, либо no, как это необходимо для конкретного приложения. В рамках элемента hostdevice имеется элемент source, а внутри следующего элемента address применяется конкретное подключаемое устройство PCI. Такой элемент address ожидает атрибуты для domain, bus, slot и function. Проще всего это увидеть на простом примере в Листинге 4-53.

 

Листинг 4-53. Получение сведений об устройстве PCI


<hostdev mode="subsystem" type="pci" managed="yes">
  <source>
    <address domain="0x0000"
             bus='0x06'
             slot='0x12'
             function='0x5'/>
  </source>
</hostdev>
 	   

Задания блочного устройства

libvirt предоставляет общие методы задания блока, которые могут применяться для инициации и управления операциями на дисках, которые относятся к некому домену. Задания запускаются вызовом той функции, которая ассоциирована с желательной операцией (например, blockPull). После запуска все задания блока управляются тем же самым образом. Они могут быть прерванными, дросселированными и поставленными в очередь. Для указания окончательного состояния по его завершению вызывается некое асинхронное событие.

Могут запускаться следующие блочные задания:

  • blockPull запускает некую операцию пула блоков для предписанного диска. Эта операция допустима только для настроенного особым образом диска. blockPull заполнит некий образ диска данными из основывающего его образа. После того как будут выставлены все данные этого лежащего в основе диска, такой диск больше не зависит от лежащего в его основе образа..

  • Некий диск может быть опрошен на предмет заданий активных блоков при помощи blockJobInfo. Если они выявлены, сведения о задании выставляются в отчёте в виде некой структуры, которая содержит значение типа задания, настроек дросселирования полосы пропускания, а также информации о ходе процесса.

  • Для прекращения активного задания на определённом диске воспользуйтесь virDomainBlockJobAbort().

  • Для ограничения значения полосы пропускания,которое может потреблять некое блочное задание, воспользуйтесь blockJobSetSpeed(). Полоса пропускания задаётся в элементах МБ/с. Листинг 4-54 отображает информацию об активных блочных заданиях.

     

    Листинг 4-54. Получение сведений об активных блочных заданиях

    
    # Example-54.py
    from __future__ import print_function
    import sys
    import libvirt
    
    domxml =
     """<domain type="kvm">
          <name>example</name>
          <memory>131072</memory>
          <vcpu>1</vcpu>
          <os>
            <type arch="x86_64" machine='pc-0.13'>hvm</type>
          </os>
          <devices>
            <disk type="file" device="disk">
              <driver name="qemu" type="qed"/>
              <source file='/var/lib/libvirt/images/example.qed' />
              <target dev="vda" bus="virtio"/>
            </disk>
          </devices>
        </domain>"""
    
    def do_cmd (cmdline):
        status = os.system(cmdline)
        if status < 0:
            return -1
        return WEXITSTATUS(status)
    
    def make_domain (conn):
        do_cmd("qemu-img create -f raw " + \
               "/var/lib/libvirt/images/backing.qed 100M")
        do_cmd("qemu-img create -f qed -b " + \
               "/var/lib/libvirt/images/backing.qed"+ \
               "/var/lib/libvirt/images/example.qed")
        dom = conn.createXML(domxml, 0)
        return dom
    
    dom = None
    disk = "/var/lib/libvirt/images/example.qed"
    
    conn = libvirt.open('qemu:///system')
    if conn == None:
        print('Failed to open connection to qemu:///system', \
              file=sys.stderr)
        exit(1)
    
    dom = make_domain(conn)
    if dom == None:
        print("Failed to create domain", file=sys.stderr)
        exit(1)
    
    if dom.blockPull(disk, 0, 0) < 0:
        print("Failed to start block pull", file=sys.stderr)
        exit(1)
    
    while (1):
        info = dom.blockJobInfo(disk, 0);
        if (info != None:
            print("BlockPull progress: %0.0f %%",
                float(100 * info.cur / info.end))
        elif info.cur == info.end):
            printf("BlockPull complete")
            break
        else:
            print("Failed to query block jobs", file=os.stderr)
            break
        time.sleep(1)
    
    os.unlink("/var/lib/libvirt/images/backing.qed")
    os.unlink("/var/lib/libvirt/images/example.qed")
    if dom != NULL:
       conn.destroy(dom)
    
    conn.close()
    exit(0)
     	   

Выводы

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