diff --git a/developing/.gitignore b/developing/.gitignore new file mode 100644 index 000000000..268f12853 --- /dev/null +++ b/developing/.gitignore @@ -0,0 +1,7 @@ +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib +bin/* \ No newline at end of file diff --git a/developing/DEVELOPMENT.md b/developing/DEVELOPMENT.md new file mode 100644 index 000000000..e7443809a --- /dev/null +++ b/developing/DEVELOPMENT.md @@ -0,0 +1,335 @@ +# Development Guide with Tilt + +This directory contains the Tilt configuration for local development of the Kubeflow Notebooks workspace components (controller, backend, and frontend). + +## Table of Contents + +- [Prerequisites](#prerequisites) +- [Quick Start](#quick-start) +- [Configuration](#configuration) +- [Development Workflow](#development-workflow) +- [Frontend Development](#frontend-development) +- [Troubleshooting](#troubleshooting) +- [Best Practices](#best-practices) + +## Prerequisites + +Before using Tilt, ensure you have the following installed: + +### Required + +- [Tilt](https://docs.tilt.dev/install.html) - v0.33.0 or later +- [Docker](https://docs.docker.com/get-docker/) - for building and running containers +- [Kubernetes cluster](https://kubernetes.io/docs/setup/) - a local cluster (e.g., [Kind](https://kind.sigs.k8s.io/)) +- [kubectl](https://kubernetes.io/docs/tasks/tools/) - configured to connect to your cluster + +### Optional (for local testing and debugging) + +All components build inside Docker containers, so Go and Node.js are **not required** to run Tilt. However, they are useful for: +- Running tests locally (`make test`, `npm run test`) +- Running linters locally (`make lint`, `npm run test:lint`) +- IDE support (type checking, autocompletion) + +If you need these capabilities: +- [Go](https://golang.org/doc/install) - v1.21.0 or later (for controller and backend) +- [Node.js](https://nodejs.org/) - v20.0.0 or later (for frontend) + +### Verify Prerequisites + +```bash +# Required +tilt version +docker --version +kubectl version --client + +# Optional (only if installed) +go version +node --version +``` + +### Install Kind + +**Note**: The Makefile will automatically create a Kind cluster named `tilt` if it doesn't exist. However, you still need to have `kind` installed. + +```bash +# macOS +brew install kind + +# Or follow instructions at: https://kind.sigs.k8s.io/docs/user/quick-start/#installation +``` + + +### Using Kind Provider (Optional) + +You can choose to set the `KIND_EXPERIMENTAL_PROVIDER` environment variable in your shell session: + +```bash +export KIND_EXPERIMENTAL_PROVIDER=podman +``` + +The Makefile will honor this environment variable when creating the Kind cluster. + +## Quick Start + +1. **Navigate to the developing directory**: + ```bash + cd developing + ``` + +2. **Start Tilt using the Makefile**: + ```bash + make tilt-up + ``` + + **Important**: Always use `make tilt-up` instead of running `tilt up` directly. The Makefile ensures: + - The Kind cluster exists and is properly configured + - The Kubernetes context is switched to `kind-tilt` + - Cert-manager is installed (required for webhooks) + - All prerequisites are met before Tilt starts + + This will: + - Set up the Kind cluster (if it doesn't exist) + - Install cert-manager + - Open the Tilt UI in your browser (usually http://localhost:10350) + - Build and deploy the controller, backend, and frontend (if enabled) to your Kubernetes cluster + - Set up port forwards for easy access + - Enable live updates when you make code changes + +3. **Monitor the Build**: + + Watch the Tilt UI in your browser. You should see: + + 1. **Kubernetes Resources** (building and deploying): + - `workspaces-controller` - Controller deployment with CRDs + - `workspaces-backend` - Backend API server + - `workspaces-frontend` - Frontend with webpack dev server (if enabled) + + **Note**: The Kind cluster and cert-manager setup are handled by the Makefile before Tilt starts, so you won't see those as Tilt resources. + + Wait until all resources show green/healthy status. The frontend may take a couple of minutes on first start as webpack compiles the bundle. + +4. **Access the components**: + - Controller health: `http://localhost:8081/healthz` + - Backend API: [Swagger UI](http://localhost:4000/api/v1/swagger/) + - Frontend UI: `http://localhost:9000` (if enabled) + +5. **Stop Tilt**: + ```bash + # In the terminal where Tilt is running, press Ctrl+C + # Or in another terminal: + make tilt-down + # Or: + tilt down + ``` + + This will: + - Stop all Tilt-managed resources + - Clean up deployments (but not the namespace) + +### Optional: Clean up namespace + +```bash +kubectl delete namespace kubeflow-workspaces +``` + +### Optional: Delete Kind cluster + +```bash +kind delete cluster --name tilt +``` + +## Configuration + +### Makefile Targets + +The Makefile provides several targets for managing your development environment: + +- `make tilt-up` - Set up Kind cluster, install cert-manager, and start Tilt +- `make tilt-down` - Stop Tilt +- `make setup-kind` - Set up the Kind cluster only (without starting Tilt) +- `make setup-cert-manager` - Install cert-manager only (requires Kind cluster) + +### Skipping Frontend + +To run Tilt without the frontend (useful for backend/controller-only development): + +```bash +ENABLE_FRONTEND=false make tilt-up +``` + +### Custom Ports + +Port forwards are configured in the Tiltfile. To change them, edit the `port_forwards` parameter in the `k8s_resource()` calls. + +## Development Workflow + +1. **Make code changes** in any of the workspace components + - Keep changes focused and small +2. **Tilt automatically detects changes**: + - Controller/Backend: Rebuilds Docker images and redeploys + - Frontend: Uses live_update to sync files into the container, then webpack HMR updates the browser +3. **View logs** in the Tilt UI or via `tilt logs ` +4. **Add tests** for any new features +5. **Run linting checks** to ensure code style consistency +6. **Ensure tests pass** before opening a PR +7. **Write meaningful commit messages** highlighting what your code contribution is doing +8. **Be responsive** to feedback on the PR + +## Frontend Development + +The frontend runs in a Kubernetes pod using webpack dev server with Tilt's `live_update` feature. This provides: + +1. **Fast Hot Reloading**: Changes to source files are synced directly into the container without rebuilding the Docker image +2. **Hot Module Replacement**: Webpack dev server's HMR provides instant feedback on code changes +3. **Kubernetes-Native**: The frontend runs in the same environment as production (nginx serves the frontend in prod) +4. **Automatic Dependency Updates**: When `package.json` or `package-lock.json` changes, Tilt automatically runs `npm install` in the container + +### How Live Update Works + +When you modify files in `src/` or `config/`: +1. Tilt detects the file change +2. The changed files are synced directly into the running container +3. Webpack dev server detects the changes and triggers HMR +4. Your browser updates without a full page reload + +For dependency changes (`package.json` or `package-lock.json`): +1. Tilt syncs the updated files +2. Tilt runs `npm install` inside the container +3. Webpack dev server restarts with the new dependencies + +### Initial Startup + +The frontend may take 2-3 minutes on first start as webpack compiles the full bundle. A startup probe is configured to allow up to 5 minutes for initial compilation. Once the initial build completes, subsequent HMR updates are nearly instant. + +## Troubleshooting + +### Build Failures + +If builds fail, check: + +```bash +# Controller build issues +cd workspaces/controller && make build + +# Backend build issues +cd workspaces/backend && make build + +# Frontend dev container issues (test the Tilt Dockerfile) +docker build -f developing/dockerfiles/Dockerfile.frontend.tilt workspaces/frontend + +# Frontend production build issues (for testing production builds) +cd workspaces/frontend && npm ci && npm run build:prod +``` + +Also verify: +- All prerequisites are installed +- Makefiles can find their dependencies +- Go modules are downloaded (`go mod download` in controller/backend) +- Node modules are installed (`npm ci` in frontend) + +#### BuildKit + +If you see the following error while `Tilt` is trying to build an image: +``` +Build Failed: failed to dial gRPC: unable to upgrade to h2c, received 404 +``` + +Try disabling Docker BuildKit support in the terminal where you are running `tilt up`: +```bash +export DOCKER_BUILDKIT=0 +``` + + +### Kubernetes Connection Issues + +The Makefile automatically handles context switching to `kind-tilt`. If you encounter issues: + +1. **Verify the Kind cluster exists**: + ```bash + kind get clusters + ``` + +2. **Check the current context**: + ```bash + kubectl config current-context + # Should be: kind-tilt + ``` + +3. **If context is wrong, manually switch**: + ```bash + kubectl config use-context kind-tilt + ``` + +4. **Verify cluster is accessible**: + ```bash + kubectl cluster-info + ``` + +5. **Ensure you have permissions** to create resources in the `kubeflow-workspaces` namespace + +**Note**: If you're running `tilt up` directly (not via `make tilt-up`), you may be on the wrong Kubernetes context. Always use `make tilt-up` to ensure the correct context is set. + +### Port Already in Use + +If ports are already in use, you can: + +1. Stop the conflicting service +2. Or modify port forwards in the Tiltfile + +### CRD Installation Fails + +If CRDs fail to install: + +```bash +# Check if you have permissions +kubectl auth can-i create crds + +# Try installing manually +cd workspaces/controller && make install +``` + +Also check that you have cluster-admin permissions or appropriate RBAC. + +### Frontend Container Issues + +If the frontend is not loading or showing errors: + +1. **Check the pod logs**: + ```bash + kubectl logs -n kubeflow-workspaces -l app=workspaces-frontend -f + ``` + +2. **Check if webpack is still compiling** (initial build can take 2-3 minutes): + ```bash + kubectl get pods -n kubeflow-workspaces -l app=workspaces-frontend + # Look for the Ready status - 0/1 means still starting up + ``` + +3. **Check for JavaScript/TypeScript errors** in the Tilt UI logs for the `workspaces-frontend` resource + +4. **If live_update isn't working**, try triggering a full rebuild by clicking the refresh button in the Tilt UI + +5. **Memory issues** - if webpack crashes with OOM errors, the container may need more memory (the Tiltfile configures 2Gi limit for development) + +## Best Practices + +1. **Run tests before committing**: + ```bash + # Controller + cd workspaces/controller && make lint && make test + + # Backend + cd workspaces/backend && make lint && make test + + # Frontend + cd workspaces/frontend && npm run test + ``` + +2. **Keep dependencies up to date**: + - Go modules: `go mod tidy` in controller/backend + - Node modules: `npm ci` in frontend + +3. **Clean up resources**: + - Always run `make tilt-down` (or `tilt down`) when done + - Optionally: `kubectl delete namespace kubeflow-workspaces` + - Optionally: `kind delete cluster --name tilt` to remove the Kind cluster diff --git a/developing/Makefile b/developing/Makefile new file mode 100644 index 000000000..920f35455 --- /dev/null +++ b/developing/Makefile @@ -0,0 +1,77 @@ +.PHONY: check-tilt tilt-up tilt-down setup-kind setup-cert-manager kustomize + +# Variables +CLUSTER_NAME := tilt +KIND_CONTEXT := kind-$(CLUSTER_NAME) + +# Location to install dependencies to +LOCALBIN ?= $(shell pwd)/bin +$(LOCALBIN): + mkdir -p $(LOCALBIN) + +# Tool Binaries +KUSTOMIZE ?= $(LOCALBIN)/kustomize + +# Tool Versions +KUSTOMIZE_VERSION ?= v5.5.0 + +# Export KIND_EXPERIMENTAL_PROVIDER to honor it if set in user's environment +# (e.g., KIND_EXPERIMENTAL_PROVIDER=podman for podman support) +export KIND_EXPERIMENTAL_PROVIDER + +# Check if tilt is installed +.PHONY: check-tilt +check-tilt: + @if ! command -v tilt >/dev/null 2>&1; then \ + echo "ERROR: tilt is not installed. Please install tilt first:"; \ + echo " curl -fsSL https://raw.githubusercontent.com/tilt-dev/tilt/master/scripts/install.sh | bash"; \ + echo " or visit: https://docs.tilt.dev/install.html"; \ + exit 1; \ + fi + +# Ensure kind cluster exists and context is set before running tilt +setup-kind: + @echo "Setting up Kind cluster..." + @if [ -n "$$KIND_EXPERIMENTAL_PROVIDER" ]; then \ + echo "Using KIND_EXPERIMENTAL_PROVIDER=$$KIND_EXPERIMENTAL_PROVIDER"; \ + fi + @./scripts/setup-kind.sh + +# Install cert-manager (depends on kind cluster being set up) +setup-cert-manager: setup-kind + @echo "Setting up cert-manager..." + @./scripts/setup-cert-manager.sh + + +# Run tilt up with kind cluster and cert-manager setup +tilt-up: check-tilt setup-cert-manager kustomize + @echo "Starting Tilt..." + @tilt up + + +# Stop Tilt +tilt-down: check-tilt kustomize + @echo "Stopping Tilt..." + @tilt down + +# Install kustomize +kustomize: $(KUSTOMIZE) +$(KUSTOMIZE): $(LOCALBIN) + $(call go-install-tool,$(KUSTOMIZE),sigs.k8s.io/kustomize/kustomize/v5,$(KUSTOMIZE_VERSION)) + +# go-install-tool will 'go install' any package with custom target and name of binary, if it doesn't exist +# $1 - target path with name of binary +# $2 - package url which can be installed +# $3 - specific version of package +define go-install-tool +@[ -f "$(1)-$(3)" ] || { \ +set -e; \ +package=$(2)@$(3) ;\ +echo "Downloading $${package}" ;\ +rm -f $(1) || true ;\ +GOBIN=$(LOCALBIN) go install $${package} ;\ +mv $(1) $(1)-$(3) ;\ +} ;\ +ln -sf $(1)-$(3) $(1) +endef + diff --git a/developing/OWNERS b/developing/OWNERS new file mode 100644 index 000000000..d6cf9cc9b --- /dev/null +++ b/developing/OWNERS @@ -0,0 +1,5 @@ +labels: + - area/ci + - area/v2 +approvers: + - andyatmiami \ No newline at end of file diff --git a/developing/Tiltfile b/developing/Tiltfile new file mode 100644 index 000000000..03f66c0b4 --- /dev/null +++ b/developing/Tiltfile @@ -0,0 +1,242 @@ +# Tiltfile for Kubeflow Notebooks development +# - Streamlines local development of controller, backend, and frontend components + +# Disable analytics +analytics_settings(False) + +# Enforce minimum Tilt version +version_settings(check_updates=True, constraint=">=0.33.0") + +# Increase timeout for k8s operations +update_settings(k8s_upsert_timeout_secs=120) + +# Allow kind-tilt context (set up by Makefile before tilt runs) +allow_k8s_contexts('kind-tilt') + +# Allow skipping frontend via environment variable +enable_frontend = os.getenv("ENABLE_FRONTEND", "true").lower() == "true" + +# Get paths relative to Tiltfile location +# Tilt evaluates paths relative to the Tiltfile directory +tilt_root = os.path.dirname(os.path.abspath(__file__)) +# Go up 1 level from Tiltfile location: developing -> repo root +workspace_root = os.path.dirname(tilt_root) + +# Define paths relative to workspace root +controller_dir = os.path.join(workspace_root, "workspaces/controller") +backend_dir = os.path.join(workspace_root, "workspaces/backend") +frontend_dir = os.path.join(workspace_root, "workspaces/frontend") + +# Kustomize binary path (installed by Makefile) +kustomize_bin = os.path.join(tilt_root, "bin/kustomize") + + +# Exclude generated files/directories from file watching to prevent rebuild loops +# This prevents rebuild loops when auto-generated files are updated +# Patterns are scoped to specific directories so they don't affect other components +watch_settings( + ignore=[ + # Controller generated files + os.path.join(controller_dir, "bin/**"), + os.path.join(controller_dir, "**/zz_generated.*"), + os.path.join(controller_dir, "config/crd/**"), + os.path.join(controller_dir, "config/webhook/manifests.yaml"), + # Backend generated files + os.path.join(backend_dir, "bin/**"), + os.path.join(backend_dir, "openapi/**"), + # Frontend generated files + os.path.join(frontend_dir, "bin/**"), + os.path.join(frontend_dir, "src/generated/**"), + ], +) + + + +# ============================================================================ +# Controller +# ============================================================================ +# Note: Kind cluster and cert-manager are set up by the Makefile before Tilt starts + + +# Docker build for controller using production Dockerfile +# The production Dockerfile builds the binary inside Docker, avoiding .dockerignore issues +# Note: kustomize replaces 'workspaces-controller' with 'ghcr.io/kubeflow/notebooks/workspaces-controller' +# so we build with that name to match the final YAML +docker_build( + "ghcr.io/kubeflow/notebooks/workspaces-controller", + dockerfile=os.path.join(controller_dir, "Dockerfile"), + context=controller_dir, +) + +# K8s deployment for controller - use kustomize to build and preprocess YAMLs +controller_kustomize_path = os.path.join(controller_dir, "config/default") + +# Build manifests with kustomize (using kustomize binary from Makefile) +manifests = kustomize(controller_kustomize_path, kustomize_bin=kustomize_bin) + +# Decode YAMLs to modify them for development +objects = decode_yaml_stream(manifests) + +# Modify the controller deployment for development +for o in objects: + # Defensive check: skip if missing kind/name + kind = o.get("kind") + name = o.get("metadata", {}).get("name") + if not kind or not name: + continue + + # Modify the controller Deployment for dev + if kind == "Deployment" and name == "workspaces-controller": + containers = o.get("spec", {}).get("template", {}).get("spec", {}).get("containers", []) + for container in containers: + if container.get("name") == "manager": + env = container.setdefault("env", []) + use_istio_found = False + for i, env_var in enumerate(env): + if env_var.get("name") == "USE_ISTIO": + env[i] = {"name": "USE_ISTIO", "value": "false"} + use_istio_found = True + break + if not use_istio_found: + env.append({"name": "USE_ISTIO", "value": "false"}) + +# Encode back to YAML and apply +# This applies all controller manifests: CRDs, RBAC, ConfigMaps, Deployment, etc. +overridden_manifests = encode_yaml_stream(objects) +k8s_yaml(overridden_manifests) + +# Configure k8s resource for the controller deployment +k8s_resource( + "workspaces-controller", + port_forwards=["8080:8080", "8081:8081"], # metrics and health probe + labels=["controller"], +) + +# ============================================================================ +# Backend +# ============================================================================ + +# Docker build for backend using production Dockerfile +docker_build( + "workspaces-backend", + dockerfile=os.path.join(backend_dir, "Dockerfile"), + context=os.path.dirname(backend_dir), # Production Dockerfile expects workspaces/ as context +) + +# K8s deployment for backend - use kustomize to build +# allow_duplicates=True because namespace is already defined by controller +backend_kustomize_path = os.path.join(backend_dir, "manifests/kustomize/base") +k8s_yaml( + kustomize(backend_kustomize_path, kustomize_bin=kustomize_bin), + allow_duplicates=True, +) + +# Configure k8s resource +# Backend waits for controller to be ready first +# Tilt automatically matches the image based on the image name in the YAML +k8s_resource( + "workspaces-backend", + port_forwards="4000", + resource_deps=["workspaces-controller"], + labels=["backend"], +) + +# ============================================================================ +# Frontend (optional) +# ============================================================================ + +if enable_frontend: + # Docker build for frontend using development Dockerfile with live_update + # This enables fast in-place updates without rebuilding the image + # Webpack dev server with HMR provides instant feedback on code changes + docker_build( + "workspaces-frontend", + dockerfile=os.path.join(tilt_root, "dockerfiles/Dockerfile.frontend.tilt"), + context=frontend_dir, # Use workspaces/frontend/ as context + live_update=[ + # Sync source files into the container + # Changes to these files trigger webpack HMR without container restart + sync(os.path.join(frontend_dir, "src"), "/app/src"), + sync(os.path.join(frontend_dir, "config"), "/app/config"), + + # If package.json or package-lock.json changes, reinstall dependencies + # This ensures new packages are available without a full rebuild + run( + "cd /app && npm install", + trigger=[ + os.path.join(frontend_dir, "package.json"), + os.path.join(frontend_dir, "package-lock.json"), + ], + ), + ], + # Ignore files that shouldn't trigger rebuilds + ignore=[ + os.path.join(frontend_dir, "node_modules"), + os.path.join(frontend_dir, "dist"), + os.path.join(frontend_dir, "coverage"), + os.path.join(frontend_dir, "*.md"), + ], + ) + + # K8s deployment for frontend - use kustomize to build + # allow_duplicates=True because namespace is already defined by controller + frontend_kustomize_path = os.path.join(frontend_dir, "manifests/kustomize/base") + + # Build and decode manifests to modify for development + frontend_manifests = kustomize(frontend_kustomize_path, kustomize_bin=kustomize_bin) + frontend_objects = decode_yaml_stream(frontend_manifests) + + # Modify the frontend deployment for development with webpack dev server + for o in frontend_objects: + kind = o.get("kind") + name = o.get("metadata", {}).get("name") + if not kind or not name: + continue + + # Modify frontend deployment for webpack dev server + if kind == "Deployment" and name == "workspaces-frontend": + containers = o.get("spec", {}).get("template", {}).get("spec", {}).get("containers", []) + for container in containers: + if container.get("name") == "workspaces-frontend": + # Increase memory limits for webpack dev server + # Production uses 512Mi but webpack compilation needs much more + container["resources"] = { + "limits": { + "cpu": "2", + "memory": "2Gi", + }, + "requests": { + "cpu": "500m", + "memory": "1Gi", + }, + } + + # Add startup probe for webpack dev server + # Webpack needs time to compile the bundle before serving requests + # Startup probe allows up to 5 minutes (30 * 10s) for initial compilation + # Once startup probe passes, liveness/readiness probes take over + container["startupProbe"] = { + "httpGet": { + "path": "/", + "port": 8080, + "scheme": "HTTP", + }, + "initialDelaySeconds": 10, + "periodSeconds": 10, + "timeoutSeconds": 5, + "failureThreshold": 30, + } + + # Apply modified manifests + k8s_yaml(encode_yaml_stream(frontend_objects), allow_duplicates=True) + + # Configure k8s resource for frontend + # Frontend waits for backend to be ready to avoid 504 errors on initial page load + # Port forward: localhost:9000 -> container:8080 (avoids conflict with controller on 8080) + k8s_resource( + "workspaces-frontend", + port_forwards="9000:8080", + resource_deps=["workspaces-backend"], + labels=["frontend"], + ) + diff --git a/developing/dockerfiles/Dockerfile.frontend.tilt b/developing/dockerfiles/Dockerfile.frontend.tilt new file mode 100644 index 000000000..a630ae99f --- /dev/null +++ b/developing/dockerfiles/Dockerfile.frontend.tilt @@ -0,0 +1,36 @@ +# ---------- Development Dockerfile for Frontend ---------- +# This Dockerfile is optimized for Tilt live_update development. +# It runs webpack-dev-server with hot module replacement (HMR). +# +# Build context: workspaces/frontend/ +# +# Environment is configured via DEV_ENV=tilt which sets up appropriate +# defaults for development. Container-specific overrides are set below. + +FROM node:20-slim + +# Set working directory +WORKDIR /app + +# Copy package files first for better layer caching +# This allows npm install to be cached when only source files change +COPY package*.json ./ + +# Install dependencies +# Using npm ci for reproducible builds, but falling back to npm install +# if package-lock.json is out of sync during development +RUN npm ci || npm install + +# Copy source code and configuration +COPY . ./ + +# Expose the webpack dev server port (matches production deployment) +EXPOSE 8080 + +# Container networking: listen on all interfaces +ENV HOST=0.0.0.0 + +# Start webpack dev server with hot reload +# start:tilt sets DEV_ENV=tilt which configures webpack for development mode +CMD ["npm", "run", "start:tilt"] + diff --git a/developing/scripts/kind.yaml b/developing/scripts/kind.yaml new file mode 100644 index 000000000..da9d0c571 --- /dev/null +++ b/developing/scripts/kind.yaml @@ -0,0 +1,18 @@ +apiVersion: kind.x-k8s.io/v1alpha4 +kind: Cluster +# This is needed in order to support projected volumes with service account tokens. +kubeadmConfigPatches: + - | + apiVersion: kubeadm.k8s.io/v1beta3 + kind: ClusterConfiguration + metadata: + name: config + apiServer: + extraArgs: + "service-account-issuer": "kubernetes.default.svc" + "service-account-signing-key-file": "/etc/kubernetes/pki/sa.key" +nodes: +- role: control-plane + image: kindest/node:v1.33.1@sha256:050072256b9a903bd914c0b2866828150cb229cea0efe5892e2b644d5dd3b34f +- role: worker + image: kindest/node:v1.33.1@sha256:050072256b9a903bd914c0b2866828150cb229cea0efe5892e2b644d5dd3b34f \ No newline at end of file diff --git a/developing/scripts/setup-cert-manager.sh b/developing/scripts/setup-cert-manager.sh new file mode 100755 index 000000000..31e285700 --- /dev/null +++ b/developing/scripts/setup-cert-manager.sh @@ -0,0 +1,36 @@ +#!/usr/bin/env bash +# Setup script for cert-manager +# This script checks if cert-manager is installed and installs it if needed +# Uses the same version as the e2e tests: v1.12.13 (LTS version) + +set -euo pipefail + +# Use LTS version of cert-manager (matches e2e tests) +CERT_MANAGER_VERSION="v1.12.13" +CERT_MANAGER_URL="https://github.com/jetstack/cert-manager/releases/download/${CERT_MANAGER_VERSION}/cert-manager.yaml" + +# Check if cert-manager is already installed +if kubectl get crd certificates.cert-manager.io >/dev/null 2>&1; then + echo "Cert-manager is already installed" + exit 0 +fi + +echo "Installing cert-manager ${CERT_MANAGER_VERSION}..." +kubectl apply -f "${CERT_MANAGER_URL}" + +echo "Waiting for cert-manager to be ready..." +# Wait for cert-manager webhook to be ready (this is the critical component) +kubectl wait --for=condition=ready pod \ + -l app.kubernetes.io/instance=cert-manager \ + -n cert-manager \ + --timeout=120s || { + echo "Warning: cert-manager pods may not be fully ready, but continuing..." +} + +# Also wait for the CRDs to be established +kubectl wait --for=condition=established crd/certificates.cert-manager.io --timeout=60s || true +kubectl wait --for=condition=established crd/issuers.cert-manager.io --timeout=60s || true +kubectl wait --for=condition=established crd/clusterissuers.cert-manager.io --timeout=60s || true + +echo "Cert-manager installation complete" + diff --git a/developing/scripts/setup-kind.sh b/developing/scripts/setup-kind.sh new file mode 100755 index 000000000..476d4ef69 --- /dev/null +++ b/developing/scripts/setup-kind.sh @@ -0,0 +1,32 @@ +#!/usr/bin/env bash +# Setup script for Kind cluster +# This script checks if a Kind cluster exists and creates it if needed + +set -euo pipefail + +CLUSTER_NAME="tilt" +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +KIND_CONFIG="${SCRIPT_DIR}/kind.yaml" + +# Check if kind command exists +if ! command -v kind >/dev/null 2>&1; then + echo "ERROR: kind is not installed. Please install kind first:" + echo " brew install kind # macOS" + echo " or visit: https://kind.sigs.k8s.io/docs/user/quick-start/#installation" + exit 1 +fi + +# Check if cluster exists +if ! kind get clusters 2>/dev/null | grep -q "^${CLUSTER_NAME}$"; then + echo "Creating Kind cluster '${CLUSTER_NAME}' with config from ${KIND_CONFIG}..." + kind create cluster --name "${CLUSTER_NAME}" --config "${KIND_CONFIG}" --wait 60s + echo "Kind cluster created successfully" +else + echo "Kind cluster '${CLUSTER_NAME}' already exists" +fi + +# Ensure kubectl context is set to the Kind cluster +kubectl config use-context "kind-${CLUSTER_NAME}" || true + +echo "Kind cluster setup complete" + diff --git a/workspaces/backend/.gitignore b/workspaces/backend/.gitignore index ce6feea73..2e7f76304 100644 --- a/workspaces/backend/.gitignore +++ b/workspaces/backend/.gitignore @@ -5,13 +5,4 @@ *.so *.dylib bin/* -Dockerfile.cross - -# Test binary, built with `go test -c` -*.test - -# Output of the go coverage tool, specifically when used with LiteIDE -*.out - -# Go workspace file -go.work \ No newline at end of file +Dockerfile.cross \ No newline at end of file diff --git a/workspaces/frontend/.env.tilt b/workspaces/frontend/.env.tilt new file mode 100644 index 000000000..4959b689e --- /dev/null +++ b/workspaces/frontend/.env.tilt @@ -0,0 +1,16 @@ +APP_ENV=development + +DEPLOYMENT_MODE=standalone +MOCK_API_ENABLED=false +MANDATORY_NAMESPACE=default +URL_PREFIX= +PUBLIC_PATH=/ + +# Server configuration - use port 8080 to match deployment manifest +PORT=8080 + +# Proxy configuration for Tilt development +# Frontend runs in Kubernetes and reaches backend via service name +PROXY_HOST=workspaces-backend.kubeflow-workspaces.svc.cluster.local +PROXY_PORT=4000 +PROXY_PROTOCOL=http diff --git a/workspaces/frontend/config/webpack.dev.js b/workspaces/frontend/config/webpack.dev.js index 777d55e1d..1a2ed6b4b 100644 --- a/workspaces/frontend/config/webpack.dev.js +++ b/workspaces/frontend/config/webpack.dev.js @@ -8,7 +8,8 @@ const SpeedMeasurePlugin = require('speed-measure-webpack-plugin'); const smp = new SpeedMeasurePlugin({ disable: !process.env.MEASURE }); -setupDotenvFilesForEnv({ env: 'development' }); +const env = process.env.DEV_ENV ?? 'development'; +setupDotenvFilesForEnv({ env }); const webpackCommon = require('./webpack.common.js'); const RELATIVE_DIRNAME = process.env._RELATIVE_DIRNAME; @@ -64,7 +65,7 @@ module.exports = smp.wrap( plugins: [ ...setupWebpackDotenvFilesForEnv({ directory: RELATIVE_DIRNAME, - env: 'development', + env, isRoot: IS_PROJECT_ROOT_DIR, }), ], @@ -82,7 +83,7 @@ module.exports = smp.wrap( port: PORT, compress: true, historyApiFallback: { - index: `${BASE_PATH}/index.html`, + index: `${BASE_PATH}/index.html`.replace('//', '/'), }, hot: true, open: [BASE_PATH], diff --git a/workspaces/frontend/package.json b/workspaces/frontend/package.json index 126afe29a..c0a0afd17 100644 --- a/workspaces/frontend/package.json +++ b/workspaces/frontend/package.json @@ -21,6 +21,7 @@ "build:prod": "webpack --config ./config/webpack.prod.js", "generate:api": "./scripts/generate-api.sh && npm run prettier", "start:dev": "webpack serve --hot --color --config ./config/webpack.dev.js", + "start:tilt": "DEV_ENV=tilt npm run start:dev", "test": "run-s prettier:check test:lint test:type-check test:unit test:cypress-ci", "test:cypress-ci": "npx concurrently -P -k -s first \"CY_MOCK=1 npm run cypress:server:build && npm run cypress:server\" \"npx wait-on tcp:127.0.0.1:9001 && npm run cypress:run:mock -- {@}\" -- ", "test:jest": "jest --passWithNoTests",