基于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文件,且文件内容如下:


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

  <domain type='kvm'>

    <name>ubuntu14</name>                    //虚拟机名称

    <memory>1048576</memory>                  //最大内存

    <currentMemory>1048576</currentMemory>    //可用内存

    <vcpu>1</vcpu>                                                      //虚拟cpu个数

    <os>

      <type arch='x86_64' machine='pc'>hvm</type>

      <boot dev='cdrom'/>                                          //光盘启动

  </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>

    <disk type='file' device='disk'>    <driver name='qemu' type='qcow2'/>            //此处关键,要求libvirt版本至少应该在0.9以上才能

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

      <source file='/var/lib/libvirt/images/ubuntu14.qcow2'/>        //目的镜像路径

      <target dev='hda' bus='ide'/>

    </disk>

    <disk type='file' device='cdrom'>

      <source file='/var/lib/libvirt/images/ubuntu-14.04.5-server-amd64.iso'/> //光盘镜像路径

      <target dev='hdb' bus='ide'/>

    </disk>

    <interface type='network'>                                               //虚拟机网络连接方式

<source network='default'/>

      <mac address="00:16:3e:5d:aa:a8"/>    //为虚拟机分配mac地址,务必唯一,否则dhcp获得同样ip,引起冲突

    </interface>

    <input type='mouse' bus='ps2'/>

    <graphics type='vnc' port='-1' autoport='yes' listen = '0.0.0.0' keymap='en-us'/>//vnc方式登录,端口号自动分配,自动加1

  </devices>

</domain>

(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
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343

推荐阅读更多精彩内容