preface

CMDB Event Push for Zabbix Asset Synchronization has enabled CMDB and Zabbix asset synchronization, and we are now close to the small goal of Operations Thinking: CMDB getting through Zabbix and JumpServer Quest.

In other words, the list of JumpServer assets is consistent with the CMDB’s business topology, distributed in a business-cluster-module tree.

The CMDB and JumpServer synchronization ideas are basically the same:

  1. Host Id Update

The node creation of services, clusters, and modules (for example, corresponding to the gold-consuming production environment, o&M platform, and Zen Way respectively) is triggered only when the host is transferred to a related module. When only empty clusters and modules are created on the CMDB side, jumpServer synchronization is not triggered to prevent the creation of empty nodes.

  1. Deleting a cluster or module

The CMDB can only perform deletes if both the cluster and module assets are empty, which is consistent with JumpServer’s policy, so deletes are not a problem after the host identity is updated to ensure consistent grouping at the asset granularity level.

  1. The host import

“Tencent Blue Whale realization of vsphere Virtual Machine delivery” article we have achieved through blue Whale standard operation and maintenance of new host in JumpServer creation, automatic registration to the CMDB, on the premise of ensuring the host shelf process, we can think that all hosts in CMDB and jumpServer already exist by default. We just need to make sure that the JumpServer asset grouping is consistent with the CMDB.

Note: Due to time constraints, this article only covers the jumpServer asset group synchronization triggered by the “CMDB host identity update”.

The directory structure

We added the JumpServer module to the gateway for asset group synchronization.

D:\work\blueking>tree gateway /F D:\work\blueking \ gateway │ ├─ vscode Settings. Json │ ├─ vscode Settings ├─ 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 │ vs.py │ ├─common │ │ ├─ ch.pdf Hostidentifier_cmdb.py │ main. Py │ module_cmdb.py │ select_cmdb.py │ ├─ JumpServer │ api.py │ main. Py │ ├─ zabbix group.py  host.py main.py template.pyCopy the code

Among them:

  • The common directory is the module associated with the CMDB:
  • Main Receives the parameters pushed by the event push gateway.
  • Hostidentifier_cmdb Returns formatting parameters for events pushed by the host.
  • Module_cmdb returns formatting parameters for module-related event push;
  • Select_cmdb Queries CMDB content, such as auxiliary information about clusters, services, and operating systems.

The JumpServer directory is the module associated with JumpServer:

  • Main parses the formatting arguments and does the appropriate thing to jumpServer;
  • The API is a reencapsulation of the official JumpServer API to implement operations on nodes, assets, and so on.

Because packet synchronization can operate without affecting zabbix usage, we focus on this feature here.

Group synchronization

1. Receive CMDB push parameters

The CMDB event push sends the parameters to the gateway, which is received by views.py. The data in JSON format is:

Among them:

  • Obj_type, host identification update: hostidentifier
  • Action, host action: update
  • Bk_biz_name, business name: consumer production environment
  • Bk_set_name, cluster name: O&M platform
  • Bk_module_name, module name: Zen way
  • Bk_host_innerip, host 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 sends message: {}'.format(data))
        ## Collate CMDB data
        res=main(data)
        Whether to link Zabbix and JumpServer
        if res['result'] = =1:
            return HttpResponse("ok")
        else:
            logger.info(res)
            # zabbix synchronization
            zabbix_request = zabbix_main(res)
            logger.info('Zabbix synchronization completed :{}'.format(zabbix_request))
            # jumpserver synchronization
            jumpserver_request = jumpserver_main(res)
            logger.info('JumpServer synchronization completed :{}'.format(jumpserver_request))
            return HttpResponse("ok")
    else:
        logger.info('This interface only supports POST mode')
        return HttpResponse("This interface only supports POST mode")

Copy the code

2. Parse parameters

(1) Common will views receive the request

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}
    Module operation
    if data['obj_type'] = ='module':
        return module_action(data)  
    ## Host id operation
    elif data['obj_type'] = ='hostidentifier':
        if data['action'] = ='update' and   data['event_type'] = ='relation' :
            logger.info("Host id update: {}".format(data))
            return hostidentifier(data)
        else:
            logger.info("Host id unknown operation: {}".format(data))
    else:
        logger.info("Unknown operation: {}".format(data))
    return result
Copy the code

(2) Host id resolution

CMDB host module transfer may trigger multiple requests, so we need to use Redis to remove requests.

import redis
import json
import hashlib
import logging

logger = logging.getLogger('log')

r = redis.StrictRedis(host='127.0.0.1',port=6379,db=1)

## Module change To get all template customization groups for the host
def hostidentifier(data) :
    ## Define the data format
    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}
    ## Get host group information and clean up record reIDS to remove repeated sessions
    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

Copy the code

3. Jumpserver operation

(1) JumpServer operation entry


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 entry function that responds only to host identity updates """
    if data['obj_type'] = ='hostidentifier':
        if data['action'] = ='update':
            cur_data = data['data'] ['cur_data']
            assets = Assets(cur_data)
            assets.perform()
            
        else:
            logger.info("Host id unknown operation: {}".format(data))
    else:
        logger.info("Unknown operation: {}".format(data))

    return data
Copy the code

(2) JumpServer API operations

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('Node {} already exists'.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('Node created successfully: {}'.format(res_data))         
        else:
            logger.info('Failed to create node: {}'.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('Asset query succeeded: {}'.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('Asset update successful: {}'.format(res_data))         
        else:
            logger.info('Asset update failed: {}'.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))
Copy the code

4. Operating

(1) Host transfer module in CMDB

(2) Analytical process

(3) The final effect

conclusion

With the event Push Gateway, we initially achieved group synchronization between the CMDB and JumpServer, allowing us to manage host resources only on the CMDB side, saving us cross-platform processing time and standardizing our infrastructure management.