diff --git a/.gitignore b/.gitignore index 1fae99915c..ae9bcb172f 100644 --- a/.gitignore +++ b/.gitignore @@ -73,6 +73,8 @@ hack/bicep-types-radius/generated/**/*.md # Debug files debug_files/* +drad +*.lock # Demo app demo/* diff --git a/.vscode/get-pid.sh b/.vscode/get-pid.sh new file mode 100644 index 0000000000..ae00662f29 --- /dev/null +++ b/.vscode/get-pid.sh @@ -0,0 +1,16 @@ +#!/bin/bash +# Simple script to read PID from file +# Usage: get-pid.sh + +if [ -z "$1" ]; then + echo "0" + exit 1 +fi + +PID_FILE="debug_files/logs/$1.pid" + +if [ -f "$PID_FILE" ]; then + cat "$PID_FILE" +else + echo "0" +fi diff --git a/.vscode/launch.json b/.vscode/launch.json index 987f916a8a..c4a9122387 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -1,113 +1,37 @@ { - // Use IntelliSense to learn about possible attributes. - // Hover to view descriptions of existing attributes. - // For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387 - "version": "0.2.0", - "configurations": [ - { - "name": "Debug rad CLI", - "type": "go", - "request": "launch", - "mode": "auto", - "preLaunchTask": "Build Radius (all)", - "program": "${workspaceFolder}/cmd/rad/main.go", - "cwd": "${workspaceFolder}", - "args": [] - }, - { - "name": "Debug rad CLI (prompt for args)", - "type": "go", - "request": "launch", - "mode": "debug", - "preLaunchTask": "Build Radius (all)", - "program": "${workspaceFolder}/cmd/rad", - "args": "${input:cliArgs}", - "console": "integratedTerminal" - }, - { - "name": "Launch Applications RP", - "type": "go", - "request": "launch", - "mode": "auto", - "preLaunchTask": "Build Radius (all)", - "program": "${workspaceFolder}/cmd/applications-rp/main.go" - }, - { - "name": "Launch Dynamic RP", - "type": "go", - "request": "launch", - "mode": "auto", - "preLaunchTask": "Build Radius (all)", - "program": "${workspaceFolder}/cmd/dynamic-rp/main.go" - }, - { - "name": "Launch UCP", - "type": "go", - "request": "launch", - "mode": "auto", - "preLaunchTask": "Build Radius (all)", - "program": "${workspaceFolder}/cmd/ucpd/main.go" - }, - { - "name": "Launch Controller", - "type": "go", - "request": "launch", - "mode": "auto", - "preLaunchTask": "Build Radius (all)", - "program": "${workspaceFolder}/cmd/controller/main.go", - "args": ["--cert-dir", ""] - }, - { - "name": "Launch Deployment Engine", - "type": "coreclr", - "request": "launch", - "preLaunchTask": "Build Deployment Engine", - "program": "${workspaceFolder}/../deployment-engine/src/DeploymentEngine/bin/Debug/net8.0/arm-de.dll", - "args": [], - "cwd": "${workspaceFolder}/../deployment-engine/src/DeploymentEngine", - "stopAtEntry": false, - "env": { - "ASPNETCORE_URLS": "http://localhost:5017", - "ASPNETCORE_ENVIRONMENT": "Development", - "KUBERNETESBICEPEXTENSIBILITYURL": "http://localhost:5017/api", - "RADIUSBACKENDURI": "http://localhost:9000" - } - }, - { - "name": "Debug Bicep generator integration tests", - "type": "node", - "request": "launch", - "runtimeArgs": [ - "--inspect-brk", - "${workspaceRoot}/hack/bicep-types-radius/src/autorest.bicep/node_modules/.bin/jest", - "--runInBand", - "--no-cache" - ], - "cwd": "${workspaceFolder}/hack/bicep-types-radius/src/autorest.bicep/src", - "console": "integratedTerminal", - "internalConsoleOptions": "neverOpen", - "sourceMaps": true - } - ], - "compounds": [ - { - "name": "Launch Control Plane (all)", - "configurations": [ - "Launch UCP", - "Launch Applications RP", - "Launch Dynamic RP", - "Launch Controller", - "Launch Deployment Engine" - ], - "stopAll": true - } - ], - "inputs": [ - { - "id": "cliArgs", - "type": "promptString", - "description": "Args for launching Radius cli. Use --cwd to set the working directory.", - "default": "init --full" - } - ] + "version": "0.2.0", + "configurations": [ + { + "name": "Start Control Plane", + "type": "node-terminal", + "request": "launch", + "command": "make debug-start && exit", + "cwd": "${workspaceFolder}" + }, + { + "name": "Stop Control Plane", + "type": "node-terminal", + "request": "launch", + "command": "make debug-stop && exit", + "cwd": "${workspaceFolder}" + }, + { + "name": "Control Plane Status", + "type": "node-terminal", + "request": "launch", + "command": "make debug-status && exit", + "cwd": "${workspaceFolder}" + }, + { "name": "Attach UCP (dlv 40001)", "type": "go", "request": "attach", "mode": "remote", "port": 40001, "host": "127.0.0.1" }, + { "name": "Attach Controller (dlv 40002)", "type": "go", "request": "attach", "mode": "remote", "port": 40002, "host": "127.0.0.1" }, + { "name": "Attach Applications RP (dlv 40003)", "type": "go", "request": "attach", "mode": "remote", "port": 40003, "host": "127.0.0.1" }, + { "name": "Attach Dynamic RP (dlv 40004)", "type": "go", "request": "attach", "mode": "remote", "port": 40004, "host": "127.0.0.1" }, + { "name": "Debug rad CLI (prompt for args)", "type": "go", "request": "launch", "mode": "auto", "program": "${workspaceFolder}/cmd/rad/main.go", "args": "${input:radArgs}", "env": { "RADIUS_ENV": "self-hosted" } } + ], + "compounds": [ + { "name": "Attach Radius (all)", "configurations": ["Attach UCP (dlv 40001)", "Attach Controller (dlv 40002)", "Attach Applications RP (dlv 40003)", "Attach Dynamic RP (dlv 40004)"], "stopAll": true } + ], + "inputs": [ + { "id": "radArgs", "type": "promptString", "description": "Arguments for the rad command (e.g. 'env list')", "default": "version" } + ] } diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..0bac69e8fe --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,22 @@ +{ + "go.gopath": "${env:GOPATH}", + "go.useLanguageServer": true, + "go.delveConfig": { + "apiVersion": 2, + "showGlobalVariables": true + }, + "files.associations": { + "*.yaml": "yaml", + "*.yml": "yaml" + }, + "terminal.integrated.env.linux": { + "RADIUS_DEV_ROOT": "${workspaceFolder}/debug_files" + }, + "terminal.integrated.env.osx": { + "RADIUS_DEV_ROOT": "${workspaceFolder}/debug_files" + }, + "terminal.integrated.env.windows": { + "RADIUS_DEV_ROOT": "${workspaceFolder}/debug_files" + }, + "makefile.configureOnOpen": false +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 69148115dd..de1bcce3b3 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,66 +1,69 @@ { - "version": "2.0.0", - "tasks": [ - { - "label": "Check for Deployment Engine", - "detail": "Checks if the Deployment Engine is cloned as a sibling to the Radius repo", - "command": "bash", - "args": [ - "-c", - "(test -d ../deployment-engine/src) || { echo >&1 \"The radius-project/deployment-engine is not cloned as a sibling to the Radius repo. Please clone the radius-project/deployment-engine repo next to the Radius repo.\"; exit 1; }" - ], - "type": "shell", - "options": { - "cwd": "${workspaceFolder}" - }, - "group": "none", - "presentation": { - "reveal": "silent", - "echo": false, - "clear": true - }, - "problemMatcher": [] - }, - { - "label": "Build Deployment Engine", - "detail": "Builds the Deployment Engine. This requires the radius-project/deployment engine repo to be cloned as a sibling to the radius-project/radius repo", - "dependsOn": ["Check for Deployment Engine"], - "command": "dotnet build", - "type": "shell", - "options": { - "cwd": "${workspaceFolder}/../deployment-engine/src/DeploymentEngine" - }, - "group": "build", - "presentation": { - "echo": true, - "reveal": "silent", - "panel": "shared", - "showReuseMessage": false, - "clear": true - }, - "problemMatcher": "$msCompile" - }, - { - "label": "Build Radius (all)", - "detail": "Builds the Radius repository using make build", - "command": "make", - "type": "shell", - "args": ["build"], - "options": { - "cwd": "${workspaceFolder}" - }, - "group": { - "kind": "build", - "isDefault": true - }, - "problemMatcher": "$gcc", - "presentation": { - "echo": true, - "reveal": "silent", - "panel": "shared", - "showReuseMessage": false, - "clear": true - } - } - ] + "version": "2.0.0", + "tasks": [ + { + "label": "Debug: Start All Components", + "type": "shell", + "command": "make", + "args": ["debug-start"], + "group": "build", + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared", + "showReuseMessage": true, + "clear": false + }, + "problemMatcher": [] + }, + { + "label": "Debug: Stop All Components", + "type": "shell", + "command": "make", + "args": ["debug-stop"], + "group": "build", + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared", + "showReuseMessage": true, + "clear": false + }, + "problemMatcher": [] + }, + { + "label": "Debug: Component Status", + "type": "shell", + "command": "make", + "args": ["debug-status"], + "group": "test", + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared", + "showReuseMessage": true, + "clear": false + }, + "problemMatcher": [] + }, + { + "label": "Debug: View Logs", + "type": "shell", + "command": "make", + "args": ["debug-logs"], + "group": "test", + "presentation": { + "echo": true, + "reveal": "always", + "focus": false, + "panel": "shared", + "showReuseMessage": true, + "clear": false + }, + "problemMatcher": [] + } + ] } diff --git a/build/configs/applications-rp.yaml b/build/configs/applications-rp.yaml new file mode 100644 index 0000000000..279063b71c --- /dev/null +++ b/build/configs/applications-rp.yaml @@ -0,0 +1,47 @@ +environment: + name: "dev" + roleLocation: "global" +databaseProvider: + provider: "postgresql" + postgresql: + url: "postgresql://applications_rp:radius_pass@localhost:5432/applications_rp?sslmode=disable" +queueProvider: + provider: "inmemory" + name: radius +secretProvider: + provider: "kubernetes" +metricsProvider: + enabled: false + serviceName: applications-rp + prometheus: + path: "/metrics" + port: 9092 +profilerProvider: + enabled: false + port: 6060 +featureFlags: + - "PLACEHOLDER" +server: + host: "0.0.0.0" + port: 8080 + enableArmAuth: false +workerServer: + maxOperationConcurrency: 10 + maxOperationRetryCount: 2 +ucp: + kind: direct + direct: + endpoint: "http://localhost:9000/apis/api.ucp.dev/v1alpha3" +logging: + level: "info" + json: false +tracerProvider: + enabled: false + serviceName: applications-rp + zipkin: + url: "http://localhost:9411/api/v2/spans" +bicep: + deleteRetryCount: 20 + deleteRetryDelaySeconds: 60 +terraform: + path: "debug_files/terraform" diff --git a/build/configs/controller.yaml b/build/configs/controller.yaml new file mode 100644 index 0000000000..e31a44a839 --- /dev/null +++ b/build/configs/controller.yaml @@ -0,0 +1,29 @@ +environment: + name: "dev" + roleLocation: "global" +profilerProvider: + enabled: false + port: 6063 +metricsProvider: + enabled: false + serviceName: "controller" + prometheus: + path: "/metrics" + port: 9093 +tracerProvider: + enabled: false + serviceName: "controller" + zipkin: + url: "http://localhost:9411/api/v2/spans" +server: + host: "0.0.0.0" + port: 8083 +workerServer: + port: 7073 +ucp: + kind: direct + direct: + endpoint: "http://localhost:9000/apis/api.ucp.dev/v1alpha3" +logging: + level: "info" + json: false diff --git a/build/configs/deployment-engine.yaml b/build/configs/deployment-engine.yaml new file mode 100644 index 0000000000..824b25a386 --- /dev/null +++ b/build/configs/deployment-engine.yaml @@ -0,0 +1,134 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: deployment-engine-config + namespace: default + labels: + app: deployment-engine + component: deployment-engine +data: + appsettings.Production.json: |- + { + "Logging": { + "LogLevel": { + "Default": "Debug", + "Microsoft.AspNetCore": "Warning", + "Microsoft.AspNetCore.HttpLogging.HttpLoggingMiddleware": "Warning", + "Microsoft.Extensions.Http": "Warning" + }, + "Console": { + "FormatterName": "RadiusJsonFormatter" + } + }, + "Prometheus": { + "ScrapeEndpointPath": "/metrics" + } + } +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: deployment-engine + namespace: default + labels: + app: deployment-engine + component: deployment-engine +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: deployment-engine + labels: + app: deployment-engine + component: deployment-engine +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: cluster-admin +subjects: + - kind: ServiceAccount + name: deployment-engine + namespace: default +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: deployment-engine + namespace: default + labels: + app: deployment-engine + component: deployment-engine +spec: + replicas: 1 + selector: + matchLabels: + app: deployment-engine + template: + metadata: + labels: + app: deployment-engine + component: deployment-engine + spec: + serviceAccountName: deployment-engine + volumes: + - name: appsettings-vol + configMap: + name: deployment-engine-config + containers: + - name: deployment-engine + image: ghcr.io/radius-project/deployment-engine:latest + args: + - --local + volumeMounts: + - name: appsettings-vol + mountPath: /app/appsettings.Production.json + subPath: appsettings.Production.json + ports: + - containerPort: 5445 + name: http + env: + - name: ASPNETCORE_ENVIRONMENT + value: "Production" + - name: ASPNETCORE_URLS + value: "http://+:5445" + - name: RADIUSBACKENDURL + value: "http://host.k3d.internal:9000/apis/api.ucp.dev/v1alpha3" + - name: SKIP_ARM + value: "true" + - name: ARM_AUTH_METHOD + value: "UCPCredential" + - name: kubernetes + value: "true" + # Enable all providers for debugging scenarios + - name: AZURE_ENABLED + value: "true" + - name: AWS_ENABLED + value: "true" + - name: KUBERNETES_ENABLED + value: "true" + resources: + requests: + memory: "128Mi" + cpu: "100m" + limits: + memory: "512Mi" + cpu: "500m" + securityContext: + allowPrivilegeEscalation: false +--- +apiVersion: v1 +kind: Service +metadata: + name: deployment-engine + namespace: default + labels: + app: deployment-engine + component: deployment-engine +spec: + selector: + app: deployment-engine + ports: + - port: 5445 + targetPort: 5445 + name: http + type: ClusterIP diff --git a/build/configs/dynamic-rp.yaml b/build/configs/dynamic-rp.yaml new file mode 100644 index 0000000000..30072c2cf6 --- /dev/null +++ b/build/configs/dynamic-rp.yaml @@ -0,0 +1,46 @@ +environment: + name: "dev" + roleLocation: "global" +databaseProvider: + provider: "postgresql" + postgresql: + url: "postgresql://ucp:radius_pass@localhost:5432/ucp?sslmode=disable" +queueProvider: + provider: "inmemory" + name: dynamic-rp +secretProvider: + provider: "kubernetes" +profilerProvider: + enabled: false + port: 6062 +metricsProvider: + enabled: false + serviceName: "dynamic-rp" + prometheus: + path: "/metrics" + port: 9092 +tracerProvider: + enabled: false + serviceName: "dynamic-rp" + zipkin: + url: "http://localhost:9411/api/v2/spans" +kubernetes: + kind: default +server: + host: "0.0.0.0" + port: 8082 +workerServer: + maxOperationConcurrency: 10 + maxOperationRetryCount: 2 +ucp: + kind: direct + direct: + endpoint: "http://localhost:9000/apis/api.ucp.dev/v1alpha3" +logging: + level: "info" + json: false +bicep: + deleteRetryCount: 20 + deleteRetryDelaySeconds: 60 +terraform: + path: "debug_files/terraform" diff --git a/build/configs/kubeconfig-template b/build/configs/kubeconfig-template new file mode 100644 index 0000000000..100f5a942a --- /dev/null +++ b/build/configs/kubeconfig-template @@ -0,0 +1,18 @@ +apiVersion: v1 +kind: Config +clusters: +- cluster: + server: https://host.docker.internal:6443 + insecure-skip-tls-verify: true + name: k3d-radius-debug +contexts: +- context: + cluster: k3d-radius-debug + user: admin@k3d-radius-debug + name: k3d-radius-debug +current-context: k3d-radius-debug +users: +- name: admin@k3d-radius-debug + user: + client-certificate-data: "" + client-key-data: "" diff --git a/build/configs/rad-debug-config.yaml b/build/configs/rad-debug-config.yaml new file mode 100644 index 0000000000..32753c7b28 --- /dev/null +++ b/build/configs/rad-debug-config.yaml @@ -0,0 +1,11 @@ +workspaces: + default: debug + items: + debug: + connection: + context: 'k3d-radius-debug' + kind: kubernetes + overrides: + ucp: http://localhost:9000 + environment: /planes/radius/local/resourceGroups/default/providers/Applications.Core/environments/default + scope: /planes/radius/local/resourceGroups/default diff --git a/build/configs/terraformrc b/build/configs/terraformrc new file mode 100644 index 0000000000..6111b70a7b --- /dev/null +++ b/build/configs/terraformrc @@ -0,0 +1,12 @@ +disable_checkpoint = true +plugin_cache_dir = "./terraform-cache" + +provider_installation { + filesystem_mirror { + path = "./terraform-cache/providers" + include = ["registry.terraform.io/*/*"] + } + direct { + exclude = ["registry.terraform.io/*/*"] + } +} diff --git a/build/configs/ucp.yaml b/build/configs/ucp.yaml new file mode 100644 index 0000000000..bdaa41b812 --- /dev/null +++ b/build/configs/ucp.yaml @@ -0,0 +1,70 @@ +environment: + name: "dev" + roleLocation: "global" + +server: + port: 9000 + pathBase: /apis/api.ucp.dev/v1alpha3 + +databaseProvider: + provider: "postgresql" + postgresql: + url: "postgresql://ucp:radius_pass@localhost:5432/ucp?sslmode=disable" + +secretProvider: + provider: "kubernetes" + +queueProvider: + provider: "inmemory" + name: 'ucp' + +profilerProvider: + enabled: false + port: 6061 + +initialization: + planes: + - id: "/planes/aws/aws" + properties: + kind: "AWS" + - id: "/planes/radius/local" + properties: + resourceProviders: + Applications.Core: "http://localhost:8080" + Applications.Messaging: "http://localhost:8080" + Applications.Dapr: "http://localhost:8080" + Applications.Datastores: "http://localhost:8080" + Microsoft.Resources: "http://localhost:5017" + kind: "UCPNative" + - id: "/planes/azure/azure" + properties: + kind: "Azure" + manifestDirectory: "deploy/manifest/built-in-providers/dev" + +identity: + authMethod: default + +ucp: + kind: direct + direct: + endpoint: "http://localhost:9000/apis/api.ucp.dev/v1alpha3" + +routing: + defaultDownstreamEndpoint: "http://localhost:8082" + +metricsProvider: + enabled: false + serviceName: "ucp" + prometheus: + path: "/metrics" + port: 9091 + +logging: + level: "debug" + json: true + +tracerProvider: + enabled: false + serviceName: "ucp" + zipkin: + url: "http://localhost:9411/api/v2/spans" diff --git a/build/debug.mk b/build/debug.mk index 863904697f..dcbb026ed0 100644 --- a/build/debug.mk +++ b/build/debug.mk @@ -21,4 +21,358 @@ dump: ## Outputs the values of all variables in the makefile. $(foreach v, \ $(shell echo "$(filter-out .VARIABLES,$(.VARIABLES))" | tr ' ' '\n' | sort), \ $(info $(shell printf "%-20s" "$(v)")= $(value $(v))) \ - ) \ No newline at end of file + ) + +##@ Debug Development Automation +# This section provides automation for running Radius components as OS processes for advanced debugging + +# Debug configuration +DEBUG_CONFIG_FILE ?= build/debug-config.yaml +DEBUG_DEV_ROOT ?= $(PWD)/debug_files + +# PostgreSQL connection - Try Docker first (postgres user), fallback to local user +POSTGRES_ADMIN_CONNECTION ?= postgresql://postgres:radius_pass@localhost:5432/postgres +POSTGRES_FALLBACK_CONNECTION ?= postgresql://$(shell whoami)@localhost:5432/postgres + +.PHONY: debug-setup debug-start debug-stop debug-status debug-help debug-build-all debug-build-ucpd debug-build-applications-rp debug-build-controller debug-build-dynamic-rp debug-build-rad debug-deployment-engine-pull debug-deployment-engine-start debug-deployment-engine-deploy debug-deployment-engine-port-forward debug-deployment-engine-stop debug-deployment-engine-status debug-deployment-engine-logs debug-register-recipes debug-env-init debug-check-prereqs + +debug-help: ## Show debug automation help + @echo "Debug Development Automation Commands:" + @echo "" + @echo "Setup Commands:" + @echo " debug-check-prereqs - Check if all required tools are installed" + @echo " debug-setup - Complete one-time setup for OS process debugging" + @echo " debug-stop - Stop all components and destroy k3d cluster" + @echo "" + @echo "Runtime Commands:" + @echo " debug-start - Start all Radius components as OS processes" + @echo " debug-stop - Stop all components, destroy cluster, and clean up completely" + @echo " debug-status - Show status of all components" + @echo " debug-logs - Tail all component logs" + @echo "" + @echo "Environment Commands:" + @echo " debug-env-init - Create resource group, environment, and register recipes (first time only)" + @echo " debug-register-recipes - Register default recipes for common resource types" + @echo "" + @echo "" + @echo "Deployment Engine Commands:" + @echo " debug-deployment-engine-pull - Pull latest deployment engine image from ghcr.io" + @echo " debug-deployment-engine-start - Start deployment engine in k3d cluster" + @echo " debug-deployment-engine-stop - Stop deployment engine" + @echo " debug-deployment-engine-status - Check deployment engine status" + @echo " debug-deployment-engine-logs - View deployment engine logs" + @echo "" + @echo "Development Commands:" + @echo " debug-build - Build all components with debug symbols (incremental)" + @echo " (alias of debug-build-all)" + @echo " debug-build-ucpd - Build only UCP daemon (only compiles changed code)" + @echo " debug-build-applications-rp - Build only Applications RP (only compiles changed code)" + @echo " debug-build-controller - Build only Controller (only compiles changed code)" + @echo " debug-build-dynamic-rp - Build only Dynamic RP (only compiles changed code)" + @echo " debug-build-rad - Build only rad CLI (only compiles changed code) + symlink" + @echo " debug-logs - Tail all component logs" + @echo "" + @echo "πŸ’‘ All builds are incremental - only changed code is recompiled" + @echo "πŸ’‘ Individual component builds are fastest when working on specific components" + @echo "πŸ’‘ drad CLI is created for debug configuration (preserves 'rad' for your installed version)" + @echo "" + @echo "Configuration:" + @echo " DEBUG_CONFIG_FILE - Debug configuration file (default: build/debug-config.yaml)" + @echo " DEBUG_DEV_ROOT - Debug development root (default: $(PWD)/debug_files)" + @echo "" + +debug-setup: debug-check-prereqs ## Complete one-time setup for OS process debugging + @echo "Setting up Radius debug environment..." + @mkdir -p $(DEBUG_DEV_ROOT)/{logs,bin,terraform-cache} + @echo "Making scripts executable..." + @chmod +x build/scripts/*.sh 2>/dev/null || true + @chmod +x build/scripts/rad-wrapper 2>/dev/null || true + @chmod +x drad 2>/dev/null || true + @echo "βœ… Debug environment setup complete at $(DEBUG_DEV_ROOT)" + @echo "πŸ’‘ Use './drad' command from project root for debug environment" + @echo "πŸ“– See docs/contributing/contributing-code/contributing-code-debugging/radius-os-processes-debugging.md for usage instructions" + +debug-check-prereqs: ## Check if all required tools are installed for debugging + @echo "πŸ” Checking debug prerequisites..." + @MISSING_TOOLS=""; \ + if ! command -v go >/dev/null 2>&1; then \ + MISSING_TOOLS="$$MISSING_TOOLS go"; \ + fi; \ + if ! command -v dlv >/dev/null 2>&1; then \ + MISSING_TOOLS="$$MISSING_TOOLS dlv"; \ + fi; \ + if ! command -v k3d >/dev/null 2>&1; then \ + MISSING_TOOLS="$$MISSING_TOOLS k3d"; \ + fi; \ + if ! command -v kubectl >/dev/null 2>&1; then \ + MISSING_TOOLS="$$MISSING_TOOLS kubectl"; \ + fi; \ + if ! command -v terraform >/dev/null 2>&1; then \ + MISSING_TOOLS="$$MISSING_TOOLS terraform"; \ + fi; \ + if [ -n "$$MISSING_TOOLS" ]; then \ + echo "❌ Missing required tools:$$MISSING_TOOLS"; \ + echo ""; \ + echo "Installation instructions:"; \ + echo " go: https://golang.org/doc/install"; \ + echo " dlv: go install github.com/go-delve/delve/cmd/dlv@latest"; \ + echo " k3d: https://k3d.io/v5.6.0/#installation"; \ + echo " kubectl: https://kubernetes.io/docs/tasks/tools/"; \ + echo " terraform: https://learn.hashicorp.com/tutorials/terraform/install-cli"; \ + exit 1; \ + fi; \ + if ! command -v psql >/dev/null 2>&1; then \ + echo "❌ psql not available - PostgreSQL client is required"; \ + exit 1; \ + fi; \ + echo "πŸ” Checking PostgreSQL connectivity..."; \ + if psql "$(POSTGRES_ADMIN_CONNECTION)" -c "SELECT 1;" >/dev/null 2>&1; then \ + echo "βœ… PostgreSQL accessible via Docker (postgres user)"; \ + elif psql "$(POSTGRES_FALLBACK_CONNECTION)" -c "SELECT 1;" >/dev/null 2>&1; then \ + echo "βœ… PostgreSQL accessible via local user ($(shell whoami))"; \ + else \ + echo "❌ Cannot connect to PostgreSQL"; \ + echo " Please ensure:"; \ + echo " 1. PostgreSQL is running on localhost:5432"; \ + echo " 2. Either Docker PostgreSQL (postgres/radius_pass) or local user access"; \ + echo " 3. Quick start: docker run --name radius-postgres -e POSTGRES_PASSWORD=radius_pass -p 5432:5432 -d postgres:15"; \ + echo ""; \ + echo " macOS (homebrew): brew services start postgresql"; \ + echo " macOS manual: pg_ctl -D /opt/homebrew/var/postgres start"; \ + echo " Linux (systemd): sudo systemctl start postgresql"; \ + echo ""; \ + echo " Quick one-off (Docker) alternative:"; \ + echo " docker run --name radius-postgres -e POSTGRES_PASSWORD=radius_pass -p 5432:5432 -d postgres:15"; \ + echo ""; \ + echo " After starting, re-run: make debug-check-prereqs"; \ + exit 1; \ + fi; \ + echo "βœ… PostgreSQL is accessible"; \ + if ! command -v docker >/dev/null 2>&1; then \ + echo "⚠️ Docker not available - deployment engine will not be available"; \ + elif ! docker info >/dev/null 2>&1; then \ + echo "⚠️ Docker daemon not running - deployment engine will not be available"; \ + fi; \ + echo "βœ… All required tools are available" + +## debug-build is maintained as an alias for debug-build-all to avoid confusion about which +## target to use. The legacy behavior depended on the top-level 'build' target with DEBUG flags; +## now we always explicitly build all debug binaries via the component-specific targets. +debug-build: debug-build-all ## Alias: build all components with debug symbols (see debug-build-all) + @echo "Building Radius components with debug symbols..." + @mkdir -p $(DEBUG_DEV_ROOT)/bin + +debug-build-all: debug-build-ucpd debug-build-applications-rp debug-build-controller debug-build-dynamic-rp debug-build-rad ## Build all debug components + @echo "βœ… All debug binaries built in $(DEBUG_DEV_ROOT)/bin/" + +debug-build-ucpd: ## Build UCP daemon with debug symbols + @echo "Building ucpd with debug symbols..." + @mkdir -p $(DEBUG_DEV_ROOT)/bin + @go build -gcflags="all=-N -l" -o $(DEBUG_DEV_ROOT)/bin/ucpd ./cmd/ucpd + @echo "βœ… ucpd built" + +debug-build-applications-rp: ## Build Applications RP with debug symbols + @echo "Building applications-rp with debug symbols..." + @mkdir -p $(DEBUG_DEV_ROOT)/bin + @go build -gcflags="all=-N -l" -o $(DEBUG_DEV_ROOT)/bin/applications-rp ./cmd/applications-rp + @echo "βœ… applications-rp built" + +debug-build-controller: ## Build Controller with debug symbols + @echo "Building controller with debug symbols..." + @mkdir -p $(DEBUG_DEV_ROOT)/bin + @go build -gcflags="all=-N -l" -o $(DEBUG_DEV_ROOT)/bin/controller ./cmd/controller + @echo "βœ… controller built" + +debug-build-dynamic-rp: ## Build Dynamic RP with debug symbols + @echo "Building dynamic-rp with debug symbols..." + @mkdir -p $(DEBUG_DEV_ROOT)/bin + @go build -gcflags="all=-N -l" -o $(DEBUG_DEV_ROOT)/bin/dynamic-rp ./cmd/dynamic-rp + @echo "βœ… dynamic-rp built" + +debug-build-rad: ## Build rad CLI with debug symbols + create drad alias + @echo "Building rad CLI with debug symbols..." + @mkdir -p $(DEBUG_DEV_ROOT)/bin + @go build -gcflags="all=-N -l" -o $(DEBUG_DEV_ROOT)/bin/rad ./cmd/rad + @echo "βœ… rad CLI built" + @echo "Creating drad alias for debug CLI..." + @if [ -f build/scripts/rad-wrapper ]; then \ + ln -sf build/scripts/rad-wrapper ./drad; \ + echo "βœ… drad alias (debug wrapper) created"; \ + else \ + ln -sf $(DEBUG_DEV_ROOT)/bin/rad ./drad; \ + echo "βœ… drad alias (binary) created"; \ + fi + @echo "πŸ’‘ Use './drad' for debug-configured CLI (preserves 'rad' for your installed version)" + +debug-start: debug-setup debug-build-all ## Start k3d cluster and all Radius components as OS processes + @echo "Creating k3d cluster..." + @if k3d cluster list | grep -q "radius-debug"; then \ + echo "k3d cluster 'radius-debug' already exists"; \ + else \ + k3d cluster create radius-debug --api-port 0.0.0.0:6443 --wait --timeout 60s; \ + fi + @echo "Switching to k3d context..." + @kubectl config use-context k3d-radius-debug + @echo "Starting Radius components as OS processes..." + @build/scripts/start-radius.sh + @echo "Waiting for components to be ready..." + @max_attempts=30; \ + attempt=0; \ + while [ $$attempt -lt $$max_attempts ]; do \ + if curl -s "http://localhost:9000/healthz" > /dev/null 2>&1; then \ + echo "βœ… UCP is ready"; \ + break; \ + fi; \ + echo "Waiting for UCP... (attempt $$((attempt + 1))/$$max_attempts)"; \ + sleep 2; \ + attempt=$$((attempt + 1)); \ + done; \ + if [ $$attempt -eq $$max_attempts ]; then \ + echo "❌ UCP not ready after $$max_attempts attempts"; \ + echo "πŸ’‘ Check component logs with 'make debug-logs'"; \ + exit 1; \ + fi + @echo "Initializing environment resources..." + @$(MAKE) debug-env-init + @echo "πŸš€ All components started and environment initialized!" + @echo "πŸ“Š Use 'make debug-status' to check component health" + @echo "🚒 Use 'make debug-deployment-engine-status' to check deployment engine" + +debug-stop: ## Stop all running Radius components, destroy k3d cluster, and clean up + @echo "Stopping Radius components..." + @if [ -f build/scripts/stop-radius.sh ]; then \ + build/scripts/stop-radius.sh; \ + else \ + echo "❌ Stop script not found at build/scripts/stop-radius.sh"; \ + exit 1; \ + fi + @echo "Cleaning up debug files and symlinks..." + @rm -rf $(DEBUG_DEV_ROOT)/logs + @rm -f ./drad + @echo "βœ… Debug environment completely stopped and cleaned up" + +debug-status: ## Show status of all components + @if [ -f build/scripts/status-radius.sh ]; then \ + build/scripts/status-radius.sh; \ + else \ + echo "❌ Status script not found at build/scripts/status-radius.sh"; \ + exit 1; \ + fi + +debug-logs: ## Tail all component logs + @echo "Tailing all component logs (Ctrl+C to stop)..." + @if [ -d $(DEBUG_DEV_ROOT)/logs ]; then \ + tail -f $(DEBUG_DEV_ROOT)/logs/*.log; \ + else \ + echo "❌ Logs directory not found. Start components first with 'make debug-start'"; \ + exit 1; \ + fi + +# Deployment Engine Management +debug-deployment-engine-pull: ## Pull latest deployment engine image from ghcr.io + @echo "Pulling Deployment Engine image from ghcr.io..." + @command -v docker >/dev/null 2>&1 || { echo "❌ Docker not found. Please install Docker to use Deployment Engine"; exit 1; } + @docker info >/dev/null 2>&1 || { echo "❌ Docker daemon not running. Please start Docker"; exit 1; } + @docker pull ghcr.io/radius-project/deployment-engine:latest \ + && echo "βœ… Deployment Engine image pulled successfully" \ + || echo "❌ Failed to pull Deployment Engine image" + +debug-deployment-engine-start: ## Start deployment engine in k3d cluster + @echo "Installing ONLY deployment engine to k3d cluster..." + @if kubectl --context k3d-radius-debug get deployment deployment-engine >/dev/null 2>&1 && \ + kubectl --context k3d-radius-debug get deployment deployment-engine -o jsonpath='{.status.readyReplicas}' 2>/dev/null | grep -q "1" && \ + curl -s "http://localhost:5017/metrics" > /dev/null 2>&1; then \ + echo "βœ… Deployment engine already running and healthy"; \ + else \ + $(MAKE) debug-deployment-engine-deploy; \ + $(MAKE) debug-deployment-engine-port-forward; \ + fi + @echo "βœ… Deployment engine installed and ready in k3d cluster" + +debug-deployment-engine-deploy: ## Deploy deployment engine to k3d cluster + @echo "Applying deployment engine manifest to k3d cluster..." + @kubectl --context k3d-radius-debug apply -f build/configs/deployment-engine.yaml + @echo "Waiting for deployment engine to be ready..." + @kubectl --context k3d-radius-debug wait --for=condition=available deployment/deployment-engine --timeout=60s + +debug-deployment-engine-port-forward: ## Set up port forwarding for deployment engine + @build/scripts/setup-deployment-engine-port-forward.sh + +debug-deployment-engine-stop: ## Stop deployment engine in k3d cluster + @echo "Removing deployment engine from k3d cluster..." + @if [ -f $(DEBUG_DEV_ROOT)/logs/de-port-forward.pid ]; then \ + kill $$(cat $(DEBUG_DEV_ROOT)/logs/de-port-forward.pid) 2>/dev/null || true; \ + rm -f $(DEBUG_DEV_ROOT)/logs/de-port-forward.pid; \ + fi + @pkill -f "port-forward.*deployment-engine" 2>/dev/null || true + @kubectl --context k3d-radius-debug delete deployment deployment-engine 2>/dev/null || echo "Deployment engine deployment not found" + @kubectl --context k3d-radius-debug delete service deployment-engine 2>/dev/null || echo "Deployment engine service not found" + @echo "βœ… Deployment engine removed from k3d cluster" + +debug-deployment-engine-status: ## Check deployment engine status + @echo "πŸš€ Deployment Engine Status:" + @if kubectl --context k3d-radius-debug get deployment deployment-engine >/dev/null 2>&1; then \ + replicas=$$(kubectl --context k3d-radius-debug get deployment deployment-engine -o jsonpath='{.status.readyReplicas}' 2>/dev/null || echo "0"); \ + if [ "$$replicas" = "1" ]; then \ + echo "βœ… Deployment Engine (k3d) - Running and ready"; \ + else \ + echo "⚠️ Deployment Engine (k3d) - Deployment exists but not ready"; \ + fi; \ + else \ + echo "❌ Deployment Engine - Not deployed to k3d cluster"; \ + echo "πŸ’‘ Start with: make debug-deployment-engine-start"; \ + fi + +debug-deployment-engine-logs: ## View deployment engine logs + @echo "Showing deployment engine logs from k3d cluster..." + @kubectl --context k3d-radius-debug logs -l app=deployment-engine --tail=100 -f + + + +# Recipe registration +debug-register-recipes: ## Register default recipes in the debug environment + @echo "Registering default recipes..." + @if [ ! -f build/scripts/rad-wrapper ]; then \ + echo "❌ rad-wrapper script not found. This should not happen."; \ + exit 1; \ + fi + @build/scripts/register-recipes.sh + +debug-env-init: ## Create default resource group, environment, and register recipes + @echo "Initializing debug environment resources..." + @if [ ! -f build/scripts/rad-wrapper ]; then \ + echo "❌ rad-wrapper script not found. This should not happen."; \ + exit 1; \ + fi + @echo "Creating resource group 'default'..." + @build/scripts/rad-wrapper group create default || echo "Resource group may already exist" + @echo "Creating environment 'default' with Kubernetes compute configuration..." + @build/scripts/rad-wrapper env create default --namespace default || echo "Environment may already exist" + @echo "Starting deployment engine in k3d cluster..." + @$(MAKE) debug-deployment-engine-start + @echo "Registering default recipes..." + @$(MAKE) debug-register-recipes + @echo "βœ… Debug environment ready for application deployment!" + +# Integration with existing build system +build-debug: debug-build ## Alias for debug-build + +# Validate debug configuration +debug-validate: + @if [ ! -f $(DEBUG_CONFIG_FILE) ]; then \ + echo "❌ Debug configuration file not found: $(DEBUG_CONFIG_FILE)"; \ + echo "πŸ’‘ This file should be created automatically during setup"; \ + exit 1; \ + fi + @echo "βœ… Debug configuration valid" + +# Development workflow targets +debug-dev-start: debug-setup debug-start ## Complete development setup and start + @echo "πŸŽ‰ Debug development environment ready!" + +debug-dev-stop: debug-stop ## Stop development environment + @echo "πŸ›‘ Debug development environment stopped" + +# Prerequisite checks are handled by the main debug-check-prereqs target above + +.PHONY: debug-check-prereqs debug-validate debug-dev-start debug-dev-stop build-debug diff --git a/build/scripts/rad-wrapper b/build/scripts/rad-wrapper new file mode 100755 index 0000000000..9872916e2a --- /dev/null +++ b/build/scripts/rad-wrapper @@ -0,0 +1,32 @@ +#!/bin/bash +# Debug wrapper for rad CLI that automatically configures UCP endpoint + +# Resolve the actual script path even when called via symlink +SCRIPT_PATH="${BASH_SOURCE[0]}" +while [ -L "$SCRIPT_PATH" ]; do + SCRIPT_DIR="$(cd -P "$(dirname "$SCRIPT_PATH")" && pwd)" + SCRIPT_PATH="$(readlink "$SCRIPT_PATH")" + [[ $SCRIPT_PATH != /* ]] && SCRIPT_PATH="$SCRIPT_DIR/$SCRIPT_PATH" +done +SCRIPT_DIR="$(cd -P "$(dirname "$SCRIPT_PATH")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" + +DEBUG_CONFIG="$PROJECT_ROOT/build/configs/rad-debug-config.yaml" +RAD_BINARY="$PROJECT_ROOT/debug_files/bin/rad" + +# Check if debug config exists +if [ ! -f "$DEBUG_CONFIG" ]; then + echo "Error: Debug config not found at $DEBUG_CONFIG" + echo "Run 'make debug-start' to start the debug environment" + exit 1 +fi + +# Check if rad binary exists +if [ ! -f "$RAD_BINARY" ]; then + echo "Error: rad binary not found at $RAD_BINARY" + echo "Run 'make debug-start' to build and start the debug environment" + exit 1 +fi + +# Execute rad with debug config, passing through all arguments +exec "$RAD_BINARY" --config "$DEBUG_CONFIG" "$@" diff --git a/build/scripts/register-recipes.sh b/build/scripts/register-recipes.sh new file mode 100755 index 0000000000..5779b56d0a --- /dev/null +++ b/build/scripts/register-recipes.sh @@ -0,0 +1,87 @@ +#!/bin/bash + +# Get the project root directory (where this script is called from) +PROJECT_ROOT="$(pwd)" +RAD_WRAPPER="$PROJECT_ROOT/build/scripts/rad-wrapper" + +echo "πŸ“ Registering default recipes..." + +# Check if rad-wrapper exists +if [ ! -f "$RAD_WRAPPER" ]; then + echo "❌ rad-wrapper script not found at $RAD_WRAPPER" + exit 1 +fi + +# Wait for environment to be ready +echo "Waiting for environment to be available..." +max_attempts=30 +attempt=0 + +while [ $attempt -lt $max_attempts ]; do + if "$RAD_WRAPPER" env show default >/dev/null 2>&1; then + echo "βœ… Environment 'default' is ready" + break + fi + echo "Waiting for environment... (attempt $((attempt + 1))/$max_attempts)" + sleep 2 + ((attempt++)) +done + +if [ $attempt -eq $max_attempts ]; then + echo "❌ Environment not ready after ${max_attempts} attempts" + echo "πŸ’‘ Make sure to run: build/scripts/rad-wrapper group create default && build/scripts/rad-wrapper env create default" + exit 1 +fi + +# Register default recipes for common resource types +# Each recipe is registered with the name "default" so deployments can find them automatically +recipes=( + "Applications.Datastores/redisCaches:ghcr.io/radius-project/recipes/local-dev/rediscaches:latest" + "Applications.Datastores/sqlDatabases:ghcr.io/radius-project/recipes/local-dev/sqldatabases:latest" + "Applications.Datastores/mongoDatabases:ghcr.io/radius-project/recipes/local-dev/mongodatabases:latest" + "Applications.Messaging/rabbitMQQueues:ghcr.io/radius-project/recipes/local-dev/rabbitmqqueues:latest" +) + +registered_count=0 +failed_count=0 + +for recipe_spec in "${recipes[@]}"; do + # Split resource_type:template_path + IFS=':' read -r resource_type template_path <<< "$recipe_spec" + + echo "Registering default recipe for $resource_type -> $template_path" + + # Try to register the recipe + output=$("$RAD_WRAPPER" recipe register "default" \ + --resource-type "$resource_type" \ + --template-kind "bicep" \ + --template-path "$template_path" \ + --environment default 2>&1) + + if [ $? -eq 0 ]; then + echo "βœ… Registered: default recipe for $resource_type" + ((registered_count++)) + elif echo "$output" | grep -q "already exists\|already registered"; then + echo "ℹ️ Already exists: default recipe for $resource_type" + ((registered_count++)) + else + echo "⚠️ Failed to register: default recipe for $resource_type" + echo " Error: $output" + ((failed_count++)) + fi +done + +echo "" +echo "πŸ“Š Recipe Registration Summary:" +echo "βœ… Successfully registered: $registered_count" +if [ $failed_count -gt 0 ]; then + echo "⚠️ Failed to register: $failed_count" +fi + +echo "" +echo "πŸŽ‰ Recipe registration complete!" +echo "πŸ’‘ You can now deploy applications that use these resource types" +echo "πŸ“‹ All recipes are registered as 'default' so deployments will find them automatically" + +# Explicitly exit with success +exit 0 diff --git a/build/scripts/setup-deployment-engine-port-forward.sh b/build/scripts/setup-deployment-engine-port-forward.sh new file mode 100755 index 0000000000..6b41498d87 --- /dev/null +++ b/build/scripts/setup-deployment-engine-port-forward.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +# Get the project root directory +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +DEBUG_ROOT="$REPO_ROOT/debug_files" + +# Ensure logs directory exists +mkdir -p "$DEBUG_ROOT/logs" + +echo "Setting up port forwarding for deployment engine..." + +# Kill any existing port forward +pkill -f "port-forward.*deployment-engine" 2>/dev/null || true + +# Start port forwarding in background and save PID +kubectl --context k3d-radius-debug port-forward -n default service/deployment-engine 5017:5445 > "$DEBUG_ROOT/logs/de-port-forward.log" 2>&1 & +port_forward_pid=$! + +# Save the PID for later cleanup +echo $port_forward_pid > "$DEBUG_ROOT/logs/de-port-forward.pid" + +echo "Port forwarding started (PID: $port_forward_pid)" + +# Wait for deployment engine health check +echo "Waiting for deployment engine health check..." +max_attempts=30 +attempt=0 +while [ $attempt -lt $max_attempts ]; do + if curl -s "http://localhost:5017/metrics" > /dev/null 2>&1; then + echo "βœ… Deployment Engine is ready" + exit 0 + fi + echo "Waiting for Deployment Engine... (attempt $((attempt + 1))/$max_attempts)" + sleep 2 + attempt=$((attempt + 1)) +done + +echo "❌ Deployment Engine not ready after $max_attempts attempts" +echo "πŸ’‘ Check component logs with 'make debug-logs' and 'make debug-deployment-engine-logs'" +exit 1 \ No newline at end of file diff --git a/build/scripts/start-deployment-engine.sh b/build/scripts/start-deployment-engine.sh new file mode 100755 index 0000000000..3d3271e551 --- /dev/null +++ b/build/scripts/start-deployment-engine.sh @@ -0,0 +1,48 @@ +#!/bin/bash +set -e + +echo "πŸš€ Starting deployment engine (Docker)..." + +# Stop existing container if running +docker stop radius-deployment-engine 2>/dev/null || true +docker rm radius-deployment-engine 2>/dev/null || true + +# Create kubeconfig for container access +echo "πŸ“ Preparing kubeconfig for container..." +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +TEMP_KUBECONFIG="/tmp/radius-debug-kubeconfig" + +# Get current kubeconfig and extract the needed parts +CURRENT_SERVER=$(kubectl config view --minify -o jsonpath='{.clusters[0].cluster.server}') +CURRENT_CERT_DATA=$(kubectl config view --raw --minify -o jsonpath='{.clusters[0].cluster.certificate-authority-data}') +CURRENT_CLIENT_CERT=$(kubectl config view --raw --minify -o jsonpath='{.users[0].user.client-certificate-data}') +CURRENT_CLIENT_KEY=$(kubectl config view --raw --minify -o jsonpath='{.users[0].user.client-key-data}') + +# Replace server with container-accessible endpoint +CONTAINER_SERVER=$(echo "$CURRENT_SERVER" | sed 's|127\.0\.0\.1|host.docker.internal|g' | sed 's|localhost|host.docker.internal|g' | sed 's|0\.0\.0\.0|host.docker.internal|g') + +# Use template and substitute values +cp "$SCRIPT_DIR/../configs/kubeconfig-template" "$TEMP_KUBECONFIG" +sed -i.bak "s|https://host.docker.internal:6443|$CONTAINER_SERVER|g" "$TEMP_KUBECONFIG" +sed -i.bak "s|certificate-authority-data: \"\"|certificate-authority-data: $CURRENT_CERT_DATA|g" "$TEMP_KUBECONFIG" +sed -i.bak "s|client-certificate-data: \"\"|client-certificate-data: $CURRENT_CLIENT_CERT|g" "$TEMP_KUBECONFIG" +sed -i.bak "s|client-key-data: \"\"|client-key-data: $CURRENT_CLIENT_KEY|g" "$TEMP_KUBECONFIG" + +# Start new container with kubeconfig mounted +docker run -d \ + --name radius-deployment-engine \ + -e RADIUSBACKENDURL=http://host.docker.internal:9000/apis/api.ucp.dev/v1alpha3 \ + -e KUBECONFIG=/root/.kube/config \ + -v "$TEMP_KUBECONFIG:/root/.kube/config:ro" \ + -p 5017:8080 \ + ghcr.io/radius-project/deployment-engine:latest + +echo "βœ… Deployment engine started on port 5017" + +# Wait for health check +sleep 5 +if curl -s http://localhost:5017/health >/dev/null; then + echo "βœ… Deployment engine health check passed" +else + echo "⚠️ Deployment engine may still be starting up" +fi diff --git a/build/scripts/start-radius.sh b/build/scripts/start-radius.sh new file mode 100755 index 0000000000..ead8e8617b --- /dev/null +++ b/build/scripts/start-radius.sh @@ -0,0 +1,375 @@ +#!/bin/bash + +# PostgreSQL connection strings - try Docker first, then Homebrew local +POSTGRES_DOCKER_CONNECTION="postgresql://postgres:radius_pass@localhost:5432/postgres" +POSTGRES_HOMEBREW_CONNECTION="postgres" +set -e + +# Get the script directory and repository root +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)" +DEBUG_ROOT="$REPO_ROOT/debug_files" + +# Color codes for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Output helper functions (aligned with test.sh) +print_info() { echo -e "\033[0;34mβ„Ή${NC} $1"; } +print_success() { echo -e "${GREEN}βœ“${NC} $1"; } +print_warning() { echo -e "${YELLOW}⚠${NC} $1"; } +print_error() { echo -e "${RED}βœ—${NC} $1"; } + +# Helper function to execute PostgreSQL commands with proper connection +psql_exec() { + local sql="$1" + if psql "$POSTGRES_DOCKER_CONNECTION" -c "$sql" >/dev/null 2>&1; then + return 0 + elif psql "$POSTGRES_HOMEBREW_CONNECTION" -c "$sql" >/dev/null 2>&1; then + return 0 + else + return 1 + fi +} + +# Helper function to determine which PostgreSQL connection is working +detect_postgres_connection() { + if psql "$POSTGRES_DOCKER_CONNECTION" -c "SELECT 1;" >/dev/null 2>&1; then + echo "docker" + export POSTGRES_WORKING_CONNECTION="$POSTGRES_DOCKER_CONNECTION" + elif psql "$POSTGRES_HOMEBREW_CONNECTION" -c "SELECT 1;" >/dev/null 2>&1; then + echo "homebrew" + export POSTGRES_WORKING_CONNECTION="$POSTGRES_HOMEBREW_CONNECTION" + else + echo "none" + export POSTGRES_WORKING_CONNECTION="" + fi +} + +check_prerequisites() { + echo "πŸ” Checking prerequisites (idempotent)..." + local missing_tools=() + local advisory_msgs=() + + # Required tools + command -v dlv >/dev/null 2>&1 || missing_tools+=("dlv -> go install github.com/go-delve/delve/cmd/dlv@latest") + command -v go >/dev/null 2>&1 || missing_tools+=("go -> https://golang.org/doc/install") + command -v k3d >/dev/null 2>&1 || missing_tools+=("k3d -> https://k3d.io/") + command -v kubectl >/dev/null 2>&1 || missing_tools+=("kubectl -> https://kubernetes.io/docs/tasks/tools/") + command -v terraform >/dev/null 2>&1 || missing_tools+=("terraform -> https://developer.hashicorp.com/terraform/install") + if ! command -v psql >/dev/null 2>&1; then + missing_tools+=("psql (PostgreSQL client) -> https://www.postgresql.org/download/") + else + postgres_type=$(detect_postgres_connection) + case $postgres_type in + "docker") + print_info "PostgreSQL accessible via Docker (postgres user)" + ;; + "homebrew") + print_info "PostgreSQL accessible via Homebrew (local user)" + ;; + "none") + advisory_msgs+=("PostgreSQL not reachable. Quick start: docker run --name radius-postgres -e POSTGRES_PASSWORD=radius_pass -p 5432:5432 -d postgres:15") + ;; + esac + fi + + if [ ${#missing_tools[@]} -ne 0 ]; then + print_error "Missing required tools (install then re-run 'make debug-start'):"; + for tool in "${missing_tools[@]}"; do + echo " - $tool" + done + echo "" + echo "Docs: docs/contributing/contributing-code/contributing-code-debugging/radius-os-processes-debugging.md#prerequisites" + exit 1 + fi + + if [ ${#advisory_msgs[@]} -ne 0 ]; then + print_warning "Advisories:"; + for msg in "${advisory_msgs[@]}"; do echo " - $msg"; done + echo "(Continuing; DB init will attempt creation)" + fi + + print_success "Prerequisite check complete" +} + +# Check if we have the debug environment set up +if [ ! -f "$DEBUG_ROOT/bin/ucpd" ]; then + print_error "Debug environment not found. Please run 'make debug-setup' first." + exit 1 +fi + +# Ensure logs directory exists +mkdir -p "$DEBUG_ROOT/logs" + +# Check prerequisites +check_prerequisites + +echo "πŸš€ Starting Radius components..." + +# Stop any existing components first +echo "Checking for existing components and stopping them..." +for component in dynamic-rp applications-rp controller ucp; do + if [ -f "$DEBUG_ROOT/logs/${component}.pid" ]; then + pid=$(cat "$DEBUG_ROOT/logs/${component}.pid") + if kill -0 "$pid" 2>/dev/null; then + echo "Stopping existing $component (PID: $pid)" + kill "$pid" 2>/dev/null || true + sleep 2 + if kill -0 "$pid" 2>/dev/null; then + kill -9 "$pid" 2>/dev/null || true + fi + fi + rm -f "$DEBUG_ROOT/logs/${component}.pid" + fi +done + +# Kill any remaining Radius processes and dlv +# Use portable process killing that works on both macOS and Linux +if command -v pgrep >/dev/null 2>&1; then + # Use pgrep/pkill if available (most Linux/macOS systems) + pkill -f "ucpd" 2>/dev/null || true + pkill -f "applications-rp" 2>/dev/null || true + pkill -f "dynamic-rp" 2>/dev/null || true + pkill -f "controller.*--config-file.*controller.yaml" 2>/dev/null || true + pkill -f "dlv.*exec.*ucpd" 2>/dev/null || true + pkill -f "dlv.*exec.*applications-rp" 2>/dev/null || true + pkill -f "dlv.*exec.*dynamic-rp" 2>/dev/null || true + pkill -f "dlv.*exec.*controller" 2>/dev/null || true +else + # Fallback for systems without pkill + ps aux | grep -E "(ucpd|applications-rp|dynamic-rp|controller.*--config-file.*controller.yaml|dlv.*exec)" | grep -v grep | awk '{print $2}' | xargs -r kill 2>/dev/null || true +fi + +print_success "Cleanup complete" + +# Ensure logs directory exists (double-check) +mkdir -p "$DEBUG_ROOT/logs" + +# Initialize PostgreSQL database if needed +echo "πŸ—„οΈ Initializing PostgreSQL database (idempotent)..." +if command -v psql >/dev/null 2>&1; then + # Detect which PostgreSQL connection is working + postgres_type=$(detect_postgres_connection) + # Manually set the working connection based on the type + if [ "$postgres_type" = "docker" ]; then + POSTGRES_WORKING_CONNECTION="$POSTGRES_DOCKER_CONNECTION" + elif [ "$postgres_type" = "homebrew" ]; then + POSTGRES_WORKING_CONNECTION="$POSTGRES_HOMEBREW_CONNECTION" + else + POSTGRES_WORKING_CONNECTION="" + fi + if [ "$postgres_type" = "none" ]; then + print_error "Cannot connect to PostgreSQL" + echo "Troubleshooting:" + echo " - macOS: brew services start postgresql" + echo " - Linux: sudo systemctl start postgresql" + echo " - Or run disposable container: docker run --name radius-postgres -e POSTGRES_PASSWORD=radius_pass -p 5432:5432 -d postgres:15" + echo "Re-run: make debug-start" + echo "Docs: docs/contributing/contributing-code/contributing-code-debugging/radius-os-processes-debugging.md#prerequisites" + exit 1 + fi + + # Create applications_rp user if it doesn't exist + if ! psql_exec "CREATE USER applications_rp WITH PASSWORD 'radius_pass';"; then + echo "(applications_rp user exists)" + else + echo "Created user applications_rp" + fi + if ! psql_exec "CREATE DATABASE applications_rp OWNER applications_rp;"; then + echo "(applications_rp database exists)" + else + echo "Created database applications_rp" + fi + + # Grant privileges + psql_exec "GRANT ALL PRIVILEGES ON DATABASE applications_rp TO applications_rp;" || true + + # Create the resources table in applications_rp database using the working connection + if [ "$postgres_type" = "docker" ]; then + applications_rp_connection=$(echo "$POSTGRES_WORKING_CONNECTION" | sed 's|/postgres$|/applications_rp|') + else + applications_rp_connection="applications_rp" + fi + + if psql "$applications_rp_connection" -c " + CREATE TABLE IF NOT EXISTS resources ( + id TEXT PRIMARY KEY NOT NULL, + original_id TEXT NOT NULL, + resource_type TEXT NOT NULL, + root_scope TEXT NOT NULL, + routing_scope TEXT NOT NULL, + etag TEXT NOT NULL, + created_at timestamp(6) with time zone DEFAULT CURRENT_TIMESTAMP, + resource_data jsonb NOT NULL + ); + CREATE INDEX IF NOT EXISTS idx_resource_query ON resources (resource_type, root_scope); + + -- Grant table-level permissions to the applications_rp user + GRANT ALL PRIVILEGES ON TABLE resources TO applications_rp; + GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO applications_rp; + "; then + echo "βœ… applications_rp tables created/verified" + else + print_warning "Could not verify/create applications_rp tables" + fi + + # Also create UCP database for completeness + if ! psql_exec "CREATE USER ucp WITH PASSWORD 'radius_pass';"; then + echo "(ucp user exists)" + else + echo "Created user ucp" + fi + if ! psql_exec "CREATE DATABASE ucp OWNER ucp;"; then + echo "(ucp database exists)" + else + echo "Created database ucp" + fi + psql_exec "GRANT ALL PRIVILEGES ON DATABASE ucp TO ucp;" || true + + # Create the resources table in ucp database using the working connection + if [ "$postgres_type" = "docker" ]; then + ucp_connection=$(echo "$POSTGRES_WORKING_CONNECTION" | sed 's|/postgres$|/ucp|') + else + ucp_connection="postgresql://ucp:radius_pass@localhost:5432/ucp" + fi + + if psql "$ucp_connection" -c " + CREATE TABLE IF NOT EXISTS resources ( + id TEXT PRIMARY KEY NOT NULL, + original_id TEXT NOT NULL, + resource_type TEXT NOT NULL, + root_scope TEXT NOT NULL, + routing_scope TEXT NOT NULL, + etag TEXT NOT NULL, + created_at timestamp(6) with time zone DEFAULT CURRENT_TIMESTAMP, + resource_data jsonb NOT NULL + ); + CREATE INDEX IF NOT EXISTS idx_resource_query ON resources (resource_type, root_scope); + + -- Grant table-level permissions to the ucp user + GRANT ALL PRIVILEGES ON TABLE resources TO ucp; + GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO ucp; + "; then + echo "βœ… UCP tables created/verified" + else + print_warning "Could not verify/create UCP tables" + fi + + print_success "Database initialization complete (idempotent)" +else + print_error "psql not available - database cannot be initialized" + exit 1 +fi + +# Start UCP with dlv +echo "Starting UCP with dlv on port 40001..." +dlv exec "$DEBUG_ROOT/bin/ucpd" --listen=127.0.0.1:40001 --headless=true --api-version=2 --accept-multiclient --continue -- --config-file="$SCRIPT_DIR/../configs/ucp.yaml" > "$DEBUG_ROOT/logs/ucp.log" 2>&1 & +echo $! > "$DEBUG_ROOT/logs/ucp.pid" + +# Wait for UCP to start and complete initialization (this can take 60+ seconds) +echo "Waiting for UCP to initialize (this may take up to 2 minutes)..." +max_attempts=60 +attempt=0 +while [ $attempt -lt $max_attempts ]; do + if curl -s "http://localhost:9000/apis/api.ucp.dev/v1alpha3" > /dev/null 2>&1; then + # Check if initialization is complete by looking for the success message in logs + if grep -q "Successfully registered manifests" "$DEBUG_ROOT/logs/ucp.log" 2>/dev/null; then + break + fi + fi + + # Show progress every 10 seconds + if [ $((attempt % 10)) -eq 0 ] && [ $attempt -gt 0 ]; then + echo " Still waiting for UCP initialization... (${attempt}s elapsed)" + fi + + sleep 2 + attempt=$((attempt + 1)) +done + +# Verify UCP is fully ready +if [ $attempt -eq $max_attempts ]; then + print_error "UCP failed to start within 2 minutes" + echo "Check the UCP log for details: $DEBUG_ROOT/logs/ucp.log" + exit 1 +fi +print_success "UCP started and initialized successfully" + +# Start Controller with dlv +echo "Starting Controller with dlv on port 40002..." +dlv exec "$DEBUG_ROOT/bin/controller" --listen=127.0.0.1:40002 --headless=true --api-version=2 --accept-multiclient --continue -- --config-file="$SCRIPT_DIR/../configs/controller.yaml" --cert-dir="" > "$DEBUG_ROOT/logs/controller.log" 2>&1 & +echo $! > "$DEBUG_ROOT/logs/controller.pid" + +# Wait for Controller to start (check health endpoint) +echo "Waiting for Controller to start..." +attempt=0 +max_attempts=15 +while [ $attempt -lt $max_attempts ]; do + if curl -s "http://localhost:7073/healthz" > /dev/null 2>&1; then + break + fi + sleep 2 + attempt=$((attempt + 1)) +done + +if [ $attempt -eq $max_attempts ]; then + print_warning "Controller health check failed, but continuing (check logs: $DEBUG_ROOT/logs/controller.log)" +else + print_success "Controller started successfully" +fi + +# Start Applications RP with dlv +echo "Starting Applications RP with dlv on port 40003..." +dlv exec "$DEBUG_ROOT/bin/applications-rp" --listen=127.0.0.1:40003 --headless=true --api-version=2 --accept-multiclient --continue -- --config-file="$SCRIPT_DIR/../configs/applications-rp.yaml" > "$DEBUG_ROOT/logs/applications-rp.log" 2>&1 & +echo $! > "$DEBUG_ROOT/logs/applications-rp.pid" + +# Wait for Applications RP to start (it takes time to register with UCP) +echo "Waiting for Applications RP to start..." +attempt=0 +max_attempts=15 +while [ $attempt -lt $max_attempts ]; do + if curl -s "http://localhost:8080/healthz" > /dev/null 2>&1; then + break + fi + sleep 2 + attempt=$((attempt + 1)) +done + +if [ $attempt -eq $max_attempts ]; then + print_warning "Applications RP health check failed, but continuing (check logs: $DEBUG_ROOT/logs/applications-rp.log)" +else + print_success "Applications RP started successfully" +fi + +# Start Dynamic RP with dlv +echo "Starting Dynamic RP with dlv on port 40004..." +dlv exec "$DEBUG_ROOT/bin/dynamic-rp" --listen=127.0.0.1:40004 --headless=true --api-version=2 --accept-multiclient --continue -- --config-file="$SCRIPT_DIR/../configs/dynamic-rp.yaml" > "$DEBUG_ROOT/logs/dynamic-rp.log" 2>&1 & +echo $! > "$DEBUG_ROOT/logs/dynamic-rp.pid" + +# Wait for Dynamic RP to start +echo "Waiting for Dynamic RP to start..." +attempt=0 +max_attempts=15 +while [ $attempt -lt $max_attempts ]; do + if curl -s "http://localhost:8082/healthz" > /dev/null 2>&1; then + break + fi + sleep 2 + attempt=$((attempt + 1)) +done + +if [ $attempt -eq $max_attempts ]; then + print_warning "Dynamic RP health check failed, but continuing (check logs: $DEBUG_ROOT/logs/dynamic-rp.log)" +else + print_success "Dynamic RP started successfully" +fi + +echo "πŸŽ‰ All components started successfully with dlv debugging!" +echo "πŸ”— UCP API: http://localhost:9000 (dlv debug port 40001)" +echo "πŸ”— Applications RP: http://localhost:8080 (dlv debug port 40003)" +echo "πŸ”— Dynamic RP: http://localhost:8082 (dlv debug port 40004)" +echo "πŸ”— Controller Health: http://localhost:7073/healthz (dlv debug port 40002)" +echo "πŸ› Attach VS Code debugger to dlv ports 40001-40004" diff --git a/build/scripts/status-radius.sh b/build/scripts/status-radius.sh new file mode 100755 index 0000000000..dfdccdf478 --- /dev/null +++ b/build/scripts/status-radius.sh @@ -0,0 +1,45 @@ +#!/bin/bash + +# Get debug directory from environment or default +DEBUG_DEV_ROOT=${DEBUG_DEV_ROOT:-"$(pwd)/debug_files"} + +cd "$DEBUG_DEV_ROOT" + +echo "πŸ“Š Radius Component Status:" +echo "==========================" + +components=("ucp" "controller" "applications-rp" "dynamic-rp") + +for component in "${components[@]}"; do + if [ -f "logs/${component}.pid" ]; then + pid=$(cat "logs/${component}.pid") + if kill -0 "$pid" 2>/dev/null; then + echo "βœ… $component (PID: $pid) - Running" + else + echo "❌ $component - PID file exists but process not running" + fi + else + echo "❌ $component - Not running (no PID file)" + fi +done + +# Check deployment engine (k3d deployment) +echo "" +echo "🚒 Deployment Engine Status:" +echo "==========================" + +if command -v kubectl >/dev/null 2>&1; then + if kubectl --context k3d-radius-debug get deployment deployment-engine -n default >/dev/null 2>&1; then + status=$(kubectl --context k3d-radius-debug get deployment deployment-engine -n default -o jsonpath='{.status.conditions[?(@.type=="Available")].status}' 2>/dev/null) + if [ "$status" = "True" ]; then + replicas=$(kubectl --context k3d-radius-debug get deployment deployment-engine -n default -o jsonpath='{.status.readyReplicas}' 2>/dev/null) + echo "βœ… deployment-engine (k3d) - Running ($replicas replicas ready)" + else + echo "❌ deployment-engine (k3d) - Not ready" + fi + else + echo "❌ deployment-engine - Not found in k3d cluster" + fi +else + echo "⚠️ deployment-engine - Cannot check status (kubectl not available)" +fi diff --git a/build/scripts/stop-radius.sh b/build/scripts/stop-radius.sh new file mode 100755 index 0000000000..4f8b9b6df3 --- /dev/null +++ b/build/scripts/stop-radius.sh @@ -0,0 +1,96 @@ +#!/bin/bash +set -e + +# PostgreSQL connection strings - try Docker first, fallback to local user +POSTGRES_ADMIN_CONNECTION="postgresql://postgres:radius_pass@localhost:5432/postgres" +POSTGRES_FALLBACK_CONNECTION="postgresql://$(whoami)@localhost:5432/postgres" + +# Helper function to execute PostgreSQL commands with proper connection +psql_exec() { + local sql="$1" + if psql "$POSTGRES_ADMIN_CONNECTION" -c "$sql" >/dev/null 2>&1; then + return 0 + elif psql "$POSTGRES_FALLBACK_CONNECTION" -c "$sql" >/dev/null 2>&1; then + return 0 + else + return 1 + fi +} + +echo "🧹 Full environment cleanup: stopping debug processes, deleting k3d cluster, deleting PostgreSQL data and schema..." + +cd debug_files 2>/dev/null || { + echo "⚠️ debug_files directory not found, stopping processes anyway..." +} + +# Stop components using PID files if available +for component in dynamic-rp applications-rp controller ucp; do + if [ -f "logs/${component}.pid" ]; then + pid=$(cat "logs/${component}.pid") + if kill -0 "$pid" 2>/dev/null; then + echo "Stopping $component (PID: $pid)" + kill "$pid" 2>/dev/null || true + sleep 2 + if kill -0 "$pid" 2>/dev/null; then + kill -9 "$pid" 2>/dev/null || true + fi + fi + rm -f "logs/${component}.pid" + fi +done + +# Kill any remaining Radius processes and dlv +if command -v pgrep >/dev/null 2>&1; then + pkill -f "ucpd" 2>/dev/null || true + pkill -f "applications-rp" 2>/dev/null || true + pkill -f "dynamic-rp" 2>/dev/null || true + pkill -f "controller.*--config-file.*controller.yaml" 2>/dev/null || true + pkill -f "dlv.*exec.*ucpd" 2>/dev/null || true + pkill -f "dlv.*exec.*applications-rp" 2>/dev/null || true + pkill -f "dlv.*exec.*dynamic-rp" 2>/dev/null || true + pkill -f "dlv.*exec.*controller" 2>/dev/null || true +else + ps aux | grep -E "(ucpd|applications-rp|dynamic-rp|controller.*--config-file.*controller.yaml|dlv.*exec)" | grep -v grep | awk '{print $2}' | xargs -r kill 2>/dev/null || true +fi + +# Stop deployment engine in k3d cluster +echo "Stopping deployment engine..." +if command -v kubectl >/dev/null 2>&1; then + kubectl --context k3d-radius-debug delete deployment deployment-engine 2>/dev/null || true + kubectl --context k3d-radius-debug delete service deployment-engine 2>/dev/null || true +else + echo "⚠️ kubectl not available - skipping deployment engine cleanup" +fi + +# Nuclear database cleanup - drop everything +echo "πŸ’£ Nuclear database cleanup..." +if command -v psql >/dev/null 2>&1; then + # Truncate tables first (if they exist) + psql "postgresql://applications_rp:radius_pass@localhost:5432/applications_rp" -c "TRUNCATE TABLE resources;" 2>/dev/null || true + psql "postgresql://ucp:radius_pass@localhost:5432/ucp" -c "TRUNCATE TABLE resources;" 2>/dev/null || true + + # Drop databases if they exist using helper function + psql_exec "DROP DATABASE IF EXISTS applications_rp;" || true + psql_exec "DROP DATABASE IF EXISTS ucp;" || true + psql_exec "DROP DATABASE IF EXISTS radius;" || true + + # Drop users if they exist using helper function + psql_exec "DROP USER IF EXISTS applications_rp;" || true + psql_exec "DROP USER IF EXISTS ucp;" || true + psql_exec "DROP USER IF EXISTS radius;" || true + + echo "βœ… Database nuclear cleanup complete" +else + echo "⚠️ psql not available - skipping database cleanup" +fi + +# Nuclear k3d cleanup +echo "πŸ’£ Nuclear k3d cleanup..." +if command -v k3d >/dev/null 2>&1; then + k3d cluster delete radius-debug 2>/dev/null || true + echo "βœ… k3d cluster destroyed" +else + echo "⚠️ k3d not available - skipping cluster cleanup" +fi + +echo "πŸ’₯ Nuclear stop complete - everything destroyed!" diff --git a/docs/contributing/contributing-code/contributing-code-control-plane/running-controlplane-locally.md b/docs/contributing/contributing-code/contributing-code-control-plane/running-controlplane-locally.md index 12af26e9bc..16275afa5f 100644 --- a/docs/contributing/contributing-code/contributing-code-control-plane/running-controlplane-locally.md +++ b/docs/contributing/contributing-code/contributing-code-control-plane/running-controlplane-locally.md @@ -1,5 +1,15 @@ # Running Radius control plane provider locally +> ⚠️ **Deprecated / Legacy Guide** +> +> This document describes an older, mostly manual workflow for running and debugging the Radius control plane. A newer, automated OS process debugging workflow is now available and is the recommended approach for most contributors. +> +> βœ… **Use this instead:** `docs/contributing/contributing-code/contributing-code-debugging/radius-os-processes-debugging.md` +> +> The new guide provides: automated environment setup, incremental debug builds, attach-based VS Code configurations, recipe registration, k3d cluster management, and streamlined database initialization. This legacy document is retained temporarily for reference and will be removed after the transition period. +> +> If you find information here that's missing from the new guide, please open an issue so we can incorporate it. + Radius consists of a few processes that get deployed inside a Kubernetes cluster. This includes: diff --git a/docs/contributing/contributing-code/contributing-code-debugging/radius-os-processes-debugging.md b/docs/contributing/contributing-code/contributing-code-debugging/radius-os-processes-debugging.md new file mode 100644 index 0000000000..df71c28d62 --- /dev/null +++ b/docs/contributing/contributing-code/contributing-code-debugging/radius-os-processes-debugging.md @@ -0,0 +1,501 @@ +# Running Radius as OS Processes for Advanced Debugging + +This guide details how to leverage the fully-integrated VS Code debugging experience for Radius development. By running core components as native OS processes instead of in containers, you can take advantage of pre-configured launch configurations and tasks to enable a seamless "inner-loop" workflow. This setup allows for advanced debugging capabilities, such as setting breakpoints, inspecting variables, and stepping through code in real-timeβ€”all directly within the VS Code editorβ€”significantly accelerating development and troubleshooting. + +## Table of Contents + +1. [Overview](#overview) +2. [Quick Start](#quick-start) +3. [Prerequisites](#prerequisites) +4. [Development Workflow](#development-workflow) +5. [VS Code Debugging](#vs-code-debugging) +6. [Troubleshooting](#troubleshooting) + +## Overview + +Radius consists of several key components that normally run in Kubernetes containers: +- **Applications Resource Provider (applications-rp)** - Manages Applications.Core resources +- **UCP Daemon (ucpd)** - Universal Control Plane for resource management +- **Controller** - Kubernetes controller for managing Radius resources +- **Dynamic Resource Provider (dynamic-rp)** - Handles dynamic resource types + +Running these as OS processes enables: +- Full debugger support with breakpoints and variable inspection +- Real-time configuration changes +- Performance profiling and analysis +- Network traffic inspection + +## Quick Start + +The simplest way to get debugging working: + +### Prerequisites +- PostgreSQL database running locally + +### Setup Commands +```bash +# Start all components as OS processes with debugging (Checks prereqs and creates necessary folders) +make debug-start + +# Check that everything is running +make debug-status +``` + +**VS Code Tasks:** +- Use `Cmd+Shift+P` (or `Ctrl+Shift+P`) β†’ "Tasks: Run Task" +- Available tasks: + - "Debug: Start All Components" - Starts the control plane + - "Debug: Stop All Components" - Stops the control plane + - "Debug: Component Status" - Check component health + - "Debug: View Logs" - Tail all component logs + +**VS Code Debugging:** +- After starting components with the task above, use F5 to attach debuggers +- Debugger attach configurations are pre-configured in `.vscode/launch.json` +- Debug ports: UCP (40001), Controller (40002), Applications RP (40003), Dynamic RP (40004) + +**CLI Debugging Options:** +- **Use `./drad` for convenience**: When you only need to test CLI commands against the debug environment without debugging the CLI code itself +- **Use "Debug rad CLI (prompt for args)" in VS Code**: When you need to debug CLI code with breakpoints, variable inspection, and step-through debugging + +**For code changes:** +1. Stop components: `Cmd+Shift+P` β†’ "Tasks: Run Task" β†’ "Debug: Stop All Components" +2. Restart (rebuilds automatically): `Cmd+Shift+P` β†’ "Tasks: Run Task" β†’ "Debug: Start All Components" +3. Re-attach debugger with F5 + +The project could take on Air as a depdendency and allow for golang hot-reload, this would be a huge value if someone wants to contribute. + +**What the automation provides:** +- Environment directory structure at `debug_files/` (in project root) +- Component configuration files with correct schemas +- Controller configured to skip webhooks in local development (no TLS certs required) +- Database setup verification +- Management scripts (start/stop/status) +- Incremental builds for individual components +- Convenient `./drad` symlink in workspace root for easy CLI access +- Debug CLI wrapper `./drad` with automatic UCP endpoint configuration + +## Prerequisites + +The automation checks for all required tools. Install any missing prerequisites: + +### Required Tools +- **Go 1.25+** - `go version` +- **Delve debugger** - `dlv version` (Go debugger for VS Code integration) +- **kubectl** - Kubernetes cluster access +- **psql** - PostgreSQL client for database verification +- **terraform** - Terraform CLI for recipe execution +- **docker** - To host k3d + +#### Quick PostgreSQL Setup (if you don't already have one) + +The automation automatically detects and works with different PostgreSQL setups: + +**Option 1: Docker PostgreSQL (Recommended for Development)** +If you need a throwaway local PostgreSQL instance for debugging Radius: + +```bash +# Quick setup (uses postgres superuser - works with current automation) +docker run --name radius-postgres \ + -e POSTGRES_PASSWORD=radius_pass \ + -p 5432:5432 \ + -d postgres:15 +``` + +**Alternative Docker setup with custom user:** +```bash +# Custom user setup (more production-like) +docker run --name dev-postgres \ + -e POSTGRES_USER=radius_user \ + -e POSTGRES_PASSWORD=radius_pass \ + -e POSTGRES_DB=radius \ + -p 5432:5432 \ + -d postgres +``` +*Note: If using the custom user setup, you'll need to update the PostgreSQL connection variables in `build/scripts/start-radius.sh` to match.* + +**Option 2: Local PostgreSQL Installation (Homebrew/System)** +If you already have PostgreSQL installed locally (via Homebrew, apt, etc.), the automation will detect and use it automatically. + +**Automatic Database Setup** +The automation handles all database setup automatically when you run `make debug-start`: +- Creates required users (`applications_rp`, `ucp`) with proper passwords +- Creates databases with correct ownership +- Sets up proper permissions and table structures +- Works with both Docker and local PostgreSQL installations + +The automation will verify connectivity during `make debug-check-prereqs` and create all required users/databases during `make debug-start`. No manual database setup is required. + +### Optional Tools +- **VS Code** - For integrated debugging experience + +### Installation Commands + +**macOS:** +```bash +# Core tools +brew install go kubectl postgresql + +# Delve debugger +go install github.com/go-delve/delve/cmd/dlv@latest + +# Add Go binaries to PATH (required for delve) +echo 'export PATH="$HOME/go/bin:$PATH"' >> ~/.zshrc +source ~/.zshrc + +# Terraform (HashiCorp official method) +brew tap hashicorp/tap +brew install hashicorp/tap/terraform + +# Optional tools +brew install --cask docker +brew install --cask visual-studio-code +``` + +**Ubuntu/Debian:** +```bash +# Install Go 1.25+ from official source (apt version is too old) +wget https://go.dev/dl/go1.25.0.linux-amd64.tar.gz +sudo rm -rf /usr/local/go && sudo tar -C /usr/local -xzf go1.25.0.linux-amd64.tar.gz +echo 'export PATH="/usr/local/go/bin:$PATH"' >> ~/.bashrc +echo 'export PATH="$HOME/go/bin:$PATH"' >> ~/.bashrc +source ~/.bashrc + +# Core tools +sudo apt update +sudo apt install kubectl postgresql-client + +# Delve debugger +go install github.com/go-delve/delve/cmd/dlv@latest + +# Terraform (HashiCorp official method) +wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg +echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list +sudo apt update && sudo apt install terraform + +# Optional tools +sudo apt install docker.io +``` + +**Verification:** +```bash +# Check all prerequisites +make debug-check-prereqs +``` + +## Development Workflow + +### Step 1: Automated Setup and Process Management + +The automation handles all setup, configuration, and management tasks: + +```bash +# Complete setup and start development environment +make debug-start + +# This single command: +# 1. Sets up directory structure and configuration files +# 2. Builds components with debug symbols +# 3. Starts all components as OS processes +# 4. Initializes a clean dev environment with default recipes + +# Check that everything is running +make debug-status + +# Stop development environment when done +make debug-stop +``` + +### Step 2: VS Code Debugging (Optional) + +Once components are running via `make debug-start`, you can attach VS Code debuggers to debug specific components. See the [VS Code Debugging](#vs-code-debugging) section below for detailed instructions. + +### Available Make Targets + +```bash +# Setup and Configuration +make debug-help # Show all available debug commands +make debug-check-prereqs # Verify all prerequisites are installed +make debug-setup # Complete one-time environment setup + +# Development Workflow +make debug-start # Start all components as OS processes +make debug-stop # Stop all running components and clean up database +make debug-status # Show component health status +make debug-build # Build all components with debug symbols (incremental) + +# Individual Component Builds (incremental - only changed code is recompiled) +make debug-build-ucpd # Build only UCP daemon +make debug-build-applications-rp # Build only Applications RP +make debug-build-controller # Build only Controller +make debug-build-dynamic-rp # Build only Dynamic RP +make debug-build-rad # Build only rad CLI + +# Monitoring and Troubleshooting +make debug-logs # Tail all component logs + +# Complete Development Setup +make debug-dev-start # Setup + VS Code config + start components +make debug-dev-stop # Stop all components +``` + +### What the Automation Creates + +When you run `make debug-setup`, the following structure is created in `debug_files/`: + +``` +debug_files/ +β”œβ”€β”€ bin/ # Built Radius binaries with debug symbols +β”‚ β”œβ”€β”€ rad # rad CLI binary +β”‚ └── rad-wrapper # Debug wrapper that auto-configures UCP +β”œβ”€β”€ configs/ # Component configuration files +β”‚ β”œβ”€β”€ ucp.yaml +β”‚ β”œβ”€β”€ applications-rp.yaml +β”‚ β”œβ”€β”€ controller.yaml +β”‚ β”œβ”€β”€ dynamic-rp.yaml +β”‚ β”œβ”€β”€ rad-debug-config.yaml # CLI config with UCP override (used by wrapper) +β”‚ └── terraformrc +β”œβ”€β”€ logs/ # Component logs +β”œβ”€β”€ scripts/ # Management scripts +β”‚ β”œβ”€β”€ start-radius.sh +β”‚ β”œβ”€β”€ stop-radius.sh +β”‚ β”œβ”€β”€ status-radius.sh +β”‚ β”œβ”€β”€ start-deployment-engine.sh +β”‚ └── stop-deployment-engine.sh +β”œβ”€β”€ terraform-cache/ # Terraform provider cache +└── env-setup.sh # Environment variables +``` + +And VS Code configuration files are already included in the repository: + +``` +.vscode/ +β”œβ”€β”€ launch.json # Debug configurations +β”œβ”€β”€ tasks.json # VS Code tasks +β”œβ”€β”€ settings.json # Workspace settings +└── extensions.json # Recommended extensions +``` + +## VS Code Debugging + +> πŸ’‘ **Prerequisites**: You must first complete the [Automated Workflow](#automated-workflow-recommended) to have components running before you can debug them. This section describes how to attach debuggers to the already-running processes. + +> πŸ’‘ **Quick Setup**: VS Code configuration files are included in the repository and ready to use. + +### Available Debug Configurations + +The following attach-based debug configurations are available in `.vscode/launch.json`: + +- **"Attach UCP (dlv 40001)"** - Attach debugger to running UCP process +- **"Attach Controller (dlv 40002)"** - Attach debugger to running Controller process +- **"Attach Applications RP (dlv 40003)"** - Attach debugger to running Applications RP process +- **"Attach Dynamic RP (dlv 40004)"** - Attach debugger to running Dynamic RP process +- **"Attach Radius (all)"** - Compound configuration to attach to all components at once + +**CLI Debug Configuration:** +- **"Debug rad CLI (prompt for args)"** - CLI debugging with argument prompts + +All server configurations use "attach" mode - they connect to already running processes started via `make debug-start`. + +**When to use each CLI option:** +- **`./drad` command**: Use for quick CLI testing when you don't need to debug the CLI code itself. Perfect for testing server-side functionality while working on UCP, RP, or Controller code. +- **"Debug rad CLI (prompt for args)"**: Use when you need to debug CLI code with breakpoints and variable inspection. + +### Debugging Workflow in VS Code + +**Important**: This workflow assumes you have already completed the [Automated Workflow](#automated-workflow-recommended) and have components running via `make debug-start`. + +This workflow separates process management (via VS Code tasks calling make) from debugging (via VS Code debugger attach), making it much cleaner and more reliable. + +#### Step-by-Step Debugging Process + +**Prerequisites**: Start components using VS Code tasks before attaching debuggers: +- Press `Cmd+Shift+P` (or `Ctrl+Shift+P`) +- Select "Tasks: Run Task" +- Select "Debug: Start All Components" +- Wait for all components to start (check with "Debug: Component Status" task) + +1. **Set Breakpoints**: Add breakpoints in your code in VS Code + +2. **Attach Debugger** (Choose one method): + + **Method A: Attach to Individual Component** + - Open Debug panel (sidebar or `Cmd+Shift+D`) + - Select a configuration: "Attach UCP (dlv 40001)", "Attach Controller (dlv 40002)", etc. + - Press F5 or click the green play button + - The debugger will attach to the running component + + **Method B: Attach to All Components** + - Open Debug panel + - Select "Attach Radius (all)" from the dropdown + - Press F5 to attach to all components simultaneously + + **Method C: CLI Debugging** + - For CLI testing without debugging: Use `./drad ` in the terminal + - For CLI debugging with breakpoints: + - Open Debug panel + - Select "Debug rad CLI (prompt for args)" + - Press F5 + - Enter your CLI command when prompted (e.g., `env list`, `app deploy app.bicep`) + +3. **Code Changes**: + - Make your code changes + - Stop components: `Cmd+Shift+P` β†’ "Tasks: Run Task" β†’ "Debug: Stop All Components" + - Restart (rebuilds automatically): `Cmd+Shift+P` β†’ "Tasks: Run Task" β†’ "Debug: Start All Components" + - Re-attach debugger using F5 + +#### Advantages of This Approach + +- **Clean Separation**: VS Code tasks handle process lifecycle (start/stop), debugger handles debugging +- **Reliable**: Simple attach-based debugging with pre-configured ports +- **Flexible**: Debug any combination of components +- **Fast Iteration**: Stop, rebuild specific components, restart, re-attach +- **Discoverable**: All operations available via Command Palette (`Cmd+Shift+P`) + +### Debugging Specific Issues + +**Authentication Problems:** +- Set breakpoints in authentication-related code +- Monitor environment variables in the Debug Console + +**Database Issues:** +- UCP database connections are pre-configured +- PostgreSQL setup is verified during `make debug-setup` + +**Kubernetes Integration:** +- Controller uses your current kubectl context +- RBAC permissions are checked during setup + +## Troubleshooting + +### Common Issues and Solutions + +**1. Component Startup Failures** + +```bash +# Check component status +make debug-status + +# View logs for specific components +cat debug_files/logs/ucp.log +cat debug_files/logs/applications-rp.log +cat debug_files/logs/controller.log +cat debug_files/logs/dynamic-rp.log + +# Restart specific components in VS Code debugger +# Or rebuild and restart all components +make debug-stop +make debug-start +``` + +**2. Missing Prerequisites** + +```bash +# Check what's missing +make debug-check-prereqs + +# Install missing tools (example for macOS) +brew install go kubectl postgresql terraform docker + +# Verify installation +make debug-check-prereqs +``` + +**3. Database Connection Issues** + +The automation handles database setup automatically and works with your current user. If you see database errors: + +```bash +# Check if PostgreSQL is running +# macOS: +brew services start postgresql + +# Linux: +sudo systemctl start postgresql + +# Docker: +docker start radius-postgres # If using Docker PostgreSQL + +# The automation will automatically: +# - Detect your PostgreSQL installation (Docker vs local) +# - Create required users and databases +# - Set up proper permissions and table structures + +# If you need to test connections manually: +# For Docker PostgreSQL: +psql "postgresql://postgres:radius_pass@localhost:5432/postgres" -c "SELECT 1;" + +# For local PostgreSQL (Homebrew/system): +psql postgres -c "SELECT 1;" + +# Test the actual databases created by automation: +psql "postgresql://applications_rp:radius_pass@localhost:5432/applications_rp" -c "SELECT 1;" +psql "postgresql://ucp:radius_pass@localhost:5432/ucp" -c "SELECT 1;" +``` + +**4. Port Conflicts** + +```bash +# Check for port conflicts +lsof -i :9000 # UCP +lsof -i :8080 # Applications RP +lsof -i :8082 # Dynamic RP +lsof -i :7073 # Controller health +lsof -i :5017 # Deployment Engine +``` + +**5. Kubernetes Permission Issues** + +```bash +# Test current permissions +kubectl auth can-i "*" "*" --all-namespaces + +# Verify kubectl context +kubectl config current-context + +# Check if radius-system namespace exists +kubectl get namespace radius-system || kubectl create namespace radius-system + +# Check if radius-testing namespace exists +kubectl get namespace radius-testing || kubectl create namespace radius-testing +``` + +### Getting Help + +If you encounter issues not covered here: + +1. **Check the rad CLI configuration**: The `./drad` wrapper is automatically configured for local debugging +2. **Check component logs**: Use `make debug-logs` to see all component output +3. **Verify prerequisites**: Run `make debug-check-prereqs` +4. **Clean and restart**: Use `make debug-stop && make debug-start` +5. **Use VS Code debugging**: Set breakpoints and step through problematic code paths + +The automation handles ~90% of the setup complexity, but understanding the underlying components helps with advanced debugging scenarios. + +## Summary + +The Radius debug automation provides: + +βœ… **Fully Automated:** +- Directory structure creation +- Configuration file generation with correct schemas +- VS Code integration (launch.json, tasks.json, settings.json) +- Build process with debug symbols +- Component management (start/stop/status) +- Controller webhook configuration (automatic TLS certificate handling) +- Environment variables and path setup +- Deployment engine configuration +- Log aggregation and monitoring +- Health checking and verification +- Incremental builds for individual components +- Database setup + +πŸ”Ά **Partially Automated:** +- Kubernetes prerequisites (namespace creation, permission verification) +- Prerequisites validation (automated checking with installation guidance) + +❌ **Manual Steps Required:** +- Tool installation (Go, Docker, kubectl, PostgreSQL, Terraform) - one-time setup +- Cloud credentials configuration (Azure/AWS) - as needed for your development + +The automation eliminates the complexity of manual configuration while preserving the flexibility needed for advanced debugging scenarios.