用python+django+twistd 开发一个属于自己的运维系统

来源:互联网 发布:淘宝商盟标准 编辑:程序博客网 时间:2024/04/29 08:05

开源的运维系统不少,比如nagios、zabbix、cati等等,但是遇到自己个性化的运维需求的时候,总是显的力不从心!最近在学习python,所以就考虑用python+django+twisted来定做一个完全个性化的运维系统。

运维系统有几个主要的功能:监控、分析、报警、更甚者直接根据分析的结果进行反应操作。而以上几点通过上述的框架可以比较容易的实现。

下面上图说明:

使用freemind整理了下思路:

下面是一些代码段,完整的代码下载见文档底部:

Server:

[python] view plaincopyprint?
  1. #!/usr/bin/env python  
  2. #coding:utf-8  
  3. __author__ = 'dwj'  
  4.   
  5.   
  6. from twisted.internet.protocol import ServerFactory  
  7. from twisted.protocols import basic  
  8. import cx_Oracle  
  9. from twisted.application import  service, internet  
  10.   
  11.   
  12.   
  13. class Mornitor_Protocol(basic.LineReceiver):  
  14.   
  15.     def __init__(self):  
  16.     #  
  17.         _oracle_conn=cx_Oracle.connect('xxxx''xxxx''192.168.7.17/test', threaded=True)  
  18.         _oracle_conn.autocommit = True  
  19.         self.cur = _oracle_conn.cursor()  
  20.         self._oracle_conn=_oracle_conn  
  21.   
  22.   
  23.     def ruku(self, line):  
  24.         ip=self.transport.getPeer().host  
  25.         #获取客户端IP  
  26.         line=line.split(':::')  
  27.         #使用:::分割原始数据  
  28.         if line[1in ['cpu''mem''disk''tcp''net''process_down']:  
  29.         #根据数据包头来确定使用insert还是update,当是tcp包头的时候插入,其余的更新  
  30.             if line[1] == 'tcp':  
  31.                 sql = "insert into MORNITOR_BASICINFO (ipadd,time,tcp) values (\'%s\',\'%s\',\'%s\')"%(ip,line[0],line[3])  
  32.                 print sql  
  33.                 self.cur.execute(sql)  
  34.   
  35.             else:  
  36.                 line_again = line[3].split('::')  
  37.                 sql = 'update MORNITOR_BASICINFO set %s=\'%s\',%s=\'%s\' where ipadd=\'%s\' and time=\'%s\''%(line[1],line_again[0],line[2],line_again[1],ip,line[0])  
  38.                 print sql  
  39.                 self.cur.execute(sql)  
  40.   
  41.     def connectionMade(self):  
  42.         print 'Connected!'  
  43.   
  44.     def lineReceived(self, line):  
  45.         print line  
  46.         self.ruku(line)  
  47.         #接受到数据之后执行入库操作!  
  48.     def connectionLost(self, reason='connectionDone'):  
  49.         self._oracle_conn.close()  
  50.         print 'The db is close... ok!'  
  51.   
  52.   
  53. class Mornitor_Factory(ServerFactory):  
  54.     #还没想好要初始化什么  
  55.     def __init__(self,service):  
  56.         self.service = service  
  57.   
  58.     protocol = Mornitor_Protocol  
  59.   
  60.   
  61. class Fish_Service(service.Service):  
  62.   
  63.     def __init__(self):  
  64.         pass  
  65.   
  66.     def startService(self):  
  67.         service.Service.startService(self)              #什么都不做,开始服务  
  68.   
  69.     # def stopService(self):  
  70.     #     return self._port.stopListening()  
  71.   
  72.   
  73.   
  74. #配置参数  
  75. port = 10000  
  76. iface = '127.0.0.1'  
  77.   
  78.   
  79.   
  80. top_server = service.MultiService()                             #定义服务容器  
  81.   
  82. fish_server = Fish_Service()                                    #实例化我们的服务  
  83. fish_server.setServiceParent(top_server)                        #把自定义的服务加入到服务容器  
  84.   
  85. factory = Mornitor_Factory(Fish_Service)                        #工厂化服务  
  86.   
  87. tcp_server = internet.TCPServer(port, factory, interface=iface) #定义tcp服务  
  88. tcp_server.setServiceParent(top_server)                         #把tcp服务加入到服务容器  
  89.   
  90. application = service.Application('Fish_Service')               #给应用起个名字  
  91. top_server.setServiceParent(application)                        #把服务容器丢到应用中去  
Client端

[python] view plaincopyprint?
  1. from twisted.protocols import basic  
  2. from twisted.internet import  protocol, defer, task  
  3. import Get_basic_info_2 as Huoqu  
  4. import guardian as shouhu  
  5. import time  
  6. from twisted.application import service, internet  
  7.   
  8.   
  9. class Monitor_Protocol(basic.LineReceiver):  
  10.     #自定义客户端和服务端的连接协议,从basic的line继承  
  11.   
  12.     def __init__(self):  
  13.         #  
  14.         pass  
  15.  
  16.     @staticmethod  
  17.     def huoqu_shuju():  
  18.         #定义一个函数获取本机的一些状态  
  19.         now = str(time.strftime('%Y-%m-%d %H:%M:%S'))  
  20.           
  21.         def add_tag(source, tag1, tag2 = 'none'):  
  22.         #定义格式化字符串函数  
  23.             return ':::'.join([now, tag1, tag2, source])  
  24.             #使用:::分隔时间、简单信息、详细信息、原始信息  
  25.           
  26.         tcp = add_tag(Huoqu.net_tcp(), 'tcp')  
  27.         cpu = add_tag(Huoqu.cpu(), 'cpu''cpu_detail')  
  28.         mem = add_tag(Huoqu.mem(), 'mem''mem_detail')  
  29.         disk = add_tag(Huoqu.disk_usage(), 'disk''disk_detail')  
  30.         net = add_tag(Huoqu.net_rate(), 'net''net_detail')  
  31.         process = add_tag(shouhu.check_alive(), 'process_down''process_alived')  
  32.         result = (tcp, cpu, mem, disk, net, process, )   
  33.         d = defer.Deferred()  
  34.         #使用defered返回结果  
  35.         d.callback(result)  
  36.         return d  
  37.   
  38.     def xunhuan(self, list):  
  39.     #定义循环发送函数  
  40.         for i in list:  
  41.             self.sendLine(i)  
  42.   
  43.     def fasong(self):  
  44.     #定义程序运行顺序,取得信息后用callback交给发送函数发送  
  45.         self.huoqu_shuju().addCallback(self.xunhuan)  
  46.   
  47.     def loop(self):  
  48.     #使用twist内置的循环函数定义几秒监控数据传送到服务端  
  49.         l = task.LoopingCall(self.fasong)  
  50.         l.start(1)  
  51.   
  52.     def connectionMade(self):  
  53.     #覆盖协议的connectmade函数,定义于服务端的连接建立后开始循环  
  54.         print 'Connected!......ok!'  
  55.         self.loop()  
  56.   
  57.     def lineReceived(self, line):  
  58.     #必须覆盖接受函数,否则twist会报not importent错误!  
  59.         pass  
  60.   
  61.   
  62. class Moinitor_client_factory(protocol.ReconnectingClientFactory):  
  63.       
  64.     def __init__(self, service):  
  65.     #还没想要要写什么  
  66.         self.service = service  
  67.     protocol = Monitor_Protocol  
  68.   
  69.   
  70. class Client_Service(service.Service):  
  71.   
  72.     def __init__(self):  
  73.         pass  
  74.   
  75.     def startService(self):  
  76.         service.Service.startService(self)  
  77.   
  78.   
  79. #配置文件开始  
  80. port = 10000  
  81. host = '127.0.0.1'  
  82.   
  83. #守护进程  
  84. top_service = service.MultiService()                   #定义服务容器  
  85.   
  86. client_service = Client_Service()                      #实例化服务类  
  87. client_service.setServiceParent(top_service)           #把自己定义的服务丢到服务容器中  
  88.   
  89. factory = Moinitor_client_factory(client_service)      #定义服务工厂化  
  90.   
  91. tcp_service = internet.TCPClient(host, port, factory)  #定义tcp连接的服务  
  92. tcp_service.setServiceParent(top_service)              #把tcp服务丢到服务容器中去  
  93.   
  94. application = service.Application('Fish_Service')      #定义应用名字  
  95. top_service.setServiceParent(application)              #把服务容器丢到应用中去  

一些自定义监控程序是否存活的脚本:

[python] view plaincopyprint?
  1. program = {'nginx': ['/opt/nginx/logs/nginx.pid''/opt/nginx/sbin/nginx'],  
  2.             'rsync-C': ['/var/run/rsyncd.pid''rsync --daemon'],  
  3.             }  
  4.   
  5.   
  6. def main():  
  7.     for k in program:  
  8.         a = get_pid(k, program[k][0])  
  9.         if isinstance(a, tuple):  
  10.             print '%s is not running!' % k  
  11.             print 'Start the program by Horland_guardian!'  
  12.             subprocess.call(program[k][1], shell=True)  
  13.         else:  
  14.             print 'The %s is running!' % k  
  15.   
  16.   
  17. def check_alive():  
  18.     l_lived = []  
  19.     l_downed = []  
  20.     for k in program:  
  21.         a = get_pid(k, program[k][0])  
  22.         if isinstance(a, tuple):  
  23.             l_downed.append(k)  
  24.         else:  
  25.             l_lived.append(k)  
  26.     process_alived = ' '.join(l_lived)  
  27.     process_down = ' '.join(l_downed)  
  28.   
  29.     return '::'.join([process_down, process_alived])  


django的使用目前只需要使用到admin模块就可以。

下面是一些代码段:

model

[python] view plaincopyprint?
  1. class BasicInfo(models.Model):  
  2.     ipadd = models.IPAddressField(verbose_name = u'IP地址')  
  3.     time = models.CharField(max_length=50, verbose_name = u'时间')  
  4.     cpu = models.CharField(max_length=255, blank=True, verbose_name = u'CPU%')  
  5.     cpu_detail = models.CharField(max_length=255, blank=True, verbose_name = u'CPU详情')  
  6.     mem = models.CharField(max_length=255, blank=True, verbose_name = u'内存%')  
  7.     mem_detail = models.CharField(max_length=255, blank=True, verbose_name = u'内存详情')  
  8.     disk = models.CharField(max_length=255, blank=True, verbose_name = u'磁盘%')  
  9.     disk_detail = models.CharField(max_length=255, blank=True, verbose_name = u'磁盘详情')  
  10.     net = models.CharField(max_length=255, blank=True, verbose_name = u'流量 bytes/s')  
  11.     net_detail = models.CharField(max_length=1000, blank=True, verbose_name = u'流量详情')  
  12.     tcp = models.CharField(max_length=255, blank=True, verbose_name = u'tcp连接状态')  
  13.     process_down = models.CharField(max_length=255, blank=True, verbose_name = u'DOWN-进程')  
  14.     process_alived = models.CharField(max_length=255, blank=True, verbose_name = u'Process_UP')  
  15.   
  16.     def Process_DOWN(self):  
  17.         return '<span style="color: #%s;">%s</span>' % ('ff0000'self.process_down)  #拓机的进程用红色标识  
  18.     Process_DOWN.allow_tags = True  

注册到admin

[python] view plaincopyprint?
  1. class BasicInfo_admin(admin.ModelAdmin):  
  2.   
  3.     list_display = ('time''cpu''cpu_detail''mem''mem_detail''disk''disk_detail''net''net_detail''tcp''Process_DOWN''process_alived')  
  4.     list_filter = ('ipadd', )  
  5. admin.site.register(BasicInfo, BasicInfo_admin)  
0 0