Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
80 changes: 66 additions & 14 deletions ci/RPM_BUILD_FLOW.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
| **4. Frontend** | 前端编译 | `./ci/docker/manage_container.sh exec "./ci/script/build_frontend.sh"` | 默认 | Container | 编译前端代码 |
| **5. Backend** | 后端编译 | `./ci/docker/manage_container.sh exec "./ci/script/build_backend.sh"` | 默认 | Container | 编译后端代码 |
| **6. Package** | RPM 打包 | `./ci/docker/manage_container.sh exec "./ci/script/build_rpm_pkg.sh"` | 默认 | Container | 打包 RPM 文件 |
| **7. Cleanup** | 销毁容器 | `./ci/docker/manage_container.sh stop` | **Always / Any** | Host | 清理容器资源 |
| **7. Cleanup** | 销毁容器 | `./ci/docker/manage_container.sh stop` | **Always** | Host | 无论成功或失败都执行,清理容器资源 |

---

Expand All @@ -25,15 +25,15 @@
| 层次 | 职责 | 环境说明 |
| :--- | :--- | :--- |
| **Host (GoCD Agent)** | 源码同步、生命周期管理 | 无 `sudo` 权限,仅需安装 `docker` |
| **Container (Build Image)** | 编译前端、编译后端、RPM 打包 | 预装 JDK8, Maven (Aliyun), Node18, pnpm10 |
| **Container (Build Image)** | 编译前端、编译后端、RPM 打包 | 预装 JDK8, Maven 3.6.3 (仓库使用 Aliyun 镜像), Node18, pnpm10 |

### 路径映射定义

| 定义项 | Host 路径 (GoCD Agent) | Container 路径 | 说明 |
| :--- | :--- | :--- | :--- |
| **工作目录** | `/var/lib/go-agent/pipelines/odc/` | `/root/odc` | 流水线根目录 |
| **代码目录** | `source_code/` | `/root/odc/source_code` | 挂载项目源码 |
| **最终产物** | `source_code/*.rpm` | `/root/odc/source_code/*.rpm` | 构建完成的 RPM 包 |
| **代码目录** | 项目根目录(如 `$PROJECT_ROOT`) | `/root/odc/source_code` | 整个项目根目录挂载到容器内 |
| **最终产物** | `*.rpm` | `/root/odc/source_code/*.rpm` | 构建完成的 RPM 包(位于项目根目录) |

---

Expand Down Expand Up @@ -76,7 +76,7 @@ flowchart TD
| :--- | :--- | :--- |
| **基础镜像** | Ubuntu 22.04 | 更好的兼容性与国内源支持 |
| **Java 环境** | OpenJDK 8 | 后端编译必需 |
| **Maven 环境** | Maven 3.6.3 | **配置 Aliyun 镜像源加速** |
| **Maven 环境** | Maven 3.6.3 | **从华为云镜像下载,Maven 仓库配置 Aliyun 镜像源加速** |
| **Node.js 环境** | Node.js 18.20.0 | 满足 pnpm 10 运行要求 |
| **前端工具** | pnpm 10.28.1 | **配置 npmmirror 镜像源加速** |
| **系统工具** | `rpm`, `file`, `git`, `xz-utils` | 打包及工具链 |
Expand All @@ -98,18 +98,44 @@ docker push reg.actiontech.com/actiontech-dev/odc/build-env:1.0
> 1. 上述镜像是流水线的默认配置。
> 2. 若需在 GoCD 中临时切换镜像,请设置环境变量 `ODC_BUILD_IMAGE`。
> 3. 若只需修改部分参数,可单独设置 `ODC_REGISTRY` 或 `ODC_TAG`。

### 3.2 容器启动时的环境变量传递

容器启动时(`manage_container.sh start`),会自动将以下环境变量传递到容器内:

- **必需变量**:
- `IS_IN_CONTAINER=1`:标识运行在容器内
- `SYNC_SUBMODULE=1`:启用子模块同步
- `BUILD_FRONTEND=1`:启用前端构建

- **可配置变量**(从 Host 环境继承,未设置时使用默认值):
- `RPM_RELEASE`:默认当前日期 `$(date +%Y%m%d)`
- `ODC_UI_BRANCH`:默认 `dev-4.3.4-v2`(容器启动时的后备值)
- `ODC_SERVER_BRANCH`:默认 `test/build_rpm`(容器启动时的后备值)
- `ODC_UI_URL`、`ODC_BUILD_RESOURCE_URL`、`ODC_BUILD_IMAGE`

> **重要**:容器启动时使用的默认值与 `env_init.sh` 中的标准默认值可能不同。建议在 GoCD 中显式设置这些环境变量,或在步骤 1(Switch Branches)中通过 `env_init.sh` 统一初始化。

---

## 4. 关键脚本说明

### 4.1 分支切换 (`ci/script/switch_branches.sh`)
在主机上执行,负责:
- **环境变量输出**: 初始化环境变量默认值并打印关键环境变量
- **后端分支切换**: 切换到 `ODC_SERVER_BRANCH` 指定的分支(默认 `test/build_rpm`)
- **前端分支切换**: 通过子模块同步切换到 `ODC_UI_BRANCH` 指定的分支(默认 `dev-4.3.4-v2`)
- **后端分支切换**: 切换到 `ODC_SERVER_BRANCH` 指定的分支(默认 `dev/4.3.4`,由 `env_init.sh` 设置)
- **前端分支切换**: 通过子模块同步切换到 `ODC_UI_BRANCH` 指定的分支(默认 `dev-4.3.4`,由 `env_init.sh` 设置)

> **注意**:如果未设置环境变量,`switch_branches.sh` 和 `manage_container.sh` 中会使用后备默认值(`test/build_rpm` 和 `dev-4.3.4-v2`),但 `env_init.sh` 中的标准默认值是 `dev/4.3.4` 和 `dev-4.3.4`。建议在 GoCD 中显式设置这些环境变量以避免混淆。

### 4.2 生命周期管理 (`ci/docker/manage_container.sh`)
- **start**: 自动拉取远程镜像,启动常驻容器,并初始化 Git `safe.directory` 权限。
- **start**: 自动拉取远程镜像,启动常驻容器,并初始化 Git `safe.directory` 权限。启动时会传递以下环境变量到容器:
- `IS_IN_CONTAINER=1`
- `RPM_RELEASE`(默认当前日期)
- `ODC_UI_BRANCH`(默认 `dev-4.3.4-v2`)
- `ODC_SERVER_BRANCH`(默认 `test/build_rpm`)
- `ODC_UI_URL`、`ODC_BUILD_RESOURCE_URL`、`ODC_BUILD_IMAGE`
- `SYNC_SUBMODULE=1`、`BUILD_FRONTEND=1`
- **exec**: 在运行中的容器内执行指定命令,并实时流式输出日志。
- **stop**: 停止并销毁容器,确保 Agent 环境整洁。

Expand All @@ -119,7 +145,22 @@ docker push reg.actiontech.com/actiontech-dev/odc/build-env:1.0
- **环境变量打印**: 以表格形式打印所有关键环境变量
- **系统环境检查**: 检查 OS、系统工具、Java、Maven、Node 等依赖

### 4.4 本地一键构建 (`ci/docker/run_build.sh`)
### 4.4 前端构建 (`ci/script/build_frontend.sh`)
在容器内执行,负责:
- **前端编译**: 使用 pnpm 编译前端代码,生成前端构建产物

### 4.5 后端构建 (`ci/script/build_backend.sh`)
在容器内执行,包含以下步骤:
- **安装本地依赖**: 安装项目所需的本地库依赖
- **准备 Obclient 驱动**: 从 `build-resource` 子模块复制 `obclient.tar.gz` 到 `import/` 目录(支持 x86_64 和 aarch64 架构)
- **编译后端 JAR**: 使用 Maven 编译后端核心 JAR 文件(支持通过 `BUILD_PROFILE` 指定 Maven Profile)

### 4.6 RPM 打包 (`ci/script/build_rpm_pkg.sh`)
在容器内执行,包含以下步骤:
- **构建 RPM 包**: 使用 Maven 和 RPM 工具构建 RPM 安装包
- **整理构建产物**: 组织并整理构建生成的 RPM 文件

### 4.7 本地一键构建 (`ci/docker/run_build.sh`)
封装了从 Host 端分支切换到容器内全流程构建的逻辑,用于本地开发环境快速验证。

---
Expand All @@ -128,8 +169,19 @@ docker push reg.actiontech.com/actiontech-dev/odc/build-env:1.0

| 变量名 | 默认值 | 用途说明 |
| :--- | :--- | :--- |
| `RPM_RELEASE` | 当前日期 | RPM 包的 Release 号 |
| `BUILD_PROFILE` | - | Maven Profile (如 `oss`) |
| `FETCH_FROM_OSS` | `0` | 是否从 OSS 获取 `obclient.tar.gz` |
| `IS_IN_CONTAINER` | `1` | 标识当前运行在容器内 |
| `CI` | `true` | 开启工具链的非交互模式 |
| `RPM_RELEASE` | 当前日期 (YYYYMMDD) | RPM 包的 Release 号 |
| `ODC_SERVER_BRANCH` | `dev/4.3.4` | 后端代码分支(`env_init.sh` 中的标准默认值) |
| `ODC_UI_BRANCH` | `dev-4.3.4` | 前端代码分支(`env_init.sh` 中的标准默认值) |
| `ODC_UI_URL` | `https://github.com/actiontech/odc-client.git` | 前端子模块的 Git 仓库地址 |
| `ODC_BUILD_RESOURCE_URL` | `https://github.com/winfredLIN/odc-build-resource.git` | build-resource 子模块的 Git 仓库地址 |
| `ODC_BUILD_IMAGE` | `reg.actiontech.com/actiontech-dev/odc/build-env:1.0` | 构建容器镜像名称 |
| `ODC_REGISTRY` | `reg.actiontech.com` | Docker 镜像仓库地址(用于构建 `ODC_BUILD_IMAGE`) |
| `ODC_REPOSITORY` | `actiontech-dev/odc/build-env` | Docker 镜像仓库路径(用于构建 `ODC_BUILD_IMAGE`) |
| `ODC_TAG` | `1.0` | Docker 镜像标签(用于构建 `ODC_BUILD_IMAGE`) |
| `SYNC_SUBMODULE` | `1` | 是否同步子模块(1=是,0=否) |
| `BUILD_FRONTEND` | `1` | 是否构建前端(1=是,0=否) |
| `BUILD_PROFILE` | 无(可选) | Maven Profile,如 `oss`。不设置则不使用 Profile |
| `FETCH_FROM_OSS` | `0` | 是否从 OSS 获取 `obclient.tar.gz`(当前未实现,功能预留) |
| `IS_IN_CONTAINER` | `1` | 标识当前运行在容器内(由容器启动脚本自动设置) |
| `CI` | `true` | 开启工具链的非交互模式(在 Dockerfile 中设置) |
| `GO_PIPELINE_NAME` | 无 | GoCD 流水线名称(用于生成容器名称,默认容器名为 `odc-builder`) |
47 changes: 47 additions & 0 deletions ci/docker/IMAGE_CONFIG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# ODC 构建镜像配置说明

本文档说明构建镜像中的配置与构建依赖的对应关系。

## 镜像信息

- **镜像名称**: `reg.actiontech.com/actiontech-dev/odc/build-env:1.0`
- **基础镜像**: Ubuntu 22.04
- **用途**: ODC RPM 包构建流水线

## 构建依赖配置对照表

| 构建依赖 | 镜像配置 | 版本 | 用途说明 |
| :--- | :--- | :--- | :--- |
| **Java 环境** | `openjdk-8-jdk` (apt 安装) | OpenJDK 8 | 后端代码编译 |
| **Maven** | 从华为云镜像下载安装 | 3.6.3 | Java 项目构建工具 |
| **Maven 仓库** | 配置阿里云镜像源 (`/root/.m2/settings.xml`) | - | 加速 Maven 依赖下载 |
| **Node.js** | 从清华镜像下载安装 | 18.20.0 | 前端构建运行时 |
| **pnpm** | 通过 npm 全局安装 | 10.28.1 | 前端包管理工具 |
| **pnpm 仓库** | 配置 npmmirror 镜像源 | - | 加速前端依赖下载 |
| **RPM 工具** | `rpm` (apt 安装) | - | RPM 包构建 |
| **Git** | `git` (apt 安装) | - | 代码版本管理 |
| **系统工具** | `file`, `curl`, `zip`, `unzip`, `make`, `gcc`, `g++`, `xz-utils`, `ca-certificates` | - | 构建过程所需的基础工具 |

## 环境变量配置

| 环境变量 | 值 | 说明 |
| :--- | :--- | :--- |
| `JAVA_HOME` | `/usr/lib/jvm/java-8-openjdk-amd64` | Java 安装路径 |
| `MAVEN_HOME` | `/usr/local/maven` | Maven 安装路径 |
| `NODE_VERSION` | `18.20.0` | Node.js 版本 |
| `PATH` | `$MAVEN_HOME/bin:$PATH` | 包含 Maven 可执行文件路径 |
| `CI` | `true` | 启用非交互模式 |

## 镜像源配置

| 工具 | 镜像源 | 说明 |
| :--- | :--- | :--- |
| **Ubuntu APT** | `mirrors.aliyun.com` | 系统包管理器镜像源 |
| **Maven 仓库** | `https://maven.aliyun.com/repository/public` | Maven 依赖下载镜像源 |
| **Node.js** | `mirrors.tuna.tsinghua.edu.cn` | Node.js 二进制下载镜像源 |
| **npm/pnpm** | `https://registry.npmmirror.com` | npm 包注册表镜像源 |

## 工作目录

- **工作目录**: `/root/odc`
- **默认命令**: `/bin/bash`
175 changes: 175 additions & 0 deletions docs/add_a_new_plugin_how_to.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
# 如何新增一个数据库插件 (以 SQLServer 为例)

本文档旨在指导开发者如何在 ODC 中新增一个数据库插件,并以 SQLServer 的实现作为参考。

## 1. 架构概述

ODC 的数据库适配遵循“逻辑下沉、接口隔离”原则,主要分为以下几个层次:

- **`libs/db-browser` (基础适配层)**:提供数据库方言的原子操作,如元数据查询(Schema)、SQL 生成(Editor)、SQL 模板(Template)等。
- **`server/plugins` (插件扩展层)**:基于 PF4J 机制,将 `db-browser` 的能力封装为 ODC Server 可用的扩展点(Extension Point)。
- **`server/odc-core` (核心逻辑层)**:处理 SQL 拆分(SqlSplitter)等跨模块的基础能力。

---

## 2. 基础适配层:`libs/db-browser`

在该层中,我们需要实现 SQLServer 的方言适配逻辑。

### 2.1 目录结构与文件说明

```text
libs/db-browser/src/main/java/com/oceanbase/tools/dbbrowser/
├── schema/sqlserver/
│ ├── SqlServerSchemaAccessor.java
│ └── SqlServerSchemaUtil.java
├── editor/sqlserver/
│ ├── SqlServerColumnEditor.java
│ ├── SqlServerConstraintEditor.java
│ ├── SqlServerIndexEditor.java
│ ├── SqlServerMViewEditor.java
│ ├── SqlServerObjectOperator.java
│ ├── SqlServerPartitionEditor.java
│ ├── SqlServerSequenceEditor.java
│ ├── SqlServerSynonymEditor.java
│ ├── SqlServerTableEditor.java
│ ├── SqlServerTriggerEditor.java
│ └── SqlServerViewEditor.java
├── template/sqlserver/
│ ├── SqlServerFunctionTemplate.java
│ ├── SqlServerProcedureTemplate.java
│ ├── SqlServerTriggerTemplate.java
│ └── SqlServerViewTemplate.java
└── util/
├── SqlServerSqlBuilder.java
└── StringUtils.java (工具类增强)
```

| 文件名 | 作用说明 |
| :--- | :--- |
| `SqlServerSchemaAccessor.java` | 实现 `DBSchemaAccessor` 接口,通过系统视图查询表、列、索引、约束等元数据。 |
| `SqlServerSchemaUtil.java` | 封装 SQLServer 特有的元数据处理工具方法。 |
| `SqlServerTableEditor.java` | 实现 `DBTableEditor`,负责生成表的 `CREATE`, `ALTER`, `DROP`, `RENAME` 等 DDL。 |
| `SqlServerColumnEditor.java` | 负责生成列相关的 DDL 语句。 |
| `SqlServerIndexEditor.java` | 负责生成索引相关的 DDL 语句。 |
| `SqlServerConstraintEditor.java` | 负责生成约束(主键、外键、唯一键、Check)相关的 DDL 语句。 |
| `SqlServerObjectOperator.java` | 实现 `DBObjectOperator`,执行通用的数据库对象操作(如删除、统计等)。 |
| `SqlServerFunctionTemplate.java` | 提供新建函数时的初始 SQL 模板。 |
| `SqlServerSqlBuilder.java` | 继承 `SqlBuilder`,处理 SQLServer 特有的标识符引用(`[]`)和值转义。 |
| `StringUtils.java` | 增加 `quoteSqlServerIdentifier` 和 `quoteSqlServerValue` 等工具方法。 |

### 2.2 核心逻辑实现

- **元数据访问**: SQLServer 支持 `database.schema` 结构。为了兼容 ODC 的单层 Schema 模型,我们将 `database.schema` 组合作为一个统一的 `schemaName` 返回。
- **SQL 生成**: 使用 `SqlServerSqlBuilder` 确保生成的 SQL 符合 SQLServer 语法规范。

---

## 3. 业务扩展层:`server/plugins`

该层负责将 `db-browser` 的能力注册到 ODC 插件系统中。

### 3.1 连接插件 (Connect Plugin)

**目录结构**: `server/plugins/connect-plugin-sqlserver/src/main/java/com/oceanbase/odc/plugin/connect/sqlserver/`

| 文件名 | 作用说明 |
| :--- | :--- |
| `SqlServerConnectionPlugin.java` | 插件入口类,定义插件 ID 和扩展点。 |
| `SqlServerConnectionExtension.java` | 实现 `ConnectionExtensionPoint`,处理驱动加载、连接测试。 |
| `SqlServerJdbcUrlParser.java` | 实现 `JdbcUrlParser`,解析 SQLServer JDBC URL 属性。 |
| `SqlServerSessionExtension.java` | 实现 `SessionExtensionPoint`,处理会话初始化、Schema 切换(`USE`)、获取连接 ID(`@@SPID`)。 |
| `SqlServerInformationExtension.java` | 提供数据库版本、特性支持等信息。 |
| `SqlServerDiagnoseExtensionPoint.java` | 实现 SQL 诊断、执行计划获取等功能。 |

### 3.2 Schema 插件 (Schema Plugin)

**目录结构**: `server/plugins/schema-plugin-sqlserver/src/main/java/com/oceanbase/odc/plugin/schema/sqlserver/`

| 文件名 | 作用说明 |
| :--- | :--- |
| `SqlServerSchemaPlugin.java` | 实现 `BaseSchemaPlugin`,注册 SQLServer 的 Schema 访问能力。 |
| `SqlServerTableExtension.java` | 将 `db-browser` 的 `SqlServerSchemaAccessor` 桥接到 ODC 的表管理接口。 |
| `SqlServerDatabaseExtension.java` | 处理数据库/Schema 列表的获取。 |
| `SqlServerViewExtension.java` | 处理视图元数据的获取。 |
| `SqlServerFunctionExtension.java` | 处理函数元数据的获取。 |

---

## 4. 核心逻辑增强:`server/odc-core`

### 4.1 SQL 拆分器 (SqlSplitter)

**路径**: `server/odc-core/src/main/java/com/oceanbase/odc/core/sql/split/SqlServerSqlSplitter.java`

| 文件名 | 作用说明 |
| :--- | :--- |
| `SqlServerSqlSplitter.java` | 实现 SQLServer 脚本拆分逻辑,支持 `GO` 分隔符,识别 `BEGIN...END` 块以避免错误切分。 |

---

## 5. 全局集成与注册

除了实现插件本身的逻辑外,还需要在 ODC 核心模块中进行注册,使系统能够识别并调用新插件。

### 5.1 `libs/db-browser` 工厂注册

| 工厂类 | 注册操作 |
| :--- | :--- |
| `AbstractDBBrowserFactory.java` | 在 `create()` 方法的 switch 中增加 `SQL_SERVER` 分支,并添加 `buildForSqlServer()` 抽象方法。 |
| `DBSchemaAccessorFactory.java` | 实现 `buildForSqlServer()`,返回 `SqlServerSchemaAccessor` 实例。 |
| `DBTableEditorFactory.java` | 实现 `buildForSqlServer()`,返回 `SqlServerTableEditor` 实例。 |
| `DBObjectOperatorFactory.java` | 实现 `buildForSqlServer()`,返回 `SqlServerObjectOperator` 实例。 |
| `DBFunctionTemplateFactory.java` | 实现 `buildForSqlServer()`,返回 `SqlServerFunctionTemplate` 实例。 |

### 5.2 `server/odc-core` 枚举与常量

| 文件路径 | 修改内容 |
| :--- | :--- |
| `DialectType.java` | 增加 `SQL_SERVER` 枚举值。 |
| `ConnectType.java` | 增加 `SQL_SERVER(DialectType.SQL_SERVER)` 枚举值。 |
| `OdcConstants.java` | 增加 `SQL_SERVER_DRIVER_CLASS_NAME` 和 `SQL_SERVER_DEFAULT_SCHEMA` 常量。 |
| `SqlCommentProcessor.java` | 在 `split()` 方法中增加对 `SQL_SERVER` 的处理逻辑。 |

### 5.3 `server/odc-service` 业务集成

| 文件路径 | 修改内容 |
| :--- | :--- |
| `ConnectTypeUtil.java` | 在 `getConnectType()` 方法中增加对 `SQL_SERVER` 的识别逻辑。 |
| `ConnectionTesting.java` | 在 `test()` 方法中增加对 SQLServer 默认 Schema 的处理逻辑。 |
| `DruidDataSourceFactory.java` | 配置 SQLServer 特有的连接池参数(如 `validationQuery`)。 |

### 5.4 `server/odc-migrate` 数据库初始化

| 文件路径 | 修改内容 |
| :--- | :--- |
| `R_2_0_0__initialize_version_diff_config.sql` | 增加 SQLServer 的版本差异配置(如 `column_data_type`、`support_view` 等)。 |

---

## 6. 配置与注册 (插件层)

1. **Plugin 注册**:
- 在插件模块的 `pom.xml` 中指定 `plugin.class`。
- 在 `META-INF/MANIFEST.MF` 或通过注解确保 PF4J 能够识别插件。

---

## 7. 总结与原则

- **逻辑下沉**: 尽量在 `db-browser` 层实现方言逻辑,保持 `server/plugins` 层的轻量化。
- **TDD 开发**: 优先编写单元测试,通过测试驱动方言适配的完善。
- **解耦设计**: 避免在公共模块中编写特定数据库的业务代码,利用工厂模式和接口实现多数据库适配。

---

## 8. 待完善功能:SQL 语法解析器 (Parser)

由于 SQL 语法解析(如 DDL 解析、SQL 检查)的实现成本较高,目前 SQLServer 插件暂未实现专用的语法解析器。如果后续需要支持如“影子表”、“回滚方案”或“SQL 检查”等深度依赖语法分析的功能,可参考以下路径进行实现:

1. **定义 Antlr4 语法**: 在底层的 SQL 解析库中增加 SQLServer 的 Antlr4 语法文件。
2. **实现插件层解析器**:
- **路径**: `server/plugins/schema-plugin-sqlserver/src/main/java/com/oceanbase/odc/plugin/schema/sqlserver/parser/`
- **操作**: 参照 `OBMySQLGetDBTableByParser.java`,实现 `SqlServerGetDBTableByParser`,通过语法树解析 DDL 字符串并还原为 `DBTable` 等模型对象。
3. **集成到扩展点**: 将解析器集成到 `TableExtensionPoint` 等相关扩展点中,以支持通过 SQL 脚本反向生成元数据。

Loading