zoukankan      html  css  js  c++  java
  • 高级配置和插件

    目录结构设计

    采集客户端

    • 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("
    
    
    
    "):
                result.append(row_line)
            for item in result:
                temp_dict = {}
                for row in item.split('
    '):
                    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('
    '):
                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
    
    
  • 相关阅读:
    Stream流的使用
    ThreadLocal原理和使用场景?
    Python+Appium实现APP自动化测试
    查看Linux系统版本信息
    linux命令之修改yum源为国内镜像
    lsb_release: command not found 解决
    docker安装mysql
    win10 系统出现“你不能访问此共享文件夹,因为你组织的安全策略阻止未经身份验证的来宾访问。”
    python常用sys模块
    python常用os模块
  • 原文地址:https://www.cnblogs.com/kai-/p/12577037.html
Copyright © 2011-2022 走看看