Django项目:CMDB(服务器硬件资产自动采集系统)--12--08CMDB采集硬件数据日志记录

 1 #log.py
 2 
 3 # ————————08CMDB采集硬件数据日志记录————————
 4 import os # 操作系统层面执行
 5 import logging  #日志模块
 6 from config import settings #配置文件
 7 
 8 class Logger(object):
 9     __instance = None #实例
10 
11     def __init__(self):
12         self.run_log_file = settings.RUN_LOG_FILE #运行日志路径 RUN_LOG_FILE = os.path.join(BASEDIR, "log", 'run.log')
13         self.error_log_file = settings.ERROR_LOG_FILE #错误日志路径 ERROR_LOG_FILE = os.path.join(BASEDIR, "log", 'error.log')
14         self.run_logger = None    #写运行日志
15         self.error_logger = None  #写错误日志
16         self.initialize_run_log() #初始化运行日志
17         self.initialize_error_log() #初始化错误日志
18 
19     def __new__(cls, *args, **kwargs):
20         if not cls.__instance: #实例
21             cls.__instance = object.__new__(cls, *args, **kwargs)
22         return cls.__instance #实例
23 
24     @staticmethod# 返回函数的静态方法
25     def check_path_exist(log_abs_file): #路径
26         log_path = os.path.split(log_abs_file)[0]#log文件夹
27         # print('日志文件:',log_path)
28         if not os.path.exists(log_path):#判断是否存在  log文件夹
29             os.mkdir(log_path) #创建 log文件夹
30 
31 
32     def initialize_run_log(self):#初始化运行日志
33         self.check_path_exist(self.run_log_file) #运行日志路径
34         #————————创建文件————————
35         file_1_1 = logging.FileHandler(self.run_log_file, 'a', encoding='utf-8')#
36         fmt = logging.Formatter(fmt="%(asctime)s - %(levelname)s :  %(message)s")
37         file_1_1.setFormatter(fmt)#为这个处理程序设置格式化程序。
38         # ————————创建文件————————
39         logger1 = logging.Logger('run_log', level=logging.INFO)#INFO = 20
40         logger1.addHandler(file_1_1) #指定处理程序添加到这个记录器。
41         self.run_logger = logger1
42         """
43         日志对应的级别
44         #CRITICAL = 50   #FATAL = CRITICAL   #ERROR = 40  #WARNING = 30    
45         #WARN = WARNING  #INFO = 20          #DEBUG = 10  #NOTSET = 0
46         """
47     def initialize_error_log(self): #初始化错误日志
48         self.check_path_exist(self.error_log_file)#错误日志路径
49         # ————————创建文件————————
50         file_1_1 = logging.FileHandler(self.error_log_file, 'a', encoding='utf-8')
51         fmt = logging.Formatter(fmt="%(asctime)s  - %(levelname)s :  %(message)s")
52         file_1_1.setFormatter(fmt)
53         # ————————创建文件————————
54         logger1 = logging.Logger('run_log', level=logging.ERROR)#ERROR = 40
55         logger1.addHandler(file_1_1)
56         self.error_logger = logger1
57 
58     def log(self, message, mode=True):#callback #写入日志#mode: True表示运行信息,False表示错误信息
59 
60         if mode:
61             self.run_logger.info(message) #Logger().log(ret['message'], True)
62         else:
63             self.error_logger.error(message)# Logger().log(ret['message'], False)
64 # ————————08CMDB采集硬件数据日志记录————————
#log.py

  1 # client.py
  2 # ————————01CMDB获取服务器基本信息————————
  3 from src import plugins  #__init__.py
  4 from lib.serialize import Json #转成字符串或者模式
  5 
  6 # ————————02CMDB将服务器基本信息提交到API接口————————
  7 import requests  #伪造页面访问
  8 from config import settings #文件配置
  9 # ————————02CMDB将服务器基本信息提交到API接口————————
 10 
 11 # ————————03CMDB信息安全API接口交互认证————————
 12 import hashlib
 13 import time
 14 # ————————03CMDB信息安全API接口交互认证————————
 15 
 16 # ————————04CMDB本地(Agent)模式客户端唯一标识(ID)————————
 17 import os         #操作系统层面执行
 18 import shutil     #高级的 文件、文件夹、压缩包 处理模块
 19 # ————————04CMDB本地(Agent)模式客户端唯一标识(ID)————————
 20 class AutoBase(object):
 21 
 22     # ————————02CMDB将服务器基本信息提交到API接口————————
 23     def __init__(self):
 24         self.asset_api = settings.ASSET_API  #ASSET_API = "http://127.0.0.1:8000/api/asset"
 25 
 26         # ————————03CMDB信息安全API接口交互认证————————
 27         self.key = settings.KEY  # 用于API认证的KEY#KEY = '299095cc-1330-11e5-b06a-a45e60bec08b'
 28         self.key_name = settings.AUTH_KEY_NAME  # 'auth-key'  API认证的请求头
 29         # ————————03CMDB信息安全API接口交互认证————————
 30 
 31     # ————————03CMDB信息安全API接口交互认证————————
 32     def auth_key(self):#API接口认证
 33         ha = hashlib.md5(self.key.encode('utf-8'))#认证的密码
 34         time_span = time.time() #现在的时间戳 #1529819687.8867188
 35         ha.update(bytes("%s|%f" % (self.key, time_span), encoding='utf-8'))#更新认证密码#密码+时间戳
 36         encryption = ha.hexdigest()  # 对‘时间密码’进行哈希
 37         result = "%s|%f" % (encryption, time_span) #把‘时间密码’和 时间戳(解密用)  作为 API认证的请求头
 38         print('‘时间密码’和 时间戳:',result)
 39         return {self.key_name: result}  # 'auth-key' API认证的请求头
 40     # ————————03CMDB信息安全API接口交互认证————————
 41 
 42     # ————————08CMDB采集硬件数据日志记录————————
 43     # def post_asset(self, msg):#post方式向API接口提交资产信息
 44     def post_asset(self, msg, callback=None): #post方式向API接口提交资产信息
 45     # ————————08CMDB采集硬件数据日志记录————————
 46 
 47         status = True#是否获取到信息
 48         try:
 49             # ————————03CMDB信息安全API接口交互认证————————
 50             headers = {}
 51             headers.update(self.auth_key())##认证的密码
 52             # ————————03CMDB信息安全API接口交互认证————————
 53             response = requests.post(
 54                 url=self.asset_api,
 55                 # ————————03CMDB信息安全API接口交互认证————————
 56                 headers=headers,
 57                 # ————————03CMDB信息安全API接口交互认证————————
 58                 json=msg
 59             )
 60         except Exception as e:
 61             response = e
 62             status = False  #获取信息时出现错误
 63         print(response.json())
 64     # ————————02CMDB将服务器基本信息提交到API接口————————
 65 
 66         # ————————08CMDB采集硬件数据日志记录————————
 67         print('服务器反馈:')
 68         print(callback)
 69         if callback:
 70             callback(status, response)
 71         # ————————08CMDB采集硬件数据日志记录————————
 72 
 73     # ————————08CMDB采集硬件数据日志记录————————
 74     def callback(self, status, response):#提交资产到服务器后的回调函数#请求成功,则是响应内容对象;请求错误,则是异常对象
 75         import json
 76         from lib.log import Logger  #写日志
 77         if not status:
 78             Logger().log(str(response), False)
 79             return
 80         ret = json.loads(response.text)
 81         if ret['code'] == 1000: #{'code': 1000, 'message': '[%s]更新完成' % hostname}
 82             #参数1:内容 参数2:True 运行日志 False 错误日志
 83             Logger().log(ret['message'], True)
 84         else:#错误日志
 85             Logger().log(ret['message'], False)
 86     # ————————08CMDB采集硬件数据日志记录————————
 87 
 88 
 89     def process(self):#派生类需要继承此方法,用于处理请求的入口
 90         raise NotImplementedError('您必须实现过程的方法')
 91 
 92 class AutoAgent(AutoBase):
 93 
 94     # ————————04CMDB本地(Agent)模式客户端唯一标识(ID)————————
 95     def __init__(self):
 96         self.cert_file_path = settings.CERT_FILE_PATH# Agent模式保存服务器唯一ID的文件
 97         super(AutoAgent, self).__init__()
 98         """
 99         super() 函数是用于调用父类(超类)的一个方法。
100         super 是用来解决多重继承问题的,直接用类名调用父类方法在使用单继承的时候没问题,
101                 但是如果使用多继承,会涉及到查找顺序(MRO)、重复调用(钻石继承)等种种问题。
102         MRO 就是类的方法解析顺序表, 其实也就是继承父类方法时的顺序表。
103         """
104     def load_local_cert(self):# 获取本地唯一标识
105         if not os.path.exists(self.cert_file_path):#使用os.path.exists()方法可以直接判断文件(或者文件夹)是否存在
106             return None #如果文件(或者文件夹)不存在 #返回空
107         if os.path.isfile(self.cert_file_path): #判断是不是文件
108             with open(self.cert_file_path, mode='r') as f: #如果文件存在 #打开读取文件
109                 data = f.read()#获取唯一ID的文件#read() 方法用于从文件读取指定的字节数,如果未给定或为负则读取所有。
110             if not data:  # 如果文件没有内容 #返回空
111                 return None
112             cert = data.strip()  # strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
113             return cert  # 返回 本地唯一标识
114         else: #防止有文件夹叫cert,导致无法创建cert文件
115             shutil.rmtree(self.cert_file_path)#就 递归的去删除文件夹 #这个目录以及子文件全部删除
116             return None #返回空 #去创建文件
117 
118     def write_local_cert(self, cert):#写入本地唯一标识
119         with open(self.cert_file_path, mode='w') as f: #循环打开文件 #没有就创建 然后打开
120             f.write(cert) #写入本地唯一标识
121     # ————————04CMDB本地(Agent)模式客户端唯一标识(ID)————————
122 
123     def process(self):
124         server_info = plugins.get_server_info()#获取本地基本信息
125 
126         # ————————04CMDB本地(Agent)模式客户端唯一标识(ID)————————
127         if not server_info.status: #获取的基本信息是否出错
128             return
129         local_cert = self.load_local_cert()  # 去获取本地唯一标识
130         if local_cert: #如果 获取本地唯一标识 后 #不是  return None
131             if local_cert == server_info.data['hostname']: #判断本地文件的唯一标识 是不是等于 获取的基本信息里主机名
132                 pass  #一样就什么都不干
133             else:   #不一样就把  获取的基本信息里主机名 替换成 本地文件的唯一标识
134                 #防止 恶意篡改 主机名 ,上报API时 错认为是 新资产
135                 server_info.data['hostname'] = local_cert  # 更新字典的主机名
136         else:  # 获取本地唯一标识为None时 #把获取到的主机名写入本地做为唯一标识
137             self.write_local_cert(server_info.data['hostname'])
138         # ————————04CMDB本地(Agent)模式客户端唯一标识(ID)————————
139 
140         server_json = Json.dumps(server_info.data)#json.dumps将 Python 对象编码成 JSON 字符串
141         print('提交资产信息:',server_json)
142 # ————————01CMDB获取服务器基本信息————————
143 
144         # ————————08CMDB采集硬件数据日志记录————————
145         # ————————02CMDB将服务器基本信息提交到API接口————————
146         # self.post_asset(server_json)# post方式向接口提交资产信息
147         self.post_asset(server_json, self.callback)# post方式向接口提交资产信息
148         # ————————02CMDB将服务器基本信息提交到API接口————————
149         # ————————08CMDB采集硬件数据日志记录————————
# client.py

 1 #base.py
 2 # ————————08CMDB采集硬件数据日志记录————————
 3 from lib.log import Logger
 4 # ————————08CMDB采集硬件数据日志记录————————
 5 
 6 # ————————01CMDB获取服务器基本信息————————
 7 from config import settings  #配置文件
 8 
 9 class BasePlugin(object):
10     def __init__(self, hostname=''):
11 
12         # ————————08CMDB采集硬件数据日志记录————————
13         self.logger = Logger() #日志 实例化
14         self.hostname = hostname  # 主机名默认为空,hostname=''
15         # ————————08CMDB采集硬件数据日志记录————————
16 
17         # ————————07CMDB文件模式测试采集硬件数据————————
18         self.test_mode = settings.TEST_MODE#是否测试模式
19         # ————————07CMDB文件模式测试采集硬件数据————————
20 
21         if hasattr(settings, 'MODE'):
22             self.mode = settings.MODE #采集资产的方式
23         else:
24             self.mode = 'agent'#默认,采集资产的方式
25     def execute(self):
26 
27         # ————————06CMDB测试Linux系统采集硬件数据的命令————————
28         # return self.windows()
29         try:#判断系统平台类型
30 
31             # ————————07CMDB文件模式测试采集硬件数据————————
32             if self.test_mode:  # 是否测试模式
33                 return self.test()  # 测试模式
34             # ————————07CMDB文件模式测试采集硬件数据————————
35 
36             import platform  # 获取操作系统信息 的模块
37             if platform.system() == 'Linux':
38                 return self.linux() #执行 #def linux(self):
39             elif platform.system() == 'Windows':
40                 return self.windows() #  执行 #def windows(self):
41         except Exception as e:
42             return '未知的系统平台类型!'
43         # ————————06CMDB测试Linux系统采集硬件数据的命令————————
44 
45     def windows(self):
46         raise Exception('您必须实现windows的方法')
47 # ————————01CMDB获取服务器基本信息————————
48 
49     # ————————06CMDB测试Linux系统采集硬件数据的命令————————
50     def linux(self):
51         raise Exception('您必须实现linux的方法')
52     # ————————06CMDB测试Linux系统采集硬件数据的命令————————
53 
54     # ————————07CMDB文件模式测试采集硬件数据————————
55     def test(self):#测试模式
56         raise Exception('您必须实现test的方法')
57     # ————————07CMDB文件模式测试采集硬件数据————————
#base.py

  1 # basic.py
  2 # ————————01CMDB获取服务器基本信息————————
  3 from .base import BasePlugin #采集资产的方式
  4 from lib.response import BaseResponse   #提交数据的类型
  5 import platform  #platform模块给我们提供了很多方法去获取操作系统的信息
  6 
  7 # ————————06CMDB测试Linux系统采集硬件数据的命令————————
  8 # import wmi#Windows操作系统上管理数据和操作的基础设施   #linux写无法导入这个模块
  9 # ————————06CMDB测试Linux系统采集硬件数据的命令————————
 10 """
 11 本模块基于windows操作系统,依赖wmi和win32com库,需要提前使用pip进行安装,
 12 我们依然可以通过pip install pypiwin32来安装win32com模块
 13 或者下载安装包手动安装。
 14 """
 15 
 16 class BasicPlugin(BasePlugin):
 17     def os_platform(self):#获取系统平台
 18         # ————————07CMDB文件模式测试采集硬件数据————————
 19         # output=platform.system() #windows和Linux 都可以执行
 20         # return output.strip()#strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
 21 
 22         try:
 23             if self.test_mode:  # 是否测试模式
 24                 output = 'Linux'  # 选择要测试的系统(windows和Linux或者苹果等未知的系统)
 25                 return output.strip()  # strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
 26             output = platform.system() #windows和Linux 都可以执行
 27             return output.strip()  # strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
 28         except Exception as e:
 29             return '未知的系统平台!'
 30         # ————————07CMDB文件模式测试采集硬件数据————————
 31 
 32     def os_version(self):#获取系统版本
 33         # output = wmi.WMI().Win32_OperatingSystem()[0].Caption
 34         # return output.strip()#strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
 35 
 36         # ————————06CMDB测试Linux系统采集硬件数据的命令————————
 37         try:
 38 
 39             # ————————07CMDB文件模式测试采集硬件数据————————
 40             if self.test_mode:  # 是否测试模式
 41                 output = """CentOS release 6.6 (Final)\nKernel \r on an \m"""
 42                 result = output.strip().split('\n')[0]  # strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。#split() 通过指定分隔符对字符串进行切片
 43                 return result
 44             # ————————07CMDB文件模式测试采集硬件数据————————
 45 
 46             if platform.system() == 'Linux':
 47                 import subprocess  # 启动一个新的进程并且与之通信
 48                 output = subprocess.getoutput('cat /etc/issue')  # Linux系统下的命令
 49                 result = output.strip().split('\n')[0]  # split() 通过指定分隔符对字符串进行切片
 50                 # strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
 51                 return result
 52             if platform.system() == 'Windows':
 53                 import wmi  # Windows操作系统上管理数据和操作的基础设施   #linux写无法导入这个模块
 54                 output = wmi.WMI().Win32_OperatingSystem()[0].Caption  # Windows系统下的命令
 55                 result = output.strip()
 56                 # strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
 57                 return result
 58         except Exception as e:
 59             return '未知的系统版本!'
 60         # ————————06CMDB测试Linux系统采集硬件数据的命令————————
 61 
 62     def os_hostname(self):#获取主机名
 63         # output = wmi.WMI().Win32_OperatingSystem()[0].CSName
 64         # return output.strip()#strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
 65 
 66         # ————————06CMDB测试Linux系统采集硬件数据的命令————————
 67         try:
 68 
 69             # ————————07CMDB文件模式测试采集硬件数据————————
 70             if self.test_mode:  # 是否测试模式
 71                 output = 'test.com'
 72                 return output.strip()  # strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
 73             # ————————07CMDB文件模式测试采集硬件数据————————
 74 
 75             if platform.system() == 'Linux':
 76                 import subprocess  # 启动一个新的进程并且与之通信
 77                 output = subprocess.getoutput('hostname')  # Linux系统下的命令
 78                 return output.strip()  # strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
 79             elif platform.system() == 'Windows':
 80                 import wmi # Windows操作系统上管理数据和操作的基础设施   #linux写无法导入这个模块
 81                 output = wmi.WMI().Win32_OperatingSystem()[0].CSName  # Windows系统下的命令
 82                 return output.strip()  # strip() 方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列。
 83         except Exception as e:
 84             return '未知的主机名!'
 85         # ————————06CMDB测试Linux系统采集硬件数据的命令————————
 86 
 87     def windows(self):
 88         response = BaseResponse()#提交数据的类型
 89         try:
 90             ret = {
 91                 'os_platform': self.os_platform(),#系统平台
 92                 'os_version': self.os_version(),#系统版本
 93                 'hostname': self.os_hostname(),#主机名
 94             }
 95             response.data = ret #字典形式
 96             print('windows服务器基本信息:',response.data)
 97         except Exception as e:
 98 
 99             # ————————08CMDB采集硬件数据日志记录————————
100             msg = "%s 基本的插件错误:%s"   #错误信息
101             import traceback    #捕获并打印异常
102             self.logger.log(msg % (self.hostname, traceback.format_exc()), False)#写入本地日志
103             response.error = msg % (self.hostname, traceback.format_exc()) #发送到远程日志
104             # ————————08CMDB采集硬件数据日志记录————————
105 
106             response.status = False  # 获取信息时出现错误
107         return response
108     """
109     class BaseResponse(object): #提交数据的类型
110     def __init__(self):
111         self.status = True      #状态
112         self.message = None     #消息
113         self.data = None        #数据内容
114         self.error = None       #错误信息
115 
116     """
117 # ————————01CMDB获取服务器基本信息————————
118 
119     # ————————06CMDB测试Linux系统采集硬件数据的命令————————
120     def linux(self):
121         response = self.windows() #因为执行同样的方法,所以,就不重复写。
122         print('linux服务器基本信息:', response.data)
123         return response
124     # ————————06CMDB测试Linux系统采集硬件数据的命令————————
125 
126     # ————————07CMDB文件模式测试采集硬件数据————————
127     def test(self):
128         response = self.windows() #因为执行同样的方法,所以,就不重复写。
129         print('test服务器基本信息:', response.data)
130         return response
131     # ————————07CMDB文件模式测试采集硬件数据————————
# basic.py

  1 # cpu.py
  2 # ————————05CMDB采集硬件数据的插件————————
  3 from .base import BasePlugin  #采集资产的方式  和  系统平台
  4 from lib.response import BaseResponse #提交数据的类型(字典)
  5 
  6 # ————————06CMDB测试Linux系统采集硬件数据的命令————————
  7 # import wmi#Windows操作系统上管理数据和操作的基础设施   #linux写无法导入这个模块
  8 # ————————06CMDB测试Linux系统采集硬件数据的命令————————
  9 
 10 class CpuPlugin(BasePlugin):
 11     def windows(self):
 12         response = BaseResponse() #提交数据的类型(字典)
 13         try:
 14             # ————————06CMDB测试Linux系统采集硬件数据的命令————————
 15             import wmi#Windows操作系统上管理数据和操作的基础设施   #linux写无法导入这个模块
 16             # ————————06CMDB测试Linux系统采集硬件数据的命令————————
 17             output =wmi.WMI().Win32_Processor() #获取CPU相关信息
 18             response.data = self.windows_parse(output)  #解析相关信息 返回结果 #存到字典
 19         except Exception as e:
 20 
 21             # ————————08CMDB采集硬件数据日志记录————————
 22             msg = "%s windows系统CPU插件错误:%s"   #错误信息
 23             import traceback    #捕获并打印异常
 24             self.logger.log(msg % (self.hostname, traceback.format_exc()), False)#写入本地日志
 25             response.error = msg % (self.hostname, traceback.format_exc()) #发送到远程日志
 26             # ————————08CMDB采集硬件数据日志记录————————
 27 
 28             response.status = False
 29         return response
 30 
 31     @staticmethod#返回函数的静态方法
 32     def windows_parse(content):
 33         response = {}
 34         cpu_physical_set = set()#set()函数创建一个无序不重复元素集,可进行关系测试,删除重复数据,还可以计算交集、差集、并集等。
 35         for item in content:
 36             response['cpu_model'] = item.Manufacturer  # cpu型号
 37             response['cpu_count'] = item.NumberOfCores  # cpu核心个量
 38             cpu_physical_set.add(item.DeviceID) #CPU物理个量
 39         response['cpu_physical_count'] = len(cpu_physical_set)#CPU物理个量
 40         return response #返回结果
 41 
 42 # ————————05CMDB采集硬件数据的插件————————
 43 
 44     # ————————07CMDB文件模式测试采集硬件数据————————
 45     def test(self):
 46         response = BaseResponse() #提交数据的类型(字典)
 47         import os  # 操作系统层面执行
 48         from config.settings import BASEDIR  # 获取路径
 49         try:
 50             output = open(os.path.join(BASEDIR, 'files/linux_out/cpu.out'), 'r').read() #打开文件获取内容
 51             response.data = self.linux_parse(output)#解析shell命令返回结果
 52         except Exception as e:
 53 
 54             # ————————08CMDB采集硬件数据日志记录————————
 55             msg = "%s 测试系统CPU插件错误:%s"   #错误信息
 56             import traceback    #捕获并打印异常
 57             self.logger.log(msg % (self.hostname, traceback.format_exc()), False)#写入本地日志
 58             response.error = msg % (self.hostname, traceback.format_exc()) #发送到远程日志
 59             # ————————08CMDB采集硬件数据日志记录————————
 60 
 61             response.status = False
 62         return response
 63     # ————————07CMDB文件模式测试采集硬件数据————————
 64 
 65 # ————————06CMDB测试Linux系统采集硬件数据的命令————————
 66     def linux(self):
 67         response = BaseResponse()  # 提交数据的类型(字典)
 68         try:
 69             import subprocess  # 启动一个新的进程并且与之通信
 70             shell_command = "cat /proc/cpuinfo"  # 定义命令 lscpu
 71             output = subprocess.getoutput(shell_command)  # linux系统上执行的命令
 72             response.data = self.linux_parse(output)  # 解析shell命令返回结果
 73         except Exception as e:
 74 
 75             # ————————08CMDB采集硬件数据日志记录————————
 76             msg = "%s linux系统CPU插件错误:%s"   #错误信息
 77             import traceback    #捕获并打印异常
 78             self.logger.log(msg % (self.hostname, traceback.format_exc()), False)#写入本地日志
 79             response.error = msg % (self.hostname, traceback.format_exc()) #发送到远程日志
 80             # ————————08CMDB采集硬件数据日志记录————————
 81 
 82             response.status = False
 83         return response
 84 
 85     @staticmethod  # 返回函数的静态方法
 86     def linux_parse(content):  # 解析shell命令返回结果
 87         response = {'cpu_count': 0, 'cpu_physical_count': 0, 'cpu_model': ''}
 88         cpu_physical_set = set()  # set()函数创建一个无序不重复元素集,可进行关系测试,删除重复数据,还可以计算交集、差集、并集等。
 89         content = content.strip()  # strip()方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列
 90         for item in content.split('\n\n'):  # split()通过指定分隔符对字符串进行切片
 91             for row_line in item.split('\n'):
 92                 key, value = row_line.split(':')
 93                 key = key.strip()
 94                 if key == 'processor':
 95                     response['cpu_count'] += 1  # cpu核心个量
 96                 elif key == 'physical id':
 97                     cpu_physical_set.add(value)  # CPU物理个量
 98                 elif key == 'model name':
 99                     if not response['cpu_model']:
100                         response['cpu_model'] = value  # cpu型号
101         response['cpu_physical_count'] = len(cpu_physical_set)  # CPU物理个量
102         return response
103 # ————————06CMDB测试Linux系统采集硬件数据的命令————————
# cpu.py

  1 # disk.py
  2 # ————————05CMDB采集硬件数据的插件————————
  3 from .base import BasePlugin  #采集资产的方式  和  系统平台
  4 from lib.response import BaseResponse #提交数据的类型(字典)
  5 # ————————06CMDB测试Linux系统采集硬件数据的命令————————
  6 # import wmi#Windows操作系统上管理数据和操作的基础设施   #linux写无法导入这个模块
  7 # ————————06CMDB测试Linux系统采集硬件数据的命令————————
  8 
  9 class DiskPlugin(BasePlugin):
 10     def windows(self):
 11         response = BaseResponse() #提交数据的类型(字典)
 12         try:
 13             # ————————06CMDB测试Linux系统采集硬件数据的命令————————
 14             import wmi#Windows操作系统上管理数据和操作的基础设施   #linux写无法导入这个模块
 15             # ————————06CMDB测试Linux系统采集硬件数据的命令————————
 16             output =wmi.WMI().Win32_DiskDrive() #获取磁盘相关信息
 17             response.data = self.windows_parse(output) #解析相关信息 返回结果 #存到字典
 18         except Exception as e:
 19 
 20             # ————————08CMDB采集硬件数据日志记录————————
 21             msg = "%s windows系统硬盘插件错误:%s"   #错误信息
 22             import traceback    #捕获并打印异常
 23             self.logger.log(msg % (self.hostname, traceback.format_exc()), False)#写入本地日志
 24             response.error = msg % (self.hostname, traceback.format_exc()) #发送到远程日志
 25             # ————————08CMDB采集硬件数据日志记录————————
 26 
 27             response.status = False
 28         return response
 29 
 30     @staticmethod#返回函数的静态方法
 31     def windows_parse(content):
 32         response = {}
 33         for item in content:
 34             item_dict = {}
 35             item_dict['slot'] = item.Index                      #插槽位
 36             item_dict['pd_type'] = item.InterfaceType           #磁盘型号
 37             item_dict['capacity'] = round(int(item.Size) / (1024**3))   # 磁盘容量
 38             item_dict['model'] = item.Model  #磁盘类型
 39             response[item_dict['slot']] = item_dict #分割存每个 磁盘信息
 40         return response #返回结果
 41 # ————————05CMDB采集硬件数据的插件————————
 42 
 43     # ————————07CMDB文件模式测试采集硬件数据————————
 44     def test(self):
 45         response = BaseResponse() #提交数据的类型(字典)
 46         import os  # 操作系统层面执行
 47         from config.settings import BASEDIR  # 获取路径
 48         try:
 49             output = open(os.path.join(BASEDIR, 'files/linux_out/disk.out'), 'r').read() #打开文件获取内容 linux_virtual_out  linux_out
 50             response.data = self.linux_parse(output)#解析shell命令返回结果
 51         except Exception as e:#如果获取内容错误或者解析错误就换一个方式
 52             try:
 53                 output = open(os.path.join(BASEDIR, 'files/linux_virtual_out/disk.out'),'r').read()  # 打开文件获取内容 linux_virtual_out  linux_out
 54                 response.data = self.linux_virtual_parse(output)  # 解析shell命令返回结果
 55             except Exception as e:#如果 出现未知错误
 56 
 57                 # ————————08CMDB采集硬件数据日志记录————————
 58                 msg = "%s 测试系统硬盘插件错误:%s"  # 错误信息
 59                 import traceback  # 捕获并打印异常
 60                 self.logger.log(msg % (self.hostname, traceback.format_exc()), False)  # 写入本地日志
 61                 response.error = msg % (self.hostname, traceback.format_exc())  # 发送到远程日志
 62                 # ————————08CMDB采集硬件数据日志记录————————
 63                 response.status = False
 64         return response
 65 
 66     # ————————07CMDB文件模式测试采集硬件数据————————
 67 
 68     # ————————06CMDB测试Linux系统采集硬件数据的命令————————
 69     def linux(self):
 70         response = BaseResponse() #提交数据的类型(字典)
 71         try:
 72             import subprocess  # 启动一个新的进程并且与之通信
 73             shell_command = "sudo MegaCli  -PDList -aALL"  #定义命令#需要安装 MegaCli 模块
 74             output = subprocess.getoutput(shell_command) #linux系统上执行的命令
 75             if 'MegaCli'in output:
 76                 shell_command = "lsblk"  # 虚拟机 #lsblk
 77                 output = subprocess.getoutput(shell_command)  # linux系统上执行的命令
 78                 response.data = self.linux_virtual_parse(output)  # 解析shell命令返回结果
 79             else:
 80                 response.data = self.linux_parse(output)#解析shell命令返回结果
 81         except Exception as e:  # 如果 出现未知错误
 82 
 83             # ————————08CMDB采集硬件数据日志记录————————
 84             msg = "%s linux系统硬盘插件错误:%s"   #错误信息
 85             import traceback    #捕获并打印异常
 86             self.logger.log(msg % (self.hostname, traceback.format_exc()), False)#写入本地日志
 87             response.error = msg % (self.hostname, traceback.format_exc()) #发送到远程日志
 88             # ————————08CMDB采集硬件数据日志记录————————
 89 
 90             response.status = False
 91         return response
 92 
 93     def linux_virtual_parse(self, content):  # 解析shell命令返回结果
 94         content = [i for i in content.split('\n') if i != '']  # split()通过指定分隔符对字符串进行切片
 95         key_list = [i for i in content[0].split(' ') if i != '']  # split()通过指定分隔符对字符串进行切片
 96         key_list[0] = 'slot'  # 替换key的名字
 97         key_list[3] = 'capacity'
 98         key_list[5] = 'pd_type'
 99         ram_dict = {}
100         for i in content[1:]:  # 从列表下标1开始循环
101             segment = {}
102             value = [x for x in i.split(' ') if x != '']  # 如果不是空值就循环   # split()通过指定分隔符对字符串进行切片
103             filter = str(value)  # 列表转成字符串进行判断
104             if '' not in filter:  # '─'  '攢' #二级逻辑硬盘
105                 if '' not in filter:  # '─'  '攢' #二级逻辑硬盘
106                     list = zip(key_list, value)  # zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
107                     for k, v in list:
108                         if k == 'capacity':  # 处理单位问题
109                             if 'G' in v:
110                                 l = v.split('G')  # split()通过指定分隔符对字符串进行切片
111                                 v = l[0]
112                             if 'M' in v:  # 处理单位问题
113                                 l = v.split('M')  # split()通过指定分隔符对字符串进行切片
114                                 s = l[0]
115                                 m = int(s)
116                                 v = m / 1024
117                         segment[k] = v
118                     ram_dict[value[0]] = segment
119         return ram_dict
120 
121     def linux_parse(self, content):  # 解析shell命令返回结果
122         import re  # 正则表达式
123         response = {}
124         result = []
125         for row_line in content.split("\n\n\n\n"):  # split()通过指定分隔符对字符串进行切片
126             result.append(row_line)  # 添加到列表
127         for item in result:  # 循环列表
128             temp_dict = {}
129             for row in item.split('\n'):  # split()通过指定分隔符对字符串进行切片
130                 if not row.strip():  # strip()方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列
131                     continue
132                 if len(row.split(':')) != 2:  # 测试长度
133                     continue
134                 key, value = row.split(':')  # split()通过指定分隔符对字符串进行切片
135                 name = self.mega_patter_match(key)
136                 if name:
137                     if key == 'Raw Size':  # 磁盘容量
138                         raw_size = re.search('(\d+\.\d+)',
139                                              value.strip())  # Raw Size: 279.396 GB [0x22ecb25c Sectors]
140                         if raw_size:
141                             temp_dict[name] = raw_size.group()
142                         else:
143                             raw_size = '0'
144                     else:
145                         temp_dict[name] = value.strip()  # 磁盘型号  #磁盘类型
146             if temp_dict:
147                 response[temp_dict['slot']] = temp_dict  # 插槽位 #分割存每个 磁盘信息
148         return response
149 
150     @staticmethod  # 返回函数的静态方法
151     def mega_patter_match(needle):
152         grep_pattern = {'Slot': 'slot', 'Raw Size': 'capacity', 'Inquiry': 'model', 'PD Type': 'pd_type'}
153         for key, value in grep_pattern.items():
154             if needle.startswith(key):  # 确定此字符串实例的开头是否与指定的字符串匹配
155                 return value
156         return False
157     # ————————06CMDB测试Linux系统采集硬件数据的命令————————
# disk.py

 1 # main_board.py
 2 # ————————05CMDB采集硬件数据的插件————————
 3 from .base import BasePlugin #采集资产的方式  和  系统平台
 4 from lib.response import BaseResponse  #提交数据的类型(字典)
 5 # ————————06CMDB测试Linux系统采集硬件数据的命令————————
 6 # import wmi#Windows操作系统上管理数据和操作的基础设施   #linux写无法导入这个模块
 7 # ————————06CMDB测试Linux系统采集硬件数据的命令————————
 8 
 9 class MainBoardPlugin(BasePlugin):
10     def windows(self):
11         response = BaseResponse() #提交数据的类型(字典)
12         try:
13             # ————————06CMDB测试Linux系统采集硬件数据的命令————————
14             import wmi#Windows操作系统上管理数据和操作的基础设施   #linux写无法导入这个模块
15             # ————————06CMDB测试Linux系统采集硬件数据的命令————————
16             output =wmi.WMI().Win32_BaseBoard() #获取主板相关信息
17             response.data = self.windows_parse(output)  #解析相关信息 返回结果 #存到字典
18         except Exception as e:
19 
20             # ————————08CMDB采集硬件数据日志记录————————
21             msg = "%s windows系统主板插件错误:%s"   #错误信息
22             import traceback    #捕获并打印异常
23             self.logger.log(msg % (self.hostname, traceback.format_exc()), False)#写入本地日志
24             response.error = msg % (self.hostname, traceback.format_exc()) #发送到远程日志
25             # ————————08CMDB采集硬件数据日志记录————————
26 
27             response.status = False
28         return response
29 
30     @staticmethod#返回函数的静态方法
31     def windows_parse(content):
32         response = {}
33         for item in content:
34             response['Manufacturer'] = item.Manufacturer #主板制造商
35             response['model'] = item.Name                 #主板型号
36             response['sn'] = item.SerialNumber             #主板SN号
37         return response #返回结果
38 # ————————05CMDB采集硬件数据的插件————————
39 
40     # ————————07CMDB文件模式测试采集硬件数据————————
41     def test(self):
42         response = BaseResponse() #提交数据的类型(字典)
43         import os  # 操作系统层面执行
44         from config.settings import BASEDIR  # 获取路径
45         try:
46             output = open(os.path.join(BASEDIR, 'files/linux_out/board.out'), 'r').read() #打开文件获取内容
47             response.data = self.linux_parse(output)#解析shell命令返回结果
48         except Exception as e:
49             # ————————08CMDB采集硬件数据日志记录————————
50             msg = "%s 测试系统主板插件错误:%s"   #错误信息
51             import traceback    #捕获并打印异常
52             self.logger.log(msg % (self.hostname, traceback.format_exc()), False)#写入本地日志
53             response.error = msg % (self.hostname, traceback.format_exc()) #发送到远程日志
54             # ————————08CMDB采集硬件数据日志记录————————
55             response.status = False
56         return response
57     # ————————07CMDB文件模式测试采集硬件数据————————
58 
59 # ————————06CMDB测试Linux系统采集硬件数据的命令————————
60     def linux(self):
61         response = BaseResponse() #提交数据的类型(字典)
62         try:
63             import subprocess  # 启动一个新的进程并且与之通信
64             shell_command = "sudo dmidecode -t1" #定义命令
65             output =subprocess.getoutput(shell_command) #linux系统上执行的命令
66             response.data = self.linux_parse(output) #解析shell命令返回结果
67         except Exception as e:
68             # ————————08CMDB采集硬件数据日志记录————————
69             msg = "%s linux系统主板插件错误:%s"   #错误信息
70             import traceback    #捕获并打印异常
71             self.logger.log(msg % (self.hostname, traceback.format_exc()), False)#写入本地日志
72             response.error = msg % (self.hostname, traceback.format_exc()) #发送到远程日志
73             # ————————08CMDB采集硬件数据日志记录————————
74             response.status = False
75         return response
76 
77     def linux_parse(self, content):#解析shell命令返回结果
78         result = {}
79         key_map = {'Manufacturer': 'manufacturer', 'Product Name': 'model','Serial Number': 'sn',}
80         for item in content.split('\n'): #split()通过指定分隔符对字符串进行切片
81             row_data = item.strip().split(':') #strip()方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列
82             if len(row_data) == 2:
83                 if row_data[0] in key_map:#如果在需要的字典里
84                     result[key_map[row_data[0]]] = row_data[1].strip() if row_data[1] else row_data[1]
85         return result
86     # ————————06CMDB测试Linux系统采集硬件数据的命令————————
# main_board.py

  1 # memory.py
  2 # ————————05CMDB采集硬件数据的插件————————
  3 from .base import BasePlugin  #采集资产的方式  和  系统平台
  4 from lib.response import BaseResponse #提交数据的类型(字典)
  5 # ————————06CMDB测试Linux系统采集硬件数据的命令————————
  6 # import wmi#Windows操作系统上管理数据和操作的基础设施   #linux写无法导入这个模块
  7 # ————————06CMDB测试Linux系统采集硬件数据的命令————————
  8 
  9 class MemoryPlugin(BasePlugin):
 10     def windows(self):
 11         response = BaseResponse()  #提交数据的类型(字典)
 12         try:
 13             # ————————06CMDB测试Linux系统采集硬件数据的命令————————
 14             import wmi#Windows操作系统上管理数据和操作的基础设施   #linux写无法导入这个模块
 15             # ————————06CMDB测试Linux系统采集硬件数据的命令————————
 16             output =wmi.WMI().Win32_PhysicalMemory()  #获取内存相关信息
 17             response.data = self.windows_parse(output)
 18         except Exception as e:
 19 
 20             # ————————08CMDB采集硬件数据日志记录————————
 21             msg = "%s windows系统内存插件错误:%s"   #错误信息
 22             import traceback    #捕获并打印异常
 23             self.logger.log(msg % (self.hostname, traceback.format_exc()), False)#写入本地日志
 24             response.error = msg % (self.hostname, traceback.format_exc()) #发送到远程日志
 25             # ————————08CMDB采集硬件数据日志记录————————
 26 
 27             response.status = False
 28         return response
 29 
 30     @staticmethod#返回函数的静态方法
 31     def windows_parse(content):
 32         response={}
 33         for item in content:
 34             item_dict = {}
 35             item_dict['slot'] = item.DeviceLocator                          #插槽位
 36             item_dict['manufacturer'] = item.Manufacturer                   # 内存制造商
 37             item_dict['model'] =item.FormFactor                             # 内存型号
 38             item_dict['Capacity'] = round(int(item.Capacity) / (1024**3))   # 内存容量
 39             item_dict['sn'] = item.SerialNumber                              #内存SN号
 40             item_dict['speed'] = item.Speed                                 #内存速度
 41             response[item_dict['slot']] = item_dict                         #分割存每条  内存信息
 42         return response
 43 
 44 # ————————05CMDB采集硬件数据的插件————————
 45     # ————————07CMDB文件模式测试采集硬件数据————————
 46     def test(self):
 47         response = BaseResponse() #提交数据的类型(字典)
 48         import os  # 操作系统层面执行
 49         from config.settings import BASEDIR  # 获取路径
 50         try:
 51             output = open(os.path.join(BASEDIR, 'files/linux_out/memory.out'), 'r').read()  #打开文件获取内容 linux_virtual_out linux_out
 52             response.data = self.linux_parse(output)  # 解析shell命令返回结果
 53         except Exception as e:#如果获取内容错误或者解析错误就换一个方式
 54             try:
 55                 output = open(os.path.join(BASEDIR, 'files/linux_virtual_out/memory.out'),'r').read()  # 打开文件获取内容 linux_virtual_out  linux_out
 56                 response.data = self.linux_virtual_parse(output)  # 解析shell命令返回结果
 57             except Exception as e:
 58                 # ————————08CMDB采集硬件数据日志记录————————
 59                 msg = "%s 测试系统内存插件错误:%s"  # 错误信息
 60                 import traceback  # 捕获并打印异常
 61                 self.logger.log(msg % (self.hostname, traceback.format_exc()), False)  # 写入本地日志
 62                 response.error = msg % (self.hostname, traceback.format_exc())  # 发送到远程日志
 63                 # ————————08CMDB采集硬件数据日志记录————————
 64                 response.status = False
 65         return response
 66     # ————————07CMDB文件模式测试采集硬件数据————————
 67 
 68     # ————————06CMDB测试Linux系统采集硬件数据的命令————————
 69     def linux(self):
 70         response = BaseResponse() #提交数据的类型(字典)
 71         try:
 72             import subprocess  # 启动一个新的进程并且与之通信
 73             shell_command = "sudo dmidecode  -q -t 17 2>/dev/null" #定义命令 cat /proc/swaps   #swapon
 74             output = subprocess.getoutput(shell_command) #linux系统上执行的命令
 75             if not output:
 76                 shell_command = "swapon"  # 定义命令 cat /proc/swaps   #swapon
 77                 output = subprocess.getoutput(shell_command)  # linux系统上执行的命令
 78                 response.data = self.linux_virtual_parse(output)  # 解析shell命令返回结果
 79             else:
 80                 response.data = self.linux_parse(output) # 解析shell命令返回结果
 81         except Exception as e:  # 如果 出现未知错误
 82             # ————————08CMDB采集硬件数据日志记录————————
 83             msg = "%s linux系统内存插件错误:%s"   #错误信息
 84             import traceback    #捕获并打印异常
 85             self.logger.log(msg % (self.hostname, traceback.format_exc()), False)#写入本地日志
 86             response.error = msg % (self.hostname, traceback.format_exc()) #发送到远程日志
 87             # ————————08CMDB采集硬件数据日志记录————————
 88             response.status = False
 89         return response
 90 
 91     def convert_mb_to_gb(self,value, default=0):#转换单位
 92         try:
 93             value = value.strip('MB') #strip()方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列
 94             result = int(value)
 95         except Exception as e:
 96             result = default
 97         return result
 98 
 99     def linux_virtual_parse(self, content):  # 解析shell命令返回结果
100         content = [i for i in content.split('\n') if i != '']  # split()通过指定分隔符对字符串进行切片
101         key_list = [i for i in content[0].split(' ') if i != '']  # split()通过指定分隔符对字符串进行切片
102         key_list[0] = 'slot'  #替换key的名字
103         key_list[1] = 'model'
104         key_list[2] = 'capacity'
105         ram_dict = {}
106         for i in content[1:]:  # 从列表下标1开始循环
107             segment = {}
108             value = [x for x in i.split(' ') if x != '']#如果不是空值就循环   # split()通过指定分隔符对字符串进行切片
109             list = zip(key_list, value)  # zip() 函数用于将可迭代的对象作为参数,将对象中对应的元素打包成一个个元组,然后返回由这些元组组成的列表。
110             for k, v in list:
111                 if k=='capacity': #处理单位问题
112                     if 'M' in v:
113                         l = v.split('M') # split()通过指定分隔符对字符串进行切片
114                         v = l[0]
115                     if 'G' in v:  # 处理单位问题
116                         l = v.split('G') # split()通过指定分隔符对字符串进行切片
117                         s = l[0]
118                         m = int(s)
119                         v = m * 1024
120                 segment[k] = v
121             ram_dict[value[0]] = segment
122         return ram_dict
123 
124     def linux_parse(self, content): # 解析shell命令返回结果
125         ram_dict = {}
126         key_map = {'Size': 'capacity','Locator': 'slot','Type': 'model','Speed': 'speed',
127                    'Manufacturer': 'manufacturer','Serial Number': 'sn',}
128         devices = content.split('Memory Device') #split()通过指定分隔符对字符串进行切片
129         for item in devices:
130             item = item.strip() #strip()方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列
131             if not item:
132                 continue
133             if item.startswith('#'): #startswith()方法用于检查字符串是否是以指定子字符串开头
134                 continue
135             segment = {}
136             lines = item.split('\n\t')  #split()通过指定分隔符对字符串进行切片
137             for line in lines:
138                 if len(line.split(':')) > 1:  #split()通过指定分隔符对字符串进行切片
139                     key, value = line.split(':')  #split()通过指定分隔符对字符串进行切片
140                 else:
141                     key = line.split(':')[0]  #split()通过指定分隔符对字符串进行切片
142                     value = ""
143                 if key in key_map:
144                     if key == 'Size':  # 内存容量
145                         segment[key_map['Size']] = self.convert_mb_to_gb(value, 0) #转换单位
146                     else:
147                         segment[key_map[key.strip()]] = value.strip() #strip()方法用于移除字符串头尾指定的字符(默认为空格或换行符)或字符序列
148             ram_dict[segment['slot']] = segment   #插槽位 #分割存每条  内存信息
149         return ram_dict
150     # ————————06CMDB测试Linux系统采集硬件数据的命令————————
# memory.py

  1 # nic.py
  2 # ————————05CMDB采集硬件数据的插件————————
  3 from .base import BasePlugin  #采集资产的方式  和  系统平台
  4 from lib.response import BaseResponse #提交数据的类型(字典)
  5 # ————————06CMDB测试Linux系统采集硬件数据的命令————————
  6 # import wmi#Windows操作系统上管理数据和操作的基础设施   #linux写无法导入这个模块
  7 # ————————06CMDB测试Linux系统采集硬件数据的命令————————
  8 
  9 class NicPlugin(BasePlugin):
 10     def windows(self):
 11         response = BaseResponse() #提交数据的类型(字典)
 12         try:
 13             # ————————06CMDB测试Linux系统采集硬件数据的命令————————
 14             import wmi#Windows操作系统上管理数据和操作的基础设施   #linux写无法导入这个模块
 15             # ————————06CMDB测试Linux系统采集硬件数据的命令————————
 16             output =wmi.WMI().Win32_NetworkAdapterConfiguration() #获取网卡相关信息
 17             response.data = self.windows_parse(output) #解析相关信息 返回结果 #存到字典
 18         except Exception as e:
 19 
 20             # ————————08CMDB采集硬件数据日志记录————————
 21             msg = "%s windows系统网卡插件错误:%s"   #错误信息
 22             import traceback    #捕获并打印异常
 23             self.logger.log(msg % (self.hostname, traceback.format_exc()), False)#写入本地日志
 24             response.error = msg % (self.hostname, traceback.format_exc()) #发送到远程日志
 25             # ————————08CMDB采集硬件数据日志记录————————
 26 
 27             response.status = False
 28         return response
 29 
 30     @staticmethod#返回函数的静态方法
 31     def windows_parse(content):
 32         response={}
 33         IPCM = 0  # 权重
 34         for item in content:
 35             if item.IPConnectionMetric: # 权重
 36                 if item.IPConnectionMetric > IPCM: # 权重 #防止虚拟网卡
 37                     item_dict = {}
 38                     name=item.ServiceName                       # 网卡名称
 39                     item_dict['hwaddr'] = item.MACAddress      # 网卡MAC地址
 40                     item_dict['ipaddrs'] = item.IPAddress[0]    # IP地址
 41                     item_dict['netmask'] = item.IPSubnet[0]     # IP子网掩码
 42                     item_dict['up'] = item.IPEnabled            #是否有启用
 43                     response[name] = item_dict
 44                     IPCM = item.IPConnectionMetric  # 权重
 45         return response
 46 # ————————05CMDB采集硬件数据的插件————————
 47 
 48     # ————————07CMDB文件模式测试采集硬件数据————————
 49     def test(self):
 50         response = BaseResponse() #提交数据的类型(字典)
 51         import os  # 操作系统层面执行
 52         from config.settings import BASEDIR  # 获取路径
 53         try:
 54             output = open(os.path.join(BASEDIR, 'files/linux_out/nic.out'), 'r').read()  #打开文件获取内容
 55             interfaces_info = self._interfaces_ip(output)  #接口 # 解析shell命令返回结果
 56             self.standard(interfaces_info) # 内容进行 标准化
 57             response.data = interfaces_info # 解析shell命令返回结果
 58         except Exception as e:
 59             # ————————08CMDB采集硬件数据日志记录————————
 60             msg = "%s 测试系统网卡插件错误:%s"   #错误信息
 61             import traceback    #捕获并打印异常
 62             self.logger.log(msg % (self.hostname, traceback.format_exc()), False)#写入本地日志
 63             response.error = msg % (self.hostname, traceback.format_exc()) #发送到远程日志
 64             # ————————08CMDB采集硬件数据日志记录————————
 65             response.status = False
 66         return response
 67     # ————————07CMDB文件模式测试采集硬件数据————————
 68 
 69 
 70     # ————————06CMDB测试Linux系统采集硬件数据的命令————————
 71     def linux(self):
 72         response = BaseResponse() #提交数据的类型(字典)
 73         try:
 74             interfaces_info = self.linux_interfaces() #linux系统上执行的命令
 75             self.standard(interfaces_info)  # 内容进行 标准化
 76             response.data = interfaces_info # 解析shell命令返回结果
 77         except Exception as e:
 78             # ————————08CMDB采集硬件数据日志记录————————
 79             msg = "%s linux系统网卡插件错误:%s"   #错误信息
 80             import traceback    #捕获并打印异常
 81             self.logger.log(msg % (self.hostname, traceback.format_exc()), False)#写入本地日志
 82             response.error = msg % (self.hostname, traceback.format_exc()) #发送到远程日志
 83             # ————————08CMDB采集硬件数据日志记录————————
 84             response.status = False
 85         return response
 86 
 87     def standard(self, interfaces_info):# 内容进行 标准化
 88         for key, value in interfaces_info.items():
 89             ipaddrs = set()#set()函数创建一个无序不重复元素集,可进行关系测试,删除重复数据,还可以计算交集、差集、并集等。
 90             netmask = set()
 91             if not 'inet' in value:
 92                 value['ipaddrs'] = ''           # IP地址
 93                 value['netmask'] = ''           # IP子网掩码
 94             else:
 95                 for item in value['inet']:
 96                     ipaddrs.add(item['address'])  # IP地址
 97                     netmask.add(item['netmask'])  # IP子网掩码
 98                 value['ipaddrs'] = '/'.join(ipaddrs) # IP地址
 99                 value['netmask'] = '/'.join(netmask) # IP子网掩码
100                 del value['inet']
101 
102     def linux_interfaces(self):#获得* NIX / BSD变种接口信息
103         ifaces = dict() #dict() 函数用于创建一个字典。返回一个字典。
104         ip_path = 'ip'
105         if ip_path:
106             # ————————在使用#linux系统上执行的命令时开启————————
107             import subprocess  # 启动一个新的进程并且与之通信
108             cmd1 = subprocess.getoutput('sudo {0} link show'.format(ip_path)) #定义命令ip link show
109             cmd2 = subprocess.getoutput('sudo {0} addr show'.format(ip_path)) #定义命令ip addr show
110             ifaces = self._interfaces_ip(cmd1 + '\n' + cmd2)  #linux系统上执行的命令 #接口 # 解析shell命令返回结果
111             # ————————在使用#linux系统上执行的命令时开启————————
112         return ifaces
113 
114     def which(self, exe):
115         import os  # 操作系统层面执行
116         def _is_executable_file_or_link(exe):
117             # 检查操作系统。X_OK不足够了,因为目录可能会执行
118             return (os.access(exe, os.X_OK) and
119                     (os.path.isfile(exe) or os.path.islink(exe)))
120 
121         if exe:
122             if _is_executable_file_or_link(exe):
123                 # executable in cwd or fullpath
124                 return exe
125 
126             # 默认路径基于busybox的默认
127             default_path = '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin'
128             search_path = os.environ.get('PATH', default_path)
129             path_ext = os.environ.get('PATHEXT', '.EXE')
130             ext_list = path_ext.split(';')
131 
132             search_path = search_path.split(os.pathsep)
133             if True:
134                 """
135             # 添加任何dirs default_path search_path不。如果
136             # 没有PATH变量中发现操作系统。环境,那么这将是
137             # 无为法。这将确保所有dirs default_path
138             # 搜索,让salt.utils.which()调用时工作得很好
139             # salt-call从cron(取决于平台
140             # 有一个极其有限的路径)。
141               """
142                 search_path.extend(
143                     [
144                         x for x in default_path.split(os.pathsep)
145                         if x not in search_path
146                     ]
147                 )
148             for path in search_path:
149                 full_path = os.path.join(path, exe)
150                 if _is_executable_file_or_link(full_path):
151                     return full_path
152         return None
153 
154     def _number_of_set_bits_to_ipv4_netmask(self, set_bits):  # pylint: disable=C0103
155         '''
156         返回一个整数表示的IPv4网络掩码,面具。
157 
158         Ex. 0xffffff00 -> '255.255.255.0'
159         '''
160         return self.cidr_to_ipv4_netmask(self._number_of_set_bits(set_bits))
161     def cidr_to_ipv4_netmask(self, cidr_bits):
162         '''
163         返回一个IPv4网络掩码
164         '''
165         try:
166             cidr_bits = int(cidr_bits)
167             if not 1 <= cidr_bits <= 32:
168                 return ''
169         except ValueError:
170             return ''
171         netmask = ''
172         for idx in range(4):
173             if idx:
174                 netmask += '.'
175             if cidr_bits >= 8:
176                 netmask += '255'
177                 cidr_bits -= 8
178             else:
179                 netmask += '{0:d}'.format(256 - (2 ** (8 - cidr_bits)))
180                 cidr_bits = 0
181         return netmask
182     def _number_of_set_bits(self, x):
183         '''
184         返回的比特数,设置在一个32位整数
185         #来自http://stackoverflow.com/a/4912729
186         '''
187         x -= (x >> 1) & 0x55555555
188         x = ((x >> 2) & 0x33333333) + (x & 0x33333333)
189         x = ((x >> 4) + x) & 0x0f0f0f0f
190         x += x >> 8
191         x += x >> 16
192         return x & 0x0000003f
193 
194     def _interfaces_ip(self, out): #接口 # 解析shell命令返回结果
195         import re  # 正则表达式
196         '''
197       使用ip来返回一个字典的接口的各种信息
198       每个(向上/向下状态、ip地址、子网掩码和hwaddr)
199         '''
200         ret = dict()
201         right_keys = ['name', 'hwaddr', 'up', 'netmask', 'ipaddrs']
202 
203         def parse_network(value, cols):
204             '''
205           子网掩码,返回一个元组的ip广播
206           基于当前的关口
207             '''
208             brd = None
209             if '/' in value:  # 我们有一个CIDR在这个地址
210                 ip, cidr = value.split('/')  # pylint:禁用= C0103
211             else:
212                 ip = value  # pylint:禁用= C0103
213                 cidr = 32
214 
215             if type_ == 'inet':
216                 mask = self.cidr_to_ipv4_netmask(int(cidr))
217                 if 'brd' in cols:
218                     brd = cols[cols.index('brd') + 1]
219             return (ip, mask, brd)
220 
221         groups = re.compile('\r?\n\\d').split(out)
222         for group in groups:
223             iface = None
224             data = dict()
225 
226             for line in group.splitlines():
227                 if ' ' not in line:
228                     continue
229                 match = re.match(r'^\d*:\s+([\w.\-]+)(?:@)?([\w.\-]+)?:\s+<(.+)>', line)
230                 if match:
231                     iface, parent, attrs = match.groups()
232                     if 'UP' in attrs.split(','):
233                         data['up'] = True
234                     else:
235                         data['up'] = False
236                     if parent and parent in right_keys:
237                         data[parent] = parent
238                     continue
239 
240                 cols = line.split()
241                 if len(cols) >= 2:
242                     type_, value = tuple(cols[0:2])
243                     iflabel = cols[-1:][0]
244                     if type_ in ('inet',):
245                         if 'secondary' not in cols:
246                             ipaddr, netmask, broadcast = parse_network(value, cols)
247                             if type_ == 'inet':
248                                 if 'inet' not in data:
249                                     data['inet'] = list()
250                                 addr_obj = dict()
251                                 addr_obj['address'] = ipaddr
252                                 addr_obj['netmask'] = netmask
253                                 addr_obj['broadcast'] = broadcast
254                                 data['inet'].append(addr_obj)
255 
256                         else:
257                             if 'secondary' not in data:
258                                 data['secondary'] = list()
259                             ip_, mask, brd = parse_network(value, cols)
260                             data['secondary'].append({
261                                 'type': type_,
262                                 'address': ip_,
263                                 'netmask': mask,
264                                 'broadcast': brd,
265                             })
266                             del ip_, mask, brd
267                     elif type_.startswith('link'):
268                         data['hwaddr'] = value
269             if iface:
270                 if iface.startswith('pan') or iface.startswith('lo') or iface.startswith('v'):
271                     del iface, data
272                 else:
273                     ret[iface] = data
274                     del iface, data
275         return ret
276     # ————————06CMDB测试Linux系统采集硬件数据的命令————————
# nic.py

猜你喜欢

转载自www.cnblogs.com/ujq3/p/9260191.html