Skip to content
Closed
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
6 changes: 5 additions & 1 deletion .github/scripts/publish-recipes.sh
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,9 @@ for RECIPE in $(find "$DIRECTORY" -type f -name "*.bicep"); do

echo "Publishing $RECIPE to $PUBLISH_REF"
echo "- $PUBLISH_REF" >>$GITHUB_STEP_SUMMARY
rad bicep publish --file $RECIPE --target "br:$PUBLISH_REF"
PUBLISH_FLAGS=()
if [[ "${PLAIN_HTTP:-false}" == "true" ]]; then
PUBLISH_FLAGS+=(--plain-http)
fi
rad bicep publish --file "$RECIPE" --target "br:$PUBLISH_REF" "${PUBLISH_FLAGS[@]}"
done
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ debug_files/*
drad
*.lock

# Local-only bicepconfig override written by `make debug-publish-bicep-types`.
# Lives next to the .bicep templates so bicep's nearest-config search picks it up
# over the tracked sibling at .../resources/bicepconfig.json. Removed by debug-stop.
test/functional-portable/dynamicrp/noncloud/resources/testdata/bicepconfig.json

# Demo app
demo/*
demo
Expand Down
380 changes: 365 additions & 15 deletions build/debug.mk

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion build/recipes.mk
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ publish-test-bicep-recipes: ## Publishes test recipes to <BICEP_RECIPE_REGISTRY>
@if [ -z "$(BICEP_RECIPE_REGISTRY)" ]; then echo "Error: BICEP_RECIPE_REGISTRY must be set to a valid OCI registry"; exit 1; fi

@echo "$(ARROW) Publishing Bicep test recipes from ./test/testrecipes/test-bicep-recipes..."
./.github/scripts/publish-recipes.sh \
PLAIN_HTTP=$(BICEP_RECIPE_PLAIN_HTTP) ./.github/scripts/publish-recipes.sh \
./test/testrecipes/test-bicep-recipes \
${BICEP_RECIPE_REGISTRY}/test/testrecipes/test-bicep-recipes \
${BICEP_RECIPE_TAG_VERSION}
Expand Down
460 changes: 460 additions & 0 deletions build/scripts/azure-local-testenv.sh

Large diffs are not rendered by default.

53 changes: 53 additions & 0 deletions build/scripts/ensure-encryption-key.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#!/usr/bin/env bash
# Ensure the radius-encryption-key Secret exists in the radius-system namespace
# of the k3d-radius-debug cluster. dynamic-rp (and other Radius components that
# use the encryption key provider) refuse to start without it.
#
# The Helm chart (deploy/Chart/templates/dynamic-rp/secret.yaml) normally
# creates this. The OS-process debug stack skips Helm, so we recreate the same
# secret format here.
#
# This script is idempotent: if the secret already exists, it does nothing.

set -euo pipefail

CONTEXT="${KUBE_CONTEXT:-k3d-radius-debug}"
NAMESPACE="${RADIUS_NAMESPACE:-radius-system}"
SECRET_NAME="radius-encryption-key"

if ! command -v kubectl >/dev/null 2>&1; then
echo "❌ kubectl not found"
exit 1
fi

if ! kubectl --context "$CONTEXT" cluster-info >/dev/null 2>&1; then
echo "❌ cluster $CONTEXT not reachable"
exit 1
fi

# Ensure namespace exists
kubectl --context "$CONTEXT" get namespace "$NAMESPACE" >/dev/null 2>&1 \
|| kubectl --context "$CONTEXT" create namespace "$NAMESPACE" >/dev/null

# If the secret already exists, leave it alone.
if kubectl --context "$CONTEXT" -n "$NAMESPACE" get secret "$SECRET_NAME" >/dev/null 2>&1; then
echo "✅ Secret $NAMESPACE/$SECRET_NAME already exists"
exit 0
fi

# Generate a 32-byte random key and build the JSON keystore the same way the
# Helm chart does.
now_iso="$(date -u +%Y-%m-%dT%H:%M:%SZ)"
expiry_iso="$(date -u -v+90d +%Y-%m-%dT%H:%M:%SZ 2>/dev/null \
|| date -u -d '+90 days' +%Y-%m-%dT%H:%M:%SZ)"
key_b64="$(head -c 32 /dev/urandom | base64 | tr -d '\n')"

keystore_json=$(cat <<EOF
{"currentVersion":1,"keys":{"1":{"key":"${key_b64}","version":1,"createdAt":"${now_iso}","expiresAt":"${expiry_iso}"}}}
EOF
)

kubectl --context "$CONTEXT" -n "$NAMESPACE" create secret generic "$SECRET_NAME" \
--from-literal=keys.json="$keystore_json" >/dev/null

echo "✅ Created secret $NAMESPACE/$SECRET_NAME (random 32-byte key, 90-day expiry)"
110 changes: 110 additions & 0 deletions build/scripts/mirror-test-images.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#!/usr/bin/env bash
# Copy upstream multi-arch container images into the
# ghcr.io/radius-project/mirror/* namespace, preserving the full OCI index
# (i.e. all platforms) so the same tag works on amd64 (CI) and arm64
# (Apple Silicon dev machines / k3d). Uses `docker buildx imagetools create`,
# which performs a server-side blob mount when source and destination are on
# the same registry, and otherwise a streaming copy.
#
# Requirements:
# - docker (with buildx, included in Docker Desktop)
# - You must be logged in to ghcr.io with a token that has write:packages.
# Easiest: `echo $GH_PACKAGES_TOKEN | docker login ghcr.io -u <user> --password-stdin`
# The token used by `gh auth login` does NOT include write:packages by default;
# create a Classic PAT with the `write:packages` scope.
#
# Usage:
# build/scripts/mirror-test-images.sh # mirror the default list below
# build/scripts/mirror-test-images.sh --dry-run # show what would be copied
# build/scripts/mirror-test-images.sh src=dst # mirror a single mapping
#
# Each mapping is SRC=DST_TAG where:
# SRC = fully-qualified upstream reference (e.g. docker.io/library/rabbitmq:3.12-management-alpine)
# DST_TAG = destination repo+tag under ghcr.io/radius-project/mirror/
# (e.g. rabbitmq:3.12-management-alpine)

set -euo pipefail

DEST_PREFIX="ghcr.io/radius-project/mirror"

# Default mappings. Every source MUST be multi-arch (at least linux/amd64 +
# linux/arm64) for the destination to be usable from both CI and arm64 dev
# machines. Verify with `docker buildx imagetools inspect <src>` before adding.
DEFAULT_MAPPINGS=(
# These mirror the exact same tags already referenced by tests / recipes.
# The previous mirror entries were pushed as single-arch (linux/amd64 only)
# blobs, which breaks tests on arm64 dev machines (e.g. rabbitmq 3.10 BEAM
# crashes under QEMU). Re-mirroring with buildx imagetools create copies the
# full upstream OCI index so all platforms work.
"docker.io/library/rabbitmq:3.10=rabbitmq:3.10"
"docker.io/library/redis:6.2=redis:6.2"
"docker.io/library/mongo:4.2=mongo:4.2"
"docker.io/library/postgres:latest=postgres:latest"
"docker.io/library/debian:latest=debian:latest"
)

dry_run=0
mappings=()
for arg in "$@"; do
case "$arg" in
--dry-run) dry_run=1 ;;
-h|--help) sed -n '1,30p' "$0"; exit 0 ;;
*=*) mappings+=("$arg") ;;
*) echo "unknown argument: $arg" >&2; exit 2 ;;
esac
done

if [[ ${#mappings[@]} -eq 0 ]]; then
mappings=("${DEFAULT_MAPPINGS[@]}")
fi

if ! command -v docker >/dev/null 2>&1; then
echo "docker is required" >&2; exit 1
fi
if ! docker buildx version >/dev/null 2>&1; then
echo "docker buildx is required (included with Docker Desktop)" >&2; exit 1
fi
Comment on lines +61 to +66

echo "Mirroring ${#mappings[@]} image(s) to ${DEST_PREFIX}/*"
for m in "${mappings[@]}"; do
src="${m%%=*}"
dst_suffix="${m#*=}"
dst="${DEST_PREFIX}/${dst_suffix}"
echo
echo "==> ${src}"
echo " -> ${dst}"

# Verify source is multi-arch before copying. The destination will inherit
# whatever platforms the source has, so a single-arch source means we did
# not solve the original problem.
platforms="$(docker buildx imagetools inspect --raw "${src}" 2>/dev/null \
| python3 -c '
import json,sys
try:
d=json.load(sys.stdin)
except Exception:
print(""); sys.exit(0)
m=d.get("manifests")
if not m:
print(""); sys.exit(0)
print(",".join(sorted({x["platform"]["os"]+"/"+x["platform"]["architecture"]
for x in m if "platform" in x and x["platform"].get("os")!="unknown"})))
')"
if [[ -z "${platforms}" ]]; then
echo " !! source is single-arch (no manifest index); refusing to mirror" >&2
exit 1
fi
if [[ "${platforms}" != *"linux/amd64"* || "${platforms}" != *"linux/arm64"* ]]; then
echo " !! source must include both linux/amd64 and linux/arm64; got: ${platforms}" >&2
exit 1
fi
echo " platforms: ${platforms}"

if [[ "${dry_run}" -eq 1 ]]; then
continue
fi
docker buildx imagetools create --tag "${dst}" "${src}"
done

echo
echo "Done."
6 changes: 6 additions & 0 deletions build/scripts/start-radius.sh
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,12 @@ fi
# Ensure logs directory exists
mkdir -p "$DEBUG_ROOT/logs"

# Use a writable Terraform global cache directory for local OS-process runs.
# The default `/terraform` path only exists inside the Radius container image
# and would fail with "read-only file system" on host filesystems.
export TERRAFORM_TEST_GLOBAL_DIR="${TERRAFORM_TEST_GLOBAL_DIR:-$DEBUG_ROOT/terraform-global}"
mkdir -p "$TERRAFORM_TEST_GLOBAL_DIR"

# Check prerequisites
check_prerequisites

Expand Down
81 changes: 79 additions & 2 deletions build/test.mk
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,40 @@ TEST_TIMEOUT ?=1h
RADIUS_CONTAINER_LOG_PATH ?=./dist/container_logs
REL_VERSION ?=latest
DOCKER_REGISTRY ?=ghcr.io/radius-project/dev

# Auto-detect the local debug OCI registry started by `make debug-publish-recipes`.
# When it is running and the user has not explicitly set BICEP_RECIPE_REGISTRY,
# point the functional tests at it so the locally-published test recipes are used
# instead of the (private) ghcr.io fallback.
ifeq ($(origin BICEP_RECIPE_REGISTRY), undefined)
ifneq ($(shell docker ps --format '{{.Names}}' 2>/dev/null | grep -x radius-debug-registry),)
export BICEP_RECIPE_REGISTRY := localhost:5000
export BICEP_RECIPE_TAG_VERSION ?= latest
$(info Using local debug recipe registry: BICEP_RECIPE_REGISTRY=$(BICEP_RECIPE_REGISTRY) BICEP_RECIPE_TAG_VERSION=$(BICEP_RECIPE_TAG_VERSION))
# When the debug-built rad CLI is available, point the functional tests at it
# (via RAD_PATH, honored by test/radcli/cli.go) so they exercise the HEAD CLI
# matching the locally-running control plane, not any system-installed rad.
ifneq ($(wildcard $(CURDIR)/debug_files/bin/rad),)
export RAD_PATH := $(CURDIR)/debug_files/bin
$(info Using debug-built rad CLI: RAD_PATH=$(RAD_PATH))
endif
endif
endif

# Auto-detect the in-cluster Git HTTP backend started by `make debug-install-git-http-backend`.
# When its port-forward PID file exists and the process is alive, export the
# GIT_HTTP_* variables that the kubernetes-noncloud Flux tests expect.
ifeq ($(origin GIT_HTTP_SERVER_URL), undefined)
ifneq ($(wildcard $(CURDIR)/debug_files/logs/git-http-port-forward.pid),)
ifneq ($(shell pid=$$(cat $(CURDIR)/debug_files/logs/git-http-port-forward.pid 2>/dev/null); kill -0 $$pid 2>/dev/null && echo up),)
export GIT_HTTP_SERVER_URL := http://localhost:30080
export GIT_HTTP_USERNAME ?= testuser
export GIT_HTTP_PASSWORD ?= not-a-secret-password
export GIT_HTTP_EMAIL ?= testuser@radapp.io
$(info Using local git-http-backend: GIT_HTTP_SERVER_URL=$(GIT_HTTP_SERVER_URL))
endif
endif
endif
ENVTEST_ASSETS_DIR=$(shell pwd)/bin
K8S_VERSION=1.30.*
ENV_SETUP=$(GOBIN)/setup-envtest$(BINARY_EXT)
Expand All @@ -50,8 +84,13 @@ GOTEST_TOOL ?= go test
else
# Use these options by default but allow an override via env-var
GOTEST_OPTS ?=
# We need the double dash here to separate the 'gotestsum' options from the 'go test' options
GOTEST_TOOL ?= gotestsum $(GOTESTSUM_OPTS) --
# When set, a per-target JSON timing file is emitted as $(GOTESTSUM_JSONFILE_DIR)/<target>.jsonl.
# This avoids the file being overwritten by each sub-target in test-functional-all-*.
# Example: GOTESTSUM_JSONFILE_DIR=/tmp/timings make test-functional-all-noncloud
GOTESTSUM_JSONFILE_DIR ?=
# Recursive '=' so $@ resolves in each recipe's context.
# We need the double dash here to separate the 'gotestsum' options from the 'go test' options.
GOTEST_TOOL = gotestsum $(GOTESTSUM_OPTS)$(if $(GOTESTSUM_JSONFILE_DIR), --jsonfile=$(GOTESTSUM_JSONFILE_DIR)/$@.jsonl) --
endif

.PHONY: test
Expand Down Expand Up @@ -162,6 +201,44 @@ test-functional-samples: test-functional-samples-noncloud ## Runs all Samples fu
test-functional-samples-noncloud: ## Runs Samples functional tests that do not require cloud resources
CGO_ENABLED=1 $(GOTEST_TOOL) ./test/functional-portable/samples/noncloud/... -timeout ${TEST_TIMEOUT} -v -parallel 5 $(GOTEST_OPTS)

# ----------------------------------------------------------------------------
# Local Azure functional tests
#
# These targets orchestrate an ephemeral Azure resource group, deploy the test
# fixtures (Cosmos Mongo for Test_AzureConnections), run the Test_Azure* subset
# of corerp-cloud tests against your locally-running Radius stack (make
# debug-start) using ambient `az login` credentials, and tear everything down.
#
# Prerequisites:
# - `az login` succeeded for the target subscription.
# - `make debug-start` is running (OS-process Radius).
# - Deployment Engine is running locally on :5017 (NOT in a container) so it
# can use the az CLI fallback. See debug_files/logs/de-external.marker.
#
# NOTE: AWS is intentionally out of scope for this iteration.
# ----------------------------------------------------------------------------
AZURE_LOCAL_TESTENV := ./build/scripts/azure-local-testenv.sh

.PHONY: test-functional-azure-local-setup
test-functional-azure-local-setup: ## Provision an ephemeral Azure RG and fixtures for local Azure functional tests.
@$(AZURE_LOCAL_TESTENV) setup

.PHONY: test-functional-azure-local-run
test-functional-azure-local-run: ## Run Test_Azure* against the locally-running Radius stack using the env from setup.
@$(AZURE_LOCAL_TESTENV) run

.PHONY: test-functional-azure-local-teardown
test-functional-azure-local-teardown: ## Delete the ephemeral Azure RG and clear local Azure test state.
@$(AZURE_LOCAL_TESTENV) teardown

.PHONY: test-functional-azure-local
test-functional-azure-local: ## Setup -> run Test_Azure* -> teardown (teardown runs even on test failure).
@$(AZURE_LOCAL_TESTENV) all

.PHONY: test-functional-azure-local-keep
test-functional-azure-local-keep: ## Same as test-functional-azure-local but skips teardown on failure (post-mortem).
@AZURE_LOCAL_KEEP_ON_FAILURE=1 $(AZURE_LOCAL_TESTENV) all

.PHONY: test-validate-bicep
test-validate-bicep: ## Validates that all .bicep files compile cleanly
BICEP_PATH="${HOME}/.rad/bin/bicep" ./build/validate-bicep.sh
Expand Down
Loading
Loading