跳到主要内容
版本:3.1.0(预览)

开发和部署 React View

Ambari View 是由 Ambari Server 管理的版本化应用归档。它可以包含浏览器应用、JAX-RS 资源、实例参数、权限和生命周期钩子。主要 React shell 会发现用户有权访问的 View 实例,并在 Server 提供的同源 iframe 上下文中打开应用。

文件浏览器、调度器编辑器、诊断控制台或 AI 辅助运维页面等可独立部署的工具适合使用 View。需要修改 Ambari 公共导航或内置工作流时,则应修改主要 React UI。

参考实现​

Ambari trunk 包含两个 React View 实现:

View前端Server 资源可参考的模式
Filescontrib/views/files/src/main/resources/uicontrib/views/files/src/main/java能识别部署路径的 API 根路径、文件操作、上传下载、错误处理和反向代理测试
Capacity Schedulercontrib/views/capacity-scheduler/src/main/resources/uicontrib/views/capacity-scheduler/src/main/java配置编辑、权限检查、YARN 操作、保存并刷新和保存并重启流程

在 3.1 构建中,两者都使用 React 19、TypeScript、Vite、Vitest、Node 22.23.1 和 npm 10.9.8。可以同时参考这两个模块,但不要把其中针对 HDFS 或 YARN 的依赖复制到无关 View。

归档结构​

React View 通常使用以下目录:

my-view/
├── pom.xml
└── src/main/
├── java/org/example/ambari/view/
│ └── MyViewService.java
└── resources/
├── view.xml
├── view.log4j.properties
└── ui/
├── package.json
├── package-lock.json
├── vite.config.ts
├── index.html
└── src/

Maven 构建需要在资源处理前完成前端构建,并将生成的 ui/dist 文件放在归档根目录。归档还要包含 view.xml、View 的 Server 类,以及 WEB-INF/lib 下的运行时库。Ambari Server 已提供的依赖必须使用 provided scope;重复打包 Servlet、Jetty、Jersey 或日志实现可能破坏 View classloader。

定义 View​

src/main/resources/view.xml 定义稳定的 View 名称、版本、配置参数、REST 资源、权限和可选的自动实例。下面是包含一个受保护资源的最小定义:

<view>
<name>AI-ASSISTANT</name>
<label>AI Assistant</label>
<version>1.0.0</version>
<min-ambari-version>3.1.*</min-ambari-version>

<parameter>
<name>request.timeout.seconds</name>
<description>Maximum time for an assisted request.</description>
<required>true</required>
<default-value>30</default-value>
</parameter>

<resource>
<name>assistant</name>
<service-class>org.example.ambari.view.AssistantService</service-class>
</resource>

<permission>
<name>USE_ASSISTANT</name>
<description>Submit requests to the assistant.</description>
</permission>
</view>

<name> 和 <version> 会成为公开 URL 和持久化 View 标识的一部分。发布不兼容的前端、资源、参数或数据改动时,应使用新版本。需要在版本间移动实例数据时,应定义明确的迁移过程。

参数属于实例配置,不能用来安全保存明文凭据。敏感值应通过 Server 端受保护凭据存储读取,绝不能返回给浏览器。

完整描述符见 View 定义,实例数据、持久化、事件和生命周期服务见框架服务。

实现 Server 资源​

<resource> 条目将资源名映射到 View 服务类。Ambari 会把该资源发布在经过身份验证的实例 URL 下:

/api/v1/views/{view}/versions/{version}/instances/{instance}/resources/{resource}

在 Server 类中使用 ViewContext 获取当前用户、实例属性、关联集群和数据服务。每个受保护操作都要先调用 ViewContext.hasPermission;React UI 可以隐藏控件,但资源端点仍是最终授权边界。

响应应使用有大小限制且字段明确的 DTO。验证路径、标识、查询大小和外部目标。调用 HDFS、YARN、Ambari 和外部服务时设置超时。将预期失败转换为有意义的 HTTP 状态码,但不要返回堆栈、凭据或未经限制的模型输出。

AI 辅助 View​

AI 服务调用应放在 View 资源后面:

React View
│ same-origin request
▼
View JAX-RS resource
├── authorized Ambari or service API
└── approved AI provider

浏览器把用户请求发送给 View 资源。Server 检查 View 权限、限制请求大小、读取受保护的服务凭据、调用批准的端点、过滤响应,并记录可审计结果。不要让 React 使用长期密钥直接调用 AI 服务。AI 建议创建 Ambari 请求或变更集群状态前,还应要求用户再次确认。

构建路径安全的 React 前端​

将 Vite 静态资源基础路径设置为相对路径,使同一归档可以适配不同的 View 名称、版本、实例和反向代理前缀:

import react from "@vitejs/plugin-react";
import { defineConfig } from "vite";

export default defineConfig({
base: "./",
plugins: [react()],
build: { outDir: "dist", emptyOutDir: true },
test: { environment: "jsdom" },
});

不要从站点根目录硬编码 /api/v1。View 可能发布在 /gateway/default/ambari/views/... 等路径下。应从当前 pathname 推导 Ambari 应用根路径,再构建经过编码的资源 URL:

const applicationRoot = (pathname: string) => {
const normalized = pathname.startsWith("/") ? pathname : `/${pathname}`;
const viewsIndex = normalized.lastIndexOf("/views/");
return viewsIndex >= 0 ? `${normalized.slice(0, viewsIndex)}/` : "/";
};

const resourceRoot = `${applicationRoot(window.location.pathname)}api/v1/` +
`views/${encodeURIComponent(view)}/versions/${encodeURIComponent(version)}/` +
`instances/${encodeURIComponent(instance)}/resources/assistant`;

资源请求需要发送会话凭据和 Ambari CSRF 请求头:

const response = await fetch(`${resourceRoot}/query`, {
method: "POST",
credentials: "same-origin",
headers: {
"Content-Type": "application/json",
"X-Requested-By": "ai-assistant-view",
},
body: JSON.stringify(request),
});

除非用户明确离开 View,否则导航应留在 View 自己的 hash 或相对路径内。需要测试 Ambari 可能提供的两种规范路径:

/views/{view}/{version}/{instance}/
/views/{view}/{instance}/

Files 和 Capacity Scheduler 的 API helper 会定位最后一个 /views/ 片段。这样既能保留反向代理前缀,也不会把前面同名的路径片段误认为 View 上下文。

构建并检查归档​

在任一参考模块中只迭代前端时:

cd contrib/views/files/src/main/resources/ui
npm ci --no-audit --no-fund
npm test
npm run build

从 Ambari 仓库根目录构建完整参考归档:

mvn -B -pl :files -am package
mvn -B -pl :capacity-scheduler -am package

新模块应将 artifact selector 换成自己的 Maven artifact ID。部署前检查产物:

jar tf target/my-view-1.0.0.jar | sort

确认归档包含 view.xml、index.html、index.html 引用的全部哈希资源、Server 类,并且只包含预期的运行时依赖。Java 资源测试和前端测试应与其验证的行为放在同一个改动中。

部署 View​

默认 View 归档目录是 /var/lib/ambari-server/resources/views。向自定义 Server 部署前,应先检查 ambari.properties 中的 views.dir。

安装经过审查的归档并重启 Ambari Server:

install -m 0644 target/my-view-1.0.0.jar \
/var/lib/ambari-server/resources/views/
ambari-server restart

查看 ambari-server.log,确认 View 版本进入 DEPLOYED。classloader、描述符或依赖错误会使该版本不可用,创建实例前必须先解决。不要在相同版本下反复用不同内容覆盖正在使用的归档;应发布新版本,使部署、回退和数据迁移保持明确。

在 Ambari 管理 UI 中创建并配置实例,然后向所需用户或组授予该实例及自定义 View 权限。等效的实例 API 见 View API。

有权限的实例会从 Server 返回的 URL 打开,例如:

/views/AI-ASSISTANT/1.0.0/PRODUCTION/

不要根据猜测的主机名或上下文根路径拼接浏览器 URL。尤其当 Server 位于 Knox 或其他反向代理后面时,应读取 Ambari 返回的实例 URL。

验证清单​

分发 View 归档之前:

  • 运行前端单元测试、TypeScript 构建和 Vite 生产构建。
  • 为每个 JAX-RS 资源和权限分支运行定向 Java 测试。
  • 检查归档内容和依赖版本。
  • 部署全新版本、创建实例并按最小权限授权。
  • 测试允许、拒绝、未认证、会话过期和 CSRF 失败场景。
  • 测试正常、空数据、格式错误、超时、重试和后端不可用场景。
  • 验证根路径和反向代理上下文路径下的 View 直接导航。
  • 检查刷新、浏览器后退、iframe 错误、窄屏和键盘操作。
  • 确认日志、响应、浏览器存储和 bundle 中没有凭据。
  • 升级到新的 View 版本,并演练回退或数据迁移。