Глава 3. Подключение к домену

Как уже упоминалось в предыдущей главе, соединение выступает основой для любого действия и объекта в обсуждаемой нами системе libvirt. Всякий логический элемент, который желает взаимодействовать с libvirt, быдь то virsh, virt-manager или программа, применяющая библиотеку libvirt, вначале должен получить некое соединение к соответствующему демону libvirt в самом узле хоста, к которому у него имеется заинтересованность. Некое соединение описывает не только занчение типа технологии виртуализации, с которой желает взаимодействовать данный агент (QEMU, XEN, UML и так далее), но также все методы аутентификации, которые требуются для подключения к такому ресурсу.

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

Обзор

Самая первая вещь которую следует сделать агенту libvirt, это выполнить вызов функции virInitialize или одной из имеющихся функций подключения libvirt Python для получения некого экземпляра класса virConnect. Этот экземпляр будет применяться в последующих действиях. Модуль libvirt Python предоставляет три различных функции для подключения к некому ресурсу.


conn = libvirt.open(name)
conn = libvirt.openAuth(uri, auth, flags)
conn = libvirt.openReadOnly(name)
 	   

Во всех трёх случаях имеется параметр name, который ссылается на значение URI того гипервизора, к которому требуется подключаться. Глава 2 предоставляет все подробности относительно различных допустимых форматов URI. Если значением URI является None, тогда libvirt применит некую эвристику и выставит на пробу какой- то подходящий драйвер гипервизора. Хотя это и может быть удобным для разработчиков выполнять проверку по месту, &qout;как есть&qout;, настоятельно рекомендуется чтобы приложения не полагались на подобную пробную логику, ибо она может измениться в любой момент. Приложения должны всегда в явном виде запрашивать какое именно подключение гипервизора желательно представлением его в URI.

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

open

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

 

Листинг 3-1. Применение open


# Listing-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)

print('Connection successful.')

conn.close()
print('Connection closed.')
exit(0)
 	   

Данный пример открывает соединение на чтение- запись к имеющемуся системному драйверу гипервизора QEMU, убеждается что оно успешно и, если это так, закрывает данное подключение. Для получения дополнительных сведений относительно URI libvirt обратитесь к Главе 2.

openReadOnly

Функция openReadOnly попробует открыть некое соединение для доступа только на чтение (Листинг 3-2). Такое подключение имеет ограниченный набор допустимых вызовов методов и обычно полезна для отслеживания приложений, которые не должны допускать изменений. Как и в случае с open, этод метод не имеет средств для обратных вызовов аутентификации, а потому он полагается на праметры доступа.

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

 

Листинг 3-2. Применение openReadOnly


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

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

conn.close()
exit(0)
 	   

Этот пример открывает подключение с доступом только для чтения к системноу драйверу гипервизора QEMU, убеждается что оно успешное и, если это так, закрывает данное подключение. Для получения дополнительных сведений относительно URI libvirt обратитесь к Главе 2.

openAuth

Функция openAuth является наиболее гибкой и действенной, делая предыдущие две функции избыточными. Она получает некий дополнительный параметр, который предоставляет некий list Python, который содержит параметры доступа аутентификации из вашего прикладного приложения клиента. Значение параметра flags позволяет приложению выполнять запросы на подключения с доступом только для чтения, если это желательно, при помощи установки флага VIR_CONNECT_RO. Листинг 3-3 показывает образец программы Python, которая применяет openAuth с правами доступа указанных именем пользователя и его паролем. Как и в случае с open, этот метод не имеет никаких средств предоставления обратных вызовов аутентификации, а потому она будет успешной лишь для тех подключений, при которых аутентификация может быть осуществлена на основании прав доступа самого данного приложения.

 

Листинг 3-3. Применение openAuth


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

SASL_USER = "my-super-user"
SASL_PASS = "my-super-pass"
def request_cred(credentials, user_data):
    for credential in credentials:
        if credential[0] == libvirt.VIR_CRED_AUTHNAME:
            credential[4] = SASL_USER
        elif credential[0] == libvirt.VIR_CRED_PASSPHRASE:
            credential[4] = SASL_PASS
    return 0

auth = [[libvirt.VIR_CRED_AUTHNAME, libvirt.VIR_CRED_PASSPHRASE], \
        request_cred, None]
conn = libvirt.openAuth('qemu+tcp://localhost/system', auth, 0)
if conn == None:
    print('Failed to open connection to qemu+tcp://localhost/system', \
          file=sys.stderr)
    exit(1)

conn.close()
exit(0)
 	   

Чтобы проверить эту программу, должны быть представлены все следующие настройки:

  1. /etc/libvirt/libvirtd.conf

    
    listen_tls = 0
    listen_tcp = 1
    auth_tcp = "sasl"
     	   
  2. /etc/sasl2/libvirt.conf

    
    mech_list: digest-md5
     	   
  3. Некий пользователь программы virt был добавлен в имеющуюся базу данных SASL. Как правило, это некая реляционная база данных, настроенная под хранение прав доступа SASL.

  4. libvirtd был запущен с --listen.

Если соблюдены все настройки, Листинг 3-3 может воспользоваться установленными именем пользователя и его паролем и разрешить к libvirtd доступ по чтению- записи.

В отличии от интерфейса C libvirt, Python не предоставляет настраиваемых обратных вызовов для получения прав достопа.

Также следует заметить, что права доступа SASL это не только доступный для данного API метод аутентификации. Также имеется большое число доступных взаимодействий с правами доступа, которые включают PolicyKit (PKI), GSSAPI, SSH, ESX и XEN. Могут быть настроены любые из них.

close

Некое подключение, когда оно больше не требуется, может быть высвобождено вызовом метода close из класса virConnection. Соединения являются объектами с подсчётом ссылок, поэтому для каждого вызова функции open должен иметься соответствующий вызов метода close (Листинг 3-4).

Как уже упоминалось, соединения подсчитывают число ссылок на них; такой счётчик в явном виде увеличивает своё значение при первоначальном open, openAuth и им подобным. Он также временно увеличивается прочими методами, которые полагают что данное соединение остаётся рабочим. Вызов функции open должен иметь соответствующий ему close, а все прочие ссылки высвобожденными по завершению соответствующих операций.

В Python счётчики ссылок могут автоматически уменьшаться когда некий экземпляр класса покидает его зону действия или когда завершается данная программа. Когда же завершается сам процесс, счётчики ссылок также мкидываются в ноль.

 

Листинг 3-4. Применение close с дополнительными ссылками


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

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

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

conn1.close()
conn2.close()
exit(0)
 	   

Обратите также внимание на то, что все прочие экземпляры класса, ассоциированные с неким соединением (virDomain, virNetwork и прочие) будут удерживать ссылку на это соединение.

Форматы URI

Для идентификации подключений к гипервизору libvirt применяет URI (uniform resource identifiers, единообразные идентификаторы ресурсов). Как локальные, так и удалённые гипервизоры адресуются со стороны libvirt при помощи URI. Сама схема URI и путь определяют гипервизор для подключения, в то время как часть хоста в этом URI задаёт его местоположение.

Локальные URI

Локальные URI libvirt имеют один из следующих видов:


driver:///system
driver:///session
driver+unix:///system
driver+unix:///session
 	   

Все прочие URI libvirt рассматриваются как удалённые и ведут себя именно так, даже если подключаются локально. Для получения дополнительных сведений об удалённых URI обратитесь к разделу с названием Удалённые URI.

В настоящее воемя поддерживаются драйверы, перечисленные в Таблице 3-1.

Таблица 3-1. Поддерживаемые драйверы
Драйвер Описание

QemU

Для управления гостями qemu и KVM

Xen

Для управления гостями Xen старого стиля (Xen 3.1 и старше)

Xenapi

Для управления гостями Xen нового стиля

UML

Для управления гостями UML

LXC

Для контейнерами Linux

VBOX

Для управления гостями VirtualBox

OpenVZ

Для управления контейнерами OpenVZ

ESX

Для управления гостями VMware ESX

ONE

Для управления гостями OpenNebula

PHYP

Для управления гостями гипревизора Power

Листинг 3-5 показывает как подключаться к некому локальному гипервизору QEMU с применением локального URI.

 

Листинг 3-5. Подключение к локальному гипервизору QEMU


# 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)

conn.close()
exit(0)
 	   

Удалённые URI

Удалённые URI имеют общую форму, показанную здесь ([...] обозначает необязательную часть):


driver[+transport]://[username@][hostname][:port]/[path][?extraparameters]
 	   

Все компоненты данного URI поясняются в Таблице 3-2.

Таблица 3-2. Компоненты URI
Компонент Описание

driver

Само название того драйвера гипервизора libvirt, к которому выполняется подключение. Оно в точности то же самое, что применяется и в локальном URI. Некими примерами выступают xen, qemu, lxc, openvz и test. В качестве особого случая может применяться псевдо драйвер remote, который вызовет проверку активности гипервизора удалённого демона и укажет на его использование. В качестве общего правила, если ваше приложение знает что ему нужно, оно всегда должно определять такое название драйвера в явном виде и не полагаться на автоматическую проверку. Предоставление автоматической проверки может вызывать то, что система выберет неверный гипервизор для необходимого вам домена.

transport

Название одного из описанных ранее в этом разделе видов доставки данных. Возможными значениями могут быть tls, tcp, unix, ssh и ext. Если оно опущено, тогда в случае когда определено имя хоста значением по умолчанию является tls, или когда нет никакого имени хоста, unix.

username

Когда для транспортировки данных применяется SSH, данный компонент делает возможным выбор имени пользователя, который отличается от имени текущего зарегистрированного пользователя.

hostname

Полностью определённое имя хоста данной удалённой машины. Когда применяются TLS с сертификатами x509 или SASL с подключаемыми модулями GSSAPI/ Keberos, критически важно чтобы это имя хоста соответствовало имени хоста, используемого в соответствующем сертификате x509 сервера/ правиле Kerberos. Отсутствие такого соответствия с гарантией приведёт к отказу в аутентификации.

port

Редко требуется, только если SSH или libvirtd не были настроены для работы с нестандартным портом TCP. Значением по умолчанию является 22 для транспорта данных SSH, 16509 для транспорта данных TCP и 16514 для транспорта данных TLS.

path

Значением пути должен быть тот же самый путь, который используется для самого локального URI драйвера гипервизора. Для Xen это всегда /, в то время как для QEMU это может быть /system.

extraparameters

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

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

  • Подключение к некому удалённому гипервизору Xen в хосте node.example.com с применением транспортировки данных через SSH туннель и имени пользователя SSH root:

    
    xen+ssh://root@node.example.com/
     	   
  • Подключение к некому удалённому гипервизору QEMU в хосте node.example.com с применением TLS с сертификатами x509:

    
    qemu://node.example.com/system
     	   
  • Подключение к некому удалённому гипервизору Xen в хосте node.example.com с применением TLS с сертификатами x509 (Обратите внимание: здесь вы допускаете компромисс со своей безопасностью):

    
    xen://node.example.com/?no_verify=1
     	   
  • Подключение к некому локальному экземпляру QEMU поверх нестандартного сокета Unix (в этом случае в явном виде поддерживается полный путь к такому сокету Unix):

    
    qemu+unix:///system?socket=/opt/libvirt/run/libvirt/libvirt-sock
     	   
  • Подключение к некому демону libvirtd, предлагающему незашифрованное соединение TCP/IP по некому альтернативному порту 5000 и применяющему тестовый драйвер с какой- то конфигурацией по умолчанию:

    
    test+tcp://node.example.com:5000/default
     	   

Для удалённого URI могут добавляться дополнительные параметры как часть строки запроса (та часть, которая следует за ?). Удалённые URI распозгают те дополнительные параметры, которые показаны в Таблице 3-3. Всё прочее передаётся без изменений самому получателю. Отметим, что значения параметров обязаны быть URI- экранированными. Для получения дополнительных сведений обратитесь к http://xmlsoft.org/html/libxml-uri.html%2523xmlURIEscapeStr.

Таблица 3-3. Компоненты URI
Название Транспорт Описание

name

любой транспорт

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


name=qemu:///system
 	   

command

ssh, ext

Значение внешней команды. Для транспорта ext оно обязательно. Для SSH значением по умолчанию является ssh. Для поиска данной команды применяется переменная среды PATH. Пример:


command=/opt/openssh/bin/ssh
 	   

socket

unix, ssh

Значение внешней команды. Для транспорта ext оно обязательно. Для SSH значением по умолчанию является ssh. Для поиска данной команды применяется переменная среды PATH. Пример:


socket=/opt/libvirt/run/libvirt/libvirt-sock
 	   

netcat

ssh

Значение команды Netcat в соответствующей удалённой машине. Хначением по умолчанию является nc. Для транспорта ssh libvirt строит некую команду ssh, которая выглядит как- то так:


command -p port [-l username] hostname netcat -U socket
 	   

где port, username и hostname могут быть заданы как часть самого удалённого URI, а command, netcat и socket поступают из дополнительных параметров (либо разумными значениями по умолчанию). Пример:


netcat=/opt/netcat/bin/nc
 	   

no_verify

tls

Клиенты проверяют что сертификат сервера отключён, когда установлено не нулевое значение. Отметим, что для отклбчения проверок сервером сертификатов клиента или IP адресов вам требуется изменить значения настроек libvirtd. Пример:


no_verify=1
 	   

no_tty

ssh

Если установлено не нулевое значение, это предотвращает запросы SSH на ввод пароля когда нет возможности зарегистрироваться автоматически в этой удалённой машине (например, при использовании агента SSH). Применяйте когда у вас нет доступа к терминалу, например в программах с графическим интерфейсом, которые применяют libvirt. Пример:


no_tty=1
 	   

Листинг 3-6 показывает как подключаться к некому гипервизору QEMU с применением удалённого URI.

 

Листинг 3-6. Подключение к удалённому гипервизору QEMU


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

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

conn.close()
exit(0)
 	   

Методы сведений о возможностях

Для получения информации относительно возможностей определённого хоста можно применять метод getCapabilities. В случае успеха он возвращает некую строку Python, которая содержит XML значение возможностей (описываемых нами через мгновение). В случае возникновения ошибки будет возвращено None. Листинг 3-7 демонстрирует применение такого метода getCapabilities.

 

Листинг 3-7. Применение getCapabilities


# Example-7.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)

caps = conn.getCapabilities() # caps will be a string of XML
print('Capabilities:\n'+caps)

conn.close()
exit(0)
 	   

Имеющийся формат возможностей XML предоставляет сведения относительно присутствующей технологии виртуализации. В частности, он описывает сами возможности данного хоста виртуализации, его драйвера виртуализации, а также те виды гостей, которые данная технология виртуализации способна запускать. Отметим, что сами возможности XML могут различаться (и на самом деле разнятся) на основе применяемого драйвера libvirt. Листинг 3-8 представляет некий образец полученных возможностей в XML.

 

Листинг 3-8. Пример возможностей драйвера QEMU


<capabilities>
 <host>
   <cpu>
     <arch>x86_64</arch>
   </cpu>
   <migration_features>
     <live/>
     <uri_transports>
       <uri_transport>tcp</uri_transport>
     </uri_transports>
   </migration_features>
   <topology>
     <cells num="1">
       <cell id="0">
         <cpus num="2">
           <cpu id="0"/>
           <cpu id="1"/>
         </cpus>
       </cell>
     </cells>
   </topology>
 </host>
 <guest>
   <os_type>hvm</os_type>
   <arch name="i686">
     <wordsize>32</wordsize>
     <emulator>/usr/bin/qemu</emulator>
     <machine>pc</machine>
     <machine>isapc</machine>
     <domain type="qemu">
     </domain>
     <domain type="kvm">
       <emulator>/usr/bin/qemu-kvm</emulator>
     </domain>
   </arch>
   <features>
     <pae/>
     <nonpae/>
     <acpi default="on" toggle="yes"/>
     <apic default="on" toggle="no"/>
   </features>
 </guest>
 <guest>
   <os_type>hvm</os_type>
   <arch name="x86_64">
     <wordsize>64</wordsize>
     <emulator>/usr/bin/qemu-system-x86_64</emulator>
     <machine>pc</machine>
     <machine>isapc</machine>
     <domain type="qemu">
     </domain>
     <domain type="kvm">
       <emulator>/usr/bin/qemu-kvm</emulator>
     </domain>
   </arch>
   <features>
     <acpi default="on" toggle="yes"/>
     <apic default="on" toggle="no"/>
   </features>
 </guest>
</capabilities>
 	   
[Совет]Совет

Остальная часть обсуждения будет посвящена такому XML с применением нотации Xpath. В представляемых XML возможностях всегда имеется подчинённый документ /host и ноль или более подчинённых документов /guest (хотя ноль подчинённых документов гостей и допускается, это означает, что в данном рассматриваемом драйвере нет возможности запускать гостей в таком конкретном хосте).

Подчинённый документ <host> описывает возможности самого хоста.

<host><uuid> отображает значение UUID данного хоста. Оно проистекает из значения UUID SMDIOS если таковой доступен и допустим, либо может быть переопределено в libvirtd.conf неким персональным значением. Когда не установлено ни одно из этих свойств, при каждом перезапуске libvirtd будет вырабатываться временный UUID.

Подчинённый документ <host><cpu> описывает все возможности ЦПУ данного хоста. Он применяется libvirt при принятии решения может ли надлежащим образом быть запущен некий гость в данной конкретной машине, а также для консультаций при миграции в реальном масштабе времени для определения того будет ли машина назначения поддерживать все необходимые флаги для запуска такого гостя.

<host><cpu><arch> является необходимым узлом XML, который описывает всю лежащую в основе архитектуру ЦПУ. На момент написания все драйверы libvirt инициализируют из получаемого вывода uname(2).

<host><cpu><features> является неким не обязательным подчинённым документом, который описывает дополнительные свойства расположенного в этом хосте ЦПУ. На момент написания используется лишь в драйвере xen для выдачи отчёта о наличии или отсутствии соответствующего флага svm или vmx, а также для получения отчёта о наличии или отсутствии флага pae.

<host><cpu><model> является необязательным элементом, который описывает ту модель, на который более всего походит ЦПУ данного хоста. Те модели ЦПУ, о которых известно в настоящее время libvirt имеются в файле cpu_map.xml.

<host><cpu><feature> состоит из нуля или более элементов, который описывает дополнительные свойства ЦПУ имеющегося в этом хосте ЦПУ, которые не содержатся в /host/cpu/model.

<host><migration_features> является необязательным подчинённым документом, который описывает те свойства миграции, которые этот драйвер поддерживает в данном хосте (если они имеются). Когда данный подчинённый документ не существует, миграция не поддерживается. На момент написания миграцию поддерживали драйверы XEN, QEMU и ESX.

Данный узел XML <host><migration_features><live> существует если этот драйвер поддерживает миграцию в реальном масштабе времени.

<host><migration_features><uri_transports> является некий необязательный подчинённый документ, который описывает альтернативные механизмы соединения миграции. Такие альтернативные механизмы соединения могут быть полезны в системах виртуализации с несколькими сетевыми контроллерами (групповых, multihomed). Например, команда virsh migrate может быть подключена к своему источнику миграции через 10.0.0.1 и к получателю через 10.0.0.2. Однако из- за политики безопасности, нашему источнику данной миграции может быть позволено только для непосредственного общения с получателями этой миграции через 192.168.0.0/24. В этом случае применение такого альтернативного механизма подключения успешно допустило бы подобную миграцию. На момент написания драйвер xen поддерживает свой альтернативный механизм миграции xenmigr, в то время как драйвер qemu поддерживает свой альтернативный механизм миграции tcp. За дополнительными сведениями относительно миграции обращайтесь к соответствующей документации.

Подчинённый документ <host><topology> описывает присутствующую топологию NUMA данной машины хостинга; каждый узел NUMA представлен <host><topology><cells><cell> и описывает какие ЦПУ находятся в этом узле NUMA. Если данная машина хостинга является машиной UMA (не- NUMA), тогда будет иметься лишь одна ячейка, а все ЦПУ будут помещены в эту ячейку. Это слишком специфично для оборудования, а потому будет разниться для различных машин.

<host><secmodel> является необязательным подчинённым документом, который определяет значение используемой в данном хосте модели безопасности. <host><secmodel><model> отображает значение названия данной модели безопасности, в то время как <host><secmodel>https://doi.org/10.1007/978-1-4842-4862-1_3 отображает значение интерпретации. За дополнительными сведениями относительно безопасности обращайтесь к Главе 14.

Всякий подчинённый документ <guest> описывает некий вид гостя, который способен запускать этот драйвер хоста. Данное описание содержит значение архитектуры такого гостя (например, i686) помимо предоставляемого этому гостю ABI (например, HVM, XEN или UML), как это представлено в Таблице 3-4.

<guest><os_type> является обязательным элементом, который задаёт значение типа гостя.

Таблица 3-4. Типы гостя
Драйвер Тип гостя

qemu

Всегда qemu

xen

Либо xen для некого гостя с паравиртуализацией, либо hvm для полностью виртуального гостя

uml

Всегда uml

lxc

Всегда exe

vbox

Всегда hvm

openvz

Всегда exe

one

Всегда hvm

ex

В настоящее время не поддерживается

<guest><arch> выступает корнем некого подчинённого документа, определяющего различные стороны виртуального оборудования для данного типа гостя. Он имеет единственный атрибут с названием name, который может применяться для ссылки на данный подчинённый документ.

<guest><arch><wordsize> является необходимым элементом, определяющим сколько бит применяется в машинном слове данного гостя. Обычно это 32 или 64.

<guest><arch><emulator> является необчзательным элементом, который задаёт значение пути по умолчанию для эмулятора данного типа гостя. Обратите внимание, что этот эмулятор может перекрываться значением элемента <guest><arch><domain><emulator> для типов гостей, которым требуются альтернативные исполняемые файлы.

<guest><arch><loader> является необязательным элементом, который описывает значение пути по умолчанию необходимого для данного типа гостя загрусчика встроенного программного обеспечения (firmware). Обратите внимание, что этот загрузчик может перекрываться значением элемента <guest><arch><domain><loader> для типов гостей, которые используют альтернативные загрузчики. В настоящее время применяется драйвером XEN для гостей HVM.

Может присутствовать ноль или более элементов <guest><arch><machine>, которые определяют значения типов по умолчанию тех машин, которые способен эмулировать данный эмулятор гостя. Такие "машины" обычно представляют свой ABI или интерфейс оборудования, с которого способен запускаться некий гость. Обратите внимание, что этот тип машины может перекрываться значениями элементов <guest><arch><domain><machine> для тех технологий виртуализации, которые предоставляют альтернативные типы машин. Обычными значениями для него являются pc и isapc, что означает, соответственно, обычный PC на основе PCI или более ранний PC на основе ISA.

Может иметься ноль или более поддеревьев XML <guest><arch><domain> (хотя при нуле поддеревьев XML <guest><arch><domain> из этого драйвера не могут быть запущены никакие гости). Каждое поддерево /guest/arch/domain имеет необязательные элементы <emulator>, <loader> и <machine>, которые перекрывают соответствующие определённые ранее значения по умолчанию. Для всех данных опускаемых элементов применяются установленные по умолчанию значения.

Необязательный подчинённый документ <guest><machine> определяет различные дополнительные свойства гостя, которые могут быть включены или отключены, совместно с их значением состояния по умолчанию и тем, могут ли они переключаться во включённое или отключённое состояние.

Информация хоста

Для получения информации о хосте виртуализации, включая само имя хоста, максимально поддерживаемое число гостевых ЦПУ и т.п. могут применяться различные методы virConnection Python.

getHostname

Метод gethostname может использоваться для получения самого имени хоста данного хоста виртуализации, возвращаемое gethostname(). Он вызывается через экземпляр virConnection и, в случае успеха, возвращает некую строку, содержащую название хоста, возможно расширенное до полностью определённого доменного имени. Если произошла ошибка, вместо этого будет возвращено None. Будет обоснованным для самого вызывающего освободить ту память, которая возвращена данным вызовом метода. Листинг 3-9 демонстрирует применение gethostname.

 

Листинг 3-9. Применение getHostname


# Example-9.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)

host = conn.getHostname()

print('Hostname:'+host)

conn.close()
exit(0)
 	   

getMaxVcpus

Для получения значения максимального числа виртуальных ЦПУ для каждого гостя, которое поддерживается лежащей в основе технологией виртуализации, может применяться метод getMaxVcpus. Он получает некий "тип" виртуализации в качестве входного параметра (которым может быть None) и, в случае успеха возвращать значение числа поддерживаемых виртуальных ЦПУ. Если произошла ошибка, вместо этого будет возвращено -1. Листинг 3-10 демонстрирует применение getMaxVcpus.

 

Листинг 3-10. Применение getMaxVcpus


# Example-10.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)

vcpus = conn.getMaxVcpus(None)

print('Maximum support virtual CPUs: '+str(vcpus))

conn.close()
exit(0)
 	   

getInfo

Метод getInfo может быть применён для получения различной информации относительно определённого хоста виртуализации. Этот метод возвращает в случае успеха list Python и None в том случае, когда произошла ошибка. Таблица 3-5 перечисляет участников данного list Python.

Таблица 3-5. Структура участников virNodeInfo
Участник Описание

list[0]

Указывающая значение модели ЦПУ строка

list[1]

Размер памяти в MiB

list[2]

Число активных ЦПУ

list[3]

Ожидаемая частота ЦПУ (МГц)

list[4]

Число узлов NUMA, для единообразного доступа к памяти 1. Неоднородный доступ к памяти (NUMA, nonuniform memory access) это метод настройки некого кластера микропроцессоров в системе со множеством процессоров с тем, чтобы они имели возможность разделять память локально.

list[5]

Число разъёмов (сокетов) ЦПУ на узел

list[6]

Число ядер на сокет

list[7]

Число потоков на ядро

Листинг 3-11 демонстрирует применение getInfo.

 

Листинг 3-11. Применение getInfo


# Example-12.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)

nodeinfo = conn.getInfo()

print('Model: '+str(nodeinfo[0]))
print('Memory size: '+str(nodeinfo[1])+'MB')
print('Number of CPUs: '+str(nodeinfo[2]))
print('MHz of CPUs: '+str(nodeinfo[3]))
print('Number of NUMA nodes: '+str(nodeinfo[4]))
print('Number of CPU sockets: '+str(nodeinfo[5]))
print('Number of CPU cores per socket: '+str(nodeinfo[6]))
print('Number of CPU threads per core: '+str(nodeinfo[7]))

conn.close()
exit(0)
 	   

getCellsFreeMemory

Для получения объёма свободной памяти (в байтах) в каком- то или во всех узлах NUMA данной системы можно воспользоваться методом getCellsFreeMemory. Он получает в качестве параметра на входе значение начальной ячейки и максимальное число ячеек для получения данных от них. В случае успеха будет возвращён некий list Python со значениями объёма свободной памяти для каждого узла. В случае неудачи возвращается None. Листинг 3-12 демонстрирует применение getCellsFreeMemory.

 

Листинг 3-12. Применение getCellsFreeMemory


# Example-13.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)

nodeinfo = conn.getInfo()
numnodes = nodeinfo[4]
memlist = conn.getCellsFreeMemory(0, numnodes)
cell = 0

for cellfreemem in memlist:
    print('Node '+str(cell)+': '+str(cellfreemem)+' bytes free memory')
    cell += 1

conn.close()
exit(0)
 	   

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


Node 0: 13226958848 bytes free memory
 	   

getType

Метод getType можно применять для получения типа виртуализации, рименяемой при данном подключении. В случае успеха он возврвщает некую строку, предоставляющую значение типа применяемой виртуализации. В случае возникновения ошибки вместо этого будет возвращено None. Листинг 3-13 демонстрирует применение getType.

 

Листинг 3-13. Применение getType


# Example-13.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('Virtualization type: '+conn.getType())

conn.close()
exit(0)
 	   

getVersion

Если не передаётся никакой параметр name (либо значением name выступает None), тогда возвращается в виде целого номер версии применяемой библиотеки libvirt. Если же getVersion передаётся и оно ссылается на некий подключённый к данной библиотеке libvirt драйвер, тогда этот метод возвратит некий кортеж (library version, driver version). Значением возвращаемого названия яляется только само название драйвера; например, как KVM, так и QEMU гости обслуживаются одним драйвером для qemu:// URI, а потому возврат QEMUmerely не указывает на то присутствует ли ускорение KVM (Листинг 3-14).

Если же переданное имя указывает на несуществующий драйвер, тогда будет получена исключительная ситуация "no support for hypervisor" (нет поддержки гипервизора). Номера версии являются целыми, а именно: 1000000*основная + 1000*вспомогательная + выпуск.

 

Листинг 3-14. Применение virConnectGetVersion


Example-14.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)

ver = conn.getVersion()

print('Version: '+str(ver))

conn.close()
exit(0)
 	   

getLibVersion

Метод getLibVersion может использоваться для получения значения версии того программного обеспечения libvirt, которое применяется в данном хосте. В случае успеха он возвращает строку Python с данной версией; в противном случае он возвращает None. Когда возвращается номер версии, он имеет формат 1000000*версия Листинг 3-15 демонстрирует применение getLibVersion.

 

Листинг 3-15. Применение getLibVersion


# Example-15.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)

ver = conn.getLibVersion();

print('Libvirt Version: '+str(ver));

conn.close()
exit(0)
 	   

getURI

Для получения значения URI текущего соединения можно воспользоваться методом getURI. Хотя обычно это та же самая строка, которая передаётся в вызов open, лежащий в основе драйвер может иногда приводить эту строку к каноническому виду. Такой метод выполнит возврат строки в канонической версии. В случае успеха он возвращает строку URI. При возникновении ошибки вместо этого будет возвращаться None. Листинг 3-16 демонстрирует применение getURI.

 

Листинг 3-16. Применение getURI


# Example-16.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)

uri = conn.getURI()

print('Canonical URI: '+uri)

conn.close()
exit(0)
 	   

isEncrypted

Для получения того шифруется ли данное соединение, можно применить метод isEncrypted. В члучае успеха он возвращает 1 для шифруемого метода и 0 для соединения без шифрации. В случае возникновения ошибки будет возвращаться -1. Листинг 3-17 демонстрирует применение isEncrypted.

 

Листинг 3-17. Применение isEncrypted


# Example-17.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('Connection is encrypted: '+str(conn.isEncrypted()))

conn.close()
exit(0)
 	   

isSecure

Метод isSecure может применяться для вывода того будет ли шифроваться данное подключение. Некое соединение будет классифицировано как безопасное либо когда оно шифруется, либо запускается в канале, которое не является уязвимым для подслущивания (как сокет домена UNIX). В случае успеха будет возвращаться 1 для безопасного подклбчения и 0 для ненадёжного соединения. В случае ошибки будет возвращаться -1. Листинг 3-18 демонстрирует применение isSecure.

 

Листинг 3-18. Применение isSecure


# Example-18.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('Connection is secure: '+str(conn.isSecure()))

conn.close()
exit(0)
 	   

isAlive

Данный метод применяется дл определения того является ли данное подключение к имеющемуся гипервизору всё ещё действующим. Некое соединение будет классифицировано как действующее (alive) если он локальное, либо запкущено в канале (TCP или сокет UNIX), который не закрыт (Листинг 3-19).

 

Листинг 3-19. Применение isAlive


# Example-19.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)

alive = conn.isAlive()

print("Connection is alive = " + str(alive))
conn.close()
exit(0)
 	   

compareCPU

Данный метод сравнивает заданное описание ЦПУ со значением ЦПУ хоста. Такое описание XML является тем же самым, что и применяемое для задания домена значение описания XML (Листинг 3-20).

 

Листинг 3-20. Применение compareCPU


# Example-20.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)

xml = '<cpu mode="custom" match="exact">' + \
        '<model fallback="forbid">kvm64</model>' + \
      '</cpu>'

retc = conn.compareCPU(xml)

if retc == libvirt.VIR_CPU_COMPARE_ERROR:
    print("CPUs are not the same or ther was error.")
elif retc == libvirt.VIR_CPU_COMPARE_INCOMPATIBLE:
    print("CPUs are incompatible.")
elif retc == libvirt.VIR_CPU_COMPARE_IDENTICAL:
    print("CPUs are identical.")
elif retc == libvirt.VIR_CPU_COMPARE_SUPERSET:
    print("The host CPU is better than the one specified.")
else:
    print("An Unknown return code was emitted.")

conn.close()
exit(0)
 	   

getFreeMemory

Данный метод запрашивает объём свободной памяти (Листинг 3-21). Обратите внимание, что большинство API libvirt предоставляет размер свобоной памяти в байтах, и данная функция возвращает значение в байтах.

 

Листинг 3-21. Применение getFreeMemory


# Example-21.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)

mem = conn.getFreeMemory()

print("Free memory on the node (host) is " + str(mem) + " bytes.")

conn.close()
exit(0)
 	   

getFreePages

Данный метод запрашивает у своей системы хостинга свободные страницы с предписанным размером. На входе значением параметра pages выступает некий list Python размеров страниц, в которых заинтересован вызывающий (размер элемента в килобайтах, поэтому, к примеру, для 2MiB передаётся 2048), значение параметра start ссылается на самый первый узел NUMA, с которого следует собирать сведения, а значение пераметра cellcount сообщает сколько последовательных узлов следует опросить. Данная функция возвращает list Python, содержащий указатель на то будут ли доступны страницы определяемого на входе размера. В случае когда система хоста не поддерживает страницы памяти запрошенных размеров, будет отброшена некая ошибка (Листинг 3-22).

 

Листинг 3-22. Применение getFreePages


# Example-22.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)

pages = [2048]
start = 0
cellcount = 4
buf = conn.getFreePages(pages, start, cellcount)

i = 0
for page in buf:
    print("Page Size: " + str(pages[i]) + \
          " Available pages: " + str(page))
    ++i

conn.close()
exit(0)
 	   

Ниже приводится вывод примера Листинга 3-22.


Page Size: 2048 Available pages: 0
 	   

getMemoryParameters

Этот метод в виде строки возвращает все имеющиеся доступными параметры памяти (Листинг 3-23).

 

Листинг 3-23. Применение getMemoryParameters


# Example-23.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)

buf = conn.getMemoryParameters()

print('shm_pages_shared       : ' + str(buf['shm_pages_shared']))
print('shm_full_scans         : ' + str(buf['shm_full_scans']))
print('shm_merge_across_nodes : ' + str(buf['shm_merge_across_nodes']))
print('shm_pages_to_scan      : ' + str(buf['shm_pages_to_scan']))
print('shm_pages_unshared     : ' + str(buf['shm_pages_unshared']))
print('shm_sleep_millisecs    : ' + str(buf['shm_sleep_millisecs']))
print('shm_pages_sharing      : ' + str(buf['shm_pages_sharing']))
print('shm_pages_volatile     : ' + str(buf['shm_pages_volatile']))

conn.close()
exit(0)
 	   

getMemoryStats

Данный метод возвращает статистические данные памяти для отдельного узла (хоста). Он возвращает некий list строк Python (Листинг 3-24).

 

Листинг 3-24. Применение getMemoryStats


# Example-24.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)

buf = conn.getMemoryStats(libvirt.VIR_NODE_MEMORY_STATS_ALL_CELLS)

print('cached : ' + str(buf['cached']))
print('total  : ' + str(buf['total']))
print('buffers: ' + str(buf['buffers']))
print('total  : ' + str(buf['total']))

conn.close()
exit(0)
 	   

getSecurityModel

В Листинге 3-25 этот метод возвращает значение модели безопасности (в виде некого list) применяемой в настоящее время (если она имеется).

 

Листинг 3-25. Применение getSecurityModel


# Example-25.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)

model = conn.getSecurityModel()

print(model[0] + " " + model[1])

conn.close()
exit(0)
 	   

Для большинства систем Дштгч x86_64 это будет SELinux. Для прочих архитектур это значение может быть иным.

getSysinfo

Данный метод возвращает всю информацию о системе в виде некого определения XML. Его формат тот же самый, что и для определения домена XML (Листинг 3-26).

 

Листинг 3-26. Применение getSysinfo


# Example-26.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)

xmlInfo = conn.getSysinfo()

print(xmlInfo)

conn.close()
exit(0)
 	   

getCPUMap

Данный метод применяется для получения карты ЦПУ процессоров узда хостинга (Листинг 3-27).

 

Листинг 3-27. Применение getCPUMap


# Example-27.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)

map = conn.getCPUMap()

print("CPUs: " + str(map[0]))
print("Available: " + str(map[1]))

conn.close()
exit(0)
 	   

getCPUStats

Данный метод применяется для получения статистических сведений для одного или всех ЦПУ. Этот метод требует некого отдельного параметра, который представляет номер опрашиваемого на статистику ЦПУ для отдельного ЦПУ либо значение VIR_NODE_CPU_STATS_ALL_CPUS для опроса списка Python статистических данных от всех ЦПУ (Листинг 3-28).

 

Листинг 3-28. Применение getCPUStats


# Example-28.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)

stats = conn.getCPUStats(0)

print("kernel: " + str(stats['kernel']))
print("idle:   " + str(stats['idle']))
print("user:   " + str(stats['user']))
print("iowait: " + str(stats['iowait']))

conn.close()
exit(0)
 	   

getCPUModelNames

Этот метод применяется для получения значения списка имён ЦПУ, которые соответствуют некому типу архитектуры (Листинг 3-29).

 

Листинг 3-29. Применение getCPUModelNames


# Example-29.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)

models = conn.getCPUModelNames('x86_64')

for model in models:
    print(model)

conn.close()
exit(0)
 	   

Выводы

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