运维自动化项目
减少人工干预,降低人员成本
- 资产管理
- 操作管理
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)
代码:
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:用于生成输入框时从全局变量取对应的字典来循环。
总结:
原文:https://www.cnblogs.com/czlong/p/6220855_.html