zoukankan      html  css  js  c++  java
  • 检测openstack云平台是否存在脑裂的虚拟机,加入zabbix告警

               在openstack运维中,有时会遇到虚拟机热迁移,evacuate等操作中,发生虚拟机脑裂的情况,即同一个虚拟机同时在两个hypervisor上面运行,在使用ceph等共享存储时,十有八九会造成虚拟机文件系统损伤,运气好的情况下能修复文件系统错误,重则数据混乱,虚拟机无法启动.为此,我写了一个Python脚本,用于检测openstack的hypervisor(KVM)是否存在脑裂虚拟机,其原理是通过libvirt的API,获取hypervisor上面的虚拟机的名字,比较是否不同的hypervisor上面有相同的虚拟机名字.脚本需要在控制节点运行(需要openrc的环境变量文件),且该控制节点与计算节点打通了ssh秘钥验证,/etc/hosts解析所有hypervisor的主机名.笔者测试在liberty版本和Mitika能正常运行.

    2018年10月25日更新:

    1. 脚本内容变更如下

    import re
    import os
    import libvirt
    import json
    from novaclient import client
    from multiprocessing import Pool,Queue
    from collections import Counter,defaultdict

    q=Queue()
    EnvFile='/root/openrc'

    def get_nova_creds():
        d={}
        pattern_save=re.compile(r'^export.*=.*')
        pattern_split=re.compile(r'=')
        with open(EnvFile,'r') as f:
            for i in f.readlines():
                match=pattern_save.search(i)
                if match:
                    temp_str = match.group(0).strip("export").strip()
                    environ_value_dic = pattern_split.split(temp_str)
                    os.environ[environ_value_dic[0]] = environ_value_dic[1].strip("'")
        d['username'] = os.environ['OS_USERNAME']
        d['api_key'] = os.environ['OS_PASSWORD']
        d['auth_url'] = os.environ['OS_AUTH_URL']
        d['project_id'] = os.environ['OS_TENANT_NAME']
        d['region_name']= os.environ['OS_REGION_NAME']
        return d

    def getHypervisor():
        HypervisorHostname = []
        pattern = re.compile(r'node-d.domain.tld')
        creds = get_nova_creds()
        nova = client.Client('2', **creds)
        for i in nova.hypervisors.list():
            match = pattern.search(i.hypervisor_hostname)
            if match:
                HypervisorHostname.append(match.group())
        return  HypervisorHostname

    def getVM(node):
        try:
            virtcon=libvirt.open("qemu+ssh://%s/system" %node)
        except libvirt.libvirtError,e:
            print "wrong to connect %s libvirt api" %node+' '+str(e)    #增加无法连接计算节点libvirt情况下错误输出
        for id  in virtcon.listDomainsID():
            vminfo=virtcon.lookupByID(id)
            if vminfo.state(0)[0]==libvirt.VIR_DOMAIN_RUNNING:     #增加判断,只把running状态的虚拟机放入Queue命令
                q.put((node,vminfo.name()))
        virtcon.close()

    def getVMList():
        InstanceNameList=[]
        # a=getHypervisor()
        # HyperDict = {}.fromkeys(a, [])
        HyperDict=defaultdict(list)
        while not q.empty():
            node,vm=q.get()
            InstanceNameList.append(vm)
            HyperDict[node].append(vm)
        return InstanceNameList,HyperDict

    def VMSplitCheck(instancelist,nodedict):
        SplitList=[]
        SplitDict=defaultdict(list)
        c=Counter(instancelist)
        for k,v in c.iteritems():
            if v>=2:
                SplitList.append(k)
        if len(SplitList)!=0:
           for i in SplitList:
               for k,v in nodedict.iteritems():
                   if i in v:
                       SplitDict[i].append(k)
        return SplitDict

    def main():
        hypername=getHypervisor()
        p=Pool()
        for i in hypername:
            p.apply_async(getVM,args=(i,))
        p.close()
        p.join()

        inslist,hydict=getVMList()
        vmsplit=VMSplitCheck(inslist,hydict)
        if len(vmsplit)!=0:
            print "found_split_vm"+":"+json.dumps(vmsplit)    #只在发现脑裂虚拟机情况下输出文本内容

    if __name__ =="__main__":
        main()

    2 zabbix的item修改

    item的Type of information改成text类型

    3.zabbix触发器修改

    触发器修改为item输出内容里面关键字过滤是否有found_vm_split字段,有的情况下触发告警。

    4 测试情况

     ############################################此为分割线###############################################

    #!/usr/bin/env python
    # -*- coding: utf-8 -*-
    # @File    : VMSplitCheck.py
    import re
    import os
    import sys
    import libvirt
    from novaclient import client
    from multiprocessing import Pool,Queue
    from collections import Counter,defaultdict
    import pdb
    q=Queue()
    EnvFile='/root/openrc'

    # 获取nova的认证token

    def get_nova_creds():
        d={}
        try:
            pattern_save=re.compile(r'^export.*=.*')
            pattern_split=re.compile(r'=')
            with open(EnvFile,'r') as f:
                for i in f.readlines():
                    match=pattern_save.search(i)
                    if match:
                        temp_str = match.group(0).strip("export").strip()
                        environ_value_dic = pattern_split.split(temp_str)
                        os.environ[environ_value_dic[0]] = environ_value_dic[1].strip("'")
            d['username'] = os.environ['OS_USERNAME']
            d['api_key'] = os.environ['OS_PASSWORD']
            d['auth_url'] = os.environ['OS_AUTH_URL']
            d['project_id'] = os.environ['OS_TENANT_NAME']
            d['region_name']= os.environ['OS_REGION_NAME']
            return d
        except:
            print  "error"
            sys.exit(5)

    #通过调用novaclient获取hypervisor,笔者环境hypervisor主机名都为node-xxx.domain.tld
    def getHypervisor():
        HypervisorHostname = []
        pattern = re.compile(r'node-d.domain.tld')
        creds = get_nova_creds()
        nova = client.Client('2', **creds)
        for i in nova.hypervisors.list():
            match = pattern.search(i.hypervisor_hostname)
            if match:
                HypervisorHostname.append(match.group())
        return  HypervisorHostname

    #获取各个hypervisor上面的虚拟机的名字,放入队列
    def getVM(node):
        try:
            virtcon=libvirt.open("qemu+ssh://%s/system" %node)
        except libvirtError,e:
            print "wrong to connect"
        for id  in virtcon.listDomainsID():
            vminfo=virtcon.lookupByID(id)
            q.put((node,vminfo.name()))

    # 获取所有运行的虚拟机名字的的列表,和以各个hypervisor的主机名为key,上面运行虚拟机为value的字典
    def getVMList():
        InstanceNameList=[]
        # a=getHypervisor()
        # HyperDict = {}.fromkeys(a, [])
        HyperDict=defaultdict(list)
        while not q.empty():
            node,vm=q.get()
            InstanceNameList.append(vm)
            HyperDict[node].append(vm)
        return InstanceNameList,HyperDict

    # 检测是否有脑裂虚拟机,如果存在,获取此脑裂虚拟机运行在哪些hypervisor上面.
    def VMSplitCheck(instancelist,nodedict):
        SplitList=[]
        SplitDict=defaultdict(list)
        c=Counter(instancelist)
        for k,v in c.iteritems():
            if v>=2:
                SplitList.append(k)
        if len(SplitList)==0:
            print "no split vm"
        else:
           for i in SplitList:
               for k,v in nodedict.iteritems():
                   if i in v:
                       SplitDict[i].append(k)
        return SplitDict

    # 主函数
    def main():
        hypername=getHypervisor()
    #    pdb.set_trace()
    #    print hypername
        p=Pool()
        for i in hypername:
            p.apply_async(getVM,args=(i,))
        p.close()
        p.join()

        inslist,hydict=getVMList()
    #    print inslist,hydict
        vmsplit=VMSplitCheck(inslist,hydict)
        print  len(vmsplit)

    if __name__ =="__main__":
        main()

    笔者测试如下:

    如下图,有2台虚拟机同时在node-4和node-6运行

    运行脚本后,返回以脑裂虚拟机名字为key,同时运行的hypervisor主机名为value的字典.

    2 增加zabbix报警设置

          zabbix-agent增加item

             zabbix-dashboard操作

      

    测试item能否正常

    增加一个触发器

    表达式:{node-1.domain.tld:vm.split.status.last(0)}>0


     

    参考:

    https://www.ibm.com/developerworks/cn/cloud/library/cl-openstack-pythonapis/

    http://blog.csdn.net/gzhouc/article/details/52915822

  • 相关阅读:
    SPU和SKU有什么区别
    Mave手动安装jar包
    maven国内镜像(国内oschina的maven服务器关了)
    用java代码将从数据库中取出的具有父子关系的数据转成json格式
    Oracle中的decode()函数
    Oracle中的instr()函数
    Oracle的nvl
    Oracle保留小数点后两位的几种方法
    【Python】djangorestframework 基于django框架的接口开发
    【MySQL】 GTID使用
  • 原文地址:https://www.cnblogs.com/360linux/p/13062107.html
Copyright © 2011-2022 走看看