在Linux上使用 Python2 统计显示 KVM 各虚拟机 CPU、内存、磁盘的使用信息及汇总统计后计算剩余可用资源信息

# 系统 CentOS 7.x
# KVM yum 安装的
# 脚本 系统自带的 Python2

 

#!/usr/bin/python
#_*_ coding:utf8 _*_

# V 1.3
# CentOS 7.x
# yum 安装的 KVM
# 系统自带的 Python2

import commands
import sys
import os
import re
import xml.etree.ElementTree as ET
Dir_VM_XML = '/etc/libvirt/qemu'


def VM_INFO(F_XML):
    tree = ET.ElementTree(file=F_XML)   # 读取xml文件
    root = tree.getroot()               # 根
    D = {}
    L_VM_DISK_FILE = []
    for i in root:
        #print("i.tag", i.tag)           # 标签名
        #print("i.attrib", i.attrib)     # 标签说明(字典形式)
        #print("i.text", i.text)         # 标签值
        if i.tag == 'name':
            D['NAME'] = i.text
        elif i.tag == 'memory':
            D['MEM'] = [int(i.text), i.attrib['unit']]
        elif i.tag == 'vcpu':
            D['VCPU'] = int(i.text)
        elif i.tag == 'devices':
            D['NET_INT'] = []
            D['DISK_FILE'] = []
            for ii in i:                    ## 继续查找下一级标签
                if ii.tag == 'disk':
                    D_disk = ii.attrib
                    if D_disk['device'] == 'disk':          # <disk type='file' device='disk'>
                        for iii in ii:                      ## 继续查找下一级标签
                            if iii.tag == 'source':
                                D['DISK_FILE'].append(iii.attrib['file'])
                                L_VM_DISK_FILE.append(iii.attrib['file'])
                elif ii.tag == 'graphics':
                    if ii.attrib['type'] == 'vnc':
                        VNC_IP = ii.attrib['listen']
                        if ii.attrib['autoport'] == 'no':
                            VNC_PORT = ii.attrib['port']
                        else:
                            VNC_PORT = 'Unknown'
                        D['VNC'] = VNC_IP + ':' + VNC_PORT
                    else:
                        D['VNC'] = 'NOT FIND'
                elif ii.tag == 'interface':
                    #print("ii tag, attr, text", ii.tag, ii.attrib, ii.text)
                    D_NET = ii.attrib
                    for iii in ii:
                        if iii.tag == 'mac':
                            D['NET_INT'].append(iii.attrib['address'])
                            #print("iii tag, attr, text", iii.tag, iii.attrib, iii.text)
    L_DISK_VS_DS = VM_DISK_INFO(L_VM_DISK_FILE)
    D['DISK_SIZE'] = L_DISK_VS_DS
    return(D)


## 累计单个虚拟机全磁盘的分配空间及当前实际使用空间
def VM_DISK_INFO(L_VM_DISK_FILE):
    VM_TOT_DISK_VS = 0
    VM_TOT_DISK_DS = 0
    D = {}
    for VM_DISK_FILE in L_VM_DISK_FILE:
        CMD = 'qemu-img info ' + VM_DISK_FILE
        (ST,OP) = commands.getstatusoutput(CMD)
        if ST == 0:
            RE_X = '(virtual size(.*))|(disk size(.*))'
            R = re.finditer(RE_X, OP)
            L_DiskSize = [i.group() for i in R]
            for DiskSize in L_DiskSize:
                #print DiskSize                     # virtual size: 200G (214748364800 bytes) 或者 disk size: 1.4G
                SP = DiskSize.split(':')
                #print SP
                K = SP[0]
                V = SP[1]
                if K == 'virtual size':             ## 分配磁盘空间大小
                    RE_search = re.search('[0-9]+ bytes', V)    # 从 ' 200G (214748364800 bytes)' 中提取:1个及以上数字+空格+bytes 的字符串,如 '214748364800 bytes'
                    if RE_search:
                        SIZE = float(RE_search.group().split()[0])/1024/1024/1024   # bytes 转成 GB 单位(并转成浮点类型数值)
                        VM_TOT_DISK_VS += SIZE
                    else:
                        print "提取 virtual size 的 bytes 数值失败,先忽略(不计入硬盘总分配空间)", VM_DISK_FILE, DiskSize
                elif K == 'disk size':              ## 当前实际使用磁盘空间大小
                    RE_search = re.search('B|K|M|G|T|P', V)    # 从 ': 1.4G' 中提取:B K M G T P
                    if RE_search:
                        if RE_search.group() == 'B':
                            SIZE = float(V.split(RE_search.group())[0])/1024/1024/1024
                        if RE_search.group() == 'K':
                            SIZE = float(V.split(RE_search.group())[0])/1024/1024
                        elif RE_search.group() == 'M':
                            SIZE = float(V.split(RE_search.group())[0])/1024
                        elif RE_search.group() == 'G':
                            SIZE = float(V.split(RE_search.group())[0])
                        elif RE_search.group() == 'T':
                            SIZE = float(V.split(RE_search.group())[0])*1024
                        elif RE_search.group() == 'P':
                            SIZE = float(V.split(RE_search.group())[0])*1024*1024
                        else:
                            SIZE = 0
                            print "识别 disk size 单位失败,先忽略(不计入硬盘总分配空间)", VM_DISK_FILE, DiskSize
                        VM_TOT_DISK_DS += SIZE
                    else:
                        print "识别 disk size 的数值失败,先忽略(不计入硬盘总分配空间)", VM_DISK_FILE, DiskSize
                else:
                    print "WARNING RE过滤结果有多余内容", DiskSize
        else:
            print "ERROR 执行命令", CMD, "失败", OP
    D['TOT_VS'] = VM_TOT_DISK_VS
    D['TOT_DS'] = VM_TOT_DISK_DS
    return(D)


## 宿主机ARP表转成MAC为KEY,IP为Value的字典
D_MAC_IP = {}
def DEF_D_MAC_IP():
    CMD = "arp -n"
    (S,O) = commands.getstatusoutput(CMD)
    if S == 0:
        L_ARP = O.split('\n')       # 命令回显内容以换行符合分割做成列表
        if len(L_ARP) > 1:
           for i in L_ARP[1:]:
               ARP = i.split()
               IP = ARP[0]
               MAC = ARP[2]
               if MAC in D_MAC_IP:
                   D_MAC_IP[MAC].append(IP)
               else:
                   D_MAC_IP[MAC] = [IP]
DEF_D_MAC_IP()
#print(D_MAC_IP)


## 显示程序帮助信息
def HELP_PRINT():
    print "可以接受一个参数,控制显示内容"
    print sys.argv[0], 't : 不显示各虚拟机详细信息,只显示统计信息'
    print sys.argv[0], 'n : 显示各虚拟机网络信息及统计信息'
    print sys.argv[0], 's : 显示各虚拟机配置信息及统计信息'


if len(sys.argv) == 1: # 没有参数
    HELP_PRINT()
    print "没有参数,使用默认显示"
    SET_SHOW = 'ALL_INFO'
elif len(sys.argv) == 2:
    if sys.argv[1] in ['t', 'tot']:
        SET_SHOW = 'TOT_INFO'
    elif sys.argv[1] in ['n', 'net']:
        SET_SHOW = 'NET_INFO'
    elif sys.argv[1] in ['s', 'sys']:
        SET_SHOW = 'SYS_INFO'
    else:
        HELP_PRINT()
        print "参数错误,使用默认设置,显示全部内容"
        SET_SHOW = 'ALL_INFO'
else:
    HELP_PRINT()
    print "参数过多,使用默认显示"
    SET_SHOW = 'ALL_INFO'

#print SET_SHOW

L_XML = []

L_Dir_File = os.listdir(Dir_VM_XML)
#print L_Dir_File
for F in L_Dir_File:
    F_FULLNAME = Dir_VM_XML+'/'+F
    if os.path.isfile(F_FULLNAME):
        L_XML.append(F_FULLNAME)

#print L_XML

L_D_VM_INFO = []
for i in L_XML:
    D_VM_INFO = VM_INFO(i)
    #print(D_VM_INFO)
    L_D_VM_INFO.append(D_VM_INFO)

#print(L_D_VM_INFO)



## 统计全部虚拟机的资源使用
VMs_TOT_MEM = 0
VMs_TOT_CPU = 0
VMs_TOT_DISK_VS = 0
VMs_TOT_DISK_DS = 0
for i in L_D_VM_INFO:
    VMs_TOT_MEM += i['MEM'][0]
    VMs_TOT_CPU += i['VCPU']
    VMs_TOT_DISK_VS += i['DISK_SIZE']['TOT_VS']
    VMs_TOT_DISK_DS += i['DISK_SIZE']['TOT_DS']



## 获取KVM 宿主机自身 CPU MEM 信息
KVM_MEM = 0
CMD = "/usr/bin/free | /usr/bin/grep Mem | awk '{print $2}'"
(S,O) = commands.getstatusoutput(CMD)
if S == 0:
    KVM_MEM += int(O)

KVM_CPU = 0
CMD = 'cat /proc/cpuinfo| grep "processor"| wc -l'
(S,O) = commands.getstatusoutput(CMD)
if S == 0:
    KVM_CPU += int(O)


## 获取各虚拟机的运行状态
(status,output) = commands.getstatusoutput('virsh list --all')
#print status
#print output
L_VMs_RUN = []
L_VMs_STOP = []
L_VMs_DEFINE = []
if status == 0:
    L_output = output.split('\n')
    #print L_output[2:-1]
    for VM_STATUS in L_output[2:-1]:
        #print VM_STATUS.split()
        SP = VM_STATUS.split()
        NAME = SP[1]
        STATUS = SP[2]
        L_VMs_DEFINE.append(NAME)
        if STATUS == 'running':
            L_VMs_RUN.append(NAME)
        else:
            L_VMs_STOP.append(NAME)

#print "DEFINE", L_VMs_DEFINE
#print "RUN", L_VMs_RUN
#print "STOP", L_VMs_STOP


## 统计全部运行中的虚拟机的资源使用
VMs_RUN_TOT_MEM = 0
VMs_RUN_TOT_CPU = 0
VMs_RUN_TOT_DISK_VS = 0
VMs_RUN_TOT_DISK_DS = 0
for i in L_D_VM_INFO:
    if i['NAME'] in L_VMs_RUN:
        VMs_RUN_TOT_MEM += i['MEM'][0]
        VMs_RUN_TOT_CPU += i['VCPU']
        VMs_RUN_TOT_DISK_VS += i['DISK_SIZE']['TOT_VS']
        VMs_RUN_TOT_DISK_DS += i['DISK_SIZE']['TOT_DS']



## 统计结果打印
print "=== VMs ==="
for i in L_D_VM_INFO:
    VM_MAC = 'NET:'
    for j in i['NET_INT']:
        if j in D_MAC_IP:
            VM_MAC += '[%s - %s]' % (j, D_MAC_IP[j])
        else:
            VM_MAC += '[%s - noARP]' % j
    VM_VNC = 'VMC:' + i['VNC']
    #VM_NAME = 'NAME:' + i['NAME']
    VM_NET_INFO = '%s | %s |' % (VM_MAC, VM_VNC)

    VM_CPU = 'VCPUs:%d' % i['VCPU']
    VM_MEM = 'MEM:%d%s' % (i['MEM'][0], i['MEM'][1])
    VM_DISK = 'DISK:%d/%dGB' % (i['DISK_SIZE']['TOT_DS'], i['DISK_SIZE']['TOT_VS'])
    VM_DISK_FILE = 'DISK_FILEs:%s' % i['DISK_FILE']
    VM_SYS_INFO = '%s | %s | %s | %s |' % (VM_CPU, VM_MEM, VM_DISK, VM_DISK_FILE)

    #print "VM_NET_INFO", VM_NET_INFO
    #print "VM_SYS_INFO", VM_SYS_INFO

    if i['NAME'] in L_VMs_RUN:
        print "RUN  |",
        if SET_SHOW == 'NET_INFO':
            print VM_NET_INFO, i['NAME']
        elif SET_SHOW == 'SYS_INFO':
            print VM_SYS_INFO, i['NAME']
        elif SET_SHOW == 'TOT_INFO':
            print i['NAME']
        else:
            print i['NAME']
            print "\t\t", VM_NET_INFO
            print "\t\t", VM_SYS_INFO
            print ""
    elif i['NAME'] in L_VMs_STOP:
        print "STOP |",
        if SET_SHOW == 'NET_INFO':
            print VM_NET_INFO, i['NAME']
        elif SET_SHOW == 'SYS_INFO':
            print VM_SYS_INFO, i['NAME']
        elif SET_SHOW == 'TOT_INFO':
            print i['NAME']
        else:
            print i['NAME']
            print "\t\t", VM_NET_INFO
            print "\t\t", VM_SYS_INFO
            print ""
    else:
        print "WARNING undefine VM", i, i['NAME']
print "==="

print "=== ALL VMs 全虚拟机统计 ==="
print "CPU : 总可用数量     %d, 已分配 %d, 剩余可分配 %d" % (KVM_CPU, VMs_TOT_CPU, KVM_CPU - VMs_TOT_CPU)
print "MEM : 总可用内存(GB) %d, 已分配 %d, 剩余可分配 %d" % ((KVM_MEM/1024/1024), VMs_TOT_MEM/1024/1024, (KVM_MEM - VMs_TOT_MEM)/1024/1024)
print "DISK: 总分配(GB)     %d, 实际使用 %d" % (VMs_TOT_DISK_VS, round(VMs_TOT_DISK_DS, 2))
print "==="
print "=== RUN VMs 只统计运行中的虚拟机 ==="
print "CPU : 总可用数量     %d, 已分配 %d, 剩余可分配 %d" % (KVM_CPU, VMs_RUN_TOT_CPU, KVM_CPU - VMs_RUN_TOT_CPU)
print "MEM : 总可用内存(GB) %d, 已分配 %d, 剩余可分配 %d" % ((KVM_MEM/1024/1024), VMs_RUN_TOT_MEM/1024/1024, (KVM_MEM - VMs_RUN_TOT_MEM)/1024/1024)
print "DISK: 总分配(GB)     %d, 实际使用 %d" % (VMs_RUN_TOT_DISK_VS, round(VMs_RUN_TOT_DISK_DS, 2))
print "==="

 

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐