目录结构设计

采集客户端

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

高级配置文件的设置

用户自定义配置

全局配置

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)  #### USER = 'qqq'

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

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

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. 从配置文件中读取配置
        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(self.command_func, self.debug )
            response[k] = ret

        return response

    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='192.168.79.131', port=22, username='root', password='root')

            # 执行命令
            stdin, stdout, stderr = ssh.exec_command(cmd)
            # 获取命令结果
            result = stdout.read()

            # 关闭连接
            ssh.close()
            return (result)

插件代码,判断方案冗余,解决方案:
1.继承 每一个子类都要继承父类的方法,通过传参的方式执行不一样的命令
2.将函数名当成一个参数传给另一个函数



插件采集核心代码

disk.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import re
import os
from lib.config.conf import settings



class Disk(object):
    def __init__(self):
        pass

    @classmethod
    def initial(cls):
        return cls()

    def process(self, command_func, debug):
        if debug:
            output = open(os.path.join(settings.BASEDIR, 'files/disk.out'), 'r', encoding='utf-8').read()
        else:
            output = command_func(" MegaCli -PDList -aALL") ### radi 卡 磁盘阵列
        return self.parse(output)

    def parse(self, content):
        """
        解析shell命令返回结果
        :param content: shell 命令结果
        :return:解析后的结果
        """
        response = {}
        result = []
        for row_line in content.split("\n\n\n\n"):
            result.append(row_line)
        for item in result:
            temp_dict = {}
            for row in item.split('\n'):
                if not row.strip():
                    continue
                if len(row.split(':')) != 2:
                    continue
                key, value = row.split(':')
                name = self.mega_patter_match(key)
                if name:
                    if key == 'Raw Size':
                        raw_size = re.search('(\d+\.\d+)', value.strip())
                        if raw_size:

                            temp_dict[name] = raw_size.group()
                        else:
                            raw_size = '0'
                    else:
                        temp_dict[name] = value.strip()
            if temp_dict:
                response[temp_dict['slot']] = temp_dict
        return response

    @staticmethod
    def mega_patter_match(needle):
        grep_pattern = {'Slot': 'slot', 'Raw Size': 'capacity', 'Inquiry': 'model', 'PD Type': 'pd_type'}
        for key, value in grep_pattern.items():
            if needle.startswith(key):
                return value
        return False


board.py

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import os
from lib.config.conf import settings


class Board(object):


    def process(self, command_func, debug):
        if debug:
            output = open(os.path.join(settings.BASEDIR, 'files/board.out'), 'r', encoding='utf-8').read()
        else:
            output = command_func(" dmidecode -t1")

        return self.parse(output)

    def parse(self, content):

        result = {}
        key_map = {
            'Manufacturer': 'manufacturer',
            'Product Name': 'model',
            'Serial Number': 'sn',
        }

        for item in content.split('\n'):
            row_data = item.strip().split(':')

            if len(row_data) == 2:
                if row_data[0] in key_map:
                    result[key_map[row_data[0]]] = row_data[1].strip() if row_data[1] else row_data[1]

        return result

 posted on 2020-03-26 20:14  Rannie`  阅读(182)  评论(0编辑  收藏  举报
去除动画
找回动画