CMDB03 /今日未采集的资产、资产入库、资产变更记录、资产采集

1. 获取今日未采集的服务器

  • 代码示例:

        def get(self,request,*args,**kwargs):
    """ 返回今日未采集的服务器列表 """
    today = datetime.datetime.today()
    queryset = models.Server.objects.filter(status=1).filter(Q(last_date__isnull=True)|Q(last_date__lt=today)).values('hostname')
    host_list = [ item['hostname'] for item in queryset]
    print(host_list)
    return Response(host_list)

2. server资产入库以及资产变更处理

  • post请求代码示例

    def post(self,request,*args,**kwargs):
    # 1. 获取到用户提交资产信息
    # 2. 保存到数据库(表关系)
    hostname = request.data.get('hostname')
    server_object = models.Server.objects.filter(hostname=hostname).first()
    if not server_object:
    return Response('主机不存在')
    process_server_info(request.data['info'],server_object) # 今日已经采集
    server_object.last_date = datetime.datetime.today()
    server_object.save() return Response('发送成功')
  • plugins /__init__.py 执行process_server_info函数,对接收到的消息做相应的处理

    代码示例:

    import importlib
    from django.conf import settings
    def process_server_info(info,server_object):
    """ 处理中控汇报资产信息 """
    for key,path in settings.CMDB_PLUGIN_DICT.items():
    module_path,class_name = path.rsplit('.',maxsplit=1)
    module = importlib.import_module(module_path)
    instance = getattr(module,class_name)()
    instance.process(info[key],server_object)
  • 判断做何处理/新增/删除/变更

    class Disk(object):
    
        def process(self,disk,server_object):
    if not disk['status']:
    print('采集资产错误',disk['error'])
    return
    disk_info = disk['data']
    new_disk_slot_set = set(disk_info.keys())
    # [obj,obj]
    db_disk_queryset = models.Disk.objects.filter(server=server_object)
    db_disk_dict = {obj.slot: obj for obj in db_disk_queryset}
    db_disk_slot_set = set(db_disk_dict.keys()) record_msg_list = [] # 新增的槽位集合
    create_slot_set = new_disk_slot_set - db_disk_slot_set
    create_object_list = []
    for slot in create_slot_set:
    # models.Disk.objects.create(**disk_info[slot],server=server_object)
    create_object_list.append(models.Disk(**disk_info[slot], server=server_object))
    if create_object_list:
    models.Disk.objects.bulk_create(create_object_list, batch_size=10)
    msg = "【新增硬盘】在%s槽位新增了硬盘。" % ",".join(create_slot_set)
    record_msg_list.append(msg) # 要删除的槽位集合
    remove_slot_set = db_disk_slot_set - new_disk_slot_set # (1,2)
    models.Disk.objects.filter(server=server_object, slot__in=remove_slot_set).delete()
    if remove_slot_set:
    msg = "【删除硬盘】在%s槽位删除了硬盘。" % ",".join(remove_slot_set)
    record_msg_list.append(msg) # 要更新的槽位集合(可能有也可能没有)
    update_slot_set = new_disk_slot_set & db_disk_slot_set
    for slot in update_slot_set:
    temp = []
    row_dict = disk_info[slot] # {'slot': '0', 'pd_type': 'SAS', 'capacity': '100', 'model': 'SEAGATE ST300MM0006 LS08S0K2B5NV'}
    row_object = db_disk_dict[slot] # row_object.slot/ row_object.pd_type = getattr(row_object,'pd_type') / row.capacity /row.model
    for key, value in row_dict.items():
    if value != getattr(row_object, key):
    msg = "%s由%s变更为%s" % (key, getattr(row_object, key), value)
    temp.append(msg)
    setattr(row_object, key, value)
    if temp:
    slot_msg = "【更新硬盘】槽位%s:%s" % (slot, " ".join(temp))
    record_msg_list.append(slot_msg)
    row_object.save() if record_msg_list:
    models.Record.objects.create(server=server_object, content="\n".join(record_msg_list))

3. client基于ssh远程资产采集

  • app.py -- 资产采集入口

    from concurrent.futures import ThreadPoolExecutor
    from lib.plugins import get_server_info
    import settings
    import requests def ssh(hostname,command):
    import paramiko
    private_key = paramiko.RSAKey.from_private_key_file(settings.SSH_PRIVATE_KEY_PATH)
    ssh = paramiko.SSHClient()
    ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    ssh.connect(hostname=hostname, port=settings.SSH_PORT, username=settings.SSH_USER, pkey=private_key)
    stdin, stdout, stderr = ssh.exec_command(command)
    result = stdout.read()
    ssh.close()
    return result.decode('utf-8') def salt(hostname,command):
    import subprocess
    cmd = "salt '%s' cmd.run '%s' " %(hostname,command)
    data = subprocess.getoutput(cmd)
    return data def task(hostname): if settings.MODE == 'SSH':
    info = get_server_info(hostname, ssh)
    elif settings.MODE == 'SALT':
    info = get_server_info(hostname, salt)
    else:
    raise Exception('模式输入错误,请修改') requests.post(
    url="http://192.168.16.64:8000/api/v1/server/",
    json={'hostname':hostname,'info':info}
    ) def run():
    response = requests.get(url="http://192.168.16.64:8000/api/v1/server/")
    host_list = response.json()
    pool = ThreadPoolExecutor(settings.THREAD_POOL_SIZE)
    for host in host_list: # 100服务器
    pool.submit(task,host) if __name__ == '__main__':
    run()
  • plugins /__init__.py 执行process_server_info函数,去采集相应的资产信息

    from settings import PLUGIN_DICT
    
    def get_server_info(hostname,ssh_func):
    """ :param hostname: 要远程操作的主机名
    :param ssh_func: 执行远程操作的方法
    :return:
    """
    info_dict = {} for key, path in PLUGIN_DICT.items():
    module_path, class_name = path.rsplit('.', maxsplit=1) # 1. 根据字符串的形式去导入模块 "lib.plugins.board"
    import importlib
    module = importlib.import_module(module_path) # 2.去模块找到类
    cls = getattr(module, class_name) # 3. 对类型实例化
    obj = cls() # 4. 执行对象的process方法
    result = obj.process(hostname,ssh_func) info_dict[key] = result return info_dict
  • 采集CPU信息示例

    import traceback
    from lib.log import logger
    import settings from .base import BasePlugin class CPU(BasePlugin):
    def process(self,hostname,ssh_func):
    info = {'status': True, 'data': None, 'error': None}
    try:
    if settings.DEBUG:
    with open('files/cpuinfo.out',mode='r',encoding='utf-8') as f:
    content = f.read()
    else:
    content = ssh_func(hostname, 'cat /proc/cpuinfo')
    data = self.parse(content)
    info['data'] = data
    except Exception as e:
    # 记录日志
    msg = traceback.format_exc()
    logger.log(msg)
    info['status'] = False
    info['error'] = msg
    return info 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('\n\n'):
    for row_line in item.split('\n'):
    value_list = row_line.split(':')
    if len(value_list) !=2:
    continue
    key,value = value_list
    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
  • log.py -- 用来记录异常日志

    import logging
    import settings class AutoLogger(object):
    def __init__(self,log_path,log_name):
    file_handler = logging.FileHandler(log_path, 'a', encoding='utf-8')
    fmt = logging.Formatter(fmt="%(asctime)s - %(name)s - %(levelname)s -%(module)s: %(message)s")
    file_handler.setFormatter(fmt) self.logger = logging.Logger(log_name, level=logging.DEBUG)
    self.logger.addHandler(file_handler) def log(self,msg):
    self.logger.error(msg) logger = AutoLogger(settings.LOG_FILE_PATH,'cmdb')

总结:

  1. 对于今日未采集的服务器采用了基于Q实现复杂的SQL查询
  2. 对于变更处理采用集合的交集、差集,进而进行判断
  3. 中控机汇报到api的资产需要做入库以及变更记录的处理
    • 由于资产搜集时是利用工厂模式实现可扩展插件,方便于扩展。在api端也是使用相同模式,对插件进行一一处理。
    • 在处理资产信息时候,对操作进行交集和差集的处理从而得到删除/更新/新增资产。
    • 在内部通过反射进行资产变更记录的获取,最终将资产以及变更记录写入数据库。

CMDB03 /今日未采集的资产、资产入库、资产变更记录、资产采集的更多相关文章

  1. CMDB服务器管理系统【s5day90】:获取今日未采集主机列表

    1.目录结构 1.服务器端 2.客户端 2.具体代码如下 1.数据库增加两个字段 class Server(models.Model): """ 服务器信息 " ...

  2. python-cmdb资产管理项目4-资产入库处理以及资产变更记录处理

    一 资产入库处理 1.1 连接数据库 在192.168.100.101安装数据库,并给总控机授权可以操作,并创建一个autoserver的数据库,密码123456 settiing.py 配置数据库连 ...

  3. WEB页面采集器编写经验之一:静态页面采集器

    严格意义来说,采集器和爬虫不是一回事:采集器是对特定结构的数据来源进行解析.结构化,将所需的数据从中提取出来:而爬虫的主要目标更多的是页面里的链接和页面的TITLE. 采集器也写过不少了,随便写一点经 ...

  4. ThinkPHP Http工具类(用于远程采集 远程下载) phpSimpleHtmlDom采集类库_Jquery筛选方式 使用phpQuery轻松采集网页内容http://www.thinkphp.cn/extend/541.html

    [php]代码库 view sourceprint? <?php // +------------------------------------------------------------ ...

  5. Java版基于SpringBoot+Vue.js实现自动创表自动定时采集(各个微信公众号商城产品进行采集)-爬虫篇

  6. CMDB资产采集方案

    CMDB资产采集方案 CMDB 资产采集的方案总共有四种 Agent SSH类 Saltstack Puttet 方案设计,从性能上考虑 下面前三种是用Python开发的,目标是兼容三种采集方式的软件 ...

  7. CMDB资产采集笔记

    一.资产采集四种方式 1. Agent方式 API:Django接收数据并入库 程序:放置在每台服务器 应用场景:针对服务器较多的公司 步骤一: #执行本地命令的库 import subprocess ...

  8. CMDB资产采集方式

    一:Agent方式 原理:在每台服务器装上agent客户端程序,定时向数据库发送指定的资产信息. 优点:速度快. 缺点:服务器上需要多装一个软件 import subprocess import re ...

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

    #settings.py # ————————01CMDB获取服务器基本信息———————— import os BASEDIR = os.path.dirname(os.path.dirname(o ...

随机推荐

  1. 十几万条数据的表中,基于帝国cms 。自己亲身体验三种批量更新数据的方法,每一种的速度是什么样的

    需求是 上传Excel 读取里面的数据.根据Excel中某一个字段,与数据表中的一个字段的唯一性.然后把 Excel表中数据和数据库表中数据一次更改.本次测试一次更新31条数据. 本次测试基于帝国cm ...

  2. OSI七层模型工作过程&&输入URL浏览器的工作过程(超详细!!)

    从以下10个方面深入理解输入URL后整个模型以及浏览器的工作流程! 目录 1.HTTP 2.DNS 3.协议栈 4.TCP 5.IP 6.MAC 7.网卡 8.交换机 9.路由器 10.服务器与客户端 ...

  3. 解决错误 CS1617 Invalid option '7.1' for /langversion; must be ISO-1, ISO-2, Default or an integer in range 1 to 6.

    解决错误 CS1617 Invalid option '7.1' for /langversion; must be ISO-1, ISO-2, Default or an integer in ra ...

  4. Head_First_Python(中文版)完整版PDF免费下载_百度云盘

    Head_First_Python(中文版)完整版PDF免费下载_百度云盘 提取码:bjbg 本书特色 根据认知科学和学习理论的最新研究成果,这本书采用一种适合大脑的丰富格式娓娓道来,而不是长篇累牍地 ...

  5. Vue数据更新页面没有更新问题总结

    Vue数据更新页面没有更新问题总结 1. Vue无法检测实例别创建时不存在于data中的property 原因: 由于Vue会在初始化实例时对property执行getter/setter转化,所以p ...

  6. 个人作业——软件工程实践总结&个人技术博客

    一. 回望 (1)对比开篇博客你对课程目标和期待,"希望通过实践锻炼,增强软件工程专业的能力和就业竞争力",对比目前的所学所练所得,在哪些方面达到了你的期待和目标,哪些方面还存在哪 ...

  7. 入门大数据---Spark_Streaming整合Flume

    一.简介 Apache Flume 是一个分布式,高可用的数据收集系统,可以从不同的数据源收集数据,经过聚合后发送到分布式计算框架或者存储系统中.Spark Straming 提供了以下两种方式用于 ...

  8. 3dTiles 数据规范详解[2] Tileset与Tile

    转载请声明出处:全网@秋意正寒 https://www.cnblogs.com/onsummer/p/13128682.html 一.一个简单的3dTiles数据示例 上图是一份 3dTiles数据集 ...

  9. Redis高级特性

    redis的事务(transaction) 转载:https://blog.csdn.net/fmwind/article/details/78065236 redis中的事务是一组命令的集合.事务同 ...

  10. el-switch 初始值(默认值)不能正确显示状态问题

    <el-table-column align="center" label="状态">       <template slot-scope= ...