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 :   第三方文件目录
- src /core : 核心的源代码文件目录
  //- log:  记录日志    放在 /var/logs/  下面
- test: 测试文件目录   

高级配置文件的设置

        # 全局配置
        for k in dir(global_settings):
            if k.isupper():
                v = getattr(global_settings, k)
                setattr(self, k, v)  #### USER = 'qqq'
                
        # 集成用户自定义的配置
        for k in dir(config):
            if k.isupper():
                v = getattr(config, k)
                setattr(self,k, v)   ### USER = root

高内聚低耦合思想

目标:实现两套方案切换采集 两套方案实现采集主机名的思路:

第一个版本代码:

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

def execute(self):
    ### 1. 从配置文件中读取配置
    response = {}
    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)
        m = importlib.import_module(moudle_path) ### 导入字符串路径的
        ### 3.导入类,实例化类,执行防范
        cls = getattr(m, class_name)
        ret = cls().process()
        response[k] = ret

        return response

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

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

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

猜你喜欢

转载自www.cnblogs.com/baohanblog/p/12575565.html