Script KVM com Python, Parte 1: libvirt

Esta série de duas partes explora como usar Python para criar scripts para gerenciar máquinas virtuais usando KVM. Nesta parte, saiba os fundamentos de usar libvirt e as ligações Python para desenvolveralgumas ferramentas de exibição e status simples.

Paul Ferrill, CTO, ATAC

Paul Ferrill escreve nos meios de comunicação de comércio de computadores há mais de 20 anos. Começou escrevendo revisões de rede para o PC Magazine sobre produtos como LANtastic e versões anteriores do Novell Netware. Paul é graduado e possui mestrado em engenharia elétrica e escreveu softwares para mais arquiteturas e plataformas de computador do que consegue se lembrar.



16/Jan/2012

A virtualização é um equipamento padrão com a maioria dos servidores no mercado hoje. No mundo do Linux® há duas opções principais para virtualização de servidor: Kernel-based Virtual Machine (KVM) e Xen. KVM é a principal tecnologia que Red Hat e outros usam. Embora a Citrix possua Xen, muito da funcionalidade central permanece no domínio público.

O projeto de Virtual Machine Manager (VMM, ou virt-manager) fornece uma ferramenta para gerenciar a criação e a execução de instâncias de KVM e virtual machine (VM) Xen. VMM é escrita em Python usando a biblioteca GTK+ para o desenvolvimento da interface gráfica com o usuário. O trabalho real é feito através da biblioteca libvirt , que é o que você usará para esta série de artigos. Embora libvirt seja um esforço patrocinado pela Red Hat, ela permanece um projeto de software livre disponível sob a Licença Pública Geral Menor GNU.

libvirt é composta de várias partes diferentes, incluindo a biblioteca da application programming interface (API), um daemon (libvirtd), e um utilitário de linha de comando padrão (virsh). Para os fins deste artigo, todo o teste é feito usando o Ubuntu Server versão 11.04. A seção Instalação e configuração aborda tudo o que foi feito para configurar o servidor para desenvolver os scripts apresentados aqui. A Parte 1 trata dos fundamentos de virtualização de libvirt e Kernel-based Virtual Machine (KVM), junto com alguns scripts de linha de comando para abrir seu apetite. A Parte 2 irá se aprofundar e mostrar como desenvolversuas próprias ferramentas de gerenciamento de virtualização usando libvirt, Python e wxPython.

Introdução

Antes de nos aprofundar nos exemplos de código reais, vamos passar por alguns termos e conceitos relacionados à virtualização com KVM. Quando você instala a KVM em um servidor como Ubuntu Server 11.04, está estabelecendo um host de virtualização ou um hypervisor. Isso significa que seu servidor poderá hospedar diversos sistemas operacionais convidados executando sobre o host KVM. Cada convidado único é chamado de domínio e funções de maneira muito semelhante ao que se poderia esperar de uma única instância de servidor em uma máquina individual. É possível conectar-se ao servidor sobre Secure Shell (SSH) ou Virtual Network Computing da mesma maneira que se estivesse se comunicando com uma máquina virtual.

Embora a KVM funcione como o hypervisor ou gerenciador de convidado, QEMU fornece a emulação de máquina real, o que significa que QEMU executa o conjunto de instruções nativo da máquina de destino. Para convidados de x86, essa execução se converte em instruções nativas capazes de execução direta no hardware subjacente. Para outras arquiteturas, como ARM, um processo de conversão deve ocorrer. A combinação de KVM e QEMU fornece todas as funções de suporte necessárias para virtualizar essencialmente todo o sistema operacional disponível no momento, mais alguns que não estão mais disponíveis.

Um domínio convidado consiste em vários arquivos, incluindo um ou mais arquivos de imagem de disco e um arquivo de configuração com base em XML. Essa configuração torna extremamente simples gerenciar múltiplas VMs criando uma imagem de sistema de linha de base e então modificando o arquivo de configuração para adequar-se às suas necessidades. Um método de configurar e comunicar-se com a KVM/QEMU é o kit de ferramentas libvirt . Diversos fornecedores padronizaram seus produtos de gerenciamento com base em libvirt.

Veja os conteúdos de um arquivo de configuração de domínio típico. A Listagem 1 mostra o arquivo testdev.xml dos exemplos de libvirt .

Listagem 1. Definição XML do dispositivo
<device>
   <name>File_test_device</name>
   <capability type='system'>
         <hardware>
               <vendor>Libvirt</vendor>
               <version>Test driver</version>
               <serial>123456</serial>
               <uuid>11111111-2222-3333-4444-555555555555</uuid>
         </hardware>
         <firmware>
               <vendor>Libvirt</vendor>
               <version>Test Driver</version>
               <release_date>01/22/2007</release_date>
         </firmware>
   </capability>
</device>

A partir do arquivo domfv0.xml de teste mostrado na Listagem 2, é possível ver um pouco mais de detalhes sobre a configuração de dispositivos virtuais.

Listagem 2. Arquivo de definição de dispositivo domfv0.xml
<devices>
  <emulator>/usr/lib/xen/bin/qemu-dm</emulator>
         <interface type='bridge'>
               <source bridge='xenbr0'/>
               <mac address='00:16:3e:5d:c7:9e'/>
               <script path='vif-bridge'/>
         </interface>
         <disk type='file'>
               <source file='/root/fv0'/>
               <target dev='hda'/>
         </disk>
         <disk type='file' device='cdrom'>
               <source file='/root/fc5-x86_64-boot.iso'/>
               <target dev='hdc'/>
               <readonly/>
         </disk>
         <disk type='file' device='floppy'>
               <source file='/root/fd.img'/>
               <target dev='fda'/>
         </disk>
         <graphics type='vnc' port='5904'/>
</devices>

O ponto principal aqui é a facilidade relativa com que é possível ler esses arquivos e então criar o seu próprio. Embora seja possível desenvolver qualquer número de arquivos de configuração manualmente, também é possível automatizar o desenvolvimento usando uma linguagem de script como Python.


Instalação e configuração

Porque esse artigo é sobre script KVM, há uma pressuposição básica de que você tem um servidor com o KVM instalado. No caso do Ubuntu Server 11.04, existe a opção de instalar virtualização durante o processo de configuração escolhendo a opção Virtual Machine Host na tela Software selection . Você também pode deseja escolher o servidor OpenSSH se desejar conectar-se remotamente à máquina.

A primeira ordem de negócios é instalar a última versão de libvirt. Para fazer isso, é necessário realizar algum trabalho de linha de comando. Ao instalar o Ubuntu Server 11.04, você obtém libvirt versão 0.8.8. A versão mais recente e melhor disponível a partir do website da libvirt é a 0.9.5. Para instalar uma versão posterior, é preciso adicionar um repositório Personal Package Archive (PPA) ao seu sistema contendo uma versão mais recente de libvirt. Uma procura rápida no site launchpad.net por libvirt mostra vários candidatos em potencial. É importante visualizar a página de detalhes do repositório antes de tentar realizar uma atualização, uma vez que alguns podem ter pacotes corrompidos. A Ubuntu Virtualization Team mantém um repositório de PPA com vários pacotes, incluindo libvirt. A última versão disponível no momento em que este artigo foi escrito era a 0.9.2-4.

Realize as seguintes etapas para instalar essa versão:

  1. Instale o pacote de python-software-propriedades como segue:
    sudo apt-get install python-software-properties

    Esse comando disponibiliza o comando add-apt-repository de que você precisa para fazer referência à origem de terceiros.

  2. Digite os seguintes comandos:
    sudo add-apt-repository ppa:ubuntu-virt/ppa
    sudo apt-get update
    sudo apt-get install libvirt-bin
  3. Porque você usará Python para realizar todo o script para este artigo, instale o shell IDLE para tornar mais fácil escrever e testar scripts.

    Esta etapa presume que você instalou o ambiente de desktop no seu servidor Ubuntu. A maneira mais rápida de instalar o desktop é usar o seguinte comando:

    sudo apt-get install ubuntu-desktop

Depois de ter feito isso, você terá acesso a qualquer número de aplicativos gráficos junto com o instalador do software Ubuntu. É possível usar o Ubuntu Software Center para instalar a ferramenta IDLE do Python.


Scripts de amostra

Neste ponto, vamos dar uma olhada em alguns dos fundamentos de trabalhar com libvirt antes de entrarmos em detalhes do código. A comunicação entre um aplicativo e a biblioteca libvirt usa um mecanismo de chamada de procedimento remoto simples, o que torna possível desenvolveraplicativos para comunicação com hypervisors remotos sobre uma conexão TCP/IP. Uniform Resource Identifiers (URIs, definidos pela Request for Comments [RFC] 2396 da Internet Engineering Task Force [IETF]) são usados para identificar um hypervisor específico com o qual você deseja estabelecer uma conexão.

Conexões locais normalmente não exigem autenticação, embora algumas conexões remotas exijam. O arquivo libvirt.conf controla a configuração de segurança. O controle mais amplo sobre a comunicação com um único domínio é através de filtragem de rede. Aqui está um exemplo de como é possível controlar o tráfego de rede usando um filtro.

<devices>
    <interface type='bridge'>
      <mac address='00:16:3e:5d:c7:9e'/>
      <filterref filter='clean-traffic'/>
    </interface>
</devices>

Esse fragmento define um filtro chamado clean-traffic que será aplicado a todo o tráfego de rede sobre o endereço de media access control (MAC) especificado. Se você examinar o XML clean-traffic , ele contém o seguinte:

<filter name='clean-traffic' chain='root'>
     <uuid>6f145c54-e3de-4c33-544a-70b69c16d9da</uuid>
     <filterref filter='no-mac-spoofing'/>
     <filterref filter='no-ip-spoofing'/>
     <filterref filter='allow-incoming-ipv4'/>
     <filterref filter='no-arp-spoofing'/>
     <filterref filter='no-other-l2-traffic'/>
     <filterref filter='qemu-announce-self'/>
</filter>

Os recursos de filtro são muito amplos e totalmente documentados. É necessário apenas um comando se você desejar uma cópia local da documentação libvirt e dos arquivos de amostra. Isto é o que você precisa fazer:

sudo apt-get install libvirt-doc

Com isso feito, toda a documentação está disponível no diretório /usr/share/doc/libvirt-doc. Você verá os exemplos do Python uma pouco mais adiante. Se você tiver atualizado para uma versão mais recente de libvirt, pode ser preciso instalar explicitamente as ligações do Python. Fazer isso exige um único comando:

sudo apt-get install python-libvirt

Use o console IDEL do Python para examinar o código do Python para estabelecer uma conexão com uma instância QEMU local, e então examinar os domínios definidos. A Listagem 3 mostra o que você deve ver usando essa abordagem.

Listagem 3. Visualizando o código Python no console IDLE
Python 2.7.1+ (r271:86832, Apr 11 2011, 18:13:53) 
[GCC 4.5.2] on linux2
Type "copyright", "credits" or "license()" for more information.
==== No Subprocess ====
>>> import libvirt
>>> conn=libvirt.open("qemu:///system")
>>> names = conn.listDefinedDomains()
>>> print names
['Test1', 'SBSLite', 'UbuntuServer1104', 'Win7_64-bit']]
>>>

Esse código mostra como obter uma lista de todos os domínios definidos. O retorno da função listDefinedDomains() mostra uma lista contendo quatro domínios de nome. Uma vez que você estabelece uma conexão com o hypervisor, terá acesso a uma lista de funções disponíveis. Aqui está um breve script mostrando como obter uma lista de todas as funções disponíveis no objeto conn :

clist = dir(conn)
for item in clist:
            print item

Para ver uma lista de filtros definidos, é possível usar uma abordagem similar:

filts = conn.listNWFilters()
for item in filts:
            print item

A ferramenta IDLE é uma ótima maneira de investigar as várias chamadas de API e rapidamente ver os resultados retornados quando executada. Algumas dessas funções operam apenas em domínios em execução. A função dir() retorna uma lista de atributos válidos para o objeto especificado. É uma ferramenta de linha de comando conveniente para ver rapidamente o que um objeto em particular fornece. É possível usá-la como mostrado acima para obter uma lista de funções disponíveis após estabelecer uma conexão com o hypervisor.

Para demonstrar, é possível usar algumas linhas do código Python no console IDLE para ter uma ideia dos tipos de operações que você pode realizar em um domínio específico. A Listagem 4 fornece um exemplo do que você pode fazer.

Listagem 4. Saída do Python de um objeto de domínio
>>> import libvirt
>>> import pprint
>>> conn=libvirt.open("qemu:///system")
>>> p = conn.lookupByName('ubuntu100403')
>>> pprint.pprint(dir(p))
['ID',
 'OSType',
 'UUID',
 'UUIDString',
 'XMLDesc',
 '__del__',
 '__doc__',
 '__init__',
 '__module__',
 '_conn',
 '_o',
 'abortJob',
 'attachDevice',
 'attachDeviceFlags',
 'autostart',
 'blkioParameters',
 'blockInfo',
 'blockPeek',
 'blockStats',
 'connect',
 'coreDump',
 'create',
 'createWithFlags',
 'destroy',
 'detachDevice',
 'detachDeviceFlags',
 'hasCurrentSnapshot',
 'hasManagedSaveImage',
 'info',
 'injectNMI',
 'interfaceStats',
 'isActive',
 'isPersistent',

É possível assumir essa abordagem básica para desenvolver um script simples que liste informações sobre todos os domínios em execução. Use as chamadas de função listDomainsID() e lookupByID() fazem a maior parte do trabalho, como a Listagem 5 mostra.

Listagem 5. Script de domínios da lista do Python
import libvirt
conn=libvirt.open("qemu:///system")

for id in conn.listDomainsID():
   dom = conn.lookupByID(id)
   infos = dom.info()
   print 'ID = %d' % id
   print 'Name =  %s' % dom.name()
   print 'State = %d' % infos[0]
   print 'Max Memory = %d' % infos[1]
   print 'Number of virt CPUs = %d' % infos[3]
   print 'CPU Time (in ns) = %d' % infos[2]
   print ' '

A saída desse script, com um domínio ativo e outro suspenso, se parece com isto:

ID = 3
Name =  ubuntu100403
State = 3
Max Memory = 1048576
Number of virt CPUs = 1
CPU Time (in ns) = 1048576

ID = 4
Name =  Win7_64-bit
State = 1
Max Memory = 2097152
Number of virt CPUs = 2
CPU Time (in ns) = 2097152

libvirt também implementa docstrings Python para todas as classes e métodos. É possível acessar essas informações digitando help(libvirt) para a ajuda de nível superior ou help(libvirt.class) para uma classe específica. Você precisa ter importado o módulo libvirt antes de digitar help() . A versão I testada para essa revisão implementa as 11 classes a seguir:

  • libvirtError
  • virConnect
  • virDomain
  • virDomainShapshot
  • virInterface
  • virNWFilter
  • virNetwork
  • virSecret
  • virStoragePool
  • virStorageVol
  • virStream

Essa lista deve ajudá-lo a descodificar a sintaxe para acessar as funções libvirt a partir do Python. Também fornece uma lista de todas as constantes nomeadas, como VIR_DOMAIN_RUNNING, que é igual a 1. Funções como dom.info(), usada acima, retornam um valor inteiro e precisam ser decodificadas com relação a esta tabela de constantes.


Scripts de utilitários para automação

Seria possível gravar qualquer número de scripts de utilitário para gerenciar uma instalação de KVM usando libvirt e Python. Pode não ser eficiente para um pequeno número de domínios, mas pode rapidamente economizar tempo quando a contagem chega a dígitos duplos. Uma tarefa simples seria fazer uma alteração em massa dos endereços IP estáticos para todas as imagens de domínio. É possível fazer isso iterando sobre todos os arquivos .conf e então fazendo as alterações adequadas. O Python tem muitos recursos integrados para ajudar com essa tarefa.

A Listagem 6 mostra um exemplo de uma definição de rede XML .

Listagem 6. Arquivo XML de configuração de rede
<network>
  <name>testnetwork</name>
  <bridge name="virbr1" />
  <forward/>
  <ip address="192.168.100.1" netmask="255.255.255.0">
    <dhcp>
      <range start="192.168.100.2" end="192.168.100.254" />
      <host mac='de:af:de:af:00:02' name='vm-1' ip='192.168.100.2' />
      <host mac='de:af:de:af:00:03' name='vm-2' ip='192.168.100.3' />
      <host mac='de:af:de:af:00:04' name='vm-3' ip='192.168.100.4' />
      <host mac='de:af:de:af:00:05' name='vm-4' ip='192.168.100.5' />
      <host mac='de:af:de:af:00:06' name='vm-5' ip='192.168.100.6' />
      <host mac='de:af:de:af:00:07' name='vm-6' ip='192.168.100.7' />
      <host mac='de:af:de:af:00:08' name='vm-7' ip='192.168.100.8' />
      <host mac='de:af:de:af:00:09' name='vm-8' ip='192.168.100.9' />
      <host mac='de:af:de:af:00:10' name='vm-9' ip='192.168.100.10' />
    </dhcp
  </ip>
</network>

Se você desejasse alterar a subrede principal de 192.168.100 para 192.168.200, poderia abrir o arquivo de configuração em um editor e fazer uma procura global e substituir. O complicado é quando você deseja fazer algo um pouco mais complexo, como adicionar 10 a todos os endereços IP e MAC começando com 2. A Figura 7 mostra como seria possível fazer isso com um pouco mais de 20 linhas de código Python.

Listagem 7. Script Python para alterar endereços IP e MAC
#!/usr/bin/env python

from xml.dom.minidom import parseString
import sys

def main():
    target = sys.argv[1]
    number = int(sys.argv[2])
    
    xml = open(target, 'r').read()
    doc = parseString(xml)
    for host in doc.getElementsByTagName('host'):
        ip = host.getAttribute('ip')
        parts = ip.split('.')
        parts[-1] = str(int(parts[-1]) + number)
        host.setAttribute('ip', '.'.join(parts))
        
        mac = host.getAttribute('mac')
        parts = mac.split(':')
        parts[-1] = str(int(parts[-1]) + number)
        host.setAttribute('mac', ':'.join(parts))
    
    f = open(target, 'w')
    f.write(doc.toxml())
    f.close()

if __name__ == '__main__':
    main()

Esse script demonstra o poder do Python quando se aproveita a Biblioteca Padrão do Python. Aqui, é usado parseString em xml.dom.minidom para fazer o trabalho pesado de analisar o arquivo XML. Depois de ter um atributo XML específico, você simplesmente divide-o em partes individuais usando a função string.split do Python. Então apenas calcule e coloque as sequências juntas de novo. É possível expandir essa abordagem para realizar alterações em massa a qualquer arquivo XML, incluindo os arquivos .conf para libvirt.

Outro script útil tomaria uma captura instantânea de todos os domínios em execução. Esse script precisaria primeiro obter uma lista de todos os domínios em execução, então pausar individualmente e criar uma captura instantânea de cada um. Embora essa operação possa não ser prática para um ambiente de produção, seria possível configurá-la para executar como uma tarefa CRON no meio da noite. Esse script seria fácil de implementar com os comandos destacados até o momento, junto com uma chamada para snapshotCreateXML().


Relaxando

Este artigo recém arranhou a superfície dos recursos contidos em libvirt. Consulte a seção Recursos para links para uma leitura mais aprofundada sobre libvirt e virtualização em geral. Entender os fundamentos de KVM é uma tarefa longa quando se começa a tentar implementar o código para monitorar e gerenciar o seu ambiente. A próxima parte desta série tomará a base estabelecida aqui e desenvolveráalgumas ferramentas de gerenciamento virtual do mundo real.

Recursos

Aprender

Obter produtos e tecnologias

  • Avalie produtos de software IBM: a partir de downloads de teste para produtos hospedados na nuvem, é possível inovar no seu próximo projeto de desenvolvimento de software livre usando software especialmente para desenvolvedores.

Discutir

Comentários

developerWorks: Conecte-se

Los campos obligatorios están marcados con un asterisco (*).


Precisa de um ID IBM?
Esqueceu seu ID IBM?


Esqueceu sua senha?
Alterar sua senha

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


A primeira vez que você entrar no developerWorks, um perfil é criado para você. Informações no seu perfil (seu nome, país / região, e nome da empresa) é apresentado ao público e vai acompanhar qualquer conteúdo que você postar, a menos que você opte por esconder o nome da empresa. Você pode atualizar sua conta IBM a qualquer momento.

Todas as informações enviadas são seguras.

Elija su nombre para mostrar



Ao se conectar ao developerWorks pela primeira vez, é criado um perfil para você e é necessário selecionar um nome de exibição. O nome de exibição acompanhará o conteúdo que você postar no developerWorks.

Escolha um nome de exibição de 3 - 31 caracteres. Seu nome de exibição deve ser exclusivo na comunidade do developerWorks e não deve ser o seu endereço de email por motivo de privacidade.

Los campos obligatorios están marcados con un asterisco (*).

(Escolha um nome de exibição de 3 - 31 caracteres.)

Ao clicar em Enviar, você concorda com os termos e condições do developerWorks.

 


Todas as informações enviadas são seguras.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=80
Zone=Linux, Software livre
ArticleID=784562
ArticleTitle=Script KVM com Python, Parte 1: libvirt
publish-date=01162012