CMDB项目开发
CMDB介绍
CMDB --Configuration Management Database 配置管理数据库, CMDB存储与管理企业IT架构中设备的各种配置信息,它与所有服务支持和服务交付流程都紧密相联,支持这些流程的运转、发挥配置信息的价值,同时依赖于相关流程保证数据的准确性。
- 整合是指能够充分利用来自其他数据源的信息,对CMDB中包含的记录源属性进行存取,将多个数据源合并至一个视图中,生成连同来自CMDB和其他数据源信息在内的报告;
- 调和能力是指通过对来自每个数据源的匹配字段进行对比,保证CMDB中的记录在多个数据源中没有重复现象,维持CMDB中每个配置项目数据源的完整性;自动调整流程使得初始实施、数据库管理员的手动运作和现场维护支持工作降至最低;
- 同步指确保CMDB中的信息能够反映联合数据源的更新情况,在联合数据源更新频率的基础上确定CMDB更新日程,按照经过批准的变更来更新 CMDB,找出未被批准的变更;
- 应用映射与可视化,说明应用间的关系并反应应用和其他组件之间的依存关系,了解变更造成的影响并帮助诊断问题。
cmdb属于运维自动化项目
目的:减少人工干预,降低人员成本
cmdb包括两部分
-资产管理
-操作管理
运维自动化路线:
cmdb的开发需要包含三部分功能:
- 采集硬件数据
- API
- 页面管理
执行流程:服务器的客户端采集硬件数据,然后将硬件信息发送到API,API负责将获取到的数据保存到数据库中,后台管理程序负责对服务器信息的配置和展示。
资产管理的实现
WHY搭建cmdb资产管理
搭建cmdb是因为最终是要搭建自动化平台,包括装机、监控、自动安装软件、部署等全部自动化的执行,而想要搭建自动化的平台的基础是要有资产的管理,因为上面的操作都是在资产的基础上进行的操作,所以搭建平台的首要目的是要对资产进行管控起来,所以我们需要有一个资产管理。
目前CMDB资产管理的实现有如下方式:
cmdb采集资产需求分析
采集资产方式
Agent
基于shell命令实现 # agent形式
# 1.采集资产
# 2.将资产数据发送到API(POST)对于Agent的版本的实现思路:
- Agent采集硬件资产
- API提供相关处理的接口
- 管理平台为用户提供可视化操作
- import subprocess
- import requests
- # pip3 install requests
- # ################## 采集数据 ##################
- # result = subprocess.getoutput('ipconfig')
- # result正则处理获取想要数据
- # 整理资产信息
- # data_dict ={
- # 'nic': {},
- # 'disk':{},
- # 'mem':{}
- # }
- # ################## 发送数据 ##################
- # requests.post('http://www.127.0.0.1:8000/assets.html',data=data_dict)
Paramiko类
基于CMDB中控机和SSH对远程服务器执行命令实现 # SSH形式
# 1.获取今日未采集主机列表
# 2.采集资产
# 3.将资产数据发送到API(POST)- # 基于paramiko模块, pip3 install paramiko
- import requests
- import paramiko
- # ################## 获取今日未采集主机名 ##################
- #result = requests.get('http://www.127.0.0.1:8000/assets.html')
- # result = ['c1.com','c2.com']
- # ################## 通过paramiko连接远程服务器,执行命令 ##################
- # 创建SSH对象
- ssh = paramiko.SSHClient()
- # 允许连接不在know_hosts文件中的主机
- ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
- # 连接服务器
- ssh.connect(hostname='192.168.14.36', port=22, username='wupeiqi', password='')
- # 执行命令
- # stdin, stdout, stderr = ssh.exec_command('df')
- # 获取命令结果
- # result = stdout.read()
- # 关闭连接
- # ssh.close()
- # print(result)
- # data_dict = {result}
- # ################## 发送数据 ##################
- # requests.post('http://www.127.0.0.1:8000/assets.html',data=data_dict)
- # 基于paramiko模块, pip3 install paramiko
SaltStack
基于SaltStack的master上的pillar以及远程执行命令实现 基于 paramiko类实现 # Salt形式
# 1.获取今日未采集主机列表
# 2.采集资产
# 3.将资产数据发送到API(POST)- # 1. 安装saltstack
- # rpm --import https://repo.saltstack.com/yum/redhat/6/x86_64/latest/SALTSTACK-GPG-KEY.pub
- #
- #
- """
- Master: yum install salt-master
- Master准备:
- a. 配置文件,监听本机IP
- vim /etc/salt/master
- interface: 本机IP地址
- b. 启动master
- /etc/init.d/salt-master start
- Slave: yum install salt-minion
- Slave准备:
- a. 配置文件,连接那个master
- vim /etc/salt/minion
- master: 远程master地址
- b. 启动slave
- /etc/init.d/salt-minion start
- 2. 创建关系
- 查看
- Master:salt-key -L
- Accepted Keys:
- Denied Keys:
- Unaccepted Keys:
- c1.com
- c2.com
- c3.com
- Rejected Keys:
- 接受
- Master:salt-key -a c1.com
- Accepted Keys:
- c1.com
- c2.com
- Denied Keys:
- Unaccepted Keys:
- c3.com
- Rejected Keys:
- 3. 执行命令
- master:
- salt 'c1.com' cmd.run 'ifconfig'
- import salt.client
- local = salt.client.LocalClient()
- result = local.cmd('c2.salt.com', 'cmd.run', ['ifconfig'])
- """
- # ################## 获取今日未采集主机名 ##################
- #result = requests.get('http://www.127.0.0.1:8000/assets.html')
- # result = ['c1.com','c2.com']
- # ################## 远程服务器执行命令 ##################
- # import subprocess
- # result = subprocess.getoutput("salt 'c1.com' cmd.run 'ifconfig'")
- #
- # import salt.client
- # local = salt.client.LocalClient()
- # result = local.cmd('c2.salt.com', 'cmd.run', ['ifconfig'])
- # ################## 发送数据 ##################
- # requests.post('http://www.127.0.0.1:8000/assets.html',data=data_dict)
开发中遇到的小问题
在用agent方式连接主机获取数据的时候,一开始获取主机的唯一标识符用的是主板上的sn号(每个电脑的sn号都不同,唯一),但是后来用虚拟机使用时候出现问题,虚拟机上的序列号(sn号)可以相同。
解决方案:使用主机的主机名,且保证主机名不能修改,并把主机名放在一个文件里面,供采集数据时候获取主机名。
为什么不使用fabic和ansible用作验证
fabic和ansible内部用的就是paramiko模块,而我们用的paramiko就是这一类的,ssh就是这一类的
API安全认证
API理解
API(Application Programming Interface,应用程序编程接口)是一些预先定义的函数,目的是提供应用程序与开发人员基于某软件或硬件得以访问一组例程的能力,而又无需访问源码,或理解内部工作机制的细节。
简单理解API是我们提供的一个URL当用户按照指定的格式提交到URL中,我们在内部的views里执行操作,然后返回给用户状态or数据!
API安全
API随便谁都可以调用API进行操作,肯定这个是不安全的!那怎么办呢?
方案如下:
1、客户端与服务器都存放着用于验证的Token字段,值字段无论通过什么方法外部的黑客都是无法获取的。
2、客户端吧本地的时间戳+Token的组合进行MD5加密生成一段新的md5-token。(用时间戳使加密字符串动态起来)
3、客户端访问的时候携带:时间戳、生成的一段新的md5-token。
4、服务端收到请求后,先判断时间戳是否合法(时间戳和当前时间不能大于10秒)
5、再判断当前访问的url是否在url列表里已经存在,如果存在,则拒绝访问。(每次访问的url写在列表里,时间超时10秒的从列表里去掉(每次循环,时间超时去掉),如用reius,membeach的实现)
6、时间戳合法和访问的url不重复了,再去反解验证(客户端拿到自己的Token值和当前时间进行md5加密,把加密后的值和当前时间发送到服务器,服务器根据拿到的时间戳和自己的Token值进行md5加密,如果加密后的数据和发送过来的加密数据md5-token相同,则验证成功。)
7、以上认证通过,执行相关Veiws然后并返回相关的状态或数据
cmdb表结构设计
代码示例
- from django.db import models
- class UserProfile(models.Model):
- """
- 用户信息
- """
- name = models.CharField(u'姓名', max_length=32)
- email = models.EmailField(u'邮箱')
- phone = models.CharField(u'座机', max_length=32)
- mobile = models.CharField(u'手机', max_length=32)
- class Meta:
- verbose_name_plural = "用户表"
- def __str__(self):
- return self.name
- class AdminInfo(models.Model):
- """
- 用户登陆相关信息
- """
- user_info = models.OneToOneField("UserProfile")
- username = models.CharField(u'用户名', max_length=64)
- password = models.CharField(u'密码', max_length=64)
- class Meta:
- verbose_name_plural = "管理员表"
- def __str__(self):
- return self.user_info.name
- class UserGroup(models.Model):
- """
- 用户组
- """
- name = models.CharField(max_length=32, unique=True)
- users = models.ManyToManyField('UserProfile')
- class Meta:
- verbose_name_plural = "用户组表"
- def __str__(self):
- return self.name
- class BusinessUnit(models.Model):
- """
- 业务线
- """
- name = models.CharField('业务线', max_length=64, unique=True)
- contact = models.ForeignKey('UserGroup', verbose_name='业务联系人', related_name='c') # 多个人
- manager = models.ForeignKey('UserGroup', verbose_name='系统管理员', related_name='m') # 多个人
- class Meta:
- verbose_name_plural = "业务线表"
- def __str__(self):
- return self.name
- class IDC(models.Model):
- """
- 机房信息
- """
- name = models.CharField('机房', max_length=32)
- floor = models.IntegerField('楼层', default=1)
- class Meta:
- verbose_name_plural = "机房表"
- def __str__(self):
- return self.name
- class Tag(models.Model):
- """
- 资产标签
- """
- name = models.CharField('标签', max_length=32, unique=True)
- class Meta:
- verbose_name_plural = "标签表"
- def __str__(self):
- return self.name
- class Asset(models.Model):
- """
- 资产信息表,所有资产公共信息(交换机,服务器,防火墙等)
- """
- device_type_choices = (
- (1, '服务器'),
- (2, '交换机'),
- (3, '防火墙'),
- )
- device_status_choices = (
- (1, '上架'),
- (2, '在线'),
- (3, '离线'),
- (4, '下架'),
- )
- device_type_id = models.IntegerField(choices=device_type_choices, default=1)
- device_status_id = models.IntegerField(choices=device_status_choices, default=1)
- cabinet_num = models.CharField('机柜号', max_length=30, null=True, blank=True)
- cabinet_order = models.CharField('机柜中序号', max_length=30, null=True, blank=True)
- idc = models.ForeignKey('IDC', verbose_name='IDC机房', null=True, blank=True)
- business_unit = models.ForeignKey('BusinessUnit', verbose_name='属于的业务线', null=True, blank=True)
- tag = models.ManyToManyField('Tag')
- latest_date = models.DateField(null=True)
- create_at = models.DateTimeField(auto_now_add=True)
- class Meta:
- verbose_name_plural = "资产表"
- def __str__(self):
- return "%s-%s-%s" % (self.idc.name, self.cabinet_num, self.cabinet_order)
- class Server(models.Model):
- """
- 服务器信息
- """
- asset = models.OneToOneField('Asset')
- hostname = models.CharField(max_length=128, unique=True)
- sn = models.CharField('SN号', max_length=64, db_index=True)
- manufacturer = models.CharField(verbose_name='制造商', max_length=64, null=True, blank=True)
- model = models.CharField('型号', max_length=64, null=True, blank=True)
- manage_ip = models.GenericIPAddressField('管理IP', null=True, blank=True)
- os_platform = models.CharField('系统', max_length=16, null=True, blank=True)
- os_version = models.CharField('系统版本', max_length=16, null=True, blank=True)
- cpu_count = models.IntegerField('CPU个数', null=True, blank=True)
- cpu_physical_count = models.IntegerField('CPU物理个数', null=True, blank=True)
- cpu_model = models.CharField('CPU型号', max_length=128, null=True, blank=True)
- create_at = models.DateTimeField(auto_now_add=True, blank=True)
- class Meta:
- verbose_name_plural = "服务器表"
- def __str__(self):
- return self.hostname
- class NetworkDevice(models.Model):
- asset = models.OneToOneField('Asset')
- management_ip = models.CharField('管理IP', max_length=64, blank=True, null=True)
- vlan_ip = models.CharField('VlanIP', max_length=64, blank=True, null=True)
- intranet_ip = models.CharField('内网IP', max_length=128, blank=True, null=True)
- sn = models.CharField('SN号', max_length=64, unique=True)
- manufacture = models.CharField(verbose_name=u'制造商', max_length=128, null=True, blank=True)
- model = models.CharField('型号', max_length=128, null=True, blank=True)
- port_num = models.SmallIntegerField('端口个数', null=True, blank=True)
- device_detail = models.CharField('设置详细配置', max_length=255, null=True, blank=True)
- class Meta:
- verbose_name_plural = "网络设备"
- class Disk(models.Model):
- """
- 硬盘信息
- """
- slot = models.CharField('插槽位', max_length=8)
- model = models.CharField('磁盘型号', max_length=32)
- capacity = models.FloatField('磁盘容量GB')
- pd_type = models.CharField('磁盘类型', max_length=32)
- server_obj = models.ForeignKey('Server',related_name='disk')
- class Meta:
- verbose_name_plural = "硬盘表"
- def __str__(self):
- return self.slot
- class NIC(models.Model):
- """
- 网卡信息
- """
- name = models.CharField('网卡名称', max_length=128)
- hwaddr = models.CharField('网卡mac地址', max_length=64)
- netmask = models.CharField(max_length=64)
- ipaddrs = models.CharField('ip地址', max_length=256)
- up = models.BooleanField(default=False)
- server_obj = models.ForeignKey('Server',related_name='nic')
- class Meta:
- verbose_name_plural = "网卡表"
- def __str__(self):
- return self.name
- class Memory(models.Model):
- """
- 内存信息
- """
- slot = models.CharField('插槽位', max_length=32)
- manufacturer = models.CharField('制造商', max_length=32, null=True, blank=True)
- model = models.CharField('型号', max_length=64)
- capacity = models.FloatField('容量', null=True, blank=True)
- sn = models.CharField('内存SN号', max_length=64, null=True, blank=True)
- speed = models.CharField('速度', max_length=16, null=True, blank=True)
- server_obj = models.ForeignKey('Server',related_name='memory')
- class Meta:
- verbose_name_plural = "内存表"
- def __str__(self):
- return self.slot
- class AssetRecord(models.Model):
- """
- 资产变更记录,creator为空时,表示是资产汇报的数据。
- """
- asset_obj = models.ForeignKey('Asset', related_name='ar')
- content = models.TextField(null=True)
- creator = models.ForeignKey('UserProfile', null=True, blank=True)
- create_at = models.DateTimeField(auto_now_add=True)
- class Meta:
- verbose_name_plural = "资产记录表"
- def __str__(self):
- return "%s-%s-%s" % (self.asset_obj.idc.name, self.asset_obj.cabinet_num, self.asset_obj.cabinet_order)
- class ErrorLog(models.Model):
- """
- 错误日志,如:agent采集数据错误 或 运行错误
- """
- asset_obj = models.ForeignKey('Asset', null=True, blank=True)
- title = models.CharField(max_length=16)
- content = models.TextField()
- create_at = models.DateTimeField(auto_now_add=True)
- class Meta:
- verbose_name_plural = "错误日志表"
- def __str__(self):
- return self.title
CMDB小结
1、三种采集资产的方式
唯一标示
2、发送到API
API验证(tornado源码,加密的cookie+时间限制+访问记录)
数据库表结构
3、后台管理(亮点)
告别增删改查(CRUD),编程开发公共组件(前端(JQUERY占多部分并采用开发的公共组件)+后端配置(自定义开发组件))
更多参考:RESTful API 设计指南:http://www.ruanyifeng.com/blog/2014/05/restful_api.html
cmdb相关文章:http://blog.uinnova.cn/articles/2015/04/23/1429791021932.html
http://www.greatops.net/?id=64
CMDB项目开发的更多相关文章
- CMDB项目要点之技术点(面试题)
1.单例模式 日志对象用单例模式 django admin中注册类是,用到单例模式 为什么要用单例模式 同一个对象操作 维护全局变量 + 对全局变量做一些操作 # __new__ import thr ...
- Android快乐贪吃蛇游戏实战项目开发教程-01项目概述与目录
一.项目简介 贪吃蛇是一个很经典的游戏,也很适合用来学习.本教程将和大家一起做一个Android版的贪吃蛇游戏. 我已经将做好的案例上传到了应用宝,无病毒.无广告,大家可以放心下载下来把玩一下.应用宝 ...
- HTML+CSS项目开发总结
好几天没更新博客了,刚实战完一个HTML+CSS的简单项目.经过几天的摸索,发现收益良多.之前只是单纯得写demo,看知识点,没有亲自实战项目.但实战过后才会了解,如何才能更好地提升自己的技术.针对这 ...
- 简历生成平台项目开发-STEP2问卷调查结果统计分析
根据之前设计的调查问卷,截止目前为止,一共收到64份问卷结果.一共16题,分别从基本信息.是否对简历制作有需要.对产品期望的特点和建议采纳四个方面设计问题.下面逐题分析问卷结果: 1.您的性别 可以看 ...
- 如何使用Worktile进行敏捷项目开发管理
Worktile在任务管理上采用了看板视图,非常适合进行敏捷项目开发管理.事实上,在开发Worktile的过程中,我们也是自产自销,使用Worktile管理Worktile本身的开发过程,在本文中跟大 ...
- Java进击C#——项目开发环境
本章简言 上一章我们了解一下开发环境,知道了什么去新建一个项目工程.却并没有去项目工程进行介绍.可是之后我们会常常跟项目工程打交道.所以这章笔者就对项程工程的常用的一些功能进行讲解.当然说全面那是不可 ...
- 关于举办 2015年 Autodesk 助力云应用项目开发活动通知
各位尊敬的Autodesk 合作伙伴,大家好! 相信您在过去的一年里应该对Autodesk最新的云服务技术有所了解,您是不是曾经闪现过一些很好的想法,却由于不确定是否真实可行,或担心没有技术支持来帮助 ...
- .NET程序员项目开发必知必会—Dev环境中的集成测试用例执行时上下文环境检查(实战)
Microsoft.NET 解决方案,项目开发必知必会. 从这篇文章开始我将分享一系列我认为在实际工作中很有必要的一些.NET项目开发的核心技术点,所以我称为必知必会.尽管这一系列是使用.NET/C# ...
- [转]基于Starling移动项目开发准备工作
最近自己趁业余时间做的flash小游戏已经开发得差不多了,准备再完善下ui及数值后,投放到国外flash游戏站.期间也萌生想法,想把游戏拓展到手机平台.这两天尝试了下,除去要接入ane接口的工作,小游 ...
随机推荐
- Linux新手随手笔记1.4
计划任务服务程序 计划任务 at 命令 一次性的 crond 服务 周期性的 23:29执行reboot命令(重启服务器) at -l 查看当前的计划任务 at ...
- Mysql基本命令及数据库存储位置
连接数据库: sudo mysql -p+密码 例如:sudo mysql -p123456 1.显示数据库列表. show databases; 2.显示库中的数据表: use mysql: //打 ...
- 01构建第一个SpringBoot工程
第一篇:构建第一个SpringBoot工程 文章指导 学习笔记 学习代码 创建项目 创建工程:Idea-> new Project ->Spring Initializr ->填写g ...
- Django Models 查询操作
1.准备数据表: from django.db import models class City(models.Model): name=models.CharField(max_length=32) ...
- MongoDB系列:二、MongoDB常用操作练习
最近在自学MongoDB,在此记录一下,当做学习笔记了(不断更新中)!! 一.背景 MongoDB 是一个基于分布式文件存储的数据库.由 C++ 语言编写.旨在为 WEB 应用提供可扩展的高性能数据存 ...
- Django(六)Session、CSRF、中间件
大纲 二.session 1.session与cookie对比 2.session基本原理及流程 3.session服务器操作(获取值.设置值.清空值) 4.session通用配置(在配置文件中) 5 ...
- eclipse中maven父子项目层级显示设置
第一步:window-->show view --> project explorer 第二步:小三角---> projects presentation----->hiera ...
- Netty的基本使用
Gradle 的优点 原文:https://blog.csdn.net/achenyuan/article/details/80682288 1. 按约定声明构建和建设: 2. 强大的支持多工程的构 ...
- webpack4 学习 --- 处理静态资源
webpack 是利用loader 来处理各种资源的,wepback的配置基本上就是为各种资源文件,指定不同类型的loader. 1,处理css 最基本的css 处理loader 是css-loade ...
- RSA加解密工具类RSAUtils.java,实现公钥加密私钥解密和私钥解密公钥解密
package com.geostar.gfstack.cas.util; import org.apache.commons.codec.binary.Base64; import javax.cr ...