zoukankan      html  css  js  c++  java
  • CMDB项目的采集的目录设计,自定义配置,高内聚低耦合

    CMDB的概念

    """
    CMDB: Configure Manage DataBase 中文:配置管理数据库。主要的作用是:收集服务器的基础信息(包括:服务器的主机名,ip,操作系统版本,磁盘,CPU等信息),将来提供给子系统(代码发布,工单系统等)数据
    """
    

    CMDB的架构图方案

    • agent方案
    """
    	将待采集的服务器看成一个agent,然后再服务器上使用python的subprocess模块执行linux相关的命令,然后分析得到的结果,将分析得到的结果通过requests模块发送给API,API获取到数据之后,进行二次比对数据,最后将比对的结果存入到数据库中,最后django起一个webserver从数据库中将数据获取出来,供用户查看
    """
    
    • ssh方案
    """
    	在中控机服务器上安装一个模块叫paramiko模块,通过这个模块登录到带采集的服务器上,然后执行相关的linux命令,最后返回执行的结果,将分析得到的结果通过requests模块发送给API,API获取到数据之后,进行二次比对数据,最后将比对的结果存入到数据库中,最后django起一个webserver从数据库中将数据获取出来,供用户查看
    """
    
    • 方案对比
    """
    	第一套方案的优点是:	不需要额外的增加中控机。 缺点:每新增一台服务器,就需要额外部署agent脚本。使用场景是:服务器多的情况 (1000台以上)
    	第二套方案的优点是:不需要额外的部署脚本。缺点:速度比较慢。使用场景是:服务器少  (1000台往下)
    """
    

    采集客户端目录的结构设计

    """
    - bin :   可执行文件   start.py  / run.py 
    - conf:  配置文件目录  config.py
    - lib :   第三方文件目录
    - files:  临时测试的数据(线下)
    - src /core : 核心的源代码文件目录
      //- log:  记录日志    放在 /var/logs/  下面
    - test: 测试文件目录 
    """
    

    实现自定义配置以及全局配置

    from conf import config   # 导入自定义的配置
    from . import global_settings  # 导入全局配置
    
    class MySettings():
    
        # 集成用户自定义的配置和默认的全局配置
        def __init__(self):
            # 集成全局的配置
            for k in dir(global_settings):   # dir的作用就是将这个对象中的所有属性显示出来,以列表的形式存储
                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()
    

    高内聚低耦合思想

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

    第一个版本:直接在启动文件中判断

        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的中间件, 可插拔式的采集 核心的采集方法:

    第三种版本

    ### 这是用户自定义的配置
    
    # 将所有插件写到配置文件,不想用就注释掉即可
    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',
    }
    
    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、先从配置文件中读取配置
            response = {}
            for k, v in self.plugins_dict.items():
                '''
                k:basic
                v:src.plugins.basic.Basic
                '''
                # 循环导入模块
                '''
                moudle_path:'src.plugins.basic'
                class_name: 'Basic'
                '''
                moudle_path, class_name = v.rsplit('.', 1)
    
                ### 2 通过字符串路径去导入对应的模块,得到的是对象
                m = importlib.import_module(moudle_path)
    
                ### 3导入类,实例化类,执行方法
                cls = getattr(m, class_name)
                res = cls().process(self.command_func, self.debug)
                response[k] = res
    
            return response
    
        def command_func(self, cmd): # 将函数名当成内存地址传递给process,解决插件代码的冗余
            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='root')
    
                # 执行命令
                stdin, stdout, stderr = ssh.exec_command(cmd)
                # 获取命令结果
                result = stdout.read()
                # print(result)
    
                # 关闭连接
                ssh.close()
                return result
    
    
  • 相关阅读:
    MD5 加密 以及 加盐加密
    github--新手使用错误分析
    iOS开发UI篇—UITabBarController简单介绍
    Xcode 那些简单实用的插件推荐
    app 转caf 音频 代码
    关于block 用法
    iOS 之播放系统声音
    ios如何实现推送通知
    Centos7安装Redis
    SpringCloud-Zuul网关
  • 原文地址:https://www.cnblogs.com/yafeng666/p/12577045.html
Copyright © 2011-2022 走看看