《cmdb事件推送實現zabbix資產同步》一文實現了cmdb和zabbix的資產同步,接下來咱們就離着《運維思索:cmdb打通zabbix、jumpserver探索》這個小目標就不遠了。node
言歸正傳,jumpserver的資產分組同步,即jumpserver的資產列表與cmdb的業務拓撲保持一致,按照業務–集羣–模塊的樹形結構分佈。python
而cmdb和jumpserver的同步思路與前面基本保持一致,即:git
只有當主機轉移至相關模塊時,纔會觸發業務、集羣、模塊(例如分別對應消金生產環境–運維平臺–禪道)的節點建立;而在cmdb側只建立空的集羣、模塊時不會觸發jumpserver同步,以避免致使建立空節點。redis
cmdb只有在集羣和模塊下資產都爲空的狀況才能執行刪除,這個策略和jumpserver一致,所以在主機標識更新保證資產粒度級別的分組一致後,刪除操做就不是問題了。django
《騰訊藍鯨實現vsphere虛擬機交付》一文咱們經過藍鯨標準運維已經實現了新建主機在jumpserver中建立、自動註冊到cmdb,在保證主機上架流程前提下,咱們能夠認爲全部的主機默認都是在cmdb和jumpserver中已經存在的,咱們只需保證jumpserver資產分組和cmdb一致便可。json
注意:因爲時間的問題,咱們本文只介紹「cmdb主機標識更新」觸發的jumpserver資產分組同步。vim
咱們在gateway網關中,增長了jumpserver模塊用於實現資產分組同步。api
D:\work\blueking>tree gateway /F
D:\WORK\BLUEKING\GATEWAY
│ .gitignore
│ README.md
│
├─.vscode
│ settings.json
│
└─gateway
│ manage.py
│
├─.vscode
│ settings.json
│
├─gateway
│ asgi.py
│ settings.py
│ urls.py
│ wsgi.py
│ __init__.py
│
└─gw_cmdb
│ admin.py
│ apps.py
│ models.py
│ tests.py
│ urls.py
│ views.py
│ __init__.py
│
├─common
│ hostidentifier_cmdb.py
│ main.py
│ module_cmdb.py
│ select_cmdb.py
│
├─jumpserver
│ api.py
│ main.py
│
└─zabbix
group.py
host.py
main.py
template.py
複製代碼
其中:markdown
jumpserver目錄是與jumpserver相關的模塊:app
因爲分組同步能夠在不影響zabbix使用的狀況下操做,所以咱們在此着重介紹此功能。
cmdb事件推送將參數發送給網關,由views.py接收,json格式數據爲:
其中:
from django.http import HttpResponse
from .common.main import main
from .zabbix.main import zabbix_main
from .jumpserver.main import jumpserver_main
import json
import logging
logger = logging.getLogger('log')
# Create your views here
def cmdb_request(request):
if request.method == 'POST':
data = json.loads(request.body)
logger.info('cmdb發送消息:{}'.format(data))
## 整理cmdb數據
res=main(data)
##是否須要聯動zabbix及jumpserver
if res['result'] == 1:
return HttpResponse("ok")
else:
logger.info(res)
#zabbix同步
zabbix_request = zabbix_main(res)
logger.info('zabbix 同步完畢:{}'.format(zabbix_request))
#jumpserver同步
jumpserver_request = jumpserver_main(res)
logger.info('jumpserver 同步完畢:{}'.format(jumpserver_request))
return HttpResponse("ok")
else:
logger.info('本接口只支持POST模式')
return HttpResponse("本接口只支持POST模式")
複製代碼
vim common/main.py
import logging
from .hostidentifier_cmdb import hostidentifier
from .module_cmdb import module_action
logger = logging.getLogger('log')
def main(data):
result = {'result': 1,'data': 0}
## 模塊操做
if data['obj_type'] == 'module':
return module_action(data)
## 主機標識操做
elif data['obj_type'] == 'hostidentifier':
if data['action'] == 'update' and data['event_type'] == 'relation' :
logger.info("主機標識更新: {}".format(data))
return hostidentifier(data)
else:
logger.info("主機標識未知操做: {}".format(data))
else:
logger.info("未知操做: {}".format(data))
return result
複製代碼
cmdb主機模塊轉移可能會觸發屢次請求,所以咱們須要藉助redis將請求進行去重。
import redis
import json
import hashlib
import logging
logger = logging.getLogger('log')
r = redis.StrictRedis(host='127.0.0.1',port=6379,db=1)
## 模塊變動獲取主機全部模板定製分組
def hostidentifier(data):
##定義數據格式
datajson= {'tex_id': '','action': data['action'],'obj_type': data['obj_type'],'data': {'cur_data': {'ip': '','group': []},'bk_host_id':data['data']['cur_data']['bk_host_id'],'pre_data': 'None'},'result': 1}
## 獲取主機組信息,並清理記錄reids去除重複會話
for i in data['data']:
datajson['data']['cur_data']['ip'] = i['cur_data']['bk_host_innerip']
grouplist = i['cur_data']['associations']
for j in grouplist:
groupname = grouplist[j]['bk_biz_name']+"_"+grouplist[j]['bk_set_name']+"_"+grouplist[j]['bk_module_name']
datajson['data']['cur_data']['group'].append(groupname)
datajson['tex_id']= hashlib.md5((data['request_id']+ i['cur_data']['bk_host_innerip']).encode('utf-8')).hexdigest()
rkey = r.hget('cmdb',datajson['tex_id'])
logger.info(rkey)
if rkey is None:
r.hset('cmdb',datajson['tex_id'],json.dumps(datajson['data']))
datajson['result'] = 0
logger.info(datajson)
return datajson
複製代碼
import logging
from django.conf import settings
from urllib import request
import json
from .api import Assets
logger = logging.getLogger('log')
def jumpserver_main(data):
""" jumpserver api入口函數,只對主機標識更新響應 """
if data['obj_type'] == 'hostidentifier':
if data['action'] == 'update':
cur_data = data['data']['cur_data']
assets = Assets(cur_data)
assets.perform()
else:
logger.info("主機標識未知操做: {}".format(data))
else:
logger.info("未知操做: {}".format(data))
return data
複製代碼
import logging
from django.conf import settings
import json
import uuid
import requests
logger = logging.getLogger('log')
class HTTP:
server = settings.JUMPSERVER_BASEURL
@classmethod
def get(cls, url, params=None, **kwargs):
url = cls.server + url
headers = settings.JUMPSERVER_HEADERS
kwargs['headers'] = headers
res = requests.get(url, params, **kwargs)
return res
@classmethod
def post(cls, url, data=None, json=None, **kwargs):
url = cls.server + url
headers = settings.JUMPSERVER_HEADERS
kwargs['headers'] = headers
res = requests.post(url, data, json, **kwargs)
return res
@classmethod
def put(cls, url, data=None, **kwargs):
url = cls.server + url
headers = settings.JUMPSERVER_HEADERS
kwargs['headers'] = headers
res = requests.put(url, data, **kwargs)
return res
class Node(object):
def __init__(self, *args):
self.id = ''
self.name = None
self.group = args
self.full_value = "/Default"
def exist(self):
url = '/api/v1/assets/nodes/'
logger.info('group Is {}'.format(self.group))
for item in self.group[0].split('_'):
self.name = item
params = {'value': self.name}
res = HTTP.get(url, params=params)
res_data = res.json()
if res.status_code in [200, 201] and res_data:
self.id = res_data[0].get('id')
self.full_value = res_data[0].get('full_value')
logger.info('節點已存在 {}'.format(self.full_value))
else:
self.create()
return self.id
def create(self):
url = '/api/v1/assets/nodes/' + str(self.id) + '/children/'
data = {
'id': str(uuid.uuid1()),
'value': self.name,
'full_value': self.full_value
}
if self.full_value == "/Default":
url = '/api/v1/assets/nodes/'
logger.info('url Is {}'.format(url))
logger.info('data Is {}'.format(data))
res = HTTP.post(url, json=data)
res_data = res.json()
if res.status_code in [200, 201] and res_data:
self.id = res_data.get('id')
self.full_value = res_data.get('full_value')
logger.info('節點建立成功: {}'.format(res_data))
else:
logger.info('節點建立失敗:{}'.format(res_data))
return self.id
def delete(self):
pass
def perform(self):
self.exist()
return self.id
class Assets(object):
def __init__(self, *args):
self.id = None
self.node = None
self.nodeid = []
self.hostname = None
self.platform = None
self.ip = args[0].get('ip')
self.group = args[0].get('group')
def exist(self):
url = '/api/v1/assets/assets/'
params = {
'ip': self.ip
}
res = HTTP.get(url, params)
res_data = res.json()
if res.status_code in [200, 201] and res_data:
self.id = res_data[0].get('id')
self.hostname = res_data[0].get('hostname')
self.platform = res_data[0].get('platform')
logger.info('資產查詢成功: {}'.format(res_data))
self.update()
else:
self.create()
def create(self):
pass
def update(self):
url = "/api/v1/assets/assets/" + self.id + "/"
params = {
'hostname': self.hostname,
'ip': self.ip,
'platform': self.platform,
'nodes': self.nodeid
}
res = HTTP.put(url, json.dumps(params))
res_data = res.json()
if res.status_code in [200, 201] and res_data:
self.id = res_data.get('id')
logger.info('資產更新成功: {}'.format(res_data))
else:
logger.info('資產更新失敗:{}'.format(res_data))
def perform(self):
for group in self.group:
self.node = Node(group)
self.nodeid.append(self.node.perform())
self.exist()
logger.info('nodeid Is {}'.format(self.nodeid))
複製代碼
經過事件推送網關咱們初步實現了cmdb和jumpserver的分組同步,咱們只須要在cmdb一側就能夠管理主機資源,不只節省了咱們跨平臺處理的時間,並且規範了咱們基礎設施的管理。