From 6d43a2be02cd46fae682e86bebeb054e6a06dda7 Mon Sep 17 00:00:00 2001 From: Aditya Thebe Date: Thu, 21 May 2026 13:29:47 +0545 Subject: [PATCH] fix(arthas): use declared operations for UI calls The Arthas UI still used the old arbitrary HTTP handler model for console, MCP, and direct /api proxy requests. Those paths are no longer mounted by the plugin SDK and can be blocked or misrouted by the host proxy.\n\nRoute command execution through the declared exec operation, remove the dead HTTPHandler proxy/MCP code, stop starting MCP port-forwards, and drop UI tabs/links that depended on arbitrary plugin endpoints. --- arthas/README.md | 6 +- arthas/http.go | 209 ------------------ arthas/http_test.go | 71 ------ arthas/internal/arthas/bootstrap.go | 62 +----- arthas/internal/arthas/session.go | 8 +- arthas/ops.go | 4 - arthas/ui-src/src/lib/api.ts | 4 - .../ui-src/src/pages/ArthasDashboardTab.tsx | 17 +- arthas/ui-src/src/pages/ArthasPage.tsx | 98 +------- arthas/ui-src/src/pages/ArthasProfilerTab.tsx | 12 +- arthas/ui-src/tsconfig.tsbuildinfo | 2 +- arthas/ui/index.html | 4 +- arthas/ui_checksum.go | 2 +- 13 files changed, 25 insertions(+), 474 deletions(-) delete mode 100644 arthas/http_test.go diff --git a/arthas/README.md b/arthas/README.md index 077b281..e61ed70 100644 --- a/arthas/README.md +++ b/arthas/README.md @@ -1,6 +1,6 @@ # Arthas Mission Control Plugin -The Arthas plugin adds JVM diagnostics to Mission Control for Kubernetes workloads. It attaches [Arthas](https://arthas.aliyun.com/) to a Java process running in a selected pod and exposes the Arthas web console, HTTP API, and diagnostic operations from the Mission Control UI. +The Arthas plugin adds JVM diagnostics to Mission Control for Kubernetes workloads. It attaches [Arthas](https://arthas.aliyun.com/) to a Java process running in a selected pod and exposes supported diagnostic operations from the Mission Control UI. ## What it does @@ -15,8 +15,8 @@ The Arthas plugin adds JVM diagnostics to Mission Control for Kubernetes workloa - Resolves the selected workload to a running pod and container. - Copies/installs `arthas-boot.jar` into the target pod when needed. - Attaches Arthas to the JVM in the target container. -- Opens Kubernetes port-forwards to the Arthas HTTP console and optional MCP endpoint. -- Proxies the Arthas UI/API through Mission Control. +- Opens a Kubernetes port-forward to the Arthas HTTP API for plugin-side operation handlers. +- Executes supported Arthas commands through declared Mission Control plugin operations. - Tracks active sessions inside the plugin process. ## Operations diff --git a/arthas/http.go b/arthas/http.go index 2081edc..6180303 100644 --- a/arthas/http.go +++ b/arthas/http.go @@ -1,16 +1,10 @@ package main import ( - "bytes" "context" "encoding/json" - "fmt" "io" - "log" "net/http" - "net/http/httputil" - "net/url" - "os" "strings" "github.com/flanksource/incident-commander/plugin/sdk" @@ -43,206 +37,3 @@ func (p *ArthasPlugin) httpInvoke(operation string, handler func(context.Context } }) } - -func (p *ArthasPlugin) HTTPHandler() http.Handler { - mux := http.NewServeMux() - mux.HandleFunc("/proxy/", p.httpProxyConsole) - mux.HandleFunc("/mcp/", p.httpProxyMCP) - mux.Handle("/version", sdk.VersionHandler(sdk.BuildInfo{ - Name: "arthas", - Version: Version, - BuildDate: BuildDate, - UIChecksum: uiChecksum, - })) - return mux -} - -func (p *ArthasPlugin) httpProxyConsole(w http.ResponseWriter, r *http.Request) { - p.proxyTo(w, r, "/proxy/", func(s sessionPorts) int { return s.HTTP }, true) -} - -func (p *ArthasPlugin) httpProxyMCP(w http.ResponseWriter, r *http.Request) { - p.proxyTo(w, r, "/mcp/", func(s sessionPorts) int { return s.MCP }, false) -} - -type sessionPorts struct { - HTTP int - MCP int -} - -func (p *ArthasPlugin) proxyTo(w http.ResponseWriter, r *http.Request, prefix string, portOf func(sessionPorts) int, rewriteHTML bool) { - rest := strings.TrimPrefix(r.URL.Path, prefix) - id, tail, _ := strings.Cut(rest, "/") - if id == "" { - http.Error(w, "missing session id", http.StatusBadRequest) - return - } - sess, ok := p.sessions.Get(id) - if !ok { - http.Error(w, "session not found", http.StatusNotFound) - return - } - port := portOf(sessionPorts{HTTP: sess.HTTPLocalPort, MCP: sess.MCPLocalPort}) - if port == 0 { - http.Error(w, "session endpoint is not enabled", http.StatusBadRequest) - return - } - target, _ := url.Parse(fmt.Sprintf("http://127.0.0.1:%d", port)) - proxy := httputil.NewSingleHostReverseProxy(target) - proxy.ErrorLog = log.New(os.Stderr, "[WARN] arthas console proxy: ", 0) - if rewriteHTML { - // The browser sees this iframe behind the host's UI proxy, so absolute - // URLs we inject must include the X-Forwarded-Prefix the host set. - hostPrefix := strings.TrimRight(r.Header.Get("X-Forwarded-Prefix"), "/") - basePrefix := fmt.Sprintf("%s%s%s/", hostPrefix, prefix, id) - proxy.ModifyResponse = func(resp *http.Response) error { - return rewriteArthasResponse(resp, basePrefix) - } - } - r.URL.Path = "/" + tail - r.URL.RawPath = "" - proxy.ServeHTTP(w, r) -} - -func rewriteArthasResponse(resp *http.Response, basePrefix string) error { - rewriteLocation(resp, basePrefix) - - ctype := resp.Header.Get("Content-Type") - isHTML := strings.Contains(ctype, "text/html") - isJS := strings.Contains(ctype, "javascript") - isCSS := strings.Contains(ctype, "text/css") - if !isHTML && !isJS && !isCSS { - return nil - } - body, err := io.ReadAll(resp.Body) - if err != nil { - return err - } - _ = resp.Body.Close() - - proxyRoot := strings.TrimSuffix(basePrefix, "/") - if isHTML { - body = rewriteHTMLRootPaths(body, basePrefix) - wsShim := fmt.Appendf(nil, ``, basePrefix, proxyRoot) - idx := bytes.Index(body, []byte("")) - if idx < 0 { - idx = bytes.Index(bytes.ToLower(body), []byte("")) - } - if idx >= 0 { - insertAt := idx + len("") - base := fmt.Appendf(nil, ``, basePrefix) - inject := append(base, wsShim...) - body = append(body[:insertAt], append(inject, body[insertAt:]...)...) - } - } - if isJS { - body = rewriteScriptRootPaths(body, proxyRoot) - } - if isCSS { - body = rewriteCSSRootPaths(body, proxyRoot) - } - resp.Body = io.NopCloser(bytes.NewReader(body)) - resp.ContentLength = int64(len(body)) - resp.Header.Set("Content-Length", fmt.Sprint(len(body))) - return nil -} - -func rewriteLocation(resp *http.Response, basePrefix string) { - loc := resp.Header.Get("Location") - if loc == "" { - return - } - proxyRoot := strings.TrimSuffix(basePrefix, "/") - for _, root := range []string{"/static/", "/api", "/ws"} { - if loc == root || strings.HasPrefix(loc, root+"/") || strings.HasPrefix(loc, root) && strings.HasSuffix(root, "/") { - resp.Header.Set("Location", proxyRoot+loc) - return - } - } -} - -func rewriteHTMLRootPaths(body []byte, basePrefix string) []byte { - proxyRoot := strings.TrimSuffix(basePrefix, "/") - attrs := []string{"src", "href", "action", "poster", "data", "content"} - for _, attr := range attrs { - for _, quote := range []byte{'"', '\''} { - for _, root := range proxiedRoots() { - old := []byte(fmt.Sprintf(`%s=%c%s`, attr, quote, root)) - newValue := proxyRoot + root - body = bytes.ReplaceAll(body, old, []byte(fmt.Sprintf(`%s=%c%s`, attr, quote, newValue))) - } - } - } - body = rewriteCSSRootPaths(body, proxyRoot) - return body -} - -func rewriteScriptRootPaths(body []byte, proxyRoot string) []byte { - for _, quote := range []byte{'"', '\'', '`'} { - for _, root := range proxiedRoots() { - old := []byte{quote} - old = append(old, root...) - newValue := []byte{quote} - newValue = append(newValue, proxyRoot...) - newValue = append(newValue, root...) - body = bytes.ReplaceAll(body, old, newValue) - } - } - return body -} - -func rewriteCSSRootPaths(body []byte, proxyRoot string) []byte { - for _, root := range proxiedRoots() { - body = bytes.ReplaceAll(body, []byte("url("+root), []byte("url("+proxyRoot+root)) - body = bytes.ReplaceAll(body, []byte(`url("`+root), []byte(`url("`+proxyRoot+root)) - body = bytes.ReplaceAll(body, []byte(`url('`+root), []byte(`url('`+proxyRoot+root)) - } - return body -} - -func proxiedRoots() []string { - return []string{"/api", "/ws", "/static/"} -} diff --git a/arthas/http_test.go b/arthas/http_test.go deleted file mode 100644 index 0238a80..0000000 --- a/arthas/http_test.go +++ /dev/null @@ -1,71 +0,0 @@ -package main - -import ( - "io" - "net/http" - "strings" - - ginkgo "github.com/onsi/ginkgo/v2" - . "github.com/onsi/gomega" -) - -var _ = ginkgo.Describe("Arthas proxy rewriting", func() { - ginkgo.It("rewrites root absolute assets in HTML", func() { - resp := &http.Response{ - Header: http.Header{"Content-Type": []string{"text/html"}}, - Body: io.NopCloser(strings.NewReader(``)), - } - Expect(rewriteArthasResponse(resp, "/proxy/s1/")).To(Succeed()) - body, err := io.ReadAll(resp.Body) - Expect(err).ToNot(HaveOccurred()) - Expect(string(body)).To(ContainSubstring(`src="/proxy/s1/static/js/main.js"`)) - Expect(string(body)).To(ContainSubstring("window.WebSocket")) - }) - - ginkgo.It("rewrites assets through the host UI prefix when present", func() { - resp := &http.Response{ - Header: http.Header{"Content-Type": []string{"text/html"}}, - Body: io.NopCloser(strings.NewReader(`
`)), - } - basePrefix := "/api/plugins/arthas/ui/proxy/s1/" - Expect(rewriteArthasResponse(resp, basePrefix)).To(Succeed()) - body, err := io.ReadAll(resp.Body) - Expect(err).ToNot(HaveOccurred()) - got := string(body) - Expect(got).To(ContainSubstring(``)) - Expect(got).To(ContainSubstring(`src="/api/plugins/arthas/ui/proxy/s1/static/js/main.js"`)) - Expect(got).To(ContainSubstring(`href="/api/plugins/arthas/ui/proxy/s1/static/main.css"`)) - Expect(got).To(ContainSubstring(`action="/api/plugins/arthas/ui/proxy/s1/api"`)) - Expect(got).To(ContainSubstring(`proxyBase = "/api/plugins/arthas/ui/proxy/s1/"`)) - }) - - ginkgo.It("rewrites JS root-relative service paths via the host prefix", func() { - resp := &http.Response{ - Header: http.Header{"Content-Type": []string{"application/javascript"}}, - Body: io.NopCloser(strings.NewReader(`fetch("/api"); new WebSocket("/ws"); var u = "/static/js/extra.js"; var v = '/static/img/logo.png';`)), - } - Expect(rewriteArthasResponse(resp, "/api/plugins/arthas/ui/proxy/s1/")).To(Succeed()) - body, err := io.ReadAll(resp.Body) - Expect(err).ToNot(HaveOccurred()) - got := string(body) - Expect(got).To(ContainSubstring(`fetch("/api/plugins/arthas/ui/proxy/s1/api")`)) - Expect(got).To(ContainSubstring(`new WebSocket("/api/plugins/arthas/ui/proxy/s1/ws")`)) - Expect(got).To(ContainSubstring(`"/api/plugins/arthas/ui/proxy/s1/static/js/extra.js"`)) - Expect(got).To(ContainSubstring(`'/api/plugins/arthas/ui/proxy/s1/static/img/logo.png'`)) - }) - - ginkgo.It("rewrites CSS urls and redirect locations", func() { - resp := &http.Response{ - Header: http.Header{ - "Content-Type": []string{"text/css"}, - "Location": []string{"/api"}, - }, - Body: io.NopCloser(strings.NewReader(`.logo{background:url(/static/png/arthas.png)}`)), - } - Expect(rewriteArthasResponse(resp, "/api/plugins/arthas/ui/proxy/s1/")).To(Succeed()) - Expect(resp.Header.Get("Location")).To(Equal("/api/plugins/arthas/ui/proxy/s1/api")) - body, err := io.ReadAll(resp.Body) - Expect(err).ToNot(HaveOccurred()) - Expect(string(body)).To(ContainSubstring(`url(/api/plugins/arthas/ui/proxy/s1/static/png/arthas.png)`)) - }) -}) diff --git a/arthas/internal/arthas/bootstrap.go b/arthas/internal/arthas/bootstrap.go index db5e371..2f499f6 100644 --- a/arthas/internal/arthas/bootstrap.go +++ b/arthas/internal/arthas/bootstrap.go @@ -30,7 +30,6 @@ const ( ArthasJarPath = "/tmp/arthas-boot.jar" ArthasBootURL = "https://arthas.aliyun.com/arthas-boot.jar" DefaultRemoteHTTP = 8563 - DefaultRemoteMCP = 8777 ) // portProbePrelude is a POSIX-sh helper injected at the top of every exec @@ -68,9 +67,7 @@ type StartOptions struct { Pod string Container string LocalHTTP int // 0 = auto-allocate - LocalMCP int // 0 = auto-allocate RemoteHTTP int // defaults to 8563 - RemoteMCP int // defaults to 8777 // SkipJDKInstall bypasses the Java 8 JRE side-load; the attach will fail // loud if tools.jar is missing. Intended for operators who've provisioned // the pod out-of-band. @@ -78,18 +75,14 @@ type StartOptions struct { } // Start runs the full bootstrap: ensure Arthas jar is present, attach it to -// PID 1 with HTTP enabled, start the MCP server plugin, and open port-forwards -// to the caller's workstation. The returned Session carries a Stop closure -// that tears down the port-forwards. Note: the in-pod Arthas process is left -// running; a subsequent Start on the same pod will reuse it. +// PID 1 with HTTP enabled, and open a port-forward to the Arthas HTTP API. +// The returned Session carries a Stop closure that tears down the port-forward. +// Note: the in-pod Arthas process is left running; a subsequent Start on the +// same pod will reuse it. func Start(ctx context.Context, restCfg *rest.Config, opts StartOptions) (*Session, error) { if opts.RemoteHTTP == 0 { opts.RemoteHTTP = DefaultRemoteHTTP } - if opts.RemoteMCP == 0 { - opts.RemoteMCP = DefaultRemoteMCP - } - javaInfo, err := detectJava(ctx, restCfg, opts) if err != nil { return nil, fmt.Errorf("detect java: %w", err) @@ -111,30 +104,11 @@ func Start(ctx context.Context, restCfg *rest.Config, opts StartOptions) (*Sessi if err := attachArthas(ctx, restCfg, opts, javaHome, remoteTelnet); err != nil { return nil, fmt.Errorf("attach arthas: %w", err) } - // MCP plugin is distributed separately from arthas-boot and isn't present - // in upstream arthas 4.1.x. Attempt to start it — if the command doesn't - // exist, fall through: the arthas HTTP /api endpoint on :8563 is itself a - // fully-featured REST surface the UI exposes directly, so MCP is a nice- - // to-have, not a hard requirement. - mcpEnabled := true - if err := enableMCP(ctx, restCfg, opts); err != nil { - mcpEnabled = false - } - _ = mcpEnabled // surfaced to Session below - localHTTP, err := pickLocalPort(opts.LocalHTTP) if err != nil { return nil, err } mappings := []k8s.PortMapping{{LocalPort: localHTTP, RemotePort: opts.RemoteHTTP}} - localMCP := 0 - if mcpEnabled { - localMCP, err = pickLocalPort(opts.LocalMCP) - if err != nil { - return nil, err - } - mappings = append(mappings, k8s.PortMapping{LocalPort: localMCP, RemotePort: opts.RemoteMCP}) - } fwd, ready, err := k8s.StartPortForward(restCfg, opts.Namespace, opts.Pod, mappings, io.Discard, io.Discard) if err != nil { @@ -145,13 +119,12 @@ func Start(ctx context.Context, restCfg *rest.Config, opts StartOptions) (*Sessi return nil, fmt.Errorf("port-forward not ready: %w", err) } - sess := NewSession(opts.Namespace, opts.Kind, opts.Name, opts.Pod, opts.Container, localHTTP, localMCP, func() error { + sess := NewSession(opts.Namespace, opts.Kind, opts.Name, opts.Pod, opts.Container, localHTTP, func() error { return fwd.Close() }) sess.JavaVersion = javaInfo.Major sess.JDKProvisioned = javaHome != "" sess.SideloadedJavaHome = javaHome - sess.MCPEnabled = mcpEnabled return sess, nil } @@ -193,7 +166,7 @@ if probe_port 127.0.0.1 %[1]d; then exit 0; fi # answers it bails with "already listen port ..., skip attach". Some base # images already bind 3658 for other reasons, so we pick a fresh high port # per session (the telnet listener stays loopback-only anyway — we only -# port-forward HTTP + MCP to the caller). +# port-forward HTTP to the plugin process). if probe_port 127.0.0.1 %[4]d; then echo "chosen telnet port %[4]d is already in use in the pod; retry to pick a different port" >&2 exit 1 @@ -245,29 +218,6 @@ exit 1`, opts.RemoteHTTP, ArthasJarPath, javaHomeExport, remoteTelnet) return execSh(ctx, restCfg, opts, script) } -func enableMCP(ctx context.Context, restCfg *rest.Config, opts StartOptions) error { - // Use Arthas HTTP API to start the mcp-server plugin. - // https://arthas.aliyun.com/en/doc/http-api.html - script := fmt.Sprintf(`set -e -`+portProbePrelude+` -if probe_port 127.0.0.1 %[2]d; then exit 0; fi -RESP=$(curl -sS -XPOST "http://127.0.0.1:%[1]d/api" \ - -H 'Content-Type: application/json' \ - -d '{"action":"exec","command":"mcp-server start --port %[2]d"}') -echo "$RESP" -echo "$RESP" | grep -q '"state":"SUCCEEDED"' || { - echo "mcp-server plugin did not start (needs Arthas with MCP support)" >&2 - exit 1 -} -for i in $(seq 1 20); do - if probe_port 127.0.0.1 %[2]d; then exit 0; fi - sleep 0.5 -done -echo "mcp port %[2]d did not come up" >&2 -exit 1`, opts.RemoteHTTP, opts.RemoteMCP) - return execSh(ctx, restCfg, opts, script) -} - func execSh(ctx context.Context, restCfg *rest.Config, opts StartOptions, script string) error { var stdout, stderr bytes.Buffer err := k8s.ExecInPod(ctx, restCfg, k8s.ExecOptions{ diff --git a/arthas/internal/arthas/session.go b/arthas/internal/arthas/session.go index 4c47535..28310dd 100644 --- a/arthas/internal/arthas/session.go +++ b/arthas/internal/arthas/session.go @@ -20,7 +20,6 @@ type Session struct { Pod string `json:"pod"` Container string `json:"container"` HTTPLocalPort int `json:"httpLocalPort"` - MCPLocalPort int `json:"mcpLocalPort"` StartedAt time.Time `json:"startedAt"` // JavaVersion is the major version detected via `java -version` in the @@ -32,10 +31,6 @@ type Session struct { // SideloadedJavaHome is the path inside the pod where the downloaded JDK // lives, when JDKProvisioned is true. SideloadedJavaHome string `json:"sideloadedJavaHome,omitempty"` - // MCPEnabled is true when the arthas mcp-server plugin was successfully - // started. Upstream arthas 4.1.x doesn't bundle MCP, so this is often - // false; clients should fall back to arthas' native HTTP /api endpoint. - MCPEnabled bool `json:"mcpEnabled"` stop func() error stopOnce sync.Once @@ -118,7 +113,7 @@ func (r *SessionRegistry) StopAll() { } // NewSession builds a Session with a random ID and installs the Stop closure. -func NewSession(namespace, kind, name, pod, container string, httpPort, mcpPort int, stop func() error) *Session { +func NewSession(namespace, kind, name, pod, container string, httpPort int, stop func() error) *Session { return &Session{ ID: newID(), Namespace: namespace, @@ -127,7 +122,6 @@ func NewSession(namespace, kind, name, pod, container string, httpPort, mcpPort Pod: pod, Container: container, HTTPLocalPort: httpPort, - MCPLocalPort: mcpPort, StartedAt: time.Now().UTC(), stop: stop, } diff --git a/arthas/ops.go b/arthas/ops.go index f2b65df..b175ff1 100644 --- a/arthas/ops.go +++ b/arthas/ops.go @@ -42,9 +42,7 @@ type SessionCreateParams struct { Pod string `json:"pod,omitempty"` Container string `json:"container,omitempty"` LocalHTTP int `json:"localHttp,omitempty"` - LocalMCP int `json:"localMcp,omitempty"` RemoteHTTP int `json:"remoteHttp,omitempty"` - RemoteMCP int `json:"remoteMcp,omitempty"` SkipJDKInstall bool `json:"skipJdkInstall,omitempty"` } @@ -123,9 +121,7 @@ func (p *ArthasPlugin) sessionCreate(ctx context.Context, req sdk.InvokeCtx) (an Pod: pod, Container: container, LocalHTTP: params.LocalHTTP, - LocalMCP: params.LocalMCP, RemoteHTTP: params.RemoteHTTP, - RemoteMCP: params.RemoteMCP, SkipJDKInstall: params.SkipJDKInstall, }) if err != nil { diff --git a/arthas/ui-src/src/lib/api.ts b/arthas/ui-src/src/lib/api.ts index 745fd25..b3f80dc 100644 --- a/arthas/ui-src/src/lib/api.ts +++ b/arthas/ui-src/src/lib/api.ts @@ -43,7 +43,3 @@ export async function callOp( export function configIDFromURL(): string { return new URLSearchParams(window.location.search).get("config_id") ?? ""; } - -export function pluginURL(path: string): string { - return new URL(path.replace(/^\//, ""), window.location.href).toString(); -} diff --git a/arthas/ui-src/src/pages/ArthasDashboardTab.tsx b/arthas/ui-src/src/pages/ArthasDashboardTab.tsx index 89eef56..51d140c 100644 --- a/arthas/ui-src/src/pages/ArthasDashboardTab.tsx +++ b/arthas/ui-src/src/pages/ArthasDashboardTab.tsx @@ -9,7 +9,7 @@ import { type ProcessNode, type ProgressSegment, } from "@flanksource/clicky-ui"; -import { pluginURL } from "@/lib/api"; +import { callOp } from "@/lib/api"; import { Input } from "@/components/ui/input"; import { Spinner } from "@/components/ui/spinner"; @@ -61,19 +61,8 @@ async function execArthas( sessionId: string, command: string, ): Promise<{ results: unknown[]; state: string }> { - const res = await fetch(pluginURL(`proxy/${sessionId}/api`), { - method: "POST", - headers: { "Content-Type": "application/json" }, - body: JSON.stringify({ action: "exec", command }), - }); - if (!res.ok) throw new Error(`arthas exec (${command}): ${res.status}`); - const body = await res.json(); - const state = body.state ?? body?.body?.state ?? "UNKNOWN"; - const results = body?.body?.results ?? []; - if (state !== "SUCCEEDED") { - throw new Error(`arthas command "${command}" failed (${state}): ${body?.body?.message ?? ""}`); - } - return { results, state }; + const body = await callOp<{ results?: unknown[]; state?: string }>("exec", { sessionId, command }); + return { results: body.results ?? [], state: body.state ?? "UNKNOWN" }; } function fmtBytes(n: number | undefined): string { diff --git a/arthas/ui-src/src/pages/ArthasPage.tsx b/arthas/ui-src/src/pages/ArthasPage.tsx index f635817..c1375ef 100644 --- a/arthas/ui-src/src/pages/ArthasPage.tsx +++ b/arthas/ui-src/src/pages/ArthasPage.tsx @@ -1,11 +1,11 @@ import { useEffect, useMemo, useRef, useState } from "react"; import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; -import { Bug, Check, ChevronDown, Copy, Plus, Trash2 } from "lucide-react"; +import { Bug, ChevronDown, Plus, Trash2 } from "lucide-react"; import { Button } from "@/components/ui/button"; import { Spinner } from "@/components/ui/spinner"; import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; import { toastManager } from "@/components/ui/toast"; -import { callOp, configIDFromURL, pluginURL } from "@/lib/api"; +import { callOp, configIDFromURL } from "@/lib/api"; import { ArthasDashboardTab } from "./ArthasDashboardTab"; import { ArthasMBeanTab } from "./ArthasMBeanTab"; import { ArthasOgnlTab } from "./ArthasOgnlTab"; @@ -19,12 +19,10 @@ interface ArthasSession { pod: string; container: string; httpLocalPort: number; - mcpLocalPort: number; startedAt: string; javaVersion?: number; jdkProvisioned?: boolean; sideloadedJavaHome?: string; - mcpEnabled?: boolean; } interface RunningPod { @@ -317,26 +315,20 @@ function SessionDetail({ }: { session: ArthasSession; } & SessionMenuProps) { - const [tab, setTab] = useState("console"); - const consoleURL = pluginURL(`proxy/${session.id}/`); + const [tab, setTab] = useState("dashboard"); return (
- Web Console - OGNL Dashboard + OGNL MBeans Profiler - {session.mcpEnabled ? MCP : HTTP API} Info
- - - @@ -349,12 +341,6 @@ function SessionDetail({ - - - - - -
Session ID
@@ -376,79 +362,3 @@ function SessionDetail({ ); } - -function ConsoleFrame({ src, pod }: { src: string; pod: string }) { - const [loaded, setLoaded] = useState(false); - const ref = useRef(null); - return ( -
- {!loaded && ( -
- - Connecting to Arthas web console… -
- )} -