zoukankan      html  css  js  c++  java
  • CMDB2 采集客户端目录架构设计, 高级配置文件, 可插拔式的采集

    采集客户端目录结构设计 参考ATM架构

    • bin : 可执行文件 start.py / run.py

    • conf: 配置文件目录 config.py

    • lib : 第三方文件目录

    • src /core : 核心的源代码文件目录 //- log: 记录日志 放在 /var/logs/ 下面

    • test: 测试文件目录

    高级配置文件的设置

    1、集成用户自定义配置与默认配置

    学习Django的配置文件我们配置文件,将类实例化,方法写在__init__中,在其他文件中直接 .settings就能获取到用户自定义的配置和默认的全局配置了,有自定义先用自定义,没有用默认的,先配置全局的配置,再配置自定义的配置

    lib/config/conf.py

    from conf import config     ## 导入自定义配置
    from . import global_settings   ## 导入高级配置
    
    class mySettings():
        # 继承用户自定义的配置和默认配置
        def __init__(self):
            # 全局配置
            for k in dir(global_settings):  # 变为字符串
                if k.isupper():
                    v = getattr(global_settings, k)
                    setattr(self, k, v)
    
    
            # 集成用户自定义的配置
            for k in dir(config):   # 变为字符串
                if k.isupper():
                    v = getattr(config, k)
                    setattr(self,k,v)
    
    settings = mySettings()

    使用高内聚低耦合思想

    目标:实现agent与ssh两套方案切换采集

    两套方案实现采集主机名的思路:

    第一个版本代码:

        if settings.MODE == 'agent':
            import subprocess
            res = subprocess.getoutput('hostname')
        else:
            import paramiko
    
            # 创建SSH对象
            ssh = paramiko.SSHClient()
            # 允许连接不在know_hosts文件中的主机
           ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
            # 连接服务器
            ssh.connect(hostname='192.168.79.131', port=22, username='root', password='root')
    
            # 执行命令
            stdin, stdout, stderr = ssh.exec_command('hostname')
            # 获取命令结果
            result = stdout.read()
            print(result)
            # 关闭连接
            ssh.close()

    如果上述代码这样写的话,会带来如下问题:

    • 耦合度太高

    • 结构混乱,导致查找问题的时候不方便

    • 业务逻辑代码不能写在启动文件中

    问:如何解决上述存在的问题?

    答:将每一个功能都封装成一个文件,比如说采集磁盘的信息,可以搞一个disk.py文件,这个文件中所有的代码都是要和采集磁盘相关的,不能有其他 的相关代码。以此类推,采集CPU的信息,也要搞一个cpu.py文件. 这种思想就是高内聚低耦合思想

    第二个版本,执行采集:

    from src.plugins.basic import Basic
    from src.plugins.disk import Disk
    #from src.plugins.memory import Memory
    
    if __name__ == '__main__':
      # 需要获取哪一个将哪一个导入,如果不需要则将哪个注释
        Basic().process()
        Disk().process()
        #Memory().process()

    但是上述做法不是特别的完美,解决的方案是:将这些采集的插件写到配置文件中统一管理,参考django的中间件, 可插拔式的采集

    核心的采集方法:可插拔式样的采集

     conf/config.py

    ## 用户自定义的配置文件
    
    USER = 'root'
    import os
    BASEDIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    
    MODE = 'agent'  ### ssh
    # MODE = 'ssh'
    
    DEBUG = True    ### True:代表是开发测试阶段  False:代表是上现阶段
    
    
    PLUGINS_DICT = {
        'basic':'src.plugins.basic.Basic',
        'board': 'src.plugins.board.Board',
        'cpu':'src.plugins.cpu.Cpu',
        'disk':'src.plugins.disk.Disk',
        'memory':'src.plugins.memory.Memory',
    }

    src/plugins/__init__.py

    from lib.config.conf import settings
    import importlib
    
    class PluginsManager():
        def __init__(self):
            self.plugins_dict = settings.PLUGINS_DICT
            self.debug = settings.DEBUG
    
        # 管理配置文件插件,采集数据  从配置文件中读取配置,循环导入模块,实例化类,执行插件类对应的采集方法
        def execute(self):
            ### 1.从配置文件中读取配置
            reponse = {}
            for k,v in self.plugins_dict.items():
                '''
                k:basic
                v:src.plugins.basic.Basic
                '''
                # 2.循环导入模块
                '''
                moudle_path:'src.plugins.basic'
                class_name:'Basic'  
                '''
                moudle_path,class_name = v.rsplit('.',1)    # 从右面分割1次
                m = importlib.import_module(moudle_path)    # 导入字符串路径
                # print(m)
                # 导入类,实例化类,执行方法
                cls = getattr(m,class_name)
                # 执行类下的获取信息函数,每一个方法都相同,鸭子类型,方便获取
                ret = cls().process(self.command_func,self.debug)
                reponse[k] = ret
            return reponse
    
        def command_func(self,cmd):
            if settings.MODE == 'agent':
                import subprocess
                res = subprocess.getoutput(cmd)
                return res
            else:
                import paramiko
    
                # 创建SSH对象
                ssh = paramiko.SSHClient()
                # 允许连接不在know_hosts文件中的主机
                ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
                # 连接服务器
                ssh.connect(hostname='10.0.0.200', port=22, username='root', password='admin123')
    
                # 执行命令
                stdin, stdout, stderr = ssh.exec_command(cmd)
                # 获取命令结果
                result = stdout.read()
    
                # 关闭连接
                ssh.close()
                return result

    插件代码,判断方案冗余,解决方案:

    1.继承 每一个子类都要继承父类的方法,通过传参的方式执行不一样的命令

    2.将函数名当成一个参数传给另一个函数

    其他部分代码:

    src/plugins/basic.py

    # 服务器基础信息,包括服务器主机名,操作系统版本等
    
    class Basic():
    
        def process(self,command_func,debug):
            if debug:
                output = {
                    'os_platform': "linux",
                    'os_version': "CentOS release 6.6 (Final)
    Kernel 
     on an m",
                    'hostname': 'c1.com'
                }
            else:
                output = {
                    'os_platform':command_func('uname').strip(),    # 操作系统名
                    'os_version':str(command_func('cat /etc/issue'),encoding=('utf8')).strip().split('
    ')[0],
                    'hostname':command_func('hostname').strip(),
                }
            return output

    lib/config/global_settings.py

    ### 全局的配置
    
    EMAIL_PORT = 25

    bin/start.py

    from src.plugins import PluginsManager
    
    if __name__ == '__main__':
        res = PluginsManager().execute()
    
        for k, v in res.items():
            print(k,v)
  • 相关阅读:
    ObserverPattern(观察者模式)-----Java/.Net
    MementoPattern(备忘录模式)-----Java/.Net
    SpringCloud-day02-服务消费者项目建立
    SpringCloud-基础项目构建
    idea git 整合使用
    springcloud-知识点总结(三):Hystrix & Dashboard & turbine & Zuul & SpringCloud Config
    springcloud-知识点总结(二):Ribbon&Feign
    springcloud-知识点总结(一):Eureka
    layui-tree创建下拉树型选项框
    ztree带有选项框的树形菜单使用
  • 原文地址:https://www.cnblogs.com/ludingchao/p/12578303.html
Copyright © 2011-2022 走看看