python2.7管理kvm虚拟主机


说明:

  • 脚本是基于 python 2.7.5 版本调试
  • 脚本使用到 libvirt 库,请安装好相应的库

依赖库

检查 libvirt

[root@localhost ~]# python
Python 2.7.5 (default, Oct 30 2018, 23:45:53) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-36)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import libvirt
>>> 

由与上述不一样,请安装好下面两个包即可

[root@localhost ~]# rpm -qa epel-release libvirt-python
epel-release-7-14.noarch
libvirt-python-4.5.0-1.el7.x86_64

python代码

#!/usr/bin/python
# coding=utf-8
import time
import libvirt
import getopt
import os
import sys

# 克隆主机的模板
## 通常启动所有主机时, 是不启动模板机的.
Template_name="CentOS7"

# 脚本使用参数指南
def help():
    print('''
    Usage:
        python test.py [-o operate] [-n vmnames] [-c cloneName] [-l list]

    -o operate: Operation of kvm virtual host, such as start, stop, restart, delete, clone..
    -n vmnames: The kvm virtual host being operated, Separate multiple hosts with commas
    -c cloneName: The parameters of the clone host must be used with the -o clone option and the -n parameter can only specify one host
    -l list: View the running status of all kvm virtual machines on the machine
    --ip: View all started kvm virtual host IP addresses

    Example:
      # Start multiple kvm virtual hosts
      kvmmanage -o start -n test01,test02

      # Shut down all kvm virtual hosts
      kvmmanage -o stop -n all

      # Quickly create kvm virtual host
      kvmmanage -o clone -n CentOS7 -c test01

      # delete kvm virtual host
      kvmmanage -o delete -n test01

      # View all started kvm virtual host IP addresses
      kvmmanage --ip
    ''')
    sys.exit()


# python脚本参数
def option(argv):
    operate = cloneName = ''
    vmnames = []
    try:
        opts, args = getopt.getopt(argv, "ho:n:c:l", ["help", "operate=", "vmnames=", "cloneName=", "list", "ip"])
    except getopt.GetoptError:
        help()
    for opt, arg in opts:
        if opt in ('-h', '--help'):
            help()
        elif opt in ("-o", "--operate"):
            operate = arg
        elif opt in ("-n", "--vmnames"):
            vmnames = arg.split(",")
        elif opt in ("-c", "--cloneName"):
            cloneName = arg
        elif opt in ("-l", "--list"):
            conn = createConnection()
            down_vm_list_name, up_vm_list_name = getStatusDomainName(conn)
            print("未启动虚拟主机: %s" % down_vm_list_name)
            print("已启动虚拟主机: %s" % up_vm_list_name)
            closeConnection(conn)
        elif opt == '--ip':
            conn = createConnection()
            down_vm_list_name, up_vm_list_name = getStatusDomainName(conn)
            if len(up_vm_list_name) != 0:
                vmnames_obj = getDomInfoByName(conn, up_vm_list_name)
                vmnames_ip = getDomainIP(conn, vmnames_obj)
                star = "*"
                print("%skvm虚拟主机对应的IP地址%s" % (star * 8, star * 8))
                for hostname, ip in dict(zip(up_vm_list_name, vmnames_ip)).items():
                    print("%15s: %s" % (hostname, ip))
                print(star * 39)
            else:
                print("All kvm virtual hosts are not started")
            closeConnection(conn)

    check_option(operate, vmnames, cloneName, args)
    return operate, vmnames, cloneName


# 检查命令参数
def check_option(operate, vmnames, cloneName, args):
    if args != []:
        help()
    elif operate == "" or vmnames == []:
        print("\033[1;31m[ERROR]\033[0m Except the parameters are list, help, the operation and vmnames parameters cannot be missing in other cases.\n")
        sys.exit()
    elif operate == "delete":
        warn = raw_input("[Dangerous operation] Are you sure you want to delete the kvm virtual machine? [y/n]: ").strip()
        if warn in ["y", "Y"]:
            pass
    elif operate == 'clone':
        if cloneName == "" or len(vmnames) != 1:
            print("\033[1;31m[ERROR]\033[0m When the -o clone parameter is used, the name of the new clone kvm virtual host must be specified with -c and the -n parameter can only specify one kvm virtual host name")
            sys.exit()
    elif "all" in vmnames:
        if operate not in ["restart", "stop", "start"]:
            print("\033[1;31m[ERROR]\033[0m When -n is specified as all, -o can only specify the operations of start, stop, restart\n")
            sys.exit()
        elif len(vmnames) != 1:
            print("\033[1;31m[ERROR]\033[0m When -n contains all, then -n cannot have other kvm virtual hosts\n")
            sys.exit()


# 创建 kvm 连接
def createConnection():
    try:
        conn = libvirt.open(None)
        print("---Successfully opened connection to hypervisor---")
    except Exception as e:
        print(e)
    else:
        return conn


# 关闭 kvm 连接
def closeConnection(conn):
    try:
        conn.close()
        print("---Successfully closed the hypervisor connection---")
    except Exception as e:
        print(e)

    print("\n本次操作耗时 %.3f 秒" % (time.time() - t1))
    sys.exit()


# 查看本机所有 kvm 虚拟主机运行情况
def getStatusDomainName(conn):
    up_vm_list_id = conn.listDomainsID()
    up_vm_list_name = []
    for st_vm in up_vm_list_id:
        up_vm_list_name.append(conn.lookupByID(st_vm).name())

    down_vm_list_id = conn.listDefinedDomains()
    down_vm_list_name = []
    for sd_vm in down_vm_list_id:
        down_vm_list_name.append(conn.lookupByName(sd_vm).name())

    return down_vm_list_name, up_vm_list_name


# 操作 kvm 虚拟主机的对象
def getDomInfoByName(conn, vmnames, operate=None):
    domain = ''
    domains = []
    if vmnames[0] == "all" and len(vmnames) == 1:
        down_vm_list_name, up_vm_list_name = getStatusDomainName(conn)
        if operate in ["stop", "restart"]:
            vmnames = up_vm_list_name
        elif operate == "start":
            down_vm_list_name.remove(Template_name)
            vmnames = down_vm_list_name
    for vmname in vmnames:
        try:
            domain = conn.lookupByName(vmname)
            domains.append(domain)
        except Exception as e:
            print(e)
            closeConnection(conn)
    return domains


# 获取kvm虚拟主机IP地址
def getDomainIP(conn, vmnames_obj):
    vmnames_ip = []
    for vmname_obj in vmnames_obj:
        try:
            ifaces = vmname_obj.interfaceAddresses(libvirt.VIR_DOMAIN_INTERFACE_ADDRESSES_SRC_AGENT, 0)
        except Exception as e:
            print(e)
            print("\033[1;31m[ERROR]\033[0m Failed to connect to the kvm virtual host, it may not be fully booted.")
            closeConnection(conn)

        for key, value in ifaces.items():
            if key == "lo":
                continue
            else:
                try:
                    for ip in value["addrs"]:
                        if ip["prefix"] == 24:
                            if ip["addr"] == '':
                                vmnames_ip.append(ip["None"])
                            else:
                                vmnames_ip.append(ip["addr"])
                except Exception as e:
                    print(e)
                    print("\033[1;31m[ERROR]\033[0m Failed to obtain the IP network card information of the kvm virtual host, it may be that the network is not started normally. Please try again later...")
                    closeConnection(conn)

    return vmnames_ip


# 操作kvm虚拟主机的方法
def manageVM(vms, operate, *args):
    for vm in vms:
        try:
            if operate == "start":
                vm.create()
            elif operate == "stop":
                vm.destroy()
            elif operate == "restart":
                vm.reboot()
            elif operate == "clone" and args != "":
                cvms = args[0].split(",")
                for cvm in cvms:
                    clone_cmd = "virt-clone -o %s -n %s -f /var/lib/libvirt/images/%s.qcow2" % (vm.name(), cvm, cvm)
                    if os.system(clone_cmd) != 0:
                        closeConnection(conn)
            elif operate == "delete":
                delete_cmd = '''virsh undefine %s && rm -rf /var/lib/libvirt/images/%s.qcow2''' % (vm.name(), vm.name())
                print("[CMD] %s" % delete_cmd)
                if os.system(delete_cmd) != 0:
                    closeConnection(conn)
            else:
                print("[ERROR] %s 操作类型不正确" % operate)
                closeConnection(conn)
        except Exception as e:
            print(e)
            closeConnection(conn)


if __name__ == '__main__':
    t1 = time.time()
    if len(sys.argv) == 1:
        help()
    operate, vmnames, cloneName = option(sys.argv[1:])
    conn = createConnection()
    domains_obj = getDomInfoByName(conn, vmnames, operate)
    manageVM(domains_obj, operate, cloneName)
    if operate == "clone":
        print("%s 克隆完成, 新的 kvm 虚拟机主机为 %s." % (vmnames[0], cloneName.split(",")))
    elif vmnames[0] == "all":
        print("所有kvm虚拟主机操作完成~~")
    else:
        print("%s kvm 虚拟主机 %s 操作完成~~~" % (vmnames, operate))
    closeConnection(conn)