CMDB学习之八,完成所有资产采集信息的收集
#!/usr/bin/env python # -*- coding:utf-8 -*- import traceback from .base import BasePlugin from lib.response import BaseResponse from lib.log import logger class Basic(BasePlugin): def os_platform(self,handler, hostname): """ 获取系统平台 :return: """ output = handler.cmd('uname',hostname) return output.strip() def os_version(self,handler, hostname): """ 获取系统版本 :return: """ output = handler.cmd('cat /etc/issue',hostname) result = output.strip().split('\n')[0] return result def os_hostname(self,handler, hostname): """ 获取主机名 :return: """ output = handler.cmd('hostname',hostname) return output.strip() def win(self, handler, hostname): raise NotImplementedError('win must be implemented ') def linux(self, handler, hostname): response = BaseResponse() try: if self.debug: ret = { 'os_platform':'linux', 'os_version':'6.5', 'hostname':'c1.com' } else: ret = { 'os_platform': self.os_platform(handler, hostname), 'os_version': self.os_version(handler, hostname), 'hostname': self.os_hostname(handler, hostname), } response.data = ret except Exception as e: msg = traceback.format_exc() response.status = False response.error = msg logger.error(msg) return response.dict
#!/usr/bin/env python # -*- coding:utf-8 -*- import os import traceback from .base import BasePlugin from lib.response import BaseResponse from lib.log import logger class MainBoard(BasePlugin): def win(self, handler, hostname): raise NotImplementedError('win must be implemented ') def linux(self, handler, hostname): response = BaseResponse() try: if self.debug: output = open(os.path.join(self.base_dir, 'files','board.out'), 'r').read() else: shell_command = "sudo dmidecode -t1" output = handler.cmd(shell_command,hostname) response.data = self.parse(output) except Exception as e: msg = traceback.format_exc() response.status = False response.error = msg logger.error(msg) return response.dict 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
# !/usr/bin/env python # -*- coding:utf-8 -*- from .base import BasePlugin import os,re import traceback from lib.response import BaseResponse from lib.log import logger class Disk(BasePlugin): def win(self,handler,hostname): ''' 执行命令拿到结果-磁盘 :return: ''' print("执行win方法") ret = handler.cmd('wmic diskdrive',hostname)[0:10] return ret # def linux(self,handler,hostname): # ''' # 执行命令拿到结果-磁盘 # :return: # ''' # print("执行Linux方法") # # ret = handler.cmd('df -h',hostname)[0:10] # return ret def linux(self, handler, hostname): ''' 采集数据 :param handler: :param hostname: :return: ''' #实现错误信息记录,标记,post 提交到服务端,首先定义一个字典如下: # result = {'status':True,'error':None,'data':None} #字典的形式使用比较麻烦,所有这里在lib 文件中定义一个类来使用,看起比较高端些,使用方法是 ''' 这里是在 lib 文件实现的 class BaseReponse(): def __init__(self): self.status = True self.error = None self.data = None #调用内部方法 静态方法属性 @property def dict(self): return self.__dict__ ''' reponse = BaseResponse() try : if self.debug: output = open(os.path.join(self.base_dir, 'files', 'disk.out'), 'r').read() else: shell_command = "sudo MegaCli -PDList -aALL" #根据执行的命令 output = handler.cmd(shell_command, hostname) reponse.data = self.parse(output) except Exception as e: error_msg = traceback.format_exc() reponse.status = False reponse.error = error_msg # 记录错误日志 logger.error(error_msg) return reponse.dict 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
#!/usr/bin/env python # -*- coding:utf-8 -*- from .base import BasePlugin from lib.response import BaseResponse import traceback import os,re from lib.log import logger class CPU(BasePlugin): def win(self,handler,hostname): ''' 执行命令拿到结果-cpu :return: ''' print("执行win方法") ret = handler.cmd('wmic cpu',hostname)[0:10] return ret def linux(self,handler,hostname): ''' 执行命令拿到结果-cpu :return: ''' reponse = BaseResponse() try: if self.debug: output = open(os.path.join(self.base_dir, 'files','cpuinfo.out'), 'r').read() else: shell_command = "cat /proc/cpuinfo" output = handler.cmd(shell_command, hostname) reponse.data = self.parse(output) except Exception as e: error_msg = traceback.format_exc() reponse.status = False reponse.error = error_msg # 记录错误日志 logger.error(error_msg) return reponse.dict @staticmethod def parse(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('\n\n'): for row_line in item.split('\n'): 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
#!/usr/bin/env python # -*- coding:utf-8 -*- import os from .base import BasePlugin from lib import convert from lib.response import BaseResponse import traceback from lib.log import logger class Memory(BasePlugin): def win(self,handler,hostname): ''' 执行命令拿到结果-内存 :return: ''' print("执行win方法") ret = handler.cmd('wmic memphysical list brief',hostname)[0:10] return ret # def linux(self,handler,hostname): # ''' # 执行命令拿到结果-内存 # :return: # ''' # print("执行Linux方法") # ret = handler.cmd('free',hostname)[0:10] # return ret def linux(self, handler, hostname): reponse = BaseResponse() try: if self.debug: output = open(os.path.join(self.base_dir, 'files', 'memory.out'), 'r').read() else: shell_command = "sudo dmidecode -q -t 17 2>/dev/null" output = handler.cmd(shell_command, hostname) reponse.data = self.parse(output) except Exception as e: error_msg = traceback.format_exc() reponse.status = False reponse.error = error_msg # 记录错误日志 logger.error(error_msg) return reponse.dict def parse(self, content): """ 解析shell命令返回结果 :param content: shell 命令结果 :return:解析后的结果 """ ram_dict = {} key_map = { 'Size': 'capacity', 'Locator': 'slot', 'Type': 'model', 'Speed': 'speed', 'Manufacturer': 'manufacturer', 'Serial Number': 'sn', } devices = content.split('Memory Device') for item in devices: item = item.strip() if not item: continue if item.startswith('#'): continue segment = {} lines = item.split('\n\t') for line in lines: if len(line.split(':')) > 1: key, value = line.split(':') else: key = line.split(':')[0] value = "" if key in key_map: if key == 'Size': segment[key_map['Size']] = convert.convert_mb_to_gb(value, 0) else: segment[key_map[key.strip()]] = value.strip() ram_dict[segment['slot']] = segment return ram_dict
#!/usr/bin/env python # -*- coding:utf-8 -*- import os,re from .base import BasePlugin from lib.response import BaseResponse import traceback from lib.log import logger class Network(BasePlugin): def win(self,handler,hostname): ''' 执行命令拿到结果-网卡 :return: ''' print("执行win方法") ret = handler.cmd('ipconfig',hostname)[0:10] return ret # def linux(self,handler,hostname): # ''' # 执行命令拿到结果-网卡 # :return: # ''' # print("执行Linux方法") # ret = handler.cmd('ifconfig',hostname)[0:10] # return ret def linux(self, handler, hostname): reponse = BaseResponse() try: if self.debug: output = open(os.path.join(self.base_dir, 'files', 'nic.out'), 'r').read() interfaces_info = self._interfaces_ip(output) else: interfaces_info = self.linux_interfaces(handler) self.standard(interfaces_info) reponse.data = interfaces_info # reponse.data = self.standard(interfaces_info) # print(reponse.data) except Exception as e: error_msg = traceback.format_exc() reponse.status = False reponse.error = error_msg #记录错误日志 logger.error(error_msg) return reponse.dict def linux_interfaces(self, handler): ''' Obtain interface information for *NIX/BSD variants ''' ifaces = dict() ip_path = 'ip' if ip_path: cmd1 = handler.cmd('sudo {0} link show'.format(ip_path)) cmd2 = handler.cmd('sudo {0} addr show'.format(ip_path)) ifaces = self._interfaces_ip(cmd1 + '\n' + cmd2) return ifaces def which(self, exe): def _is_executable_file_or_link(exe): # check for os.X_OK doesn't suffice because directory may executable return (os.access(exe, os.X_OK) and (os.path.isfile(exe) or os.path.islink(exe))) if exe: if _is_executable_file_or_link(exe): # executable in cwd or fullpath return exe # default path based on busybox's default default_path = '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin' search_path = os.environ.get('PATH', default_path) path_ext = os.environ.get('PATHEXT', '.EXE') ext_list = path_ext.split(';') search_path = search_path.split(os.pathsep) if True: # Add any dirs in the default_path which are not in search_path. If # there was no PATH variable found in os.environ, then this will be # a no-op. This ensures that all dirs in the default_path are # searched, which lets salt.utils.which() work well when invoked by # salt-call running from cron (which, depending on platform, may # have a severely limited PATH). search_path.extend( [ x for x in default_path.split(os.pathsep) if x not in search_path ] ) for path in search_path: full_path = os.path.join(path, exe) if _is_executable_file_or_link(full_path): return full_path return None def _number_of_set_bits_to_ipv4_netmask(self, set_bits): # pylint: disable=C0103 ''' Returns an IPv4 netmask from the integer representation of that mask. Ex. 0xffffff00 -> '255.255.255.0' ''' return self.cidr_to_ipv4_netmask(self._number_of_set_bits(set_bits)) def cidr_to_ipv4_netmask(self, cidr_bits): ''' Returns an IPv4 netmask ''' try: cidr_bits = int(cidr_bits) if not 1 <= cidr_bits <= 32: return '' except ValueError: return '' netmask = '' for idx in range(4): if idx: netmask += '.' if cidr_bits >= 8: netmask += '255' cidr_bits -= 8 else: netmask += '{0:d}'.format(256 - (2 ** (8 - cidr_bits))) cidr_bits = 0 return netmask def _number_of_set_bits(self, x): ''' Returns the number of bits that are set in a 32bit int ''' # Taken from http://stackoverflow.com/a/4912729. Many thanks! x -= (x >> 1) & 0x55555555 x = ((x >> 2) & 0x33333333) + (x & 0x33333333) x = ((x >> 4) + x) & 0x0f0f0f0f x += x >> 8 x += x >> 16 return x & 0x0000003f def _interfaces_ip(self, out): ''' Uses ip to return a dictionary of interfaces with various information about each (up/down state, ip address, netmask, and hwaddr) ''' ret = dict() right_keys = ['name', 'hwaddr', 'up', 'netmask', 'ipaddrs'] def parse_network(value, cols): ''' Return a tuple of ip, netmask, broadcast based on the current set of cols ''' brd = None if '/' in value: # we have a CIDR in this address ip, cidr = value.split('/') # pylint: disable=C0103 else: ip = value # pylint: disable=C0103 cidr = 32 if type_ == 'inet': mask = self.cidr_to_ipv4_netmask(int(cidr)) if 'brd' in cols: brd = cols[cols.index('brd') + 1] return (ip, mask, brd) groups = re.compile('\r?\n\\d').split(out) for group in groups: iface = None data = dict() for line in group.splitlines(): if ' ' not in line: continue match = re.match(r'^\d*:\s+([\w.\-]+)(?:@)?([\w.\-]+)?:\s+<(.+)>', line) if match: iface, parent, attrs = match.groups() if 'UP' in attrs.split(','): data['up'] = True else: data['up'] = False if parent and parent in right_keys: data[parent] = parent continue cols = line.split() if len(cols) >= 2: type_, value = tuple(cols[0:2]) iflabel = cols[-1:][0] if type_ in ('inet',): if 'secondary' not in cols: ipaddr, netmask, broadcast = parse_network(value, cols) if type_ == 'inet': if 'inet' not in data: data['inet'] = list() addr_obj = dict() addr_obj['address'] = ipaddr addr_obj['netmask'] = netmask addr_obj['broadcast'] = broadcast data['inet'].append(addr_obj) else: if 'secondary' not in data: data['secondary'] = list() ip_, mask, brd = parse_network(value, cols) data['secondary'].append({ 'type': type_, 'address': ip_, 'netmask': mask, 'broadcast': brd, }) del ip_, mask, brd elif type_.startswith('link'): data['hwaddr'] = value if iface: if iface.startswith('pan') or iface.startswith('lo') or iface.startswith('v'): del iface, data else: ret[iface] = data del iface, data return ret def standard(self, interfaces_info): for key, value in interfaces_info.items(): ipaddrs = set() netmask = set() if not 'inet' in value: value['ipaddrs'] = '' value['netmask'] = '' else: for item in value['inet']: ipaddrs.add(item['address']) netmask.add(item['netmask']) value['ipaddrs'] = '/'.join(ipaddrs) value['netmask'] = '/'.join(netmask) del value['inet']
到此 资产采集所有信息完成