CMDB项目管理
运维自动化项目
减少人工干预,降低人员成本
- 资产管理
- 操作管理
CMDB
- 运维自动化基础
- 资产管理,自动化收集,API接口,可视化管理
装系统,装服务器环境,比特流上传代码,实时监控服务器
一、资产采集方式
1.CMDB资产采集方式之agent
- 本地执行命令 v=subprocess.getoutput('ipconfig')
- 获取关键信息
- 将数据录入数据库
- 不能直连数据库,由于安全,写django程序,通过某个url提交数据到views函数,再提交给数据库(API,requests.post)
优点:快
不好:有agent
# 采集数据 import subprocess import 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)
2.CMDB资产采集方式之ssh
中间有一个采集资产的机器,不能subprocess了
python 有个模块paramiko,主机名+密码+命令即可在机器执行命令,获取结果返回给中间机器,然后给API,再给数据库
优点:无agent
缺点:paramiko慢(ansible,fabric)
代码:
import requests import paramiko # 获取今天未采集主机名 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='123') # 执行命令 # stdin, stdout, stderr = ssh.exec_command('ipconfig') # stdin.write('') # 用于写信息 # 获取命令结果 # result = stdout.read() # 关闭连接 # ssh.close() # print(result) # data_dict = {result} # ################## 发送数据 ################## # requests.post('http://www.127.0.0.1:8000/assets.html',data=data_dict)
3.CMDB资产采集方式之saltstack(最火)
基本流程一样,也有中间的采集资产机器
但不同在于依赖第三方工具,远程发送执行命令的时候比较快(salt.cmd('c1.com','ipconfig'))
与ssh的区别:不是硬连,维护一个队列。salt-master主动发送命令给队列,salt-slave获取自己命令,将结果放到另一个队列
master从这个队列取。RPC形式,没有等待。
优点:快,不用开发部署agent
缺点:依赖第三方
代码: # ################## 获取今日未采集主机名 ################## #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'") # 本地执行命令,本地通过saltstack去远程拿数据 # # 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)
4.CMDB资产采集方式之puppet(比较老了)
puppet类似于saltstack,被动接受slava结果
puppet有个报表功能,slave每一段时间主动连master,执行自定义命令,这个脚本得用ruby写
优点:自动汇报
缺点:ruby
总结:写配置文件,兼容前三种方式,根据情况选择。每天采集一次即可。
- 第一种,agent定时执行脚本,汇报给api(提供数据,收集数据统一管理)
- 第二种,paramiko从api取哪台机器还没汇报,远程执行命令,拿取数据
- 第三种,依赖saltstack,队列RPC形式,
- 第四种,知道即可,每段时间连接master,执行factor命令脚本,汇报结果
二、SaltStack运行
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' python中执行 import salt.client local = salt.client.LocalClient() result = local.cmd('c2.salt.com', 'cmd.run', ['ifconfig'])
三、资产采集插件
python程序目录结构:
- bin:可执行文件目录
- conf:配置文件目录
- lib:公共模块目录
- log:日志
- src:业务逻辑
发送数据:字典嵌套字典的数据,通过requests.post的json可以自动转为字符串,再转为字节,服务器需要先str(body)再loads
四、动态加密方式
第一种:在headers设置一个随机字符串,服务器获取request.META['HTTP_AUTHKEY']比较
headers={'authkey':'asdasd'} json.loads(str(request.body,encoding='utf-8'))
第二种:将随机字符串md5加密
app_id = 'asdasdasdasd' m = hashlib.md5() m.update(bytes(app_id,encoding='utf-8')) authkey = m.hexdigest()
第三种:随机字符串|当前时间 =》加密后的字符串|时间
current_time = time.time() app_id = 'asdasdasdasd' app_id_time = "%s|%s" %(app_id,current_time) m = hashlib.md5() m.update(bytes(app_id_time,encoding='utf-8')) authkey = m.hexdigest() authkey_time = "%s|%s"%(authkey,current_time) auth_key_time = request.META['HTTP_AUTHKEY'] auth_key,client_ctime = auth_key_time.split('|') key_time = "%s|%s" %(ck,client_ctime) m = hashlib.md5() m.update(bytes(key_time, encoding='utf-8')) authkey = m.hexdigest() if authkey!=auth_key: return HttpResponse('授权失败')
第四种:在第三种基础上,通过加密字符串列表和时间限制,来限制
server_current_time = time.time() auth_list = [] if server_current_time - 10 > float(client_ctime): return HttpResponse('授权失败') if auth_key_time in auth_list: return HttpResponse('授权失败') auth_list.append(auth_key_time) #仅当通过三重验证后才加入列表
2018/07/25 day 76 CMDB之后台管理
一、配置文件控制生成表格
table_config = [ { 'q':'id', 'title':'ID', 'display':False }, { 'q': 'cabinet_num', 'title': '机柜号', 'display': True }, ] q_list.append(i['q']) # 添加要取的列名 data_list = models.Asset.objects.all().values(*q_list) data_list = list(data_list) # 转列表 function initHeaders(table_config) { var tr = document.createElement('tr'); $.each(table_config,function (k,item) { # 循环 if(item.display){ var th = document.createElement('th'); th.innerHTML = item.title; # 赋值 $(tr).append(th); } }); $('#thead_th').append(tr) }
二、自定义字符串方法实现字符串替换
String.prototype.format = function (kwargs) { var ret = this.replace(/\{(\w+)\}/g,function(km,m) { return kwargs[m] }); return ret };
三、自定义@符号规则
{ 'q': None, 'title': '操作', 'display': True, 'text': {'content': '<a href="/asset-detail/{m}">{n}</a>', 'kwargs': {'n': '查看','m':'@id'}} }, var kwargs = {}; $.each(config.text.kwargs,function (key,value) { if(value[0]=='@'){ #遇到第一个字符为@时获取数据库的数据 kwargs[key]=item[value.substring(1,value.length)]; }else { kwargs[key]=value; } }); var temp = config.text.content.format(kwargs); td.innerHTML = temp;
四、双@规则
在前端设置字符串的全局变量 function initGlobalData(global_list) { $.each(global_list,function (k,v) { window[k]=v }) } views函数中 { 'q': 'device_type_id', 'title': '资产类型', 'display': True, 'text': {'content': '{n}', 'kwargs': {'n': '@@device_type_choices'}} }, JavaScript判断 if(value.substring(0,2)=='@@'){ var globalName = value.substring(2,value.length); var currentId = item[config.q]; # 获取数据库对应的id var t = getTextFromGlobalById(globalName,currentId);# 去全局变量中取id对应的文本 kwargs[key]=t; } 定义函数 function getTextFromGlobalById(globalName,currentId) { var ret = null; $.each(window[globalName],function (k,item) { if(item[0]==currentId){ ret = item[1]; # 取id对应的文本 return } }); return ret }
五、自定义属性以及单@规则
{ 'q': 'cabinet_num', 'title': '机柜号', 'display': True, 'text': {'content':'{n}','kwargs':{'n':'@cabinet_num'}}, 'attrs': {'edit-enable': 'true', 'edit-type': 'input'} }, $.each(config.attrs,function (kk,vv) { td.setAttribute(kk,vv); });
单@规则:
{ 'q': 'manager__name', 'title': '管理人组', 'display': True, 'text': {'content': '{n}', 'kwargs': {'n': '@manager__name'}}, 'attrs': {'name': 'manager_id', 'origin': '@manager_id', 'edit-enable': 'true', 'edit-type': 'select', 'global-name': 'manager_choices'} },
origin:用于生成select框时的赋值(ID数字),origin的@在initBody函数内会转换为item的值,这样生成select框时有值可赋。
而对于input,则不赋值,只用于比较新生成的值new-val
name:用于保存新编辑的值,字典的key
global-name:用于生成输入框时从全局变量取对应的字典来循环。
总结: