Skip to content
Merged
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
6 changes: 6 additions & 0 deletions api/config/crd/bases/rlinf.io_clusters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -57,9 +57,14 @@ spec:
agentNamespace:
description: AgentNamespace is the management-plane namespace that
contains the agent heartbeat Lease and Node CRs.
minLength: 1
type: string
cordoned:
type: boolean
delisted:
type: boolean
drainPreviousCordoned:
type: boolean
draining:
type: boolean
required:
Expand Down Expand Up @@ -145,6 +150,7 @@ spec:
- Downgraded
- Cordoned
- Draining
- Delisted
type: string
totalNodes:
format: int32
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions api/rlark.io/v1alpha1/annotations.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ const (
WorkflowLabel = "rlinf.io/workflow"
WorkflowStoppedByAnnotation = "rlinf.io/workflow-stopped-by"

ClusterStoppedAnnotation = "rlark.io/stopped"
// ClusterDrainSuspendedAnnotation records that Task.Spec.Suspended was set by a
// cluster drain, so cancelling the drain only resumes Tasks the drain suspended.
ClusterDrainSuspendedAnnotation = "rlark.io/drain-suspended"

RayRoleAnnotation = "rlark.io/ray-role"
RayHeadTaskNameAnnotation = "rlark.io/ray-head-task-name"
RayTotalNodesAnnotation = "rlark.io/ray-total-nodes"
Expand Down
12 changes: 8 additions & 4 deletions api/rlark.io/v1alpha1/cluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
// ClusterPhase summarizes the current lifecycle state of a data-plane cluster.
// The set is closed in the CRD schema: adding a value requires updating the
// enum marker, regenerating the CRD manifests, and updating the documentation.
// +kubebuilder:validation:Enum=Online;Offline;Downgraded;Cordoned;Draining
// +kubebuilder:validation:Enum=Online;Offline;Downgraded;Cordoned;Draining;Delisted
type ClusterPhase string

const (
Expand All @@ -14,14 +14,18 @@ const (
ClusterDowngraded ClusterPhase = "Downgraded"
ClusterCordoned ClusterPhase = "Cordoned"
ClusterDraining ClusterPhase = "Draining"
ClusterDelisted ClusterPhase = "Delisted"
)

// ClusterSpec declares the durable operational state of a data-plane cluster.
type ClusterSpec struct {
// AgentNamespace is the management-plane namespace that contains the agent heartbeat Lease and Node CRs.
AgentNamespace string `json:"agentNamespace"`
Cordoned bool `json:"cordoned,omitempty"`
Draining bool `json:"draining,omitempty"`
// +kubebuilder:validation:MinLength=1
AgentNamespace string `json:"agentNamespace"`
Cordoned bool `json:"cordoned,omitempty"`
Draining bool `json:"draining,omitempty"`
Delisted bool `json:"delisted,omitempty"`
DrainPreviousCordoned bool `json:"drainPreviousCordoned,omitempty"`
}

// ClusterStatus reports the controller's current observation of a data-plane cluster.
Expand Down
31 changes: 17 additions & 14 deletions apps/rlark-ui/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,7 @@ import type { Job } from "./data";
import { copy, type Lang, type Theme } from "./i18n";
import { navItems } from "./constants";
import type { Page } from "./types";
import {
filesPath,
hasTerminalSession,
parseRoute,
useIsAdminPath,
} from "./utils/route";
import { hasTerminalSession, parseRoute, useIsAdminPath } from "./utils/route";
import { Logo, Header, PlatformFooter } from "./components/shared";
import { TerminalPage } from "./components/terminal";
import { Overview } from "./pages/Overview";
Expand Down Expand Up @@ -75,13 +70,17 @@ export default function App() {
document.title = isTerminal
? "WebTerminal · RLark"
: isAdmin
? "RLark 管理后台"
: "RLark具身智能云原生纳管平台";
? lang === "zh"
? "RLark 管理后台"
: "RLark Admin Console"
: lang === "zh"
? "RLark具身智能云原生纳管平台"
: "RLark Cloud-Native Embodied Intelligence Platform";
const favicon = document.querySelector<HTMLLinkElement>("#app-favicon");
if (favicon) {
favicon.href = "/favicon.png";
}
}, [isAdmin, isTerminal]);
}, [isAdmin, isTerminal, lang]);

const navigate = (
next: Page,
Expand Down Expand Up @@ -135,6 +134,7 @@ export default function App() {
if (!userLoggedIn && !(isTerminal && terminalLoggedIn)) {
return (
<UserLogin
lang={lang}
onLogin={(name) => {
setUserName(name);
setUserLoggedIn(true);
Expand All @@ -151,7 +151,9 @@ export default function App() {
if (!workerCRName) {
return (
<div className="terminal-page-error">
缺少 Worker 参数,无法连接终端。
{lang === "zh"
? "缺少 Worker 参数,无法连接终端。"
: "Missing worker parameter, cannot open the terminal."}
</div>
);
}
Expand All @@ -161,6 +163,7 @@ export default function App() {
workerName={workerCRName}
jobName={jobName}
workerStatus={workerStatus}
lang={lang}
/>
);
}
Expand All @@ -179,7 +182,9 @@ export default function App() {
const Icon = item.icon;
const isParent = item.children && item.children.length > 0;
const itemLabel = isParent ? c.nav.clustersParent : c.nav[item.id];
const isActive = page === item.id;
const isActive =
page === item.id ||
(item.id === "storageClass" && page === "files");
const isChildActive = isParent
? item.children!.some((ch) => ch.id === page)
: false;
Expand Down Expand Up @@ -353,9 +358,7 @@ export default function App() {
navigate("storageClass", name, { replace: !name })
}
onCreate={() => setStorageCreateOpen(true)}
onBrowseFiles={(cluster, storageClass) =>
window.open(filesPath(cluster, storageClass), "_blank")
}
onBrowseFiles={(storageClass) => navigate("files", storageClass)}
refreshKey={storageRefreshKey}
/>
)}
Expand Down
22 changes: 21 additions & 1 deletion apps/rlark-ui/src/admin/Addons.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@
export function AddonsPage({ lang }: { lang: Lang }) {
const zh = lang === "zh";
const [clusters, setClusters] = useState<{ id: string; name: string }[]>([]);
const [catalog, setCatalog] = useState<any[]>([]);

Check warning on line 8 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint-frontend

Unexpected any. Specify a different type

Check warning on line 8 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint-frontend

Unexpected any. Specify a different type

Check warning on line 8 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint / lint-frontend

Unexpected any. Specify a different type
const [installed, setInstalled] = useState<any[]>([]);

Check warning on line 9 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint-frontend

Unexpected any. Specify a different type

Check warning on line 9 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint-frontend

Unexpected any. Specify a different type

Check warning on line 9 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint / lint-frontend

Unexpected any. Specify a different type
const [clusterFilter, setClusterFilter] = useState("");
const [page, setPage] = useState(1);
const pageSize = 10;
const [error, setError] = useState("");
const [installAddonName, setInstallAddonName] = useState("");
const [configInstalled, setConfigInstalled] = useState<any>(null);

Check warning on line 15 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint-frontend

Unexpected any. Specify a different type

Check warning on line 15 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint-frontend

Unexpected any. Specify a different type

Check warning on line 15 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint / lint-frontend

Unexpected any. Specify a different type

useEffect(() => {
clustersApi
Expand All @@ -39,7 +39,7 @@
fetchInstalled();
const interval = setInterval(fetchInstalled, 5000);
return () => clearInterval(interval);
}, [clusterFilter]);

Check warning on line 42 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint-frontend

React Hook useEffect has a missing dependency: 'fetchInstalled'. Either include it or remove the dependency array

Check warning on line 42 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint-frontend

React Hook useEffect has a missing dependency: 'fetchInstalled'. Either include it or remove the dependency array

Check warning on line 42 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint / lint-frontend

React Hook useEffect has a missing dependency: 'fetchInstalled'. Either include it or remove the dependency array

useEffect(() => {
setPage(1);
Expand All @@ -59,6 +59,26 @@
}
};

// Addon.status.phase values reported by the addon controller. Unknown values
// are rendered verbatim so new phases still surface in the UI.
const phaseLabel = (phase: string) => {
if (!zh) return phase;
switch (phase) {
case "Ready":
return "就绪";
case "Failed":
return "失败";
case "Installing":
return "安装中";
case "Upgrading":
return "升级中";
case "Pending":
return "等待中";
default:
return phase;
}
};

const totalPages = Math.ceil(installed.length / pageSize);
const pagedInstalled = installed.slice(
(page - 1) * pageSize,
Expand Down Expand Up @@ -209,7 +229,7 @@
<td>{a.status?.version || a.spec?.version || "-"}</td>
<td>
<span style={{ color: phaseColor(a.status?.phase) }}>
{a.status?.phase || "Pending"}
{phaseLabel(a.status?.phase || "Pending")}
</span>
</td>
<td className="muted">{a.status?.message || "-"}</td>
Expand Down Expand Up @@ -310,7 +330,7 @@
onBack,
onInstalled,
}: {
addon: any;

Check warning on line 333 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint-frontend

Unexpected any. Specify a different type

Check warning on line 333 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint-frontend

Unexpected any. Specify a different type

Check warning on line 333 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint / lint-frontend

Unexpected any. Specify a different type
clusters: { id: string; name: string }[];
lang: Lang;
onBack: () => void;
Expand All @@ -320,7 +340,7 @@
const [installCluster, setInstallCluster] = useState("");
const [values, setValues] = useState<Record<string, string>>(() => {
const defaults: Record<string, string> = {};
(addon.parameters || []).forEach((p: any) => {

Check warning on line 343 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint-frontend

Unexpected any. Specify a different type

Check warning on line 343 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint-frontend

Unexpected any. Specify a different type

Check warning on line 343 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint / lint-frontend

Unexpected any. Specify a different type
defaults[p.name] = p.default || "";
});
return defaults;
Expand Down Expand Up @@ -421,7 +441,7 @@
<strong>{zh ? "参数配置" : "Parameters"}</strong>
</div>
<div style={{ display: "flex", flexDirection: "column", gap: 16 }}>
{addon.parameters.map((p: any) => (

Check warning on line 444 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint-frontend

Unexpected any. Specify a different type

Check warning on line 444 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint-frontend

Unexpected any. Specify a different type

Check warning on line 444 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint / lint-frontend

Unexpected any. Specify a different type
<div
key={p.name}
style={{ display: "flex", flexDirection: "column", gap: 6 }}
Expand Down Expand Up @@ -577,8 +597,8 @@
onBack,
onSaved,
}: {
addon: any;

Check warning on line 600 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint-frontend

Unexpected any. Specify a different type

Check warning on line 600 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint-frontend

Unexpected any. Specify a different type

Check warning on line 600 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint / lint-frontend

Unexpected any. Specify a different type
installed: any;

Check warning on line 601 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint-frontend

Unexpected any. Specify a different type

Check warning on line 601 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint-frontend

Unexpected any. Specify a different type

Check warning on line 601 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint / lint-frontend

Unexpected any. Specify a different type
lang: Lang;
onBack: () => void;
onSaved: () => void;
Expand All @@ -588,7 +608,7 @@
const addonName = installed.metadata?.name;
const [values, setValues] = useState<Record<string, string>>(() => {
const init: Record<string, string> = {};
(addon.parameters || []).forEach((p: any) => {

Check warning on line 611 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint-frontend

Unexpected any. Specify a different type

Check warning on line 611 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint-frontend

Unexpected any. Specify a different type

Check warning on line 611 in apps/rlark-ui/src/admin/Addons.tsx

View workflow job for this annotation

GitHub Actions / lint / lint-frontend

Unexpected any. Specify a different type
init[p.name] = installed.spec?.values?.[p.name] ?? p.default ?? "";
});
return init;
Expand Down
11 changes: 6 additions & 5 deletions apps/rlark-ui/src/admin/AdminApp.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import { SSHKeysPage } from "../pages/SSHKeys";
import { ImageRegistriesPage } from "../pages/ImageRegistries";
import { SystemConfigPage } from "../pages/SystemConfig";
import { JobsPage } from "../pages/Jobs";
import { filesPath, parseAdminRoute } from "../utils/route";
import { parseAdminRoute } from "../utils/route";
import {
clearAuthSession,
hasAuthSession,
Expand Down Expand Up @@ -285,7 +285,9 @@ export function AdminApp() {
const Icon = item.icon;
const itemLabel = zh ? item.zh : item.en;
const isParent = item.children && item.children.length > 0;
const isActive = adminPage === item.id;
const isActive =
adminPage === item.id ||
(item.id === "storageClass" && adminPage === "files");
const isChildActive = isParent
? item.children!.some((ch) => ch.id === adminPage)
: false;
Expand Down Expand Up @@ -396,6 +398,7 @@ export function AdminApp() {
selectedClusterID={adminSub}
onSelectCluster={(id?: string) => navigate("clusters-list", id)}
onSelectNode={(name: string) => navigate("clusters-nodes", name)}
adminMode
/>
)}
{adminPage === "jobs" && (
Expand Down Expand Up @@ -431,9 +434,7 @@ export function AdminApp() {
selectedName={adminSub}
onSelect={(name?: string) => navigate("storageClass", name)}
onCreate={() => navigate("storageClass", "create")}
onBrowseFiles={(cluster, storageClass) =>
window.open(filesPath(cluster, storageClass, true), "_blank")
}
onBrowseFiles={(storageClass) => navigate("files", storageClass)}
refreshKey={storageRefreshKey}
/>
)}
Expand Down
4 changes: 2 additions & 2 deletions apps/rlark-ui/src/admin/AdminPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -239,7 +239,7 @@ export function ClustersOverviewAdminPage({ copy: c }: { copy: Copy }) {
<div className="panel cluster-map-card">
<div className="panel-title">
<div>
<span>Distribution</span>
<span>{zh ? "分布" : "Distribution"}</span>
<h3>{zh ? "集群分布" : "Cluster Distribution"}</h3>
</div>
</div>
Expand Down Expand Up @@ -1595,7 +1595,7 @@ export function AdminPage({
(category) =>
categoryLabels[category][zh ? "zh" : "en"],
)
.join("、")
.join(zh ? "、" : ", ")
: zh
? "当前未设置"
: "Not set"}
Expand Down
22 changes: 10 additions & 12 deletions apps/rlark-ui/src/admin/CreateCluster.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import {
systemConfigApi,
type DeploymentConfig,
} from "../backend";
import { copyText } from "../utils/clipboard";
import { buildDeployYaml } from "../utils/deployYaml";

export function CreateClusterPage({ lang }: { lang: Lang }) {
Expand Down Expand Up @@ -72,11 +73,10 @@ export function CreateClusterPage({ lang }: { lang: Lang }) {

const deployYaml = result ? buildDeployYaml(result, deploymentConfig) : "";

const handleCopy = () => {
navigator.clipboard.writeText(deployYaml).then(() => {
setCopied(true);
setTimeout(() => setCopied(false), 2000);
});
const handleCopy = async () => {
if (!(await copyText(deployYaml))) return;
setCopied(true);
setTimeout(() => setCopied(false), 2000);
};

const handleExpand = async (cid: string) => {
Expand All @@ -92,14 +92,12 @@ export function CreateClusterPage({ lang }: { lang: Lang }) {
} catch {}
};

const handleExpandedCopy = () => {
const handleExpandedCopy = async () => {
if (!expandedResult) return;
navigator.clipboard
.writeText(buildDeployYaml(expandedResult, deploymentConfig))
.then(() => {
setExpandedCopied(true);
setTimeout(() => setExpandedCopied(false), 2000);
});
const yaml = buildDeployYaml(expandedResult, deploymentConfig);
if (!(await copyText(yaml))) return;
setExpandedCopied(true);
setTimeout(() => setExpandedCopied(false), 2000);
};

return (
Expand Down
Loading
Loading