Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
313 changes: 259 additions & 54 deletions Makefile

Large diffs are not rendered by default.

114 changes: 114 additions & 0 deletions deployments/dev-cluster-config.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
# k3d cluster config for Helm dev mode (DEV_MODE=helm)
# Based on single-cluster-config.yaml with additional AMP service port mappings.
# This allows all services (OpenChoreo + AMP) to run in a single k3d cluster.
apiVersion: k3d.io/v1alpha5
kind: Simple
metadata:
name: openchoreo-local-v0.14.0
image: rancher/k3s:v1.32.9-k3s1
servers: 1
agents: 0
kubeAPI:
hostPort: "6550"
ports:
# === OpenChoreo Ports (same as single-cluster-config.yaml) ===
# Control Plane uses port range 8xxx
# HTTP traffic to OpenChoreo UI and API (Kgateway LoadBalancer on port 80)
- port: 8080:80
nodeFilters:
- loadbalancer
# HTTPS traffic to OpenChoreo UI and API (Kgateway LoadBalancer on port 443)
- port: 8443:443
nodeFilters:
- loadbalancer
# Data Plane uses port range 19xxx
# HTTP traffic to workloads via Gateway
- port: 19080:19080
nodeFilters:
- loadbalancer
# HTTPS traffic to workloads via Gateway
- port: 19443:19443
nodeFilters:
- loadbalancer
# Build Plane uses port range 10xxx
# Argo Workflows UI for development testing
- port: 10081:2746
nodeFilters:
- loadbalancer
# Container Registry for storing built images
- port: 10082:5000
nodeFilters:
- loadbalancer
# Observability Plane uses port range 11xxx
# Observer API
- port: 11080:8080
nodeFilters:
- loadbalancer
# OpenSearch Dashboard
- port: 11081:5601
nodeFilters:
- loadbalancer
# OpenSearch API for Fluent Bit data pushing
- port: 11082:9200
nodeFilters:
- loadbalancer

# === AMP Service Ports ===
# Console (React frontend)
- port: 3000:3000
nodeFilters:
- loadbalancer
# Agent Manager API
- port: 9000:9000
nodeFilters:
- loadbalancer
# Internal API / Gateway Management
- port: 9243:9243
nodeFilters:
- loadbalancer
# Traces Observer Service
- port: 9098:9098
nodeFilters:
- loadbalancer

# === OTel / Observability Ports ===
# Data Prepper HTTP source
- port: 21893:21893
nodeFilters:
- loadbalancer
# OTel gRPC
- port: 22893:22893
nodeFilters:
- loadbalancer
# OTel HTTP
- port: 22894:22894
nodeFilters:
- loadbalancer
options:
k3s:
extraArgs:
# Add host.k3d.internal to API server TLS certificate SANs.
# This allows consistent DataPlane configuration across single and multi-cluster setups
# where Control Plane pods can access the API server via host.k3d.internal:6550
- arg: "--tls-san=host.k3d.internal"
nodeFilters:
- server:*
# Configure kubelet eviction thresholds to prevent resource exhaustion
- arg: "--kubelet-arg=eviction-hard=imagefs.available<1%,nodefs.available<1%"
nodeFilters:
- server:*
- arg: "--kubelet-arg=eviction-minimum-reclaim=imagefs.available=1%,nodefs.available=1%"
nodeFilters:
- server:*
# Disable Traefik to avoid conflicts with OpenChoreo Gateway controller
- arg: "--disable=traefik"
nodeFilters:
- server:*
# Configure insecure registries for HTTP access
# Allows kubelet to pull images from Build Plane registry via HTTP
registries:
config: |
mirrors:
"host.k3d.internal:10082":
endpoint:
- http://host.k3d.internal:10082
86 changes: 86 additions & 0 deletions deployments/scripts/build-and-import.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
#!/bin/bash
set -e

# Build Docker images from production Dockerfiles and import them into k3d.
# Usage:
# ./build-and-import.sh # Build and import all components
# ./build-and-import.sh api # Build and import API only
# ./build-and-import.sh console api # Build and import Console and API
#
# Supported components: api, console, traces-observer, evaluation-job

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"

source "$SCRIPT_DIR/env.sh"

# Components and their build contexts (relative to ROOT_DIR)
declare -A COMPONENT_CONTEXT=(
[api]="agent-manager-service"
[console]="console"
[traces-observer]="traces-observer-service"
[evaluation-job]="evaluation-job"
)

declare -A COMPONENT_IMAGE=(
[api]="amp-api"
[console]="amp-console"
[traces-observer]="amp-traces-observer"
[evaluation-job]="amp-evaluation-job"
)
Comment on lines +18 to +30
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical

🧩 Analysis chain

🏁 Script executed:

cat -n deployments/scripts/build-and-import.sh | head -n 35

Repository: wso2/agent-manager

Length of output: 1357


🏁 Script executed:

# Check what Bash version shows declare -A support issue
# First, let's see if the file exists and its content
file deployments/scripts/build-and-import.sh
wc -l deployments/scripts/build-and-import.sh

Repository: wso2/agent-manager

Length of output: 164


🏁 Script executed:

# Run the verification script from the review comment
echo "Checking /bin/bash version..."
/bin/bash --version | head -n1

echo
echo "Checking associative array support in /bin/bash..."
if /bin/bash -lc 'declare -A m=([k]=v); echo ok' >/dev/null 2>&1; then
  echo "PASS: /bin/bash supports associative arrays."
else
  echo "FAIL: /bin/bash does not support associative arrays."
fi

echo
echo "Locating associative-array usage in repo:"
rg -n 'declare -A' deployments/scripts/build-and-import.sh || echo "No matches found"

Repository: wso2/agent-manager

Length of output: 355


Add Bash 4+ version guard to prevent script failure on macOS.

The script uses declare -A (associative arrays) on lines 18 and 25, which requires Bash 4+. Default macOS /bin/bash is version 3.2 (due to Apple's GPL licensing constraints), causing the script to fail immediately on standard macOS systems before any build/import work runs.

Add this check after sourcing env.sh
 source "$SCRIPT_DIR/env.sh"

+# Require Bash 4+ for associative arrays.
+if [ "${BASH_VERSINFO[0]}" -lt 4 ]; then
+    echo "This script requires Bash 4+ (found ${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]})."
+    echo "Use a newer bash (e.g., via Homebrew) or refactor to avoid associative arrays."
+    exit 1
+fi
+
 # Components and their build contexts (relative to ROOT_DIR)
 declare -A COMPONENT_CONTEXT=(
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@deployments/scripts/build-and-import.sh` around lines 18 - 30, After sourcing
env.sh, add a Bash version guard that checks the current shell is Bash >= 4 and
exits with a clear error if not; specifically validate BASH_VERSINFO (or bash
--version) before the script reaches the declare -A usage for COMPONENT_CONTEXT
and COMPONENT_IMAGE so the script fails with a helpful message on macOS rather
than crashing at the declare -A lines, and include guidance to run with a newer
bash (e.g., brew-installed bash) or using env to find the correct interpreter.


ALL_COMPONENTS="api console traces-observer evaluation-job"

# Determine which components to build
if [ $# -eq 0 ]; then
COMPONENTS="$ALL_COMPONENTS"
else
COMPONENTS="$*"
fi

# Validate component names
for comp in $COMPONENTS; do
if [ -z "${COMPONENT_CONTEXT[$comp]}" ]; then
echo "Unknown component: $comp"
echo "Valid components: $ALL_COMPONENTS"
exit 1
fi
done

echo "=== Building and importing images into k3d ==="
echo ""

# Verify k3d cluster exists
if ! k3d cluster list 2>/dev/null | grep -q "${CLUSTER_NAME}"; then
echo "k3d cluster '${CLUSTER_NAME}' not found. Run 'make setup-k3d' first."
exit 1
fi

FAILED=""

for comp in $COMPONENTS; do
IMAGE="${COMPONENT_IMAGE[$comp]}:${AMP_IMAGE_TAG}"
CONTEXT="${ROOT_DIR}/${COMPONENT_CONTEXT[$comp]}"

echo "Building ${comp} -> ${IMAGE}..."
if docker build -t "$IMAGE" "$CONTEXT" --quiet; then
echo "Importing ${IMAGE} into k3d cluster..."
if k3d image import "$IMAGE" -c "${CLUSTER_NAME}"; then
echo "${comp} ready."
else
echo "Failed to import ${comp}."
FAILED="$FAILED $comp"
fi
else
echo "Failed to build ${comp}."
FAILED="$FAILED $comp"
fi
echo ""
done

if [ -n "$FAILED" ]; then
echo "Failed components:${FAILED}"
exit 1
fi

echo "All images built and imported successfully."
5 changes: 5 additions & 0 deletions deployments/scripts/env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,8 @@ OPENCHOREO_VERSION="0.14.0"
OPENCHOREO_PATCH_VERSION="0.0.0-b53c6dc3"
CLUSTER_NAME="openchoreo-local-v${OPENCHOREO_VERSION}"
CLUSTER_CONTEXT="k3d-${CLUSTER_NAME}"

# AMP (Agent Management Platform) variables
AMP_NAMESPACE="wso2-amp"
AMP_RELEASE_NAME="amp"
AMP_IMAGE_TAG="0.0.0-dev"
70 changes: 70 additions & 0 deletions deployments/scripts/helm-deploy-amp.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#!/bin/bash
set -e

# Deploy AMP to the k3d cluster using Helm.
# Usage:
# ./helm-deploy-amp.sh # Install or upgrade
# ./helm-deploy-amp.sh --uninstall # Uninstall (preserves cluster)

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "$SCRIPT_DIR/../.." && pwd)"
CHART_DIR="$ROOT_DIR/deployments/helm-charts/wso2-agent-manager"
VALUES_FILE="$ROOT_DIR/deployments/values/values-local.yaml"

source "$SCRIPT_DIR/env.sh"

if [ "$1" = "--uninstall" ]; then
echo "=== Uninstalling AMP from k3d ==="
if helm status "$AMP_RELEASE_NAME" -n "$AMP_NAMESPACE" --kube-context "${CLUSTER_CONTEXT}" &>/dev/null; then
helm uninstall "$AMP_RELEASE_NAME" -n "$AMP_NAMESPACE" --kube-context "${CLUSTER_CONTEXT}"
echo "AMP uninstalled. Cluster and namespace preserved."
else
echo "AMP release '${AMP_RELEASE_NAME}' not found in namespace '${AMP_NAMESPACE}'."
fi
exit 0
fi

echo "=== Deploying AMP to k3d cluster ==="
echo ""

# Verify cluster is accessible
if ! kubectl cluster-info --context "${CLUSTER_CONTEXT}" &>/dev/null; then
echo "k3d cluster '${CLUSTER_NAME}' is not accessible."
echo "Run 'make setup-k3d' or 'k3d cluster start ${CLUSTER_NAME}' first."
exit 1
fi

# Create namespace if it doesn't exist
kubectl create namespace "$AMP_NAMESPACE" --context "${CLUSTER_CONTEXT}" --dry-run=client -o yaml | \
kubectl apply --context "${CLUSTER_CONTEXT}" -f -

# Update Helm dependencies
echo "Updating Helm chart dependencies..."
helm dependency update "$CHART_DIR"
echo ""

# Install or upgrade
echo "Running helm upgrade --install..."
helm upgrade --install "$AMP_RELEASE_NAME" "$CHART_DIR" \
--namespace "$AMP_NAMESPACE" \
--kube-context "${CLUSTER_CONTEXT}" \
--values "$VALUES_FILE" \
--wait \
--timeout 5m

echo ""
echo "Waiting for deployments to be ready..."
kubectl wait --for=condition=Available deployment --all \
-n "$AMP_NAMESPACE" \
--context "${CLUSTER_CONTEXT}" \
--timeout=300s 2>/dev/null || true

echo ""
echo "AMP deployed successfully!"
Comment on lines +57 to +63
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Don’t suppress deployment readiness failures.

Line 60 uses || true, so the script can print “AMP deployed successfully!” even when deployments are not actually Available.

Suggested fix
 kubectl wait --for=condition=Available deployment --all \
     -n "$AMP_NAMESPACE" \
     --context "${CLUSTER_CONTEXT}" \
-    --timeout=300s 2>/dev/null || true
+    --timeout=300s
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
kubectl wait --for=condition=Available deployment --all \
-n "$AMP_NAMESPACE" \
--context "${CLUSTER_CONTEXT}" \
--timeout=300s 2>/dev/null || true
echo ""
echo "AMP deployed successfully!"
kubectl wait --for=condition=Available deployment --all \
-n "$AMP_NAMESPACE" \
--context "${CLUSTER_CONTEXT}" \
--timeout=300s
echo ""
echo "AMP deployed successfully!"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@deployments/scripts/helm-deploy-amp.sh` around lines 57 - 63, The kubectl
wait call that uses "kubectl wait --for=condition=Available deployment --all -n
\"$AMP_NAMESPACE\" --context \"${CLUSTER_CONTEXT}\" --timeout=300s 2>/dev/null
|| true" is suppressing failures; remove the "|| true" and stop swallowing
stderr so the script can detect non-zero exit: run the kubectl wait without
trailing "|| true", keep or remove the 2>/dev/null as desired, and if the
kubectl wait command fails, log an error (including AMP_NAMESPACE and
CLUSTER_CONTEXT) and exit with a non-zero status so the script does not print
"AMP deployed successfully!" on failed readiness.

echo ""
echo "Services:"
echo " Console: http://localhost:3000"
echo " API: http://localhost:9000"
echo ""
echo "Status:"
kubectl get pods -n "$AMP_NAMESPACE" --context "${CLUSTER_CONTEXT}"
36 changes: 32 additions & 4 deletions deployments/scripts/setup-k3d.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,14 @@ cd "$SCRIPT_DIR"

source "$SCRIPT_DIR/env.sh"

echo "=== Setting up k3d Cluster for OpenChoreo ==="
# Select k3d config based on DEV_MODE
if [ "${DEV_MODE}" = "helm" ]; then
K3D_CONFIG="../dev-cluster-config.yaml"
echo "=== Setting up k3d Cluster for OpenChoreo + AMP (Helm mode) ==="
else
K3D_CONFIG="../single-cluster-config.yaml"
echo "=== Setting up k3d Cluster for OpenChoreo ==="
fi

# Check prerequisites
if ! command -v k3d &> /dev/null; then
Expand Down Expand Up @@ -52,6 +59,27 @@ if k3d cluster list 2>/dev/null | grep -q "${CLUSTER_NAME}"; then
done
fi

# When using Helm mode, verify AMP ports are mapped
if [ "${DEV_MODE}" = "helm" ]; then
echo ""
echo "🔍 Checking AMP port mappings..."
MISSING_PORTS=""
for PORT in 3000 9000; do
if ! docker port "k3d-${CLUSTER_NAME}-serverlb" "${PORT}/tcp" &>/dev/null; then
MISSING_PORTS="${MISSING_PORTS} ${PORT}"
fi
done
Comment on lines +67 to +71
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Helm port validation is incomplete.

At Line 67, the check only verifies 3000 and 9000. Helm mode also relies on 9243, 9098, and OTel ports (21893, 22893, 22894), so an existing cluster can pass this check but still be misconfigured.

Suggested fix
-        for PORT in 3000 9000; do
+        for PORT in 3000 9000 9243 9098 21893 22893 22894; do
             if ! docker port "k3d-${CLUSTER_NAME}-serverlb" "${PORT}/tcp" &>/dev/null; then
                 MISSING_PORTS="${MISSING_PORTS} ${PORT}"
             fi
         done
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
for PORT in 3000 9000; do
if ! docker port "k3d-${CLUSTER_NAME}-serverlb" "${PORT}/tcp" &>/dev/null; then
MISSING_PORTS="${MISSING_PORTS} ${PORT}"
fi
done
for PORT in 3000 9000 9243 9098 21893 22893 22894; do
if ! docker port "k3d-${CLUSTER_NAME}-serverlb" "${PORT}/tcp" &>/dev/null; then
MISSING_PORTS="${MISSING_PORTS} ${PORT}"
fi
done
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@deployments/scripts/setup-k3d.sh` around lines 67 - 71, The port-check loop
only tests 3000 and 9000; expand it to include all Helm-required ports (9243,
9098, 21893, 22893, 22894) so the check properly detects missing mappings:
update the for PORT in ... loop that references CLUSTER_NAME and appends to
MISSING_PORTS (the docker port "k3d-${CLUSTER_NAME}-serverlb" "${PORT}/tcp"
call) to iterate over the full set of ports and keep the same MISSING_PORTS
behavior when a port is absent.

if [ -n "$MISSING_PORTS" ]; then
echo "⚠️ AMP ports not mapped:${MISSING_PORTS}"
echo " The cluster was created without AMP port mappings."
echo " To fix, delete and recreate the cluster:"
echo " k3d cluster delete ${CLUSTER_NAME}"
echo " DEV_MODE=helm make setup-k3d"
else
echo "✅ AMP ports are mapped correctly"
fi
fi

echo ""
echo "Cluster info:"
kubectl cluster-info --context ${CLUSTER_CONTEXT}
Expand All @@ -62,9 +90,9 @@ else
echo "📁 Creating shared directory for OpenChoreo..."
mkdir -p /tmp/k3d-shared

# Create k3d cluster with OpenChoreo configuration
echo "🚀 Creating k3d cluster with OpenChoreo configuration..."
k3d cluster create --config ../single-cluster-config.yaml
# Create k3d cluster with appropriate configuration
echo "🚀 Creating k3d cluster with config: ${K3D_CONFIG}..."
k3d cluster create --config "${K3D_CONFIG}"

echo ""
echo "✅ k3d cluster created successfully!"
Expand Down
Loading