An OpenShift Console Dynamic Plugin for booking and managing shared GPU resources with Kueue integration. Users reserve GPU time slots through an interactive calendar interface embedded directly in the OpenShift console, and the system automatically manages Kueue ClusterQueue quotas to enforce reservation priority via workload preemption.
- OpenShift Console integration - runs as a dynamic plugin inside the OpenShift web console (admin perspective)
- Interactive calendar with day/multi-day/hour-range bookings, Ctrl+click multi-select, Shift+click ranges, and right-click context menu
- GPU auto-discovery - automatically detects GPU types, MIG partitions, and cluster capacity from Kubernetes node labels and allocatable resources
- Kueue integration - automatically syncs LocalQueue GPU usage as "consumed" bookings; user reservations take priority and trigger workload preemption
- Reservation system - creates per-user ClusterQueues with protected
nominalQuota, ensuring reserved workloads cannot be preempted by unreserved ones - Admin dashboard - sortable/filterable bookings table, runtime reservation sync toggle, on-demand GPU discovery, database export/import
- Built-in help - 8-page markdown documentation with sidebar navigation
- OpenShift auth - authentication via console
UserTokenproxy and Kubernetes TokenReview/SubjectAccessReview
┌──────────────────────────────────────────────────────────────┐
│ OpenShift Console │
│ │
│ ┌────────────────────────────────────────────────┐ │
│ │ GPU Booking Plugin (React / PatternFly v6) │ │
│ │ BookingPage │ AdminPage │ HelpPage │ │
│ └───────┬────────────────────────────────────────┘ │
│ │ /api/proxy/plugin/gpu-booking-plugin/backend/api │
│ │ (Bearer token injected by console) │
│ ┌───────▼────────────────────────────────────────┐ │
│ │ Console Proxy (UserToken) │ │
│ └───────┬────────────────────────────────────────┘ │
└──────────┼───────────────────────────────────────────────────┘
│
┌────────▼─────────────────────────────────────────────┐
│ GPU Booking Pod (:9443 TLS) │
│ │
│ Go Backend │
│ ├── Auth (TokenReview + SubjectAccessReview) │
│ ├── Booking API (CRUD, bulk, conflict resolution) │
│ ├── Admin API (list, delete, export/import DB) │
│ ├── GPU Discovery (5m - auto-detect from nodes) │
│ ├── Kueue Sync (30s - consumed bookings) │
│ ├── Reservation Sync (10m - K8s resources) │
│ └── Static Assets (plugin dist/) │
│ │
│ SQLite DB (/app/data/bookings.db) │
└──────────────────────────────────────────────────────┘
│
┌────────▼─────────────────────────────────────────────┐
│ Kueue API (ClusterQueues, LocalQueues, Cohorts) │
│ HardwareProfiles (infrastructure.opendatahub.io) │
└──────────────────────────────────────────────────────┘
The plugin runs as a single pod with one container. The Go backend serves both the plugin's static assets (loaded by the OpenShift console) and the REST API. Authentication is handled by the console's UserToken proxy, which forwards the logged-in user's Bearer token to the backend.
For the full architecture details, see ARCHITECTURE.md.
- Go 1.25+
- Node.js 22+
- yarn
- SQLite development libraries (
sqlite-develorsqlite-libs) - An OpenShift 4.x cluster with Kueue installed
Full openshift console development commands.
# Install frontend dependencies for the plugin
yarn install
# Start the backend (with Kueue sync disabled for local dev)
cd cmd/backend
DEV_MODE=true KUEUE_SYNC_ENABLED=false DB_PATH=./bookings.db go run .
# Start the plugin frontend dev server (in another terminal)
yarn start
# you need a matching openshift-console build
cd ~/git/openshift-console
git checkout release-4.21
go build -o ./bin/bridge ./cmd/bridge/
cd ~/git/openshift-console/frontend
yarn install && yarn build
# create a local oauth client
oc create -f - <<'EOF'
apiVersion: oauth.openshift.io/v1
kind: OAuthClient
metadata:
name: console-oauth-client
grantMethod: auto
redirectURIs:
- http://localhost:9000/auth/callback
secret: console-secret-123
EOF
# unauth access
cd ~/git/openshift-console
source ./contrib/oc-environment.sh
./bin/bridge -plugins gpu-booking-plugin=http://localhost:9001/ -i18n-namespaces=plugin__gpu-booking-plugin
# for auth you need to run the bridge cmd directly with proxy
./bin/bridge \
--base-address=http://localhost:9000 \
--k8s-mode=off-cluster \
--k8s-mode-off-cluster-skip-verify-tls=true \
--listen=http://0.0.0.0:9000 \
--public-dir=./frontend/public/dist \
-plugins gpu-booking-plugin=http://localhost:9001/ \
-i18n-namespaces=plugin__gpu-booking-plugin \
--plugin-proxy='{"services":[{"consolePluginName":"gpu-booking-plugin","endpoint":"http://localhost:9443","authorize":true,"consoleAPIPath":"/api/proxy/plugin/gpu-booking-plugin/backend/"}]}' \
--user-auth=openshift \
--user-auth-oidc-client-id=console-oauth-client \
--user-auth-oidc-client-secret=console-secret-123
# login
http://localhost:9000The backend runs on :9443 and the webpack dev server on :9001 (proxying API calls to the backend).
| Variable | Default | Description |
|---|---|---|
PORT |
9443 |
Server port |
DB_PATH |
/app/data/bookings.db |
SQLite database path |
PLUGIN_DIST_DIR |
/app/dist |
Path to frontend static assets |
BOOKING_WINDOW_DAYS |
30 |
How far ahead users can book |
KUEUE_SYNC_ENABLED |
true |
Enable LocalQueue watcher |
KUEUE_SYNC_INTERVAL |
30 |
Kueue poll interval in seconds |
KUEUE_BOOKING_DAYS |
7 |
Days to book ahead for consumed slots |
GPU_DISCOVERY_ENABLED |
true |
Auto-discover GPUs from cluster nodes |
GPU_DISCOVERY_INTERVAL |
300 |
Discovery interval in seconds |
# Build and push the container image
make podman-push
# Or build without pushing
make podman-buildThe default image is quay.io/eformat/gpu-booking-plugin:latest. Override with:
make podman-push REGISTRY=my-registry.example.com REPOSITORY=my-registry.example.com/my-org/gpu-booking-pluginhelm install gpu-booking-plugin chart/ \
-n gpu-booking-app-plugin --create-namespaceThis creates:
- Deployment - single-replica pod with TLS via service-serving certificates
- ConsolePlugin CR - registers the plugin with OpenShift console
- Service - ClusterIP on port 9443
- PVC - 2Gi for SQLite database persistence
- ServiceAccount + ClusterRole - RBAC for Kueue, auth, and HardwareProfile APIs
- Console patch - enables the plugin in the OpenShift console
| Value | Default | Description |
|---|---|---|
image.repository |
quay.io/eformat/gpu-booking-plugin |
Container image |
image.tag |
latest |
Image tag |
replicas |
1 |
Pod replicas |
persistence.size |
2Gi |
PVC size for SQLite |
tls.enabled |
true |
Enable TLS via service-serving certs |
kueueSync.enabled |
true |
Enable Kueue LocalQueue sync |
kueueSync.interval |
30 |
Kueue sync interval in seconds |
kueueSync.bookingDays |
7 |
Days ahead for consumed bookings |
bookingWindowDays |
30 |
Booking window in days |
When Kueue sync is enabled, the plugin:
- Polls all LocalQueues for GPU usage and creates "consumed" bookings
- When users reserve slots, consumed bookings are evicted and per-user ClusterQueues are created with protected quotas
- Kueue's
reclaimWithinCohortpreemption ensures reserved workloads take priority over unreserved ones - HardwareProfiles are created in user namespaces for OpenDataHub/RHOAI workbench scheduling
- When reservations expire, ClusterQueues are gracefully drained (
stopPolicy: HoldAndDrain) before deletion, giving active workloads time to complete
See ARCHITECTURE.md for the full quota flow, preemption model, and sync lifecycle.
| Method | Endpoint | Auth | Description |
|---|---|---|---|
GET |
/api/auth/me |
user | Current user info (username, groups, is_admin) |
GET |
/api/config |
user | GPU resource specs, booking window, cluster capacity |
GET |
/api/bookings |
user | List all bookings + active reservations |
POST |
/api/bookings |
user | Create a booking |
POST |
/api/bookings/bulk |
user | Bulk create bookings (multi-day) |
DELETE |
/api/bookings?id=<id> |
user | Cancel own booking |
GET |
/api/admin |
admin | All bookings (admin only) |
DELETE |
/api/admin?id=<id> |
admin | Delete any booking |
DELETE |
/api/admin?before=<YYYY-MM-DD> |
admin | Delete all bookings before date |
POST |
/api/admin/reservations |
admin | Toggle reservation sync |
POST |
/api/admin/discover |
admin | Trigger GPU auto-discovery |
GET |
/api/admin/database/export |
admin | Download database as JSON |
POST |
/api/admin/database/import |
admin | Restore database from JSON |
GET |
/api/health |
none | Health check |
gpu-booking-app-plugin/
├── cmd/plugin/ # Go entry point
├── pkg/
│ ├── api/ # HTTP handlers (auth, bookings, admin, config)
│ ├── database/ # SQLite schema and queries
│ └── kube/ # Kueue sync + reservation management
├── src/
│ ├── components/ # React components (BookingPage, AdminPage, HelpPage, etc.)
│ ├── utils/ # AuthContext, API helpers
│ └── docs/ # Help markdown files, images, topic registry
├── chart/ # Helm chart (deployment, ConsolePlugin, RBAC, PVC)
├── console-extensions.json # Plugin routes and navigation
├── webpack.config.ts # Frontend build config
├── Containerfile # Multi-stage build (Node.js + Go + UBI minimal)
└── ARCHITECTURE.md # Detailed architecture documentation
Apache License 2.0