zoukankan      html  css  js  c++  java
  • cmdb 可插拔式

    实现三套方案,采集IP信息

    首先应该能想到的代码:

            if self.mode == 'agent':
                import subprocess
                res = subprocess.getoutput(cmd)
                return res
    
            elif self.mode == 'ssh':
                import paramiko
                # 创建SSH对象
                ssh = paramiko.SSHClient()
                # 允许连接不在know_hosts文件中的主机
                ssh.set_missing_host_key_policy(paramiko.
                                                AutoAddPolicy())
                # 连接服务器
                ssh.connect(hostname=self.hostname, port=22,                                     username='root', password='root')
    
                # 执行命令
                stdin, stdout, stderr = ssh.exec_command(cmd)
                # 获取命令结果
                result = stdout.read()
    
                # 关闭连接
                ssh.close()
                return result
    
            elif self.mode == 'salt':
                import salt.client
    
                local = salt.client.LocalClient()
                result = local.cmd(self.hostname, 'cmd.run', [cmd])
                return result
            else:
                raise  Exception('当前模式只支持 agent/ssh/salt !!!')
    

    存在的问题很明显:

    1、复用性差,需要将其封装成方法,然后在进行调用

    2、高内聚低耦合原则(这一块代码是负责干啥的,其所有的代码都应该和这个功能是相关的)

    举个栗子:

    在函数中是:
    	def getUserInfo():
            #此函数体内,所有的代码,都应该和获取用户信息的这个目标功能相关联 ## 非			得要写处理订单相关的功能
            
    在类中,也是一样的概念:
    	class UserInfo():
        	def getUserInfo(): 
                pass 
            def login(): 
                pass 
            def logOut(): 
                pass
    

    采用高内聚低耦合的原则,迭代上述代码:

    思路:

    1.将硬盘或者cpu等代码封装成一个文件,此文件中涉及到的代码和这个文件的具体功能是相关的

    采取仿Django的可插拔式采集:

    a. conf.py 中的配置插件:

    import os
    
    BASEDIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
    
    USER = 'root'
    
    
    MODE = 'agent' ## ssh /salt
    
    DEBUG = True  ### True 代表调试模式  False 代表上线正式采集
    
    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',
        'nic'   : 'src.plugins.nic.Nic',
    }
    

    b. src下的plugins目录 创建__init__.py , 此文件中有一个类:

    #### 用来管理采集的插件的
    import traceback #这个模块是用来查看详情错误信息的,不然用了异常捕获,获取的信息只有一点点
    from lib.config.settings import settings #配置文件(高级配置和自定义都有)
    
    import importlib #关键模块,用来获取每个文件里面的类,然后调用Process方法。
    
    class Plugins_Dict():
    
        def __init__(self, hostname=None):
            self.mode = settings.MODE
            self.plugins_dict = settings.PLUGINS_DICT
            self.debug = settings.DEBUG
            self.hostname = hostname
    
    
        #### 从配置文件中读取插件配置,并执行相关的函数获取数据
        def execute(self):
            ### 1.从配置文件中读取插件配置
            res = {}
            for k, v in self.plugins_dict.items():
                ### 'basic' : 'src.plugins.basic.Basic',
                ### k: basic
                ### v: 'src.plugins.basic.Basic'
                response = {'status':None, 'data':None}
                #### 2. 导入模块, 获取类, 并实例化
                try:
                    # 这里解压缩,一个是src.plugins.basic,一个是Basic
                    module_path, class_name = v.rsplit('.', 1)
                    ### 3. 加载模块,给一个路径,就能把名称空间加载过来
                    m = importlib.import_module(module_path)
                    #### 4. 加载类, 通过反射,就可以在这个上面加载过来的名称空间					中拿到类。也就是栗子里的Basic类
                    cls = getattr(m, class_name)
                    #### 5. 执行每一个插件类下面的process方法,并且传入两个参				数,第一个是函数对象,第二个是debug。因为这里的每个process代表的只是设备,你需要获取信息的设备,如网卡,磁盘等等,以什么样的方式采集信息才是重点,也就是这个函数对象所做的。debug就是判断是否是调试。
                    ret = cls().process(self.command_func, self.debug )
    
                    response['status'] = 10000
                    response['data'] = ret
    
                except Exception as e:
                    response['status'] = 10001
                    #本来被捕获的异常打印出来只有一点点错误信息,无法精准判断错误位置和错误类型,用这个模块就可以知道了。
                    response['data'] = traceback.format_exc()
    
                res[k] = response
    
            return res
    
    	#这个函数就是用来传进process方法里的。之前也写过这个方法了。放在了这个__init__文件里面。
        def command_func(self, cmd):
    
            if self.mode == 'agent':
                import subprocess
                res = subprocess.getoutput(cmd)
                return res
    
            elif self.mode == 'ssh':
                import paramiko
                # 创建SSH对象
                ssh = paramiko.SSHClient()
                # 允许连接不在know_hosts文件中的主机
                ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
                # 连接服务器
                ssh.connect(hostname=self.hostname, port=22, username='root', password='root')
    
                # 执行命令
                stdin, stdout, stderr = ssh.exec_command(cmd)
                # 获取命令结果
                result = stdout.read()
    
                # 关闭连接
                ssh.close()
                return result
    
            elif self.mode == 'salt':
                import salt.client
    
                local = salt.client.LocalClient()
                result = local.cmd(self.hostname, 'cmd.run', [cmd])
                return result
            else:
                raise  Exception('当前模式只支持 agent/ssh/salt !!!')
    
    
    

    img

    这些都是插件,就是一个个设备,随便拿一个看一下,就拿cpu来看

    import os
    from lib.config.settings import settings
    class Cpu(object):
        def __init__(self):
            pass
    
        @classmethod
        def initial(cls):
            return cls()
    
        def process(self, command_func, debug):
            #如果是debug模式,就返回一些已经有了的准备好了的信息。
            if debug:
                output = open(os.path.join(settings.BASEDIR, 'files
                             /cpuinfo.out'), 'r',encoding='utf8').read()
            else:
                output = command_func("cat /proc/cpuinfo")
            return self.parse(output)
    	
        #这个函数就是用来解析拿到的结果的。
        def parse(self, content):
            """
            解析shell命令返回结果
            :param content: shell 命令结果
            :return:解析后的结果
            """
            response = {'cpu_count': 0, 'cpu_physical_count': 0, 'cpu_model': ''}
    
            cpu_physical_set = set()
    
            content = content.strip()
            for item in content.split('
    
    '):
                for row_line in item.split('
    '):
                    key, value = row_line.split(':')
                    key = key.strip()
                    if key == 'processor':
                        response['cpu_count'] += 1
                    elif key == 'physical id':
                        cpu_physical_set.add(value)
                    elif key == 'model name':
                        if not response['cpu_model']:
                            response['cpu_model'] = value
            response['cpu_physical_count'] = len(cpu_physical_set)
    
            return response
    
    

    这是一个Cpu类, 在__init__里面,通过反射拿到了这个类,并实例化,再执行了process方法。

  • 相关阅读:
    HTTP Digest authentication
    HDU 1520 Anniversary party 树形DP
    Servlet过滤器
    Js apply 方法 具体解释
    java 读取固定目录下的文件(和上篇差点儿相同)
    使用nodeitk进行角点检測
    ~/.local/share/Trash/files
    mv,Directory not empty不能目录覆盖
    cp 提示 overwrite 问题
    cv:显示Linux命令运行进度
  • 原文地址:https://www.cnblogs.com/chanyuli/p/12299937.html
Copyright © 2011-2022 走看看