蓝鲸配置平台 bk-cmdb delete_inst 接口详解:删除对象实例的请求参数、返回结果与底层实现
蓝鲸配置平台 bk-cmdb delete_inst 接口详解:删除对象实例的请求参数、返回结果与底层实现
本文以蓝鲸智云配置平台(bk-cmdb)开放接口文档中的 delete_inst(删除实例)接口为核心,讲解如何通过指定模型 ID 与实例 ID 删除自定义层级模型和通用模型下的对象实例,覆盖接口适用边界、请求参数、请求/响应示例、权限要求,并结合 src/source_controller/coreservice 与 src/ac/parser 的源码剖析其删除校验、级联清理与鉴权实现的底层逻辑。读完本文,你可以独立完成该接口的调用与排障,并理解它与批量删除、级联删除等同类接口的差异。
功能概述与适用场景
delete_inst 接口用于指定模型 ID(bk_obj_id)和实例 ID(bk_inst_id)删除该模型下的对象实例,其权限要求为模型实例删除权限(在权限中心的动作类型为 delete 实例)。
使用前必须明确该接口的适用范围,这是最容易踩坑的一点:
- 适用:自定义层级模型(自定义主线模型)实例、通用模型实例。
- 不适用:业务、集群、模块、主机等平台内置模型实例。这些内置模型实例拥有专属的管理接口(例如主机的迁移、业务拓扑管理等),不能通过本接口直接删除。
若需要批量删除模型实例,请使用同一文档体系中的
batch_delete_inst接口;若需要连同实例的关联关系一并删除,可关注本文后面介绍的级联删除实现(CascadeDeleteModelInstance)。
接口信息总览
根据 docs/apidoc/cc/cc.yaml 中 delete_inst 的网关定义,该接口的完整映射关系如下:
| 项目 | 值 |
|---|---|
| 网关路径(建议方式) | /v2/cc/delete_inst/ |
| 网关 HTTP 方法 | POST(suggest_method) |
| 内部目标路径 | /api/v3/delete/instance/object/{bk_obj_id}/inst/{bk_inst_id} |
| 内部目标 HTTP 方法 | DELETE |
| API 类型 | operate(操作类接口) |
| 权限点 | 模型实例删除权限(meta.Delete) |
也就是说,请求经过 API 网关(ESB)时使用 POST + 网关路径;网关将请求转换为对 CMDB 内部服务的 DELETE /api/v3/delete/instance/object/{bk_obj_id}/inst/{bk_inst_id} 调用。权限中心在内部路径上完成实例级鉴权(详见下文"权限鉴权链路")。
请求参数详解
公共参数
接口文档中以 {{ common_args_desc }} 占位符表示的公共参数(通用请求头/公共鉴权参数)在真实调用中必须携带,从文档给出的请求示例可以看到通常包含:
| 字段 | 类型 | 说明 |
|---|---|---|
bk_app_code |
string | 应用标识,ESB 网关鉴权用 |
bk_app_secret |
string | 应用密钥,ESB 网关鉴权用 |
bk_username |
string | 用户名,标识操作者 |
bk_token |
string | 用户登录态 Token(与 bk_username 二选一或按网关要求组合) |
接口参数
| 字段 | 类型 | 必选 | 描述 |
|---|---|---|---|
bk_obj_id |
string | 是 | 模型 ID |
bk_inst_id |
int | 是 | 实例 ID |
bk_biz_id |
int | 否 | 业务 ID,当删除的是自定义主线层级模型实例时则必传 |
关于 metadata 的特殊注意事项
文档明确提示一个兼容性坑点:当操作的是自定义主线层级模型实例,且同时接入了权限中心时,对于 CMDB 小于 3.9 的版本,还需要额外传入包含实例所在业务 ID 的 metadata 参数,否则会导致权限中心鉴权失败。格式如下:
"metadata": {
"label": {
"bk_biz_id": "64"
}
}
这是为了让旧版本 CMDB 在鉴权时能够定位实例所属的业务范围。从源码看,权限解析逻辑在从请求 body 中读取业务 ID(见 src/ac/parser/topolatest.go 中的 getBizIDFromBody),因此传入 metadata.label.bk_biz_id 可以保证实例级鉴权正确命中。
请求参数示例
以下是文档给出的完整请求示例(通过网关发起):
{
"bk_app_code": "esb_test",
"bk_app_secret": "xxx",
"bk_username": "xxx",
"bk_token": "xxx",
"bk_obj_id": "test",
"bk_inst_id": 44
}
其中 bk_obj_id 为 test 的模型下、bk_inst_id 为 44 的实例将被删除。若该模型是自定义主线层级模型且版本小于 3.9、接入了权限中心,则还需要按上一节格式补充 metadata 字段。
返回结果解析
返回结果示例
{
"result": true,
"code": 0,
"message": "success",
"permission": null,
"request_id": "e43da4ef221746868dc4c837d36f3807",
"data": null
}
response 字段说明
| 字段 | 类型 | 描述 |
|---|---|---|
result |
bool | 请求成功与否。true:请求成功;false:请求失败 |
code |
int | 错误编码。0 表示 success,>0 表示失败错误 |
message |
string | 请求失败返回的错误信息 |
permission |
object | 权限信息(鉴权失败或需要额外授权时返回) |
request_id |
string | 请求链 ID,用于全链路追踪 |
data |
object | 请求返回的数据(删除成功时为空) |
底层实现:删除一条实例的完整调用链
理解底层实现有助于在调用失败时快速定位问题。删除实例的内部调用链在 src/source_controller/coreservice 模块中可以分为三层:
1. 路由注册(service 层入口)
在 src/source_controller/coreservice/service/service_initfunc.go 中注册了两个删除实例的路由:
DELETE /delete/model/{bk_obj_id}/instance→s.DeleteModelInstances(普通删除)DELETE /delete/model/{bk_obj_id}/instance/cascade→s.CascadeDeleteModelInstances(级联删除)
对应 HTTP 处理器定义在 src/source_controller/coreservice/service/instances.go:
func (s *coreService) DeleteModelInstances(ctx *rest.Contexts) {
inputData := metadata.DeleteOption{}
if err := ctx.DecodeInto(&inputData); nil != err {
ctx.RespAutoError(err)
return
}
ctx.RespEntityWithError(s.core.InstanceOperation().DeleteModelInstance(
ctx.Kit, ctx.Request.PathParameter("bk_obj_id"), inputData))
}
请求体被解码为 metadata.DeleteOption 结构体,其定义在 src/common/metadata/delete.go:
type DeleteOption struct {
Condition mapstr.MapStr `json:"condition"`
}
注意:删除接口的请求体本质上是一个**条件(condition)**结构,从 bk_inst_id 会被转换为 Condition 中实例 ID 字段的等值条件。
2. 核心删除逻辑(core 层)
核心实现在 src/source_controller/coreservice/core/instances/instance.go 的 DeleteModelInstance 函数中,大致分五步:
- 确定数据表与实例 ID 字段:通过
common.GetInstTableName(objID, kit.SupplierAccount)获取模型对应的实例表名,通过common.GetInstIDField(objID)获取实例 ID 字段名(通用模型为bk_inst_id,主线模型为对应主线字段)。 - 注入数据归属条件:将
bk_supplier_account(供应商账号)写入查询条件,保证只操作本供应商范围内的数据。 - 查询并逐一校验关联关系:先按条件查询出全部待删除实例,随后对每个实例调用
IsInstAsstExist检查是否存在实例关联关系;一旦发现仍有关联,立即返回错误码CCErrorInstHasAsst(对应 src/common/errInfo.go 中定义的1101075),并拒绝删除。这也是调用该接口最常见的失败原因之一。 - 删除实例数据:调用
mongodb.Client().Table(tableName).Delete(...)从 Mongo 表中物理删除满足条件的数据;若模型是通用模型(metadata.IsCommon(objID),判断逻辑见 src/common/metadata/object.go),还会同步清理实例 ID 与实例的映射数据(instancemapping.Delete)。 - 清理被引用实例:调用
DeleteQuotedInst删除这些实例对应的"被引用实例"(quoted inst)数据,避免留下脏数据。
最终返回被删除的实例数量 DeletedCount。
3. 级联删除的差异
同文件中的 CascadeDeleteModelInstance 与普通删除唯一的区别在于第 3 步:普通删除在发现实例有关联关系时会报错中止,而级联删除会先调用 DeleteInstAsst 把实例的所有关联关系一并删除,然后再删除实例本身,从而实现"连坐"式清理。如果你希望删除一个仍存在关联关系的实例,应使用级联删除路径 /api/v3/delete/model/{bk_obj_id}/instance/cascade(对应批量/级联场景),而不是普通删除。
权限鉴权链路
该接口的鉴权在 API 网关转发到内部服务后由权限解析器处理。在 src/ac/parser/topolatest.go 中,删除实例的请求会命中正则 ^/api/v3/delete/instance/object/[^\s/]+/inst/[0-9]+/?$(对应变量 deleteObjectInstanceLatestRegexp),解析流程为:
- 从 URL 中解析出模型 ID(
objID)与实例 ID(instID); - 根据模型 ID 查询模型,确定实例类型(
getInstanceTypeByObject); - 从请求 body 中读取业务 ID(
getBizIDFromBody,即前文 metadata 参数被使用的位置); - 组装
ResourceAttribute,其中Action: meta.Delete,InstanceID: instID,交给权限中心完成实例级删除授权。
这也解释了文档中"权限:模型实例删除权限"的落点:权限中心需要用户对该模型实例具备 delete 动作,且能定位到实例所属业务,否则返回 permission 相关信息。
常见失败场景与排查建议
- 实例仍存在关联关系:返回错误码
1101075(CCErrorInstHasAsst)。请先调用删除实例关联接口清理关联,或改用级联删除路径。 - 鉴权失败:确认用户具备模型实例删除权限;删除自定义主线层级模型实例且 CMDB 版本小于 3.9 时,务必携带
metadata.label.bk_biz_id。 - 尝试删除内置模型实例(如
bk_host、业务、集群、模块):接口不适用,请改用对应业务/拓扑/主机管理接口。 - 实例不存在:删除操作按条件执行,条件不匹配时不会报"实例不存在",返回
data为空或删除数量为 0,需要结合返回的DeletedCount或前置查询接口(如search_inst)确认实例 ID 正确。
相关接口与资源
- 批量删除实例:
batch_delete_inst(对应网关定义同样位于 docs/apidoc/cc/cc.yaml,内部路径/api/v3/deletemany/instance/object/{bk_obj_id})。 - 实例关联关系管理:
delete_instance_association、delete_related_inst_asso,用于删除实例关联后再执行本接口。 - 接口英文版文档:delete_inst.md(en);中文版原文见 docs/apidoc/cc/zh_hans/delete_inst.md。
- 核心实现与测试:实例删除逻辑位于 src/source_controller/coreservice/core/instances/instance.go,对应单元测试见 src/source_controller/coreservice/core/instances/instance_test.go,可作为调用行为与边界条件的进一步参考。