zoukankan      html  css  js  c++  java
  • 自动化监控系统(四) 客户端设计

    一个程序的目录结构:

    bin:可执行文件

    conf:配置文件

    core:逻辑关系

    plugins:各种插件

    var:日志

    客户端:

    1、设置一个程序入口,运行该文件A就能启动客户端。

    2、给A传位置参数(start 或 stop),通过获取位置参数名称,使用反射来调用相应方法,做到启动或者停止client。

    3、启动客户端后,通过发起HTTP请求,获取service下发的任务(监控哪些服务:CPU、memory、network。。。。。。)

    发送请求中,应该有client相关配置信息:主机Id、主机IP地址、主机端口、url配置、请求超时时间和更新监控配置时间。

    暂时这些,后面再添加

     client端通过特定url,发送http请求,然后server端返回相应的信息,告诉client需要监控什么服务

    在服务端也需要添加相应的url和view,返回客户端的请求信息。

    view

    from django.shortcuts import render
    
    # Create your views here.
    
    from django.views.generic import View
    from django.http import HttpResponse
    import json
    
    from .serializer import ClientHandler
    
    
    class client_config_view(View):
    
        #返回客户端需要监控信息
        def get(self,request,client_id):
            #获取client信息
            # client_configs = ClientHandler(client_id).fetch_configs()
            client_obj = ClientHandler(client_id)
            client_config = client_obj.fetch_configs()
            print("客户端ID",client_id)
            if client_config:
                return HttpResponse(json.dumps(client_config),content_type="application/json")
    View Code

    serializer

    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    __author__ = "BIGNI"
    __date__ = "2017/4/29 16:34"
    import traceback
    
    from django.views.generic import View
    
    from .models import Host
    
    
    class ClientHandler(View):
        #初始化
        def __init__(self,client_id):
            self.client_id = client_id
            #client配置
            self.client_configs = {
                "services":{}
            }
    
    
        def fetch_configs(self):
    
            try:
    
                host_obj_id = Host.objects.get(id=self.client_id)
                print(">>>>>>>>>",host_obj_id)
                #获取模板list
                template_list = list(host_obj_id.templates.select_related())
                print(">>>>",template_list)
                #获取主机组obj
    
                host_group_obj = host_obj_id.host_groups.select_related()
                #把主机组下的目标添加进来
                template_list.extend([template for template in host_group_obj])
                print("--->",template_list)
                #获取服务列表
                for template in template_list:
                    for service in template.services.select_related():
                        print(service)
                        #获取插件名和间隔时间
                        self.client_configs['services'][service.name] = [service.plugin_name,service.interval]
    
            except:
                traceback.print_exc()
            return self.client_configs
    
    # test = ClientHandler(1)
    # print(test,test.fetch_configs())
    View Code

     测试下:

    调用特定url,server端可以返回需要监控的信息。

    {"services": {"LinuxCPU": ["get_linux_cpu", 15], "LinuxNetwork": ["GetNetworkStatus", 60], "LinuxMemory": ["get_memory_info", 60]}}
    返回这种格式{"services":{"监控的服务":["插件名",监控间隔]}}
    client拿到这个信息后会根据插件名调用相关的脚本,拿到数据返回给server,这一过程会在线程里完成。

     接下来继续client端的开发:

    1、通过运行monitor_client启动客户端,执行main_command方法。

    2、main_command方法自带start和stop两个方法

    #!/usr/bin/env python
    # _*_ coding:utf-8 _*_
    __author__ = "BIGNI"
    __date__ = "2017/4/15 23:48"
    
    from .client import ClientHandlers
    
    class main_command(object):
        #初始化
        def __init__(self,sys_argv):
            self.sys_argv = sys_argv
            if len(sys_argv) < 2 :
                exit("请输入start或stop")
            else:
                self.entry_command()
    
        #根据命令调用方法
        def entry_command(self):
            print("##############################################")
            if hasattr(self.sys_argv[1]):
                func = getattr(self,self.sys_argv[1])
                return func()
            else:
                print("请输入正确的命令")
    
    
        def start(self):
            client = ClientHandlers()
            client.forever_run()
    
        def stop(self):
            pass
    main_command

    3、start方法会创建ClientHandlers对象,接着调用里面的forever_run方法,获取server端返回的信息,并根据插件名给各个服务进行监控

    #!/usr/bin/env python3
    # _*_ coding:utf-8 _*_
    __author__ = "BIGNI"
    __date__ = "2017/4/29 11:42"
    import time,threading,json
    
    import requests
    
    from conf import settings
    from plugins import plugin_api
    
    class ClientHandlers(object):
    
        def __init__(self):
            #初始化监控服务
            self.monitor_services = {}
    
        def load_lastest_config(self):
            """
            加载最新的配置信息
            :return:
            """
            #request请求方式
            request_type = settings.configs["urls"]["get_configs"][1]
            #拼接url
            request_url = "%s/%s" % (settings.configs['urls']['get_configs'][0], settings.configs['HostID'])
            lastest_config = self.url_request(request_type,request_url)
            #把最小配置更新到监控服务字典中
            self.monitor_services.update(lastest_config)
    
    
        def forever_run(self):
            #启动客户端
            exit_flag = False
            #第一次启动时初始化最新配置时间
            config_lastest_update_time = 0
            while not exit_flag:
    
                if time.time() - config_lastest_update_time > settings.configs['ConfigUpdateInterval']:
                    self.load_lastest_config()
                    print("Lastest_config:",self.monitor_services)
                    config_lastest_update_time = time.time()
    
                """
                Lastest_config: {'services': {'LinuxCPU': ['get_linux_cpu', 15], 'LinuxMemory': ['get_memory_info', 60],
                'LinuxNetwork': ['GetNetworkStatus', 60]}}
    
                """
                for service_name,val in self.monitor_services['services'].items():
                    if len(val) ==2:
                        # 第一次启动插件时,初始化当前时间,给每个服务维护一个计时器
                        self.monitor_services['services'][service_name].append(0)
                    #获取监控间隔和最新插件时间
                    monitor_interval = val[1]
                    last_invoke_time = val[2]
                    if time.time() - last_invoke_time > monitor_interval:
                        print("--->",last_invoke_time,"--->",time.time())
                        #重置计时器时间
                        self.monitor_services['services'][service_name][2] = time.time()
                        t = threading.Thread(target=self.invoke_plugin,args=(service_name,val))
                        t.start()
                        print("启动监控的服务: [{ServiceName}]".format(ServiceName=service_name))
    
                    else:
                        #需要等待监控间隔时间
                        print("监控的服务: {ServiceName} 距离下次启动时间:{interval} secs".format(ServiceName=service_name,
                                                                      interval=monitor_interval - (time.time() - last_invoke_time)))
                        time.sleep(5)
    
            time.sleep(1)
    
    
        #运行插件
        def invoke_plugin(self,service_name,val):
            #{"services": {"LinuxNetwork": ["n/a", 60,0], "LinuxMemory": ["n/a", 60,0], "LinuxCPU": ["n/a", 60,0]}}
            #获取插件名
            plugin_name = val[0]
            if hasattr(plugin_api,plugin_name):
                func = getattr(plugin_api,plugin_name)
                plugin_callback = func()
                print("####################################################")
                print(plugin_callback)
                print("####################################################")
    
                report_data = {
                    'client_id':settings.configs['HostID'],
                    'service_name':service_name,
                    'data':plugin_callback
                }
                #请求方式get or post
                request_action = settings.configs['urls']['service_report'][1]
                #请求路径
                request_url = settings.configs['urls']['service_report'][0]
    
                #report_data = json.dumps(report_data)
                # print('---report data(发送的数据):',report_data)
                #调用url_request方法,以post方式发送request
                self.url_request(request_action, request_url, params=report_data)
            else:
                print("33[31;1mCannot find service [%s]'s plugin name [%s] in plugin_api33[0m"% (service_name,plugin_name ))
            print('--plugin:',val)
    
    
        def url_request(self,action,request_url,**extra_data):
    
            abs_url = "http://{ip_addr}:{port}/{url}".format(ip_addr=settings.configs["Server"],
                                                             port=settings.configs["ServerPort"],
                                                             url=request_url)
            print("33[31;1m{abs_url}33[0m".format(abs_url=abs_url),type(extra_data),extra_data)
            if action in ('get',"GET"):
                print(abs_url,extra_data)
                try:
                    r = requests.get(abs_url,timeout=settings.configs['RequestTimeout'])
                    r_data = r.json()
                    return r_data
    
                except requests.RequestException as E :
                    exit("33[31;1m%s33[0m" % E)
    
            elif action in ('post','POST'):
                try:
                    #把数据转换成json再通过post发送
                    # data = json.dumps(extra_data['params'])
                    req = requests.post(url=abs_url,data=extra_data["params"])
    
                    res_data = req.json()
                    # res_data = req.text
                    print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
                    print("33[31;1m[%s]:[%s]33[0m response:
    %s,%s" % (action, abs_url, res_data,data))
                    print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
                    return res_data
    
                except Exception as e:
                    print('------exec', e)
                    exit("33[31;1m%s33[0m" % e)
    client

    PS:客户端在接收到服务端返回的配置信息,并不能识别具体要监控的服务,比如server端告诉client端需要监控CPU各项参数等,所以两端要能约定好,比如server端返回CPU、Memory和Network这三个字符串,就表示要监控这三种服务,三个字符串在这里就是插件名。插件统一放在plugins目录下。

     不同服务监控的时间可以通过server端返回的监控间隔来判断

     

     每次监控服务就生成一个新的线程,然后就让线程返回数据给服务端,不需要再做处理。

    client通过post发送的数据格式:

    report_data = {
         #客户端ID
          client_id':settings.configs['HostID'],
          #服务名
          'service_name':service_name,
          #数据
          'data':plugin_callback
    }

    发送数据这里我踩了个坑,其实也是不熟悉requests模块造成的,requests的post发送有三种方式,其中有form和json两种,

    区别是form发送可以直接把report_data直接发送到客户端,通过request.post.get方法可以获取到值。但我的report_data是嵌套字典,这种发送方式会把数据内容进行转换(细节我没搞懂,反正我传的数据变了。),所以嵌套字典的先转换成json格式,然后再用requests发送,服务端通过request.body可以拿到数据。

     对于server端和client端的数据交互,推荐使用requests模块,可以自动处理数据的编码、json、发送超时等问题。

     问题1:在models里的manytomany字段不会存储在数据表中,多对多的在xadmin里要按ctrl选中才行,不然通过select_relate获取到的是空的queryset,

    问题2:我调用model的serializer没放在app的默认views文件里,进行debug调试时,serializer也需要打上断点。

    问题3:我在client通过post方式发送数据给server端,debug调试时发现没取到值,查了资料,原来requests库有三种post发送数据方式,我使用的是json方式(发送前先用json.dumps处理下),改成用form方式(实际就是不需要json,requests会自动转换)

     
  • 相关阅读:
    The Mac Application Environment 不及格的程序员
    Xcode Plugin: Change Code In Running App Without Restart 不及格的程序员
    The property delegate of CALayer cause Crash. 不及格的程序员
    nil localizedTitle in SKProduct 不及格的程序员
    InApp Purchase 不及格的程序员
    Safari Web Content Guide 不及格的程序员
    在Mac OS X Lion 安装 XCode 3.2 不及格的程序员
    illustrate ARC with graphs 不及格的程序员
    Viewing iPhoneOptimized PNGs 不及格的程序员
    What is the dSYM? 不及格的程序员
  • 原文地址:https://www.cnblogs.com/laonicc/p/6701779.html
Copyright © 2011-2022 走看看