python+Django实现Nagios自动化添加监控项目
最近机房刚上了一批机器(有100台左右),需要使用Nagios对这一批机器进行监控。领导要求两天时间完成所有主机的监控。从原来的经验来看,两天时间肯定完成不了。那怎么办?按照之前的想法,肯定是在nagios配置文件逐一添加每台客户端的监控信息,工作量巨大。突然,想到一个想法,是否可以通过脚本来实现批量对主机进行监控,也就是运维自动化。
写脚本,最重要的就是思路。思路压倒一切,经过思考最终决定就这么做了。先贴出来一张网路拓扑图:
整个过程可以分为三部分。
cmdb端:主要用来实现对数据的收集,采用两个API,一个是提供给客户机的API。用于将客户端的数据上传的cmdb服务器;另外一个API是nagios通过此API可以得到要监控主机的信息,然后对该信息进行整理,做成nagios监控模板。
Client端:通过Python脚本收集本机器要监控的软硬件信息,然后通过cmdb端提供的API接口将数据上传到cmdb端的数据库。
Nagios端:通过cmdb端提供的API接口实现对cmdb收集到的信息进行抓取,然后将数据写入到模板,最后copy到naigos指定的objects目录,最终实现对客户机的监控。
这三部分最重要的应该是CMDB端。接下来通过安装django和编写API接口实现cmdb可以正常工作。可以将cmdb端分为三个步骤来完成:
安装django
配置django
编写API接口
首先来进行安装django:
在安装django之前首先应该安装python(版本建议2.7.)
- 1.下载django软件包
- 可以到django官方网站下载最新django软件包(https://www.djangoproject.com).
- 2.解压缩并安装软件包
- tar -zxvf Django-1.5.1.tar.gz
- cd Django-1.5.1
- python setup.py install
创建项目和应用:
- 1.创建一个项目
- python startproject simplecmdb
- 2.创建一个应用
- python startapp hostinfo
配置django:
1.修改setting.py
DATABASES = {'ENGIN':'django.db.backends.sqlite','name':path.join('CMDB.db')} #使用的数据库及数据库名
INSTALLED_APPS =(hostinfoINSTALLED_APPS = ('hostinfo')
INSTALLED_APPS = ('hostinfo') #应用的名称
2.修改urls.py
url(r'^api/gethost\.json$','hostinfo.views.gethosts'), #nagios客户端访问API接口地址
url(r'^api/clooect$','hostinfo.views.collect'), #客户端访问API进行上传数据的API
url(r'^admin/',include(admin.site.urls)), #django后台管理登入url
from django.contrib import admin
admin.autodiscover()
3.修改项目hostinfo下的views.py
代码如下:
- # Create your views here.
- #包含以下模块
- from django.shortcuts import render_to_response
- from django.http import HttpResponse
- from models import Host, HostGroup
- #包含json模块
- try:
- import json
- except ImportError,e:
- import simplejson as json
- #用来接收客户端服务器发送过来的数据
- def collect(request):
- req = request
- if req.POST:
- vendor = req.POST.get('Product_Name')
- sn = req.POST.get('Serial_Number')
- product = req.POST.get('Manufacturer')
- cpu_model = req.POST.get('Model_Name')
- cpu_num = req.POST.get('Cpu_Cores')
- cpu_vendor = req.POST.get('Vendor_Id')
- memory_part_number = req.POST.get('Part_Number')
- memory_manufacturer = req.POST.get('Manufacturer')
- memory_size = req.POST.get('Size')
- device_model = req.POST.get('Device_Model')
- device_version = req.POST.get('Firmware_Version')
- device_sn = req.POST.get('Serial_Number')
- device_size = req.POST.get('User_Capacity')
- osver = req.POST.get('os_version')
- hostname = req.POST.get('os_name')
- os_release = req.POST.get('os_release')
- ipaddrs = req.POST.get('Ipaddr')
- mac = req.POST.get('Device')
- link = req.POST.get('Link')
- mask = req.POST.get('Mask')
- device = req.POST.get('Device')
- host = Host()
- host.hostname = hostname
- host.product = product
- host.cpu_num = cpu_num
- host.cpu_model = cpu_model
- host.cpu_vendor = cpu_vendor
- host.memory_part_number = memory_part_number
- host.memory_manufacturer = memory_manufacturer
- host.memory_size = memory_size
- host.device_model = device_model
- host.device_version = device_version
- host.device_sn = device_sn
- host.device_size = device_size
- host.osver = osver
- host.os_release = os_release
- host.vendor = vendor
- host.sn = sn
- host.ipaddr = ipaddrs
- host.save() #将客户端传过来的数据通过POST接收,存入数据库
- return HttpResponse('OK') #如果插入成功,返回'ok'
- else:
- return HttpResponse('no post data')
- #提供给NAGIOS 的API
- def gethosts(req):
- d = []
- hostgroups = HostGroup.objects.all()
- for hg in hostgroups:
- ret_hg = {'hostgroup':hg.name,'members':[]}
- members = hg.members.all()
- for h in members:
- ret_h = {'hostname':h.hostname, #API接口返回的数据
- 'ipaddr':h.ipaddr
- }
- ret_hg['members'].append(ret_h)
- d.append(ret_hg)
- ret = {'status':0,'data':d,'message':'ok'}
- return HttpResponse(json.dumps(ret))
4.修改model.py 文件
代码如下:
- from django.db import models
- # Create your models here.
- #插入数据库的Host表,主要存储客户端主机的信息
- class Host(models.Model):
- """store host information"""
- vendor = models.CharField(max_length=30,null=True)
- sn = models.CharField(max_length=30,null=True)
- product = models.CharField(max_length=30,null=True)
- cpu_model = models.CharField(max_length=50,null=True)
- cpu_num = models.CharField(max_length=2,null=True)
- cpu_vendor = models.CharField(max_length=30,null=True)
- memory_part_number = models.CharField(max_length=30,null=True)
- memory_manufacturer = models.CharField(max_length=30,null=True)
- memory_size = models.CharField(max_length=20,null=True)
- device_model = models.CharField(max_length=30,null=True)
- device_version = models.CharField(max_length=30,null=True)
- device_sn = models.CharField(max_length=30,null=True)
- device_size = models.CharField(max_length=30,null=True)
- osver = models.CharField(max_length=30,null=True)
- hostname = models.CharField(max_length=30,null=True)
- os_release = models.CharField(max_length=30,null=True)
- ipaddr = models.IPAddressField(max_length=15)
- def __unicode__(self):
- return self.hostname
- #主机组表,用来对主机进行分组
- class HostGroup(models.Model):
- name = models.CharField(max_length=30)
- members = models.ManyToManyField(Host)
5.修改admin.py文件
- #from models import Host, IPaddr
- from models import Host, HostGroup
- from django.contrib import admin
- #设置在django在admin后天显示的名称
- class HostAdmin(admin.ModelAdmin):
- list_display = ['vendor',
- 'sn',
- 'product',
- 'cpu_model',
- 'cpu_num',
- 'cpu_vendor',
- 'memory_part_number',
- 'memory_manufacturer',
- 'memory_size',
- 'device_model',
- 'device_version',
- 'device_sn',
- 'device_size',
- 'osver',
- 'hostname',
- 'os_release'
- ]
- #在django后台amdin显示的组名称
- class HostGroupAdmin(admin.ModelAdmin):
- list_display = ['name',]
- #将如上两个类的数据展示到django的后台
- admin.site.register(HostGroup,HostGroupAdmin)
- admin.site.register(Host, HostAdmin)
6.创建数据库
python manager.py syncdb #创建数据库
7.启动应用
python manager.py runserver 0.0.0.0:8000
8.测试
http://132.96.77.12:8000/admin
通过上图可以看到,django已经配置成功。
接下来可以在客户端编写收集主机信息的脚本了,主要抓取cpu、内存、硬盘、服务器型号、服务器sn、ip地址、主机名称、操作系统版本等信息,共7个脚本:
1.cpu抓取脚本:
- #!/usr/local/src/python/bin/python
- #-*- coding:utf-8 -*-
- from subprocess import PIPE,Popen
- import re
- def getCpuInfo():
- p = Popen(['cat','/proc/cpuinfo'],shell=False,stdout=PIPE)
- stdout, stderr = p.communicate()
- return stdout.strip()
- def parserCpuInfo(cpudata):
- pd = {}
- model_name = re.compile(r'.*model name\s+:\s(.*)')
- vendor_id = re.compile(r'vendor_id\s+:(.*)')
- cpu_cores = re.compile(r'cpu cores\s+:\s([\d]+)')
- lines = [line for line in cpudata.split('\n')]
- for line in lines:
- model = re.match(model_name,line)
- vendor = re.match(vendor_id,line)
- cores = re.match(cpu_cores,line)
- if model:
- pd['Model_Name'] = model.groups()[0].strip()
- if vendor:
- pd['Vendor_Id'] = vendor.groups()[0].strip()
- if cores:
- pd['Cpu_Cores'] = cores.groups()[0]
- else:
- pd['Cpu_Cores'] = int('1')
- return pd
- if __name__ == '__main__':
- cpudata = getCpuInfo()
- print parserCpuInfo(cpudata)
2.硬盘抓取脚本:
- #!/usr/local/src/python/bin/python
- #-*- coding:utf-8 -*-
- from subprocess import PIPE,Popen
- import re
- def getDiskInfo():
- disk_dev = re.compile(r'Disk\s/dev/[a-z]{3}')
- disk_name = re.compile(r'/dev/[a-z]{3}')
- p = Popen(['fdisk','-l'],shell=False,stdout=PIPE)
- stdout, stderr = p.communicate()
- for i in stdout.split('\n'):
- disk = re.match(disk_dev,i)
- if disk:
- dk = re.search(disk_name,disk.group()).group()
- n = Popen('smartctl -i %s' % dk,shell=True,stdout=PIPE)
- stdout, stderr = n.communicate()
- return stdout.strip()
- def parserDiskInfo(diskdata):
- ld = []
- pd = {}
- device_model = re.compile(r'(Device Model):(\s+.*)')
- serial_number = re.compile(r'(Serial Number):(\s+[\d\w]{1,30})')
- firmware_version = re.compile(r'(Firmware Version):(\s+[\w]{1,20})')
- user_capacity = re.compile(r'(User Capacity):(\s+[\d\w, ]{1,50})')
- for line in diskdata.split('\n'):
- serial = re.search(serial_number,line)
- device = re.search(device_model,line)
- firmware = re.search(firmware_version,line)
- user = re.search(user_capacity,line)
- if device:
- pd['Device_Model'] = device.groups()[1].strip()
- if serial:
- pd['Serial_Number'] = serial.groups()[1].strip()
- if firmware:
- pd['Firmware_Version'] = firmware.groups()[1].strip()
- if user:
- pd['User_Capacity'] = user.groups()[1].strip()
- return pd
- if __name__ == '__main__':
- diskdata = getDiskInfo()
- print parserDiskInfo(diskdata)
3.内存抓取脚本:
- #!/usr/local/src/python/bin/python
- #-*- coding:utf-8 -*-
- from subprocess import PIPE,Popen
- import re
- import sys
- def getMemInfo():
- p = Popen(['dmidecode'],shell=False,stdout=PIPE)
- stdout, stderr = p.communicate()
- return stdout.strip()
- def parserMemInfo(memdata):
- line_in = False
- mem_str = ''
- pd = {}
- fd = {}
- for line in memdata.split('\n'):
- if line.startswith('Memory Device') and line.endswith('Memory Device'):
- line_in = True
- mem_str+='\n'
- continue
- if line.startswith('\t') and line_in:
- mem_str+=line
- else:
- line_in = False
- for i in mem_str.split('\n')[1:]:
- lines = i.replace('\t','\n').strip()
- for ln in lines.split('\n'):
- k, v = [i for i in ln.split(':')]
- pd[k.strip()] = v.strip()
- if pd['Size'] != 'No Module Installed':
- mem_info = 'Size:%s ; Part_Number:%s ; Manufacturer:%s' % (pd['Size'],pd['Part Number'],pd['Manufacturer'])
- for line in mem_info.split('\n'):
- for word in line.split(';'):
- k, v = [i.strip() for i in word.split(':')]
- fd[k] = v.strip()
- yield fd
- if __name__ == '__main__':
- memdata = getMemInfo()
- for i in parserMemInfo(memdata):
- print i
4.抓取服务器信息脚本:
- #!/usr/local/src/python/bin/python
- # -*- coding:utf-8 -*-
- from subprocess import PIPE,Popen
- import urllib, urllib2
- def getDMI():
- p = Popen('dmidecode',shell=True,stdout=PIPE)
- stdout, stderr = p.communicate()
- return stdout
- def parserDMI(dmidata):
- pd = {}
- fd = {}
- line_in = False
- for line in dmidata.split('\n'):
- if line.startswith('System Information'):
- line_in = True
- continue
- if line.startswith('\t') and line_in:
- k, v = [i.strip() for i in line.split(':')]
- pd[k] = v
- else:
- line_in = False
- name = "Manufacturer:%s ; Serial_Number:%s ; Product_Name:%s" % (pd['Manufacturer'],pd['Serial Number'],pd['Product Name'])
- for i in name.split(';'):
- k, v = [j.strip() for j in i.split(':')]
- fd[k] = v
- return fd
- if __name__ == '__main__':
- dmidata = getDMI()
- postdata = parserDMI(dmidata)
- print postdata
5.抓取主机信息
- #!/usr/local/src/python/bin/python
- #-*- coding:utf-8 -*-
- import platform
- def getHostInfo():
- pd ={}
- version = platform.dist()
- os_name = platform.node()
- os_release = platform.release()
- os_version = '%s %s' % (version[0],version[1])
- pd['os_name'] = os_name
- pd['os_release'] = os_release
- pd['os_version'] = os_version
- return pd
- if __name__ == '__main__':
- print getHostInfo()
6.抓取ip地址:
- #!/usr/local/src/python/bin/python
- #-*- coding:utf-8 -*-
- from subprocess import PIPE,Popen
- import re
- def getIpaddr():
- p = Popen(['ifconfig'],shell=False,stdout=PIPE)
- stdout, stderr = p.communicate()
- return stdout.strip()
- def parserIpaddr(ipdata):
- device = re.compile(r'(eth\d)')
- ipaddr = re.compile(r'(inet addr:[\d.]{7,15})')
- mac = re.compile(r'(HWaddr\s[0-9A-Fa-f:]{17})')
- link = re.compile(r'(Link encap:[\w]{3,14})')
- mask = re.compile(r'(Mask:[\d.]{9,15})')
- for lines in ipdata.split('\n\n'):
- pd = {}
- eth_device = re.search(device,lines)
- inet_ip = re.search(ipaddr,lines)
- hw = re.search(mac,lines)
- link_encap = re.search(link,lines)
- _mask = re.search(mask,lines)
- if eth_device:
- if eth_device:
- Device = eth_device.groups()[0]
- if inet_ip:
- Ipaddr = inet_ip.groups()[0].split(':')[1]
- if hw:
- Mac = hw.groups()[0].split()[1]
- if link_encap:
- Link = link_encap.groups()[0].split(':')[1]
- if _mask:
- Mask = _mask.groups()[0].split(':')[1]
- pd['Device'] = Device
- pd['Ipaddr'] = Ipaddr
- pd['Mac'] = Mac
- pd['Link'] = Link
- pd['Mask'] = Mask
- yield pd
- if __name__ == '__main__':
- ipdata = getIpaddr()
- for i in parserIpaddr(ipdata):
- print i
7.对这些信息进行合并,并通过API形式将数据发送给cmdb端
- #!/usr/local/src/python/bin/python
- import urllib, urllib2
- from cpuinfo import *
- from diskinfo import *
- from meminfo import *
- from product import *
- from hostinfo import *
- from ipaddress import *
- def getHostTotal():
- ld = []
- cpuinfo = parserCpuInfo(getCpuInfo())
- diskinfo = parserDiskInfo(getDiskInfo())
- for i in parserMemInfo(getMemInfo()):
- meminfo = i
- productinfo = parserDMI(getDMI())
- hostinfo = getHostInfo()
- ipaddr = parserIpaddr(getIpaddr())
- for i in ipaddr:
- ip = i
- for k in cpuinfo.iteritems():
- ld.append(k)
- for i in diskinfo.iteritems():
- ld.append(i)
- for j in meminfo.iteritems():
- ld.append(j)
- for v in productinfo.iteritems():
- ld.append(v)
- for x in hostinfo.iteritems():
- ld.append(x)
- for y in ip.iteritems():
- ld.append(y)
- return ld
- def parserHostTotal(hostdata):
- pg = {}
- for i in hostdata:
- pg[i[0]] = i[1]
- return pg
- def urlPost(postdata):
- data = urllib.urlencode(postdata)
- req = urllib2.Request('http://132.96.77.12:8000/api/collect',data)
- response = urllib2.urlopen(req)
- return response.read()
- if __name__ == '__main__':
- hostdata = getHostTotal()
- postdata = parserHostTotal(hostdata)
- print urlPost(postdata)
到目前为止,cmdb系统已经可以将所有客户端的主机信息写入到数据库,并且可以通过nagios端的API接口直接调到数据:
http://132.96.77.12:8000/api/gethosts.json
通过图可以看到,已经成功调用到API接口的数据。
接下来可以在nagios端进行调用API接口的数据,对数据进行格式化。并写入文件。
1.nagios脚本
- #!/opt/data/py/bin/python
- #!-*- coding:utf-8 -*-
- import urllib, urllib2
- import json
- import os
- import shutil
- CURR_DIR = os.path.abspath(os.path.dirname(__file__))
- HOST_CONF_DIR = os.path.join(CURR_DIR,'hosts')
- HOST_TMP = """define host {
- use linux-server
- host_name %(hostname)s
- check_command check-host-alive
- alias %(hostname)s
- address %(ipaddr)s
- contact_groups admins
- }
- """
- def getHosts():
- url = 'http://132.96.77.12:8000/api/gethosts.json'
- return json.loads(urllib2.urlopen(url).read())
- def initDir():
- if not os.path.exists(HOST_CONF_DIR):
- os.mkdir(HOST_CONF_DIR)
- def writeFile(f,s):
- with open(f,'w') as fd:
- fd.write(s)
- def genNagiosHost(hostdata):
- initDir()
- conf = os.path.join(HOST_CONF_DIR,'hosts.cfg')
- hostconf = ""
- for hg in hostdata:
- for h in hg['members']:
- hostconf+=HOST_TMP %h
- writeFile(conf,hostconf)
- return "ok"
- def main():
- result = getHosts()
- if result['status'] == 0:
- print genNagiosHost(result['data'])
- else:
- print 'Error: %s' % result['message']
- if os.path.exists(os.path.join(HOST_CONF_DIR,'hosts.cfg')):
- os.chdir(HOST_CONF_DIR)
- shutil.copyfile('hosts.cfg','/etc/nagios/objects/hosts.cfg')
- if __name__ == "__main__":
- main()
现在已经生成nagios主机的配置文件,并copy到nagios/objects目录下hosts.cfg。接下来可以测试是否nagios配置有问题,如果没有问题,就可以启动nagios服务
[root@yetcomm-v2 bin]# ./nagios -v /etc/nagios/nagios.cfg
通过测试,nagios没有发生错误或警告信息,现在可以启动nagios服务:
[root@yetcomm-v2 bin]# service nagios restart
最后,可以通过浏览器查看nagios的监控界面:
通过上图,可以看到已经将一台主机加入到监控组。由于是生产环境,所有只能拿测试服务器进行测试。其实测试环境和生产环境的代码完全一致。
python+Django实现Nagios自动化添加监控项目的更多相关文章
- Python+Django+ansible playbook自动化运维项目实战☝☝☝
Python+Django+ansible playbook自动化运维项目实战☝☝☝ 一.入门引导 DevOPSDevOps(英文Development和Operations的组合)是一组过程.方法 ...
- Python+Django+ansible playbook自动化运维项目实战✍✍✍
Python+Django+ansible playbook自动化运维项目实战 整个课程都看完了,这个课程的分享可以往下看,下面有链接,之前做java开发也做了一些年头,也分享下自己看这个视频的感受 ...
- Python+Django+Ansible Playbook自动化运维项目实战
Python+Django+AnsiblePlaybook自动化运维项目实战 整个课程都看完了,这个课程的分享可以往下看,下面有链接,之前做java开发也做了一些年头,也分享下自己看这个视频的感受,单 ...
- zabbix的自动发现、自定义添加监控项目、配置邮件告警
1.zabbix的自动发现这里的自动发现,所显示出来的是规则的上自动了现 然后 可以对其内容进行相关的配制,如时间或周期 注意:对于单个主机的规则,可以自行添加或删除, 但对于已经添加好了的规则,若需 ...
- 【转】python+django+vue搭建前后端分离项目
https://www.cnblogs.com/zhixi/p/9996832.html 以前一直是做基于PHP或JAVA的前后端分离开发,最近跟着python风搭建了一个基于django的前后端分享 ...
- python+django+vue搭建前后端分离项目
以前一直是做基于PHP或JAVA的前后端分离开发,最近跟着python风搭建了一个基于django的前后端分享项目 准备工作:IDE,[JetBrains PyCharm2018][webpack 3 ...
- zabbix添加自定义监控项目
在zabbix里添加一个自定义监控项目,简单做个笔记,怕忘了 首先需要定义 zabbix_agentd.conf 中的 UnsafeUserParameters 修改为 UnsafeUserPara ...
- Django-Multitenant,分布式多租户数据库项目实战(Python/Django+Postgres+Citus)
Python/Django 支持分布式多租户数据库,如 Postgres+Citus. 通过将租户上下文添加到您的查询来实现轻松横向扩展,使数据库(例如 Citus)能够有效地将查询路由到正确的数据库 ...
- Python(Django)项目与Apache的管理
(开开心心每一天~ ---虫瘾师) Python(Django)项目交给Apache的管理(一) 准备:Django的环境(Python).Apache.Wsgi(必须文件) 首先需要电脑有Pytho ...
随机推荐
- Oracle Apex 有用笔记系列 6 - 可编辑交互报告 Editable Interactive Report
据笔者所知.Apex 4.x 是没有提供可编辑交互报告组件的.这就须要我们手动实现. 事实上这也并非非常复杂,仅仅须要简单几步. 1. 依据向导建立一个interactive report.查询语句能 ...
- Objective-C基础笔记(6)Block
Block(代码段)封装了一段代码,能够在不论什么时候运行. Block能够作为函数參数或者函数返回值,而其本身又能够带输入參数或返回值.它和传统的函数指针非常相似,可是有差别:block是inlin ...
- centos 使用 CP 命令 不提示 覆盖
今天 在我的VPS上拷一个目录,但放的地方有一个同名目录并且里面还有文件.如是直接拷过去,结果有N个要确认替换的提示,直接CTRL+C,在网上搜了把,发现有几个方法能够解决,方法例如以下: 一般我们使 ...
- 【转载】C#扫盲之:带你掌握C#的扩展方法、以及探讨扩展方法的本质、注意事项
1.为什么需要扩展方法 .NET3.5给我们提供了扩展方法的概念,它的功能是在不修改要添加类型的原有结构时,允许你为类或结构添加新方法. 思考:那么究竟为什么需要扩展方法呢,为什么不直接修改原有类型呢 ...
- STL源代码剖析——基本算法stl_algobase.h
前言 在STL中.算法是常常被使用的,算法在整个STL中起到很关键的数据.本节介绍的是一些基本算法,包括equal.fill.fill_n,iter_swap.lexicographical_comp ...
- Android API Guides---NFC Basics
本文档介绍了Android中运行基本任务NFC. 它说明了怎样在NDEF消息的形式发送和接收数据的NFC并介绍了支持这些功能的Android框架的API. 对于更高级的主题.包含与非NDEF数据工 ...
- C#基础系列:反射笔记
前言:使用反射也有几年了,但是一直觉得,反这个概念很抽象,今天有时间就来总结下这个知识点. 1.为什么需要反射: 最初使用反射的时候,作为小菜总是不理解,既然可以通过new 一个对象的方式得到对象,然 ...
- session自己定义存储,怎样更好地进行session共享;读tomcat7源代码,org.apache.catalina.session.FileStore可知
session自己定义存储.怎样更好地进行session共享: 读tomcat源代码,org.apache.catalina.session.FileStore可知 一.详见: 方法1 public ...
- Linux struct itimerval使用方法
版权声明:本文为博主原创文章.未经博主同意不得转载. https://blog.csdn.net/hbuxiaofei/article/details/35569229 先看一段代码 #include ...
- GNU linux 中makefile那点事
转自陈皓: http://bbs.chinaunix.net/viewthread.php?tid=408225 概述—— 什么是makefile?或许很多Winodws的程序员都不知道这个东西,因为 ...