diff --git a/.vscode/launch.json b/.vscode/launch.json index cf83d8b22..5ee35321c 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -83,5 +83,37 @@ "APIP_GW_ANALYTICS_ACCESS__LOGS__SERVICE_MODE": "tcp", }, }, + { + "name": "Gateway Controller (Remote)", + "type": "go", + "request": "attach", + "mode": "remote", + "port": 2345, + "host": "127.0.0.1", + "apiVersion": 2, + "trace": "log", + "substitutePath": [ + { + "from": "${workspaceFolder}/gateway/gateway-controller", + "to": "/build" + } + ] + }, + { + "name": "Policy Engine (Remote)", + "type": "go", + "request": "attach", + "mode": "remote", + "port": 2346, + "host": "127.0.0.1", + "apiVersion": 2, + "trace": "log", + "substitutePath": [ + { + "from": "${workspaceFolder}/gateway/gateway-runtime/policy-engine", + "to": "/api-platform/gateway/gateway-runtime/policy-engine" + } + ] + }, ] } diff --git a/gateway/DEBUG_GUIDE.md b/gateway/DEBUG_GUIDE.md index 3638fae65..8a1fd5848 100644 --- a/gateway/DEBUG_GUIDE.md +++ b/gateway/DEBUG_GUIDE.md @@ -1,8 +1,80 @@ -# Gateway Local Debug Guide +# Gateway Debug Guide -This guide explains how to debug the gateway with **Gateway Controller** and **Policy Engine** running locally in VS Code, and the **Gateway Runtime (Router)** running in Docker Compose. +Two debug options are available. **Option 1 (Remote Debug)** is the recommended approach — everything runs in Docker and VS Code attaches via dlv. **Option 2 (Local Process)** runs the controller and policy engine as local VS Code processes with only the router in Docker. -## Architecture Overview +--- + +## Option 1 (Recommended): Remote Debug — All Components in Docker + +Gateway Controller and Policy Engine run inside Docker containers with dlv in server mode. VS Code attaches remotely. + +### Step 1: Build Debug Images + +```bash +cd gateway +make build-debug +``` + +This builds both `gateway-controller-debug:latest` and `gateway-runtime-debug:latest`. + +### Step 2: Start the Full Stack + +```bash +cd gateway +docker compose -f docker-compose.debug.yaml up +``` + +Wait until you see both containers are ready. The policy engine waits up to 30 seconds for dlv startup before the socket becomes available. + +### Step 3: Set Breakpoints + +Open the relevant source files in VS Code and set breakpoints: + +- **Gateway Controller**: files under `gateway/gateway-controller/` +- **Policy Engine**: files under `gateway/gateway-runtime/policy-engine/` + +### Step 4: Attach VS Code Debugger + +In the VS Code **Run & Debug** panel, launch: + +- **"Gateway Controller (Remote)"** — attaches to `localhost:2345` +- **"Policy Engine (Remote)"** — attaches to `localhost:2346` + +Both can be attached simultaneously. Source path substitution is configured automatically in `.vscode/launch.json`: + +| Component | Local path | Container path | +|---|---|---| +| Gateway Controller | `gateway/gateway-controller` | `/build` | +| Policy Engine | `gateway/gateway-runtime/policy-engine` | `/api-platform/gateway/gateway-runtime/policy-engine` | + +### Step 5: Deploy an API and Trigger Breakpoints + +```bash +# Deploy a test API +curl -X POST http://localhost:9090/apis \ + -H "Content-Type: application/yaml" \ + --data-binary @path/to/api.yaml + +# Send a request through the router +curl http://localhost:8080/petstore/v1/pets +``` + +### Notes + +- dlv runs with `--accept-multiclient` — you can detach and re-attach without restarting containers. +- Containers run as root (required by dlv for ptrace); resource limits are removed for debug headroom. +- Policy Engine socket wait timeout is 30s (vs 10s in production) to account for dlv startup overhead. +- All ports remain accessible: `9090` (Controller REST), `8080`/`8443` (Router), `9002` (PE admin), `18000`/`18001` (xDS). + +--- + +## Option 2 (Alternative): Local Process Debug — Controller + Policy Engine in VS Code + +Gateway Controller and Policy Engine run as local VS Code processes. Only the Envoy Router runs in Docker Compose. + +> **Warning:** Processes run directly on the host, so Go resolves modules via `go.work`. Local versions of `sdk` and other workspace modules are used instead of the published Go module versions — including any uncommitted or untagged changes. Behavior may differ from a production build. + +### Architecture ```mermaid graph TB @@ -21,14 +93,12 @@ graph TB GC -->|localhost:18001| PE ``` -## Prerequisites +### Prerequisites - VS Code with Go extension installed - Docker and Docker Compose - Control plane host and registration token (optional, for gateway registration) -## Step-by-Step Instructions - ### Step 1: Configure Control Plane Connection Update `.vscode/launch.json` in the **Gateway Controller** configuration with your control plane details: @@ -48,22 +118,33 @@ Update `.vscode/launch.json` in the **Gateway Controller** configuration with yo ### Step 2: Update Docker Compose Configuration -Edit `gateway/docker-compose.yml` and comment out the policy engine port mappings in the `gateway-runtime` service, keeping only the router ports: +In `gateway/docker-compose.yaml`, make two changes to the `gateway-runtime` service: + +1. Set `GATEWAY_CONTROLLER_HOST` to `host.docker.internal` so the runtime reaches the locally-running controller: + +```yaml +services: + gateway-runtime: + environment: + GATEWAY_CONTROLLER_HOST: host.docker.internal +``` + +2. Comment out the **Policy Engine** port block: ```yaml services: gateway-runtime: ports: - # Router ports (keep these) - - "8080:8080" # HTTP - - "8443:8443" # HTTPS - - "9901:9901" # Admin - - # Policy engine ports (comment these out - running locally) - # - "9001:9001" # ext_proc - # - "9002:9002" # Policy engine admin + # Router (Envoy) - keep these + - "8080:8080" # HTTP ingress + - "8443:8443" # HTTPS ingress + - "8081:8081" # xDS-managed API listener + - "8082:8082" # WebSub Hub dynamic forward proxy + - "8083:8083" # WebSub Hub internal listener + - "9901:9901" # Envoy admin + # Policy Engine - comment these out + # - "9002:9002" # Admin API # - "9003:9003" # Metrics - # - "18090:18090" # ALS ``` ### Step 3: Start Gateway Controller diff --git a/gateway/Makefile b/gateway/Makefile index 261ecc5f9..884cd9fe8 100644 --- a/gateway/Makefile +++ b/gateway/Makefile @@ -39,11 +39,12 @@ help: ## Show this help message @echo '' @echo 'Build Targets:' @echo ' make build - Build all gateway component Docker images (buildx)' - @echo ' make build-local - Build all gateway component Docker images locally (faster)' @echo ' make build-controller - Build gateway-controller Docker image' + @echo ' make build-controller-debug - Build debug gateway-controller image for remote debugging (dlv on port 2345)' @echo ' make build-gateway-builder - Build gateway-builder Docker image' @echo ' make build-gateway-runtime - Build gateway-runtime Docker image (Router + Policy Engine)' - @echo ' make build-local-gateway-runtime - Build gateway-runtime Docker image locally (faster)' + @echo ' make build-debug - Build all debug images (controller + runtime) for remote debugging' + @echo ' make build-gateway-runtime-debug - Build debug gateway-runtime image for remote debugging (dlv on port 2346)' @echo '' @echo 'Multi-arch Build and Push Targets:' @echo ' make build-and-push-multiarch - Build and push all gateway components for multiple architectures' @@ -79,8 +80,9 @@ help: ## Show this help message .PHONY: build build: build-controller build-gateway-builder build-gateway-runtime ## Build all gateway components -.PHONY: build-local -build-local: build-local-controller build-local-gateway-builder build-local-gateway-runtime ## Build all gateway components locally (faster) + +.PHONY: build-debug +build-debug: build-controller-debug build-gateway-runtime-debug ## Build all debug images (controller + runtime) for remote debugging .PHONY: build-coverage build-coverage: build-gateway-builder build-controller-coverage build-gateway-runtime-coverage ## Build all coverage-instrumented gateway components @@ -90,41 +92,39 @@ build-controller: ## Build gateway-controller Docker image @echo "Building controller Docker image ($(VERSION))..." $(MAKE) -C gateway-controller build VERSION=$(VERSION) -.PHONY: build-local-controller -build-local-controller: ## Build gateway-controller Docker image locally (faster) - @echo "Building controller Docker image locally ($(VERSION))..." - $(MAKE) -C gateway-controller build-local VERSION=$(VERSION) .PHONY: build-controller-coverage build-controller-coverage: ## Build coverage-instrumented gateway-controller Docker image @echo "Building coverage-instrumented controller Docker image ($(VERSION))..." $(MAKE) -C gateway-controller build-coverage-image VERSION=$(VERSION) +.PHONY: build-controller-debug +build-controller-debug: ## Build debug gateway-controller image for remote debugging + @echo "Building debug controller Docker image ($(VERSION))..." + $(MAKE) -C gateway-controller build-debug VERSION=$(VERSION) + .PHONY: build-gateway-builder build-gateway-builder: ## Build gateway-builder Docker image @echo "Building gateway-builder Docker image ($(VERSION))..." $(MAKE) -C gateway-builder build VERSION=$(VERSION) -.PHONY: build-local-gateway-builder -build-local-gateway-builder: ## Build gateway-builder Docker image locally (faster) - @echo "Building gateway-builder Docker image locally ($(VERSION))..." - $(MAKE) -C gateway-builder build-local VERSION=$(VERSION) .PHONY: build-gateway-runtime build-gateway-runtime: ## Build gateway-runtime Docker image (Router + Policy Engine) @echo "Building gateway-runtime Docker image ($(VERSION))..." $(MAKE) -C gateway-runtime build VERSION=$(VERSION) -.PHONY: build-local-gateway-runtime -build-local-gateway-runtime: ## Build gateway-runtime Docker image locally (faster) - @echo "Building gateway-runtime Docker image locally ($(VERSION))..." - $(MAKE) -C gateway-runtime build-local VERSION=$(VERSION) .PHONY: build-gateway-runtime-coverage build-gateway-runtime-coverage: ## Build coverage-instrumented gateway-runtime Docker image @echo "Building coverage-instrumented gateway-runtime Docker image ($(VERSION))..." $(MAKE) -C gateway-runtime build-coverage-image VERSION=$(VERSION) +.PHONY: build-gateway-runtime-debug +build-gateway-runtime-debug: ## Build debug gateway-runtime image for remote debugging + @echo "Building debug gateway-runtime Docker image ($(VERSION))..." + $(MAKE) -C gateway-runtime build-debug VERSION=$(VERSION) + # Multi-arch Build and Push Targets .PHONY: build-and-push-multiarch build-and-push-multiarch: build-and-push-multiarch-controller build-and-push-multiarch-gateway-builder build-and-push-multiarch-gateway-runtime ## Build and push all gateway components for multiple architectures diff --git a/gateway/docker-compose.debug.yaml b/gateway/docker-compose.debug.yaml new file mode 100644 index 000000000..8f3b0d19c --- /dev/null +++ b/gateway/docker-compose.debug.yaml @@ -0,0 +1,98 @@ +# -------------------------------------------------------------------- +# Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). +# +# WSO2 LLC. licenses this file to you under the Apache License, +# Version 2.0 (the "License"); you may not use this file except +# in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# -------------------------------------------------------------------- + +# Compose overlay for remote debugging gateway components with dlv. +# Usage: docker compose -f docker-compose.yaml -f docker-compose.debug.yaml up +# +# Prerequisites: +# 1. Build debug images: +# cd gateway-controller && make build-debug +# cd gateway-runtime && make build-debug +# 2. In VS Code Run & Debug: +# - "Gateway Controller (Remote)" (port 2345) +# - "Policy Engine (Remote)" (port 2346) + +# NOTE: gateway-controller and gateway-runtime here duplicate docker-compose.yaml — keep in sync. + +services: + gateway-controller: + image: ghcr.io/wso2/api-platform/gateway-controller-debug:latest + command: ["-config", "/etc/gateway-controller/config.toml"] + ports: + - "9090:9090" # REST API + - "9094:9092" # Admin API + - "18000:18000" # xDS gRPC (Router) + - "18001:18001" # xDS gRPC (Policy Engine) + - "9011:9091" # Metrics + - "2345:2345" # dlv remote debug port + environment: + - APIP_GW_CONTROLLER_STORAGE_TYPE=sqlite + - APIP_GW_CONTROLLER_STORAGE_SQLITE_PATH=./data/gateway.db + - APIP_GW_CONTROLLER_LOGGING_LEVEL=info + - APIP_GW_CONTROLLER_METRICS_PORT=9091 + - APIP_GW_GATEWAY_REGISTRATION_TOKEN=${GATEWAY_REGISTRATION_TOKEN:-} + - APIP_GW_CONTROLPLANE_HOST=${GATEWAY_CONTROLPLANE_HOST:-host.docker.internal:9243} + volumes: + - controller-data:/app/data + - ./configs/config.toml:/etc/gateway-controller/config.toml:ro + - ./gateway-controller/certificates:/app/certificates + - ./gateway-controller/listener-certs:/app/listener-certs:ro + extra_hosts: + - "host.docker.internal:host-gateway" + networks: + - gateway-network + cap_add: + - SYS_PTRACE # required by dlv for process introspection + security_opt: + - seccomp:unconfined # dlv uses syscalls blocked by the default seccomp profile + + gateway-runtime: + image: ghcr.io/wso2/api-platform/gateway-runtime-debug:latest + command: ["--pol.config", "/etc/policy-engine/config.toml"] + ports: + # Router (Envoy) + - "8080:8080" # HTTP ingress + - "8443:8443" # HTTPS ingress + - "8081:8081" # xDS-managed API listener + - "8082:8082" # WebSub Hub dynamic forward proxy + - "8083:8083" # WebSub Hub internal listener + - "9901:9901" # Envoy admin + # Policy Engine + - "9002:9002" # Admin API + - "9003:9003" # Metrics + - "2346:2346" # dlv remote debug port + environment: + - GATEWAY_CONTROLLER_HOST=gateway-controller + - MOESIF_KEY=${MOESIF_KEY:-} + - LOG_LEVEL=info + volumes: + - ./configs/config.toml:/etc/policy-engine/config.toml:ro + networks: + - gateway-network + cap_add: + - SYS_PTRACE # required by dlv for process introspection + security_opt: + - seccomp:unconfined # dlv uses syscalls blocked by the default seccomp profile + +volumes: + controller-data: + driver: local + +networks: + gateway-network: + driver: bridge diff --git a/gateway/docker-compose.yaml b/gateway/docker-compose.yaml index e3f0a2373..d3afcc640 100644 --- a/gateway/docker-compose.yaml +++ b/gateway/docker-compose.yaml @@ -16,6 +16,8 @@ # under the License. # -------------------------------------------------------------------- +# NOTE: gateway-controller and gateway-runtime are duplicated in docker-compose.debug.yaml — keep in sync. + services: gateway-controller: image: ghcr.io/wso2/api-platform/gateway-controller:0.8.8-SNAPSHOT @@ -53,14 +55,16 @@ services: cpus: 0.175 command: ["--pol.config", "/etc/policy-engine/config.toml"] ports: - - "8080:8080" # HTTP traffic (Envoy) - - "8443:8443" # HTTPS traffic (Envoy) + # Router (Envoy) + - "8080:8080" # HTTP ingress + - "8443:8443" # HTTPS ingress + - "8081:8081" # xDS-managed API listener + - "8082:8082" # WebSub Hub dynamic forward proxy + - "8083:8083" # WebSub Hub internal listener - "9901:9901" # Envoy admin - - "8081:8081" - - "8082:8082" - - "8083:8083" - - "9002:9002" # Policy Engine admin - - "9003:9003" # Policy Engine metrics + # Policy Engine + - "9002:9002" # Admin API + - "9003:9003" # Metrics environment: - GATEWAY_CONTROLLER_HOST=gateway-controller - MOESIF_KEY=${MOESIF_KEY:-} diff --git a/gateway/gateway-builder/Makefile b/gateway/gateway-builder/Makefile index 7a4912a2d..e08a4e598 100644 --- a/gateway/gateway-builder/Makefile +++ b/gateway/gateway-builder/Makefile @@ -39,7 +39,6 @@ help: ## Show this help message @echo '' @echo 'Build Targets:' @echo ' make build - Build Docker image using buildx' - @echo ' make build-local - Build Docker image locally (faster)' @echo ' make push - Push Docker image to registry' @echo ' make build-and-push-multiarch - Build and push multi-arch Docker image' @echo '' @@ -69,19 +68,6 @@ build: ## Build Docker image using buildx --load \ . -.PHONY: build-local -build-local: ## Build Docker image locally (faster, no buildx) - @echo "Building Docker image locally ($(IMAGE_NAME):$(VERSION))..." - @DOCKER_BUILDKIT=1 docker build -f Dockerfile \ - --build-context policy-engine=../gateway-runtime/policy-engine \ - --build-context system-policies=../system-policies \ - --build-context sdk=../../sdk \ - --build-context common=../../common \ - --build-arg VERSION=$(VERSION) \ - --build-arg GIT_COMMIT=$(GIT_COMMIT) \ - -t $(IMAGE_NAME):$(VERSION) \ - -t $(IMAGE_NAME):latest \ - . .PHONY: push push: ## Push Docker image to registry diff --git a/gateway/gateway-builder/internal/compilation/compiler.go b/gateway/gateway-builder/internal/compilation/compiler.go index b0c1273fe..fe23cd032 100644 --- a/gateway/gateway-builder/internal/compilation/compiler.go +++ b/gateway/gateway-builder/internal/compilation/compiler.go @@ -127,6 +127,14 @@ func runGoBuild(srcDir string, options *types.CompilationOptions) error { args = append(args, "-cover") } + // Add debug flags if enabled (no optimizations/inlining for dlv) + if options.EnableDebug { + slog.Info("Building with debug flags (no optimizations/inlining)", + "step", "build", + "phase", "compilation") + args = append(args, "-gcflags", "all=-N -l") + } + // Add build tags if len(options.BuildTags) > 0 { tags := "" diff --git a/gateway/gateway-builder/internal/compilation/options.go b/gateway/gateway-builder/internal/compilation/options.go index 99500fbcd..6881aaa13 100644 --- a/gateway/gateway-builder/internal/compilation/options.go +++ b/gateway/gateway-builder/internal/compilation/options.go @@ -36,6 +36,12 @@ func BuildOptions(outputPath string, buildMetadata *types.BuildMetadata) *types. enableCoverage = true } + // Check for debug mode from environment variable + enableDebug := false + if debugEnv := os.Getenv("DEBUG"); strings.EqualFold(debugEnv, "true") { + enableDebug = true + } + // Determine target architecture: // 1. Use TARGETARCH env var if set (Docker buildx cross-compilation) // 2. Fall back to runtime.GOARCH (native build) @@ -45,8 +51,8 @@ func BuildOptions(outputPath string, buildMetadata *types.BuildMetadata) *types. } // Generate ldflags for build metadata injection - // Pass enableCoverage to avoid stripping debug info needed for coverage - ldflags := generateLDFlags(buildMetadata, enableCoverage) + // Pass enableCoverage/enableDebug to avoid stripping debug info when needed + ldflags := generateLDFlags(buildMetadata, enableCoverage, enableDebug) return &types.CompilationOptions{ OutputPath: outputPath, @@ -56,17 +62,18 @@ func BuildOptions(outputPath string, buildMetadata *types.BuildMetadata) *types. TargetOS: "linux", TargetArch: targetArch, EnableCoverage: enableCoverage, + EnableDebug: enableDebug, } } // generateLDFlags creates ldflags string for embedding build metadata -// enableCoverage determines if coverage is enabled (skip -s -w flags if so) -func generateLDFlags(metadata *types.BuildMetadata, enableCoverage bool) string { +// enableCoverage/enableDebug determine if debug info should be preserved +func generateLDFlags(metadata *types.BuildMetadata, enableCoverage bool, enableDebug bool) string { var ldflags string - - // Only strip debug info if coverage is NOT enabled - // -s and -w interfere with Go coverage instrumentation - if !enableCoverage { + + // Only strip debug info if neither coverage nor debug mode is enabled + // -s and -w interfere with Go coverage instrumentation and dlv debugging + if !enableCoverage && !enableDebug { ldflags = "-s -w" // Strip debug info and symbol table } diff --git a/gateway/gateway-builder/internal/compilation/options_test.go b/gateway/gateway-builder/internal/compilation/options_test.go index 136be011e..a000693bd 100644 --- a/gateway/gateway-builder/internal/compilation/options_test.go +++ b/gateway/gateway-builder/internal/compilation/options_test.go @@ -127,7 +127,7 @@ func TestGenerateLDFlags_WithoutCoverage(t *testing.T) { Timestamp: time.Date(2025, 6, 15, 14, 30, 0, 0, time.UTC), } - ldflags := generateLDFlags(metadata, false) + ldflags := generateLDFlags(metadata, false, false) assert.Contains(t, ldflags, "-s -w") assert.Contains(t, ldflags, "-X main.Version=v1.2.3") @@ -142,7 +142,7 @@ func TestGenerateLDFlags_WithCoverage(t *testing.T) { Timestamp: time.Date(2025, 12, 25, 8, 0, 0, 0, time.UTC), } - ldflags := generateLDFlags(metadata, true) + ldflags := generateLDFlags(metadata, true, false) // Should NOT have -s -w when coverage is enabled assert.NotContains(t, ldflags, "-s -w") @@ -158,7 +158,7 @@ func TestGenerateLDFlags_EmptyMetadata(t *testing.T) { Timestamp: time.Time{}, } - ldflags := generateLDFlags(metadata, false) + ldflags := generateLDFlags(metadata, false, false) assert.Contains(t, ldflags, "-s -w") assert.Contains(t, ldflags, "-X main.Version=") diff --git a/gateway/gateway-builder/pkg/types/policy.go b/gateway/gateway-builder/pkg/types/policy.go index 83d514235..ca6fa79d7 100644 --- a/gateway/gateway-builder/pkg/types/policy.go +++ b/gateway/gateway-builder/pkg/types/policy.go @@ -98,6 +98,7 @@ type CompilationOptions struct { TargetOS string TargetArch string EnableCoverage bool // Enable coverage instrumentation for integration tests + EnableDebug bool // Disable optimizations/inlining for dlv remote debugging } // PackagingMetadata contains Docker image metadata diff --git a/gateway/gateway-controller/Dockerfile b/gateway/gateway-controller/Dockerfile index 5c862652e..a203c2973 100644 --- a/gateway/gateway-controller/Dockerfile +++ b/gateway/gateway-controller/Dockerfile @@ -8,6 +8,9 @@ ARG GIT_COMMIT=unknown # Coverage build argument - set to "true" for coverage-instrumented builds ARG ENABLE_COVERAGE=false +# Debug build argument - set to "true" for debug builds with dlv support (disables optimizations) +ARG ENABLE_DEBUG=false + WORKDIR /build # Install build dependencies for SQLite (CGO) and cross-compilation toolchains @@ -37,7 +40,7 @@ COPY --from=sdk . /sdk COPY --from=common . /common COPY . ./ -# Build with CGO (required for SQLite), set CC for cross-compilation, add -cover flag if enabled +# Build with CGO (required for SQLite), set CC for cross-compilation, add -cover/-gcflags if enabled RUN --mount=type=cache,target=/go/pkg/mod \ --mount=type=cache,target=/root/.cache/go-build \ if [ "$TARGETARCH" = "amd64" ]; then \ @@ -52,14 +55,43 @@ RUN --mount=type=cache,target=/go/pkg/mod \ else \ COVER_FLAG=""; \ fi && \ - CGO_ENABLED=1 \ - GOOS=linux \ - GOARCH=${TARGETARCH} \ - go build $COVER_FLAG \ - -ldflags "-X main.Version=${VERSION} \ - -X main.GitCommit=${GIT_COMMIT} \ - -X main.BuildDate=$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ - -o controller cmd/controller/main.go + export CGO_ENABLED=1 && \ + export GOOS=linux && \ + export GOARCH=${TARGETARCH} && \ + BUILD_DATE=$(date -u +%Y-%m-%dT%H:%M:%SZ) && \ + if [ "$ENABLE_DEBUG" = "true" ]; then \ + go build $COVER_FLAG \ + -gcflags "all=-N -l" \ + -ldflags "-X main.Version=${VERSION} -X main.GitCommit=${GIT_COMMIT} -X main.BuildDate=${BUILD_DATE}" \ + -o controller cmd/controller/main.go; \ + else \ + go build $COVER_FLAG \ + -ldflags "-X main.Version=${VERSION} -X main.GitCommit=${GIT_COMMIT} -X main.BuildDate=${BUILD_DATE}" \ + -o controller cmd/controller/main.go; \ + fi + +# Stage: debug (select with --target debug; NOT part of the default build) +# Full Go image needed to install dlv via go install; acceptable for dev-only use. +# Runs as root — dlv requires ptrace; container security settings handle isolation. +FROM golang:1.25.7-bookworm AS debug +WORKDIR /app + +# Install dlv (Delve debugger) +RUN go install github.com/go-delve/delve/cmd/dlv@latest + +# Copy debug-compiled binary and required runtime assets +COPY --from=builder /build/controller . +COPY default-policies /app/default-policies +COPY lua /app/lua +COPY default-llm-provider-templates /app/default-llm-provider-templates +RUN mkdir -p /app/data + +EXPOSE 2345 9090 18000 + +# Run controller under dlv in headless mode, waiting for debugger attach on :2345 +ENTRYPOINT ["/go/bin/dlv", "exec", "/app/controller", \ + "--listen=:2345", "--headless=true", \ + "--api-version=2", "--accept-multiclient", "--"] # Stage 2: Runtime image (Debian slim for glibc compatibility) FROM debian:bookworm-slim diff --git a/gateway/gateway-controller/Makefile b/gateway/gateway-controller/Makefile index 1a36821c1..69b85ad48 100644 --- a/gateway/gateway-controller/Makefile +++ b/gateway/gateway-controller/Makefile @@ -28,7 +28,7 @@ LDFLAGS := -X main.Version=$(VERSION) -X main.GitCommit=$(GIT_COMMIT) -X main.Bu DOCKER_REGISTRY ?= ghcr.io/wso2/api-platform IMAGE_NAME := $(DOCKER_REGISTRY)/gateway-controller -.PHONY: help generate build build-local test generate-listener-certs push build-coverage-image +.PHONY: help generate build test generate-listener-certs push build-coverage-image build-debug help: ## Show this help message @echo 'Usage: make [target]' @@ -57,16 +57,6 @@ build: generate test ## Build Docker image using buildx --load \ . -build-local: generate ## Build Docker image locally (faster, no buildx) - @echo "Building Docker image locally ($(IMAGE_NAME):$(VERSION))..." - DOCKER_BUILDKIT=1 docker build -f Dockerfile \ - --build-context sdk=../../sdk \ - --build-context common=../../common \ - --build-arg VERSION=$(VERSION) \ - --build-arg GIT_COMMIT=$(GIT_COMMIT) \ - -t $(IMAGE_NAME):$(VERSION) \ - -t $(IMAGE_NAME):latest \ - . push: ## Push Docker image to registry @echo "Pushing Docker images..." @@ -97,6 +87,19 @@ build-coverage-image: test ## Build coverage-instrumented gateway-controller ima --load \ . +build-debug: ## Build debug image for remote debugging with dlv (VS Code attach on port 2345) + docker buildx build -f Dockerfile \ + --build-context sdk=../../sdk \ + --build-context common=../../common \ + --build-arg VERSION=$(VERSION) \ + --build-arg GIT_COMMIT=$(GIT_COMMIT) \ + --build-arg ENABLE_DEBUG=true \ + --target debug \ + -t $(IMAGE_NAME)-debug:$(VERSION) \ + -t $(IMAGE_NAME)-debug:latest \ + --load \ + . + generate-listener-certs: ## Generate listener certificates @echo "Generating listener certificates..." @mkdir -p listener-certs diff --git a/gateway/gateway-controller/pkg/config/config.go b/gateway/gateway-controller/pkg/config/config.go index e1baf73d1..f58656824 100644 --- a/gateway/gateway-controller/pkg/config/config.go +++ b/gateway/gateway-controller/pkg/config/config.go @@ -517,7 +517,7 @@ func defaultConfig() *Config { Port: 9091, }, ControlPlane: ControlPlaneConfig{ - Host: "localhost:9243", + Host: "", Token: "", ReconnectInitial: 1 * time.Second, ReconnectMax: 5 * time.Minute, @@ -934,31 +934,34 @@ func (c *Config) validateEventGatewayConfig() error { // validateControlPlaneConfig validates the control plane configuration func (c *Config) validateControlPlaneConfig() error { - // Host validation - required if control plane is configured - if c.Controller.ControlPlane.Host == "" { - return fmt.Errorf("controlplane.host is required") - } + cp := &c.Controller.ControlPlane - // Token is optional - gateway can run without control plane connection - // If token is empty, connection will not be established + // If no host is set, the gateway runs in standalone mode — skip all CP validation. + if cp.Host == "" { + // A token without a host is a misconfiguration. + if cp.Token != "" { + return fmt.Errorf("controlplane.host is required when controlplane.token is set") + } + return nil + } // Validate reconnection intervals - if c.Controller.ControlPlane.ReconnectInitial <= 0 { - return fmt.Errorf("controlplane.reconnect_initial must be positive, got: %s", c.Controller.ControlPlane.ReconnectInitial) + if cp.ReconnectInitial <= 0 { + return fmt.Errorf("controlplane.reconnect_initial must be positive, got: %s", cp.ReconnectInitial) } - if c.Controller.ControlPlane.ReconnectMax <= 0 { - return fmt.Errorf("controlplane.reconnect_max must be positive, got: %s", c.Controller.ControlPlane.ReconnectMax) + if cp.ReconnectMax <= 0 { + return fmt.Errorf("controlplane.reconnect_max must be positive, got: %s", cp.ReconnectMax) } - if c.Controller.ControlPlane.ReconnectInitial > c.Controller.ControlPlane.ReconnectMax { + if cp.ReconnectInitial > cp.ReconnectMax { return fmt.Errorf("controlplane.reconnect_initial (%s) must be <= controlplane.reconnect_max (%s)", - c.Controller.ControlPlane.ReconnectInitial, c.Controller.ControlPlane.ReconnectMax) + cp.ReconnectInitial, cp.ReconnectMax) } // Validate polling interval - if c.Controller.ControlPlane.PollingInterval <= 0 { - return fmt.Errorf("controlplane.polling_interval must be positive, got: %s", c.Controller.ControlPlane.PollingInterval) + if cp.PollingInterval <= 0 { + return fmt.Errorf("controlplane.polling_interval must be positive, got: %s", cp.PollingInterval) } return nil diff --git a/gateway/gateway-controller/pkg/config/config_test.go b/gateway/gateway-controller/pkg/config/config_test.go index 106d085ab..2d605f6f1 100644 --- a/gateway/gateway-controller/pkg/config/config_test.go +++ b/gateway/gateway-controller/pkg/config/config_test.go @@ -633,6 +633,7 @@ func TestConfig_ValidateControlPlaneConfig(t *testing.T) { tests := []struct { name string host string + token string reconnectInitial time.Duration reconnectMax time.Duration pollingInterval time.Duration @@ -648,10 +649,19 @@ func TestConfig_ValidateControlPlaneConfig(t *testing.T) { wantErr: false, }, { - name: "Missing host", + name: "Missing host (standalone mode)", + host: "", + reconnectInitial: 1 * time.Second, + reconnectMax: 30 * time.Second, + pollingInterval: 5 * time.Second, + wantErr: false, + }, + { + name: "Token set without host", host: "", + token: "some-token", wantErr: true, - errContains: "controlplane.host is required", + errContains: "controlplane.host is required when controlplane.token is set", }, { name: "Non-positive reconnect initial", @@ -695,6 +705,7 @@ func TestConfig_ValidateControlPlaneConfig(t *testing.T) { t.Run(tt.name, func(t *testing.T) { cfg := validConfig() cfg.Controller.ControlPlane.Host = tt.host + cfg.Controller.ControlPlane.Token = tt.token cfg.Controller.ControlPlane.ReconnectInitial = tt.reconnectInitial cfg.Controller.ControlPlane.ReconnectMax = tt.reconnectMax cfg.Controller.ControlPlane.PollingInterval = tt.pollingInterval diff --git a/gateway/gateway-runtime/Dockerfile b/gateway/gateway-runtime/Dockerfile index b7515715a..e4c235f72 100644 --- a/gateway/gateway-runtime/Dockerfile +++ b/gateway/gateway-runtime/Dockerfile @@ -72,11 +72,13 @@ ARG VERSION ARG GIT_COMMIT ARG BUILD_DATE ARG ENABLE_COVERAGE +ARG ENABLE_DEBUG=false ARG TARGETARCH ENV VERSION=${VERSION} ENV GIT_COMMIT=${GIT_COMMIT} ENV BUILD_DATE=${BUILD_DATE} ENV TARGETARCH=${TARGETARCH} +ENV ENABLE_DEBUG=${ENABLE_DEBUG} # Download SDK dependencies (cached by go.mod/go.sum changes) COPY --from=sdk go.mod go.sum /api-platform/sdk/ @@ -108,18 +110,59 @@ RUN mkdir -p /workspace/output WORKDIR /workspace -# Run gateway builder with build file, conditionally enable coverage +# Run gateway builder with build file, conditionally enable coverage or debug # Cache mounts let the builder's internal go build reuse compiled packages RUN --mount=type=cache,target=/go/pkg/mod \ --mount=type=cache,target=/root/.cache/go-build \ [ "$ENABLE_COVERAGE" = "true" ] && export COVERAGE=true || true; \ + [ "$ENABLE_DEBUG" = "true" ] && export DEBUG=true || true; \ /usr/local/bin/gateway-builder \ -build-file /workspace/policies/build.yaml \ -system-build-lock /workspace/system-policies/system-build-lock.yaml \ -policy-engine-src /api-platform/gateway/gateway-runtime/policy-engine \ -out-dir /workspace/output -# Stage 3: Runtime +# Stage 3a: dlv installer (builds dlv for the debug stage) +FROM golang:1.25.7-bookworm AS debug-dlv-builder +RUN go install github.com/go-delve/delve/cmd/dlv@latest + +# Stage 3b: Debug Runtime (policy-engine wrapped in dlv, port 2346) +FROM envoyproxy/envoy:v1.35.3 AS debug + +USER root +RUN --mount=type=cache,target=/var/cache/apt,sharing=locked \ + --mount=type=cache,target=/var/lib/apt/lists,sharing=locked \ + apt-get update && apt-get install -y --no-install-recommends \ + tini \ + gettext-base \ + ca-certificates \ + curl \ + netcat-openbsd \ + dnsutils \ + iproute2 \ + iputils-ping \ + net-tools + +RUN mkdir -p /app /var/run/api-platform /coverage + +COPY --from=debug-dlv-builder /go/bin/dlv /usr/local/bin/dlv +COPY --from=policy-compiler /workspace/output/gateway-runtime/policy-engine /app/policy-engine +COPY router/config/envoy-bootstrap.yaml /etc/envoy/envoy.yaml +COPY router/config/config-override.yaml /etc/envoy/config-override.yaml +COPY docker-entrypoint-debug.sh /usr/local/bin/docker-entrypoint.sh +COPY health-check.sh /usr/local/bin/health-check.sh + +RUN chmod +x /app/policy-engine /usr/local/bin/dlv /usr/local/bin/docker-entrypoint.sh /usr/local/bin/health-check.sh + +ENV GATEWAY_CONTROLLER_HOST=gateway-controller \ + LOG_LEVEL=info + +# dlv requires elevated privileges (no USER wso2) +EXPOSE 2346 8080 8443 9901 9002 9003 + +ENTRYPOINT ["/usr/bin/tini", "--", "/usr/local/bin/docker-entrypoint.sh"] + +# Stage 4: Runtime (production — must remain last so default builds are unaffected) FROM envoyproxy/envoy:v1.35.3 ARG VERSION=unknown diff --git a/gateway/gateway-runtime/Makefile b/gateway/gateway-runtime/Makefile index e2ea59198..71912e7b0 100644 --- a/gateway/gateway-runtime/Makefile +++ b/gateway/gateway-runtime/Makefile @@ -26,7 +26,7 @@ GIT_COMMIT := $(shell git rev-parse --short HEAD 2>/dev/null || echo "unknown") DOCKER_REGISTRY ?= ghcr.io/wso2/api-platform IMAGE_NAME := $(DOCKER_REGISTRY)/gateway-runtime -.PHONY: help build build-local build-coverage-image push clean build-and-push-multiarch test +.PHONY: help build build-coverage-image build-debug push clean build-and-push-multiarch test help: ## Show this help message @echo 'Gateway Runtime Build (Version: $(VERSION))' @@ -53,10 +53,11 @@ build: ## Build Gateway Runtime Docker image using buildx @rm -rf target @echo "Docker image built successfully: $(IMAGE_NAME):$(VERSION)" -build-local: ## Build Gateway Runtime Docker image locally (faster, no buildx) - @echo "Building Gateway Runtime Docker image locally ($(IMAGE_NAME):$(VERSION))..." + +build-debug: ## Build debug Gateway Runtime image for remote debugging with dlv (VS Code attach on port 2346) + @echo "Building Gateway Runtime debug image ($(IMAGE_NAME)-debug:$(VERSION))..." @mkdir -p target && cp ../build.yaml target/ - DOCKER_BUILDKIT=1 docker build -f Dockerfile \ + docker buildx build -f Dockerfile \ --build-context sdk=../../sdk \ --build-context common=../../common \ --build-context gateway-builder=../gateway-builder \ @@ -65,11 +66,14 @@ build-local: ## Build Gateway Runtime Docker image locally (faster, no buildx) --build-context target=target \ --build-arg VERSION=$(VERSION) \ --build-arg GIT_COMMIT=$(GIT_COMMIT) \ - -t $(IMAGE_NAME):$(VERSION) \ - -t $(IMAGE_NAME):latest \ + --build-arg ENABLE_DEBUG=true \ + --target debug \ + -t $(IMAGE_NAME)-debug:$(VERSION) \ + -t $(IMAGE_NAME)-debug:latest \ + --load \ . @rm -rf target - @echo "Docker image built successfully: $(IMAGE_NAME):$(VERSION)" + @echo "Debug image built successfully: $(IMAGE_NAME)-debug:$(VERSION)" build-coverage-image: test ## Build Gateway Runtime Docker image with coverage instrumentation @echo "Building Gateway Runtime coverage image ($(IMAGE_NAME)-coverage:$(VERSION))..." diff --git a/gateway/gateway-runtime/docker-entrypoint-debug.sh b/gateway/gateway-runtime/docker-entrypoint-debug.sh new file mode 100644 index 000000000..f31b6729b --- /dev/null +++ b/gateway/gateway-runtime/docker-entrypoint-debug.sh @@ -0,0 +1,224 @@ +#!/bin/bash + +# -------------------------------------------------------------------- +# Copyright (c) 2026, WSO2 LLC. (https://www.wso2.com). +# +# WSO2 LLC. licenses this file to you under the Apache License, +# Version 2.0 (the "License"); you may not use this file except +# in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# -------------------------------------------------------------------- + +# Gateway Runtime Debug Entrypoint Script +# Variant of docker-entrypoint.sh that wraps the policy engine in dlv for +# remote debugging via VS Code (port 2346). + +# NOTE: Mostly duplicates docker-entrypoint.sh — keep in sync. + +# Process-specific args can be passed using prefixed flags: +# --rtr. → forwarded to Router (Envoy) +# --pol. → forwarded to Policy Engine +# +# Examples: +# docker run gateway-runtime-debug --rtr.component-log-level upstream:debug --pol.log-format text + +set -e + +# Logging function for entrypoint messages +log() { + echo "[ent] $(date '+%Y-%m-%d %H:%M:%S') $1" +} + +# Parse process-specific args from command line. +# Uses dot (.) as the prefix separator (e.g. --rtr.flag, --pol.flag) because no +# standard CLI flag contains a dot, making prefix detection unambiguous. +# --rtr.X → ROUTER_ARGS, --pol.X → PE_ARGS, unrecognized → warning +ROUTER_ARGS=() +PE_ARGS=() + +while [[ $# -gt 0 ]]; do + case "$1" in + --rtr.*) + ROUTER_ARGS+=("--${1#--rtr.}") + shift + # Consume the value if next arg is not a flag + if [[ $# -gt 0 && "$1" != --* ]]; then + ROUTER_ARGS+=("$1") + shift + fi + ;; + --pol.*) + PE_ARGS+=("--${1#--pol.}") + shift + if [[ $# -gt 0 && "$1" != --* ]]; then + PE_ARGS+=("$1") + shift + fi + ;; + *) + log "ERROR: Unrecognized arg '$1' (use --rtr. or --pol. prefix)" + exit 1 + ;; + esac +done + +# Default configuration +# GATEWAY_CONTROLLER_HOST is the primary user-facing env var to configure connectivity +# to the gateway controller. The xDS ports default to well-known values: +# - ROUTER_XDS_PORT (18000): Router (Envoy) route/cluster/listener configs +# - POLICY_ENGINE_XDS_PORT (18001): Policy Engine policy chain configs +export GATEWAY_CONTROLLER_HOST="${GATEWAY_CONTROLLER_HOST:-gateway-controller}" +export ROUTER_XDS_PORT="${ROUTER_XDS_PORT:-18000}" +export POLICY_ENGINE_XDS_PORT="${POLICY_ENGINE_XDS_PORT:-18001}" +export LOG_LEVEL="${LOG_LEVEL:-info}" + +# Performance tuning configuration +# GOMAXPROCS limits Go's CPU usage - set to leave cores for Envoy (default: 2) +# ROUTER_CONCURRENCY sets Envoy's worker thread count (default: auto-detect, 0 means use all cores) +# APIP_GW_POLICY_ENGINE_METRICS_ENABLED controls metrics collection (default: true, set false for high-load) +export GOMAXPROCS="${GOMAXPROCS:-2}" +export ROUTER_CONCURRENCY="${ROUTER_CONCURRENCY:-0}" +export APIP_GW_POLICY_ENGINE_METRICS_ENABLED="${APIP_GW_POLICY_ENGINE_METRICS_ENABLED:-true}" + +# Derive Router (Envoy) xDS config — used by envsubst on config-override.yaml +export XDS_SERVER_HOST="${GATEWAY_CONTROLLER_HOST}" +export XDS_SERVER_PORT="${ROUTER_XDS_PORT}" + +# Policy Engine xDS address +PE_XDS_SERVER="${GATEWAY_CONTROLLER_HOST}:${POLICY_ENGINE_XDS_PORT}" + +POLICY_ENGINE_SOCKET="/var/run/api-platform/policy-engine.sock" + +log "Starting Gateway Runtime (DEBUG mode — dlv on port 2346)" +log " Gateway Controller: ${GATEWAY_CONTROLLER_HOST}" +log " Router xDS: ${GATEWAY_CONTROLLER_HOST}:${ROUTER_XDS_PORT}" +log " Policy Engine xDS: ${PE_XDS_SERVER}" +log " Log Level: ${LOG_LEVEL}" +log " Policy Engine Socket: ${POLICY_ENGINE_SOCKET}" +log " GOMAXPROCS: ${GOMAXPROCS}" +log " Router Concurrency: ${ROUTER_CONCURRENCY}" +log " Policy Engine Metrics: ${APIP_GW_POLICY_ENGINE_METRICS_ENABLED}" +[[ ${#ROUTER_ARGS[@]} -gt 0 ]] && log " Router extra args: ${ROUTER_ARGS[*]}" +[[ ${#PE_ARGS[@]} -gt 0 ]] && log " Policy Engine extra args: ${PE_ARGS[*]}" + +# Cleanup stale socket from previous runs +rm -f "${POLICY_ENGINE_SOCKET}" + +# Generate Envoy config override by substituting environment variables +CONFIG_OVERRIDE=$(envsubst < /etc/envoy/config-override.yaml) + +# Track child PIDs +PE_PID="" +ENVOY_PID="" + +# Shutdown handler - gracefully terminate both processes +shutdown() { + log "Received shutdown signal, terminating processes..." + + # Send SIGTERM to both processes + if [ -n "$PE_PID" ] && kill -0 "$PE_PID" 2>/dev/null; then + log "Stopping Policy Engine / dlv (PID $PE_PID)..." + kill -TERM "$PE_PID" 2>/dev/null || true + fi + + if [ -n "$ENVOY_PID" ] && kill -0 "$ENVOY_PID" 2>/dev/null; then + log "Stopping Envoy (PID $ENVOY_PID)..." + kill -TERM "$ENVOY_PID" 2>/dev/null || true + fi + + # Wait for processes to exit + wait + + # Cleanup socket + rm -f "${POLICY_ENGINE_SOCKET}" + + log "Shutdown complete" + exit 0 +} + +# Set up signal handlers +trap shutdown SIGTERM SIGINT SIGQUIT + +# Start Policy Engine under dlv for remote debugging (port 2346) +log "Starting Policy Engine under dlv (listening on :2346, headless)..." +/usr/local/bin/dlv exec /app/policy-engine \ + --listen=:2346 --headless=true \ + --api-version=2 --accept-multiclient -- \ + -xds-server "${PE_XDS_SERVER}" "${PE_ARGS[@]}" \ + > >(while IFS= read -r line; do echo "[pol] $line"; done) \ + 2> >(while IFS= read -r line; do echo "[pol] $line" >&2; done) & +PE_PID=$! +log "Policy Engine (dlv) started (PID $PE_PID)" + +# Wait for Policy Engine to create the socket (with timeout) +# Increased to 30s to account for dlv startup overhead before policy-engine initialises +SOCKET_WAIT_TIMEOUT=30 +SOCKET_WAIT_COUNT=0 +while [ ! -S "${POLICY_ENGINE_SOCKET}" ]; do + if [ $SOCKET_WAIT_COUNT -ge $SOCKET_WAIT_TIMEOUT ]; then + log "ERROR: Policy Engine socket not created within ${SOCKET_WAIT_TIMEOUT}s" + log "Checking if Policy Engine is still running..." + if ! kill -0 "$PE_PID" 2>/dev/null; then + log "ERROR: Policy Engine process has exited" + fi + exit 1 + fi + + # Check if Policy Engine is still running + if ! kill -0 "$PE_PID" 2>/dev/null; then + log "ERROR: Policy Engine exited before creating socket" + exit 1 + fi + + sleep 1 + SOCKET_WAIT_COUNT=$((SOCKET_WAIT_COUNT + 1)) +done +log "Policy Engine socket ready: ${POLICY_ENGINE_SOCKET}" + +# Start Envoy (Router) with [rtr] log prefix +log "Starting Envoy..." +/usr/local/bin/envoy \ + -c /etc/envoy/envoy.yaml \ + --config-yaml "${CONFIG_OVERRIDE}" \ + --log-level "${LOG_LEVEL}" \ + --concurrency "${ROUTER_CONCURRENCY}" \ + "${ROUTER_ARGS[@]}" \ + > >(while IFS= read -r line; do echo "[rtr] $line"; done) \ + 2> >(while IFS= read -r line; do echo "[rtr] $line" >&2; done) & +ENVOY_PID=$! +log "Envoy started (PID $ENVOY_PID)" + +log "Gateway Runtime running (DEBUG) - Policy Engine/dlv (PID $PE_PID), Envoy (PID $ENVOY_PID)" + +# Monitor both processes - exit if either dies +wait -n "$PE_PID" "$ENVOY_PID" +EXIT_CODE=$? + +# Determine which process exited and clean up the other +if ! kill -0 "$PE_PID" 2>/dev/null; then + log "Policy Engine exited with code $EXIT_CODE" + if kill -0 "$ENVOY_PID" 2>/dev/null; then + log "Terminating Envoy due to Policy Engine exit..." + kill -TERM "$ENVOY_PID" 2>/dev/null || true + wait "$ENVOY_PID" 2>/dev/null || true + fi +else + log "Envoy exited with code $EXIT_CODE" + if kill -0 "$PE_PID" 2>/dev/null; then + log "Terminating Policy Engine due to Envoy exit..." + kill -TERM "$PE_PID" 2>/dev/null || true + wait "$PE_PID" 2>/dev/null || true + fi +fi + +rm -f "${POLICY_ENGINE_SOCKET}" +exit $EXIT_CODE diff --git a/gateway/gateway-runtime/docker-entrypoint.sh b/gateway/gateway-runtime/docker-entrypoint.sh index 795a573c9..b6791ecc0 100644 --- a/gateway/gateway-runtime/docker-entrypoint.sh +++ b/gateway/gateway-runtime/docker-entrypoint.sh @@ -20,7 +20,9 @@ # Gateway Runtime Entrypoint Script # Manages both Policy Engine and Envoy processes -# + +# NOTE: docker-entrypoint-debug.sh is a near-duplicate of this file — keep in sync. + # Process-specific args can be passed using prefixed flags: # --rtr. → forwarded to Router (Envoy) # --pol. → forwarded to Policy Engine diff --git a/gateway/it/Makefile b/gateway/it/Makefile index a180937fb..48f921411 100644 --- a/gateway/it/Makefile +++ b/gateway/it/Makefile @@ -27,7 +27,7 @@ COMPOSE_FILE ?= docker-compose.test.yaml # Refresh :test tags from :VERSION images when available. # If :VERSION is unavailable but :test already exists, keep using :test. # Tries coverage image first (from make build-coverage), then falls back to -# non-coverage image (from make build-local) for local development convenience. +# non-coverage image (from make build) for local development convenience. ensure-test-tags: @for img in $(COVERAGE_IMAGES); do \ base=$${img%-coverage}; \ @@ -40,7 +40,7 @@ ensure-test-tags: elif docker image inspect $(DOCKER_REGISTRY)/$$img:test >/dev/null 2>&1; then \ echo "Using existing $(DOCKER_REGISTRY)/$$img:test (no :$(VERSION) image found)"; \ else \ - echo "Error: No image found for $$img (:$(VERSION) or :test). Run 'make build-coverage' or 'make build-local' in gateway/ first." && exit 1; \ + echo "Error: No image found for $$img (:$(VERSION) or :test). Run 'make build-coverage' or 'make build' in gateway/ first." && exit 1; \ fi; \ done diff --git a/gateway/it/docker-compose.test.postgres.yaml b/gateway/it/docker-compose.test.postgres.yaml index 8e2a96b93..8729b3ed8 100644 --- a/gateway/it/docker-compose.test.postgres.yaml +++ b/gateway/it/docker-compose.test.postgres.yaml @@ -20,6 +20,8 @@ # Uses the gateway-runtime container (Router + Policy Engine combined) # Build coverage images with: make build-gateway-runtime-coverage +# NOTE: gateway-controller and gateway-runtime are duplicated in docker-compose.test.yaml — keep in sync. + services: postgres: container_name: it-postgres @@ -86,11 +88,13 @@ services: cpus: 1 command: ["--pol.config", "/etc/policy-engine/config.toml"] ports: - - "8080:8080" # HTTP traffic (Envoy) - - "8443:8443" # HTTPS traffic (Envoy) + # Router (Envoy) + - "8080:8080" # HTTP ingress + - "8443:8443" # HTTPS ingress - "9901:9901" # Envoy admin - - "9002:9002" # Policy Engine admin - - "9003:9003" # Policy Engine metrics + # Policy Engine + - "9002:9002" # Admin API + - "9003:9003" # Metrics environment: - GATEWAY_CONTROLLER_HOST=it-gateway-controller - LOG_LEVEL=info diff --git a/gateway/it/docker-compose.test.yaml b/gateway/it/docker-compose.test.yaml index 035cf6a77..4d77108bd 100644 --- a/gateway/it/docker-compose.test.yaml +++ b/gateway/it/docker-compose.test.yaml @@ -20,6 +20,8 @@ # Uses the gateway-runtime container (Router + Policy Engine combined) # Build coverage images with: make build-gateway-runtime-coverage +# NOTE: gateway-controller and gateway-runtime are duplicated in docker-compose.test.postgres.yaml — keep in sync. + services: gateway-controller: container_name: it-gateway-controller @@ -62,11 +64,13 @@ services: cpus: 1 command: ["--pol.config", "/etc/policy-engine/config.toml"] ports: - - "8080:8080" # HTTP traffic (Envoy) - - "8443:8443" # HTTPS traffic (Envoy) + # Router (Envoy) + - "8080:8080" # HTTP ingress + - "8443:8443" # HTTPS ingress - "9901:9901" # Envoy admin - - "9002:9002" # Policy Engine admin - - "9003:9003" # Policy Engine metrics + # Policy Engine + - "9002:9002" # Admin API + - "9003:9003" # Metrics environment: - GATEWAY_CONTROLLER_HOST=it-gateway-controller - LOG_LEVEL=info