Aspire 实现


用来管理 BootAgent 。

实现功能

通过 gRPC 实现通讯,同时提供 REST-API 接口。

1. 子Agent管理。
   1.1 安装、卸载,启动、停止、重启。
   1.2 健康检查、资源限制。
2. 命令通道。
   2.1 修改BootAgent配置。上报时间间隔、Tags列表。
   2.2 Agent管理命令,也就是1.1的内容。
3. 前端展示。分为三个TAB页进行管理。
   3.1 DashBoard。主机总数、在线数、API 调用次数;Agent的部署数量、在线数。采用离线统计。
   3.2 主机展示。显示基本信息,包括AgentSN、Region分组、主机名、管理IP、OS类型、架构、版本类型、状态(在线、离线、删除)、最近更新时间(状态变化时才会修改)。下拉展示TAG信息。
   3.3 Agent版本管理。包括了BootAgent及其子Agent的版本信息,包括Agent名称、版本号、OS类型、架构、文件路径、安装命令、SHA256。
   3.4 TAG管理。包括TAG的Key/Value、绑定主机数、更新时间。

注意,所谓的命令通道是有限的功能,简单来说,保证成功率,但是不保证时效性。实现时有两种策略:

最简单的是单机或者通过TAG更新的任务,此时会为每台主机生成一个任务进行跟踪。

另外一类是全局任务,这一类任务在主机数过大时会导致生成任务列表耗时过大,因此会置位一个全局标记,在 BootAgent 上报状态信息时匹配对应的字段,如果不符合则执行对应的操作。(暂时不实现)

Agent API

自动注册

在 BootAgent 第一次启动时会尝试注册到服务端。

----- POST /api/v1/agent/register
{
	"hostname": "127.0.0.1",                            # 可以通过hostname命令查看
	"ipaddr": "127.0.0.1",                              # 在发送注册信息时与服务端建立连接的IP
	"agentsn": "bfdcc18c-b6b9-4725-9c47-37fd93dba5b6"   # 本地生成的UUID用来唯一标识一台主机
	"tags": "svc=ecs,cmpt=DB",                          # TODO: 可以根据固定的模版生成
}

----- 返回信息
{
	"status": 0,
	"agentsn": "dcb886e9-04ed-41bb-9c12-4d2de12cd59b",  # 如果上层判断有冲突,则返回合法的AgentSN
	"tags": "svc=ecs,cmpt=DB",                          # 这里的tag一般是根据自动规则生成的
}

在注册时,需要保证 AgentSN 的唯一,如果有相同的 AgentSN 那么会再次检查 ipaddr 是否相同,如果相同那么认为是重复注册,此时会直接返回成功。否则,生成新的 AgentSN 。

状态上报

pyresttest http://booter.cargo.com:8180 contrib/tests/register.yaml --print-bodies=true --log=debug

REST-API

提供了针对 Agent 的 API 接口,其对应的地址为 booter.cargo.com:8180

响应格式

主要是分为了成功和失败的报文格式。

{
	"status": 130010,                        统一的错误码
	"message": "not found",                  报错信息,与错误码对应
	"cause": "no agent package found"        具体的报错信息
}

{
	"status": 0,                             表示正常
	"message": "success"
	"cause":"already deleted"                可选
}

主机管理

----- GET  /api/v1/server/host?agentsn="845d6374-7d4e-402f-87cc-2a780e794dd6"
{

}

包 VS. Agent 管理

会根据入参自动生成一个相对路径,一般为 $PACKAGE_PATH/{OS}/{ARCH}/{FILENAME} ,实际上包含了两类操作,分别是:A) 包管理;B) 元数据管理。

包管理

PUT    /api/v1/server/package/upload/CentOS/x86_64/BootAgent-1.2.3-rc1.x86_64.rpm
GET    /api/v1/server/package/download/CentOS/x86_64/BootAgent-1.2.3-rc1.x86_64.rpm
DELETE /api/v1/server/package/file/CentOS/x86_64/BootAgent-1.2.3-rc1.x86_64.rpm

Agent 管理

通过 name version arch os 唯一确定一个安装包。

----- POST   /api/v1/server/agent        上传包相关的元数据信息
{
	"name":"FoobarAgent",
	"version":"1.2.3-rc1",
	"arch":"x86_64",
	"os":"CentOS",
	"file":"FoobarAgent-1.2.3-rc1.x86_64.rpm"
}

----- GET    /api/v1/server/agent?name=FoobarAgent&version=1.2.4.-rc1&offset=0&limit=10&order=asc&sortby=id
{
	"count": 2,
	"offset": 0,
	"limit": 10,
	"packages": [{
		"id": 7,
		"name": "FoobarAgent",
		"os": "linux",
		"arch": "x86_64",
		"version": "1.2.3-rc1"
		"file": "FoobarAgent-1.2.3-rc1.x86_64.rpm",
		"path": "packages/linux/x86_64/FoobarAgent-1.2.3-rc1.x86_64.rpm",
		"gmt_create": "2018-11-09T00:14:27+08:00",
		"gmt_modify": "2018-11-09T00:14:27+08:00",
	}]
}

----- DELETE /api/v1/server/agent?name=FoobarAgent&version=1.2.4.-rc1&offset=0&limit=10&order=asc&sortby=id

任务管理

目前基于两种模式:

  1. 根据 AgentSN 。直接指定 AgentSN 列表,此时会拆解成子任务运行,当子任务运行完成则返回。
  2. 基于 Tags 。会在一个时间窗内一直有效,如果与 Agent 上报的 tag 与之匹配,那么就会下发相关对任务信息。

也就是说,前者适用于少量的 Agent 更新,可以控制数量;而后者适用于大量 Agent 的升级,只能控制时间范围,不能控制具体的更新数量。

----- POST /api/v1/server/task 下发任务
{
	"command": "install",                 # 必选,任务类型
	"agents": [                           # 服务器列表
		"9b62aabb-eda4-4d62-b036-b605d887bde3",
		"845d6374-7d4e-402f-87cc-2a780e794dd6"
	],
	"parameters": {
		"url": "http://xxxx",
		"url": "command://yum install MiniAgent -y",   # 通过命令安装
	}
}

{
	"id": 135,                               # 自动生成的任务ID
	"status": 0,                             # 状态码,0 表示成功
	"message": "success",                    # 返回的信息,可能是报错
	"results": [{
		"AgentSN": "9b62aabb-eda4-4d62-b036-b605d887bde3",
	}, {
		"AgentSN": "845d6374-7d4e-402f-87cc-2a780e794dd6",
	}]
}

----- GET  /api/v1/server/task?id=1 查询任务

表结构

记录了 BootAgent 以及 Aspire 服务端所生成的事件信息,通过 AgentSN局部ID发生时间戳 唯一确定一个事件。

CREATE DATABASE IF NOT EXISTS `Aspire`;
USE `Aspire`;

DROP TABLE IF EXISTS `subtasks`;
CREATE TABLE IF NOT EXISTS `subtasks` (
	`id` CHAR(40) NOT NULL PRIMARY KEY,
	`agentsn` CHAR(64) NOT NULL COMMENT "该任务对应的Agent",
	`status` INT NOT NULL DEFAULT 0 COMMENT "状态 0: INIT",
	`taskid` INT NOT NULL COMMENT "拆解前的任务ID",
	`gmt_modify` TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP,
	`gmt_create` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
	INDEX idx_task(`taskid`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT "针对任务拆解后的任务信息";

DROP TABLE IF EXISTS `tasks`;
CREATE TABLE IF NOT EXISTS `tasks` (
	`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
	`status` INT NOT NULL DEFAULT 0 COMMENT "状态 0: INIT",
	`user` CHAR(64) COMMENT "下发任务的用户名",
	`count` INT NOT NULL COMMENT "拆解后的子任务数",
	`complete` INT NOT NULL DEFAULT 0 COMMENT "已经完成的子任务数",
	`body` VARCHAR(4096) NOT NULL COMMENT "任务消息体",
	`gmt_modify` TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP,
	`gmt_create` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT "服务端下发的任务";

DROP TABLE IF EXISTS `pendings`;
CREATE TABLE IF NOT EXISTS `pendings` (
	`subtaskid` CHAR(40) NOT NULL PRIMARY KEY,
	`taskid` INT NOT NULL,
	`status` INT NOT NULL DEFAULT 0 COMMENT "状态 0: INIT",
	`gmt_schedule` TIMESTAMP NOT NULL DEFAULT 0,
	`gmt_create` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
	INDEX idx_sched(`gmt_schedule`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT "正在处理的任务";

DROP TABLE IF EXISTS `events`;
CREATE TABLE IF NOT EXISTS `events` (
	`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
	`agentsn` CHAR(64) NOT NULL COMMENT "那个机器发生的事件",
	`category` INT NOT NULL DEFAULT 0 COMMENT "事件的分类 0:Server",
	`localid` INT NOT NULL COMMENT "机器的本地ID标示",
	`occured` TIMESTAMP NOT NULL COMMENT "事件发生的时间戳",
	`gmt_create` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
	UNIQUE KEY `uk_event` (`agentsn`, `localid`, `occured`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT "Agent发生的事件记录";

DROP TABLE IF EXISTS `agents`;
CREATE TABLE IF NOT EXISTS `agents` (
	`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
	`name` CHAR(64) NOT NULL COMMENT "名称",
	`os` CHAR(64) NOT NULL COMMENT "操作系统类型,例如Linux、Windows10等",
	`arch` CHAR(16) NOT NULL COMMENT "机器架构,例如x86_64、ARM等",
	`version` CHAR(64) NOT NULL COMMENT "版本号",
	`file` VARCHAR(1024) NOT NULL COMMENT "文件名称",
	`gmt_modify` TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP,
	`gmt_create` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
	UNIQUE KEY `uk_name_version` (`name`, `os`, `arch`, `version`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT "Agent发布的版本信息";
INSERT INTO agents(name, version, arch, os, file, gmt_modify) VALUES("BasicAgent", "0.1.1-1", "x86_64", "linux",
                "BasicAgent-0.1.1-1.x86_64.rpm", now());
INSERT INTO agents(name, version, arch, os, file, gmt_modify) VALUES("MonitorAgent", "0.1.2-1", "x86_64", "linux",
                "MonitorAgent-0.1.2-1.x86_64.rpm", now());

DROP TABLE IF EXISTS `hosts`;
CREATE TABLE IF NOT EXISTS `hosts` (
	`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
	`agentsn` CHAR(64) NOT NULL COMMENT "AgentSN用来唯一标示一台主机",
	`hostname` CHAR(64) COMMENT "主机名",
	`ipaddr` CHAR(64) COMMENT "注册时连接到Server的客户端IP,管理面IP",
	`region` INT NOT NULL DEFAULT 0 COMMENT "所属region信息",
	`status` INT NOT NULL DEFAULT 0 COMMENT "主机状态 0:unknown 1:register 2:online 3:offline",
	`feature` INT NOT NULL DEFAULT 0 COMMENT "Agent所具有的特性 0: cgroup",
	`step` INT NOT NULL DEFAULT 300 COMMENT "Agent的采集时间间隔,单位是秒",
	`prevers` CHAR(64) COMMENT "上个版本,用来回滚",
	`curvers` CHAR(64) COMMENT "当前版本号",
	`gmt_modify` TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP,
	`gmt_create` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
	UNIQUE KEY `uk_agentsn` (`agentsn`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT "保存主机基本信息";

DROP TABLE IF EXISTS `tags`;
CREATE TABLE IF NOT EXISTS `tags` (
	`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
	`name` CHAR(64) NOT NULL COMMENT "TAG名称",
	`value` CHAR(64) NOT NULL COMMENT "TAG值",
	`gmt_modify` TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP,
	`gmt_create` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT "TAG信息表";
INSERT INTO tags(name, value) VALUES("svc", "ecs");

DROP TABLE IF EXISTS `regions`;
CREATE TABLE IF NOT EXISTS `regions` (
	`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
	`name` CHAR(64) NOT NULL COMMENT "Region的名称",
	`gmt_modify` TIMESTAMP NOT NULL ON UPDATE CURRENT_TIMESTAMP,
	`gmt_create` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT "保存的Region信息";
INSERT INTO regions(id, name) VALUES(0, "global");

DROP TABLE IF EXISTS `hosts_tags`;
CREATE TABLE IF NOT EXISTS `hosts_tags` (
	`hostid` INT NOT NULL COMMENT "主机ID信息",
	`tagid` INT NOT NULL COMMENT "TAG ID信息",
	PRIMARY KEY (hostid, tagid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT "主机与TAG的关联表";

DROP TABLE IF EXISTS `hosts_agents`;
CREATE TABLE IF NOT EXISTS `hosts_agents` (
	`hostid` INT NOT NULL COMMENT "主机ID信息",
	`agentid` INT NOT NULL COMMENT "Agent版本信息",
	PRIMARY KEY (hostid, agentid)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT "主机与Agent的关联表";

API



This Site was built by Jin Yang, generated with Jekyll, and hosted on GitHub Pages
©2013-2019 – Jin Yang