centos下C编程调用libvirt的API访问KVM虚拟机

一、简介

        libvirt是一套免费、开源的支持Linux下主流虚拟化工具的C函数库,其旨在为包括Xen在内的各种虚拟化工具提供一套方便、可靠的编程接口,支持与C,C++,Ruby,Python等多种主流开发语言的绑定。当前主流Linux平台上默认的虚拟化管理工具virt-manager(图形化),virt-install(命令行模式)等均基于libvirt开发而成。
       本文基于libvirt,使用它的C函数库进行虚拟机的相应操作。

二、详解

1、创建虚拟机

(1)C语言代码

/*************************************************************************** 
     *  create_kvm.c  
     *  create kvm machine(domain) based on conf.xml 
     *  compile command: 'gcc -g -Wall create_kvm.c -o create -lvirt' 
     *  run shell command:'qemu-img create -f qcow2 newlinux.img 15G'
     *  running command: './create ./create_kvm.xml' 
***************************************************************************/  
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include<assert.h>
#include <libvirt/libvirt.h>
#include <libvirt/virterror.h>

static int create_kvm();
static int get_status();
static int open_file(char *file_name);

static virConnectPtr conn = NULL;
static virDomainPtr dom = NULL;
char *buff = NULL;

int main(int argc, char *argv[])
{
  if (argc != 2) {
    fprintf(stderr, "parametes are wrong,please checkout!\n");
    return -1;
  }
  if (open_file(argv[1]) != 0) {
    fprintf(stderr, "open_file failed!\n");
    return -1;
  }
  conn = virConnectOpen("qemu:///system");
  if (conn == NULL) {
    fprintf(stderr, "Failed to open connection to qemu:///system\n");
    return -1;
  }
  if (create_kvm() != 0) {
    fprintf(stderr, "create_kvm failed!\n");
    virConnectClose(conn);
    return -1;
  }
  if (get_status() != 0) {
    fprintf(stderr, "create_kvm failed!\n");
    virDomainFree(dom);
    virConnectClose(conn);
    return -1;
  }
  if (dom != NULL)  virDomainFree(dom);
  if (conn != NULL)  virConnectClose(conn);
  return 0;
}
int open_file(char *file_name)
{
   FILE *fp = fopen(file_name, "r+");
   assert(fp);
   int flag = fseek(fp, 0, SEEK_END);
   assert(flag == 0);
   int len = ftell(fp);
   buff = (char *)malloc(sizeof(char) * (len + 1));
   flag = fseek(fp, 0, SEEK_SET);
   assert(flag == 0);
   int num = fread(buff, 1, len + 1, fp);
   assert(num == len);
   return 0;
}
int create_kvm()
{
  dom = virDomainDefineXML(conn, buff);
  if (!dom) {
    virErrorPtr error = virGetLastError();
    fprintf(stderr, "virDomainDefineXML failed:%s!\n", error->message);
    virFreeError(error);
    return -1;
  }
  if (virDomainCreate(dom) < 0) {
    virErrorPtr error = virGetLastError();
    fprintf(stderr, "virDomainCreate failed:%s!\n", error->message);
    virDomainUndefine(dom);
    virFreeError(error);
    //virDomainFree(dom);
    return -1;
  }
  return 0;
}

int get_status()
{
  char *status = NULL;
  virErrorPtr error = NULL;
  int vcpus = 0;
  unsigned long long node_free_memory = 0;
  int id = 0;
  const char *name = NULL;
  virNodeInfo nodeinfo;
  virDomainInfo info; 
  // 获取虚拟机状态
  fprintf(stdout, "****************************************************\n");
  /* get the capabilities of conn*/
  status =  virConnectGetCapabilities(conn);
  if (status == NULL) {
    error = virGetLastError();
    fprintf(stderr, "virConnectGetCapabilities failed: %s\n", error->message);
    virFreeError(error);
    return -1;
  }
  fprintf(stdout, "Capabilities of connection:\t%s\n", status);
  free(status);  status = NULL;

  /* get the hostname reported from conn*/
  status = virConnectGetHostname(conn);
  if (status == NULL) {
    error = virGetLastError();
    fprintf(stderr, "virConnectGetHostname failed: %s\n", error->message);
    virFreeError(error);
    return -1;
  }
  fprintf(stdout, "Connection hostname:\t%s\n", status);
  free(status);  status = NULL;

  /* get the maximum number of vcpus supported by conn3 */
  vcpus = virConnectGetMaxVcpus(conn, NULL);
  if (vcpus < 0) {
    error = virGetLastError();
    fprintf(stderr, "virConnectGetMaxVcpus failed: %s\n", error->message);
    virFreeError(error);
    return -1;
   }
   fprintf(stdout, "Maximum number of cpus supported on connection:\t%d\n", vcpus);

   /* get the amount of free memory available on the node from conn4 */
    node_free_memory = virNodeGetFreeMemory(conn);
    if (node_free_memory == 0) {
      error = virGetLastError();
      fprintf(stderr, "virNodeGetFreeMemory failed: %s\n", error->message);
      virFreeError(error);
      return -1;
   }
   fprintf(stdout, "Node free memory:\t%llu\n", node_free_memory);

   /* get the node information from conn*/
   if (virNodeGetInfo(conn, &nodeinfo) < 0) {
      error = virGetLastError();
      fprintf(stderr, "virNodeGetInfo failed: %s\n", error->message);
      virFreeError(error);
      return -1;
   }
   fprintf(stdout, "Node information from connection\n");
   fprintf(stdout, "Model:\t%s\n", nodeinfo.model);
   fprintf(stdout, "Memory size:\t%lukb\n", nodeinfo.memory);
   fprintf(stdout, "Number of CPUs:\t%u\n", nodeinfo.cpus);
   fprintf(stdout, "MHz of CPUs:\t%u\n", nodeinfo.mhz);
   fprintf(stdout, "Number of NUMA nodes:\t%u\n", nodeinfo.nodes);
   fprintf(stdout, "Number of CPU sockets:\t%u\n", nodeinfo.sockets);
   fprintf(stdout, "Number of CPU cores per socket:\t%u\n", nodeinfo.cores);
   fprintf(stdout, "Number of CPU threads per core:\t%u\n", nodeinfo.threads);
   fprintf(stdout, "****************************************************\n");
   fprintf(stdout, "id\t名称\t\t状态\n");
   fprintf(stdout, "------------------------------------------\n");
   id = virDomainGetID(dom);
   name = virDomainGetName(dom);
   if (virDomainGetInfo(dom, &info) < 0) {
     error = virGetLastError();
     fprintf(stderr, "virDomainGetInfo failed: %s\n", error->message);
     virFreeError(error);
     return -1;
   }
   fprintf(stdout, "%d\t%s\t\t%d\n", id, name, info.state);
   fprintf(stdout, "****************************************************\n");
   return 0;
}
(2)创建所需要的启动配置xml文件

       首先需要准备好centos6.3.iso系统镜像文件,在xml中<source file = ‘/home/taiyang/centos6.3.iso‘/>设置其全路径。
       然后创建img虚拟机镜像文件#qemu-img create -f qcow2 newlinux.img 15G,在 <source file = ‘/var/lib/libvirt/images/newlinux.img‘/>设置其路径。
      最后#vim create_kvm.xml,输入一下内容:

<domain type = 'kvm'>        //虚拟机类型,kvm
<name>newlinux</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/libexec/qemu-kvm</emulator>
    <disk type = 'file' device = 'disk'>  //对应的镜像,就是之前使用qemu-img命令新建的img文件,注意路径要正确
      <driver name = 'qemu' type = 'qcow2'/>
      <source file = '/var/lib/libvirt/images/newlinux.img'/>
      <target dev = 'hda' bus = 'ide'/>
    </disk>
    <disk type = 'file' device = 'cdrom'> //可选项,iso通常是操作系统的安装光盘
      <source file = '/home/taiyang/centos6.3.iso'/>
      <target dev = 'hdb' bus = 'ide'/>
    </disk>
    <interface type = 'bridge'>           //libvirt默认虚拟机的网络配置是NAT模式,就是虚拟机与宿主机的网络拓扑是NAT形式。实际中,许多开发者更希望使用网桥模式。
      <source bridge = 'virbr0'/>
    </interface>

    <input type ='tablet' bus='usb'/>
    <input type = 'mouse' bus = 'ps2'/>
    <graphics type = 'vnc' port = '-1' listen = '0.0.0.0' keymap = 'en-us'/>  //vnc端口系统自动配置
  </devices>
</domain>
注意:<memory>1048576</memory>单位kb,分配内存过大无法启动;文件路径不正确无法启动。

(3)编译运行

#gcc -g -Wall create_kvm.c -o create -lvirt

#./create create_kvm.xml

可以通过virsh查看创建的虚拟机:

centos下C编程调用libvirt的API访问KVM虚拟机

也可以通过virt-manager查看创建的虚拟机:

centos下C编程调用libvirt的API访问KVM虚拟机

2、操作虚拟机(开机、关机、查询状态)

(1)C语言代码

/*   gcc -g -Wall virtctl.c -o virtctl -lvirt      */
/*   virtctl  guest-name  start/shutdown/status    */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <libvirt/libvirt.h>
#include <libvirt/virterror.h>

static int set_start(char *guestname);
static int set_shutdown(char *guestname);
static int get_status(char *guestname);
static virConnectPtr conn = NULL;
static virDomainPtr dom = NULL;

int main(int argc, char *argv[])
{
  if (argc != 3) {
    fprintf(stderr, "Usage:./virtctl guest-name start/shutdown/status\n");
    return -1;
  }
  conn = virConnectOpen("qemu:///system");
  if (conn == NULL) {
    fprintf(stderr, "Failed to open connection to qemu:///system\n");
    return -1;
  }
  dom = virDomainLookupByName(conn, argv[1]);
  if (dom == NULL) {
    fprintf(stderr, "virDomainLookupByName failed!\n");
    virConnectClose(conn);
    return -1;
  }

  if (strcmp(argv[2], "start") == 0 || strcmp(argv[2], "START") == 0) {
    if (set_start(argv[1]) != 0) {
      fprintf(stderr, "start failed!\n");
      virDomainFree(dom);
      //virConnectClose(conn);
      return -1;
    }
  }
  if (strcmp(argv[2], "shutdown") == 0 || strcmp(argv[2], "SHUTDOWN") == 0) {
    if (set_shutdown(argv[1]) != 0) {
      fprintf(stderr, "shutdown failed!\n");
      virConnectClose(conn);
      virDomainFree(dom);
      return -1;
    }
  }
  if (strcmp(argv[2], "status") == 0 || strcmp(argv[2], "STATUS") == 0) {
    if (get_status(argv[1]) != 0) {
      fprintf(stderr, "get status failed!\n");
      virDomainFree(dom);
      virConnectClose(conn);
      return -1;
    }
  }
  if (dom != NULL)  virDomainFree(dom);
  if (conn != NULL)  virConnectClose(conn);
  return 0;
}
int set_start(char *guestname)
{
  int flag = -1;
  // 启动已定义虚拟机
  flag = virDomainCreate(dom);
  if (flag != 0) {
    virErrorPtr error = virGetLastError();
    fprintf(stderr, "virDomainCreate failed:%s!\n", error->message);
    virFreeError(error);
    return -1; 
  }
  return 0;
}
int set_shutdown(char *guestname)
{
  int flag = -1;
   // 关闭已定义虚拟机
  flag = virDomainShutdown(dom);
  if(flag != 0) { 
    virErrorPtr error = virGetLastError();
    fprintf(stderr, "virDomainShutdown failed:%s!\n", error->message);
    virFreeError(error);
    return -1; 
  }
  return 0;
}
int get_status(char *guestname)
{
  char *status = NULL;
  virErrorPtr error = NULL;
  int vcpus = 0;
  unsigned long long node_free_memory = 0;
  int id = 0;
  const char *name = NULL;
  virNodeInfo nodeinfo;
  virDomainInfo info; 
  // 获取虚拟机状态
  fprintf(stdout, "****************************************************\n");
  /* get the capabilities of conn*/
  status =  virConnectGetCapabilities(conn);
  if (status == NULL) {
    error = virGetLastError();
    fprintf(stderr, "virConnectGetCapabilities failed: %s\n", error->message);
    virFreeError(error);
    return -1;
  }
  //fprintf(stdout, "Capabilities of connection:\n%s\n", status);
  free(status);  status = NULL;

  /* get the hostname reported from conn*/
  status = virConnectGetHostname(conn);
  if (status == NULL) {
    error = virGetLastError();
    fprintf(stderr, "virConnectGetHostname failed: %s\n", error->message);
    virFreeError(error);
    return -1;
  }
  //fprintf(stdout, "------------------------------------------\n");
  fprintf(stdout, "Connection hostname:\t%s\n", status);
  free(status);  status = NULL;

  /* get the maximum number of vcpus supported by conn3 */
  vcpus = virConnectGetMaxVcpus(conn, NULL);
  if (vcpus < 0) {
    error = virGetLastError();
    fprintf(stderr, "virConnectGetMaxVcpus failed: %s\n", error->message);
    virFreeError(error);
    return -1;
   }
   fprintf(stdout, "Maximum number of cpus supported on connection:\t%d\n", vcpus);

   /* get the amount of free memory available on the node from conn4 */
    node_free_memory = virNodeGetFreeMemory(conn);
    if (node_free_memory == 0) {
      error = virGetLastError();
      fprintf(stderr, "virNodeGetFreeMemory failed: %s\n", error->message);
      virFreeError(error);
      return -1;
   }
   fprintf(stdout, "Node free memory:\t%llu\n", node_free_memory);

   /* get the node information from conn*/
   if (virNodeGetInfo(conn, &nodeinfo) < 0) {
      error = virGetLastError();
      fprintf(stderr, "virNodeGetInfo failed: %s\n", error->message);
      virFreeError(error);
      return -1;
   }
   fprintf(stdout, "------------------------------------------\n");
   fprintf(stdout, "Node information from connection\n");
   fprintf(stdout, "Model:\t%s\n", nodeinfo.model);
   fprintf(stdout, "Memory size:\t%lukb\n", nodeinfo.memory);
   fprintf(stdout, "Number of CPUs:\t%u\n", nodeinfo.cpus);
   fprintf(stdout, "MHz of CPUs:\t%u\n", nodeinfo.mhz);
   fprintf(stdout, "Number of NUMA nodes:\t%u\n", nodeinfo.nodes);
   fprintf(stdout, "Number of CPU sockets:\t%u\n", nodeinfo.sockets);
   fprintf(stdout, "Number of CPU cores per socket:\t%u\n", nodeinfo.cores);
   fprintf(stdout, "Number of CPU threads per core:\t%u\n", nodeinfo.threads);
   fprintf(stdout, "****************************************************\n");
   fprintf(stdout, "id\t名称\t\t状态\n");
   fprintf(stdout, "------------------------------------------\n");
   id = virDomainGetID(dom);
   name = virDomainGetName(dom);
   if (virDomainGetInfo(dom, &info) < 0) {
     error = virGetLastError();
     fprintf(stderr, "virDomainGetInfo failed: %s\n", error->message);
     virFreeError(error);
     return -1;
   }
   fprintf(stdout, "%d\t%s\t\t%d\n", id, name, info.state);
   fprintf(stdout, "****************************************************\n");
   return 0;
}

(2)编译运行

#gcc -g -Wall virtctl.c -o virtctl -lvirt

#./virtctl newlinux status

****************************************************
Connection hostname:	localhost.localdomain
Maximum number of cpus supported on connection:	16
Node free memory:	1381175296
------------------------------------------
Node information from connection
Model:	x86_64
Memory size:	3823996kb
Number of CPUs:	4
MHz of CPUs:	3200
Number of NUMA nodes:	1
Number of CPU sockets:	1
Number of CPU cores per socket:	2
Number of CPU threads per core:	2
****************************************************
id	名称		状态
------------------------------------------
8	newlinux		1
****************************************************

3、virsh命令行管理工具

Libvirt有两种控制方式,命令行和图形界面

(1)图形界面:通过执行名virt-manager,启动libvirt的图形界面,在图形界面下可以一步一步的创建虚拟机,管理虚拟机,还可以直接控制虚拟机的桌面。

(2)virsh所有命令行:

    help            打印帮助
    attach-device   从一个XML文件附加装置
    attach-disk     附加磁盘设备
    attach-interface 获得网络界面
    autostart       自动开始一个域
    capabilities    性能
    cd              change the current directory
    connect         连接(重新连接)到 hypervisor
    console         连接到客户会话
    cpu-baseline    compute baseline CPU
    cpu-compare     compare host CPU with a CPU described by an XML file
    create          从一个 XML 文件创建一个域
    start           开始一个(以前定义的)非活跃的域
    destroy         删除一个域
    detach-device   从一个 XML 文件分离设备
    detach-disk     分离磁盘设备
    detach-interface 分离网络界面
    define          从一个 XML 文件定义(但不开始)一个域
    domid           把一个域名或 UUID 转换为域 id
    domuuid         把一个域名或 id 转换为域 UUID
    dominfo         域信息
    domjobinfo      domain job information
    domjobabort     abort active domain job
    domname         将域 id 或 UUID 转换为域名
    domstate        域状态
    domblkstat      获得域设备块状态
    domifstat       获得域网络接口状态
    dommemstat      get memory statistics for a domain
    domblkinfo      domain block device size information
    domxml-from-native Convert native config to domain XML
    domxml-to-native Convert domain XML to native config
    dumpxml         XML 中的域信息
    edit            编辑某个域的 XML 配置
    find-storage-pool-sources 发现潜在存储池源
    find-storage-pool-sources-as 找到潜在存储池源
    freecell        NUMA可用内存
    hostname        打印管理程序主机名
    list            列出域
    migrate         将域迁移到另一个主机中
    migrate-setmaxdowntime set maximum tolerable downtime
    net-autostart   自动开始网络
    net-create      从一个 XML 文件创建一个网络
    net-define      从一个 XML 文件定义(但不开始)一个网络
    net-destroy     删除一个网络
    net-dumpxml     XML 中的网络信息
    net-edit        为网络编辑 XML 配置
    net-list        列出网络
    net-name        把一个网络UUID 转换为网络名
    net-start       开始一个(以前定义的)不活跃的网络
    net-undefine    取消定义一个非活跃的网络
    net-uuid        把一个网络名转换为网络UUID
    iface-list      list physical host interfaces
    iface-name      convert an interface MAC address to interface name
    iface-mac       convert an interface name to interface MAC address
    iface-dumpxml   interface information in XML
    iface-define    define (but don‘t start) a physical host interface from an XML file
    iface-undefine  undefine a physical host interface (remove it from configuration)
    iface-edit      edit XML configuration for a physical host interface
    iface-start     start a physical host interface (enable it / "if-up")
    iface-destroy   destroy a physical host interface (disable it / "if-down")
    managedsave     managed save of a domain state
    nodeinfo        节点信息
    nodedev-list    这台主机中中的枚举设备
    nodedev-dumpxml XML 中的节点设备详情
    nodedev-dettach dettach node device from its device driver
    nodedev-reattach reattach node device to its device driver
    nodedev-reset   重置节点设备
    nodedev-create  create a device defined by an XML file on the node
    nodedev-destroy destroy a device on the node
    nwfilter-define define or update a network filter from an XML file
    nwfilter-undefine undefine a network filter
    nwfilter-dumpxml network filter information in XML
    nwfilter-list   list network filters
    nwfilter-edit   edit XML configuration for a network filter
    pool-autostart  自动启动某个池
    pool-build      建立池
    pool-create     从一个 XML 文件中创建一个池
    pool-create-as  从一组变量中创建一个池
    pool-define     在一个 XML 文件中定义(但不启动)一个池
    pool-define-as  在一组变量中定义池
    pool-destroy    销毁池
    pool-delete     删除池
    pool-dumpxml    XML 中的池信息
    pool-edit       为存储池编辑 XML 配置
    pool-info       存储池信息
    pool-list       列出池
    pool-name       将池 UUID 转换为池名称
    pool-refresh    刷新池
    pool-start      启动一个(以前定义的)非活跃的池
    pool-undefine   取消定义一个不活跃的池
    pool-uuid       把一个池名称转换为池 UUID
    secret-define   define or modify a secret from an XML file
    secret-dumpxml  secret attributes in XML
    secret-set-value set a secret value
    secret-get-value Output a secret value
    secret-undefine undefine a secret
    secret-list     list secrets
    pwd             print the current directory
    quit            退出这个非交互式终端
    exit            退出这个非交互式终端
    reboot          重新启动一个域
    restore         从一个存在一个文件中的状态恢复一个域
    resume          重新恢复一个域
    save            把一个域的状态保存到一个文件
    schedinfo       显示/设置日程安排变量
    dump            把一个域的内核 dump 到一个文件中以方便分析
    shutdown        关闭一个域
    setmem          改变内存的分配
    setmaxmem       改变最大内存限制值
    setvcpus        改变虚拟 CPU 的号
    suspend         挂起一个域
    ttyconsole      tty 控制台
    undefine        取消定义一个非活跃的域
    update-device   update device from an XML file
    uri             打印管理程序典型的URI
    vol-create      从一个 XML 文件创建一个卷
    vol-create-from create a vol, using another volume as input
    vol-create-as   从一组变量中创建卷
    vol-clone       clone a volume.
    vol-delete      删除卷
    vol-wipe        wipe a vol
    vol-dumpxml     XML 中的卷信息
    vol-info        存储卷信息
    vol-list        列出卷
    vol-pool        returns the storage pool for a given volume key or path
    vol-path        returns the volume path for a given volume name or key
    vol-name        returns the volume name for a given volume key or path
    vol-key         returns the volume key for a given volume name or path
    vcpuinfo        域 vcpu 的信息
    vcpupin         控制域 vcpu affinity
    version         显示版本
    vncdisplay      vnc 显示
    snapshot-create Create a snapshot
    snapshot-current Get the current snapshot
    snapshot-delete Delete a domain snapshot
    snapshot-dumpxml Dump XML for a domain snapshot
    snapshot-list   List snapshots for a domain
    snapshot-revert Revert a domain to a snapshot

其中总结常用的命令:

virsh -c qemu:///system                       #连接本机

virsh -c qemu+ssh://root@192.168.40.125   #连接远程libvirt,也可通过connect命令

virsh list                                                 #显示本地活动虚拟机

virsh list --all                                         #显示本地所有的虚拟机(活动的+不活动的)

virsh define create_kvm.xml              #通过配置文件定义一个虚拟机(这个虚拟机还不是活动的)

virsh start newlinux                             #启动名字为virtual的非活动虚拟机

virsh create create_kvm.xml              # 创建虚拟机(创建后,虚拟机立即执行,成为活动主机)

virsh suspend newlinux                     # 暂停虚拟机

virsh resume newlinux                       # 启动暂停的虚拟机

virsh shutdown newlinux                   # 正常关闭虚拟机

virsh destroy newlinux                       # 强制关闭虚拟机

virsh dominfo newlinux                     #显示虚拟机的基本信息

virsh domname 2                                # 显示id号为2的虚拟机名

virsh domid newlinux                        # 显示虚拟机id号

virsh domuuid newlinux                   # 显示虚拟机的uuid

virsh domstate newlinux                   # 显示虚拟机的当前状态

virsh dumpxml newlinux                   # 显示虚拟机的当前配置文件(可能和定义虚拟机时的配置不同,因为当虚拟机启动时,需要给虚拟机分配id号、uuid、vnc端口号等等)

virsh setmem newlinux 512000      #给不活动虚拟机设置内存大小

virsh setvcpus newlinux 4                # 给不活动虚拟机设置cpu个数

virsh edit newlinux                            # 编辑配置文件(一般是在刚定义完虚拟机之后)

例1:virsh创建kvm虚拟机
#qemu-img create -f qcow2 newlinux.qcow2 15G    //制作虚拟机镜像
#vim create_kvm.xml                        //创建配置文件
#virsh define create_kvm.xml          //创建虚拟机
#virsh start newlinux                        //启动虚拟机
#virsh vncdisplay newlinux            //查看虚拟机的vnc端口,然后就可以通过vnc登录 #vncviewer :0来完成虚拟机的安装
例2:Add CDROM

#virsh attach-disk guest01 /root/disc1.iso hdc --driver file --type cdrom  --mode readonly 

例3:Change CDROM

#virsh attach-disk guest01 /root/disc2.iso hdc --driver file --type cdrom --mode readonly

例4:Remove CDROM

#virsh attach-disk guest01 " " hdc --driver file --type cdrom --mode readonly

三、参考

(1)libvirt官方的APIs列表:http://libvirt.org/html/index.html

(2)网络博客:http://blog.csdn.net/qq250941970/article/details/5989940

(3)libvirt架构及源码分析:http://blog.chinaunix.net/uid-20940095-id-3813601.html

四、总结

(1)Libvirt涉及内容众多,可以先了解qemu-img、virsh、virt-manager、virt-install等工具。

(2)有时间的可以下载开源的Libvirt源码分析,这样对自己的帮助更大。

centos下C编程调用libvirt的API访问KVM虚拟机

上一篇:C#如何控制方法的执行时间,超时则强制退出方法执行


下一篇:C#事务