mirror of https://github.com/veops/cmdb.git
428 lines
12 KiB
Markdown
428 lines
12 KiB
Markdown
**CMDB接口文档v0.1** @ [维易科技](https://veops.cn)
|
||
|
||
# <div style="text-align: center;">CMDB接口文档</div>
|
||
|
||
### 一、CI接口
|
||
|
||
#### 1. CI查询接口
|
||
|
||
**条件搜索CI**, 按照模型的属性进行条件过滤、统计、排序等查询
|
||
|
||
* GET `/api/v0.1/ci/s`
|
||
* 参数
|
||
|
||
| 参数名 | 示例值 | 参数类型 | 是否必填 | 参数描述 |
|
||
| ---- | ---- | ------ | ------ | ----|
|
||
| **q** | q=private_ip:192* | string | 是 | 搜索表达式 |
|
||
| **fl** | | string | 否 | 返回的属性字段, 逗号分隔 |
|
||
| **facet** | facet=idc | string | 否 | 属性字段,逗号分隔,返回属性对应的所有值的统计 |
|
||
| **count** | count=1 | int | 否 | 一页返回的CI数, 默认是25 |
|
||
| **page** | page=1 | int | 否 | 页数, 默认是1 |
|
||
| **sort** | sort=-private_ip| string | 否 | 属性的排序,降序字段前面加负号- |
|
||
| **ret_key** | ret_key=name | enum | 否 | 返回字段类型, 可以是`id`、`name`、`alias`, 默认`name` |
|
||
|
||
* 参数**q**说明:
|
||
* `_type` 指定CI模型, 多个用分号分隔. 例如: `_type:(server;vserver)`
|
||
* `attribute:value` 指定属性搜索, `attribute`可以是`id`,`attr_name`和`attr_alias`
|
||
* 以上的组合,逗号分隔
|
||
* 组合查询使用方法
|
||
* **`与`** 关系: `默认关系`
|
||
* **`或`**关系: 属性字段前加`-`, 例如: `-hostname:cmdb*`、
|
||
* **`非`**关系: 属性字段前加`~` 例如: `~hostname:cmdb*`
|
||
* **`或非`**关系: 属性字段前加`-~` 例如: `-~hostname:*`
|
||
* **`IN`**查询: 例如: `hostname:(cmdb*;cmdb-web*)` 小括号, 分号分隔
|
||
* **`范围`**查询: 例如: `hostname:[cmdb* _TO_ cmdb-web*]` `_TO_`分隔
|
||
* **`比较`**查询: 例如: `cpu_count:>5` 支持`>, >=, <, <=`
|
||
|
||
* 结果字段说明
|
||
|
||
| 字段名 | 值的类型 | 说明 |
|
||
| ---- | ---- | ----|
|
||
| **numfound** | int | CI总数 |
|
||
| **total** | int | 当前页的CI数 |
|
||
| **page** | int |分页 |
|
||
| **result** | list | 返回的CI列表 |
|
||
| **facet** | dict| 根据参数facet做的聚合统计|
|
||
| **counter** | dict | 当前页按模型的分类统计 |
|
||
|
||
* 返回结果
|
||
* 搜索示例 `/api/v0.1/ci/s?q=_type:server,private_ip:192.*,idc:*,status:在线&sort=-private_ip&facet=idc&page=1&count=1`
|
||
* 返回数据(默认json)
|
||
---
|
||
```json
|
||
{
|
||
"counter": {
|
||
"server": 1
|
||
},
|
||
"facet": {
|
||
"idc": [
|
||
[
|
||
"南汇",
|
||
600,
|
||
"idc"
|
||
],
|
||
[
|
||
"外高桥",
|
||
600,
|
||
"idc"
|
||
],
|
||
[
|
||
"张江",
|
||
600,
|
||
"idc"
|
||
]
|
||
]
|
||
},
|
||
"numfound": 1800,
|
||
"page": 1,
|
||
"result": [
|
||
{
|
||
"_id": 7238,
|
||
"_type": 4,
|
||
"buy_date": null,
|
||
"ci_type": "server",
|
||
"cpu": "Intel(R) Xeon(R) CPU E5-2630 v4 @ 2.20GHz",
|
||
"cpu_count": 20,
|
||
"device_spec": "PowerEdge R630",
|
||
"env": "test",
|
||
"idc": "外高桥",
|
||
"ilo_ip": "192.168.0.120",
|
||
"ilo_mac": "82:7b:eb:f8:cb:03",
|
||
"kernel_version": "4.1.12-61.1.33.el6uek.x86_64",
|
||
"logic_cpu_count": 40,
|
||
"maintain_enddate": null,
|
||
"maintain_startdate": null,
|
||
"manufacturer": "DELL",
|
||
"op_duty": "张三",
|
||
"os_version": "CentOS Linux release 7.6.1810 (Core)",
|
||
"perm": null,
|
||
"pos": null,
|
||
"private_ip": "192.168.66.99",
|
||
"rack": "12086",
|
||
"raid": "1.089TB/RAID5",
|
||
"ram": "128GB",
|
||
"ram_size": "128GB",
|
||
"rd_duty": "李四",
|
||
"server_name": "192.168.66.99",
|
||
"sn": "8cbe16404c11",
|
||
"status": "在线",
|
||
"unique": "sn",
|
||
"vnc_port": null
|
||
}
|
||
],
|
||
"total": 1
|
||
}
|
||
```
|
||
|
||
#### 2. 新增CI接口
|
||
|
||
**创建或者修改CI**
|
||
|
||
* POST `/api/v0.1/ci`
|
||
* 参数
|
||
|
||
| 参数名 | 示例值 | 参数类型 | 是否必填 | 参数描述 |
|
||
| ---- | ---- | ------ | ------ | ----|
|
||
| **ci_type** | ci_type=server | string | 是 | 创建CI所属的模型名 |
|
||
| **no_attribute_policy** | no_attribute_policy=ignore | string | 否 | 当添加不存在的attribute时的策略, 可选: `reject`、`ignore`, 默认`ignore` |
|
||
| **exist_policy** | exist_policy=reject | string | 否 | CI已经存在的处理策略, 可选: `need`、`reject`、`replace` 默认`reject` |
|
||
| **模型的属性名** | sn=xxxx | string | 否 | 属性名(id或别名亦可) |
|
||
|
||
> 注意: 请求的参数里必须包含该CI的唯一标识
|
||
|
||
* 返回结果
|
||
|
||
```json
|
||
{
|
||
"ci_id": 1
|
||
}
|
||
```
|
||
|
||
#### 3. 修改CI接口
|
||
|
||
**修改CI**, 可以使用新增CI的接口, exist_policy=replace, 或者根据ci_id来修改
|
||
|
||
* PUT `/api/v0.1/ci` 或者 `/api/v0.1/ci/<int:ci_id>`
|
||
* 参数
|
||
|
||
| 参数名 | 示例值 | 参数类型 | 是否必填 | 参数描述 |
|
||
| ---- | ---- | ------ | ------ | ----|
|
||
| **ci_type** | ci_type=server | string | 是 | 创建CI所属的模型名 |
|
||
| **no_attribute_policy** | no_attribute_policy=ignore | string | 否 | 当添加不存在的attribute时的策略, 可选: `reject`、`ignore`, 默认`ignore` |
|
||
| **模型的属性名** | sn=xxxx | string | 否 | 属性名(id或别名亦可) |
|
||
|
||
> 注意: 如果使用`/api/v0.1/ci`, 请求的参数里必须包含该CI的唯一标识
|
||
|
||
* 返回结果
|
||
|
||
```json
|
||
{
|
||
"ci_id": 1
|
||
}
|
||
```
|
||
|
||
#### 4. 删除CI接口
|
||
|
||
**根据ci_id删除CI**, 硬删除操作
|
||
|
||
* DELETE `/api/v0.1/ci/<int:ci_id>`
|
||
* 参数 无
|
||
* 返回结果
|
||
|
||
```json
|
||
{
|
||
"message": "ok"
|
||
}
|
||
```
|
||
|
||
<div STYLE="page-break-after: always;"></div>
|
||
|
||
### 二、CI关系接口
|
||
|
||
#### 1. CI关系查询接口
|
||
|
||
**搜索所有的CI之间的关系**, 比如某一个事业部的所有应用或者是所有服务器
|
||
|
||
* GET `/api/v0.1/ci_relations/s`
|
||
* 参数
|
||
|
||
| 参数名 | 示例值 | 参数类型 | 是否必填 | 参数描述 |
|
||
| ---- | ---- | ------ | ------ | ----|
|
||
| **root_id** | root_id=1 | int | 是 | 根节点的ci_id |
|
||
| **level** | level=1 | string | 否 | 关系的层级,多层用逗号分隔 |
|
||
| **reverse** | reverse=0 | int | 否 | 是否反向搜索, 0或者1, 默认是0, |
|
||
| **q** | q=hostname:cmdb* | string | 否 | 搜索表达式 |
|
||
| **fl** | | string | 否 | 返回的属性字段, 逗号分隔 |
|
||
| **facet** | | string | 否 | 属性字段,逗号分隔,返回属性对应的所有值的统计 |
|
||
| **count** | count=25 | int | 否 | 一页返回的CI数, 默认是25 |
|
||
| **page** | page=1 | int | 否 | 页数, 默认是1 |
|
||
| **sort** | | string | 否 | 属性的排序,降序字段前面加负号- |
|
||
| **ret_key** | | enum | 否 | 返回字段类型, 可以是`id`、`name`、`alias`, 默认`name` |
|
||
|
||
> 搜索表达式`q` 和 `CI查询接口`的搜索表达式q 完全一样!
|
||
|
||
* 结果字段说明
|
||
|
||
| 字段名 | 值的类型 | 说明 |
|
||
| ---- | ---- | ----|
|
||
| **numfound** | int | CI总数 |
|
||
| **total** | int | 当前页的CI数 |
|
||
| **page** | int |分页 |
|
||
| **result** | list | 返回的CI列表 |
|
||
| **facet** | dict| 根据参数facet做的聚合统计|
|
||
| **counter** | dict | 当前页按模型的分类统计 |
|
||
|
||
* 返回结果
|
||
* 搜索某个事业部下面的物理机 `/api/v0.1/ci_relations/s?root_id=5&level=3&count=1&q=_type:server,idc:南汇`
|
||
* 返回数据(默认json)
|
||
---
|
||
|
||
```json
|
||
{
|
||
"counter": {
|
||
"server": 1
|
||
},
|
||
"facet": {},
|
||
"numfound": 400,
|
||
"page": 1,
|
||
"result": [
|
||
{
|
||
"_id": 159,
|
||
"_type": 4,
|
||
"bu": null,
|
||
"buy_date": null,
|
||
"ci_type": "server",
|
||
"cmc_ip": null,
|
||
"cnc_ip": null,
|
||
"cpu": "Intel(R) Xeon(R) CPU E5-2630 v4 @ 2.20GHz",
|
||
"cpu_count": 20,
|
||
"ctc_ip": null,
|
||
"device_spec": "PowerEdge R630",
|
||
"env": "prod",
|
||
"idc": "南汇",
|
||
"ilo_ip": "192.168.0.120",
|
||
"ilo_mac": "82:7b:eb:f8:cb:03",
|
||
"kernel_version": "4.1.12-61.1.33.el6uek.x86_64",
|
||
"logic_cpu_count": 40,
|
||
"maintain_enddate": null,
|
||
"maintain_startdate": null,
|
||
"manufacturer": "DELL",
|
||
"oneagent_id": null,
|
||
"op_duty": "张三",
|
||
"os_version": "Microsoft Windows Server 2019 Standard",
|
||
"perm": null,
|
||
"pos": null,
|
||
"private_ip": "192.168.1.2",
|
||
"rack": "12086",
|
||
"raid": "1.089TB/RAID5",
|
||
"ram": "128GB",
|
||
"ram_size": "128GB",
|
||
"rd_duty": "李四",
|
||
"server_name": "192.168.1.2",
|
||
"server_room": null,
|
||
"sn": "1fd3b1d5c253",
|
||
"ssh_port": null,
|
||
"status": "在线",
|
||
"unique": "sn",
|
||
"vnc_port": null
|
||
}
|
||
],
|
||
"total": 1
|
||
}
|
||
```
|
||
|
||
#### 2. 增加CI关系接口
|
||
|
||
**新增CI关系**, 参数`src_ci_id`是源CI的id, `dst_ci_id`是目标CI的id
|
||
|
||
* POST `/api/v0.1/ci_relations/<int:src_ci_id>/<int:dst_ci_id>`
|
||
* 参数 无
|
||
* 返回结果
|
||
|
||
```json
|
||
{
|
||
"cr_id": 1
|
||
}
|
||
```
|
||
|
||
#### 3. 删除CI关系接口
|
||
|
||
**根据`cr_id`删除CI关系**, 参数`cr_id`是CI关系的id
|
||
|
||
* DELETE `/api/v0.1/ci_relations/<int:cr_id>`
|
||
* 参数 无
|
||
* 返回结果
|
||
|
||
```json
|
||
{
|
||
"message": "CIType relation deleted"
|
||
}
|
||
```
|
||
|
||
<div STYLE="page-break-after: always;"></div>
|
||
|
||
### 三、响应状态码说明
|
||
|
||
|状态码|说明|
|
||
|----|---|
|
||
|200|成功|
|
||
|400|请求参数错误或者失败|
|
||
|401|未认证|
|
||
|403|权限不够|
|
||
|404|访问的资源不存在|
|
||
|500|服务端未知错误|
|
||
|502|服务未启动或者异常退出|
|
||
|
||
> 所有错误或者失败,统一返回json格式为:
|
||
```json
|
||
{
|
||
"message": "错误描述"
|
||
}
|
||
```
|
||
|
||
|
||
<div STYLE="page-break-after: always;"></div>
|
||
|
||
### 四、API鉴权方法
|
||
- 每个用户会自动生成一个 `api key` 和 一个`secret`, 在ACL系统里可查看到
|
||
- 调用API的时候,需要提供2个参数 `_key`和`_secret`
|
||
- `_key`的值为您的`api key`
|
||
- `_secret`的计算方法:
|
||
- 除`_key`以外的参数,把**参数名**排序后参数值拼接在一起,并连接到`url path` + `secret`之后
|
||
- 求`sha1`**十六进制**值, 即sha1(`url path` + `secret` + `参数名排序后拼接的参数值`)的16进制值
|
||
|
||
|
||
### 五、Python调用样例
|
||
#### 鉴权
|
||
```python
|
||
import hashlib
|
||
|
||
key = "Your API key"
|
||
secret = "Your API secret"
|
||
|
||
def build_api_key(path, params):
|
||
values = "".join([str(params[k]) for k in sorted(params.keys())
|
||
if params[k] is not None and not k.startswith('_')]) if params.keys() else ""
|
||
_secret = "".join([path, secret, values]).encode("utf-8")
|
||
params["_secret"] = hashlib.sha1(_secret).hexdigest()
|
||
params["_key"] = key
|
||
|
||
return params
|
||
```
|
||
|
||
#### 查询
|
||
* 以查询CI为例
|
||
```python
|
||
import hashlib
|
||
|
||
import requests
|
||
from future.moves.urllib.parse import urlparse
|
||
|
||
URL = "https://demo.veops.cn/api/v0.1/ci/s"
|
||
KEY = "Your API key"
|
||
SECRET = "Your API secret"
|
||
|
||
|
||
def build_api_key(path, params):
|
||
values = "".join([str(params[k]) for k in sorted(params.keys())
|
||
if params[k] is not None and not k.startswith('_')]) if params.keys() else ""
|
||
_secret = "".join([path, SECRET, values]).encode("utf-8")
|
||
params["_secret"] = hashlib.sha1(_secret).hexdigest()
|
||
params["_key"] = KEY
|
||
|
||
return params
|
||
|
||
|
||
def get_ci(payload):
|
||
payload = build_api_key(urlparse(URL).path, payload)
|
||
|
||
return requests.get(URL, params=payload).json()
|
||
|
||
```
|
||
|
||
#### 增、删、改
|
||
* 以CI的增、删、改为例
|
||
```python
|
||
import hashlib
|
||
|
||
import requests
|
||
from future.moves.urllib.parse import urlparse
|
||
|
||
URL = "https://demo.veops.cn/api/v0.1/ci"
|
||
KEY = "Your API key"
|
||
SECRET = "Your API secret"
|
||
|
||
|
||
def build_api_key(path, params):
|
||
values = "".join([str(params[k]) for k in sorted(params.keys())
|
||
if params[k] is not None and not k.startswith('_')]) if params.keys() else ""
|
||
_secret = "".join([path, SECRET, values]).encode("utf-8")
|
||
params["_secret"] = hashlib.sha1(_secret).hexdigest()
|
||
params["_key"] = KEY
|
||
|
||
return params
|
||
|
||
|
||
def add_ci(payload):
|
||
payload = build_api_key(urlparse(URL).path, payload)
|
||
|
||
return requests.post(URL, json=payload).json()
|
||
|
||
|
||
def update_ci(payload, ci_id=None):
|
||
url = "{url}/{ci_id}".format(url=URL, ci_id=ci_id) if ci_id is not None else URL
|
||
|
||
payload = build_api_key(urlparse(url).path, payload)
|
||
|
||
return requests.put(url, json=payload).json()
|
||
|
||
|
||
def delete_ci(ci_id):
|
||
url = "{url}/{ci_id}".format(url=URL, ci_id=ci_id)
|
||
|
||
payload = build_api_key(urlparse(url).path, {})
|
||
|
||
return requests.delete(url, json=payload).json()
|
||
|
||
```
|