ESB使用指南

导出PDF

ESB介绍

蓝鲸组件系统是蓝鲸体系的服务总线,简称 ESB;主要功能是集成各个系统,以统一的方式(REST API)为蓝鲸平台上的应用提供接口服务。

ESB提供了统一的用户认证蓝鲸应用鉴权请求转发日志记录等功能,不仅降低了接口的维护成本,而且方便开发者使用。

名词解释

系统

系统主要用于对组件进行分类,在 ESB 中,每一个组件只能属于一个组件系统;系统的名称是系统的唯一标识,主要由字母和数字组成。

注:系统 CC、JOB、AUTH、BK_LOGIN 为默认系统,注册系统时,不能使用

通道和组件模块

ESB 通过组合通道和组件模块来为用户提供接口服务:

  • 1)通道

  • 负责用户认证、应用认证、请求日志记录

  • 2)组件模块

  • 负责参数验证、请求转发、响应处理

  • 通道与组件模块的对应关系,可以在 通道管理 中进行管理。

  • 在通道管理页面,管理员为某个通道设置对应组件模块时,需要填写组件模块的 组件代号。组件代号由 ESB 为组件模块自动生成,规则如下:

  • 1)组件代号由三部分组成:前缀.系统名.模块名

  • 2)前缀目前固定为 generic

  • 3)系统名和模块名均为小写,原名中的大写字母前会被添加下划线,如 GetHostList 会变成 get_host_list

  • 根据上述规则,系统 CMDB 的 get_host_list 组件的代号为:generic.cmdb.get_host_list

自助接入组件

自助接入组件,是用户通过 自助接入 功能,注册的组件。

通过自助接入的方式,用户不需要开发组件模块代码,仅通过配置即可将自己的接口接入 ESB,自助接入的组件,

同样会进行用户认证和 APP 应用认证,以减少接口开发者的负担。

组件开发

组件开发,是通过开发组件模块代码,注册通道,提供组件服务。以如下接口为例,详细介绍如何开发新组件。

注:适用于需要编码具体业务逻辑的组件

  • 1)系统名称:主机配置平台 HCP

  • 2)接口名称:查询主机列表 get_host_list

  • 3)接口地址:http://hcp.domain.com/hcp/get_host_list/

添加系统

添加一个新的系统 ,系统信息中填入以下内容:

  • 1)系统名称:HCP

  • 2)系统标签:主机配置平台

创建系统及组件文件

在 ESB 项目的 components/generic/apis/ 下,按照下面结构创建目录及文件(模版下载):

components/generic/apis/
|
|-- hcp
|   |-- __init__.py
|   |-- toolkit
|   |   |-- __init__.py
|   |   |-- configs.py
|   |   |-- tools.py
|   |-- get_host_list.py
  • 1)hcp 为系统包,包名为系统名称小写

  • 2)hcp/toolkit 为系统工具包,存储系统配置及共用方法

  • 3)hcp/toolkit/configs.py 为系统配置模块,配置系统名称、系统域名地址等

  • 4)hcp/toolkit/tools.py 为系统共用方法模块

  • 5)hcp/get_host_list.py 为”查询主机列表”组件模块

组件配置中添加系统信息

在 components/generic/apis/hcp/toolkit/configs.py 中添加系统配置,样例如下:

# -*- coding: utf-8 -*-
from esb.utils import SmartHost


# 系统名的小写形式要与系统包名保持一致
SYSTEM_NAME = 'HCP'

host = SmartHost(
    # 需要填入系统正式环境的域名地址
    host_prod='hcp.domain.com',
)

开发组件模块

在 components/generic/apis/hcp/get_host_list.py 中添加组件代码,样例如下:

# -*- coding: utf-8 -*-
import json

from django import forms

from common.forms import BaseComponentForm
from components.component import Component
from .toolkit import configs


class GetHostList(Component):
    """
    @api {get} /api/c/compapi/hcp/get_host_list/ get_host_list
    @apiName get_host_list
    @apiGroup API-HCP
    @apiVersion 1.0.0
    @apiDescription 查询主机列表

    @apiParam {string} app_code app标识
    @apiParam {string} app_secret app密钥
    @apiParam {string} bk_token 当前用户登录态

    @apiParam {int} app_id 业务ID
    @apiParam {array} [ip_list] 主机IP地址,包含 ip 和 plat_id;其中,plat_id表示子网ID

    @apiParamExample {json} Request-Example:
        {
            "app_code": "esb_test",
            "app_secret": "xxx",
            "bk_token": "xxx-xxx-xxx-xxx-xxx",
            "app_id": 1,
            "ip_list": [
                {
                    "ip": "127.0.0.1",
                    "plat_id": 1,
                },
                {
                    "ip": "127.0.0.2"
                    "plat_id": 1,
                }
            ]
        }
    @apiSuccessExample {json} Success-Response
        HTTP/1.1 200 OK
        {
            "result": true,
            "code": "00",
            "message": "",
            "data": [
                {
                    "inner_ip": "127.0.0.1",
                    "plat_id": 1,
                    "host_name": "db-1",
                    "maintainer": "admin",
                },
                {
                    "inner_ip": "127.0.0.2",
                    "plat_id": 1,
                    "host_name": "db-2",
                    "maintainer": "admin",
                }
            ],
        }
    """

    # 组件所属系统的系统名
    sys_name = configs.SYSTEM_NAME

    # Form处理参数校验
    class Form(BaseComponentForm):
        app_id = forms.CharField(label=u'业务ID', required=True)

        # clean方法返回的数据可通过组件的form_data属性获取
        def clean(self):
            data = self.cleaned_data
            return {
                'ApplicatioNID': data['app_id'],
            }

    # 组件处理入口
    def handle(self):
        # 获取Form clean处理后的数据
        data = self.form_data

        # 设置当前操作者
        data['operator'] = self.current_user.username

        # 请求系统接口
        response = self.outgoing.http_client.post(
            host=configs.host,
            path='/hcp/get_host_list/',
            data=json.dumps(data),
        )

        # 对结果进行解析
        code = str(response['code'])
        if code == '0':
            result = {
                'result': True,
                'data': response['data'],
            }
        else:
            result = {
                'result': False,
                'message': result['extmsg']
            }

        # 设置组件返回结果,payload为组件实际返回结果
        self.response.payload = result

注意:

  • 1)组件类名,为组件模块名去掉下划线(_),并转为驼峰形式,如 get_host_list 组件类名应为 GetHostList

  • 2)组件开头部分为组件文档,通过下面指令可更新文档,组件使用的文档生成工具

# proj_base_dir 默认为安装open_paas时的项目根路径: /data/paas/open_paas/
cd $proj_base_dir/src
# `-c`指定配置文件的路径 `-o`指定输出到的路径
apidoc -c paas/static/doc/ -o paas/static/doc/

注册组件通道

组件模块开发完成后,注册组件通道 ,通道信息中填入内容如下:

  • 1)通道名称:[HCP] 查询服务列表

  • 2)通道路径:/hcp/get_host_list/

  • 3)所属组件系统:选择 HCP 系统

  • 4)对应组件代号:generic.hcp.get_host_list

重启服务

组件添加完成后,重启 ESB 服务,重启步骤如下:

# proj_base_dir 默认为安装open_paas时的项目根路径: /data/paas/open_paas/
cd $proj_base_dir
./bin/dashboard.sh restart esb

新组件的访问地址为:

http://xxx.domain.com/api/c/compapi/hcp/get_host_list/

组件自助接入

如果希望不编写代码,直接将接口接入ESB,可通过自助接入组件实现。

自助接入组件,通过配置接口信息的方式,实现对接口的访问。以如下接口为例,详细介绍如何完成组件自助接入。

注:适用于无需编码具体业务逻辑并且支持 HTTP 协议的组件

  • 1)系统名称:主机配置平台 HCP

  • 2)接口名称:查询主机列表 get_host_list

  • 3)接口地址:http://hcp.domain.com/hcp/get_host_list/

添加系统

添加一个新的系统,系统信息中填入以下内容:

  • 1)系统名称:HCP

  • 2)系统标签:主机配置平台

自助接入新组件

打开 自助接入组件页面,填写接口配置信息,配置信息包含三部分内容:注册配置请求发出前请求目的地

1)注册配置

  • 注册配置用于配置新组件的信息,可指定用户访问新组件的信息,及新组件自身配置。样例组件注册配置中填入以下内容:

      A.组件名称:查询主机列表
    	
      B.所属组件系统:选择 HCP 系统
    	
      C.注册到的请求类型:GET
    	
      D.注册到的组件路径:/hcp/get_host_list/
    
  • 通过”注册到的组件路径”,加上统一前缀,即是新组件的接口地址:

      http://xxx.domain.com/api/c/self-service-api/hcp/get_host_list/
    

2)请求发出前

  • 请求发出前用于配置新组件访问系统接口时的请求头信息。样例组件请求发出前不需要配置。

3)请求目的地

  • 请求目的地用于配置请求系统接口的信息,如系统接口的地址,请求方式,参数设置等。样例组件请求目的地配置中填入以下内容:

      A.目标接口地址:`http://hcp.domain.com/hcp/get_host_list/`
    	
      B.目标接口请求类型:POST
    	
      C.编码POST参数方式:json `目标接口请求方式为 POST 时,才需要指定`
    

新组件访问信息

通过上面的配置,即可接入新的组件,访问新组件同样会进行应用和用户的认证。新组件的访问地址为:

http://xxx.domain.com/api/c/self-service-api/hcp/get_host_list/

CMSI消息组件

当前,ESB 提供的消息通知通道有:

  • 1)公共语音通知: /cmsi/noc_notice/

  • 2)发送邮件: /cmsi/send_mail/

  • 3)发送企业微信: /cmsi/send_qy_weixin/

  • 4)发送短信: /cmsi/send_sms/

ESB 定义了这些消息通知组件的接口协议,给出了组件样例(参考 ESB 项目下的 components/generic/apis/cmsi/),但是,并没有完全实现组件内容,用户可根据接口协议,重写此部分组件。ESB 为降低实现消息通知组件的难度,提供了在线更新组件配置,不需编写组件代码的方案。

方案一

用户提供兼容消息通知组件接口协议的接口,然后,通过以下步骤配置到组件,ESB 会将请求转发到此接口。

  • 1)在通道管理中找到对应的组件通道,打开编辑页面

  • 2)在组件配置下,将接口地址配置到变量 dest_url 下

注意:

1. noc_notice 组件,若 receiver__username 参数有效,将会根据平台用户数据,生成参数 user_list_information
2. send_mail 组件,若 receiver__username,cc__username 参数有效,将会根据平台用户数据,分别生成参数 receiver, cc
3. send_sms 组件,若 receiver__username 参数有效,将会根据平台用户数据,生成参数 receiver
4. send_mail 组件配置中,变量 mail_sender 表示默认的邮件发送者

方案二

用户提供 SMTP 邮件服务地址和帐号,然后,通过以下步骤配置到发送邮件组件,支持通过 SMTP 发送邮件。

  • 1)在通道管理中找到 /cmsi/send_mail/ 组件通道,打开编辑页面

  • 2)在组件配置下,将 SMTP 协议信息配置到变量 smtp_host, smtp_port, smtp_user, smtp_pwd 下

组件调用说明

请求组件时,需提供 APP 应用认证信息和用户认证信息,用以组件对 APP 应用和当前用户进行认证。

APP应用认证

使用组件前,需先根据已有应用创建一个应用,获取应用ID 和应用TOKEN,作为应用认证信息。

  • 1)应用ID: 应用唯一标识,创建应用时由创建者指定,可在应用基本信息中通过APP_ID获取

  • 2)应用TOKEN: 应用密钥,创建应用后由平台生成,可在应用基本信息中通过APP_TOKEN获取

用户认证

用户认证,通过验证用户登录态实现。用户登录态 bk_token,在用户登录后,存储在浏览器的 Cookies 中。

调用组件时,若无法提供用户登录态,可将应用ID 添加到应用免登录态验证白名单中,则此应用请求组件时,提供当前用户的 username 即可。

  • 1)functioncontroller: 通用白名单管理,通过指定不同的功能code,维护不同的白名单

  • 2)user_auth::skip_user_auth: “应用免登录态验证白名单” 功能code,添加此功能code,然后将应用ID 添加到”功能测试白名单”中

组件调用

调用组件主要有两种方式,一种是使用APP开发框架中提供的组件包,一种是根据组件地址直接访问。

1)利用 APP 开发框架中的组件包访问组件

  • 使用组件包访问组件有两种方式,shortcuts 或 ComponentClient。使用示例如下:

A.shortcuts – get_client_by_request


    from blueking.component.shortcuts import get_client_by_request
    # 默认从django settings中获取APP认证信息:应用ID和应用TOKEN
    # 默认从django request中获取用户登录态bk_token
    client = get_client_by_request(request)
    # 组件参数
    kwargs = {'app_id': 1}
    result = client.cc.get_app_host_list(kwargs)

B.shortcuts – get_client_by_user

    from blueking.component.shortcuts import get_client_by_user
    # 默认从django settings中获取APP认证信息:应用ID和应用TOKEN
    # 默认从user中获取username,user为User对象或直接为User中username数据
    user = 'username'
    client = get_client_by_user(user)
    # 组件参数
    kwargs = {'app_id': 1}
    result = client.cc.get_app_host_list(kwargs)

C.ComponentClient

     from blueking.component.client import ComponentClient
     # APP应用ID
     app_code = 'xxx' 
     # APP应用TOKEN
     app_secret = 'xxx-xxx-xxx-xxx-xxx' 
     # 用户登录态信息
     common_args = {'bk_token': 'xxx'}
     # APP应用ID和APP应用TOKEN如未提供,默认从django settings中获取
     client = ComponentClient(
         app_code=app_code, 
         app_secret=app_secret, 
         common_args=common_args
     )
     # 组件参数
     kwargs = {'app_id': 1}
     result = client.cc.get_app_host_list(kwargs)

2)APP 开发框架中的组件包

  • 组件包默认包含系统提供的所有组件;

  • 用户开发的组件及自助接入的组件,可以通过以下步骤添加到组件包:

A.在 APP 开发框架 blueking/component/apis 目录下,创建组件包文件,如系统名称为 agent,可创建组件包文件 agent.py

B.包文件中添加组件信息,如 agent.py 中添加组件 create_task 的访问入口

# -*- coding: utf-8 -*-
from ..base import ComponentAPI


# 系统组件集合类的名称,一般为 Collections + 系统名
class CollectionsAGENT(object):

    def __init__(self, client):
        self.client = client

        # create_task为组件名,method为请求组件使用的方法,path为组件路径,组件域名为系统默认域名
        self.create_task = ComponentAPI(
            client=self.client, method='POST', path='/api/c/compapi/agent/create_task/',
            description=u'',
        )

C.在 blueking/component/collections.py 中加入新包信息(若已加入则忽略此步骤)

# 导入新包路径
from .apis.agent import CollectionsAGENT 

AVAILABLE_COLLECTIONS = {
    'cc': CollectionsCC,
    'job': CollectionsJOB,
    'bk_login': CollectionsBkLogin,
    
    # 此处加入新包信息
    'agent': CollectionsAGENT,
}

3)直接访问

请求参数包括:应用信息(app_code + app_secret),用户信息(bk_tokenusername),及组件参数

用 curl 直接访问示例如下:

    curl -d '{"app_code": "xxx", "app_secret": "xxx", "bk_token": "xxx", "app_id": 1}' 'http://domain.com/component_path/'

    curl 'http://domain.com/component_path/?app_code=xxx&app_secret=xxx&bk_token=xxx&app_id=1'   # 数据需urlencode编码

组件模块特性数据

开发新组件时,在组件模块中,可根据组件基类 Component 或公用模块获取一些有用数据,帮助开发。

Component基类中可用数据

1)request: 请求数据,其中常用的属性参考下文描述

2)form_data: 组件模块中自定义Form clean后的数据

3)current_user: 当前用户,通过其属性username获取当前用户的用户名

4)outgoing.http_client: 请求接口Client,可用其请求其他接口,具体参数参考下面描述

1.Component中request的常用属性

  • 1)request_id: 一次请求的唯一 ID ,一个 uuid 字符串

  • 2)app_code: 当前请求的应用 ID

  • 3)kwargs: 当前的请求参数,GET 请求中的 QueryString 数据 或 POST 请求中 Request Body 数据,已转换为 dict

2.Component中outgoing.http_client支持方法

# response_type: json,接口数据是否需要转换为JSON字典,其他不转换
# max_retries: 0, 接口请求异常时,重试次数
# request_encoding: 请求接口参数转码为此种类型
# response_encoding: 接口返回数据转码为此种类型
outgoing.http_client.request(
    method, host, path, params=None, data=None, headers={},
    response_type='json', max_retries=0, response_encoding=None,
    request_encoding=None, verify=False, cert=None,
    timeout=None
)

outgoing.http_client.get # 表示 request('GET', *args, **kwargs)
outgoing.http_client.post # 表示 request('POST', *args, **kwargs)

common.forms模块中自定义Field

  • 1)ListField: 列表 Field,可将逗号,分号、换行、空格分隔的字符串,转换为列表,如可将 “123;456;789” 转换为[“123”, “456”, “789”]

  • 2)TypeCheckField: 类型检测 Field, 通过设置 promise_type 参数,检测数据的类型,若参数类型不符,抛出异常

  • 3)DefaultBooleanField: 默认布尔 Field,布尔数据可通过 default 参数设置默认值

组件内调用其他组件的方式

  • 1)invoke_other 方式,当前用户 current_user 会传递到被调用组件
result = self.invoke_other('generic.auth.get_user', kwargs={'username': 'xxx'})
  • 2)直接调用方式
from esb.components.generic.apis.auth.get_user import GetUser
result = GetUser().invoke(kwargs={'username': 'xxx'})

本文档是否对您有帮助?