一、简介
libvirt是Linux上的虚拟化库,是长期稳定的C语言API,支持KVM/QEMU、Xen、LXC等主流虚拟化方案。链接:
API开发手册:
virsh是libvirt对应的shell命令。
之前写了一篇使用virsh管理kvm虚拟机的博客《使用libvirt管理kvm(virsh篇)》(传送门:),这里再从编程接口API的角度介绍如何使用libvirt管理kvm虚拟机。
二、环境介绍
OS:Ubuntu 12.04.1 LTS
内核:Linux 3.2.0-33-generic-pae #52-Ubuntu SMP Thu Oct 18 16:39:21 UTC 2012 i686 i686 i386 GNU/Linux
libvirt:0.9.8
三、准备工作
ubuntu安装,直接apt-get install
1、安装kvm/qemu
sudo apt-get install kvm qemu
2、安装libvirt
sudo apt-get install libvirt-bin libvirt-dev
3、网桥管理工具
sudo apt-get install bridge-utils
4、统一建模语言
sudo apt-get install uml-utilities
5、vnc 虚拟机查看工具
sudo apt-get install vncviewer vnc4server
四、创建镜像
执行 qemu-img create -f raw template.img 3G
这样就创建了一个大小为3G的镜像(img)
有人可能问镜像是什么东西。简单的说,我们在镜像上启动一个虚拟机,这个3G的镜像就相当于这个虚拟机对应的磁盘空间。
也有人执行 qemu-img create -f qcow2 template.img 3G,(备注:qcow2支持动态扩张)来获得一个动态扩张的镜像。我个人还需要对磁盘资源进行简单的统计、管理,因此没有用这个。不同情景下可能这种模式更好,有兴趣的朋友自己试一下。
五、libvirt xml配置文件
libvirt(包括virsh)使用xml文件对虚拟机进行配置,其中包括虚拟机名称、分配内存、vcpu等多种信息。定义、创建虚拟机等操作都需要xml配置文件的参与,因此这里先介绍xml配置文件。我编辑了一个名为template.xml的xml文件,其中定义了一个名为demo的kvm 虚拟机。
<domain type = 'kvm'> //虚拟机类型,kvm <name>demo</name> //虚拟机名称 <memory>1048576</memory> //分配内存,单位kb <vcpu>1</vcpu> //分配vcpu,单位个数 <os> <type arch = 'x86_64' machine = 'pc'>hvm</type> <boot dev = 'cdrom'/> //cd 启动 <boot dev = 'hd'/> //硬盘启动 </os> <features> <acpi/> <apic/> <pae/> </features> <clock offset = 'localtime'/> <on_poweroff>destroy</on_poweroff> <on_reboot>restart</on_reboot> <on_crash>destroy</on_crash> <devices> <emulator>/usr/bin/kvm</emulator> <disk type = 'file' device = 'disk'> //对应的镜像,就是之前使用qemu-img命令新建的img文件,注意路径要正确 <driver name = 'qemu' type = 'raw'/> <source file = '/var/lib/lynn/img/template.img'/> <target dev = 'hda' bus = 'ide'/> </disk> <disk type = 'file' device = 'cdrom'> //可选项,iso通常是操作系统的安装光盘 <source file = '/var/lib/lynn/img/template.iso'/> <target dev = 'hdb' bus = 'ide'/> </disk> <interface type = 'bridge'> //libvirt默认虚拟机的网络配置是NAT模式,就是虚拟机与宿主机的网络拓扑是NAT形式。实际中,许多开发者更希望使用网桥模式。 <source bridge = 'br0'/> </interface> <input type ='tablet' bus='usb'/> <input type = 'mouse' bus = 'ps2'/> <graphics type = 'vnc' port = '-1' listen = '0.0.0.0' autoport = 'yes' keymap = 'en-us'/> //vnc端口系统自动配置 </devices> </domain>
六、libvirt的使用——头文件与编译
#include "libvirt/libvirt.h" //libvirt主要API
#include <libvirt/virterror.h> //libvirt 错误提示
编译时加入连接库 -lvirt,例如我要编译名为createvm.cpp的源文件,可以运行如下命令g++ createvm.cpp -o createvm -lvirt。
七、主要使用的API
这里只列举一些常用的API,具体可参见libvirt API开发手册
主要功能 | 函数原型 |
创建连接 | virConnectPtr virConnectOpen(const char * name) |
根据xml文档创建虚拟机 | virDomainPtr virDomainCreateXML(virConnectPtr conn, const char * xmlDesc, unsigned int flags) |
根据虚拟机名字获得虚拟域 | virDomainPtr virDomainLookupByName(virConnectPtr conn, const char * name) |
获取虚拟域相关信息 | int virDomainGetInfo(virDomainPtr domain, virDomainInfoPtr info) |
关闭虚拟域 | int virDomainShutdown (virDomainPtr domain) |
销毁虚拟域 | int virDomainDestroy (virDomainPtr domain) |
八、新建虚拟机
备注:这里只是写一个简单的例子,除print.cpp以外的代码没有写成带参数、可配置的,请见谅。
/* createvm.cpp */
/* compile with: g++ createvm.cpp -o createvm -lvirt */
/* Wang Min @ iie */
/* autumn_sky_is@163.com */
/* date: 2013-02-27 */
#include <iostream>
#include <cstdio>
#include <string>
#include <fstream>
#include <sstream> // for stringstream
#include "libvirt/libvirt.h"
#include <libvirt/virterror.h>
using namespace std;
string vm_xml_location = "../xml/template.xml";
int main() {
ifstream file(vm_xml_location.c_str());
if (!file) {
cout<<"Cannot open file "<<vm_xml_location<<endl;
return -1;
}
// read xml file
stringstream buffer;
buffer << file.rdbuf();
string vm_xml_template = buffer.str();
file.close();
virConnectPtr conn = virConnectOpen("qemu:///system");
if (NULL==conn) {
fprintf(stderr, "Failed to build connection to qemu:///system.\n");
return -1;
}
virDomainPtr vm_ptr = virDomainCreateXML(conn, vm_xml_template.c_str(), 0);
if (!vm_ptr) {
virErrorPtr error = virGetLastError();
cout << error->message << endl;
return -1;
}
return 0;
}
九、读取虚拟机信息
/* print.cpp */
/* compile with: g++ print.cpp -o print -lvirt */
/* Wang Min @ iie */
/* autumn_sky_is@163.com */
/* date: 2013-02-27 */
#include <iostream>
#include <cstdio>
#include <string>
#include <fstream>
#include <sstream> // for stringstream
#include "libvirt/libvirt.h"
#include <libvirt/virterror.h>
using namespace std;
//using namespace rapidxml;
int main(int argc, char * argv[]) {
if (2 != argc){
cout << "Error: print need 1 parametre" << endl;
cout << "usage: ./print vm_name" << endl;
return -1;
}
virConnectPtr conn = virConnectOpen("lxc:///");
if (NULL == conn) {
fprintf(stderr, "Failed to build connection to lxc:///.\n");
return -1;
}
virDomainPtr domain = virDomainLookupByName(conn, argv[1]);
if (domain == NULL){
cout << "can not find " << argv[1] << ", regard it as success." << endl;
return -1;
}
// get lxc Info
virDomainInfo info;
if (-1 == virDomainGetInfo(domain, &info)){
cout << "can not get domain info" << endl;
return -1;
}
printf("state:%d|maxmem:%d|memused:%d|cpunum:%d|cputime:%ld\n", info.state, info.maxMem, info.memory, info.nrVirtCpu, info.cpuTime);
cout << "Helloworld" << endl;
return 0;
}
编译后运行./print virt_name,例如./print demo
十、关闭虚拟机
/* shutdownvm.cpp */
/* compile with: g++ shutdownvm.cpp -o shutdownvm -lvirt */
/* Wang Min @ iie */
/* autumn_sky_is@163.com */
/* date: 2013-02-27 */
#include <iostream>
#include <cstdio>
#include <string>
#include <fstream>
#include <sstream> // for stringstream
#include "libvirt/libvirt.h"
#include <libvirt/virterror.h>
using namespace std;
string domname = "demo";
int main() {
virConnectPtr conn = virConnectOpen("qemu:///system");
if(NULL==conn) {
fprintf(stderr, "Failed to build connection to qemu:///system.\n");
return -1;
}
virDomainPtr domain = virDomainLookupByName(conn, domname.c_str());
if (domain == NULL){
cout << "can not find " << domname << ", regard it as success." << endl;
return 0;
}
if (virDomainShutdown(domain) != 0){
virErrorPtr error = virGetLastError();
cout << error->message << endl;
return -1;
}
return 0;
}
编译后运行./shutdownvm
十一、销毁虚拟机
/* destroyvm.cpp */
/* compile with: g++ destroyvm.cpp -o destroyvm -lvirt */
/* Wang Min @ iie */
/* autumn_sky_is@163.com */
/* date: 2013-02-27 */
#include <iostream>
#include <cstdio>
#include <string>
#include <fstream>
#include <sstream> // for stringstream
#include "libvirt/libvirt.h"
#include <libvirt/virterror.h>
using namespace std;
string domname = "demo";
int main() {
virConnectPtr conn = virConnectOpen("qemu:///system");
if (NULL == conn) {
fprintf(stderr, "Failed to build connection to qemu:///system.\n");
return -1;
}
virDomainPtr domain = virDomainLookupByName(conn, domname.c_str());
if (domain == NULL){
cout << "can not find " << domname << ", regard it as success." << endl;
return 0;
}
if (virDomainDestroy(domain) != 0){
virErrorPtr error = virGetLastError();
cout << error->message << endl;
return -1;
}
return 0;
}
编译后运行./destroyvm