基于Libvirt的轻量级虚拟机管理(Virsh)

1 .环境介绍

虚拟机软件:Vmware

操作系统:Ubuntu16.04

程序语言:Python

2.实现功能介绍

程序实现了虚拟机的所有基本操作。包括虚拟机的启动、暂停、关闭、重启、强制关机、强制重启、保存等功能。

3.步骤

(1)更新软件


image

(2).进入虚拟机之后需要安装的一些组件:libvirt-bin,libvirt-dev,qemu,virt-manager,python3-libvirt,如图:

image

image
image

image
image

(3)创建虚拟机镜像,镜像和iso文件位置:


image
image

(4)创建**.xml文件,且文件内容如下:


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

  

    ubuntu14                    //虚拟机名称

    1048576                  //最大内存

    1048576    //可用内存

    1                                                      //虚拟cpu个数

    

      hvm

                                                //光盘启动

  

  

    

    

    

  

  

  destroy

  restart

  destroy

  

                    //此处关键,要求libvirt版本至少应该在0.9以上才能

支持,libvirt版本升级http://blog.csdn.net/gg296231363/article/details/6891460

              //目的镜像路径

      

    

    

       //光盘镜像路径

      

    

                                                   //虚拟机网络连接方式



          //为虚拟机分配mac地址,务必唯一,否则dhcp获得同样ip,引起冲突

    

    

    //vnc方式登录,端口号自动分配,自动加1

  


(5)程序代码:

import libvirt
import sys, os
from xml.dom import minidom
from datetime import datetime
import readline

# 连接函数
def lib_connect():
    try:
        conn = libvirt.open('qemu:///system')
    except libvirt.libvirtError:
        print("connect error")
        return 'None'
    return conn


# 列出所有虚拟机状态
def lib_listall(conn):
    domains = conn.listAllDomains()
    print("Id\tName\t\t\t\tState")
    print('-' * 52)
    for domain in domains:
        if domain.ID() == -1:
            Id = '--'
        else:
            Id = str(domain.ID())
        print('%-8s%-32s%s' % (Id, domain.name(), State(domain)))
    print("")


# 列出正在运行的虚拟机
def lib_listisactive(conn):
    domainIDs = conn.listDomainsID()
    print('Id\tName\t\t\t\tState')
    print('-' * 52)
    for domainID in domainIDs:
        dom = conn.lookupByID(domainID)
        print('%-8s%-32s%s' % (dom.ID(), dom.name(), State(dom)))
    print("")


# 定义域函数
def def_Xml(conn, cmd):
    f = open(cmd)
    xmlconfig = f.read()
    f.close()
    if conn == None:
        print('Failed to open connection to qemu:///system', file=sys.stderr)
        return 'Error'
    try:
        dom = conn.defineXML(xmlconfig)
    except libvirt.libvirtError:
        return 'Error'
    if dom == None:
        print('Failed to define a domain from an XML definition.', file=sys.stderr)
        return 'Error'

    print('Guest ' + dom.name() + ' has booted', file=sys.stderr)
    return 'Error'


# 取消定义域
def undef_xml(conn, cmd):
    dom = sel_cmd(conn, cmd)
    if dom == 'None':
        return
    name = dom.name()
    flag = dom.undefine()
    if flag >= 0:
        print(cmd, ' undefined')
    return name


# 查找域
def sel_cmd(conn, cmd):
    CMD = cmd
    try:
        CMD = int(CMD)
    except ValueError:
        CMD = cmd
        try:
            dom = conn.lookupByName(CMD)
        except libvirt.libvirtError:
            return 'None'

    try:
        if type(CMD) == int:
            dom = conn.lookupByID(CMD)
        else:
            pass
    except libvirt.libvirtError:
        return 'Error'
    return dom


# 启动域
def lib_start(conn, cmd):
    dom = sel_cmd(conn, cmd)
    if dom == 'None':
        return
    try:
        flag = dom.create()
    except libvirt.libvirtError:
        return 'Error'
    if flag >= 0:
        print('Domain %s started' % dom.name())


# 关闭域
def lib_shutdown(conn, cmd):
    dom = sel_cmd(conn, cmd)
    if dom == 'None':
        return
    dom.shutdown()
    print('Domain %s is shutting down' % dom.name())


# 销毁域
def lib_destroy(conn, cmd):
    dom = sel_cmd(conn, cmd)
    if dom == 'None':
        return
    dom.destroy()
    print('Domain %s destroyed' % dom.name())


# 暂停域
def lib_pause(conn, cmd):
    dom = sel_cmd(conn, cmd)
    if dom == 'None':
        return
    flag = dom.suspend()
    if flag >= 0:
        print('Domain %s is paused' % dom.name())
#恢复域
def lib_continue(conn, cmd):
        dom = sel_cmd(conn, cmd)
        if dom == 'None':
            return
        flag = dom.resume()
        if flag >= 0:
            print('Domain %s continue' % dom.name())

# 域状态
def State(dom):
    state, reason = dom.state()
    if state == libvirt.VIR_DOMAIN_NOSTATE:
        sta = 'nostate'
    elif state == libvirt.VIR_DOMAIN_RUNNING:
        sta = 'running'
    elif state == libvirt.VIR_DOMAIN_BLOCKED:
        sta = 'blocked'
    elif state == libvirt.VIR_DOMAIN_PAUSED:
        sta = 'paused'
    elif state == libvirt.VIR_DOMAIN_SHUTDOWN:
        sta = 'shutdown'
    elif state == libvirt.VIR_DOMAIN_SHUTOFF:
        sta = 'shut off'
    elif state == libvirt.VIR_DOMAIN_CRASHED:
        sta = 'crashed'
    elif state == libvirt.VIR_DOMAIN_PMSUSPENDED:
        sta = 'pmsuspened'
    else:
        sta = 'unknown'

    return sta


# 保存域状态
def lib_save(conn, cmd, path):
    dom = sel_cmd(conn, cmd)
    if dom == 'None':
        return
    if State(dom) == 'shut off':
        print('guest is not running')
        return
    try:
        path = 'save/' + path
        print(path)
        dom.save(path)
    except libvirt.libvirtError:
        print('Save Error')
        return
    print('save over')


# 创建域函数
def lib_create(conn, cmd):
   # cmd=sel_cmd(conn,cmd)
    f = open(cmd)
    xmlConfig = f.read()
    f.close()
    try:
        dom = conn.createXML(xmlConfig)
    except libvirt.libvirtError:
        return 'Error'
    if dom == None:
        print("Failed to create a domain from an XMLdefinition")
        return 'Error'
    print('Guest' + dom.name() + 'has booted')
    return 'Error'


# 上传镜像
def lib_uploadimg(img, Type):
    if Type == 'linux':
        path = 'img/linux/'
        os.system('cp ' + img + ' ' + path)
        print("上传成功!")
    elif Type == 'windows':
        path = 'img/windows/'
        os.system('cp ' + img + ' ' + path)
        print("上传成功!")
    else:
        print("no such os,please check")


# 删除镜像
def lib_deleteimg(img, Type):
    if Type == 'linux':
        path = 'img/linux/' + img
        os.system('rm ' + path)
    elif Type == 'windows':
        path = 'img/windows/' + img
        os.system('rm ' + path)
    else:
        print('No such img,please check!')

#带参创建虚拟机
def lib_createA(cmd1, cmd2, conn, func):
    f_localpath = os.popen('pwd')
    localpath = f_localpath.read()
    localpath = localpath.strip()
    orign_file = localpath + '/img/' + cmd1 + '/' +cmd2+'.img'
    if cmd2 == 'None':
        bkfile_name = datetime.now().strftime('%Y%m%d_%H%m%S_') + Type[-1] + '.img'
        bkfile_path = localpath + '/guest/'
        bkfile_cmd = 'qemu-img create -f qcow2 ' + bkfile_path + bkfile_name + '10G'
        path_guest = bkfile_path + bkfile_name
        os.system(bkfile_cmd)
    else:
        bkfile_path = localpath + '/img/windows/'
        path_guest = bkfile_path + cmd2+'.img'

    cpuactive = conn.getInfo()[2]
    memactive = int(conn.getInfo()[1])
    while True:
        name = input('Name:')
        cpus = input('CPU(s):')
        mem = input('Memory(MAX)(M):')
        cmem = input('currentMemory(M):')
        if name == '':
            if cmd2 == 'None':
                name = bkfile_name.split('.')[0]
            else:
                name = cmd2.split('.')[0]
        if cpus == '':
            cpus = '1'
        if mem == '':
            mem = '1024'
        if cmem == '':
            cmem = '1024'
        try:
            int(mem);
            int(cmem);
            int(cpus)
        except ValueError:
            print(' Input Wrong')
            continue
        if int(mem) > memactive:
            print('Sorry No Enough Memory!')
            continue
        if int(cpus) > cpuactive:
            print('Sorry No Enough CPUs')
            continue
        print('''
            Name:%s
            CPU(s):%s
            Memory(MAX):%s
            currentMemory:%s
            ''' % (name, cpus, mem, cmem))
        cmd = input('That is OK(Y)?')
        if cmd == 'Y' or cmd == 'y':
            break
    mem = str(int(mem) * 1024)
    cmem = str(int(cmem) * 1024)
    orig_domainfile = 'domainfile/img/demo.xml'
    dom = minidom.parse(orig_domainfile)
    dom_name = dom.getElementsByTagName('name')
    dom_mem = dom.getElementsByTagName('memory')
    dom_curmem = dom.getElementsByTagName('currentMemory')
    dom_vcpu = dom.getElementsByTagName('vcpu')
    dom_name[0].childNodes[0].nodeValue = name
    dom_mem[0].childNodes[0].nodeValue = mem
    dom_curmem[0].childNodes[0].nodeValue = cmem
    dom_vcpu[0].childNodes[0].nodeValue = cpus
    dom_devices = dom.getElementsByTagName('devices')
    dom_disk = dom_devices[0].getElementsByTagName('disk')
    dom_source = dom_disk[0].getElementsByTagName('source')
    dom_source[0].setAttribute('file', path_guest)

    save_domainfile = 'domainfile/img/' + 'demo.xml'
    print(save_domainfile)

    fp = open(save_domainfile, 'w')
    dom.writexml(fp)
    fp.close()

    recv = func['define'](conn, save_domainfile)
    print('Create Over')
#列出镜像
def Imglist():
        F_Buffer = os.popen('ls -l  img')
      #  print(F_Buffer)
        Floders = F_Buffer.readlines()
      #  print(Floders)
        for Floder in Floders:
               if len(Floder.split())>3:
                       print ('')
                       F_name=Floder.split()[-1]
                       print ('%-24s%s'%(F_name,'Size'))
                       print ('-'*52)
                       f_Buffer = os.popen('ls -l img/'+F_name)
                       files = f_Buffer.readlines()
                       print(files)
                       for f in files:
                               if len(f.split())>3:
                                       f_name=f.split()[-1]
                                       f_size=f.split()[4]
                                       f_size=str(int(f_size)/(1024**2))
                                       print ('%-24s%sMB'%(f_name,f_size))
#网络
def net(conn,cmd):
    domName=sel_cmd(conn,cmd)
    if domName == None:
        print('Failed to find the domain ')
        exit(1)
    raw_xml = domName.XMLDesc(0)
    xml = minidom.parseString(raw_xml)
    interfaceTypes = xml.getElementsByTagName('interface')
    for interfaceType in interfaceTypes:
        print('interface: type='+interfaceType.getAttribute('type'))
        interfaceNodes = interfaceType.childNodes
        for interfaceNode in interfaceNodes:
            if interfaceNode.nodeName[0:1] != '#':
                if interfaceNode.nodeName=='source':
                    print(' '+interfaceNode.nodeName)
                for attr in interfaceNode.attributes.keys():
                    if interfaceNode.attributes[attr].name=='network':
                        netwo=input("请输入网络类型:")
                        interfaceNode.attributes[attr].value=netwo
                        print(' '+interfaceNode.attributes[attr].name+' = '+interfaceNode.attributes[attr].value)
                        save_domainfile = '/etc/libvirt/qemu/' + cmd+'.xml'
                        fp = open(save_domainfile, 'w')
                        xml.writexml(fp)
                        fp.close()
    return 'Error'

# 主函数
if __name__ == '__main__':
    conn = lib_connect()
    if conn == 'None':
        sys.exit()
    while True:
        print("****************-虚拟机生命周期管理-*************")
        print("1.定义")
        print("2.取消定义")
        print("3.开始虚拟机")
        print("4关闭虚拟机")
        print("5.暂停虚拟机")
        print("6.恢复虚拟机")
        print("7.保存虚拟机状态")
        print("8.销毁虚拟机")
        print("9.创建虚拟机")
        print("10.带参创建虚拟机")
        print("11.列出活动域")
        print("12.列出全部域")
        print("****************-镜像管理-*************")
        print("13.上传镜像")
        print("14.删除镜像")
        print("15.列出镜像")
        print("****************-网络管理-*************")
        print("16.网络")
        print("quit.退出")
        print("*****************************")
        cmd1 = input("Virsh(控制窗口)").strip()
        cmd = {}
        if cmd1 == '1':
            cmd[0] = 'define'
        if cmd1 == '2':
            cmd[0] = 'undefine'
        if cmd1 == '3':
            cmd[0] = 'start'
        if cmd1 == '4':
            cmd[0] = 'shutdown'
        if cmd1 == '5':
            cmd[0] = 'suspend'
        if cmd1 == '6':
            cmd[0] = 'continue'
        if cmd1 == '7':
            cmd[0] = 'save'
        if cmd1 == '8':
            cmd[0] = 'destroy'
        if cmd1 == '9':
            cmd[0] = 'create'
        if cmd1 == '10':
            cmd[0] = 'createA'
        if cmd1 == '11':
            cmd[0] = 'list'
        if cmd1 == '12':
            cmd[0] = 'list --all'
        if cmd1 == '13':
            cmd[0] = 'uploadimg'
        if cmd1 == '14':
            cmd[0] = 'deleteimg'
        if cmd1 == '15':
            cmd[0] = 'imglist'
        if cmd1 == '16':
            cmd[0] = 'net'
        if cmd1=='quit':
            cmd[0]='quit'
        if cmd[0] == 'define':
            try:
                cmd[1] = input("请输入你要定义的域的名字:")
            except IndexError:
                print("Wrong,please check")
                continue
            def_Xml(conn, cmd[1])
        elif cmd[0] == 'undefine':
            try:
                cmd[1] = input("请输入你要取消哪个域:")
            except IndexError:
                print("Wrong cmd")
                continue
            undef_xml(conn, cmd[1])
        elif cmd[0]=='list --all':
            lib_listall(conn)
        elif cmd[0] == 'list':
            lib_listisactive(conn)
        elif cmd[0] == 'start':
            try:
                cmd[1] = input("请输入开启哪个虚拟机:")
            except IndexError:
                print('Wrong CMD')
                continue

            lib_start(conn, cmd[1])
        elif cmd[0] == 'shutdown':
            try:
                cmd[1] = input("请输入你要关闭的虚拟机:")
            except IndexError:
                print('Wrong CMD')
                continue
            lib_shutdown(conn, cmd[1])
        elif cmd[0] == 'destroy':
            try:
                cmd[1] = input("请输入你要销毁的虚拟机:")
            except IndexError:
                print('Wrong CMD')
                continue
            lib_destroy(conn, cmd[1])
        elif cmd[0] == 'suspend':
            try:
                cmd[1] = input("请输入你要暂停的虚拟机:")
            except IndexError:
                print('Wrong CMD')
                continue
            lib_pause(conn, cmd[1])
        elif cmd[0] == 'quit':
            break
        elif cmd[0] == 'save':
            try:
                cmd[1]=input("请输入你要保存那个虚拟机的状态:")
                cmd[2]=input("请输入你要保存到那个文件里:")
            except IndexError:
                print('Wrong CMD')
                continue
            lib_save(conn, cmd[1], cmd[2])
        elif cmd[0] == 'create':
            try:
                cmd[1]=input("输入你要创建的虚拟机域的路径:")
            except IndexError:
                print('Wrong CMD')
                continue
            lib_create(conn, cmd[1])
        elif cmd[0]=='createA':
            func = {'define': def_Xml, 'start': lib_start}
            cmd[1]=input("请输入你要创建的虚拟机系统类型(linux/windows):")
            cmd[2]=input("请输入你要创建的虚拟机名字:")
            if cmd[2]=='None':
                lib_createA(cmd[1], 'None', conn, func)
            else:
                lib_createA(cmd[1], cmd[2], conn, func)
        elif cmd[0] == 'uploadimg':
            try:
                cmd[2]=input("请输入你要上传的镜像类型:")
                cmd[1]=input("请输入你要上传的虚拟机名字:")
            except IndexError:
                print("Wrong command")
                continue
            lib_uploadimg(cmd[1], cmd[2])
        elif cmd[0] == 'deleteimg':
            try:
                cmd[2] = input("请输入你要删除的镜像类型:")
                cmd[1] = input("请输入你要删除的虚拟机名字:")
            except IndexError:
                print("Wrong command")
                continue
            lib_deleteimg(cmd[1], cmd[2])
        elif cmd[0]=='imglist':
            Imglist()
        elif cmd[0]=='net':
            try:
                cmd[1]=input("输入你要修改那个虚拟机的网络类型:")
            except IndexError:
                print("Wrong cmd")
                continue
            net(conn,cmd[1])
        elif cmd[0] == 'continue':
             try:
                 cmd[1] = input("请输入你要恢复的虚拟机:")
             except IndexError:
                 print('Wrong CMD')
                 continue
             lib_continue(conn, cmd[1])

(6)执行效果图:


image
image
image
image
image
image

你可能感兴趣的:(基于Libvirt的轻量级虚拟机管理(Virsh))