Red Hat Enterprise Virtualization 3 (RHEV) comes with a great API that makes it easy to write Python scripts or Java programs for administrative tasks. The full documentation is available here : https://access.redhat.com/site/documentation/en-US/Red_Hat_Enterprise_Virtualization/3.3/html/Developer_Guide/index.html

A classical need is to automate the creation of virtual machine cold backups on an export domain. This can be easily done by using the Python API.

First you need to install the RHEV Software Development Kit :

$ yum install rhevm-sdk

You can now write a Python script using the ovirtsdk (RHEV SDK) :

#!/usr/bin/python

from ovirtsdk.api import API

Let’s declare a few constants :

RHEV_URL = "https://127.0.0.1"
RHEV_USERNAME = "admin@internal"
RHEV_PASSWORD = "ThePassword"

Then try to connect to RHEV :

api = API ( url=RHEV_URL,
username=RHEV_USERNAME,
password=RHEV_PASSWORD,
ca_file="/etc/pki/ovirt-engine/ca.pem")

print "Connected to %s successfully!" % api.get_product_info().name

We can display information about the virtual machine « vm1 » :

vm = api.vms.get(name="vm1")

print "VM name : %s" % (vm.name)

vm_status = vm.status.state
print "Status : %s" % (vm_status)

vm_cluster = api.clusters.get(id=vm.cluster.id)
print "Cluster : %s" % (vm_cluster.get_name())

vm_dc = api.datacenters.get(id=vm_cluster.data_center.id)
print "Datacenter : %s" % (vm_dc.get_name())

Another example, stop a virtual machine :

if api.vms.get(name="vm1").status.state != 'down':
api.vms.get(name="vm1").shutdown()
print 'Waiting for VM to reach Down status'
while api.vms.get(name="vm1").status.state != 'down':
sleep(1)
print 'OK'
else:
print "VM already down"

As you can see it’s really easy to get information about a virtual machine like the cluster, the datacenter, the state, etc.

Now let’s have a look at the virtual machine full backup scenario. A possible process could be to :

  • Collect the virtual machine name to backup
  • Connect to RHEV
  • Save the initial state of the virtual machine (up, down, etc.)
  • Ensure that the export domain is not mounted on any other RHEV datacenter
  • Mount the export domain of the virtual machine’s datacenter
  • Stop the virtual machine (if ‘up’)
  • Export the virtual machine to the export domain
  • Restore the initial state of the virtual machine (previously saved)
  • Unmount the export domain
  • Disconnect from RHEV

All of these operations can be done using the Python API.
You can find a full example script on our GitHub page https://github.com/clevernet/RHEV-scripts/blob/master/backup-vm.py or below :

#!/usr/bin/python
# -*- coding: utf-8 -*-

####
# This scripts performs a cold-backup of the argument-specified VM, to an export domain
# Usage : backup-vm.py
# You need to modify the RHEV_URL, RHEV_USERNAME, RHEV_PASSWORD and
# EXPORT_DOMAIN_NAME variables below before use
###

from ovirtsdk.api import API
from ovirtsdk.xml import params
from time import sleep, gmtime, strftime
import sys

RHEV_URL = "https://127.0.0.1"
RHEV_USERNAME = "admin@internal"
RHEV_PASSWORD = "mypassword"

EXPORT_DOMAIN_NAME = "My-export-domain-name"

try:

################################################################################ Check parameters
if len(sys.argv) < 2:
print "Usage : backup-vm.py "
exit(2)

################################################################################ Connection to RHEV
print strftime("%a, %d %b %Y %H:%M:%S", gmtime())+" : Connecting to RHEV"
api = API ( url=RHEV_URL,
username=RHEV_USERNAME,
password=RHEV_PASSWORD,
ca_file="/etc/pki/ovirt-engine/ca.pem")
print "Connected to %s successfully!" % api.get_product_info().name

################################################################################ Display information about the VM
print "\n"+strftime("%a, %d %b %Y %H:%M:%S", gmtime())+" : Gathering information about the virtual machine %s" % (sys.argv[1])
vm = api.vms.get(name=sys.argv[1])
print "VM name : %s" % (vm.name)
initial_status = vm.status.state
print "Status : %s" % (initial_status)
vm_cluster = api.clusters.get(id=vm.cluster.id)
print "Cluster : %s" % (vm_cluster.get_name())
vm_dc = api.datacenters.get(id=vm_cluster.data_center.id)
print "Datacenter : %s" % (vm_dc.get_name())

################################################################################ Check export domain availability
print "\n"+strftime("%a, %d %b %Y %H:%M:%S", gmtime())+" : Ensuring that the export domain %s is not already attached and activated on a datacenter" % (EXPORT_DOMAIN_NAME)
dc_list = api.datacenters.list()
for dc in dc_list:
dc_export_list = dc.storagedomains.list()
for dc_export in dc_export_list:
if dc_export.name == EXPORT_DOMAIN_NAME:
print "Datacenter %s, Export %s : KO" % (dc.get_name(), dc_export.name)
print "> Deactivating the export domain from the Datacenter %s" % (dc.get_name())
dc_export.deactivate()
print "> OK : Deactivated data storage domain '%s' to data center '%s' (Status:%s)." %(dc_export.get_name(), dc.get_name(), dc_export.get_status().get_state())
print "> Unattaching export domain from the Datacenter %s" % (dc.get_name())
dc_export.delete()
print "> OK : Detached data storage domain '%s' to data center '%s' (Status:%s)." %(dc_export.get_name(), dc.get_name(), dc_export.get_status().get_state())
else:
print "Datacenter %s, Export %s : OK" % (dc.get_name(), dc_export.name)

################################################################################ Activate export domain
print "\n"+strftime("%a, %d %b %Y %H:%M:%S", gmtime())+" : Activating export domain %s on the datacenter %s" % (EXPORT_DOMAIN_NAME, vm_dc.get_name())
sd_export = api.storagedomains.get(name=EXPORT_DOMAIN_NAME)
dc_export = vm_dc.storagedomains.add(sd_export)

################################################################################ Shutdown the VM
if api.vms.get(name=sys.argv[1]).status.state != 'down':
print '\n"+strftime("%a, %d %b %Y %H:%M:%S", gmtime())+" : Shutdown VM'
api.vms.get(name=sys.argv[1]).shutdown()
print 'Waiting for VM to reach Down status'
while api.vms.get(name=sys.argv[1]).status.state != 'down':
sys.stdout.write('.')
sleep(1)
print '\nOK'
else:
print "\n"+strftime("%a, %d %b %Y %H:%M:%S", gmtime())+" : VM already down"

################################################################################ Export the VM
print "\n"+strftime("%a, %d %b %Y %H:%M:%S", gmtime())+" : Export of the virtual machine"
api.vms.get(sys.argv[1]).export(params.Action(storage_domain=api.storagedomains.get(EXPORT_DOMAIN_NAME), exclusive=1, discard_snapshots=1))
print 'Waiting '
while api.vms.get(sys.argv[1]).status.state != 'down':
print "Export in progress : %s" %(api.vms.get(sys.argv[1]).status.state)
sleep(1)
print "\n"+strftime("%a, %d %b %Y %H:%M:%S", gmtime())+" OK"

################################################################################ Restart of the VM
if initial_status == 'up':
print "\n"+strftime("%a, %d %b %Y %H:%M:%S", gmtime())+" : Virtual machine was up before the backup. Restoring state to up."
if api.vms.get(name=sys.argv[1]).status.state != 'up':
print 'Starting VM'
api.vms.get(name=sys.argv[1]).start()
print 'Waiting for VM to reach Up status'
while api.vms.get(name=sys.argv[1]).status.state != 'up':
sleep(1)
sys.stdout.write('.')
print '\nOK'
else:
print 'VM is already up'
else:
print "\n"+strftime("%a, %d %b %Y %H:%M:%S", gmtime())+" : Virtual machine was down before the backup. Keeping it down."

################################################################################ Deactivation of the export domain
dc_export = vm_dc.storagedomains.get(name=EXPORT_DOMAIN_NAME)
print "\n"+strftime("%a, %d %b %Y %H:%M:%S", gmtime())+" : Deactivating the export domain"
dc_export.deactivate()
print "OK : Deactivated data storage domain '%s' to data center '%s' (Status:%s)." %(dc_export.get_name(), vm_dc.get_name(), dc_export.get_status().get_state())
print "\n"+strftime("%a, %d %b %Y %H:%M:%S", gmtime())+" : Unattaching export domain from the Datacenter %s" % (vm_dc.get_name())
dc_export.delete()
print "OK : Detached data storage domain '%s' to data center '%s' (Status:%s)." %(dc_export.get_name(), vm_dc.get_name(), dc_export.get_status().get_state())

################################################################################ End
api.disconnect()
print "\n"+strftime("%a, %d %b %Y %H:%M:%S", gmtime())+" : BACKUP OK"
exit(0)

except Exception as ex:
print "\n"+strftime("%a, %d %b %Y %H:%M:%S", gmtime())+" : Unexpected error: %s" % ex
exit(1)
6 réponses
  1. Jerome Steunenberg
    Jerome Steunenberg dit :

    Hello Manuel, to perform a hot backup, you need to create a snapshot and backup that snapshot. This is currently possible online but in order to merge back the snapshot, you need to turn the VM off.
    A hot backup solution is therefore not yet completely available in RHEV.

    Répondre
  2. tad
    tad dit :

    I recently upgraded to RHEV 3.5.1 and i believe the syntax for the RHEVM-SDK may have changed. Suddenly I am seeing errors on the RHEV gui when running the script that say

    « The Storage Domain does not contain any OVF_STORE disks. Usually the Storage Domain does not contain OVF_STORE disks when the Storage Domain has been previously managed with a Data Center version lower then 3.5 »

    When you run the script, the command line errors out with these last few lines:

    ———–snip———
    Wed, 17 Jun 2015 19:11:19 : VM already down

    Wed, 17 Jun 2015 19:11:19 : Export of the virtual machine

    Wed, 17 Jun 2015 19:11:19 : Unexpected error:
    status: 400
    reason: Bad Request
    detail: Value « 1 » isn’t a valid boolean, it should be « true » or « false »
    ——————–snip—————

    This makes me think that this line needs exclusive=true and discard_snapshots=true instead of « 1 »s:

    ################################################################################ Export the VM
    print « \n »+strftime(« %a, %d %b %Y %H:%M:%S », gmtime())+ » : Export of the virtual machine »
    api.vms.get(sys.argv[1]).export(params.Action(storage_domain=api.storagedomains.get(EXPORT_DOMAIN_NAME), exclusive=1, discard_snapshots=1))

    Any thoughts? Nervous to run this in production

    Répondre
  3. tad
    tad dit :

    Sorry to double-post, but I got bored and tried it, and it worked. The proper syntax of the offending line is:

    api.vms.get(sys.argv[1]).export(params.Action(storage_domain=api.storagedomains.get(EXPORT_DOMAIN_NAME), exclusive= »true », discard_snapshots= »true »))

    so you basically just replace the 1’s with true in quotes.

    Hope this helps any other visitors, great script, BTW!

    Répondre

Laisser un commentaire

Participez-vous à la discussion?
N'hésitez pas à contribuer!

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.