diff --git a/admin/src/lib/admin-rpc.ts b/admin/src/lib/admin-rpc.ts index a269427..1facad9 100644 --- a/admin/src/lib/admin-rpc.ts +++ b/admin/src/lib/admin-rpc.ts @@ -8,123 +8,123 @@ * import { listWorkspaceSessions, kickUser } from "@/lib/admin-rpc"; */ -import { ADMIN_RPC_URL } from "./env"; +import {ADMIN_RPC_URL} from "./env"; // Default to k8s internal service address; override via ADMIN_RPC_URL env var -const BASE_URL = ADMIN_RPC_URL || "http://adminrpc.admin.svc.cluster.local:9091"; +const BASE_URL = ADMIN_RPC_URL || "http://adminrpc.gitdataai.svc.cluster.local:9091"; async function rpc(path: string, options?: RequestInit): Promise { - const url = `${BASE_URL}${path}`; - const res = await fetch(url, { - ...options, - headers: { - "Content-Type": "application/json", - ...options?.headers, - }, - }); - if (!res.ok) { - const body = await res.text(); - throw new Error(`adminrpc ${options?.method ?? "GET"} ${path} failed (${res.status}): ${body}`); - } - return res.json() as Promise; + const url = `${BASE_URL}${path}`; + const res = await fetch(url, { + ...options, + headers: { + "Content-Type": "application/json", + ...options?.headers, + }, + }); + if (!res.ok) { + const body = await res.text(); + throw new Error(`adminrpc ${options?.method ?? "GET"} ${path} failed (${res.status}): ${body}`); + } + return res.json() as Promise; } // ─── Types ──────────────────────────────────────────────────────────────────── export interface UserSession { - session_id: string; - user_id: string; - workspace_id: string; - ip_address: string; - user_agent: string; - connected_at: string; - last_heartbeat: string; + session_id: string; + user_id: string; + workspace_id: string; + ip_address: string; + user_agent: string; + connected_at: string; + last_heartbeat: string; } export interface SessionInfo { - user_id: string; - session_count: number; - workspaces: string[]; - latest_session: UserSession | null; + user_id: string; + session_count: number; + workspaces: string[]; + latest_session: UserSession | null; } // ─── Sessions API ───────────────────────────────────────────────────────────── /** List all active sessions for a workspace. */ export async function listWorkspaceSessions(workspaceId: string): Promise { - return rpc(`/api/admin/sessions/workspace/${encodeURIComponent(workspaceId)}`); + return rpc(`/api/admin/sessions/workspace/${encodeURIComponent(workspaceId)}`); } /** List all active sessions for a specific user. */ export async function listUserSessions(userId: string): Promise { - return rpc(`/api/admin/sessions/user/${encodeURIComponent(userId)}`); + return rpc(`/api/admin/sessions/user/${encodeURIComponent(userId)}`); } /** Get the online status of a specific user. */ export async function getUserStatus(userId: string): Promise<{ status: string }> { - return rpc<{ status: string }>(`/api/admin/sessions/user/${encodeURIComponent(userId)}/status`); + return rpc<{ status: string }>(`/api/admin/sessions/user/${encodeURIComponent(userId)}/status`); } /** Get detailed info for a user (session count, workspaces, latest session). */ export async function getUserInfo(userId: string): Promise { - return rpc(`/api/admin/sessions/user/${encodeURIComponent(userId)}/info`); + return rpc(`/api/admin/sessions/user/${encodeURIComponent(userId)}/info`); } /** List all online user IDs in a workspace. */ export async function getWorkspaceOnlineUsers(workspaceId: string): Promise<{ user_ids: string[] }> { - return rpc<{ user_ids: string[] }>(`/api/admin/sessions/workspace/${encodeURIComponent(workspaceId)}/online-users`); + return rpc<{ user_ids: string[] }>(`/api/admin/sessions/workspace/${encodeURIComponent(workspaceId)}/online-users`); } /** Check if a user is currently online. */ export async function isUserOnline(userId: string): Promise<{ online: boolean }> { - return rpc<{ online: boolean }>(`/api/admin/sessions/user/${encodeURIComponent(userId)}/online`); + return rpc<{ online: boolean }>(`/api/admin/sessions/user/${encodeURIComponent(userId)}/online`); } /** Kick all sessions for a user. Returns the number of sessions kicked. */ export async function kickUser(userId: string): Promise<{ kicked_count: number }> { - return rpc<{ kicked_count: number }>("/api/admin/sessions/kick", { - method: "POST", - body: JSON.stringify({ user_id: userId }), - }); + return rpc<{ kicked_count: number }>("/api/admin/sessions/kick", { + method: "POST", + body: JSON.stringify({user_id: userId}), + }); } /** Kick all sessions for a user in a specific workspace. */ export async function kickUserFromWorkspace( - userId: string, - workspaceId: string + userId: string, + workspaceId: string ): Promise<{ kicked_count: number }> { - return rpc<{ kicked_count: number }>("/api/admin/sessions/kick-workspace", { - method: "POST", - body: JSON.stringify({ user_id: userId, workspace_id: workspaceId }), - }); + return rpc<{ kicked_count: number }>("/api/admin/sessions/kick-workspace", { + method: "POST", + body: JSON.stringify({user_id: userId, workspace_id: workspaceId}), + }); } // ─── Metrics API ───────────────────────────────────────────────────────────── export interface InstanceMetrics { - instance_id: string; - timestamp_secs: number; - http: Record; - room: Record; + instance_id: string; + timestamp_secs: number; + http: Record; + room: Record; } /** Get metrics across all app instances. */ export async function getMetrics(instanceFilter = ""): Promise { - const qs = instanceFilter ? `?instance_filter=${encodeURIComponent(instanceFilter)}` : ""; - return rpc(`/api/admin/metrics${qs}`); + const qs = instanceFilter ? `?instance_filter=${encodeURIComponent(instanceFilter)}` : ""; + return rpc(`/api/admin/metrics${qs}`); } /** Export all metrics as CSV string. */ export async function exportMetricsCsv(instanceFilter = ""): Promise { - const qs = instanceFilter ? `?instance_filter=${encodeURIComponent(instanceFilter)}` : ""; - const res = await fetch(`${BASE_URL}/api/admin/metrics/export${qs}`); - if (!res.ok) { - throw new Error(`adminrpc GET /metrics/export failed (${res.status})`); - } - return res.text(); + const qs = instanceFilter ? `?instance_filter=${encodeURIComponent(instanceFilter)}` : ""; + const res = await fetch(`${BASE_URL}/api/admin/metrics/export${qs}`); + if (!res.ok) { + throw new Error(`adminrpc GET /metrics/export failed (${res.status})`); + } + return res.text(); } /** Get adminrpc health status. */ export async function adminRpcHealth(): Promise<{ ok: boolean }> { - return rpc<{ ok: boolean }>("/health"); + return rpc<{ ok: boolean }>("/health"); } diff --git a/deploy/templates/adminrpc-deployment.yaml b/deploy/templates/adminrpc-deployment.yaml index 77227f9..37ca9ff 100644 --- a/deploy/templates/adminrpc-deployment.yaml +++ b/deploy/templates/adminrpc-deployment.yaml @@ -35,6 +35,9 @@ spec: - name: grpc containerPort: {{ .Values.adminrpc.service.port }} protocol: TCP + - name: http + containerPort: {{ .Values.adminrpc.service.http_port }} + protocol: TCP args: - --bind - "0.0.0.0:{{ .Values.adminrpc.service.port }}" @@ -43,12 +46,12 @@ spec: name: {{ include "gitdata.fullname" . }}-config livenessProbe: tcpSocket: - port: {{ .Values.adminrpc.service.port }} + port: {{ .Values.adminrpc.service.http_port }} initialDelaySeconds: 5 periodSeconds: 10 readinessProbe: tcpSocket: - port: {{ .Values.adminrpc.service.port }} + port: {{ .Values.adminrpc.service.http_port }} initialDelaySeconds: 5 periodSeconds: 5 {{- if .Values.adminrpc.resources }} @@ -83,6 +86,10 @@ spec: targetPort: grpc protocol: TCP name: grpc + - port: {{ .Values.adminrpc.service.http_port }} + targetPort: http + protocol: TCP + name: http selector: app.kubernetes.io/name: {{ include "gitdata.fullname" . }}-adminrpc app.kubernetes.io/instance: {{ .Release.Name }} diff --git a/deploy/values.yaml b/deploy/values.yaml index 5adeccb..ec9b7e9 100644 --- a/deploy/values.yaml +++ b/deploy/values.yaml @@ -401,6 +401,7 @@ adminrpc: service: port: 9090 + http_port: 9091 readinessProbe: tcpSocket: