必须 Ambari Plus 3.0.3 数据库初始化文件
# Ambari Plus 3.0.3 数据库初始化
新装 Ambari Plus 3.0.3 时,按 Step9:Ambari Server 初始化,导入官方 Ambari DDL,再将本文的扩展 SQL 导入同一个 ambari 数据库。
这份 SQL 对应 3.0.3 的 Ambari-Plus-DDL-MySQL-CREATE.sql,包含 31 张扩展表、相关索引和初始化数据:
| 范围 | 主要内容 |
|---|---|
| 租户与权限 | 用户归属、租户成员、角色绑定、权限模板、执行面引用与审计总账 |
| 控制面与 HA | Server 实例登记、控制面租约、全局写操作租约、HA 操作及步骤记录 |
| Agent 身份 | Agent 证书登记、状态与撤销记录 |
| 安全治理 | 软件物料与漏洞记录、访问复核、审批、安全审计链、事件投递及兼容性记录 |
初始化这些表不会自动开启 HA、Kerberos 或 LDAP;相应能力仍需在页面中配置。
选择正确的数据库和初始化方式
本文用于 MySQL / MariaDB 全新安装,必须与官方 Ambari DDL 导入同一个数据库。示例库名为 ambari,请按实际配置替换,不要额外创建 ambari_plus 库,也不要导入 Hive、Ranger 或 Monitor 的元数据库。
已有环境升级请使用对应的升级流程与迁移 SQL。CREATE TABLE IF NOT EXISTS 不会补齐已存在表的字段,文件中的独立建索引语句也不保证重复执行成功;不要将完整 CREATE 文件当作升级或修复脚本反复导入。
# 保存并导入
将下方完整 SQL 保存为 UTF-8 文件 Ambari-Plus-DDL-MySQL-CREATE.sql。使用源码随附文件时,对应路径为:
ambari-plus-init/3.0.3/db/mysql/Ambari-Plus-DDL-MySQL-CREATE.sql
确认官方 Ambari 基础表已存在,再导入扩展表:
mysql -uambari -p -D ambari -N -e "SHOW TABLES LIKE 'metainfo';"
mysql -uambari -p --default-character-set=utf8mb4 ambari < Ambari-Plus-DDL-MySQL-CREATE.sql
2
第一条命令应返回 metainfo。如果没有输出,先完成官方 DDL 初始化。第二条命令应正常结束;出现 SQL 错误时先处理第一处错误,不能仅凭部分表已创建就继续启动服务。
# 检查初始化结果
导入后,在同一个数据库检查几类关键表:
mysql -uambari -p -D ambari -e "
SELECT table_name
FROM information_schema.tables
WHERE table_schema = DATABASE()
AND table_name IN (
'ambari_plus_tenant',
'ambari_plus_tenant_member',
'ambari_plus_perm_ext_ref',
'ambari_server_instance',
'ambari_server_lease',
'ambari_server_ha_operation',
'ambari_server_ha_operation_step',
'ambari_agent_certificate',
'security_approval_request',
'security_audit_ledger',
'security_event_outbox',
'security_compatibility_profile'
)
ORDER BY table_name;"
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
应返回以上 12 张表。再检查内置租户、角色和租约记录:
mysql -uambari -p -D ambari -e "
SELECT tenant_key, status
FROM ambari_plus_tenant WHERE tenant_key = 'root';
SELECT role_key, status
FROM ambari_plus_role_def WHERE role_key = 'tenant_admin';
SELECT resource_key
FROM ambari_server_lease
WHERE resource_key IN ('CONTROL_PLANE', 'CONTROL_PLANE_MUTATION');"
2
3
4
5
6
7
8
root 租户和 tenant_admin 角色应为 ACTIVE;租约表应包含 CONTROL_PLANE 和 CONTROL_PLANE_MUTATION 两条记录。初始化时不需要手工指定租约持有者,也不要重置运行中的租约。
# 完整初始化 SQL
复制下面整个代码块,保留全部表结构、索引和基线数据。此处仅包含 Ambari Plus 控制面 SQL;Monitor 元数据库使用独立的 Ambari-Plus-Monitor-DDL-MySQL-CREATE.sql。
-- 版权所有 (c) JaneTTR 2025
-- 项目名称:ambari-server
-- 本文件属于付费部分代码,仅供个人学习和研究使用。
--
-- 禁止行为:
-- 1. 未经授权,不得将本文件或其编译后的代码用于任何商业用途;
-- 2. 禁止重新分发本文件或其修改版本;
-- 3. 禁止通过反编译、反向工程等手段试图绕过授权验证。
--
-- 商业授权:[email protected]
-- 责任声明:本文件按“现状”提供,不附带任何形式的担保。
-- Ambari Plus 租户控制面、默认集群归属与租户审计表结构。
-- 3.0.3 新装初始化 CREATE SQL。Ambari 基础库初始化完成后执行一次。
-- 每个数据库目录只保留一个 CREATE 文件,后续字段直接并入本文件。
-- 表:ambari_plus_tenant
-- 租户主表。用于初始化内置 root 租户,不改变 Ambari 登录流程。
CREATE TABLE IF NOT EXISTS ambari_plus_tenant(
tenant_key VARCHAR(100) NOT NULL COMMENT '租户标识,默认 root,可用于租户上下文',
display_name VARCHAR(255) NOT NULL COMMENT '租户展示名称',
description VARCHAR(1024) COMMENT '租户说明',
status VARCHAR(32) NOT NULL COMMENT '租户状态,如 ACTIVE、DISABLED',
created_by VARCHAR(255) COMMENT '创建人',
created_time BIGINT NOT NULL COMMENT '创建时间,Unix 毫秒',
updated_by VARCHAR(255) COMMENT '最近更新人',
updated_time BIGINT NOT NULL COMMENT '最近更新时间,Unix 毫秒',
CONSTRAINT PK_ap_tenant PRIMARY KEY (tenant_key)
) COMMENT='租户主表,用于初始化内置 root 租户,不改变 Ambari 登录流程';
-- 表:ambari_plus_user
-- 平台用户主表。按集群身份域保存租户归属需要的用户标识,不保存密码。
CREATE TABLE IF NOT EXISTS ambari_plus_user(
user_key VARCHAR(512) NOT NULL COMMENT '平台用户主键,格式为 clusterName::userName',
cluster_name VARCHAR(255) NOT NULL COMMENT 'Ambari 集群名称,也是用户所属 LDAP 身份域',
user_name VARCHAR(255) NOT NULL COMMENT '平台用户名,对应该集群 LDAP 用户名',
display_name VARCHAR(255) NOT NULL COMMENT '用户展示名称',
auth_source VARCHAR(32) NOT NULL COMMENT '认证来源,如 AMBARI、LDAP',
status VARCHAR(32) NOT NULL COMMENT '用户状态,如 ACTIVE、DISABLED',
created_by VARCHAR(255) COMMENT '创建人',
created_time BIGINT NOT NULL COMMENT '创建时间,Unix 毫秒',
updated_by VARCHAR(255) COMMENT '最近更新人',
updated_time BIGINT NOT NULL COMMENT '最近更新时间,Unix 毫秒',
CONSTRAINT PK_ap_user PRIMARY KEY (user_key)
) COMMENT='平台用户主表,按集群身份域保存租户归属需要的用户标识,不保存密码';
-- 表:ambari_plus_user_checkin
-- 登录欢迎语用户访问节奏表。记录最近登录和上次登录,不保存凭据。
CREATE TABLE IF NOT EXISTS ambari_plus_user_checkin(
user_name VARCHAR(255) NOT NULL COMMENT 'Ambari 登录用户名',
display_name VARCHAR(255) COMMENT '用户展示名称',
previous_login_time BIGINT COMMENT '本次登录前的最近一次登录时间,Unix 毫秒',
last_login_time BIGINT COMMENT '最近一次登录时间,Unix 毫秒',
last_active_time BIGINT COMMENT '最近一次活跃时间,Unix 毫秒',
login_count BIGINT NOT NULL DEFAULT 0 COMMENT '累计登录次数',
created_time BIGINT NOT NULL COMMENT '记录创建时间,Unix 毫秒',
updated_time BIGINT NOT NULL COMMENT '记录最近更新时间,Unix 毫秒',
CONSTRAINT PK_ap_user_checkin PRIMARY KEY (user_name)
) COMMENT='登录欢迎语用户访问节奏表,记录最近登录和上次登录,不保存凭据';
-- 表:ambari_plus_tenant_member
-- 租户成员关系表。按集群身份域支持一个用户归属多个租户。
CREATE TABLE IF NOT EXISTS ambari_plus_tenant_member(
membership_key VARCHAR(128) NOT NULL COMMENT '成员关系唯一标识,由集群、租户和用户组合生成',
tenant_key VARCHAR(100) NOT NULL COMMENT '租户标识',
cluster_name VARCHAR(255) NOT NULL COMMENT 'Ambari 集群名称,也是成员所属 LDAP 身份域',
user_name VARCHAR(255) NOT NULL COMMENT '平台用户名,对应该集群 LDAP 用户名',
member_role VARCHAR(64) NOT NULL COMMENT '租户内成员角色,如 OWNER、ADMIN、MEMBER',
status VARCHAR(32) NOT NULL COMMENT '成员关系状态',
source VARCHAR(64) NOT NULL COMMENT '成员来源,如 SYSTEM、MANUAL、SYNC',
created_by VARCHAR(255) COMMENT '创建人',
created_time BIGINT NOT NULL COMMENT '创建时间,Unix 毫秒',
updated_by VARCHAR(255) COMMENT '最近更新人',
updated_time BIGINT NOT NULL COMMENT '最近更新时间,Unix 毫秒',
CONSTRAINT PK_ap_member PRIMARY KEY (membership_key)
) COMMENT='租户成员关系表,按集群身份域支持一个用户归属多个租户';
-- 表:ambari_plus_role_def
-- 租户角色定义表。保存内置角色和后续扩展角色。
CREATE TABLE IF NOT EXISTS ambari_plus_role_def(
role_key VARCHAR(100) NOT NULL COMMENT '角色唯一标识',
display_name VARCHAR(255) NOT NULL COMMENT '角色展示名称',
scope_type VARCHAR(32) NOT NULL COMMENT '角色作用域类型,如 TENANT、CLUSTER、GLOBAL',
built_in INTEGER NOT NULL COMMENT '是否内置角色,1 表示内置',
status VARCHAR(32) NOT NULL COMMENT '角色状态',
description VARCHAR(1024) COMMENT '角色说明',
created_by VARCHAR(255) COMMENT '创建人',
created_time BIGINT NOT NULL COMMENT '创建时间,Unix 毫秒',
updated_by VARCHAR(255) COMMENT '最近更新人',
updated_time BIGINT NOT NULL COMMENT '最近更新时间,Unix 毫秒',
CONSTRAINT PK_ap_role_def PRIMARY KEY (role_key)
) COMMENT='租户角色定义表,保存内置角色和后续扩展角色';
-- 表:ambari_plus_perm_tpl
-- 权限模板表。描述 Ambari RBAC、平台入口和 Ranger 资源权限原子。
CREATE TABLE IF NOT EXISTS ambari_plus_perm_tpl(
permission_key VARCHAR(255) NOT NULL COMMENT '权限模板唯一标识',
object_type VARCHAR(100) NOT NULL COMMENT '权限对象类型,如 AMBARI_RBAC、PLATFORM_ENTRY、RANGER_RESOURCE',
object_name VARCHAR(255) NOT NULL COMMENT '权限对象名称',
action_name VARCHAR(100) NOT NULL COMMENT '权限动作名称',
scope_type VARCHAR(32) NOT NULL COMMENT '权限作用域类型',
built_in INTEGER NOT NULL COMMENT '是否内置权限模板,1 表示内置',
status VARCHAR(32) NOT NULL COMMENT '权限模板状态',
description VARCHAR(1024) COMMENT '权限模板说明',
CONSTRAINT PK_ap_perm_tpl PRIMARY KEY (permission_key)
) COMMENT='权限模板表,描述 Ambari RBAC、平台入口和 Ranger 资源权限原子';
-- 表:ambari_plus_role_binding
-- 租户角色绑定表。按集群身份域持久化租户角色与授权主体关系。
CREATE TABLE IF NOT EXISTS ambari_plus_role_binding(
binding_key VARCHAR(128) NOT NULL COMMENT '角色绑定唯一标识',
tenant_key VARCHAR(100) NOT NULL COMMENT '租户标识',
cluster_name VARCHAR(255) NOT NULL COMMENT 'Ambari 集群名称,也是 USER / LDAP_GROUP 所属身份域',
role_key VARCHAR(100) NOT NULL COMMENT '角色标识',
subject_type VARCHAR(64) NOT NULL COMMENT '授权主体类型,如 USER、LDAP_GROUP',
subject_name VARCHAR(255) NOT NULL COMMENT '授权主体名称',
status VARCHAR(32) NOT NULL COMMENT '绑定状态',
source VARCHAR(64) NOT NULL COMMENT '绑定来源,如 SYSTEM、MANUAL、SYNC',
description VARCHAR(1024) COMMENT '绑定说明',
created_by VARCHAR(255) COMMENT '创建人',
created_time BIGINT NOT NULL COMMENT '创建时间,Unix 毫秒',
updated_by VARCHAR(255) COMMENT '最近更新人',
updated_time BIGINT NOT NULL COMMENT '最近更新时间,Unix 毫秒',
CONSTRAINT PK_ap_role_bind PRIMARY KEY (binding_key)
) COMMENT='租户角色绑定表,按集群身份域持久化租户角色与授权主体关系';
-- 表:ambari_plus_tenant_audit
-- 租户审计总账。记录 bootstrap、默认集群归属、LDAP 目录写入、Ambari RBAC 下发和 Ranger/Knox 授权下发。
CREATE TABLE IF NOT EXISTS ambari_plus_tenant_audit(
audit_id VARCHAR(128) NOT NULL COMMENT '审计记录唯一标识',
tenant_key VARCHAR(100) COMMENT '租户标识,可为空用于系统级事件',
cluster_name VARCHAR(255) COMMENT 'Ambari 集群名称',
event_type VARCHAR(100) NOT NULL COMMENT '事件类型,如 BOOTSTRAP、LDAP_SYNC、RANGER_POLICY_DEPLOY',
status VARCHAR(32) NOT NULL COMMENT '执行状态,如 SUCCESS、FAILED',
actor VARCHAR(255) COMMENT '操作人或系统主体',
target_type VARCHAR(100) COMMENT '目标类型,如 USER、GROUP、POLICY、TOPOLOGY',
target_name VARCHAR(255) COMMENT '目标名称',
execution_target VARCHAR(100) COMMENT '实际执行目标,如 AMBARI、LDAP、RANGER、KNOX',
binding_id VARCHAR(128) COMMENT '关联的角色绑定或授权绑定标识',
external_id TEXT COMMENT '外部系统返回的对象 ID,如 Ranger policy id',
external_name VARCHAR(255) COMMENT '外部系统对象名称',
message VARCHAR(2048) COMMENT '审计消息或失败原因',
correlation_id VARCHAR(128) COMMENT '全链路关联 ID,用于串联一次页面操作、后台补偿和下游同步',
operation_id VARCHAR(128) COMMENT '控制面写操作 ID,如 LDAP operationId 或授权部署操作 ID',
request_id VARCHAR(128) COMMENT 'Ambari 异步 request id,无异步 request 时为空',
details_json TEXT COMMENT '脱敏后的结构化详情 JSON',
event_time BIGINT NOT NULL COMMENT '事件发生时间,Unix 毫秒',
CONSTRAINT PK_ap_audit PRIMARY KEY (audit_id)
) COMMENT='租户审计总账,记录 bootstrap、LDAP、Ambari RBAC、Ranger 和 Knox 授权下发事件';
-- 表:ambari_plus_perm_ext_ref
-- 权限执行面外部引用表。记录 Ambari RBAC、Ranger policy 等已接管对象及 drift 核对摘要。
CREATE TABLE IF NOT EXISTS ambari_plus_perm_ext_ref(
ref_key VARCHAR(128) NOT NULL COMMENT '外部引用唯一标识,由绑定和外部对象关键字段生成',
tenant_key VARCHAR(100) NOT NULL COMMENT '租户标识',
cluster_name VARCHAR(255) NOT NULL COMMENT 'Ambari 集群名称',
binding_id VARCHAR(128) NOT NULL COMMENT '授权控制面绑定 ID',
object_type VARCHAR(100) NOT NULL COMMENT '权限对象类型',
object_name VARCHAR(255) NOT NULL COMMENT '权限对象名称',
subject_type VARCHAR(64) NOT NULL COMMENT '授权主体类型',
subject_name VARCHAR(255) NOT NULL COMMENT '授权主体名称',
execution_target VARCHAR(100) NOT NULL COMMENT '执行面目标,如 AMBARI_RBAC、RANGER、KNOX',
external_type VARCHAR(100) NOT NULL COMMENT '外部对象类型,如 AMBARI_RBAC_PRIVILEGE、RANGER_POLICY',
external_service VARCHAR(255) COMMENT '外部服务名称,如 Ranger service name',
external_id VARCHAR(255) COMMENT '外部对象 ID,如 Ranger policy id',
external_name VARCHAR(255) COMMENT '外部对象名称,如 Ranger policy name',
desired_signature VARCHAR(128) COMMENT '期望状态摘要',
actual_signature VARCHAR(128) COMMENT '实际状态摘要',
drift_status VARCHAR(32) NOT NULL COMMENT '漂移状态,如 OK、DRIFT、UNKNOWN',
source VARCHAR(64) NOT NULL COMMENT '引用来源,如 AUTHORIZATION_CONTROL_PLANE、IMPORTED',
message VARCHAR(2048) COMMENT '最近核对或修复说明',
last_verified_time BIGINT COMMENT '最近核对时间,Unix 毫秒',
last_reconciled_time BIGINT COMMENT '最近修复时间,Unix 毫秒',
created_by VARCHAR(255) COMMENT '创建人',
created_time BIGINT NOT NULL COMMENT '创建时间,Unix 毫秒',
updated_by VARCHAR(255) COMMENT '最近更新人',
updated_time BIGINT NOT NULL COMMENT '最近更新时间,Unix 毫秒',
CONSTRAINT PK_ap_ext_ref PRIMARY KEY (ref_key)
) COMMENT='权限执行面外部引用表,记录 Ambari RBAC、Ranger policy 等已接管对象及 drift 核对摘要';
-- 索引:用于租户成员查询、角色绑定查询和审计时间线查询。
CREATE INDEX idx_ap_user_cluster ON ambari_plus_user (cluster_name);
CREATE UNIQUE INDEX uq_ap_user_cluster_name ON ambari_plus_user (cluster_name, user_name);
CREATE INDEX idx_ap_user_checkin_last_login ON ambari_plus_user_checkin (last_login_time);
CREATE INDEX idx_ap_member_tenant ON ambari_plus_tenant_member (cluster_name, tenant_key);
CREATE UNIQUE INDEX uq_ap_member_user ON ambari_plus_tenant_member (cluster_name, tenant_key, user_name);
CREATE INDEX idx_ap_rb_tenant ON ambari_plus_role_binding (cluster_name, tenant_key);
CREATE INDEX idx_ap_rb_subject ON ambari_plus_role_binding (cluster_name, subject_type, subject_name);
CREATE INDEX idx_ap_audit_tenant ON ambari_plus_tenant_audit (tenant_key);
CREATE INDEX idx_ap_audit_time ON ambari_plus_tenant_audit (event_time);
CREATE INDEX idx_ap_audit_corr ON ambari_plus_tenant_audit (correlation_id);
CREATE INDEX idx_ap_audit_op ON ambari_plus_tenant_audit (operation_id);
CREATE INDEX idx_ap_ext_cluster ON ambari_plus_perm_ext_ref (cluster_name);
CREATE INDEX idx_ap_ext_binding ON ambari_plus_perm_ext_ref (binding_id);
CREATE INDEX idx_ap_ext_target ON ambari_plus_perm_ext_ref (execution_target, drift_status);
-- 表:ambari_plus_tenant_cluster
-- 租户集群默认归属表。一套集群只归属一个租户,默认 root。
CREATE TABLE IF NOT EXISTS ambari_plus_tenant_cluster(
cluster_name VARCHAR(255) NOT NULL COMMENT 'Ambari 集群名称,作为归属主键',
tenant_key VARCHAR(100) NOT NULL COMMENT '集群所属租户标识,默认 root',
ambari_cluster_id BIGINT COMMENT 'Ambari 内部集群 ID',
ownership_mode VARCHAR(64) NOT NULL COMMENT '归属模式,如 DEFAULT_ROOT、TENANT_BOUND',
status VARCHAR(32) NOT NULL COMMENT '集群归属状态',
source VARCHAR(64) NOT NULL COMMENT '归属来源,如 BOOTSTRAP、SYSTEM',
created_by VARCHAR(255) COMMENT '创建人',
created_time BIGINT NOT NULL COMMENT '创建时间,Unix 毫秒',
updated_by VARCHAR(255) COMMENT '最近更新人',
updated_time BIGINT NOT NULL COMMENT '最近更新时间,Unix 毫秒',
CONSTRAINT PK_ap_tenant_cluster PRIMARY KEY (cluster_name)
) COMMENT='租户集群默认归属表,一套集群只归属一个租户,默认 root';
-- 索引:用于默认集群归属查询和租户总账按集群、绑定过滤。
CREATE INDEX idx_ap_tc_tenant ON ambari_plus_tenant_cluster (tenant_key);
CREATE INDEX idx_ap_tc_status ON ambari_plus_tenant_cluster (status);
CREATE INDEX idx_ap_audit_cluster ON ambari_plus_tenant_audit (cluster_name);
CREATE INDEX idx_ap_audit_binding ON ambari_plus_tenant_audit (binding_id);
-- 基线数据:只初始化 root 租户和内置角色。
-- 用户、成员关系和角色绑定必须带真实 cluster_name,由运行时 bootstrap 按当前 Ambari 集群幂等补齐。
SET @ap_now := CAST(UNIX_TIMESTAMP(CURRENT_TIMESTAMP(3)) * 1000 AS UNSIGNED);
INSERT INTO ambari_plus_tenant(
tenant_key, display_name, description, status, created_by, created_time, updated_by, updated_time
) VALUES (
'root', 'root', '系统内置租户,用于承载默认资源归属和基础管理员关系。', 'ACTIVE',
'Ttbigdata', @ap_now, 'Ttbigdata', @ap_now
) ON DUPLICATE KEY UPDATE
display_name = VALUES(display_name),
description = VALUES(description),
status = 'ACTIVE',
updated_by = 'Ttbigdata',
updated_time = @ap_now;
INSERT INTO ambari_plus_role_def(
role_key, display_name, scope_type, built_in, status, description, created_by, created_time, updated_by, updated_time
) VALUES (
'tenant_admin', '租户管理员', 'TENANT', 1, 'ACTIVE',
'管理租户成员、角色绑定和集群归属。',
'Ttbigdata', @ap_now, 'Ttbigdata', @ap_now
) ON DUPLICATE KEY UPDATE
display_name = VALUES(display_name),
scope_type = VALUES(scope_type),
built_in = VALUES(built_in),
status = 'ACTIVE',
description = VALUES(description),
updated_by = 'Ttbigdata',
updated_time = @ap_now;
-- Ambari Server HA 实例登记与数据库 Lease。
CREATE TABLE IF NOT EXISTS ambari_server_instance(
instance_id VARCHAR(128) NOT NULL COMMENT '稳定 Server 实例 ID,同一安装实例重启后保持不变',
session_id VARCHAR(128) NOT NULL COMMENT '本次 JVM 会话 ID,每次启动重新生成',
host_name VARCHAR(255) NOT NULL COMMENT 'Server 所在主机名',
server_version VARCHAR(64) COMMENT 'Ambari Server 版本',
build_hash VARCHAR(128) COMMENT '构建标识,用于版本一致性检查',
desired_state VARCHAR(32) NOT NULL COMMENT '期望状态,如 ENABLED、DRAINING、DISABLED',
runtime_role VARCHAR(32) NOT NULL COMMENT '运行角色,如 ACTIVE、STANDBY、FENCED',
readiness_reason VARCHAR(512) COMMENT '当前就绪或隔离原因',
last_heartbeat_at TIMESTAMP(3) NULL COMMENT '最近一次数据库心跳时间',
created_at TIMESTAMP(3) NOT NULL COMMENT '实例首次登记时间',
updated_at TIMESTAMP(3) NOT NULL COMMENT '实例最近更新时间',
CONSTRAINT PK_ambari_server_instance PRIMARY KEY (instance_id)
) COMMENT='Ambari Server HA 实例登记表';
CREATE TABLE IF NOT EXISTS ambari_server_lease(
resource_key VARCHAR(64) NOT NULL COMMENT '单例资源键,固定为 CONTROL_PLANE',
cluster_epoch VARCHAR(64) NOT NULL COMMENT 'HA 集群世代,防止旧部署重新加入',
lease_term BIGINT NOT NULL COMMENT '单调递增任期,新持有者获取时递增',
holder_instance_id VARCHAR(128) COMMENT '当前持有者稳定实例 ID',
holder_session_id VARCHAR(128) COMMENT '当前持有者 JVM 会话 ID',
lease_until TIMESTAMP(3) NULL COMMENT '基于数据库时间的 Lease 截止时间',
renewed_at TIMESTAMP(3) NULL COMMENT '最近一次成功续租时间',
transition_id VARCHAR(128) COMMENT '计划切换关联 ID',
updated_at TIMESTAMP(3) NOT NULL COMMENT 'Lease 最近更新时间',
CONSTRAINT PK_ambari_server_lease PRIMARY KEY (resource_key)
) COMMENT='Ambari Server HA 唯一控制面 Lease';
CREATE TABLE IF NOT EXISTS ambari_server_ha_operation(
operation_id VARCHAR(128) NOT NULL,
client_request_id VARCHAR(128) NOT NULL,
operation_type VARCHAR(32) NOT NULL,
status VARCHAR(32) NOT NULL,
phase VARCHAR(64) NOT NULL,
target_host_name VARCHAR(255),
target_instance_id VARCHAR(128),
entry_mode VARCHAR(32),
input_fingerprint VARCHAR(64) NOT NULL,
plan_snapshot LONGTEXT,
error_summary VARCHAR(1024),
created_by VARCHAR(255),
created_at TIMESTAMP(3) NOT NULL,
updated_at TIMESTAMP(3) NOT NULL,
CONSTRAINT PK_ha_operation PRIMARY KEY (operation_id),
CONSTRAINT UQ_ha_operation_client UNIQUE (client_request_id)
) COMMENT='Ambari Server HA 持久化操作';
CREATE TABLE IF NOT EXISTS ambari_server_ha_operation_step(
step_key VARCHAR(256) NOT NULL,
operation_id VARCHAR(128) NOT NULL,
phase VARCHAR(64) NOT NULL,
status VARCHAR(32) NOT NULL,
target_host_name VARCHAR(255),
request_id BIGINT,
task_id BIGINT,
attempt_count INT NOT NULL DEFAULT 0,
idempotency_key VARCHAR(128),
result_summary LONGTEXT,
started_at TIMESTAMP(3) NULL,
ended_at TIMESTAMP(3) NULL,
created_at TIMESTAMP(3) NOT NULL,
updated_at TIMESTAMP(3) NOT NULL,
CONSTRAINT PK_ha_operation_step PRIMARY KEY (step_key),
CONSTRAINT FK_ha_step_operation FOREIGN KEY (operation_id)
REFERENCES ambari_server_ha_operation(operation_id)
) COMMENT='Ambari Server HA 持久化操作步骤';
CREATE TABLE IF NOT EXISTS ambari_agent_certificate(
certificate_serial VARCHAR(64) NOT NULL,
host_name VARCHAR(255) NOT NULL,
certificate_status VARCHAR(16) NOT NULL,
certificate_fingerprint VARCHAR(64) NOT NULL,
issued_term BIGINT,
issued_instance_id VARCHAR(128),
issued_at TIMESTAMP(3) NOT NULL,
revoked_at TIMESTAMP(3) NULL,
updated_at TIMESTAMP(3) NOT NULL,
CONSTRAINT PK_agent_certificate PRIMARY KEY (certificate_serial),
INDEX idx_agent_cert_host (host_name, certificate_status)
);
INSERT INTO ambari_server_lease(
resource_key, cluster_epoch, lease_term, updated_at
) VALUES (
'CONTROL_PLANE', 'UNINITIALIZED', 0, CURRENT_TIMESTAMP(3)
) ON DUPLICATE KEY UPDATE resource_key = VALUES(resource_key);
-- SEC-303-21: signed SBOM inventory and CVE remediation lifecycle.
CREATE TABLE IF NOT EXISTS security_artifact_import_batch(
batch_id VARCHAR(64) NOT NULL, cluster_name VARCHAR(100) NOT NULL,
batch_kind VARCHAR(16) NOT NULL, external_batch_id VARCHAR(128) NOT NULL,
request_digest VARCHAR(64) NOT NULL, result_digest VARCHAR(64) NOT NULL,
result_payload LONGTEXT NOT NULL,
document_format VARCHAR(32), document_ref VARCHAR(1000),
document_digest VARCHAR(64), document_signature_digest VARCHAR(64),
request_signature_digest VARCHAR(64), provenance_digest VARCHAR(64),
provenance_key_id VARCHAR(255), rows_canonical_sha256 VARCHAR(64),
snapshot_scope VARCHAR(128) NOT NULL, row_count INTEGER NOT NULL,
active_slot VARCHAR(64) NOT NULL,
batch_status VARCHAR(16) NOT NULL, created_by VARCHAR(255) NOT NULL,
created_at TIMESTAMP(3) NOT NULL, activated_at TIMESTAMP(3),
generation BIGINT NOT NULL DEFAULT 0,
CONSTRAINT PK_sec_artifact_import_batch PRIMARY KEY (batch_id),
CONSTRAINT UQ_sec_artifact_batch_external UNIQUE (cluster_name, batch_kind, external_batch_id),
CONSTRAINT UQ_sec_art_batch_slot UNIQUE (active_slot),
INDEX idx_sec_artifact_batch_active (cluster_name, batch_kind, snapshot_scope, batch_status)
);
CREATE TABLE IF NOT EXISTS security_artifact_inventory(
artifact_id VARCHAR(64) NOT NULL, import_id VARCHAR(128) NOT NULL, batch_id VARCHAR(64) NOT NULL,
cluster_name VARCHAR(100) NOT NULL,
purl VARCHAR(512) NOT NULL, artifact_name VARCHAR(255) NOT NULL, artifact_version VARCHAR(128) NOT NULL,
artifact_digest VARCHAR(64) NOT NULL, inventory_kind VARCHAR(32) NOT NULL,
bom_ref VARCHAR(512) NOT NULL, parent_bom_ref VARCHAR(512),
deployment_scope_digest VARCHAR(64) NOT NULL,
sbom_format VARCHAR(32) NOT NULL, sbom_ref VARCHAR(1000) NOT NULL,
sbom_digest VARCHAR(64) NOT NULL, sbom_signature VARCHAR(128) NOT NULL,
service_name VARCHAR(128) NOT NULL, component_name VARCHAR(128) NOT NULL, host_name VARCHAR(255) NOT NULL,
package_type VARCHAR(32) NOT NULL, evidence_ref VARCHAR(1000) NOT NULL,
generated_at TIMESTAMP(3) NOT NULL, imported_by VARCHAR(255) NOT NULL, imported_at TIMESTAMP(3) NOT NULL,
generation BIGINT NOT NULL DEFAULT 0,
CONSTRAINT PK_security_artifact_inventory PRIMARY KEY (artifact_id),
CONSTRAINT UQ_sec_artifact_scope UNIQUE (cluster_name, import_id, deployment_scope_digest),
INDEX idx_sec_artifact_purl (cluster_name, purl, artifact_version),
INDEX idx_sec_artifact_sbom (cluster_name, sbom_digest)
);
CREATE TABLE IF NOT EXISTS security_vulnerability_finding(
finding_id VARCHAR(64) NOT NULL, scan_id VARCHAR(128) NOT NULL, batch_id VARCHAR(64) NOT NULL,
cluster_name VARCHAR(100) NOT NULL, cve_id VARCHAR(64) NOT NULL, artifact_id VARCHAR(64) NOT NULL,
deployment_identity_digest VARCHAR(64) NOT NULL, purl VARCHAR(512) NOT NULL,
artifact_version VARCHAR(128) NOT NULL, artifact_digest VARCHAR(64) NOT NULL,
service_name VARCHAR(128) NOT NULL, component_name VARCHAR(128) NOT NULL, host_name VARCHAR(255) NOT NULL,
severity VARCHAR(16) NOT NULL, cvss_score DOUBLE, exposure VARCHAR(32) NOT NULL,
sla_due_at TIMESTAMP(3) NOT NULL, finding_status VARCHAR(32) NOT NULL,
feed_source VARCHAR(255) NOT NULL, feed_digest VARCHAR(64) NOT NULL,
advisory_ref VARCHAR(1000) NOT NULL, evidence_digest VARCHAR(64) NOT NULL,
waiver_approval_id VARCHAR(64), waiver_owner VARCHAR(255), waiver_reason VARCHAR(1000),
waiver_ticket VARCHAR(128), waiver_expires_at TIMESTAMP(3), patch_operation_id VARCHAR(128),
rescan_id VARCHAR(128), rescan_digest VARCHAR(64), rescan_evidence_ref VARCHAR(1000),
first_observed_at TIMESTAMP(3) NOT NULL, last_observed_at TIMESTAMP(3) NOT NULL,
resolved_at TIMESTAMP(3), imported_by VARCHAR(255) NOT NULL, generation BIGINT NOT NULL DEFAULT 0,
CONSTRAINT PK_security_vulnerability PRIMARY KEY (finding_id),
CONSTRAINT UQ_sec_vulnerability_scope UNIQUE (cluster_name, cve_id, deployment_identity_digest),
INDEX idx_sec_vuln_status (cluster_name, finding_status, sla_due_at),
INDEX idx_sec_vuln_operation (cluster_name, patch_operation_id)
);
CREATE TABLE IF NOT EXISTS security_artifact_patch_operation(
operation_id VARCHAR(128) NOT NULL, cluster_name VARCHAR(100) NOT NULL,
request_digest VARCHAR(64) NOT NULL, bundle_id VARCHAR(128) NOT NULL,
request_payload LONGTEXT NOT NULL,
finding_snapshot LONGTEXT NOT NULL, version_update_run_id VARCHAR(128),
operation_status VARCHAR(32) NOT NULL, reconcile_cursor VARCHAR(64),
created_by VARCHAR(255) NOT NULL,
created_at TIMESTAMP(3) NOT NULL, updated_at TIMESTAMP(3) NOT NULL,
generation BIGINT NOT NULL DEFAULT 0,
CONSTRAINT PK_sec_artifact_patch_operation PRIMARY KEY (operation_id),
INDEX idx_sec_patch_cluster_status (cluster_name, operation_status),
INDEX idx_sec_patch_version_run (version_update_run_id)
);
INSERT INTO ambari_server_lease(
resource_key, cluster_epoch, lease_term, updated_at
) VALUES (
'CONTROL_PLANE_MUTATION', 'GLOBAL', 0, CURRENT_TIMESTAMP(3)
) ON DUPLICATE KEY UPDATE resource_key = VALUES(resource_key);
-- SEC-303-22: periodic access review governance.
CREATE TABLE IF NOT EXISTS security_access_review_campaign(
campaign_id VARCHAR(64) NOT NULL, campaign_key VARCHAR(128) NOT NULL, cluster_name VARCHAR(100) NOT NULL,
campaign_name VARCHAR(255) NOT NULL, scope_digest VARCHAR(64) NOT NULL,
campaign_owner VARCHAR(255) NOT NULL, reviewer VARCHAR(255) NOT NULL, review_period_days INTEGER NOT NULL,
due_at TIMESTAMP(3) NOT NULL, escalate_at TIMESTAMP(3) NOT NULL, campaign_status VARCHAR(32) NOT NULL,
data_status VARCHAR(32) NOT NULL, source_evidence_ref VARCHAR(1000) NOT NULL,
connector_id VARCHAR(128) NOT NULL, inventory_id VARCHAR(128) NOT NULL,
inventory_collected_at TIMESTAMP(3) NOT NULL, inventory_expires_at TIMESTAMP(3) NOT NULL,
attestation_key_id VARCHAR(64) NOT NULL, attestation_signature VARCHAR(128) NOT NULL,
created_by VARCHAR(255) NOT NULL, created_at TIMESTAMP(3) NOT NULL, closed_at TIMESTAMP(3),
audit_event_id VARCHAR(64) NOT NULL, generation BIGINT NOT NULL DEFAULT 0,
CONSTRAINT PK_sec_review_campaign PRIMARY KEY (campaign_id),
CONSTRAINT UQ_sec_review_campaign UNIQUE (cluster_name, campaign_key),
INDEX idx_sec_review_campaign_due (cluster_name, campaign_status, due_at)
);
CREATE TABLE IF NOT EXISTS security_access_review_item(
item_id VARCHAR(64) NOT NULL, campaign_id VARCHAR(64) NOT NULL, cluster_name VARCHAR(100) NOT NULL,
identity_type VARCHAR(32) NOT NULL, subject_ref VARCHAR(512) NOT NULL,
entitlement_type VARCHAR(32) NOT NULL, entitlement_ref VARCHAR(1000) NOT NULL,
entitlement_digest VARCHAR(64) NOT NULL, responsible_owner VARCHAR(255) NOT NULL,
evidence_status VARCHAR(32) NOT NULL, evidence_ref VARCHAR(1000) NOT NULL,
recommended_action VARCHAR(32) NOT NULL, decision_status VARCHAR(32) NOT NULL,
latest_decision_id VARCHAR(64), remediation_action VARCHAR(64) NOT NULL,
remediation_status VARCHAR(32) NOT NULL, remediation_operation_id VARCHAR(64),
created_at TIMESTAMP(3) NOT NULL, updated_at TIMESTAMP(3) NOT NULL, generation BIGINT NOT NULL DEFAULT 0,
CONSTRAINT PK_sec_review_item PRIMARY KEY (item_id),
CONSTRAINT UQ_sec_review_item UNIQUE (campaign_id, identity_type, subject_ref, entitlement_digest),
INDEX idx_sec_review_item_decision (campaign_id, decision_status),
INDEX idx_sec_review_item_remed (cluster_name, remediation_status)
);
CREATE TABLE IF NOT EXISTS security_access_review_decision(
decision_id VARCHAR(64) NOT NULL, item_id VARCHAR(64) NOT NULL, campaign_id VARCHAR(64) NOT NULL,
cluster_name VARCHAR(100) NOT NULL, decision_sequence BIGINT NOT NULL,
decision_status VARCHAR(32) NOT NULL, rationale VARCHAR(1000) NOT NULL,
reviewer VARCHAR(255) NOT NULL, request_digest VARCHAR(64) NOT NULL,
decided_at TIMESTAMP(3) NOT NULL, audit_event_id VARCHAR(64) NOT NULL,
CONSTRAINT PK_sec_review_decision PRIMARY KEY (decision_id),
CONSTRAINT UQ_sec_review_dec_seq UNIQUE (item_id, decision_sequence),
CONSTRAINT UQ_sec_review_dec_digest UNIQUE (item_id, request_digest),
INDEX idx_sec_review_dec_campaign (campaign_id, decided_at)
);
CREATE TABLE IF NOT EXISTS security_access_review_exception(
exception_id VARCHAR(64) NOT NULL, item_id VARCHAR(64) NOT NULL, decision_id VARCHAR(64) NOT NULL,
campaign_id VARCHAR(64) NOT NULL, cluster_name VARCHAR(100) NOT NULL,
exception_owner VARCHAR(255) NOT NULL, reason_text VARCHAR(1000) NOT NULL,
change_ticket VARCHAR(128) NOT NULL, approval_id VARCHAR(64) NOT NULL,
approved_by VARCHAR(255) NOT NULL, approved_at TIMESTAMP(3) NOT NULL, expires_at TIMESTAMP(3) NOT NULL,
exception_status VARCHAR(32) NOT NULL, audit_event_id VARCHAR(64) NOT NULL,
generation BIGINT NOT NULL DEFAULT 0,
CONSTRAINT PK_sec_review_exception PRIMARY KEY (exception_id),
CONSTRAINT UQ_sec_review_exception UNIQUE (item_id, decision_id),
INDEX idx_sec_review_exc_expiry (cluster_name, exception_status, expires_at)
);
CREATE TABLE IF NOT EXISTS security_access_review_remediation(
operation_id VARCHAR(64) NOT NULL, campaign_id VARCHAR(64) NOT NULL, cluster_name VARCHAR(100) NOT NULL,
request_digest VARCHAR(64) NOT NULL, result_digest VARCHAR(64), approval_id VARCHAR(64) NOT NULL,
connector_id VARCHAR(128), connector_execution_id VARCHAR(128),
connector_started_at TIMESTAMP(3), connector_finished_at TIMESTAMP(3),
attestation_key_id VARCHAR(64), attestation_signature VARCHAR(128),
action_mode VARCHAR(32) NOT NULL, item_count INTEGER NOT NULL, operation_status VARCHAR(32) NOT NULL,
requested_by VARCHAR(255) NOT NULL, owner_instance_id VARCHAR(128), owner_session_id VARCHAR(128),
cluster_epoch VARCHAR(128), owner_term BIGINT, mutation_lock_term BIGINT,
created_at TIMESTAMP(3) NOT NULL, started_at TIMESTAMP(3), finished_at TIMESTAMP(3),
evidence_ref VARCHAR(1000), failure_summary VARCHAR(1000), audit_event_id VARCHAR(64) NOT NULL,
generation BIGINT NOT NULL DEFAULT 0,
CONSTRAINT PK_sec_review_remediation PRIMARY KEY (operation_id),
CONSTRAINT UQ_sec_review_remediation UNIQUE (cluster_name, request_digest),
INDEX idx_sec_review_remed_state (cluster_name, operation_status, created_at)
);
-- SEC-303-08/09/19 shared security governance, WORM ledger and SIEM outbox.
CREATE TABLE IF NOT EXISTS security_role_binding(
binding_id VARCHAR(64) NOT NULL, cluster_name VARCHAR(100) NOT NULL,
role_name VARCHAR(32) NOT NULL, group_name VARCHAR(255) NOT NULL,
binding_status VARCHAR(16) NOT NULL, generation BIGINT NOT NULL DEFAULT 0,
CONSTRAINT PK_security_role_binding PRIMARY KEY (binding_id),
CONSTRAINT UQ_sec_role_cluster UNIQUE (cluster_name, role_name, group_name)
);
CREATE TABLE IF NOT EXISTS security_approval_request(
approval_id VARCHAR(64) NOT NULL, cluster_name VARCHAR(100) NOT NULL,
operation_id VARCHAR(128) NOT NULL, action_name VARCHAR(96) NOT NULL,
target_ref VARCHAR(512) NOT NULL, request_digest VARCHAR(64) NOT NULL,
requester VARCHAR(255) NOT NULL, approver VARCHAR(255),
reason_text VARCHAR(1000) NOT NULL, change_ticket VARCHAR(128) NOT NULL,
approval_status VARCHAR(16) NOT NULL, expires_at TIMESTAMP(3) NOT NULL,
created_at TIMESTAMP(3) NOT NULL, approved_at TIMESTAMP(3),
consumed_at TIMESTAMP(3), owner_instance_id VARCHAR(128),
owner_session_id VARCHAR(128), cluster_epoch VARCHAR(128), owner_term BIGINT,
generation BIGINT NOT NULL DEFAULT 0,
CONSTRAINT PK_security_approval PRIMARY KEY (approval_id),
CONSTRAINT UQ_sec_approval_op UNIQUE (cluster_name, operation_id)
);
CREATE TABLE IF NOT EXISTS security_audit_chain_head(
cluster_name VARCHAR(100) NOT NULL, last_sequence BIGINT NOT NULL DEFAULT 0,
last_hash VARCHAR(64) NOT NULL, generation BIGINT NOT NULL DEFAULT 0,
CONSTRAINT PK_security_audit_head PRIMARY KEY (cluster_name)
);
CREATE TABLE IF NOT EXISTS security_audit_ledger(
event_id VARCHAR(64) NOT NULL, cluster_name VARCHAR(100) NOT NULL,
event_type VARCHAR(96) NOT NULL, operation_id VARCHAR(128) NOT NULL,
request_id VARCHAR(128), task_id VARCHAR(128), knox_request_id VARCHAR(128),
risk_level VARCHAR(16) NOT NULL DEFAULT 'MEDIUM',
disposition_status VARCHAR(24) NOT NULL DEFAULT 'OPEN',
chain_sequence BIGINT NOT NULL, prev_hash VARCHAR(64) NOT NULL,
record_hash VARCHAR(64) NOT NULL, record_signature VARCHAR(128) NOT NULL,
actor VARCHAR(255) NOT NULL, owner_term BIGINT, payload_digest VARCHAR(64) NOT NULL,
canonical_payload LONGTEXT NOT NULL, created_at TIMESTAMP(3) NOT NULL,
CONSTRAINT PK_security_audit_ledger PRIMARY KEY (event_id),
CONSTRAINT UQ_sec_audit_sequence UNIQUE (cluster_name, chain_sequence),
CONSTRAINT UQ_sec_audit_hash UNIQUE (cluster_name, record_hash),
CONSTRAINT UQ_sec_audit_operation UNIQUE (cluster_name, event_type, operation_id),
INDEX idx_sec_audit_correlation
(cluster_name, operation_id, request_id, task_id, knox_request_id)
);
CREATE TABLE IF NOT EXISTS security_event_outbox(
outbox_id VARCHAR(64) NOT NULL, event_id VARCHAR(64) NOT NULL,
cluster_name VARCHAR(100) NOT NULL, destination_id VARCHAR(64) NOT NULL,
event_type VARCHAR(96) NOT NULL, risk_level VARCHAR(16) NOT NULL,
disposition_status VARCHAR(24) NOT NULL, payload_digest VARCHAR(64) NOT NULL,
canonical_payload LONGTEXT NOT NULL, delivery_status VARCHAR(24) NOT NULL,
attempt_count INT NOT NULL DEFAULT 0, next_retry_at TIMESTAMP(3) NOT NULL,
receipt_id VARCHAR(128), receipt_digest VARCHAR(64), last_error_code VARCHAR(96),
created_at TIMESTAMP(3) NOT NULL, updated_at TIMESTAMP(3) NOT NULL,
delivered_at TIMESTAMP(3), generation BIGINT NOT NULL DEFAULT 0,
CONSTRAINT PK_security_event_outbox PRIMARY KEY (outbox_id),
CONSTRAINT UQ_sec_event_destination UNIQUE (destination_id, event_id),
CONSTRAINT FK_sec_event_ledger FOREIGN KEY (event_id)
REFERENCES security_audit_ledger(event_id),
INDEX idx_sec_event_outbox_due (delivery_status, next_retry_at),
INDEX idx_sec_event_outbox_cluster (cluster_name, created_at)
);
CREATE TABLE IF NOT EXISTS security_event_dead_letter(
dead_letter_id VARCHAR(64) NOT NULL, outbox_id VARCHAR(64) NOT NULL,
event_id VARCHAR(64) NOT NULL, cluster_name VARCHAR(100) NOT NULL,
attempts INT NOT NULL DEFAULT 0, last_error_code VARCHAR(96) NOT NULL,
operator_status VARCHAR(24) NOT NULL, created_at TIMESTAMP(3) NOT NULL,
updated_at TIMESTAMP(3) NOT NULL, generation BIGINT NOT NULL DEFAULT 0,
CONSTRAINT PK_security_event_dead PRIMARY KEY (dead_letter_id),
CONSTRAINT UQ_sec_dead_outbox UNIQUE (outbox_id),
CONSTRAINT FK_sec_dead_outbox FOREIGN KEY (outbox_id)
REFERENCES security_event_outbox(outbox_id),
INDEX idx_sec_event_dead_cluster (cluster_name, operator_status)
);
-- SEC-303-15: signed compatibility evidence profiles.
CREATE TABLE IF NOT EXISTS security_compatibility_profile(
row_id VARCHAR(64) NOT NULL, profile_id VARCHAR(128) NOT NULL, cluster_name VARCHAR(100) NOT NULL,
product_name VARCHAR(64) NOT NULL, product_version_range VARCHAR(255) NOT NULL,
os_family VARCHAR(64) NOT NULL, os_version_range VARCHAR(255) NOT NULL,
jdk_version_range VARCHAR(255) NOT NULL, browser_name VARCHAR(64) NOT NULL,
browser_version_range VARCHAR(255) NOT NULL, identity_provider VARCHAR(64) NOT NULL,
identity_version_range VARCHAR(255) NOT NULL, service_combination VARCHAR(1000) NOT NULL,
compatibility_status VARCHAR(32) NOT NULL, evidence_ref VARCHAR(1000) NOT NULL,
profile_digest VARCHAR(64) NOT NULL, profile_signature VARCHAR(128) NOT NULL,
valid_from TIMESTAMP(3) NOT NULL, expires_at TIMESTAMP(3) NOT NULL,
imported_by VARCHAR(255) NOT NULL, imported_at TIMESTAMP(3) NOT NULL,
generation BIGINT NOT NULL DEFAULT 0,
CONSTRAINT PK_sec_compat_profile PRIMARY KEY (row_id),
CONSTRAINT UQ_sec_compat_profile UNIQUE (cluster_name, profile_id),
INDEX idx_sec_compat_product (cluster_name, product_name)
);
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583