1.什么是cmdb

  配置管理数据库 ,存储基础设备的各种信息配置等

  CMDB可以存储并自动发现整个IT网络上的各种信息,比如一个IT网络上有多少台服务器、多少存储、设备的品牌、资产编号、维护人员、所属部门、服务器上运营什么操作系统、操作系统的版本、操作系统上有哪些应用、每个应用的版本等等,不仅如此,CMDB还有一个非常重要的功能——存储不同资源之间的依赖关系,如果网络上某个节点出现问题(比如某个服务器down了),通过CMDB,可以判断因此受到影响的业务

  CMDB由三个部分实现 : api系统(django)   +  资产采集系统   +  后台管理系统

2.知识点分解

  1)django实现api ,python普通项目实现client ,完成二者间的通信

    api使用Django提供的rest_framwork模块

      APIView避免csrf对post的限制

      request.data中存放了客户端post请求的数据

      Response方法将数据进行json转换

    client使用requests和json模块

      requests.get对api发起get请求获取到的数据可以使用content拿出Byte类型

      requests.post对api发起post提交数据必须提交json编码后的类型

###api
##路由
urlpatterns = [
url(r'^asset/', views.Asset.as_view()),
]
##视图函数
from django.shortcuts import render, HttpResponse
from rest_framework.views import APIView
from rest_framework.response import Response class Asset(APIView):
def get(self, request):
server_info = ['master1', 'master2']
return Response(server_info) def post(self, request):
print(request.data)
return HttpResponse('200ok')
###client端
import requests
import json client_info = {'hostname': 'c1.com'} r1 = requests.get(
url='http://127.0.0.1:8000/api/asset/'
) r1_data = json.loads(r1.content.decode('utf-8')) print(r1_data)
  
r2 = requests.post(                      ###post提交数据一定要加请求头部标记json格式
url='http://127.0.0.1:8000/api/asset/',
data=json.dumps(client_info).encode('utf-8'),
headers={
'content-type': 'application/json'
}
)

  2)通过字符串加载文件中的类 ,实现开放封闭必备小点

    我们如何在配置中定义使用哪个文件中的类呢 ,使用字典 ,以点分割 目录.文件.类名

    如 : agent模式对应了一个字符串它对应了 /src/engine/agent.py文件中的AgentHandler类

###settings.py
ENGINE = 'agent' ENGINE_DICT = {
'agent': 'src.engine.agent.AgentHandler',
'ssh': 'src.engine.ssh.SSHHandler',
} ####设计一个函数完成从文件中获取类
import importlib
def import_string(class_string):
"""
根据配置中字符串获取文件中的类
:param 'src.engine.agent.AgentHandler',
module, engine = src.engine.agent 和 AgentHandler
importlib.import_module()就是import src.engine.agent
engine_class = 反射获取到AgentHandler类
"""
module, engine = class_string.rsplit('.', maxsplit=1)
module_file = importlib.import_module(module)
engine_class = getattr(module_file, engine)
return engine_class

3.CMDB资产采集系统简单实现要点

  采集模式engine
    agent模式 ,每台主机安装client ,执行命令将采集的数据上报api
    中控机模式(ssh ansible) ,使用一台机器远程所有的主机 ,执行命令完成资产采集 ,再将数据上报api
    调用issa层的api接口直接获取基础设备信息

  程序设计思想

    开放封闭原则 ,代码封闭 ,配置开放(定义当前的使用的engine与plugin),支持扩展

  程序设计关注点

    资产采集

      engine采集模式可扩展 (抽象接口)

      plugin命令插件可扩展 (抽象接口)

    唯一标识
    错误处理
    日志

4.CMDB资产采集系统简单实现代码

  1)API端后续完善 ,先使用标题2-1的api

  2)新建项目 ,完善常规目录

  3)程序入口/bin/client

    执行run()

import os
import sys
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) from src.script import run if __name__ == '__main__':
run()

  4)资产采集上报入口/src/script

    定义run()

    根据配置settings实例化engine的对象 ,并执行对象的handler方法

from conf import settings
from lib.import_class import import_string #标题2-2的根据配置字符串取类 def run():
"""资产采集入口"""
engine_path = settings.ENGINE_DICT.get(settings.ENGINE)
engine_class = import_string(engine_path)
obj = engine_class()
obj.handler()

  5)采集模式engine实现handler()方法

    定义基类约束BaseHandler() 要求每个engine必须有handler()完成采集与上报, cmd()完成调用命令窗口

    定义基类简化ssh这一类的插件SSHandSaltHandler(BaseHandler)  ,这一类的handler()方法都是从api获取主机列表 ,远程采集设备信息 ,再提交api ,所以会出现同时对很多的主机进行连接 ,这里使用线程池

import requests
from concurrent.futures import ThreadPoolExecutor
from ..plugins import get_server_info
import json class BaseHandler():
"""
定义engine的基类 ,每个engine都要有这两个方法
""" def handler(self):
raise NotImplementedError('handler() must be Implemented') def cmd(self, command, hostname=None):
raise NotImplementedError('cmd() must be Implemented') class SShandSaltHandler(BaseHandler):
"""
简化ssh这一类engine的代码
""" def handler(self):
# 1.获取主机列表
r1 = requests.get(
url='http://127.0.0.1:8000/api/asset/',
)
host_list = r1.json() # 2.创建线程池
pool = ThreadPoolExecutor(20) # 3.提交任务给线程池
for hostname in host_list:
pool.submit(self.task, hostname) def task(self, hostname):
"""线程池任务"""
info = get_server_info(self, hostname)
r1 = requests.post(
url='http://127.0.0.1:8000/api/asset/',
data=json.dumps(info).encode('gbk'),
headers={
'content-type': 'application/json'
}
)

    engine--agent模式实现handler()

      cmd()方法使用subprocess模块完成本地命令调用

from src.engine.base import BaseHandler
from ..plugins import get_server_info
import requests
import json class AgentHandler(BaseHandler):
"""定义cmd窗口 ,操控资产采集 + 上报""" def cmd(self, command, hostname=None):
import subprocess
return subprocess.getoutput(command) def handler(self):
info = get_server_info(self)
r1 = requests.post(
url='http://127.0.0.1:8000/api/asset/',
data=json.dumps(info).encode('gbk'),
headers={
'content-type': 'application/json'
}
)

    engine--ssh模式实现handler()

      cmd()方法使用paramiko模块完成远程命令调用 (秘钥需要配置在settings中)

from src.engine.base import SShandSaltHandler
from conf import settings class SSHandler(SShandSaltHandler):
"""仅定义cmd即可 ,采集与上报在父类中""" def cmd(self, command, hostname=None):
import paramiko
private_key = paramiko.RSAKey.from_private_key_file(settings.SSH_PRIVATE_KEY)
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

  6)handler方法中的数据采集使用了get_server_info()方法

    script.py与__init__有异曲同工之处 ! 依据配置应用不同插件

from conf import settings
from lib.import_class import import_string def get_server_info(handler, hostname=None):
"""采集信息入口"""
info = {}
for name, path in settings.PLUGINS_DICT.items():
"""
{'disk':'src.plugins.disk.Disk'}
"""
plugin_class = import_string(path)
obj = plugin_class()
info = obj.process(handler, hostname)
return info

  7)命令插件plugins实现process()方法

    定义基类约束BasePlugin

      增加debug属性判断是否为调试模式 ,增加项目根路径

      每个命令插件都要分为window与linux的具体系统判断执行什么命令

from conf import settings

class BasePlugin:
def __init__(self):
self.debug = settings.DEBUG
self.base_dir = settings.BASE_DIR def get_os(self, handler, hostname=None): ## 调试
# os = handler.cmd('命令',hostname)
return 'linux' def win(self, handler, hostname=None):
raise NotImplementedError('win() must be Implemented') def linux(self, handler, hostname=None):
raise NotImplementedError('linux() must be Implemented') def process(self, handler, hostname=None):
os = self.get_os(handler, hostname)
if os == 'win':
ret = self.win(handler, hostname)
else:
ret = self.linux(handler, hostname) return ret

    查看硬盘的命令插件

      其中process--->调用win或者linux--->执行handler对象的cmd()方法 (这个对象最开始就被当做参数传过来了)

      其中还会有debug判断 ,如果是调试就直接从文件获取数据了

      其中parse方法是将采集的数据格式化 ,需要根据api所需要的格式进行格式化

from .base import BasePlugin
import os
import re class Disk(BasePlugin):
def win(self, handler, hostname=None):
ret = handler.cmd('dir', hostname)[:60] return 'Disk' def linux(self, handler, hostname=None):
if self.debug:
with open(os.path.join(self.base_dir, 'files', 'disk.out')) as f:
ret = f.read()
else:
ret = handler.cmd('ifconfig', hostname)[:60]
return self.parse(ret) 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 = ''
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

    查看内存的命令插件

from .base import BasePlugin
import os
from lib import convert class Memory(BasePlugin):
def win(self, handler, hostname=None):
"""
windowns下执行命令
:param handler:
:param hostname:
:return:
"""
ret = handler.cmd('dir', hostname)[:60] return 'Disk' def linux(self, handler, hostname=None):
if self.debug:
with open(os.path.join(self.base_dir, 'files', 'memory.out')) as f:
ret = f.read()
else:
ret = handler.cmd('lsblk', hostname)[:60] return ret 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

5.简单一些想法完成开放封闭

  首先属于同类功能 ,这类的功能是需要不停增加的 ,或者说可以选用的都通过配置实现 ,使用抽象类约束

    配置 :指定操作者  ,操作者使用的工具

    生成操作者(script)

    handler操作者: 可以操作任意工具

    生成操作者使用的工具(__init__)  

    plugin工具: 网卡查看工具  硬盘查看工具查看

cmdb项目-1的更多相关文章

  1. Python Django CMDB项目实战之-3创建form表单,并在前端页面上展示

    基于之前的项目代码 Python Django CMDB项目实战之-1如何开启一个Django-并设置base页.index页.文章页面 Python Django CMDB项目实战之-2创建APP. ...

  2. Python Django CMDB项目实战之-2创建APP、建模(models.py)、数据库同步、高级URL、前端页面展示数据库中数据

    基于之前的项目代码来编写 Python Django CMDB项目实战之-1如何开启一个Django-并设置base页index页文章页面 现在我们修改一个文章列表是从数据库中获取数据, 下面我们就需 ...

  3. Python Django CMDB项目实战之-1如何开启一个Django-并设置base页、index页、文章页面

    1.环境 win10 python 2.7.14 django 1.8.2 需要用到的依赖包:MySQLdb(数据库的接口包).PIL/pillow(处理图片的包) 安装命令: pip install ...

  4. CMDB项目要点之技术点(面试题)

    1.单例模式 日志对象用单例模式 django admin中注册类是,用到单例模式 为什么要用单例模式 同一个对象操作 维护全局变量 + 对全局变量做一些操作 # __new__ import thr ...

  5. Python之路【第二十二篇】CMDB项目

    浅谈ITIL TIL即IT基础架构库(Information Technology Infrastructure Library, ITIL,信息技术基础架构库)由英国政府部门CCTA(Central ...

  6. CMDB项目开发

    CMDB介绍 CMDB --Configuration Management Database 配置管理数据库, CMDB存储与管理企业IT架构中设备的各种配置信息,它与所有服务支持和服务交付流程都紧 ...

  7. CMDB项目实战

    01-CMDB项目介绍 02-CMDB开发背景 03-CMDB开发目的 04-CMDB资产采集方式之agent 05-CMDB资产采集方式之ssh 06-CMDB资产采集方式之saltstack 07 ...

  8. cmdb项目-3

    1. cmdb资产审计 2.stark组件使用 快速完成网站的一个组件,使用方式与django的admin系统类似 ,仅仅将model注册 ,就可以生成对model增删改查的页面 ,当然这里还包括了模 ...

  9. CMDB项目要点总结之中控机

    1.基于paramiko对远程主机执行命令操作 秘钥形式 private_key = paramiko.RSAKey.from_private_key_file('c:/Users/用户名/.ssh/ ...

随机推荐

  1. AOP框架Dora.Interception 3.0 [4]: 基于特性的拦截器注册

    按照单一职责的原则,拦截器只负责需要的拦截操作的执行,至于它采用何种方式应用到目标方法上,以及它在整个拦截器管道中的位置则属于“拦截器注册”的范畴.Dora.Interception提供了几种典型的注 ...

  2. SpringCloud-使用路由网关统一访问接口(附代码下载)

    场景 SpringCloud-使用熔断器仪表盘监控熔断: https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/102673599 Spr ...

  3. Java面试题_第四阶段

    1.1 电商行业特点 1.分布式 垂直拆分:根据功能模块进行拆分 水平拆分:根据业务层级进行拆分 2.高并发 用户单位时间内访问服务器数量,是电商行业中面临的主要问题 3.集群 抗击高兵发的有效手段, ...

  4. 富士通 DX90 S2存储分配映射盘

    屁话不多说,直接开操: 1.连接存储 用pc连接到存储管理口,如192.168.1.101 登录管理账号:默认root/root 创建Volume, 点击create开始创建新的volume 按需填写 ...

  5. Azure 上的高可用概念

    更多内容,添加公众号关注: 场景一: 某智能家居厂家,用户喊出“小X同学,帮我扫地”后,服务器宕机了,扫地机器人不能立即启动,于是,用户可能再连续喊几次后,无奈又习惯的按下了扫地机器人的启动按钮. 场 ...

  6. Maven pom.xml文件深度学习

    本文介绍Maven项目构建中,pom.xml文件的生成规则和常用节点的使用方法.pom.xml官方网址:http://maven.apache.org/pom.html pom简介 pom作为项目对象 ...

  7. Prometheus学习系列(九)之Prometheus 存储

    前言 本文来自Prometheus官网手册 和 Prometheus简介 存储 Prometheus是一个本地磁盘时间序列数据库,但也可选择与远程存储系统集成,其本地时间序列数据库以自定义格式在磁盘上 ...

  8. Prometheus学习系列(五)之Prometheus 规则(rule)、模板配置说明

    前言 本文来自Prometheus官网手册1.2.3.4和 Prometheus简介1.2.3.4 记录规则 一.配置规则 Prometheus支持两种类型的规则,这些规则可以定期配置,然后定期评估: ...

  9. js中关于constructor与prototype的理解

    1.①__proto__和constructor属性是对象所独有的:② prototype属性是函数所独有的,因为函数也是一种对象,所以函数也拥有__proto__和constructor属性. 2. ...

  10. 一条简单的更新语句,MySQL是如何加锁的?

    看如下一条sql语句: # table T (id )) delete : MySQL在执行的过程中,是如何加锁呢? 在看下面这条语句: : 那这条语句呢?其实这其中包含太多知识点了.要回答这两个问题 ...