源自我们已经用KVM创建了一个虚拟机,这时你想再创建一个,这当然没有问题,但问题是如果你创建很多个虚拟机,你想对其中的一个进行停止操作,你需要PS下kvm进程,然后再处理,这样我们就想到事情能不能简单一点,谁帮我管理一下这几个破虚拟机好不好。

  先行者们也已经早就想到了,Libvirt就是开源的虚拟机管理程序,当然它支持qemu,xen....

   1. 安装

       ubuntu的世界,安装永远不是问题,apt-get install

   2. 导入我们之前创建的虚拟机

       virt-install --import --name demo3 --ram 512 --disk path=/media/kvm/winxp.img,format=qcow2 

       解释下:--import 是告诉这个工具,镜像我都做好系统了,用kvm启动他就行

                       --name xxx 告诉这个工具,以后这个镜像就叫这个名字了,你想对他做什么,告诉名字就可以

                       --raw 512 虚拟机内存啦

                       --disk path 镜像的地址

                                 format  镜像的格式(libvirt默认是raw,如果不是raw必须要显示指出,否则会报boot失败)

 

  3. 上面的操作就已经将这个虚拟机启动了,并且用virt-viewer打开了

   4. 想管理他是吧,有两个工具

      图形的virt-manager,这个不讲了,点点点

      文本交互的virsh

      virsh  -c kemu:///system

       virsh shutdown demo 关闭虚拟机

   5. Libvirt提供了多种语言绑定开发,C/java/python

---------------------------------------------------------------------

 

一般而言,程序之中最最重要的是数据结构,故而我们从查找核心数据结构开始,但最初的表象切入点是libvirt的交互工具virsh。

 


 

 


  1. 存储池的核心数据结构

          

 

 


·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150


1. typedef struct _virStoragePoolObj virStoragePoolObj;  
2. typedef virStoragePoolObj *virStoragePoolObjPtr;  
3. struct _virStoragePoolObj {  
4. //线程异步锁  
5. char *configFile;                                            //XML文件路径  
6. char *autostartLink;                                       //软链接位置  
7. int active;                                                       //是否激活  
8. int autostart;                                                   //是否自动启用  
9. int asyncjobs;                                 //异步线程号  
10. //当前存储池属性  
11. //新存储池属性  
12. //当前存储池中卷列表  
13. };


 

          其中的virStoragePoolDefPtr类型是存储池属性数据结构

          

 


[c-sharp]   view plain copy


1. typedef struct _virStoragePoolDef virStoragePoolDef;  
2. typedef virStoragePoolDef *virStoragePoolDefPtr;  
3. struct _virStoragePoolDef {  
4. /* General metadata */  
5. char *name;                                                         //存储池的名字  
6. char uuid[VIR_UUID_BUFLEN];     //UUID  
7. int type; /* virStoragePoolType */                      //类型  
8. long long allocation;                            //使用容量大小  
9. long long capacity;                              //全部容量大小  
10. long long available;                             //可用容量大小  
11. //原路径  
12. //目的路径  
13. };

          找到以上两个核心数据结构,就基本上能够了解到如何描述每一个存储池,但是libvirt需要管理的是多个存储池

          这时需要用到结构指针: 理解起来也简单,类似于一个数组, *p[1] 可以找到第二个结构变量

<细节>指针可以用malloc在堆上给他分配几个sizeof()的大小,存放几个结构变量,需要改数量时calloc堆上内存块的大小,根据调整变量的位置,通过memmove移动其他结构变量的位置。

 

          实际使用中,又引入了这个结构体,便于获得到结构指针指向内存区域中结构变量的总个数

          

 


[c-sharp]   view plain copy


1. typedef struct _virStoragePoolObjList virStoragePoolObjList;  
2. typedef virStoragePoolObjList *virStoragePoolObjListPtr;  
3. struct _virStoragePoolObjList {  
4. int count;  
5.     virStoragePoolObjPtr *objs;  
6. }


 

          libvirt.c中conn->storageDriver->pools 就是这个类型的

 

2. 核心业务流程

        表象 -> 细节

        virsh的命令行 -> tools/virsh.c代码 -> src/libvirt.c -> src/storage/storage_dirver.c -> src/storage/storage_backend_XX.c

 

3. 新建存储池类操作

        表象: 支持DIR,FS,NetFS,Logical,Disk,IScsi,Scsi,multipath  (我们实际上只关=心DIR,FS,NetFs,Iscsi)

        细节: DIR,FS,NetFS的卷的一些poolcreate,poolstart等需要实际跟操作系统打交道的功能是走的storage_backend_fs.c这个后端

                     同样的Logical,Disk,Iscsi,Scsi,mpath都有各自的后端

 

pool-define

                                                 XML描述格式,我们只关心DIR,Fs,NetFs,Iscsi几种

                                                 DIR:

                                                

 


[c-sharp]   view plain copy


1. <pool type="dir">  
2.     <name>virtimages</name>  
3.     <target>  
4.         <path>/var/lib/virt/images</path>  
5.     </target>  
6. </pool>


 

                                                 Fs:

                                                

 


[c-sharp]   view plain copy


1. <pool type="fs">  
2.     <name>virtimages</name>  
3.     <source>  
4. "/dev/VolGroup00/VirtImages"/>  
5.     </source>  
6.     <target>  
7.         <path>/var/lib/virt/images</path>  
8.     </target>  
9. </pool>

                 NetFs:

                                                

 


[c-sharp]   view plain copy

1. <pool type="netfs">  
2.     <name>virtimages</name>  
3.     <source>  
4. "nfs.example.com"/>  
5. "/var/lib/virt/images"/>  
6.     </source>  
7.     <target>  
8.         <path>/var/lib/virt/images</path>  
9.     </target>  
10. </pool>

                                                 Iscsi:  这里path不指明一个固定的块设备,是因为物理机硬盘数的不确定性

                                                

 


[c-sharp]   view plain copy


1. <pool type="iscsi">  
2.     <name>virtimages</name>  
3.     <source>  
4. "iscsi.example.com"/>  
5. "demo-target"/>  
6.     </source>  
7.     <target>  
8.         <path>/dev/disk/by-path</path>  
9.     </target>  
10. </pool>

 命令使用:

                                virsh> pool-define /tmp/default.xml


                          <细节> pool-define 只是把你要加入到存储池大家庭的这个存储池介绍给libvirt认识,他只看到的你的外表而已,不追究你的内在存不存在,但是你在libvirt那里已经挂上号了,pool-list --all 就能看到你,你是inactive的

                                        代码:src/storage/storage_driver.c的storagePoolDefine函数中做以下几个事情:

                                                     * 读入xml信息 --virStoragePoolDefParseString

                                                     * 按读入的xml的name和uuid 信息判断是否在driver-pools重复存在 --virStoragePoolObjIsDuplicate

按读入的xml的type 判断类型写入dep->type --virStorageBackendForType

扩展分配结构指针的的大小 calloc +1 并且driver->pools->count +1

dirver->pools->obj[dirver->pools->count] = pool (这个是传入的xml构建的) --virStoragePoolObjAssignDef

将存储池信息保存到指定配置文件位置,如果autostart==1,做软连接存储信息均为0 -virStoragePoolDefFormat 构建xml --virStoragePoolObjSaveDef 保存xml

                                                    * 向hypervisor connection注册存储池,加入到HashTable里 --virGetStoragePool


pool-define-as

                                                    他有个重要的选项 --print-xml 可以看到你输入的参数构成的XML,对照出那个参数传入的不对应。

                           命令使用: virsh> pool-define-as test, 0,0,0,0,/tmp/test                       


pool-build

                           命令使用: virsh> pool-build test


pool-start

                          命令使用:virsh> pool-start test


                           <细节>          一方面修改核心数据结构中变量的active参数,另一方面做一些二道贩子的事,如

                                                  dir/fs/netfs类型 脚本执行 mount/mount.nfs

                                                  iscsi  脚本执行iscsiadm XXXXX --login

                                                  执行上面命令后,回调用refresh_pool的函数,获取pool的容量信息,并存入核心数据结构变量中

                           

pool-create

                          命令使用:virsh>pool-create /tmp/example.xml


pool-create-as


                                                    他有个重要的选项 --print-xml 可以看到你输入的参数构成的XML,对照出那个参数传入的不对应。

                         命令使用:virsh>pool-create-as test, 0,0,0,0,/tmp/test


4. 删除/停止存储池类操作

pool-destory

                        命令使用: virsh>pool-destory test

                        <细节>        改变核心数据结构变量的active的值为0

                                             后端处理不同 fs,netfs 分别执行 umount / umount.nfs

iscsi来说就是iscsiadm xxxxx --logout

     

pool-delete

                       命令使用:virsh>pool-delete test

                       <细节>         后端调用 rm -f 这个脚本命令


pool-undefine

                       命令使用; virsh>pool-undefine test

                       <细节>         src/storage/storage_driver.c storagePoolUndefine函数,做了这么几件事

                                             * 判断pool是否存在于关键数据结构列表中

                                             * 判断是否为inactive

                                             * 判断是否没有异步线程

unlink(ConfigureFile),删除xml文件 --virStoragePoolObjDeleteDef

不论是否为autostart,删除软连接 --unlink

释放结构指针多余内存,count -1,调整结构指针大小 --virStoragePoolObjRemove


5. 修改存储池类操作

pool-edit 

                       命令使用: virsh>pool-edit test


6. 查询存储池类操作

     <十一> virsh pool-dumpxml

                       命令使用: virsh>pool-dumpxml test

                       <细节>        virStoragePoolDefFormat函数


     <十二> pool-list

                       命令使用: virsh>pool-list --all

                       <细节>        先通过pools->count 得到总数量,根据条件遍历出active 数量

                                           再遍历pools,得到name等的数组,按字母顺序排序


     <十三> pool-info

激活的显示name,uuid,state,autostart,presistent和容量信息

非激活的显示 name,uuid,state,autostart,presistent信息

                        命令使用: virsh>pool-info test

virStoragePoolGetInfo函数得到信息


     <十四> pool-refresh  virsh命令之一,刷新存储池,是个异步任务,先清空当前volumes列表,后端执行refreshPool 更新volumes列表,更新pool的容量信息

                         命令使用: pool-refresh