cmdb事件推送實現jumpserver資產分組同步

前言

《cmdb事件推送實現zabbix資產同步》一文實現了cmdb和zabbix的資產同步,接下來咱們就離着《運維思索:cmdb打通zabbix、jumpserver探索》這個小目標就不遠了。node

言歸正傳,jumpserver的資產分組同步,即jumpserver的資產列表與cmdb的業務拓撲保持一致,按照業務–集羣–模塊的樹形結構分佈。python

16.png

而cmdb和jumpserver的同步思路與前面基本保持一致,即:git

  1. 主機標識更新

只有當主機轉移至相關模塊時,纔會觸發業務、集羣、模塊(例如分別對應消金生產環境–運維平臺–禪道)的節點建立;而在cmdb側只建立空的集羣、模塊時不會觸發jumpserver同步,以避免致使建立空節點。redis

  1. 集羣、模塊刪除操做

cmdb只有在集羣和模塊下資產都爲空的狀況才能執行刪除,這個策略和jumpserver一致,所以在主機標識更新保證資產粒度級別的分組一致後,刪除操做就不是問題了。django

  1. 主機導入

《騰訊藍鯨實現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

  • common目錄是與cmdb相關的模塊:
  • main 接收事件推送網關推送過來的參數;
  • hostidentifier_cmdb 針對主機相關事件推送返回格式化參數;
  • module_cmdb 針對模塊相關事件推送返回格式化參數;
  • select_cmdb 查詢cmdb內容如集羣、業務、操做系統等輔助信息;

jumpserver目錄是與jumpserver相關的模塊:app

  • main 解析格式化參數,對jumpserver作相應的處理;
  • api是對按官方jumpserver api進行的從新封裝,實現對節點、資產等的操做;

因爲分組同步能夠在不影響zabbix使用的狀況下操做,所以咱們在此着重介紹此功能。

分組同步

1.接收cmdb推送參數

cmdb事件推送將參數發送給網關,由views.py接收,json格式數據爲:

17.png

其中:

  • obj_type,主機標識更新:hostidentifier
  • action, 主機動做:update
  • bk_biz_name ,業務名稱:消金生產環境
  • bk_set_name,集羣名稱:運維平臺
  • bk_module_name,模塊名稱:禪道
  • bk_host_innerip,主機ip:10.166.202.10
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模式")

複製代碼

2.解析參數

(1)common將views接收的請求

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
複製代碼

(2)主機標識解析

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

複製代碼

3.jumpserver操做

(1)jumpserver操做入口

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
複製代碼

(2)jumpserver api操做

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))
複製代碼

4.操做

(1)cmdb側主機轉移模塊

18.png

(2)解析過程

19.png

(3)最終效果

20.png

總結

經過事件推送網關咱們初步實現了cmdb和jumpserver的分組同步,咱們只須要在cmdb一側就能夠管理主機資源,不只節省了咱們跨平臺處理的時間,並且規範了咱們基礎設施的管理。

相關文章
相關標籤/搜索