Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
4 changes: 2 additions & 2 deletions .secrets.baseline

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

324 changes: 324 additions & 0 deletions devplanetv2/dev-environments/qa-vpodc-helm/values/values.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,15 @@ frontend-framework:
image:
repository: quay.io/cdis/vpodc-data-commons
tag: feat-update_oncology_filters
env:
HATCHERY_URL: "http://hatchery-service"
HATCHERY_API: "/lw-workspace"
JUPYTER_GATEWAY_URL: "http://jupyter-enterprise-gateway:8888"
JUPYTER_ASSETS_ROOT_PATH: "/gen3/jupyter-workspaces/assets"
GEN3_ENDPOINT: "https://qa-vpodc.planx-pla.net"
KERNEL_SPEC_POLICY: "{}"
ENABLE_JEG: "true"


guppy:
authFilterField: auth_resource_path
Expand Down Expand Up @@ -1588,6 +1597,205 @@ revproxy:
aws:
group: devplanetv2
sslPolicy: ELBSecurityPolicy-TLS13-1-2-FIPS-2023-04
additionalConfigs:
# NOTE: /search/* is not exposed directly by nginx; /guppy/* rewrites to
# /search/* on API Gateway, where the custom authorizer enforces access.
workspace-api.conf: |-
# Free tier is static JupyterLite assets rendered in-browser (WASM only).
# Do not gate these files on workspace launch authz checks.
location ^~ /api/workspace-assets/free/ {
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin $http_origin always;
add_header Access-Control-Allow-Credentials true always;
add_header Access-Control-Allow-Methods "GET, POST, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;
add_header Content-Length 0;
add_header Content-Type text/plain;
return 204;
}
set $upstream http://frontend-framework-service.$namespace.svc.cluster.local;
proxy_pass $upstream;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-URL-SCHEME https;
add_header Access-Control-Allow-Origin $http_origin always;
add_header Access-Control-Allow-Credentials true always;
add_header Access-Control-Allow-Methods "GET, POST, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;
client_max_body_size 0;
proxy_read_timeout 600s;
}

location ^~ /workspace-api/workspace-assets/free/ {
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin $http_origin always;
add_header Access-Control-Allow-Credentials true always;
add_header Access-Control-Allow-Methods "GET, POST, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;
add_header Content-Length 0;
add_header Content-Type text/plain;
return 204;
}
set $upstream http://frontend-framework-service.$namespace.svc.cluster.local;
rewrite ^/workspace-api/(.*) /api/$1 break;
proxy_pass $upstream;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-URL-SCHEME https;
add_header Access-Control-Allow-Origin $http_origin always;
add_header Access-Control-Allow-Credentials true always;
add_header Access-Control-Allow-Methods "GET, POST, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;
client_max_body_size 0;
proxy_read_timeout 600s;
}

# Remote JupyterLite assets served by workspace-proxy (no auth gate — static files).
location ^~ /api/workspace-assets/remote/ {
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin $http_origin always;
add_header Access-Control-Allow-Credentials true always;
add_header Access-Control-Allow-Methods "GET, POST, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;
add_header Content-Length 0;
add_header Content-Type text/plain;
return 204;
}
set $upstream http://frontend-framework-service.$namespace.svc.cluster.local;
proxy_pass $upstream;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-URL-SCHEME https;
add_header Access-Control-Allow-Origin $http_origin always;
add_header Access-Control-Allow-Credentials true always;
add_header Access-Control-Allow-Methods "GET, POST, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;
client_max_body_size 0;
proxy_read_timeout 600s;
}

location ^~ /workspace-api/workspace-assets/remote/ {
if ($request_method = 'OPTIONS') {
add_header Access-Control-Allow-Origin $http_origin always;
add_header Access-Control-Allow-Credentials true always;
add_header Access-Control-Allow-Methods "GET, POST, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;
add_header Content-Length 0;
add_header Content-Type text/plain;
return 204;
}
set $upstream http://frontend-framework-service.$namespace.svc.cluster.local;
rewrite ^/workspace-api/(.*) /api/$1 break;
proxy_pass $upstream;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-URL-SCHEME https;
add_header Access-Control-Allow-Origin $http_origin always;
add_header Access-Control-Allow-Credentials true always;
add_header Access-Control-Allow-Methods "GET, POST, DELETE, OPTIONS" always;
add_header Access-Control-Allow-Headers "Authorization, Content-Type" always;
client_max_body_size 0;
proxy_read_timeout 600s;
}

# Workspace API routes (hatchery options/status/launch, gateway, kernel) are
# handled by the vectis Next.js app API routes — NOT workspace-proxy.
# Next.js rewrites /workspace-api/:path* → /api/:path* internally.
location ^~ /workspace-api/workspace/ {
set $authz_resource "/workspace";
set $authz_method "access";
set $authz_service "jupyterhub";
auth_request /gen3-authz;
error_page 403 = @errorworkspace;
set $upstream http://frontend-framework-service.$namespace.svc.cluster.local;
proxy_pass $upstream;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-URL-SCHEME https;
client_max_body_size 0;
proxy_read_timeout 600s;
}

# JupyterLab kernel tunnel (workspace-proxy handles per-user routing).
location ^~ /workspace-api/ {
set $authz_resource "/workspace";
set $authz_method "access";
set $authz_service "jupyterhub";
auth_request /gen3-authz;
error_page 403 = @errorworkspace;
set $upstream http://workspace-proxy-service.$namespace.svc.cluster.local:8080;
rewrite ^/workspace-api/(.*) /api/$1 break;
proxy_pass $upstream;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Host $host;
proxy_set_header X-URL-SCHEME https;
client_max_body_size 0;
proxy_read_timeout 600s;
}

ambassador-service.conf: |-
location = /lw-workspace/proxy {
return 308 $scheme://$http_host/lw-workspace/proxy/;
}

location /lw-workspace/proxy/ {
set $authz_resource "/workspace";
set $authz_method "access";
set $authz_service "jupyterhub";
auth_request_set $remoteUser $upstream_http_REMOTE_USER;
auth_request_set $saved_set_cookie $upstream_http_set_cookie;
auth_request /gen3-authz;

if ($saved_set_cookie != "") {
add_header Set-Cookie $saved_set_cookie always;
}
add_header Cache-Control "no-store";

proxy_set_header REMOTE_USER $remoteUser;
error_page 403 = @errorworkspace;

set $proxy_service "workspace-proxy";
set $upstream http://workspace-proxy-service.$namespace.svc.cluster.local:8080;
rewrite ^/lw-workspace/proxy/$ /lab break;
rewrite ^/lw-workspace/proxy/(.*) /$1 break;
proxy_pass $upstream;
proxy_redirect http://$host/ https://$host/lw-workspace/proxy/;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
proxy_set_header X-URL-SCHEME https;
client_max_body_size 0;
proxy_read_timeout 36000s;
}

sheepdog:
enabled: true
image:
Expand All @@ -1612,3 +1820,119 @@ wts:
image:
repository: 707767160287.dkr.ecr.us-east-1.amazonaws.com/gen3/workspace-token-service
tag: "2025.10"

workspace-proxy:
enabled: true
deploymentNamespace: qa-vpodc-helm
workspaceNamespace: jupyter-pods-qa-vpodc
kubernetesApiServerCIDRs:
- "10.100.0.1/32" # kubernetes ClusterIP (pre-DNAT)
- "172.27.140.0/22" # EKS private subnet (DHCP)
- "172.27.136.0/22" # EKS private subnet (DHCP)
- "172.27.132.0/22" # EKS private subnet (DHCP)

replicaCount: 1

image:
repository: quay.io/cdis/multihead-workspace-proxy
tag: master
pullPolicy: Always

listenAddr: ":8080"
jegKernelSpecPolicy: |
{
"allowedSpecs": [
"python_kubernetes",
"python_tensorflow_kubernetes",
"python_tensorflow_gpu_kubernetes"
]
}

resources:
requests:
cpu: "50m"
memory: "64Mi"
limits:
cpu: "500m"
memory: "256Mi"

networkPolicy:
enabled: true

jeg:
enabled: true
workspaceNamespace: jupyter-pods-qa-vpodc

replicaCount: 1

image:
repository: quay.io/cdis/gen3-vectis
tag: "qa-jegv2"
pullPolicy: Always

env:
# CRITICAL: must match hatchery user-namespace and workspace-proxy WORKSPACE_NAMESPACE.
EG_NAMESPACE: jupyter-pods-qa-vpodc
EG_KERNEL_LAUNCH_TIMEOUT: "120"
EG_MAX_KERNELS_PER_USER: "2"
EG_CULL_IDLE_TIMEOUT: "14400"
EG_CULL_CONNECTED: "True"
EG_AUTH_TOKEN: ""
EG_DEFAULT_KERNEL_NAME: python3
EG_LIST_KERNELS: "True"
EG_KERNEL_IMAGE_PULL_POLICY: IfNotPresent
EG_SHARED_NAMESPACE: "True"
EG_MIRROR_WORKING_DIRS: "False"
EG_KERNEL_SPEC_POLICY: |
{
"default_kernel_name": "python3",
"kernel_specs": {
"python3": {
"display_name": "Python (Micro — Local)",
"language": "python"
},
"python_kubernetes": {
"display_name": "Python on Kubernetes (4Gi, 2 cpu)",
"language": "python",
"image_name": "elyra/kernel-py:latest",
"resources": {
"cpu": "2",
"memory": "4Gi",
"gpu_type": "none"
}
},
"python_tensorflow_kubernetes": {
"display_name": "Python on Kubernetes with TensorFlow (4Gi, 1 cpu)",
"language": "python",
"image_name": "elyra/kernel-py-tensorflow:latest",
"resources": {
"cpu": "1",
"memory": "4Gi",
"gpu_type": "none"
}
},
"python_tensorflow_gpu_kubernetes": {
"display_name": "Python on Kubernetes with TensorFlow with GPUs (8Gi, 2 cpu, gpu)",
"language": "python",
"image_name": "elyra/kernel-py-tensorflow:latest",
"resources": {
"cpu": "2",
"memory": "8Gi",
"gpu_type": "NVIDIA"
}
},
"r_kubernetes": {
"display_name": "R on Kubernetes",
"language": "r",
"image_name": "elyra/kernel-r:latest"
}
}
}

resources:
requests:
cpu: "100m"
memory: "256Mi"
limits:
cpu: "500m"
memory: "512Mi"
Loading