腾讯蓝鲸cmdb二次开发文档

目录

1 本地启动cmdb

2 cmdb数据库表设计

3 代码模块介绍

4 功能介绍

5 请求调用流程

6 新增接口

7 cmdb如何操作mongo数据库

一  本地启动cmdb

 服务器启动回顾

部署cmdb的时候,输入./start.sh 就可以启动12个服务,那么针对这12个服务进行分析一下。首先看一下启动后输出的内容:

image.png

这里的配置参数,是根据运行的配置脚本所生成的,如:

image.png

生成配置文件位置:

configcenter/src/bin/build/3.2.17/cmdb_adminserver/configures/*

二  打开cmdb项目,把上一步cmdb_adminserver/configures/下生成的所有配置文件覆盖到configcenter/resources/configures/目录中 (即替换配置文件)。

然后修改configcenter/resources/configures/migrate.conf文件 

image.png

三、本地启动项目


cmdb是微服务框架,把平台拆分成了12个服务,本次我们启动hostServer服务,其他服务启动类似。

启动hostServer的main方法(host.go文件):

image.png

启动的的时候配置参数:Program arguments

例如:

–addrport=127.0.0.1:60001 –logtostderr=false –log-dir=./logs –v=3 –regdiscv=127.0.0.1:2181

每个服务启动时 Program arguments 参数不同 可参考服务启动时显示的参数进行配置

image.png

二 cmdb数据库表设计

表名关联业务接口备注
cc_ApplicationBase基础资源-业务信息存储  
cc_AsstDes模型管理-关联类型数据存储  
cc_History  
cc_HostBase基础资源-主机数据存储  
cc_HostFavourite  
cc_idgenerator生成ID的,记录每种记录最大的ID,类似mysql 主键的auto_increment  
cc_InsAsst  
cc_ModuleBase业务资源-业务拓扑中的叶子节点数据  
cc_ModuleHostConfig主机分配到具体业务模块表,bk_module_id是cc_ModuleBase.bk_module_id  
cc_Netcollect_Device  
cc_Netcollect_Property  
cc_ObjAsst模型与模型之间的关联关系,见模型管理-模型拓扑  
cc_ObjAttDes模型的所有字段  
cc_ObjClassification存储模型分组数据,针对模型管理-新建分组业务  
cc_ObjDes存储模型数据,针对模型管理-模型-新建模型业务  
cc_ObjectBase自定义模型的实例  
cc_ObjectUnique  
cc_UserGroupPrivilege当添加用户权限的时候,
表里面才显示数据
 通过group_id字段关联
cc_UserGroup添加用户权限管理  
cc_UserCustom用户自定义收藏模块 index_v4_recently
存储最近添加唯一标识

cc_UserAPI
  
cc_TopoGraphics存储模块在拓扑图中的位置
 用户删除位置,数据表还是保留当前字段,位置置空
  

cc_System
系统  
cc_Subscription事件推送  
cc_SetBase业务资源-> 业务拓扑  
cc_PropertyGroup   
cc_Process业务资源-> 进程管理 存储进程 bk_biz_id 对应 cc_ApplicationBase

表中的bk_biz_id
cc_ProcOpTask  
cc_ProcInstanceModel  
cc_ProcInstanceDetail  

cc_Proc2Module
  
cc_Privilege  
cc_PlatBase  

 三 模块介绍

ui:                            前端代码 

web_server                 后端服务,所有请求入口

api_server :             接口层,这一层是系统的api服务网关 

scene_server/         业务场景模块,基于资源管理对应用场景的封装

     admin_server     把配置文件放入zk

     event_server      事件订阅

     host_server        主机

     topo_server        模型,实例,业务,模块等

     proc_server        进程  

source_controller   :源管理模块,把资源类型进行了抽象,每一类资源由一类微服务进程来管理

       auditController   审计

       hostController    主机

       objectController 对象

       procController    进程

storage:                  提供系统所需的资源存储等系统服务

apimachinery :      根据要操作的资源生成新的url,调用source_controller

 四、

请求执行过程:

api_server

1  http   —>   api_server(网关)  

2 api_server(网关)   –>  scene_server下的xxServer/service/service.go文件中

scene_server

3  service.go文件接收路由并调用响应的方法A

4  方法A处理逻辑包括验证头信息请求参数,最后调用apimachinery

apimachinery

5 在apimachinery中会生成一个新的URL 并根据这个URL向source_controller发起请求

source_controller

6 source_controller/XXcontroller/service/service.go接收请求 并调用响应方法B

storage

7  B方法调用了storage中的方法

 ——————————————

v3.2.17

蓝鲸CMDB文档

本地启动cmdb

一、服务器启动回顾

部署cmdb的时候,输入./start.sh 就可以启动12个服务,那么针对这12个服务进行分析一下。首先看一下启动后输出的内容:

image.png

这里的配置参数,是根据运行的配置脚本所生成的,如:

image.png

生成配置文件位置:

configcenter/src/bin/build/3.2.17/cmdb_adminserver/configures/*

二  打开cmdb项目,把上一步cmdb_adminserver/configures/下生成的所有配置文件覆盖到configcenter/resources/configures/目录中 (即替换配置文件)。

然后修改configcenter/resources/configures/migrate.conf文件 

image.png

三、本地启动项目


cmdb是微服务框架,把平台拆分成了12个服务,本次我们启动hostServer服务,其他服务启动类似。

启动hostServer的main方法(host.go文件):

image.png

启动的的时候配置参数:Program arguments

例如:

–addrport=127.0.0.1:60001 –logtostderr=false –log-dir=./logs –v=3 –regdiscv=127.0.0.1:2181

每个服务启动时 Program arguments 参数不同 可参考服务启动时显示的参数进行配置

image.png

CMDB数据库表设计

1表功能

表名关联业务接口备注
cc_ApplicationBase基础资源-业务信息存储  
cc_AsstDes模型管理-关联类型数据存储  
cc_History  
cc_HostBase基础资源-主机数据存储  
cc_HostFavourite  
cc_idgenerator生成ID的,记录每种记录最大的ID,类似mysql 主键的auto_increment  
cc_InsAsst  
cc_ModuleBase业务资源-业务拓扑中的叶子节点数据  
cc_ModuleHostConfig主机分配到具体业务模块表,bk_module_id是cc_ModuleBase.bk_module_id  
cc_Netcollect_Device  
cc_Netcollect_Property  
cc_ObjAsst模型与模型之间的关联关系,见模型管理-模型拓扑  
cc_ObjAttDes模型的所有字段  
cc_ObjClassification存储模型分组数据,针对模型管理-新建分组业务  
cc_ObjDes存储模型数据,针对模型管理-模型-新建模型业务  
cc_ObjectBase自定义模型的实例  
cc_ObjectUnique  
cc_UserGroupPrivilege当添加用户权限的时候,
表里面才显示数据
 通过group_id字段关联
cc_UserGroup添加用户权限管理  
cc_UserCustom用户自定义收藏模块 index_v4_recently
存储最近添加唯一标识

cc_UserAPI
  
cc_TopoGraphics存储模块在拓扑图中的位置
 用户删除位置,数据表还是保留当前字段,位置置空
  

cc_System
系统  
cc_Subscription事件推送  
cc_SetBase业务资源-> 业务拓扑  
cc_PropertyGroup   
cc_Process业务资源-> 进程管理 存储进程 bk_biz_id 对应 cc_ApplicationBase

表中的bk_biz_id
cc_ProcOpTask  
cc_ProcInstanceModel  
cc_ProcInstanceDetail  

cc_Proc2Module
  
cc_Privilege  
cc_PlatBase  

2 名词介绍

资源名称:

biz:   业务线

set:集群

module:模块

host:主机

字段描述:

bk_supplier_id :供应商ID  默认为0 ,不做变动

bk_host_id  :     主机id

bk_obj_id.   :     模型id, 模型的唯一标识,如,szone,redis,set,module

关键词:

association 关联类型

object_association模型关联

inst_association     实例关联

privilege              权限

inst                      模型实例

object                 对象:如 module,set等

classification      模型分类

custom_query:userapi  自定义api

favorites            主机收藏

模块介绍

ui:                            前端代码 

web_server                 后端服务,所有请求入口

api_server :             接口层,这一层是系统的api服务网关 

scene_server/         业务场景模块,基于资源管理对应用场景的封装

     admin_server     把配置文件放入zk

     event_server      事件订阅

     host_server        主机

     topo_server        模型,实例,业务,模块等

     proc_server        进程  

source_controller   :源管理模块,把资源类型进行了抽象,每一类资源由一类微服务进程来管理

       auditController   审计

       hostController    主机

       objectController 对象

       procController    进程

storage:                  提供系统所需的资源存储等系统服务

apimachinery :      根据要操作的资源生成新的url,调用source_controller

功能介绍

1 常用方法

法/文件作用位置详细位置
FindSingleObject(bk_obj_id)查找是否存在此模型Topo_servertopo_server  /core/operation/object.go
condition.CreateCondition()创建一个结构体存储查询条件common/condition/condition.go 
dbInst :=   logic.Instance.       Table(tName).        Find(condition).            Sort(sort).              Start(uint64(skip)).                  Limit(uint64(limit))将查询条件赋值给结构体赋值解析:logic   是一个结构体,Instance是结构体中的一个字段Instance同时还是一个接口,Table是其中一个实现方法Table()的返回值是CollectionCollection是一个结构体,挂在其结体下的方法有findSort,Start,Limit返回值是 Find这个结构体src/source_controller/hostcontroller/logics/object.go GetObjectByCondition()方法
dbInst.All() 即Find.All()dbInst.One() 即Find.One()查询数据库解析:one() 和All()这两个方法都挂在Find结构体下,而在上一行中已经将查询条件赋值给Find,所以当调用All方法时,可直接从Find中取值进行查询尽行查询例如:f.dbc.DB(f.dbname).C(f.collName).Find(f.filter).One(result)src/storage/dal/mongo/mgo_mongo.go 

2 UI:

前端 VUE:

cmdb vue组件库:https://magicbox.bk.tencent.com/components_vue/2.0/example/index.html#/

前端vue 代码规范使用 Eslint插件,如不按照规范编写则编译报错:

部分规则如下:

不要有多个连续空行。

关键字后面要有一个空格,

函数参数列表括号前面要有一个空格。

始终使用 === 不使用 ==,

逗号后面有一个空格。

else 与它的大括号同行

始终处理函数的 err 参数

浏览器全局变量始终添加前缀 window.

var 声明,每个声明占一行

无多余逗号

逗号必须放在当前行的末尾

. 应当与属性同行

文件以空行结尾

键名和键值之间要有空格

构造函数的名字以大写字母开始

…..等等

若要关闭Eslint验证:

src/ui/build/webpack.base.conf.js 文件中 注释掉eslint

image.png

前端请求示例:

请求调用流程:getHostList()——>search()—> getHostList()  ———>searchHost()   
方法位置ui/src/views/resource/index.vue ui/src/components/hosts/table/index.vueui/src/store/modules/api/host-search.js   
功能页面:获取所有主机调用子组件中的方法接收参数 ,发送http请求   

文件介绍

位置作用    
src/ui/src/componentsVue组件,方便复用    
ui/src/store/modules/api/*封装URL,接收参数,向后台发请求    
      
      
src/ui/src/views /*所有页面    
ui/src/views/index/index.vue首页    
ui/src/views/business/index.vue基础资源/业务    
ui/src/views/resource/index.vue基础资源/主机    
ui/src/views/hosts/index.vue业务资源/主机    
ui/src/views/eventpush/index.vue模型管理/事件推送    
ui/src/views/topology/index.vue业务资源/业务拓扑    
ui/src/views/custom-query/index.vue 业务资源/动态分组    
ui/src/views/process/index.vue业务资源/进程管理    
ui/src/views/audit/index.vue审计与分析/操作审计    
ui/src/views/model-association/index.vue模型管理/关联模型    
ui/src/views/model-manage/index.vue模型管理/模型    
ui/src/views/model-topology/index.vue模型管理/模型拓扑    
ui/src/views/business-model/index.vue模型管理/业务模型    
      
      
      

3 web_server

文件作用    
src/web_server/service/service.go接收所有请求    
src/web_server/middleware/login.go中间件:判断请求是否已经登陆,以及是否需要转发到api_server    
      

4 api_server:网关,对请求分类,转发进入sence_server

文件作用    
api_server/service/v3/uri.go对请求进行分类:topo,host,event,proc    
api_server/service/v3/service.go根据请求类别,对请求进行转发    
      

5 sence_server:业务处理,调用apimachinery 向资源层发起请求

文件做用隶属接口       
XX__server/service/service.go接收路由请求,请求入口        
XX__server/service/*请求响应方法        
topo_server/service/*对set,module,biz,privite相关请求进行响应        
topo_server/service/inst_module.gotopo_server/service/inst_set.gotopo_server/service/inst_business 对模块,集群,业务初步逻辑处理        
topo_server/core/operation/inst_module.go对modul进一步逻辑处理ModuleOperationInterface       
topo_server/core/operation/inst.go对逻辑处理结束的对象,向下级服务发起crud请求:module,set,biz,自定义模型,等对象        
topo_server/service/privilege.go用户权限相关请求进行响应        
topo_server/core/privilege/privilege.go对用户权限的逻辑处理        

6 apimachinery :向资源层发起请求

文件/方法作用    
apimachinery/objcontroller/inst/inst.go对object的增删改查请求进行处理:module ,set,biz,自定义对象 等    
apimachinery/objcontroller/privilege/api.go权限,角色相关接口    
apimachinery/objcontroller/privilege/privilege.go权限,角色,相关接口实现方法    

7 controller :对资源(数据库)进行操作

操作方式:

在每个微服务下通常有三个文件夹 :app,service,logics

image.png

Service文件夹: 下主要是请求入口,已及请求的响应方法,进行逻辑处理,然后调用logics文件夹下的方法

Logics文件夹:  下通常有一个都有一个logics.go文件,logics.go文件中都有一个结构体Logics 如:

                type Logics struct{

                    Instance dal.RDB

                   } 

              Logics文件夹中的所有方法都挂在结构体Logics下,如 func (lgc *Logics) DelModule(); 

       Logics结构体中的Instance 是对数据操作的一些接口如:

        type RDB interface {

                   Clone() RDB

                   // Table collection 操作 

                   Table(collection string) Table

                   // StartTransaction 开启新事务

                  StartTransaction(ctx context.Context) (RDB, error)

                   }

       所以通过结构体Logics,Logics文件夹下的方法可以实现对数据库的操作。

文件作用    
auditcontroller收集和查询 操作记录(审计)    
hostcontroller主机相关操作    
objectcontrollerSet, module,biz,自定义模型等操作    
proccontroller进程相关操作    
source_controller/objectcontroller/service/inst_action.go对实例进行增删改查:module,set,biz等    
source_controller/objectcontroller/service/common.go对数据库操作的通用方法    
objectcontroller/service/*对权限,角色,模型,biz相关接口进行响应    
objectcontroller/service/privilege_action.go对用户组权限进行增删改查    
      
      

8 common

文件     
src/common/*封装了对数据库操作的方法    
src/common/condition封装查询条件,如sort,limit,start,fiels    
src/common/conf读取解析配置文件    
src/common/mapstr将condition的fields字段转换成map    
      

请求调用流程

1 执行流程

HTTP—-  /*  —-web_server

http请求首先进入web_server 在其中会验证登陆等信息

web_server———/api/v3/*——–> api_server 

web_server中/api/v3的请求会被转发到api_server,在api_server中请求被分类,以host资源为例:/api/v3/*   会转换成/host/v3/* 向下一层服务发起请求

api_server—-/host/v3/*——->scene_server—-调用—>apimachinery(类似SDK)

api_server向scene_server发起请求,在scene_server中处理业务逻辑,scene_server调用apimachinery向下一级服务发起请求,在apimachinery中url会根据资源类型作出更改,以更改后的url向资源层发请求

apimachinery ———> source_controller ———调用—— storage

apimachinery向source_controller发起请求,在source_controller中调用storage封装的方法完成对数据库的操作

——————————————————————————————————-

ps:由于api_server只处理url路径是 /api/v3/* 的请求,所以部分请求 url 不是 /api/v3/开头则不会进入api_server,而是进入web_server进行处理。web_server通过调用apimachinery,向source_controller发起请求 来完成对资源的操作。

2  介绍

api_server 将收到的请求处理,分为四类转发进入sence_server下的四个微服务,分别是,topo,host,proc,event 四大类。

例如:/api/v3/biz/…在api_server   中请求会被转成    /topo/v3/biz/…

topo类包括:audit,biz,topo,identifier,inst,module,object,objects,/object/attr,objectatt,set,                        privilege

host类包括:host,hosts,userapi,usercustom,/findmany/modulehost

event类包括:event

proc类包括:proc

3 CMDB API请求示例

ps:每个微服务下都有一个../service/service.go文件作为请求入口

3.1 获取主机基础信息详情

  • API: GET /api/{version}/hosts/{bk_supplier_account}/{bk_host_id}
  • http://localhost:8083/api/v3/hosts/0/77
  • 功能说明:获取77号主机基础信息详情
  • input body: 无

 http请求——–>  api_server

api_server: 在src/api_server/service/v3/service.go 中接收所有跟路径是/api/v3/ 的请求

                    请求变成/host/v3/hosts/0/77 进入下一个服务

api_server ——> scene_server : 

scene_server:    在src/scene_server/host_server/service/service.go   接收所有跟路径是/host/v3 的路由

                           其中/hosts/{bk_supplier_account}/{bk_host_id} 接收到请求 并调用     

                           GetHostInstanceProperties()方法:获取参数,处理参数

                          在 src/apimachinery/hostcontroller/host/api.go文件GetHostByID()方法中 进入下一级服务,                            跳转路径:/host/v3/host/77

 scene_server——-source_controller:

 source_controller:在src/source_controller/hostcontroller/service/service.go文件中接收所有跟路径   

                                为/host/v3的路由,/host/v3/host/{bk_host_id} 接收请求,并调用GetHostByID()方法

                                 最后调用storage,src/storage/dal/mongo/mgo_mongo.go文件中One()方法完成数据库

                               查询 。

3.2 查询业务线

  API: POST /api/{version}/biz/search/{bk_supplier_account}

  参数:{ “condition”: {}}

   condition 参数为业务的任意属性,如果不写代表搜索全部数据

  例:  http://localhost:8083/api/v3/biz/search/0

    apiServer 接收请求并转换成:/topo/v3/app/search/0

    topo_server 接收请求并调用 SearchBusiness方法—— 调用FindBusiness()(实现方法在本 页)—-  FindOriginInst(实现方法在本页)……

                            最后调用在 src/apimachinery/objcontroller/inst/inst.go。SearchObjects方法  

   请求变成: /insts/biz/search

   TopoConroller

   调用SearchInstObjects方法响应,然后调用src/source_controller/objectcontroller/service/common.go        GetObjectByCondition方法

 3.3 查询模型实例

API POST /api/{version}/inst/association/search/owner/{bk_supplier_account}/object/{bk_obj_id}

 参数{

   “condition”:{

        “bk_weblogic”:[

            {

                “field”:”bk_inst_name”,

                “operator”:”$regex”,

                “value”:”qq”

            }

        ]

    }

}

例:http://localhost:8083/api/v3/inst/association/search/owner/0/object/redis

api_server 收到请求转化成 /topo/v3/inst/association/search/owner/0/object/redis进入下一服务

业务场景 :topo_server

     src/scene_server/topo_server/service/service_initfunc.go 接收请求 转到           

     SearchInstByAssociation方法—    FindInstByAssociationInst—-FindInst—-FindOriginInst—    

                      c.clientSet.ObjectController().Instance().SearchObjects()—-

    src/apimachinery/objcontroller/inst/inst.go SearchObjects()生成URL:/insts/object/search 进入   

     下一级服务.

资源管理 :object_controller

     /insts/{obj_type}/search 接收请求 调用响应方法SearchInstObjects()——  GetHostByCondition—all()              

3.4 条件查询主机 

API: POST /api/{version}/hosts/search

参数:可根据根据set 、host、biz、module等模型属性进行查询

{
    "page":{
        "start":0,
        "limit":10,
        "sort":"bk_host_id"
    },
    "pattern":"",
    "bk_biz_id":2,
    "ip":{
        "flag":"bk_host_innerip|bk_host_outerip",
        "exact":1,
        "data":[
        ]
    },
    "condition":[
        {
            "bk_obj_id":"host",
            "fields":[
            ],
            "condition":[
            ]
        },
        {
            "bk_obj_id":"module",
            "fields":[
            ],
            "condition":[
            ]
        },
        {
            "bk_obj_id":"set",
            "fields":[
            ],
            "condition":[
            ]
        },
        {
            "bk_obj_id":"biz",
            "fields":[
            ],
            "condition":[
                {
                    "field":"default",
                    "operator":"$ne",
                    "value":1
                }
            ]
        }
    ]
}

示例:

localhost:8083/api/v3/hosts/search

参数:{}

api_sever 接收请求 (生成url:/host/v3/hosts/search)—->

sence_service(src/scene_server/host_server/service/service.go )——SearchHost()—s.Logics.SearchHost()—-SearchHostByConds()—-sh.searchByHostConds()——-sh.lgc.CoreAPI.HostController().Host().GetHosts:  path=src/apimachinery/hostcontroller/host/api.go

url==/hosts/search

进入 host_controller

src/source_controller/hostcontroller/service/service.go—–GetHosts()–GetObjectByCondition()—all()

3.5 创建模块

POST /api/{version}/module/{bk_biz_id}/{bk_set_id}

input body:

{

    “bk_module_name”:”cc_module”,

    “bk_supplier_account”:”0″,

    “bk_parent_id”:0

}

示例:

localhost:8083/api/v3/module/3/2

参数:{ “bk_module_name”:”devops”}

http  ———> api_server —-  跳入下一服务,URL:/topo/v3/module/3/2

//查询模型类型是否存在

topo_server :/module/{app_id}/{set_id} 接收上一请求——>CreateModule()方法

                        ——-FindSingleObject()//查询 — 跳入下一服务,url:/insts/module/search

object_controller:/insts/{obj_type}/search 接收上一请求——>SearchInstObjects                       

//创建模型

topo_server:    ——ModuleOperation().CreateModule()

object_controller:         /insts/{obj_type}接收请求

3.6 创建集群

API: POST /api/{version}/set/{bk_biz_id}

参数

{

   “bk_set_name”:”wefd”,  集群名字

   “bk_parent_id”:0,          集群上级id 可以是业务线 ,或者其他,具体参照拓扑模型

   “bk_biz_id”:1               业务线

}

示例:localhost:8083/api/v3/set/3

topo_server  /set/{app_id} 接收请求

新增接口流程

1 简介版

查询主机:localhost:8083/api/v3/hosts/selectAll

1  url 设计: 以/api/v3/{type}/….  开头的请求会被web_server转发进入 api_server

2  type 代表资源类型 根据type 类型 被转发进入sence_server

3  在host_server中编写请求 /host/v3/hosts/selectAll的入口,以及响应方法selectAll(),在selectAll()中处理 

    调用资源层完成,业务逻辑的处理

4  selectAll()方法调用src/apimachinery  中的httpclient 向controller发起请求

     所以在src/apimachinery/hostcontroller/host/api.go 中编写方法 ,使用httpClient向host_controller 发起请

    求

    请求的url 设计没有规定 如 subPath := “/hosts/myJob

     则完整请求是 localhost:8083/host/v3/hosts/myJob

5 在hostcontroller中 编写请求    /host/v3/hosts/myJob的 路由入口

6  编写myJob的响应方法 查询数据 返回数据

ps  : 从第4步开始 src/apimachinery  中的httpclient 向controller发起请求 只是纯粹的对资源进行操作,不包含业务逻辑,所以 一般情况下 只需要变动sence_server,无需变动apimachinery 和controller

2 实操版

1  url 设计: 以/api/v3/{type}/….  开头的请求会被web_server转发进入 api_server

2  type 代表资源类型 可以为:

biz,topo,identifier,inst,module,objectset,privilege,host,hosts,userapi,usercustom, event proc等,具体请见src/api_server/service/v3/uri.go 中资源划分

3 新增接口查询主机,假设 url设计为:localhost:8083/api/v3/hosts/selectAll,在api_server中 会根据url中的关键词hosts ,判定要操作的资源是host,所以url  从 /api/v3/hosts/selectAll     变成  /host/v3/hosts/selectAll

4 在host_server中,src/scene_server/host_server/service/service.go 接收所有/host/{version}

的请求

所以在此文件中编写/host/v3/hosts/selectAll请求入口

api.Route(api.POST(“/hosts/selectAll).To(s.SelectAllHost))

—————-

响应方法:

func (s *Service) SelectAllHost(req *restful.Request, resp *restful.Response) {

//获取头信息

pheader := req.Request.Header

// new 出一个结构体 存储查询参数

body := new(meta.HostCommonSearch)

//获取讲请求中的参数 解析赋值到 结构体body中

json.NewDecoder(req.Request.Body).Decode(body)

// 获得头信息pheader 和 传递的参数body后  调用下个方法SearchHost() 进行查询

host, err := s.Logics.SearchHost(pheader, body)

}


Ps: SearchHost()方法挂在结构体Logics下,Logics结构体中有接口可以调用下一个微服务

func (lgc *Logics)SearchHost(phader http.Header,body Body) (*metadata.GetHostsResult, error) {

   //从传入的body中 获取到参数 赋值在 结构体 metadata.QueryInput中

   query := metadata.QueryInput{

      Start:     body.start,

      Limit:     body.limit,

      Sort:      common.BKHostInnerIPField,

      Fields:    common.BKHostInnerIPField,

   }

//  把查询参数query 传给apimacheniry,由apimacheniry 向controller发起请求

  lgc.CoreAPI.HostController().Host().MyjobSpimachinery()

}

编写 MyjobSpimachinery方法:

在src/apimachinery/hostcontroller/host/api.go 中编写 方法 MyjobSpimachinery(),

在MyjobSpimachinery中

         subPath为要跳转的路由入口,可自己设计

         metadata.GetHostsResult返回值类型

         .Do() 进行跳转

         .Into() 把查询结果放进new 出来的结构体,并return

代码如下:

func (t *hostctrl) MyjobSpimachinery(ctx context.Context, h http.Header, opt *metadata.QueryInput) (resp *metadata.GetHostsResult, err error) {
   resp = new(metadata.GetHostsResult)
   subPath := "/hosts/myJob"
   err = t.client.Post().
      WithContext(ctx).
      Body(opt).
      SubResource(subPath).
      WithHeaders(h).
      Do().
      Into(resp)
   return
}

——————————————————————-

5  在src/source_controller/hostcontroller/service/service.go中接收所有请求是/host/v3 的请求

所以在此文件中编写/hosts/myJob 的入口

api.Route(api.POST(“/hosts/myJob”).To(s.MyJob))

响应方法:

func (s *Service) MyJob(req *restful.Request, resp *restful.Response) {

   //获取参数调用数据库进行查询

}

6.

CMDB中对mongo的操作

1、

cmdb对mongo的常规操作进行了一层封装,方便之后的CRUD,在代码中发现最常见的一种查询方式如下:

lgc.Instance.Table(“表名”). Find(map) .All(ctx,&results);

map代表查询条件,通过这行代码完成查询并且把查询结果赋值给results,下面将对这行代码进行解释

观察结构体Logics

type Logics struct {

   Instance dal.RDB

   Cache    *redis.Client

   *backbone.Engine

}

发现Logics下 Instance dal.RDB 是一个interface ,其实现方法 有对db的一些操作  如下

type RDB interface {

   Clone() RDB

   // Table collection 操作

   Table(collection string) Table

   // StartTransaction 开启新事务

   StartTransaction(ctx context.Context) (RDB, error)

   // Commit 提交事务

   Commit(context.Context) error

   // Abort 取消事务

   Abort(context.Context) error

}

其中Table(collection string) Table是一个interface,其实现方法有

type Table interface {

   // Find 查询多个并反序列化到 Result

   Find(filter Filter) Find

   // Aggregate 聚合查询

   AggregateOne(ctx context.Context, pipeline interface{}, result interface{}) error

   AggregateAll(ctx context.Context, pipeline interface{}, result interface{}) error

   // Insert 插入数据, docs 可以为 单个数据 或者 多个数据

   Insert(ctx context.Context, docs interface{}) error

   // Update 更新数据

   Update(ctx context.Context, filter Filter, doc interface{}) error

   // Delete 删除数据

   Delete(ctx context.Context, filter Filter) error

}

观察上面结构体总结如下:

Logics   是一个结构体,Instance是结构体中的一个字段。

即:Logics.Instance

Instance同时还是一个接口,Table是其中一个实现方法。

 即 :Logics.Instance.Table(“表名”)

Table(name String)的返回值是Collection,Collection是一个结构体指定了要操作的表名。

Find(map)方法挂在Collection结构体下,Find方法将Collection 和map(查询条件)放入Find结构对应的字段。 返回Find结构体 。

即: inst :=  Logics.Instance.Table(“表名”).Find(map)

此时inst 是一个指定了查寻条件和 要操作的表名的Find结构体

All()方法 挂在Find结构体下:  

 Logics.Instance.Table(“表名”).Find(map).all(results)

进行最终查询。

在以上的操作中只是为了将各种查询条件放入Find结构中,最终All()方法从Find结构体中取出查询条件进行查询,将结果赋值给results;

All 方法代码如下:

func (f *Find) All(result interface{}) error {

   f.dbc.Refresh()

   query := f.dbc.DB(f.dbname).C(f.collName).Find(f.filter)

   query = query.Select(f.projection)

   query = query.Skip(int(f.start))

   query = query.Limit(int(f.limit))

   query = query.Sort(f.sort…)

    //执行查询,若是查询出错 返回错误信息

   return query.All(result)

}

实操:

1 查询内网ip是121.21.13.14的主机

首先创建一个map存放查询条件

condition:=make(map[string]interface{})

condition[“bk_host_innerip”]=“121.21.13.14”

condition[“bk_host_id”]=“host”

然后定义一个可变的 map数组接收查询结果

results := make([]map[string]interface{}, 0)

最后进行查询

lgc.Instance.

   //指定查询的表

   Table(“cc_HostBase”).

          //查询条件   

             Find(condition)

                 //进行查询

                .All(ctx,&results);

find方法只是为了将查询条件赋值给Find结构体,最后的All方法从Find结构体中取出查询条件编写查询语句进行查询

2  插入一条信息进入表cc_HostBase中

//创建插入信息

inputc := input.(map[string]interface{})

inputc[“name”]=“张三”

//开始插入

lgc.Instance.

   //指定查询的表

   Table(“cc_HostBase”).

                 //进行查询

                .insert(ctx,inputc);

3 在上文查询语句 Logics.Instance.Table(“表名”).Find(map).all(results)中,将查询条件放在map中,但并不能完全满足需求,例如:查询主机id 不等于”23″的主机,或者大于/小于某个值时都无法用简单的map进行封装查询条件,而在cmdb中还有另外一种存放查询条件的结构体

3.1 查询条件放在结构体condition中

type condition struct {

   start        int64

   limit        int64

   sort         string

   fields       []Field

   or           []OR

   filterFields []string

}

// 上面这个结构体 调用下面这个接口的实现方法

type Condition interface {

   SetPage(page types.MapStr) error

   SetStart(start int64)

   GetStart() int64

   SetLimit(limit int64)

   GetLimit() int64

   SetSort(sort string)

   GetSort() string

   SetFields(fields []string)

   GetFields() []string

   Field(fieldName string) Field

   NewOR() OR

   Parse(data types.MapStr) error

   ToMapStr() types.MapStr

}

接口Condition 有Field 字段,其中字段fields 是个interface 其实现方法有

type Field interface {

   Eq(val interface{}) Condition

   NotEq(val interface{}) Condition

   Like(val interface{}) Condition

   In(val interface{}) Condition

   NotIn(val interface{}) Condition

   Lt(val interface{}) Condition

   Lte(val interface{}) Condition

   Gt(val interface{}) Condition

   NotGt(val interface{}) Condition

   Gte(val interface{}) Condition

   ToMapStr() types.MapStr

}

所以:cond.Field(字段”).NotEq(“条件”)

如:

// 创建condition结构体

cond := condition.CreateCondition()

//查询内网ip不等于121.21.13.14的机器

cond.Field(“bk_host_innerIp”).NotEq(“121.21.13.14”)

//创建结构体condMapStr

var condMapStr mapstr.MapStr= mapstr.New()

//将conf 进行一些转化

condMapStr.Merge(cond.ToMapStr())

//condMapStr放着查询条件,作为参数放入Find中进行查询

err:= lgc.Instance.Table(“cc_HostBase”). Find(condMapStr) .All(ctx,&results);

Redis在cmdb中的作用

redis在cmdb中主要用于事件订阅

1 redis的ident文件夹下中存放的信息有:

   业务信息,主机信息,模块信息,集群信息,进程信息

image.png
image.png

2 redis中的信息同步:

  2.1 以上信息并非是实时更新,event_server负责从mongo数据库中同步最新的数据,大概每隔1分钟向redis中同步一次信息。

   2.2  在event_server启动时调用app.Run()方法——   errCh <- distribution.Start(ctx, cache, db, rpccli)————chErr <- ih.StartHandleInsts()中代码片段:

go func() {

   ih.fetchHostCache()

   for range time.Tick(time.Second * 60) {

      ih.fetchHostCache()

   }

}()

可设置redis中的信息多久和mongo同步一次 

 2.3 新增订阅事件,删除订阅事件,会时时同步到redis,redis中记录的只是 订阅事件id

image.png

3 event_server 直接调用storage 操作数据库,不再调用controller 

event_server : 事件订阅服务

请求入口:src/scene_server/event_server/service/service.go:

    //查询订阅事件

api.Route(api.POST(“/subscribe/search/{ownerID}/{appID}”).To(s.Query))

//只测试连通性

api.Route(api.POST(“/subscribe/ping”).To(s.Ping))

//测试推送

api.Route(api.POST(“/subscribe/telnet”).To(s.Telnet))

//新增订阅事件

api.Route(api.POST(“/subscribe/{ownerID}/{appID}”).To(s.Subscribe))

//删除订阅事件

api.Route(api.DELETE(“/subscribe/{ownerID}/{appID}/{subscribeID}”).To(s.UnSubscribe))

//修改订阅事件

api.Route(api.PUT(“/subscribe/{ownerID}/{appID}/{subscribeID}”).To(s.Rebook))

4 生产者–消费者

1生产者:

type Service struct {

   Core     *backbone.Engine

   Instance dal.RDB

   Cache    *redis.Client

}

在结构体Service中有  Cache    *redis.Client 

当对资源进行增删改查时,在controller中操作成功后,会向redis中新增一个消息 如下:

ec := eventclient.NewEventContextByReq(req.Request.Header, cli.Cache)

ec.InsertEvent(metadata.EventTypeInstData, objType, metadata.EventActionUpdate, newData)

lpush(key,value) 将消息放入redis

这时在redis中,如图4个消息存放于队列中等待被消费:

image.png

2 消费者

在 src/scene_server/event_server/identifier/identifier.go :

handleInstLoop方法:

在服务启动的时候 调用handleInstLoop()方法,其中for循环中ih.popEventInst()会和redis建立连接,并从redis中根据key获取到值

for {

   event := ih.popEventInst()

   if nil == event {

      time.Sleep(time.Second * 2)

      continue

   } 

上面for循环内的代码会不停的向redis建立连接取值,当value为空时,继续建立连接会造成资源浪费,所以在ih.popEventInst()中,从redis中取值时并未使用rpop,而是使用了阻塞命令brpop,当value为空时线程会阻塞在那

image.png

审计信息的记录

8/10

审计操作是在业务逻辑层完成的操作:

Sence_server ————调用———— src/apimachinery/auditcontroller ——跳转——— audit_controller

在业务逻辑层中(server)处理业务后,根据返回的结果新增操作的审计信息

apimachinery 内封装的有新增审计信息方法:

新增业务操作      AddBusinessLog()

查询审计信息   GetAuditLog ()

新增主机操作   AddHostLog()

新增模块操作   AddModuleLog()

新增对象操作   AddObjectLog()

新增进程操作   AddProcLog()

新增集群操作   AddSetLog()

server 调用apimachinery 封装的方法,上述方法之外的操作不记录审计。

具体新增审计代码(1):

type Service struct {

   *options.Config

   *backbone.Engine

   *logics.Logics

   disc discovery.DiscoveryInterface

}

type Engine struct {

   sync.Mutex

   ServerInfo types.ServerInfo

   CoreAPI    apimachinery.ClientSetInterface

   SvcDisc    ServiceDiscoverInterface

   Language   language.CCLanguageIf

   CCErr      errors.CCErrorIf

}

aResult, err := service.CoreAPI.AuditController().AddHostLogs(context.Background(), common.BKDefaultOwnerID, appID, user, pheader, log)

通过结构体Service   调用CoreAPI 即apimachinery 内封装的方法 

9/10

具体新增审计代码(2)

在topo_server 中 

src/scene_server/topo_server/service/service_initfunc.go 可以接收请求有:

新增biz,

新增module,

新增set,

新增Inst 

以上请求的响应方法处理逻辑之后,最终都要调用src/scene_server/topo_server/core/operation/inst.go下的

func (c *commonInst) CreateInst(){}方法。

在CreateInst中 新增审计信息 如下:

NewSupplementary().Audit(…).CommitCreateLog(…)

CommitCreateLog方法———commitSnapshot()在commitSnapshot中根据参数不同调用AuditController()中封装好的审计方法

image.png

src/common/tablenames.go   所用到的表名,每个表名在这里都有一个变量表示;数据库查询时不直接写查询的表名,而是使用表名所代表的变量

association 关联关系

在topo_server;

src/scene_server/topo_server/service/service_initfunc.go:中有着所有关联关系的入口,分类如下

1  关联类型:创建一种关联关系用于实例间关联事被引用

image.png

查询关联类型

“/topo/association/type/action/search

 新增关联类型

 “/topo/association/type/action/create

更新一个关联类型

  “/topo/association/type/{id}/action/update

删除一个关联类型

  “/topo/association/type/{id}/action/delete

2 主机和模型实例关联关系

image.png

/inst/association/action/search

/inst/association/action/create

/inst/association/{association_id}/action/delete

10/10

3模型拓扑关联关系

image.png

/object/association/action/search


/object/association/action/create


/object/association/{id}/action/update


/object/association/{id}/action/delete

权限管理

1 创建角色,添加成员

image.png

创建角色时,选择拥有此角色的成员;  也称新建用户分组

topo_server.  API: POST /api/{version}/topo/privilege/group/{bk_supplier_account}

参数:分组名,分组成员

{

    “group_name”:”管理员”,

    “user_list”:”owen;tt”

}

src/apimachinery/objcontroller/privilege/privilege.go:  CreateUserGroup() 跳转进入object——controller

image.png

src/source_controller/objectcontroller/service/service.go:接收请求

api.Route(api.POST(“/privilege/group/{bk_supplier_account}”).To(s.CreateUserGroup))

表:cc_Usergroup

image.png

2 添加的成员必须时 已经存在的账户  :查询现有的的用户

web_server :ws.GET(“/user/list”, s.GetUserList)

————— src/web_server/middleware/user/public.go :GetUserList

———— — —  src/web_server/middleware/user/plugins/method/self/userinfo.go :GetUserList

image.png

在cmdb开源代码中,不支持多用户,在代码固定了一个 admin 用户

3  编辑用户分组权限

image.png

API: POST /api/{version}/topo/privilege/group/detail/{bk_supplier_account}/{group_id}

参数:

{bk_middleware: {

    bk_tomcat: [“search”, “update”, “delete”], 

        redis: [“search”, “update”, “delete”]

}

}

4 查询用户权限:

API: GET /api/{version}/topo/privilege/user/detail/{bk_supplier_account}/{user_name}

http://localhost:8083/api/v3/topo/privilege/user/detail/0/admin  获取用户admin的权限

Share