1. 程式人生 > >用python+django+twistd 開發一個屬於自己的運維繫統

用python+django+twistd 開發一個屬於自己的運維繫統

開源的運維繫統不少,比如nagios、zabbix、cati等等,但是遇到自己個性化的運維需求的時候,總是顯的力不從心!最近在學習python,所以就考慮用python+django+twisted來定做一個完全個性化的運維繫統。

運維繫統有幾個主要的功能:監控、分析、報警、更甚者直接根據分析的結果進行反應操作。而以上幾點通過上述的框架可以比較容易的實現。

下面上圖說明:

使用freemind整理了下思路:

下面是一些程式碼段,完整的程式碼下載見文件底部:

Server:

#!/usr/bin/env python
#coding:utf-8
__author__ = 'dwj'


from twisted.internet.protocol import ServerFactory
from twisted.protocols import basic
import cx_Oracle
from twisted.application import  service, internet



class Mornitor_Protocol(basic.LineReceiver):

    def __init__(self):
    #
        _oracle_conn=cx_Oracle.connect('xxxx', 'xxxx', '192.168.7.17/test', threaded=True)
        _oracle_conn.autocommit = True
        self.cur = _oracle_conn.cursor()
        self._oracle_conn=_oracle_conn


    def ruku(self, line):
        ip=self.transport.getPeer().host
        #獲取客戶端IP
        line=line.split(':::')
        #使用:::分割原始資料
        if line[1] in ['cpu', 'mem', 'disk', 'tcp', 'net', 'process_down']:
        #根據資料包頭來確定使用insert還是update,當是tcp包頭的時候插入,其餘的更新
            if line[1] == 'tcp':
                sql = "insert into MORNITOR_BASICINFO (ipadd,time,tcp) values (\'%s\',\'%s\',\'%s\')"%(ip,line[0],line[3])
                print sql
                self.cur.execute(sql)

            else:
                line_again = line[3].split('::')
                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])
                print sql
                self.cur.execute(sql)

    def connectionMade(self):
        print 'Connected!'

    def lineReceived(self, line):
        print line
        self.ruku(line)
        #接受到資料之後執行入庫操作!
    def connectionLost(self, reason='connectionDone'):
        self._oracle_conn.close()
        print 'The db is close... ok!'


class Mornitor_Factory(ServerFactory):
    #還沒想好要初始化什麼
    def __init__(self,service):
        self.service = service

    protocol = Mornitor_Protocol


class Fish_Service(service.Service):

    def __init__(self):
        pass

    def startService(self):
        service.Service.startService(self)              #什麼都不做,開始服務

    # def stopService(self):
    #     return self._port.stopListening()



#配置引數
port = 10000
iface = '127.0.0.1'



top_server = service.MultiService()                             #定義服務容器

fish_server = Fish_Service()                                    #例項化我們的服務
fish_server.setServiceParent(top_server)                        #把自定義的服務加入到服務容器

factory = Mornitor_Factory(Fish_Service)                        #工廠化服務

tcp_server = internet.TCPServer(port, factory, interface=iface) #定義tcp服務
tcp_server.setServiceParent(top_server)                         #把tcp服務加入到服務容器

application = service.Application('Fish_Service')               #給應用起個名字
top_server.setServiceParent(application)                        #把服務容器丟到應用中去
Client端
from twisted.protocols import basic
from twisted.internet import  protocol, defer, task
import Get_basic_info_2 as Huoqu
import guardian as shouhu
import time
from twisted.application import service, internet


class Monitor_Protocol(basic.LineReceiver):
    #自定義客戶端和服務端的連線協議,從basic的line繼承

    def __init__(self):
        #
        pass

    @staticmethod
    def huoqu_shuju():
        #定義一個函式獲取本機的一些狀態
        now = str(time.strftime('%Y-%m-%d %H:%M:%S'))
        
        def add_tag(source, tag1, tag2 = 'none'):
        #定義格式化字串函式
            return ':::'.join([now, tag1, tag2, source])
            #使用:::分隔時間、簡單資訊、詳細資訊、原始資訊
        
        tcp = add_tag(Huoqu.net_tcp(), 'tcp')
        cpu = add_tag(Huoqu.cpu(), 'cpu', 'cpu_detail')
        mem = add_tag(Huoqu.mem(), 'mem', 'mem_detail')
        disk = add_tag(Huoqu.disk_usage(), 'disk', 'disk_detail')
        net = add_tag(Huoqu.net_rate(), 'net', 'net_detail')
        process = add_tag(shouhu.check_alive(), 'process_down', 'process_alived')
        result = (tcp, cpu, mem, disk, net, process, ) 
        d = defer.Deferred()
        #使用defered返回結果
        d.callback(result)
        return d

    def xunhuan(self, list):
    #定義迴圈傳送函式
        for i in list:
            self.sendLine(i)

    def fasong(self):
    #定義程式執行順序,取得資訊後用callback交給傳送函式傳送
        self.huoqu_shuju().addCallback(self.xunhuan)

    def loop(self):
    #使用twist內建的迴圈函式定義幾秒監控資料傳送到服務端
        l = task.LoopingCall(self.fasong)
        l.start(1)

    def connectionMade(self):
    #覆蓋協議的connectmade函式,定義於服務端的連線建立後開始迴圈
        print 'Connected!......ok!'
        self.loop()

    def lineReceived(self, line):
    #必須覆蓋接受函式,否則twist會報not importent錯誤!
        pass


class Moinitor_client_factory(protocol.ReconnectingClientFactory):
    
    def __init__(self, service):
    #還沒想要要寫什麼
        self.service = service
    protocol = Monitor_Protocol


class Client_Service(service.Service):

    def __init__(self):
        pass

    def startService(self):
        service.Service.startService(self)


#配置檔案開始
port = 10000
host = '127.0.0.1'

#守護程序
top_service = service.MultiService()                   #定義服務容器

client_service = Client_Service()                      #例項化服務類
client_service.setServiceParent(top_service)           #把自己定義的服務丟到服務容器中

factory = Moinitor_client_factory(client_service)      #定義服務工廠化

tcp_service = internet.TCPClient(host, port, factory)  #定義tcp連線的服務
tcp_service.setServiceParent(top_service)              #把tcp服務丟到服務容器中去

application = service.Application('Fish_Service')      #定義應用名字
top_service.setServiceParent(application)              #把服務容器丟到應用中去

一些自定義監控程式是否存活的指令碼:
program = {'nginx': ['/opt/nginx/logs/nginx.pid', '/opt/nginx/sbin/nginx'],
            'rsync-C': ['/var/run/rsyncd.pid', 'rsync --daemon'],
            }


def main():
    for k in program:
        a = get_pid(k, program[k][0])
        if isinstance(a, tuple):
            print '%s is not running!' % k
            print 'Start the program by Horland_guardian!'
            subprocess.call(program[k][1], shell=True)
        else:
            print 'The %s is running!' % k


def check_alive():
    l_lived = []
    l_downed = []
    for k in program:
        a = get_pid(k, program[k][0])
        if isinstance(a, tuple):
            l_downed.append(k)
        else:
            l_lived.append(k)
    process_alived = ' '.join(l_lived)
    process_down = ' '.join(l_downed)

    return '::'.join([process_down, process_alived])


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

下面是一些程式碼段:

model

class BasicInfo(models.Model):
    ipadd = models.IPAddressField(verbose_name = u'IP地址')
    time = models.CharField(max_length=50, verbose_name = u'時間')
    cpu = models.CharField(max_length=255, blank=True, verbose_name = u'CPU%')
    cpu_detail = models.CharField(max_length=255, blank=True, verbose_name = u'CPU詳情')
    mem = models.CharField(max_length=255, blank=True, verbose_name = u'記憶體%')
    mem_detail = models.CharField(max_length=255, blank=True, verbose_name = u'記憶體詳情')
    disk = models.CharField(max_length=255, blank=True, verbose_name = u'磁碟%')
    disk_detail = models.CharField(max_length=255, blank=True, verbose_name = u'磁碟詳情')
    net = models.CharField(max_length=255, blank=True, verbose_name = u'流量 bytes/s')
    net_detail = models.CharField(max_length=1000, blank=True, verbose_name = u'流量詳情')
    tcp = models.CharField(max_length=255, blank=True, verbose_name = u'tcp連線狀態')
    process_down = models.CharField(max_length=255, blank=True, verbose_name = u'DOWN-程序')
    process_alived = models.CharField(max_length=255, blank=True, verbose_name = u'Process_UP')

    def Process_DOWN(self):
        return '<span style="color: #%s;">%s</span>' % ('ff0000', self.process_down)  #拓機的程序用紅色標識
    Process_DOWN.allow_tags = True

註冊到admin

class BasicInfo_admin(admin.ModelAdmin):

    list_display = ('time', 'cpu', 'cpu_detail', 'mem', 'mem_detail', 'disk', 'disk_detail', 'net', 'net_detail', 'tcp', 'Process_DOWN', 'process_alived')
    list_filter = ('ipadd', )
admin.site.register(BasicInfo, BasicInfo_admin)

freemind整理的思路中還有一些功能沒有實現,目前這個只能算個簡單的demon吧,但是基本實現了監控的目的。歡迎大家給我留言!

下面上個django的admin介面截圖吧!


程式碼下載

http://download.csdn.net/detail/qcpm1983/7611579