Managing KVM with Libvirt In Java: Step by Step Tutorial

As mentioned earlier, I got the KVM instances running on my compute cluster after installing the Openstack. I’ve been curious on KVM management APIs, so I took some time to give it a try. In the following, I’ll detail on how to set up environment and get your first HelloWorld type of Java code working.

You don’t have to install Openstack to get KVM running just because I’ve got the KVM as a by-product of Openstack installation. You can install KVM standalone pretty easily. It’s much easier than Openstack to install. For that, I also include a few commands to install KVM as part of environment setup. Please feel free to skip that part if you’ve got your KVM installed.

Bothered by SLOW Web UI to manage vSphere? Want to manage ALL your VMware vCenters, AWS, Azure, Openstack, container behind a SINGLE pane of glass? Want to search, analyze, report, visualize VMs, hosts, networks, datastores, events as easily as Google the Web? Find out more about vSearch 3.0: the search engine for all your private and public clouds.

Installing KVM and Virt-Manager

As mentioned, installing KVM is relatively easy. On CentOS, you just need to run the following command. If you have proxy, you need to set it up properly before running this command.

# yum groupinstall virtualization

Although the GUI is not required, I highly recommend you install two GUI components so that you can familiarize yourself with KVM.

# yum install virt-manager virt-viewer
# virt-manager &

After the second command, you should see the Virtualization Manager GUI coming up. I found it’s similar to the old VMware Player, and pretty straightforward to use.

More information can be found at this article if you runs on CentOS 6.4, or this if CentOS 6.3. If you are using Ubuntu, check out this article at dedoimedo.com. BTW, I found dedoimedo.com very well written and easy to follow. There are many other great posts about how to use other hypervisors like KVM, XEN, VirtualBox.

Configuring libvirtd

To make it easy, we’ll use tcp protocol with no password – not something you want to do outside of your development and test. There are secure ways like ssh, tls, sasl, etc. You want to read the details () from libvirt.org.

# vim /etc/libvirt/libvirtd.conf
listen_tls = 0 #it’s enabled by default. To disable it, set it to be zero
listen_tcp = 1
tcp_port=”16509listen_addr=”192.168.45.22”
# tcp_auth = “sasl”
auth_tcp = “none”
# /usr/sbin/libvirtd –listen

I could have set up the sasl with tcp. To do that, you need to add username and pass to the sasl database as follows, which would prompt for password twice:

# saslpasswd2 -a libvirt root

Also, in the libvirtd.conf file change the auth_tcp to “sasl” (comment the none line and uncomment the sasl line).

It works fine if you connect it from virtualization manager running on another Linux machine. But it did seem to work from Windows client. The following error message would come up:

org.libvirt.LibvirtException: authentication failed: unsupported authentication type 1
 at org.libvirt.ErrorHandler.processError(ErrorHandler.java:33)
 at org.libvirt.Connect.processError(Connect.java:1322)
 at org.libvirt.Connect.(Connect.java:227)

To make sure it’s not Java code issue, I also ran it with virsh.exe and got similar error. So I guess sasl may not be supported on Windows client. Anyway, that is not really what I cared about the most. To move forward, I decided to turn off the password. It’s not something you want in your production environment.

Set up Development Environment

Now you’ve got the KVM server ready. It’s time to set up your client side. Here are downloads you would need.

First is the libvirt java binding. There are many different versions, I just downloaded version 0.4.9. It’s in tar.gz format, which can easily uncompressed using 7-Zip. You can import the source code directly to your project. Optionally, you can build it to jar as reference it as library in your build path.

The libvirt Java binding is built on top of underlying native library using JNA which is similar to JNI but pure Java implementation. For that reason, you would need JNA library from here.

After this, we are not done yet. We would need Windows implementation of libvirt client library. This is also pretty confusing as I tried quite a few different ways. You probably don’t need all I had tried, but if you do it would surely work. Just pick one and move on to next section. If it doesn’t work, come back with other two. If you use Linux as your client, you can skip the rest in this section.

According to this page on libvirt site, you can download Windows version of virt-viewer and get the client dll without compile it. Here is the link and you can download the MSI installer for virt-viewer 0.5.6 per your OS type (32 bits or 64 bits). When using IE to download it, the file extension somehow got changed from .msi to .man. If that happens to you, just rename it back to .msi. The installation is pretty straightforward – just follow the wizard.

There are actually pre-built libvirt for Window on libvirt Website as I found out later. The latest version of the installer is for version 0.8.8 published on Mar 15, 2011. . You can download it here and install it to default location C:\Program Files (x86)\Libvirt.

Because the authentication error, I was thinking maybe the version of the libvirt is not up to date. So I started to build it by myself. It may seem daunting, but not necessary with the msys_setup project on Github. You can download the zip file and unzip it to a folder. You will also need download wget.exe and put it in the same directory as msys_setup.bat.

In that folder, you run msys_setup.bat in your DOS window. After that, you will run msys\msys.bat to bring up MSYS shell and run a few more commands to compile everything. The detail can be found in the readme_libvirt.txt file in your msys folder. Just follow the short list of instructions. If you run behind a proxy, your got to set up both http and ftp proxy as follows: (change the proxy IP/port to yours and http/ftp proxies are not necessarily the same)

export http_proxy=http://10.10.10.10:8080
export ftp_proxy=http://10.10.10.10:8080

There is also compiled installer on sourceforge.net, which I also installed.

As this far, you would have several copies of libvirt DLL files in your computer.

To verify it, you can run the virsh.exe to see if it works

> virsh -c qemu+tcp://192.168.23.22/system
...
virsh #

If you see the virsh prompt, you are good.

One problem I got into while running virsh.exe is it pops up error dialog box saying “The program can’t start because libtermcap-0.dll is missing from your computer. Try reinstalling the program to fix this program.” Later on, it disappeared for whatever reason. I didn’t bother to root-cause the issue. After it works, my computer doesn’t seem to have the libtermcap-0.dll file.

Coding Java to manage KVM

Now you are good to try out a simple Java code. As you would see, the Java binding still have strong C flavor which is expected for a wrapper around the original C APIs.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package org.doublecloud.libvirt;
 
import org.libvirt.Connect;
import org.libvirt.ConnectAuth;
import org.libvirt.ConnectAuthDefault;
import org.libvirt.Domain;
import org.libvirt.LibvirtException;
import org.libvirt.NodeInfo;
 
public class MiniTest 
{
  public static void main(String[] args)
  {
    System.setProperty("jna.library.path", "C:\\Program Files (x86)\\Libvirt\\bin");
 
    try
    {
      ConnectAuth ca = new ConnectAuthDefault();
      Connect conn = new Connect("qemu+tcp://192.168.45.22/system", ca, 0);
      NodeInfo ni = conn.nodeInfo();
 
      System.out.println("model: " + ni.model + " mem(kb):" + ni.memory);
 
      int numOfVMs = conn.numOfDomains();
 
      for(int i=1; i < numOfVMs + 1; i++)
      {
        Domain vm = conn.domainLookupByID(i);
        System.out.println("vm name: " + vm.getName() + "  type: " + vm.getOSType()
	    	+ " max mem: " + vm.getMaxMemory() + " max cpu: " + vm.getMaxVcpus());
      }
      String cap = conn.getCapabilities();
      System.out.println("cap: " + cap);
      conn.close();
    }
	catch(LibvirtException le)
	{
		le.printStackTrace();
	}
  }
}

Before you run the code, you want to change at least the IP address to your KVM server. If the path of your libvirt is different from what I used, you want to change it too. Then, run the program and you would see output like the following:

 
model: x86_64 mem(kb):99006632
vm name: instance-0000000d  type: hvm max mem: 524288 max cpu: 1
vm name: instance-0000000f  type: hvm max mem: 524288 max cpu: 1
cap: <capabilities>
 
  <host>
    <uuid>c92d59a0-277c-11e2-3210-32100000001e</uuid>
    <cpu>
      <arch>x86_64</arch>
      <model>Westmere</model>
      <vendor>Intel</vendor>
      <topology sockets='1' cores='6' threads='2'/>
      <feature name='rdtscp'/>
      <feature name='pdpe1gb'/>
      <feature name='dca'/>
      <feature name='pcid'/>
      <feature name='pdcm'/>
      <feature name='xtpr'/>
      <feature name='tm2'/>
      <feature name='est'/>
      <feature name='smx'/>
      <feature name='vmx'/>
      <feature name='ds_cpl'/>
      <feature name='monitor'/>
      <feature name='dtes64'/>
      <feature name='pclmuldq'/>
      <feature name='pbe'/>
      <feature name='tm'/>
      <feature name='ht'/>
      <feature name='ss'/>
      <feature name='acpi'/>
      <feature name='ds'/>
      <feature name='vme'/>
    </cpu>
    <power_management>
      <suspend_disk/>
    </power_management>
    <migration_features>
      <live/>
      <uri_transports>
        <uri_transport>tcp</uri_transport>
      </uri_transports>
    </migration_features>
    <topology>
      <cells num='2'>
        <cell id='0'>
          <cpus num='12'>
            <cpu id='0' socket_id='0' core_id='0' siblings='0,12'/>
            <cpu id='2' socket_id='0' core_id='1' siblings='2,14'/>
            <cpu id='4' socket_id='0' core_id='2' siblings='4,16'/>
            <cpu id='6' socket_id='0' core_id='8' siblings='6,18'/>
            <cpu id='8' socket_id='0' core_id='9' siblings='8,20'/>
            <cpu id='10' socket_id='0' core_id='10' siblings='10,22'/>
            <cpu id='12' socket_id='0' core_id='0' siblings='0,12'/>
            <cpu id='14' socket_id='0' core_id='1' siblings='2,14'/>
            <cpu id='16' socket_id='0' core_id='2' siblings='4,16'/>
            <cpu id='18' socket_id='0' core_id='8' siblings='6,18'/>
            <cpu id='20' socket_id='0' core_id='9' siblings='8,20'/>
            <cpu id='22' socket_id='0' core_id='10' siblings='10,22'/>
          </cpus>
        </cell>
        <cell id='1'>
          <cpus num='12'>
            <cpu id='1' socket_id='1' core_id='0' siblings='1,13'/>
            <cpu id='3' socket_id='1' core_id='1' siblings='3,15'/>
            <cpu id='5' socket_id='1' core_id='2' siblings='5,17'/>
            <cpu id='7' socket_id='1' core_id='8' siblings='7,19'/>
            <cpu id='9' socket_id='1' core_id='9' siblings='9,21'/>
            <cpu id='11' socket_id='1' core_id='10' siblings='11,23'/>
            <cpu id='13' socket_id='1' core_id='0' siblings='1,13'/>
            <cpu id='15' socket_id='1' core_id='1' siblings='3,15'/>
            <cpu id='17' socket_id='1' core_id='2' siblings='5,17'/>
            <cpu id='19' socket_id='1' core_id='8' siblings='7,19'/>
            <cpu id='21' socket_id='1' core_id='9' siblings='9,21'/>
            <cpu id='23' socket_id='1' core_id='10' siblings='11,23'/>
          </cpus>
        </cell>
      </cells>
    </topology>
    <secmodel>
      <model>selinux</model>
      <doi>0</doi>
    </secmodel>
    <secmodel>
      <model>dac</model>
      <doi>0</doi>
    </secmodel>
  </host>
 
  <guest>
    <os_type>hvm</os_type>
    <arch name='i686'>
      <wordsize>32</wordsize>
      <emulator>/usr/libexec/qemu-kvm</emulator>
      <machine>rhel6.4.0</machine>
      <machine canonical='rhel6.4.0'>pc</machine>
      <machine>rhel6.3.0</machine>
      <machine>rhel6.2.0</machine>
      <machine>rhel6.1.0</machine>
      <machine>rhel6.0.0</machine>
      <machine>rhel5.5.0</machine>
      <machine>rhel5.4.4</machine>
      <machine>rhel5.4.0</machine>
      <domain type='qemu'>
      </domain>
      <domain type='kvm'>
        <emulator>/usr/libexec/qemu-kvm</emulator>
      </domain>
    </arch>
    <features>
      <cpuselection/>
      <deviceboot/>
      <acpi default='on' toggle='yes'/>
      <apic default='on' toggle='no'/>
      <pae/>
      <nonpae/>
    </features>
  </guest>
 
  <guest>
    <os_type>hvm</os_type>
    <arch name='x86_64'>
      <wordsize>64</wordsize>
      <emulator>/usr/libexec/qemu-kvm</emulator>
      <machine>rhel6.4.0</machine>
      <machine canonical='rhel6.4.0'>pc</machine>
      <machine>rhel6.3.0</machine>
      <machine>rhel6.2.0</machine>
      <machine>rhel6.1.0</machine>
      <machine>rhel6.0.0</machine>
      <machine>rhel5.5.0</machine>
      <machine>rhel5.4.4</machine>
      <machine>rhel5.4.0</machine>
      <domain type='qemu'>
      </domain>
      <domain type='kvm'>
        <emulator>/usr/libexec/qemu-kvm</emulator>
      </domain>
    </arch>
    <features>
      <cpuselection/>
      <deviceboot/>
      <acpi default='on' toggle='yes'/>
      <apic default='on' toggle='no'/>
    </features>
  </guest>
 
</capabilities>

Possible Errors and Solutions

There are many ways things could go south like the following error:

Exception in thread "main" java.lang.UnsatisfiedLinkError: Unable to load library 'virt': The specified module could not be found.

By default, the dll on Windows is named as libvirt-0.dll, you may want to copy it and name the copy to libvirt.dll so that it can be discovered. To avoid it break something else, you want to copy it, not simply rename it.

You can optionally change Java source code in the Libvirt.java

Libvirt INSTANCE = (Libvirt) Native.loadLibrary("virt", Libvirt.class);

I would not recommend you change this way although it’s doable.

If you find the following error, it’s likely that your libvirtd is not listening to the tcp port. You must have –listen option while running the libvirtd.

org.libvirt.LibvirtException: unable to connect to server at '192.168.45.22:16509': Unknown error 107

Summary

With the rising of Openstack, KVM is gaining momentum. You can run the KVM without Openstack, and automate the infrastructure by yourself with either virsh command line or APIs in various languages. This tutorial shows you how to set up an environment and code a sample to achieve remote manageability for KVM. I will further discuss the libvirt API itself in future posts. Stay tuned.

This entry was posted in Virtualization and tagged , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

7 Comments

  1. Prashant
    Posted December 3, 2013 at 7:29 am | Permalink

    This tutorial was really very enlightening. Thanks!!!!!!!1

  2. Posted December 3, 2013 at 8:22 pm | Permalink

    Glad you enjoyed it. -Steve

  3. Posted December 10, 2013 at 11:30 pm | Permalink

    Hey Steve, Thanks a lot for the detailed tutorial. We too have some interesting tutorials if you’d like to check them out at http://www.fireboxtraining.com/java

  4. maXPert
    Posted March 10, 2014 at 8:19 am | Permalink

    I am Following this tutorial and I am getting an error with code 138 which is

    org.libvirt.LibvirtException: unable to connect to server at ‘192.168.x.x:16509’: Unknown error 138
    at org.libvirt.ErrorHandler.processError(ErrorHandler.java:33)
    at org.libvirt.Connect.processError(Connect.java:1322)
    at org.libvirt.Connect.(Connect.java:194)
    at libvirt.testing.MiniTest.main(MiniTest.java:16)
    libvirt: XML-RPC error : unable to connect to server at ‘192.168.x.x:16509’: Unknown error 138

    Error code Description
    138 License edition could not be applied

    Any Help in this will be highly appreciated

  5. Posted March 10, 2014 at 10:21 am | Permalink

    It seems there was a connection issue. You may want to check the libvirtd status and command options. Here is a doc that may be helpful for your troubleshooting.

    http://docs.fedoraproject.org/en-US/Fedora_Draft_Documentation/0.1/html/Virtualization_Deployment_and_Administration_Guide/App_TCP_Ports.html

    Steve

  6. Oliver Kuster
    Posted January 13, 2015 at 12:39 pm | Permalink

    getCapabilities() makes JVM crash and burn…

  7. Posted January 15, 2015 at 4:41 pm | Permalink

    Thanks for the update. More details?

    Steve

2 Trackbacks

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

  • NEED HELP?


    My company has created products like vSearch ("Super vCenter"), vijavaNG APIs, EAM APIs, ICE tool. We also help clients with virtualization and cloud computing on customized development, training. Should you, or someone you know, need these products and services, please feel free to contact me: steve __AT__ doublecloud.org.

    Me: Steve Jin, VMware vExpert who authored the VMware VI and vSphere SDK by Prentice Hall, and created the de factor open source vSphere Java API while working at VMware engineering. Companies like Cisco, EMC, NetApp, HP, Dell, VMware, are among the users of the API and other tools I developed for their products, internal IT orchestration, and test automation.