From c6d10ed74a056001edbb475ed948c14b8a9cd44b Mon Sep 17 00:00:00 2001 From: Xuan Gu <162244362+xuang7@users.noreply.github.com> Date: Sat, 4 Jul 2026 19:39:29 -0700 Subject: [PATCH 1/4] fix: repair Python virtual environment in single-node deployment --- .../pythonvirtualenvironment/PveManager.scala | 12 ++++++++---- bin/single-node/nginx.conf | 10 ++++++++++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/amber/src/main/scala/org/apache/texera/web/resource/pythonvirtualenvironment/PveManager.scala b/amber/src/main/scala/org/apache/texera/web/resource/pythonvirtualenvironment/PveManager.scala index 2256798030b..1f1eedfe054 100644 --- a/amber/src/main/scala/org/apache/texera/web/resource/pythonvirtualenvironment/PveManager.scala +++ b/amber/src/main/scala/org/apache/texera/web/resource/pythonvirtualenvironment/PveManager.scala @@ -94,11 +94,15 @@ object PveManager { } } + // The lock file is copied to /tmp/system-requirements-lock.txt inside every + // deployed image (see bin/computing-unit-master.dockerfile), so single-node + // Docker and Kubernetes both find it there. Only a source-tree dev run reads + // the repo-relative amber/ copy. `isLocal` alone can't distinguish a + // containerized single-node run (also non-k8s) from a dev run, so probe. private def getSystemPath(isLocal: Boolean): Path = { - Paths.get( - if (isLocal) "amber/system-requirements-lock.txt" - else "/tmp/system-requirements-lock.txt" - ) + val deployPath = Paths.get("/tmp/system-requirements-lock.txt") + if (Files.exists(deployPath)) deployPath + else Paths.get("amber/system-requirements-lock.txt") } def getSystemPackages(isLocal: Boolean): Seq[String] = { diff --git a/bin/single-node/nginx.conf b/bin/single-node/nginx.conf index 515a7016da0..a5b4490ffc7 100644 --- a/bin/single-node/nginx.conf +++ b/bin/single-node/nginx.conf @@ -95,6 +95,16 @@ http { proxy_set_header Host $host; } + # Python Virtual Environment (PVE) REST endpoints are served by the + # amber webserver under /api/pve. Mirror the dev proxy and k8s gateway + # by rewriting /pve -> /api/pve before proxying. + location /pve/ { + rewrite ^/pve/(.*)$ /api/pve/$1 break; + proxy_pass http://workflow-runtime-coordinator-service:8085; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } + # Fallback for all other routes location / { proxy_pass http://dashboard-service:8080; From 5ae3794213f604d9d1a1dd2ad464a22404cd3138 Mon Sep 17 00:00:00 2001 From: Xuan Gu <162244362+xuang7@users.noreply.github.com> Date: Mon, 6 Jul 2026 15:55:47 -0700 Subject: [PATCH 2/4] simplify /pve route to prefix-replacing proxy_pass Co-Authored-By: Claude Fable 5 --- bin/single-node/nginx.conf | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/bin/single-node/nginx.conf b/bin/single-node/nginx.conf index a5b4490ffc7..deffb6021ef 100644 --- a/bin/single-node/nginx.conf +++ b/bin/single-node/nginx.conf @@ -95,12 +95,8 @@ http { proxy_set_header Host $host; } - # Python Virtual Environment (PVE) REST endpoints are served by the - # amber webserver under /api/pve. Mirror the dev proxy and k8s gateway - # by rewriting /pve -> /api/pve before proxying. location /pve/ { - rewrite ^/pve/(.*)$ /api/pve/$1 break; - proxy_pass http://workflow-runtime-coordinator-service:8085; + proxy_pass http://workflow-runtime-coordinator-service:8085/api/pve/; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } From 447a235379a64fec0c7f457735c20d47289faa9f Mon Sep 17 00:00:00 2001 From: Xuan Gu <162244362+xuang7@users.noreply.github.com> Date: Tue, 7 Jul 2026 15:51:52 -0700 Subject: [PATCH 3/4] request /api/pve from the frontend and drop all gateway rewrites v1.2 adaptation of b86474568 on main (PR #6130): the frontend builds PVE URLs with AppSettings.getApiEndpoint(), so single-node nginx, the dev proxy, and the k8s gateway all become plain routes with no rewriting. Fewer files than on main because this branch predates the StoredPve db endpoints and the gateway chart reorganization. Co-Authored-By: Claude Fable 5 --- bin/k8s/templates/gateway-routes.yaml | 13 +------------ bin/single-node/nginx.conf | 4 ++-- frontend/proxy.config.json | 13 +++++-------- .../virtual-environment.service.ts | 9 +++++---- 4 files changed, 13 insertions(+), 26 deletions(-) diff --git a/bin/k8s/templates/gateway-routes.yaml b/bin/k8s/templates/gateway-routes.yaml index ac8096aa212..935d38bb079 100644 --- a/bin/k8s/templates/gateway-routes.yaml +++ b/bin/k8s/templates/gateway-routes.yaml @@ -124,20 +124,9 @@ spec: - path: type: PathPrefix value: /api/executions/result/export - backendRefs: - - group: gateway.envoyproxy.io - kind: Backend - name: texera-dynamic-backend - - matches: - path: type: PathPrefix - value: /pve - filters: - - type: URLRewrite - urlRewrite: - path: - type: ReplacePrefixMatch - replacePrefixMatch: /api/pve + value: /api/pve backendRefs: - group: gateway.envoyproxy.io kind: Backend diff --git a/bin/single-node/nginx.conf b/bin/single-node/nginx.conf index deffb6021ef..c05a45e1bfe 100644 --- a/bin/single-node/nginx.conf +++ b/bin/single-node/nginx.conf @@ -95,8 +95,8 @@ http { proxy_set_header Host $host; } - location /pve/ { - proxy_pass http://workflow-runtime-coordinator-service:8085/api/pve/; + location /api/pve/ { + proxy_pass http://workflow-runtime-coordinator-service:8085; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } diff --git a/frontend/proxy.config.json b/frontend/proxy.config.json index f68602e0714..6802ae762c4 100755 --- a/frontend/proxy.config.json +++ b/frontend/proxy.config.json @@ -50,18 +50,15 @@ "secure": false, "changeOrigin": true }, - "/api": { - "target": "http://localhost:8080", + "/api/pve": { + "target": "http://localhost:8085", "secure": false, "changeOrigin": false }, - "/pve": { - "target": "http://localhost:8085", + "/api": { + "target": "http://localhost:8080", "secure": false, - "changeOrigin": false, - "pathRewrite": { - "^/pve": "/api/pve" - } + "changeOrigin": false }, "/wsapi": { "target": "http://localhost:8085", diff --git a/frontend/src/app/workspace/service/virtual-environment/virtual-environment.service.ts b/frontend/src/app/workspace/service/virtual-environment/virtual-environment.service.ts index d3108e47564..f47cc6b9856 100644 --- a/frontend/src/app/workspace/service/virtual-environment/virtual-environment.service.ts +++ b/frontend/src/app/workspace/service/virtual-environment/virtual-environment.service.ts @@ -21,6 +21,7 @@ import { Observable } from "rxjs"; import { map } from "rxjs/operators"; import { HttpClient, HttpParams } from "@angular/common/http"; import { AuthService } from "../../../common/service/user/auth.service"; +import { AppSettings } from "../../../common/app-setting"; export interface PackageResponse { system: string[]; @@ -51,12 +52,12 @@ export class WorkflowPveService { getSystemPackages(cuid: number): Observable { const params = this.buildBaseParams().set("cuid", cuid.toString()); - return this.http.get("/pve/system", { params }); + return this.http.get(`${AppSettings.getApiEndpoint()}/pve/system`, { params }); } fetchPVEs(cuid: number): Observable { const params = this.buildBaseParams().set("cuid", cuid.toString()); - return this.http.get("/pve/pves", { params }); + return this.http.get(`${AppSettings.getApiEndpoint()}/pve/pves`, { params }); } getUserPackages(cuid: number, pveName: string): Observable { @@ -64,14 +65,14 @@ export class WorkflowPveService { } deleteEnvironments(cuid: number) { - return this.http.delete(`/pve/pves/${cuid}`); + return this.http.delete(`${AppSettings.getApiEndpoint()}/pve/pves/${cuid}`); } deletePackage(cuid: number, pveName: string, packageName: string) { const params = this.buildBaseParams(); return this.http.delete( - `/pve/${cuid}/${encodeURIComponent(pveName)}/packages/${encodeURIComponent(packageName)}`, + `${AppSettings.getApiEndpoint()}/pve/${cuid}/${encodeURIComponent(pveName)}/packages/${encodeURIComponent(packageName)}`, { params } ); } From f496f716b59414dddb68168844b48d4305082509 Mon Sep 17 00:00:00 2001 From: Xuan Gu <162244362+xuang7@users.noreply.github.com> Date: Fri, 10 Jul 2026 16:20:09 -0700 Subject: [PATCH 4/4] group /api/pve/ with the other /api/ locations and document prefix matching Mirrors the same change on the main PR (#6130) to keep the two branches identical. Co-Authored-By: Claude Fable 5 --- bin/single-node/nginx.conf | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/bin/single-node/nginx.conf b/bin/single-node/nginx.conf index c05a45e1bfe..c5e500e6670 100644 --- a/bin/single-node/nginx.conf +++ b/bin/single-node/nginx.conf @@ -81,6 +81,13 @@ http { proxy_send_timeout 1d; } + location /api/pve/ { + proxy_pass http://workflow-runtime-coordinator-service:8085; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + } + + # nginx prefix locations match by longest prefix location /api/ { proxy_pass http://dashboard-service:8080; proxy_set_header Host $host; @@ -95,12 +102,6 @@ http { proxy_set_header Host $host; } - location /api/pve/ { - proxy_pass http://workflow-runtime-coordinator-service:8085; - proxy_set_header Host $host; - proxy_set_header X-Real-IP $remote_addr; - } - # Fallback for all other routes location / { proxy_pass http://dashboard-service:8080;