Recently I've been doing a fair amount of work with the libvirt API, specifically using the Node.js bindings found here. The bindings are great and work as expected but I was rather disappointed in the lack of documentation.
The authors reference the tests for the project as documentation, but this can be a bit of a pain to read through especially if you are new to the language. Given this, I'm going to start documenting some of the functions I use most often.
This post assumes you are using the latest version of node-libvirt (>=0.1.3). Please note this is important because earlier versions of this library were not asynchronous - code snippets in this post will not work for earlier versions.
Hypervisor
Before you can do anything else, you must communicate with the hypervisor its self.
Connection
Communication with the hypervisor can be achieved by instantiating a new hypervisor object:
var libvirt = require('libvirt');
var hypervisor_object = new libvirt.Hypervisor(CONNECT_URI);
Connect URI will vary depending on your specific hypervisor (KVM, Xen, etc.) and how you are connecting exactly. For KVM this would be qemu:///system
.
Next, you need to actually connect to the hypervisor:
hypervisor_object.connect(function(err) {
if (!err) {
console.log("I'm connected!");
}
});
Statistics
Most projects will want to know a bit about the hypervisor, you can gather all sorts of information but I have found the virNodeInfo
call the most useful. This provides you with the model of the CPU, memory allocated to the host, number of CPUs, speed of CPUs, nodes, sockets, cores and threads per core. This call is made using the hypervisor object:
hypervisor_object.getNodeInfo(function(err, info) {
console.log(info);
});
All remaining hypervisor functions are called in a similar fashion with a callback. Other stats functions of interest include:
listDefinedDomains
- Returns an array of defined, but not active domain IDslistActiveDomains
- Returns an array of active domain names.getNumberOfDefinedDomains
- Returns an integer representing the total number of defined but not active domains.getNumberOfActiveDomains
- Returns an integer representing the total number of active domains.getNodeFreeMemory
- Returns an integer representing the amount of free memory on the host.
From here you can use the hypervisor object to do other things.
Domains
Next, lets get to the meat of the library and discuss domain handling.
Create a Domain
Creating a domain is done using the hypervisor object we created before. You'll need to magic up some XML in the appropriate format to make this work. Once you have that being generated and accessible from Node you can use the following call to make a domain:
hypervisor_object.createDomain(domain_xml, function(err, domain) {
// Domain is created if no error
});
This will create a non-persistent domain which basically means if the domain is destroyed (completely stopped) it ceases to exist. This is okay if you have all the information you need to reconstruct the domain XML elsewhere (like in a database), if you don't you might want to look into using persistent domains. These can be created using the define
function instead of the createDomain
wrapper:
hypervisor_object.define(domain_xml, function(err, domain) {
// Persistent domain created
});
Actions
There are a number of actions available for a domain including:
reset
reboot
suspend
resume
shutdown
start
All of these are called the same way using the domain
object. You can get the domain object by accessing domain
in the create domain example or you can look a domain up using lookupDomainById
or lookupDomainByName
, both are covered later.
domain.ACTION(function(err) {
// If no error action successful
});
Substitute an action from the list above for ACTION
.
Get
Getting a domain can be done using either lookupDomainById
or lookupDomainByName
. Realistically, unless you have a unique application lookupDomainByName
will be better used because the domain ID is not static and there is no reliable way of predicting it, the name however is static and should be unique.
hypervisor_object.lookupDomainByName(DOMAIN_NAME_HERE, function(err, domain) {
// You've got your domain!
});
Should you need to look up the domain by ID you call that function the same way as shown above.
Destroy
Some people get confused by the nomenclature used by libvirt regarding destroying a domain. In the context of libvirt, destroy does not mean delete in the traditional sense, it essentially means stop the domain now (force it to stop if it cannot be stopped otherwise). This is like pulling the plug on the machine so data loss is a possibility. There is an exception however, if the domain is not persistent destroy will actually remove the domain from libvirt. This is done like the other actions mentioned above:
domain.destroy(function(err) {
// I'm stopped!
});
If you have yourself a persistent domain and you want to actually make libvirt forget about it completely you would need to use the undefine
function:
domain.undefine(function(err) {
// Poof, I'm gone!
});
Would you like to know more?
I originally started writing this guide with the intention of documenting all the things, but in truth it would be a waste of time. All calls are made using the same basic format:
the_object.WHAT_I_WANT(function(err, RESPONSE_IF_THERE_IS_ONE) {
});
If you find anything particularly challenging regarding hypervisor or domain functions please let me know - I'm happy to help!
While a bit annoying, the tests for node-libvirt are useful if you want to see the context of these calls. You can find the tests for domains here and hypervisors here.
If there is any interest I'd be happy to continue covering the basic calls for other libvirt areas - please let me know if you are interested in that at all.
Thanks for reading!