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

posted @ 2020-03-26 20:15  亚峰牛皮  阅读(...)  评论(...编辑  收藏
返回顶部