安装完node_exporter后,需要在prometheus的配置文件中添加该节点才能使之被纳入prometheus的监控范围中。想要自动化该过程,不免需要两台主机之间的通信,不过既然能被监控说明之间的网络应该是相通的。
为了使脚本尽可能的轻量并具有泛用性,不添加额外的库和包,脚本方面采用curl发送get和post的方式进行通信。prometheus服务器上部署一个服务接收参数并处理,这个服务不可避免要装一些组件的,不过装一次就够了。服务采用tronado框架。prometheus的配置文件采用conf.d的方法实现自动更新,具体可以参考这里:,实际上就是把prometheus.yml中的job换成conf.d中的json文件,例如:
这样这个job的节点就是读取该json中的内容。
下面上代码:
自动化脚本script.py:
# -*- coding: utf-8 -*-
import os
#与prometheus服务器通信,注册prometheus监控
print((os.popen('curl 192.168.100.181:9123')).read())
print('请选择job:')
job=raw_input()
ip = ((os.popen("ip addr | grep 'state UP' -A2 | tail -n1 | awk '{print $2}' | cut -f1 -d '/'")).read())
print('输入hostname:(按enter使用默认值:jt-'+ip[:-1]+')')
hostname = raw_input()#这是python2的,3的话就input()就好
if hostname =='':
hostname ='linux-'+ip[:-1]
order="curl 192.168.100.181:9123 -X POST -d '{ \"job\": \"" + job + '\",\"hostname\": \"' + hostname + '\", \"ip\": \"' + ip[:-1] + "\"}' --header 'Content-Type: application/json'"
print((os.popen(order).read()))
服务端脚本scriptService.py:
import tornado.ioloop
import tornado.web
import json
import os
def promeConf(hostname,ip,job):
path="/opt/monitor/prometheus/prometheus-2.7.1.linux-amd64/conf.d/"#prometheus配置文件路径,根据实际情况修改
filename=j.joblist[int(job)]+'.json'
with open(path+filename, mode='r') as f:
list=json.load(f)
f.close()
dict=\
{
"targets": [ip+":9100"],
"labels":
{
"hostname": hostname
}
}
with open(path+"hf10g_virtual.json", mode='w') as f:
list.append(dict)
f.write(json.dumps(list,indent=1))
class Job():
joblist=[]#定义一个类供全局使用
class MainHandler(tornado.web.RequestHandler):
def get(self):
datalist=''
job = (os.popen('ls /opt/monitor/prometheus/prometheus-2.7.1.linux-amd64/conf.d/')).read()
j.joblist = (job.split('\n'))
while ('' in j.joblist):
j.joblist.remove('')
for i in range(len(j.joblist) - 1):
if (j.joblist[i])[-5:] == '.json':
j.joblist[i] = j.joblist[i][:-5]
else:
j.joblist.remove(j.joblist[i])
i = i + 1
for i in range(len(j.joblist) - 1):
datalist = datalist + str(i) + ':' + j.joblist[i] + '\n'
datalist='请选择job:\n'+datalist
self.write(datalist)
self.finish()
def post(self):
data = json.loads(self.request.body)
hostname=data['hostname']
ip=data['ip']
job=data['job']
promeConf(hostname,ip,job)
application = tornado.web.Application([
(r"/", MainHandler),
])
if __name__ == "__main__":
j=Job()#实例化
application.listen(9123)#自设端口
tornado.ioloop.IOLoop.instance().start()
大致流程:
下面逐步解析这套程序:
1.script.py:get请求job列表
print((os.popen('curl 192.168.100.181:9123')).read())
在linux端用curl方法去get prometheus服务器对应服务接口,没什么好说的。
2.scriptService.py:接收get请求、获取job列表、处理数据、返回信息
ls一下文件夹,把str切成列表,把不是.json的、空的都去掉,逻辑上仔细看应该就能明白,但是一般来讲拿去就能用,毕竟形式都固定的。然后加个序号排一下版再发回去,同时列表存起来供下一步使用。
def get(self):
datalist=''
job = (os.popen('ls /opt/monitor/prometheus/prometheus-2.7.1.linux-amd64/conf.d/')).read()
j.joblist = (job.split('\n'))
while ('' in j.joblist):
j.joblist.remove('')
for i in range(len(j.joblist) - 1):
if (j.joblist[i])[-5:] == '.json':
j.joblist[i] = j.joblist[i][:-5]
else:
j.joblist.remove(j.joblist[i])
i = i + 1
for i in range(len(j.joblist) - 1):
datalist = datalist + str(i) + ':' + j.joblist[i] + '\n'
datalist='请选择job:\n'+datalist
self.write(datalist)
self.finish()
3.script.py:键入job编号,获取本机ip,键入或生成hostname
想获取本机网络上的ip就是ip addr | grep 'state UP' -A2 | tail -n1 | awk '{print $2}' | cut -f1 -d '/'这条命令,根据实际情况使用。raw_input是python2的方法,3的话就input(),主机名输入为空的话就默认为linux-ip。查到的ip最后一位是‘\n’,所以截掉最后一位。
job=raw_input()
ip = ((os.popen("ip addr | grep 'state UP' -A2 | tail -n1 | awk '{print $2}' | cut -f1 -d '/'")).read())
print('输入hostname:(按enter使用默认值:kvm-'+ip[:-1]+')')
hostname = raw_input()
if hostname =='':
hostname ='linux-'+ip[:-1]
这个是适用于单网卡的方法多网卡不一定适用,下面给出另一种方法:
ip = ((os.popen("ifconfig -a|grep inet|grep -v 127.0.0.1|grep -v inet6|awk '{print $2}'|tr -d 'addr:'")).read())#ifconfig -a|grep inet|grep -v 127.0.0.1|grep -v inet6|awk "{print $2}'|tr -d "addr:"
ip = ip.split('\n')
if len(ip)>1:
ip=[s for s in ip if '192' in s]#如果多网卡中想要的ip有特征可以在这里筛选,否则就手动选择吧
ip=ip[0]
而且这种方法ip后面不带‘\n’,不用切掉最后一位。总之核心都是围绕着shell命令,再根据情况做数据处理。
4.script.py:post发送参数json
还是curl,发送一个json,注明--header 'Content-Type: application/json'。python2中解析json好像内部的引号必须是双引号,可以用\"来区分。
order="curl 192.168.100.181:9123 -X POST -d '{ \"job\": \"" + job + '\",\"hostname\": \"' + hostname + '\", \"ip\": \"' + ip[:-1] + "\"}' --header 'Content-Type: application/json'"
print((os.popen(order).read()))
5.scriptService.py:接收post,解析json
也没啥好说的,拿来就用就行
def post(self):
data = json.loads(self.request.body)
hostname=data['hostname']
ip=data['ip']
job=data['job']
promeConf(hostname,ip,job)
6.scriptService.py:更新配置文件
首先确定自己prometheus的配置conf.d路径,然后按照job的序号在joblist中找到对应job.json,格式就是
[
{
"targets": ["10.30.17.13:9100"],
"labels": {
"hostname": "kvm1"
}
},
{
"targets": ["10.30.17.14:9100"],
"labels": {
"hostname": "kvm2"
}
},
{
"targets": ["10.30.17.15:9100"],
"labels": {
"hostname": "linux01"
}
}
]
文件操作是先读,把json转成字典列表,然后append新的字典,再写入json文件。
def promeConf(hostname,ip,job):
path="/opt/monitor/prometheus/prometheus-2.7.1.linux-amd64/conf.d/"
filename=j.joblist[int(job)]+'.json'
with open(path+filename, mode='r') as f:
list=json.load(f)
f.close()
dict=\
{
"targets": [ip+":9100"],
"labels":
{
"hostname": hostname
}
}#有些node设定的端口不是9100,根据实际情况去改
with open(path+"hf10g_virtual.json", mode='w') as f:
list.append(dict)
f.write(json.dumps(list,indent=1))
注意防火墙开对应端口嗷~
7.注册跳板机资产
这个可以看,把模块整合进去,反正注册只需要ip和hostname,传参里都有了。admin_user是跳板机中root用户的id,nodes是节点的id,都可以是固定的。
def get_token(jms_url, username, password):
url = jms_url + '/api/v1/authentication/auth/'
query_args = {
"username": username,
"password": password
}
response = requests.post(url, data=query_args)
return json.loads(response.text)['token']
def create_assest(jms_url, token,ip,hostname):
url = jms_url + '/api/v1/assets/assets/'
headers = {
"Authorization": 'Bearer ' + token,
'X-JMS-ORG': '',
'accept': 'application/json',
'Content-Type': 'application/json'
}
data={
"ip": ip,
"hostname": hostname,
"platform": "Linux",
"is_active": True,
"admin_user": "53594e64-48c7-4679-bf7c-d54aba747416",
"nodes": ["d422754d-36fb-4f6f-a0ba-8f41b60c38e2"]
}
data_json = json.dumps(data)
response = requests.post(url,data_json, headers=headers)
response.json()
return(response.text)
class MainHandler(tornado.web.RequestHandler):
def post(self):
data = json.loads(self.request.body)
hostname=data['hostname']
ip=data['ip']
jms_url = '跳板机地址'
username = '~'
password = '~'
token = get_token(jms_url, username, password)
#promeConf(hostname,ip)
self.write(create_assest(jms_url,token,ip,hostname))