From e6bafc3f8c89d24144af838cfa6e6948535801f3 Mon Sep 17 00:00:00 2001 From: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> Date: Mon, 26 May 2025 10:54:09 -0700 Subject: [PATCH 01/14] make workflow Signed-off-by: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> --- Makefile | 2 +- build/workflow-helper.sh | 322 +++++++++++++++++++++++++++++++++++++++ build/workflow.mk | 62 ++++++++ 3 files changed, 385 insertions(+), 1 deletion(-) create mode 100755 build/workflow-helper.sh create mode 100644 build/workflow.mk diff --git a/Makefile b/Makefile index 8046daedfb..d15df33135 100644 --- a/Makefile +++ b/Makefile @@ -17,4 +17,4 @@ ARROW := \033[34;1m=>\033[0m # order matters for these -include build/help.mk build/version.mk build/build.mk build/util.mk build/generate.mk build/test.mk build/docker.mk build/recipes.mk build/install.mk build/db.mk build/prettier.mk build/debug.mk \ No newline at end of file +include build/help.mk build/version.mk build/build.mk build/util.mk build/generate.mk build/test.mk build/docker.mk build/recipes.mk build/install.mk build/db.mk build/prettier.mk build/debug.mk build/workflow.mk \ No newline at end of file diff --git a/build/workflow-helper.sh b/build/workflow-helper.sh new file mode 100755 index 0000000000..c2ba633b57 --- /dev/null +++ b/build/workflow-helper.sh @@ -0,0 +1,322 @@ +#!/bin/bash +# ------------------------------------------------------------ +# Copyright 2023 The Radius Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ------------------------------------------------------------ + +set -euo pipefail + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Function to print colored output +print_info() { + echo -e "${BLUE}ℹ${NC} $1" +} + +print_success() { + echo -e "${GREEN}✓${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}⚠${NC} $1" +} + +print_error() { + echo -e "${RED}✗${NC} $1" +} + +# Check if we're in a radius-project organization repo for security +check_org_restriction() { + local operation="$1" + local repo_url + repo_url=$(git remote get-url origin 2>/dev/null || echo "") + + if [[ "$repo_url" == *"radius-project/"* ]]; then + print_info "Operation '$operation' should only be used on personal forks." + exit 1 + fi +} + +# Check if GitHub CLI is installed and authenticated +check_gh_cli() { + if ! command -v gh &> /dev/null; then + print_error "GitHub CLI (gh) is required but not installed." + print_info "Please install it from: https://cli.github.com/" + exit 1 + fi + + # Check if GITHUB_TOKEN or GH_TOKEN environment variables are already set + if [[ -n "${GITHUB_TOKEN:-}" ]] || [[ -n "${GH_TOKEN:-}" ]]; then + return 0 + fi + + # Check if user is authenticated and get token + local token + if ! token=$(gh auth token 2>/dev/null); then + print_error "GitHub CLI is not authenticated." + print_info "Please run 'gh auth login' to authenticate." + exit 1 + fi + + if [[ -z "$token" ]]; then + print_error "Unable to retrieve GitHub authentication token." + print_info "Please run 'gh auth login' to authenticate." + exit 1 + fi + + export GITHUB_TOKEN="$token" +} + +# Get repository info +get_repo_info() { + + # Verify we're in a git repository + if ! git rev-parse --git-dir &> /dev/null; then + print_error "Not in a git repository." + exit 1 + fi + + local repo_url + repo_url=$(git remote get-url origin 2>/dev/null) + + if [[ -z "$repo_url" ]]; then + print_error "Not in a git repository or no origin remote found." + exit 1 + fi + + # Check if it's a GitHub repository + if [[ "$repo_url" != *"github.com"* ]]; then + print_error "Repository is not hosted on GitHub." + exit 1 + fi + + # Remove https://github.com/ from the beginning + repo_url="${repo_url#https://github.com/}" + + # Remove .git from the end if present + repo_url="${repo_url%.git}" + + echo "$repo_url" +} + +# Dispatch a workflow +dispatch_workflow() { + local workflow_name="$1" + local branch="$2" + + print_info "Dispatching workflow '$workflow_name' on branch '$branch'..." + + # Check if workflow file exists + if [[ ! -f ".github/workflows/$workflow_name" ]]; then + print_error "Workflow file '.github/workflows/$workflow_name' not found." + print_info "Available workflows:" + list_workflows + exit 1 + fi + + # Attempt to dispatch the workflow + if gh workflow run "$workflow_name" --ref "$branch"; then + print_success "Workflow '$workflow_name' dispatched successfully on branch '$branch'." + print_info "You can view the workflow run at: $(gh repo view --web --branch "$branch" 2>/dev/null || echo "GitHub repository page")" + else + print_error "Failed to dispatch workflow '$workflow_name'." + print_info "Make sure the workflow supports manual triggering (workflow_dispatch event)." + exit 1 + fi +} + +# List all workflows +list_workflows() { + local REPO_NAME=$1 + print_info "Available workflows for $REPO_NAME:" + + local workflows + workflows=$(gh workflow list --all --repo "$REPO_NAME" --json name,path,state --jq '.[] | "\(.path)|\(.name)|\(.state)"' 2>/dev/null) + + if [[ -n "$workflows" ]]; then + while IFS='|' read -r path name state; do + local filename + filename=$(basename "$path") + printf " %-30s %-40s %s\n" "$filename" "($name)" "[$state]" + done <<< "$workflows" + else + print_warning "No workflows found or unable to retrieve workflow information." + fi +} + +# Disable a workflow +disable_workflow() { + local workflow_name="$1" + local REPO_NAME="$2" + + check_org_restriction "disable workflow" + + print_info "Disabling workflow '$workflow_name'..." + + if gh workflow disable --repo "$REPO_NAME" "$workflow_name"; then + print_success "Workflow '$workflow_name' disabled successfully." + else + print_error "Failed to disable workflow '$workflow_name'." + print_info "Make sure the workflow name is correct. Use 'make workflow-list' to see available workflows." + exit 1 + fi +} + +# Enable a workflow +enable_workflow() { + local workflow_name="$1" + local REPO_NAME="$2" + + print_info "Enabling workflow '$workflow_name'..." + + if gh workflow enable --repo "$REPO_NAME" "$workflow_name"; then + print_success "Workflow '$workflow_name' enabled successfully." + else + print_error "Failed to enable workflow '$workflow_name'." + print_info "Make sure the workflow name is correct. Use 'make workflow-list' to see available workflows." + exit 1 + fi +} + +# Disable all triggered workflows +disable_triggered_workflows() { + check_org_restriction "disable triggered workflows" + + print_info "Disabling all workflows triggered by events..." + + local disabled_count=0 + + # Get list of workflows and their trigger events + for workflow_file in .github/workflows/*.{yml,yaml}; do + if [[ -f "$workflow_file" ]]; then + local filename=$(basename "$workflow_file") + + # Check if workflow has triggers other than workflow_dispatch + if grep -qE "^\s*(on:|push:|pull_request:|schedule:|workflow_run:)" "$workflow_file" && \ + ! grep -qE "^\s*workflow_dispatch:\s*$" "$workflow_file" || \ + grep -qE "^\s*schedule:" "$workflow_file"; then + + print_info "Disabling '$filename'..." + if gh workflow disable "$filename" 2>/dev/null; then + print_success " Disabled '$filename'" + ((disabled_count++)) + else + print_warning " Failed to disable '$filename' (may already be disabled)" + fi + fi + fi + done + + if [[ $disabled_count -gt 0 ]]; then + print_success "Disabled $disabled_count triggered workflows." + else + print_info "No triggered workflows found to disable." + fi +} + +# Delete all workflow runs +delete_all_runs() { + check_org_restriction "delete all workflow runs" + + print_info "Deleting all workflow runs..." + + # Check if repository parameter is provided + if [ $# -eq 0 ]; then + echo "Usage: $0 " + exit 1 + fi + + local REPO="$1" + + while true; do + # Get a batch of workflow run IDs + run_ids=$(gh run list --repo "$REPO" -L 30 --json databaseId --jq '.[].databaseId') + + # Check if we got any results + if [[ -z "$run_ids" ]]; then + echo "No more workflow runs found. Exiting." + break + fi + + # Process each ID in the current batch + echo "$run_ids" | while read id; do + echo "Deleting workflow run with ID: $id" + # The gh CLI command is simpler but much slower than using curl + #gh run delete --repo "$REPO" "$id" + curl -sL -X DELETE \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer $GITHUB_TOKEN" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "https://api.github.com/repos/$REPO/actions/runs/$id" + done + + echo "Batch completed. Checking for more workflow runs..." + done + + print_success "Deleted all workflow runs." +} + +# Main function +main() { + local command="$1" + check_gh_cli + local repo + repo=$(get_repo_info) + + case "$command" in + "dispatch") + if [[ $# -lt 3 ]]; then + print_error "Usage: $0 dispatch " + exit 1 + fi + dispatch_workflow "$2" "$3" + ;; + "list") + list_workflows "$repo" + ;; + "disable") + if [[ $# -lt 2 ]]; then + print_error "Usage: $0 disable " + exit 1 + fi + disable_workflow "$2" "$repo" + ;; + "enable") + if [[ $# -lt 2 ]]; then + print_error "Usage: $0 enable " + exit 1 + fi + enable_workflow "$2" "$repo" + ;; + "disable-triggered") + disable_triggered_workflows + ;; + "delete-all-runs") + delete_all_runs "$repo" + ;; + *) + print_error "Unknown command: $command" + print_info "Available commands: dispatch, list, disable, enable, disable-triggered, delete-all-runs" + exit 1 + ;; + esac +} + +# Run main function with all arguments +main "$@" diff --git a/build/workflow.mk b/build/workflow.mk new file mode 100644 index 0000000000..335cad45b2 --- /dev/null +++ b/build/workflow.mk @@ -0,0 +1,62 @@ +# ------------------------------------------------------------ +# Copyright 2023 The Radius Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ------------------------------------------------------------ + +##@ GitHub Workflows + +WORKFLOW_SCRIPT_DIR := build +WORKFLOW_SCRIPT := $(WORKFLOW_SCRIPT_DIR)/workflow-helper.sh + +# Default branch to current branch if not specified +BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD) + +.PHONY: workflow-dispatch +workflow-dispatch: ## Dispatch a workflow by name. Usage: make workflow-dispatch NAME= [BRANCH=] + @if [ -z "$(NAME)" ]; then \ + echo "Error: NAME parameter is required. Usage: make workflow-dispatch NAME= [BRANCH=]"; \ + exit 1; \ + fi + @bash $(WORKFLOW_SCRIPT) dispatch "$(NAME)" "$(BRANCH)" + +.PHONY: workflow +workflow: workflow-dispatch ## Alias for workflow-dispatch + +.PHONY: workflow-list +workflow-list: ## List all workflows in the repository + @bash $(WORKFLOW_SCRIPT) list + +.PHONY: workflow-disable +workflow-disable: ## Disable a workflow by name. Usage: make workflow-disable NAME= + @if [ -z "$(WORKFLOW_NAME)" ]; then \ + echo "Error: WORKFLOW_NAME parameter is required. Usage: make workflow-disable WORKFLOW_NAME="; \ + exit 1; \ + fi + @bash $(WORKFLOW_SCRIPT) disable "$(WORKFLOW_NAME)" + +.PHONY: workflow-disable-triggered +workflow-disable-triggered: ## Disable all workflows triggered by events (push, PR, timers) + @bash $(WORKFLOW_SCRIPT) disable-triggered + +.PHONY: workflow-enable +workflow-enable: ## Enable a workflow by name. Usage: make workflow-enable NAME= + @if [ -z "$(WORKFLOW_NAME)" ]; then \ + echo "Error: WORKFLOW_NAME parameter is required. Usage: make workflow-enable WORKFLOW_NAME="; \ + exit 1; \ + fi + @bash $(WORKFLOW_SCRIPT) enable "$(WORKFLOW_NAME)" + +.PHONY: workflow-delete-all-runs +workflow-delete-all-runs: ## Delete all workflow runs in the repository + @bash $(WORKFLOW_SCRIPT) delete-all-runs From b01390bc60ed99e80aa8e05a52a442390d3d547e Mon Sep 17 00:00:00 2001 From: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> Date: Mon, 26 May 2025 11:34:14 -0700 Subject: [PATCH 02/14] simplify Signed-off-by: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> --- build/workflow-helper.sh | 322 --------------------------------------- build/workflow.mk | 47 +----- build/workflow.sh | 227 +++++++++++++++++++++++++++ 3 files changed, 235 insertions(+), 361 deletions(-) delete mode 100755 build/workflow-helper.sh create mode 100755 build/workflow.sh diff --git a/build/workflow-helper.sh b/build/workflow-helper.sh deleted file mode 100755 index c2ba633b57..0000000000 --- a/build/workflow-helper.sh +++ /dev/null @@ -1,322 +0,0 @@ -#!/bin/bash -# ------------------------------------------------------------ -# Copyright 2023 The Radius Authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# ------------------------------------------------------------ - -set -euo pipefail - -# Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' # No Color - -# Function to print colored output -print_info() { - echo -e "${BLUE}ℹ${NC} $1" -} - -print_success() { - echo -e "${GREEN}✓${NC} $1" -} - -print_warning() { - echo -e "${YELLOW}⚠${NC} $1" -} - -print_error() { - echo -e "${RED}✗${NC} $1" -} - -# Check if we're in a radius-project organization repo for security -check_org_restriction() { - local operation="$1" - local repo_url - repo_url=$(git remote get-url origin 2>/dev/null || echo "") - - if [[ "$repo_url" == *"radius-project/"* ]]; then - print_info "Operation '$operation' should only be used on personal forks." - exit 1 - fi -} - -# Check if GitHub CLI is installed and authenticated -check_gh_cli() { - if ! command -v gh &> /dev/null; then - print_error "GitHub CLI (gh) is required but not installed." - print_info "Please install it from: https://cli.github.com/" - exit 1 - fi - - # Check if GITHUB_TOKEN or GH_TOKEN environment variables are already set - if [[ -n "${GITHUB_TOKEN:-}" ]] || [[ -n "${GH_TOKEN:-}" ]]; then - return 0 - fi - - # Check if user is authenticated and get token - local token - if ! token=$(gh auth token 2>/dev/null); then - print_error "GitHub CLI is not authenticated." - print_info "Please run 'gh auth login' to authenticate." - exit 1 - fi - - if [[ -z "$token" ]]; then - print_error "Unable to retrieve GitHub authentication token." - print_info "Please run 'gh auth login' to authenticate." - exit 1 - fi - - export GITHUB_TOKEN="$token" -} - -# Get repository info -get_repo_info() { - - # Verify we're in a git repository - if ! git rev-parse --git-dir &> /dev/null; then - print_error "Not in a git repository." - exit 1 - fi - - local repo_url - repo_url=$(git remote get-url origin 2>/dev/null) - - if [[ -z "$repo_url" ]]; then - print_error "Not in a git repository or no origin remote found." - exit 1 - fi - - # Check if it's a GitHub repository - if [[ "$repo_url" != *"github.com"* ]]; then - print_error "Repository is not hosted on GitHub." - exit 1 - fi - - # Remove https://github.com/ from the beginning - repo_url="${repo_url#https://github.com/}" - - # Remove .git from the end if present - repo_url="${repo_url%.git}" - - echo "$repo_url" -} - -# Dispatch a workflow -dispatch_workflow() { - local workflow_name="$1" - local branch="$2" - - print_info "Dispatching workflow '$workflow_name' on branch '$branch'..." - - # Check if workflow file exists - if [[ ! -f ".github/workflows/$workflow_name" ]]; then - print_error "Workflow file '.github/workflows/$workflow_name' not found." - print_info "Available workflows:" - list_workflows - exit 1 - fi - - # Attempt to dispatch the workflow - if gh workflow run "$workflow_name" --ref "$branch"; then - print_success "Workflow '$workflow_name' dispatched successfully on branch '$branch'." - print_info "You can view the workflow run at: $(gh repo view --web --branch "$branch" 2>/dev/null || echo "GitHub repository page")" - else - print_error "Failed to dispatch workflow '$workflow_name'." - print_info "Make sure the workflow supports manual triggering (workflow_dispatch event)." - exit 1 - fi -} - -# List all workflows -list_workflows() { - local REPO_NAME=$1 - print_info "Available workflows for $REPO_NAME:" - - local workflows - workflows=$(gh workflow list --all --repo "$REPO_NAME" --json name,path,state --jq '.[] | "\(.path)|\(.name)|\(.state)"' 2>/dev/null) - - if [[ -n "$workflows" ]]; then - while IFS='|' read -r path name state; do - local filename - filename=$(basename "$path") - printf " %-30s %-40s %s\n" "$filename" "($name)" "[$state]" - done <<< "$workflows" - else - print_warning "No workflows found or unable to retrieve workflow information." - fi -} - -# Disable a workflow -disable_workflow() { - local workflow_name="$1" - local REPO_NAME="$2" - - check_org_restriction "disable workflow" - - print_info "Disabling workflow '$workflow_name'..." - - if gh workflow disable --repo "$REPO_NAME" "$workflow_name"; then - print_success "Workflow '$workflow_name' disabled successfully." - else - print_error "Failed to disable workflow '$workflow_name'." - print_info "Make sure the workflow name is correct. Use 'make workflow-list' to see available workflows." - exit 1 - fi -} - -# Enable a workflow -enable_workflow() { - local workflow_name="$1" - local REPO_NAME="$2" - - print_info "Enabling workflow '$workflow_name'..." - - if gh workflow enable --repo "$REPO_NAME" "$workflow_name"; then - print_success "Workflow '$workflow_name' enabled successfully." - else - print_error "Failed to enable workflow '$workflow_name'." - print_info "Make sure the workflow name is correct. Use 'make workflow-list' to see available workflows." - exit 1 - fi -} - -# Disable all triggered workflows -disable_triggered_workflows() { - check_org_restriction "disable triggered workflows" - - print_info "Disabling all workflows triggered by events..." - - local disabled_count=0 - - # Get list of workflows and their trigger events - for workflow_file in .github/workflows/*.{yml,yaml}; do - if [[ -f "$workflow_file" ]]; then - local filename=$(basename "$workflow_file") - - # Check if workflow has triggers other than workflow_dispatch - if grep -qE "^\s*(on:|push:|pull_request:|schedule:|workflow_run:)" "$workflow_file" && \ - ! grep -qE "^\s*workflow_dispatch:\s*$" "$workflow_file" || \ - grep -qE "^\s*schedule:" "$workflow_file"; then - - print_info "Disabling '$filename'..." - if gh workflow disable "$filename" 2>/dev/null; then - print_success " Disabled '$filename'" - ((disabled_count++)) - else - print_warning " Failed to disable '$filename' (may already be disabled)" - fi - fi - fi - done - - if [[ $disabled_count -gt 0 ]]; then - print_success "Disabled $disabled_count triggered workflows." - else - print_info "No triggered workflows found to disable." - fi -} - -# Delete all workflow runs -delete_all_runs() { - check_org_restriction "delete all workflow runs" - - print_info "Deleting all workflow runs..." - - # Check if repository parameter is provided - if [ $# -eq 0 ]; then - echo "Usage: $0 " - exit 1 - fi - - local REPO="$1" - - while true; do - # Get a batch of workflow run IDs - run_ids=$(gh run list --repo "$REPO" -L 30 --json databaseId --jq '.[].databaseId') - - # Check if we got any results - if [[ -z "$run_ids" ]]; then - echo "No more workflow runs found. Exiting." - break - fi - - # Process each ID in the current batch - echo "$run_ids" | while read id; do - echo "Deleting workflow run with ID: $id" - # The gh CLI command is simpler but much slower than using curl - #gh run delete --repo "$REPO" "$id" - curl -sL -X DELETE \ - -H "Accept: application/vnd.github+json" \ - -H "Authorization: Bearer $GITHUB_TOKEN" \ - -H "X-GitHub-Api-Version: 2022-11-28" \ - "https://api.github.com/repos/$REPO/actions/runs/$id" - done - - echo "Batch completed. Checking for more workflow runs..." - done - - print_success "Deleted all workflow runs." -} - -# Main function -main() { - local command="$1" - check_gh_cli - local repo - repo=$(get_repo_info) - - case "$command" in - "dispatch") - if [[ $# -lt 3 ]]; then - print_error "Usage: $0 dispatch " - exit 1 - fi - dispatch_workflow "$2" "$3" - ;; - "list") - list_workflows "$repo" - ;; - "disable") - if [[ $# -lt 2 ]]; then - print_error "Usage: $0 disable " - exit 1 - fi - disable_workflow "$2" "$repo" - ;; - "enable") - if [[ $# -lt 2 ]]; then - print_error "Usage: $0 enable " - exit 1 - fi - enable_workflow "$2" "$repo" - ;; - "disable-triggered") - disable_triggered_workflows - ;; - "delete-all-runs") - delete_all_runs "$repo" - ;; - *) - print_error "Unknown command: $command" - print_info "Available commands: dispatch, list, disable, enable, disable-triggered, delete-all-runs" - exit 1 - ;; - esac -} - -# Run main function with all arguments -main "$@" diff --git a/build/workflow.mk b/build/workflow.mk index 335cad45b2..2adeaf1a0d 100644 --- a/build/workflow.mk +++ b/build/workflow.mk @@ -16,47 +16,16 @@ ##@ GitHub Workflows -WORKFLOW_SCRIPT_DIR := build -WORKFLOW_SCRIPT := $(WORKFLOW_SCRIPT_DIR)/workflow-helper.sh +WORKFLOW_SCRIPT := ./build/workflow.sh -# Default branch to current branch if not specified -BRANCH ?= $(shell git rev-parse --abbrev-ref HEAD) +.PHONY: workflow-disable-all +workflow-disable-all: ## Disable all workflows in the current repo + @bash $(WORKFLOW_SCRIPT) disable-all -.PHONY: workflow-dispatch -workflow-dispatch: ## Dispatch a workflow by name. Usage: make workflow-dispatch NAME= [BRANCH=] - @if [ -z "$(NAME)" ]; then \ - echo "Error: NAME parameter is required. Usage: make workflow-dispatch NAME= [BRANCH=]"; \ - exit 1; \ - fi - @bash $(WORKFLOW_SCRIPT) dispatch "$(NAME)" "$(BRANCH)" - -.PHONY: workflow -workflow: workflow-dispatch ## Alias for workflow-dispatch - -.PHONY: workflow-list -workflow-list: ## List all workflows in the repository - @bash $(WORKFLOW_SCRIPT) list - -.PHONY: workflow-disable -workflow-disable: ## Disable a workflow by name. Usage: make workflow-disable NAME= - @if [ -z "$(WORKFLOW_NAME)" ]; then \ - echo "Error: WORKFLOW_NAME parameter is required. Usage: make workflow-disable WORKFLOW_NAME="; \ - exit 1; \ - fi - @bash $(WORKFLOW_SCRIPT) disable "$(WORKFLOW_NAME)" - -.PHONY: workflow-disable-triggered -workflow-disable-triggered: ## Disable all workflows triggered by events (push, PR, timers) - @bash $(WORKFLOW_SCRIPT) disable-triggered - -.PHONY: workflow-enable -workflow-enable: ## Enable a workflow by name. Usage: make workflow-enable NAME= - @if [ -z "$(WORKFLOW_NAME)" ]; then \ - echo "Error: WORKFLOW_NAME parameter is required. Usage: make workflow-enable WORKFLOW_NAME="; \ - exit 1; \ - fi - @bash $(WORKFLOW_SCRIPT) enable "$(WORKFLOW_NAME)" +.PHONY: workflow-enable-all +workflow-enable-all: ## Enable all workflows in the current repo + @bash $(WORKFLOW_SCRIPT) enable-all .PHONY: workflow-delete-all-runs -workflow-delete-all-runs: ## Delete all workflow runs in the repository +workflow-delete-all-runs: ## Delete all workflow runs in the repository. NOTE: This is a destructive operation and cannot be undone. @bash $(WORKFLOW_SCRIPT) delete-all-runs diff --git a/build/workflow.sh b/build/workflow.sh new file mode 100755 index 0000000000..d392e059b9 --- /dev/null +++ b/build/workflow.sh @@ -0,0 +1,227 @@ +#!/bin/bash +# ------------------------------------------------------------ +# Copyright 2023 The Radius Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ------------------------------------------------------------ + +set -euo pipefail + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# Function to print colored output +print_info() { + echo -e "${BLUE}ℹ${NC} $1" +} + +print_success() { + echo -e "${GREEN}✓${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}⚠${NC} $1" +} + +print_error() { + echo -e "${RED}✗${NC} $1" +} + +# Check if we're in a radius-project organization repo for security +check_org_restriction() { + local operation="$1" + local repo_url + repo_url=$(git remote get-url origin 2>/dev/null || echo "") + + if [[ "$repo_url" == *"radius-project/"* ]]; then + print_info "Operation '$operation' should only be used on personal forks." + exit 1 + fi +} + +# Check if GitHub CLI is installed and authenticated +check_gh_cli() { + if ! command -v gh &> /dev/null; then + print_error "GitHub CLI (gh) is required but not installed." + print_info "Please install it from: https://cli.github.com/" + exit 1 + fi + + # Check if GITHUB_TOKEN or GH_TOKEN environment variables are already set + if [[ -n "${GITHUB_TOKEN:-}" ]] || [[ -n "${GH_TOKEN:-}" ]]; then + return 0 + fi + + # Check if user is authenticated and get token + local token + if ! token=$(gh auth token 2>/dev/null); then + print_error "GitHub CLI is not authenticated." + print_info "Please run 'gh auth login' to authenticate." + exit 1 + fi + + if [[ -z "$token" ]]; then + print_error "Unable to retrieve GitHub authentication token." + print_info "Please run 'gh auth login' to authenticate." + exit 1 + fi + + export GITHUB_TOKEN="$token" +} + +# Get repository info +get_repo_info() { + + # Verify we're in a git repository + if ! git rev-parse --git-dir &> /dev/null; then + print_error "Not in a git repository." + exit 1 + fi + + local repo_url + repo_url=$(git remote get-url origin 2>/dev/null) + + if [[ -z "$repo_url" ]]; then + print_error "Not in a git repository or no origin remote found." + exit 1 + fi + + # Check if it's a GitHub repository + if [[ "$repo_url" != *"github.com"* ]]; then + print_error "Repository is not hosted on GitHub." + exit 1 + fi + + # Remove https://github.com/ from the beginning + repo_url="${repo_url#https://github.com/}" + + # Remove .git from the end if present + repo_url="${repo_url%.git}" + + echo "$repo_url" +} + +# Delete all workflow runs +delete_all_runs() { + check_org_restriction "delete all workflow runs" + + print_info "Deleting all workflow runs..." + + # Check if repository parameter is provided + if [ $# -eq 0 ]; then + echo "Usage: $0 " + exit 1 + fi + + local REPO="$1" + + while true; do + # Get a batch of workflow run IDs + run_ids=$(gh run list --repo "$REPO" -L 30 --json databaseId --jq '.[].databaseId') + + # Check if we got any results + if [[ -z "$run_ids" ]]; then + echo "No more workflow runs found. Exiting." + break + fi + + # Process each ID in the current batch + echo "$run_ids" | while read id; do + echo "Deleting workflow run with ID: $id" + # The gh CLI command show below is simpler but much slower than using curl + # gh run delete --repo "$REPO" "$id" + curl -sL -X DELETE \ + -H "Accept: application/vnd.github+json" \ + -H "Authorization: Bearer $GITHUB_TOKEN" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "https://api.github.com/repos/$REPO/actions/runs/$id" + done + + echo "Batch completed. Checking for more workflow runs..." + done + + print_success "Deleted all workflow runs." +} + +# Toggle workflows (enable or disable) +toggle_workflows() { + local action="$1" + local repo="$2" + check_org_restriction "$action all workflows" + + local action_verb action_past_tense gh_command gh_state + if [[ "$action" == "enable" ]]; then + action_verb="Enabling" + action_past_tense="enabled" + gh_command="enable" + gh_state="disabled_manually" + else + action_verb="Disabling" + action_past_tense="disabled" + gh_command="disable" + gh_state="active" + fi + + print_info "$action_verb all workflows in repository: $repo" + + # Get workflows with their current state + local workflows + workflows=$(gh workflow list --all --json name,state | jq -r '.[] | select(.state == "'"$gh_state"'") | .name') + + if [[ -z "$workflows" ]]; then + print_warning "No workflows found that need to be $action_past_tense." + return 0 + fi + + # Enable/disable each workflow that needs the action + while read -r name; do + if [[ -n "$name" ]]; then + print_info "$action_verb workflow: $name" + gh workflow "$gh_command" --repo "$repo" "$name" + fi + done <<< "$workflows" + + print_success "All workflows have been $action_past_tense." +} + +# Main function +main() { + local command="$1" + check_gh_cli + local repo + repo=$(get_repo_info) + + case "$command" in + "enable-all") + toggle_workflows "enable" "$repo" + ;; + "disable-all") + toggle_workflows "disable" "$repo" + ;; + "delete-all-runs") + delete_all_runs "$repo" + ;; + *) + print_error "Unknown command: $command" + print_info "Available commands: enable-all, disable-all, delete-all-runs" + exit 1 + ;; + esac +} + +# Run main function with all arguments +main "$@" From b6fb6a0c1db2fd407edee9f01a15b28b7b8b4482 Mon Sep 17 00:00:00 2001 From: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> Date: Mon, 26 May 2025 11:54:47 -0700 Subject: [PATCH 03/14] review comments Signed-off-by: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> --- build/workflow.sh | 46 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 34 insertions(+), 12 deletions(-) diff --git a/build/workflow.sh b/build/workflow.sh index d392e059b9..0492f6ad56 100755 --- a/build/workflow.sh +++ b/build/workflow.sh @@ -1,4 +1,5 @@ #!/bin/bash + # ------------------------------------------------------------ # Copyright 2023 The Radius Authors. # @@ -18,11 +19,11 @@ set -euo pipefail # Colors for output -RED='\033[0;31m' -GREEN='\033[0;32m' -YELLOW='\033[1;33m' -BLUE='\033[0;34m' -NC='\033[0m' # No Color +readonly RED='\033[0;31m' +readonly GREEN='\033[0;32m' +readonly YELLOW='\033[1;33m' +readonly BLUE='\033[0;34m' +readonly NC='\033[0m' # No Color # Function to print colored output print_info() { @@ -61,6 +62,13 @@ check_gh_cli() { exit 1 fi + # Check if jq is installed + if ! command -v jq &> /dev/null; then + print_error "jq is required but not installed." + print_info "Please install jq to parse JSON responses." + exit 1 + fi + # Check if GITHUB_TOKEN or GH_TOKEN environment variables are already set if [[ -n "${GITHUB_TOKEN:-}" ]] || [[ -n "${GH_TOKEN:-}" ]]; then return 0 @@ -144,13 +152,15 @@ delete_all_runs() { echo "Deleting workflow run with ID: $id" # The gh CLI command show below is simpler but much slower than using curl # gh run delete --repo "$REPO" "$id" - curl -sL -X DELETE \ + if ! curl -sL -X DELETE \ -H "Accept: application/vnd.github+json" \ -H "Authorization: Bearer $GITHUB_TOKEN" \ -H "X-GitHub-Api-Version: 2022-11-28" \ - "https://api.github.com/repos/$REPO/actions/runs/$id" + "https://api.github.com/repos/$REPO/actions/runs/$id"; then + print_error "Failed to delete workflow run with ID: $id" + fi done - + echo "Batch completed. Checking for more workflow runs..." done @@ -159,8 +169,20 @@ delete_all_runs() { # Toggle workflows (enable or disable) toggle_workflows() { + + if [[ $# -ne 2 ]]; then + print_error "Usage: toggle_workflows " + exit 1 + fi + local action="$1" local repo="$2" + + if [[ "$action" != "enable" && "$action" != "disable" ]]; then + print_error "Invalid action: $action. Must be 'enable' or 'disable'" + exit 1 + fi + check_org_restriction "$action all workflows" local action_verb action_past_tense gh_command gh_state @@ -175,12 +197,12 @@ toggle_workflows() { gh_command="disable" gh_state="active" fi - - print_info "$action_verb all workflows in repository: $repo" - + + print_info "$action_verb all workflows in repository '$repo' with state '$gh_state'." + # Get workflows with their current state local workflows - workflows=$(gh workflow list --all --json name,state | jq -r '.[] | select(.state == "'"$gh_state"'") | .name') + workflows=$(gh workflow list --repo "$repo" --all --json name,state | jq -r '.[] | select(.state == "'"$gh_state"'") | .name') if [[ -z "$workflows" ]]; then print_warning "No workflows found that need to be $action_past_tense." From a975a0427f00d6601733e4e83de3de4643bd43fc Mon Sep 17 00:00:00 2001 From: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> Date: Tue, 27 May 2025 17:42:07 -0700 Subject: [PATCH 04/14] missing .PHONY identifiers Signed-off-by: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> --- build/test.mk | 27 ++++++++++++++++++++++++--- 1 file changed, 24 insertions(+), 3 deletions(-) diff --git a/build/test.mk b/build/test.mk index 8aaa8792d9..e69dae15f0 100644 --- a/build/test.mk +++ b/build/test.mk @@ -58,64 +58,87 @@ test-get-envtools: test-validate-cli: ## Run cli integration tests CGO_ENABLED=1 $(GOTEST_TOOL) -coverpkg= ./pkg/cli/cmd/... ./cmd/rad/... -timeout ${TEST_TIMEOUT} -v -parallel 5 $(GOTEST_OPTS) +.PHONY: test-functional-all test-functional-all: test-functional-ucp test-functional-kubernetes test-functional-corerp test-functional-cli test-functional-msgrp test-functional-daprrp test-functional-datastoresrp test-functional-samples test-functional-dynamicrp-noncloud ## Runs all functional tests +.PHONY: test-functional-all-noncloud # Run all functional tests that do not require cloud resources test-functional-all-noncloud: test-functional-ucp-noncloud test-functional-kubernetes-noncloud test-functional-corerp-noncloud test-functional-cli-noncloud test-functional-msgrp-noncloud test-functional-daprrp-noncloud test-functional-datastoresrp-noncloud test-functional-samples-noncloud test-functional-dynamicrp-noncloud ## Runs all functional tests that do not require cloud resources +.PHONY: test-functional-all-cloud # Run all functional tests that require cloud resources test-functional-all-cloud: test-functional-ucp-cloud test-functional-corerp-cloud +.PHONY: test-functional-ucp test-functional-ucp: test-functional-ucp-noncloud test-functional-ucp-cloud ## Runs all UCP functional tests (both cloud and non-cloud) +.PHONY: test-functional-ucp-noncloud test-functional-ucp-noncloud: ## Runs UCP functional tests that do not require cloud resources CGO_ENABLED=1 $(GOTEST_TOOL) ./test/functional-portable/ucp/noncloud/... -timeout ${TEST_TIMEOUT} -v -parallel 5 $(GOTEST_OPTS) +.PHONY: test-functional-ucp-cloud test-functional-ucp-cloud: ## Runs UCP functional tests that require cloud resources CGO_ENABLED=1 $(GOTEST_TOOL) ./test/functional-portable/ucp/cloud/... -timeout ${TEST_TIMEOUT} -v -parallel 5 $(GOTEST_OPTS) +.PHONY: test-functional-kubernetes test-functional-kubernetes: test-functional-kubernetes-noncloud ## Runs all Kubernetes functional tests CGO_ENABLED=1 $(GOTEST_TOOL) ./test/functional-portable/kubernetes/... -timeout ${TEST_TIMEOUT} -v -parallel 5 $(GOTEST_OPTS) +.PHONY: test-functional-kubernetes-noncloud test-functional-kubernetes-noncloud: ## Runs Kubernetes functional tests that do not require cloud resources CGO_ENABLED=1 $(GOTEST_TOOL) ./test/functional-portable/kubernetes/noncloud/... -timeout ${TEST_TIMEOUT} -v -parallel 5 $(GOTEST_OPTS) +.PHONY: test-functional-corerp test-functional-corerp: test-functional-corerp-noncloud test-functional-corerp-cloud ## Runs all Core RP functional tests (both cloud and non-cloud) +.PHONY: test-functional-corerp-noncloud test-functional-corerp-noncloud: ## Runs corerp functional tests that do not require cloud resources CGO_ENABLED=1 $(GOTEST_TOOL) ./test/functional-portable/corerp/noncloud/... -timeout ${TEST_TIMEOUT} -v -parallel 10 $(GOTEST_OPTS) +.PHONY: test-functional-corerp-cloud test-functional-corerp-cloud: ## Runs corerp functional tests that require cloud resources CGO_ENABLED=1 $(GOTEST_TOOL) ./test/functional-portable/corerp/cloud/... -timeout ${TEST_TIMEOUT} -v -parallel 10 $(GOTEST_OPTS) +.PHONY: test-functional-msgrp test-functional-msgrp: test-functional-msgrp-noncloud ## Runs all Messaging RP functional tests (both cloud and non-cloud) +.PHONY: test-functional-msgrp-noncloud test-functional-msgrp-noncloud: ## Runs Messaging RP functional tests that do not require cloud resources CGO_ENABLED=1 $(GOTEST_TOOL) ./test/functional-portable/messagingrp/noncloud/... -timeout ${TEST_TIMEOUT} -v -parallel 2 $(GOTEST_OPTS) +.PHONY: test-functional-cli test-functional-cli: test-functional-cli-noncloud ## Runs all cli functional tests (both cloud and non-cloud) +.PHONY: test-functional-cli-noncloud test-functional-cli-noncloud: ## Runs cli functional tests that do not require cloud resources CGO_ENABLED=1 $(GOTEST_TOOL) ./test/functional-portable/cli/noncloud/... -timeout ${TEST_TIMEOUT} -v -parallel 10 $(GOTEST_OPTS) +.PHONY: test-functional-daprrp test-functional-daprrp: test-functional-daprrp-noncloud ## Runs all Dapr RP functional tests (both cloud and non-cloud) +.PHONY: test-functional-daprrp-noncloud test-functional-daprrp-noncloud: ## Runs Dapr RP functional tests that do not require cloud resources CGO_ENABLED=1 $(GOTEST_TOOL) ./test/functional-portable/daprrp/noncloud/... -timeout ${TEST_TIMEOUT} -v -parallel 3 $(GOTEST_OPTS) +.PHONY: test-functional-datastoresrp test-functional-datastoresrp: test-functional-datastoresrp-noncloud ## Runs all Datastores RP functional tests (non-cloud) +.PHONY: test-functional-datastoresrp-noncloud test-functional-datastoresrp-noncloud: ## Runs Datastores RP functional tests that do not require cloud resources CGO_ENABLED=1 $(GOTEST_TOOL) ./test/functional-portable/datastoresrp/noncloud/... -timeout ${TEST_TIMEOUT} -v -parallel 3 $(GOTEST_OPTS) +.PHONY: test-functional-dynamicrp-noncloud test-functional-dynamicrp-noncloud: ## Runs Dynamic RP functional tests that do not require cloud resources CGO_ENABLED=1 $(GOTEST_TOOL) ./test/functional-portable/dynamicrp/noncloud/... -timeout ${TEST_TIMEOUT} -v -parallel 2 $(GOTEST_OPTS) - + +.PHONY: test-functional-samples test-functional-samples: test-functional-samples-noncloud ## Runs all Samples functional tests +.PHONY: test-functional-samples-noncloud 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) +.PHONY: test-validate-bicep test-validate-bicep: ## Validates that all .bicep files compile cleanly BICEP_PATH="${HOME}/.rad/bin/rad-bicep" ./build/validate-bicep.sh @@ -130,5 +153,3 @@ oav-installed: test-ucp-spec-examples: oav-installed ## Validates UCP examples conform to UCP OpenAPI Spec # @echo "$(ARROW) Testing x-ms-examples conform to ucp spec..." # oav validate-example swagger/specification/ucp/resource-manager/UCP/preview/2023-10-01-preview/openapi.json - - From 9d78a4eff1321aa94072aef59b9febc3506e7f17 Mon Sep 17 00:00:00 2001 From: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> Date: Tue, 27 May 2025 21:00:06 -0700 Subject: [PATCH 05/14] make lrt cluster Signed-off-by: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> --- build/test.mk | 10 ++ build/test.sh | 214 ++++++++++++++++++++++++++++++++++++ test/infra/azure/main.bicep | 2 +- 3 files changed, 225 insertions(+), 1 deletion(-) create mode 100755 build/test.sh diff --git a/build/test.mk b/build/test.mk index e69dae15f0..8b905ad217 100644 --- a/build/test.mk +++ b/build/test.mk @@ -153,3 +153,13 @@ oav-installed: test-ucp-spec-examples: oav-installed ## Validates UCP examples conform to UCP OpenAPI Spec # @echo "$(ARROW) Testing x-ms-examples conform to ucp spec..." # oav validate-example swagger/specification/ucp/resource-manager/UCP/preview/2023-10-01-preview/openapi.json + +.PHONY: test-deploy-lrt-cluster +test-deploy-lrt-cluster: ## Deploys long-running test cluster to Azure + @echo "$(ARROW) Deploying long-running test cluster to Azure..." + @bash ./build/test.sh deploy-lrt-cluster + +.PHONY: test-delete-lrt-cluster +test-delete-lrt-cluster: ## Cleans up long-running test cluster from Azure + @echo "$(ARROW) Cleaning up long-running test cluster from Azure..." + @bash ./build/test.sh delete-lrt-cluster diff --git a/build/test.sh b/build/test.sh new file mode 100755 index 0000000000..f8787dc91d --- /dev/null +++ b/build/test.sh @@ -0,0 +1,214 @@ +#!/bin/bash + +# ------------------------------------------------------------ +# Copyright 2023 The Radius Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ------------------------------------------------------------ + +set -euo pipefail + +# Colors for output +readonly RED='\033[0;31m' +readonly GREEN='\033[0;32m' +readonly YELLOW='\033[1;33m' +readonly BLUE='\033[0;34m' +readonly NC='\033[0m' # No Color + +# Function to print colored output +print_info() { + echo -e "${BLUE}ℹ${NC} $1" +} + +print_success() { + echo -e "${GREEN}✓${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}⚠${NC} $1" +} + +print_error() { + echo -e "${RED}✗${NC} $1" +} + +# Check if Azure CLI is installed and authenticated +check_azure_cli() { + if ! command -v az &> /dev/null; then + print_error "Azure CLI (az) is required but not installed." + exit 1 + fi + + # Check if user is authenticated + if ! az account show &> /dev/null; then + print_error "Azure CLI is not authenticated." + print_info "Please run 'az login' to authenticate." + exit 1 + fi + + print_success "Azure CLI is installed and authenticated." +} + +# Deploy long-running test cluster +deploy_lrt_cluster() { + print_info "Deploying long-running test cluster to Azure..." + + # Default values (can be overridden by environment variables) + local location="${AZURE_LOCATION:-westus3}" + local resource_group="${LRT_RG:-$(whoami)-radius-lrt}" + local grafana_enabled="${GRAFANA_ENABLED:-false}" + local grafana_admin_object_id="${GRAFANA_ADMIN_OBJECT_ID:-}" + + print_info "Configuration:" + print_info " Location: $location" + print_info " Resource Group: $resource_group" + print_info " Grafana Enabled: $grafana_enabled" + + # Check if we need Grafana admin object ID + if [[ "$grafana_enabled" == "true" && -z "$grafana_admin_object_id" ]]; then + print_warning "Grafana is enabled but GRAFANA_ADMIN_OBJECT_ID is not set." + print_info "Getting current user object ID..." + grafana_admin_object_id=$(az ad signed-in-user show --query objectId -o tsv) + print_info "Using current user object ID: $grafana_admin_object_id" + fi + + # Step 1: Check and register feature flag + print_info "Checking Microsoft.ContainerService/EnableImageCleanerPreview feature flag..." + local feature_state + feature_state=$(az feature show --namespace "Microsoft.ContainerService" --name "EnableImageCleanerPreview" --query properties.state -o tsv 2>/dev/null || echo "NotRegistered") + + if [[ "$feature_state" != "Registered" ]]; then + print_warning "Feature flag is not registered. Registering now..." + az feature register --namespace "Microsoft.ContainerService" --name "EnableImageCleanerPreview" + print_info "Re-registering Microsoft.ContainerService resource provider..." + az provider register --namespace Microsoft.ContainerService + print_warning "Feature flag registration may take some time to propagate." + else + print_success "Feature flag is already registered." + fi + + # Step 2: Create resource group + print_info "Creating resource group '$resource_group' in location '$location'..." + az group create --location "$location" --resource-group "$resource_group" + print_success "Resource group created successfully." + + # Step 3: Deploy main.bicep + local template_file="./test/infra/azure/main.bicep" + if [[ ! -f "$template_file" ]]; then + print_error "Template file not found: $template_file" + print_info "Please ensure you're running this from the repository root." + exit 1 + fi + + print_info "Deploying Bicep template..." + local deployment_params="grafanaEnabled=$grafana_enabled" + + if [[ "$grafana_enabled" == "true" && -n "$grafana_admin_object_id" ]]; then + deployment_params="$deployment_params grafanaAdminObjectId=$grafana_admin_object_id" + fi + + print_info "Deployment parameters: $deployment_params" + + if az deployment group create \ + --resource-group "$resource_group" \ + --template-file "$template_file" \ + --parameters "$deployment_params"; then + print_success "Deployment completed successfully!" + print_info "Resource group: $resource_group" + print_info "Location: $location" + + # Get AKS cluster name + local aks_cluster + aks_cluster=$(az aks list --resource-group "$resource_group" --query '[0].name' -o tsv 2>/dev/null || echo "") + if [[ -n "$aks_cluster" ]]; then + print_info "AKS Cluster: $aks_cluster" + print_info "To connect to the cluster, run:" + print_info " az aks get-credentials --resource-group $resource_group --name $aks_cluster" + fi + + if [[ "$grafana_enabled" == "true" ]]; then + local grafana_endpoint + grafana_endpoint=$(az grafana list --resource-group "$resource_group" --query '[0].properties.endpoint' -o tsv 2>/dev/null || echo "") + if [[ -n "$grafana_endpoint" ]]; then + print_info "Grafana Dashboard: $grafana_endpoint" + fi + fi + else + print_error "Deployment failed!" + exit 1 + fi +} + +# Cleanup long-running test cluster +cleanup_lrt_cluster() { + print_info "Cleaning up long-running test cluster..." + + local resource_group="${LRT_RG:-}" + + if [[ -z "$resource_group" ]]; then + print_error "LRT_RG environment variable is required for cleanup." + print_info "Please set LRT_RG to the resource group name you want to delete." + exit 1 + fi + + print_warning "This will delete the entire resource group: $resource_group" + print_warning "This action cannot be undone!" + + # Check if resource group exists + if ! az group exists --name "$resource_group" --output tsv | grep -q "true"; then + print_warning "Resource group '$resource_group' does not exist." + return 0 + fi + + print_info "Deleting resource group '$resource_group'..." + if az group delete --name "$resource_group" --yes --no-wait; then + print_success "Resource group deletion initiated." + print_info "Deletion is running in the background and may take several minutes to complete." + else + print_error "Failed to initiate resource group deletion." + exit 1 + fi +} + +# Main function +main() { + if [[ $# -eq 0 ]]; then + print_error "No command specified." + print_info "Available commands: deploy-lrt-cluster, cleanup-lrt-cluster" + exit 1 + fi + + local command="$1" + check_azure_cli + + case "$command" in + "deploy-lrt-cluster") + deploy_lrt_cluster + ;; + "delete-lrt-cluster") + cleanup_lrt_cluster + ;; + *) + print_error "Unknown command: $command" + print_info "Available commands: deploy-lrt-cluster, delete-lrt-cluster" + exit 1 + ;; + esac +} + +# Run main function with all arguments +main "$@" + + +set aks name +add some type of validation to ensure that LRT_RG name is set \ No newline at end of file diff --git a/test/infra/azure/main.bicep b/test/infra/azure/main.bicep index 4703d0897e..726b47c6fe 100644 --- a/test/infra/azure/main.bicep +++ b/test/infra/azure/main.bicep @@ -98,7 +98,7 @@ module aksCluster './modules/akscluster.bicep' = { systemAgentPoolOsDiskType: 'Managed' systemAgentPoolOsSKU: 'AzureLinux' userAgentPoolName: 'userpool' - userAgentPoolVmSize: 'Standard_D4as_v5' + userAgentPoolVmSize: 'Standard_D8as_v5' userAgentPoolAvailabilityZones: [] userAgentPoolOsDiskType: 'Managed' userAgentPoolOsSKU: 'AzureLinux' From 568ed502777a50af036bdb278496ac2c4a63332a Mon Sep 17 00:00:00 2001 From: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> Date: Tue, 27 May 2025 21:46:43 -0700 Subject: [PATCH 06/14] make test-deploy-lrt-cluster Signed-off-by: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> --- build/test.mk | 8 +--- build/test.sh | 124 ++++---------------------------------------------- 2 files changed, 10 insertions(+), 122 deletions(-) diff --git a/build/test.mk b/build/test.mk index 8b905ad217..223b1e26c2 100644 --- a/build/test.mk +++ b/build/test.mk @@ -155,11 +155,5 @@ test-ucp-spec-examples: oav-installed ## Validates UCP examples conform to UCP O # oav validate-example swagger/specification/ucp/resource-manager/UCP/preview/2023-10-01-preview/openapi.json .PHONY: test-deploy-lrt-cluster -test-deploy-lrt-cluster: ## Deploys long-running test cluster to Azure - @echo "$(ARROW) Deploying long-running test cluster to Azure..." +test-deploy-lrt-cluster: ## Deploys an AKS cluster to Azure for the long-running tests. Optional parameters: [LRT_AZURE_LOCATION=] [LRT_RG=] @bash ./build/test.sh deploy-lrt-cluster - -.PHONY: test-delete-lrt-cluster -test-delete-lrt-cluster: ## Cleans up long-running test cluster from Azure - @echo "$(ARROW) Cleaning up long-running test cluster from Azure..." - @bash ./build/test.sh delete-lrt-cluster diff --git a/build/test.sh b/build/test.sh index f8787dc91d..3ef5b41e1f 100755 --- a/build/test.sh +++ b/build/test.sh @@ -52,11 +52,8 @@ check_azure_cli() { # Check if user is authenticated if ! az account show &> /dev/null; then print_error "Azure CLI is not authenticated." - print_info "Please run 'az login' to authenticate." exit 1 fi - - print_success "Azure CLI is installed and authenticated." } # Deploy long-running test cluster @@ -64,68 +61,32 @@ deploy_lrt_cluster() { print_info "Deploying long-running test cluster to Azure..." # Default values (can be overridden by environment variables) - local location="${AZURE_LOCATION:-westus3}" + local location="${LRT_AZURE_LOCATION:-westus3}" local resource_group="${LRT_RG:-$(whoami)-radius-lrt}" - local grafana_enabled="${GRAFANA_ENABLED:-false}" - local grafana_admin_object_id="${GRAFANA_ADMIN_OBJECT_ID:-}" print_info "Configuration:" - print_info " Location: $location" + print_info " Subscription: $(az account show --query "[name,id]" --output tsv | paste -sd,)" print_info " Resource Group: $resource_group" - print_info " Grafana Enabled: $grafana_enabled" - - # Check if we need Grafana admin object ID - if [[ "$grafana_enabled" == "true" && -z "$grafana_admin_object_id" ]]; then - print_warning "Grafana is enabled but GRAFANA_ADMIN_OBJECT_ID is not set." - print_info "Getting current user object ID..." - grafana_admin_object_id=$(az ad signed-in-user show --query objectId -o tsv) - print_info "Using current user object ID: $grafana_admin_object_id" - fi + print_info " Location: $location" - # Step 1: Check and register feature flag - print_info "Checking Microsoft.ContainerService/EnableImageCleanerPreview feature flag..." local feature_state feature_state=$(az feature show --namespace "Microsoft.ContainerService" --name "EnableImageCleanerPreview" --query properties.state -o tsv 2>/dev/null || echo "NotRegistered") - if [[ "$feature_state" != "Registered" ]]; then print_warning "Feature flag is not registered. Registering now..." az feature register --namespace "Microsoft.ContainerService" --name "EnableImageCleanerPreview" - print_info "Re-registering Microsoft.ContainerService resource provider..." az provider register --namespace Microsoft.ContainerService - print_warning "Feature flag registration may take some time to propagate." - else - print_success "Feature flag is already registered." fi - # Step 2: Create resource group print_info "Creating resource group '$resource_group' in location '$location'..." - az group create --location "$location" --resource-group "$resource_group" + az group create --location "$location" --resource-group "$resource_group" --output none print_success "Resource group created successfully." - # Step 3: Deploy main.bicep local template_file="./test/infra/azure/main.bicep" - if [[ ! -f "$template_file" ]]; then - print_error "Template file not found: $template_file" - print_info "Please ensure you're running this from the repository root." - exit 1 - fi - print_info "Deploying Bicep template..." - local deployment_params="grafanaEnabled=$grafana_enabled" - - if [[ "$grafana_enabled" == "true" && -n "$grafana_admin_object_id" ]]; then - deployment_params="$deployment_params grafanaAdminObjectId=$grafana_admin_object_id" - fi - - print_info "Deployment parameters: $deployment_params" - if az deployment group create \ --resource-group "$resource_group" \ - --template-file "$template_file" \ - --parameters "$deployment_params"; then + --template-file "$template_file"; then print_success "Deployment completed successfully!" - print_info "Resource group: $resource_group" - print_info "Location: $location" # Get AKS cluster name local aks_cluster @@ -134,14 +95,8 @@ deploy_lrt_cluster() { print_info "AKS Cluster: $aks_cluster" print_info "To connect to the cluster, run:" print_info " az aks get-credentials --resource-group $resource_group --name $aks_cluster" - fi - - if [[ "$grafana_enabled" == "true" ]]; then - local grafana_endpoint - grafana_endpoint=$(az grafana list --resource-group "$resource_group" --query '[0].properties.endpoint' -o tsv 2>/dev/null || echo "") - if [[ -n "$grafana_endpoint" ]]; then - print_info "Grafana Dashboard: $grafana_endpoint" - fi + print_info "To delete the cluster, run:" + print_info " az group delete --name $resource_group --yes --no-wait" fi else print_error "Deployment failed!" @@ -149,66 +104,5 @@ deploy_lrt_cluster() { fi } -# Cleanup long-running test cluster -cleanup_lrt_cluster() { - print_info "Cleaning up long-running test cluster..." - - local resource_group="${LRT_RG:-}" - - if [[ -z "$resource_group" ]]; then - print_error "LRT_RG environment variable is required for cleanup." - print_info "Please set LRT_RG to the resource group name you want to delete." - exit 1 - fi - - print_warning "This will delete the entire resource group: $resource_group" - print_warning "This action cannot be undone!" - - # Check if resource group exists - if ! az group exists --name "$resource_group" --output tsv | grep -q "true"; then - print_warning "Resource group '$resource_group' does not exist." - return 0 - fi - - print_info "Deleting resource group '$resource_group'..." - if az group delete --name "$resource_group" --yes --no-wait; then - print_success "Resource group deletion initiated." - print_info "Deletion is running in the background and may take several minutes to complete." - else - print_error "Failed to initiate resource group deletion." - exit 1 - fi -} - -# Main function -main() { - if [[ $# -eq 0 ]]; then - print_error "No command specified." - print_info "Available commands: deploy-lrt-cluster, cleanup-lrt-cluster" - exit 1 - fi - - local command="$1" - check_azure_cli - - case "$command" in - "deploy-lrt-cluster") - deploy_lrt_cluster - ;; - "delete-lrt-cluster") - cleanup_lrt_cluster - ;; - *) - print_error "Unknown command: $command" - print_info "Available commands: deploy-lrt-cluster, delete-lrt-cluster" - exit 1 - ;; - esac -} - -# Run main function with all arguments -main "$@" - - -set aks name -add some type of validation to ensure that LRT_RG name is set \ No newline at end of file +check_azure_cli +deploy_lrt_cluster From 5c4e0c88ff569fadcfb235adf45b45c3a1b3b5f0 Mon Sep 17 00:00:00 2001 From: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> Date: Tue, 10 Jun 2025 14:44:57 -0700 Subject: [PATCH 07/14] local test Signed-off-by: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> --- build/install.mk | 7 ++- build/test.mk | 8 +++- build/test.sh | 115 ++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 121 insertions(+), 9 deletions(-) diff --git a/build/install.mk b/build/install.mk index c239720a63..5f8ef41759 100644 --- a/build/install.mk +++ b/build/install.mk @@ -21,4 +21,9 @@ RAD_LOCATION := /usr/local/bin/rad .PHONY: install install: build-binaries ## Installs a local build for development @echo "$(ARROW) Installing rad" - cp $(OUT_DIR)/$(GOOS)_$(GOARCH)/$(BUILDTYPE_DIR)/rad$(BINARY_EXT) $(RAD_LOCATION) \ No newline at end of file + sudo cp $(OUT_DIR)/$(GOOS)_$(GOARCH)/$(BUILDTYPE_DIR)/rad$(BINARY_EXT) $(RAD_LOCATION) + +.PHONY: install-latest +install-latest: ## Installs the latest release from GitHub + @echo "$(ARROW) Installing latest rad release" + @bash ./deploy/install.sh \ No newline at end of file diff --git a/build/test.mk b/build/test.mk index 223b1e26c2..9fdb022192 100644 --- a/build/test.mk +++ b/build/test.mk @@ -154,6 +154,10 @@ test-ucp-spec-examples: oav-installed ## Validates UCP examples conform to UCP O # @echo "$(ARROW) Testing x-ms-examples conform to ucp spec..." # oav validate-example swagger/specification/ucp/resource-manager/UCP/preview/2023-10-01-preview/openapi.json -.PHONY: test-deploy-lrt-cluster -test-deploy-lrt-cluster: ## Deploys an AKS cluster to Azure for the long-running tests. Optional parameters: [LRT_AZURE_LOCATION=] [LRT_RG=] +.PHONY: test-deploy-aks-cluster +test-deploy-aks-cluster: ## Deploys an AKS cluster to Azure for the long-running tests. Optional parameters: [LRT_AZURE_LOCATION=] [LRT_RG=] @bash ./build/test.sh deploy-lrt-cluster + +.PHONY: test-lrt +test-lrt: ## Runs the long-running tests against the AKS cluster deployed by test-deploy-lrt-cluster using the currently installed version of the Radius CLI and the current az authenticated subscription. + @bash ./build/test.sh run-lrt \ No newline at end of file diff --git a/build/test.sh b/build/test.sh index 3ef5b41e1f..b469375397 100755 --- a/build/test.sh +++ b/build/test.sh @@ -63,7 +63,7 @@ deploy_lrt_cluster() { # Default values (can be overridden by environment variables) local location="${LRT_AZURE_LOCATION:-westus3}" local resource_group="${LRT_RG:-$(whoami)-radius-lrt}" - + print_info "Configuration:" print_info " Subscription: $(az account show --query "[name,id]" --output tsv | paste -sd,)" print_info " Resource Group: $resource_group" @@ -88,13 +88,16 @@ deploy_lrt_cluster() { --template-file "$template_file"; then print_success "Deployment completed successfully!" - # Get AKS cluster name + # Connect to the AKS cluster local aks_cluster aks_cluster=$(az aks list --resource-group "$resource_group" --query '[0].name' -o tsv 2>/dev/null || echo "") + az aks get-credentials --resource-group "$resource_group" --name "$aks_cluster" --admin --overwrite-existing --output none + if [[ -n "$aks_cluster" ]]; then - print_info "AKS Cluster: $aks_cluster" + # Connect to cluster + print_success "AKS cluster created and connected: '$aks_cluster'." print_info "To connect to the cluster, run:" - print_info " az aks get-credentials --resource-group $resource_group --name $aks_cluster" + print_info " az aks get-credentials --resource-group $resource_group --name $aks_cluster --admin" print_info "To delete the cluster, run:" print_info " az group delete --name $resource_group --yes --no-wait" fi @@ -104,5 +107,105 @@ deploy_lrt_cluster() { fi } -check_azure_cli -deploy_lrt_cluster +set_test_env() { + + # Required environment variables + # You must be connected to a kubernetes cluster + # Radius must be installed locally + + export AZURE_SUBSCRIPTION_ID="${AZURE_SUBSCRIPTION_ID:-$(az account show --query id -o tsv)}" + export AZURE_SP_TESTS_APPID="960d45e2-3636-46f7-ac3a-57262dc5e9c5" + export AZURE_SP_TESTS_TENANTID=${AZURE_SP_TESTS_TENANTID:-$(az account show --query tenantId -o tsv)} + export TEST_BICEP_TYPES_REGISTRY="${TEST_BICEP_TYPES_REGISTRY:-testuserdefinedbiceptypes.azurecr.io}" + RAD_VERSION="${RAD_VERSION:-$(rad version -o json | jq -r ".release //empty")}" + export RAD_VERSION + export BICEP_RECIPE_TAG_VERSION="${BICEP_RECIPE_TAG_VERSION:-$RAD_VERSION}" # Use the RAD version as the tag for recipes by default + export BICEP_RECIPE_REGISTRY="${BICEP_RECIPE_REGISTRY:-ghcr.io/radius-project/dev/test/recipes}" + + # Resource group where tests will deploy resources + local id="${GITHUB_RUN_NUMBER:-$(whoami)}" + TEST_RESOURCE_GROUP=${TEST_RESOURCE_GROUP:-($(whoami)-test-$(echo "$id" | sha1sum | head -c 5))} + export TEST_RESOURCE_GROUP + export TEST_RESOURCE_GROUP_LOCATION="${TEST_RESOURCE_GROUP_LOCATION:-westus3}" +} + +run_lrt() { + set_test_env + + print_info "Running long-running tests against the AKS cluster..." + + print_info "Publishing Bicep types to registry..." + rad bicep publish-extension -f ./test/functional-portable/dynamicrp/noncloud/resources/testdata/testresourcetypes.yaml --target types.tgz --force + make publish-test-bicep-recipes + + print_info "Creating resource group for tests '$TEST_RESOURCE_GROUP' in location '$TEST_RESOURCE_GROUP_LOCATION'..." + az group create --name "$TEST_RESOURCE_GROUP" --location "$TEST_RESOURCE_GROUP_LOCATION" --output none + + print_info "Installing Radius CLI..." + rad install kubernetes --reinstall + + # Ensure that all pods are running before proceeding + kubectl wait --for=condition=available --all deployments --namespace radius-system --timeout=120s + + rad workspace create kubernetes --force + rad group create default + rad group switch default + rad env create default --namespace default + rad env switch default + rad env update default --azure-subscription-id "$AZURE_SUBSCRIPTION_ID" --azure-resource-group "$TEST_RESOURCE_GROUP" + rad credential register azure wi --client-id "$AZURE_SP_TESTS_APPID" --tenant-id "$AZURE_SP_TESTS_TENANTID" + + # rad env update ${{ env.RADIUS_TEST_ENVIRONMENT_NAME }} --aws-region ${{ env.AWS_REGION }} --aws-account-id ${{ secrets.FUNCTEST_AWS_ACCOUNT_ID }} + # rad credential register aws access-key \ + # --access-key-id ${{ secrets.FUNCTEST_AWS_ACCESS_KEY_ID }} --secret-access-key ${{ secrets.FUNCTEST_AWS_SECRET_ACCESS_KEY }} + + # curl -s https://fluxcd.io/install.sh | FLUX_VERSION=2.5.1 sudo bash + # flux install --namespace=flux-system --version=v2.5.1 --components=source-controller --network-policy=false + # kubectl wait --for=condition=available deployment -l app.kubernetes.io/component=source-controller -n flux-system --timeout=120s + + # Install Gitea + + make publish-test-terraform-recipes + + # FUNC_TEST_OIDC_ISSUER not used + # export FUNCTEST_OIDC_ISSUER=$(az aks show -n $AKS_CLUSTER_NAME -g $AZURE_RESOURCE_GROUP --query "oidcIssuerProfile.issuerUrl" -otsv) + + # Restore Radius Bicep types + bicep restore ./test/functional-portable/corerp/cloud/resources/testdata/corerp-azure-connection-database-service.bicep --force + # Restore AWS Bicep types + bicep restore ./test/functional-portable/corerp/cloud/resources/testdata/aws-s3-bucket.bicep --force + + # make test-functional-all + + #Delete the resource group after tests + print_info "Deleting resource group '$TEST_RESOURCE_GROUP'..." + az group delete --name "$TEST_RESOURCE_GROUP" --yes --no-wait +} + +main() { + if [[ $# -eq 0 ]]; then + print_error "No command specified." + print_info "Available commands: deploy-lrt-cluster, run-lrt" + exit 1 + fi + + local command="$1" + check_azure_cli + + case "$command" in + "deploy-lrt-cluster") + deploy_lrt_cluster + ;; + "run-lrt") + run_lrt + ;; + *) + print_error "Unknown command: $command" + print_info "Available commands: deploy-lrt-cluster, run-lrt" + exit 1 + ;; + esac +} + +# Run main function with all arguments +main "$@" From db0cf16ed5ac16fdf27c61c2ef1d4dee597fc5f0 Mon Sep 17 00:00:00 2001 From: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> Date: Sat, 14 Jun 2025 17:38:25 -0700 Subject: [PATCH 08/14] deploy cluster Signed-off-by: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> --- .github/actions/install-flux/install-flux.sh | 1 + .../actions/install-gitea/install-gitea.sh | 4 +- build/install.mk | 19 +++- build/test.sh | 104 ++++++++++++------ 4 files changed, 90 insertions(+), 38 deletions(-) diff --git a/.github/actions/install-flux/install-flux.sh b/.github/actions/install-flux/install-flux.sh index a9010389f1..f813918ed2 100755 --- a/.github/actions/install-flux/install-flux.sh +++ b/.github/actions/install-flux/install-flux.sh @@ -26,6 +26,7 @@ if [ -z "$FLUX_VERSION" ]; then fi for i in 1 2 3; do + echo "Attempt $i to install Flux version $FLUX_VERSION..." flux install --namespace=flux-system --version=v"$FLUX_VERSION" --components=source-controller --network-policy=false && \ kubectl wait --for=condition=available deployment -l app.kubernetes.io/component=source-controller -n flux-system --timeout=120s && break echo "Attempt $i failed, retrying in 10 seconds..." diff --git a/.github/actions/install-gitea/install-gitea.sh b/.github/actions/install-gitea/install-gitea.sh index 9206599391..7e22a17344 100755 --- a/.github/actions/install-gitea/install-gitea.sh +++ b/.github/actions/install-gitea/install-gitea.sh @@ -73,4 +73,6 @@ echo "$output" output=$(kubectl exec -it "$gitea_pod" -n gitea -- gitea admin user generate-access-token --username "$GITEA_USERNAME" --token-name "$GITEA_ACCESS_TOKEN_NAME" --scopes "write:repository,write:user" --raw) echo "$output" -echo "gitea-access-token=$output" >> "$GITHUB_OUTPUT" +if [ -n "$GITHUB_OUTPUT" ]; then + echo "gitea-access-token=$output" >> "$GITHUB_OUTPUT" +fi diff --git a/build/install.mk b/build/install.mk index 5f8ef41759..0dfa2c9601 100644 --- a/build/install.mk +++ b/build/install.mk @@ -26,4 +26,21 @@ install: build-binaries ## Installs a local build for development .PHONY: install-latest install-latest: ## Installs the latest release from GitHub @echo "$(ARROW) Installing latest rad release" - @bash ./deploy/install.sh \ No newline at end of file + @bash ./deploy/install.sh + +FLUX_VERSION ?= 2.5.1 +.PHONY: install-flux +install-flux: ## Installs flux using the install script + @echo "$(ARROW) Installing flux" + @export FLUX_VERSION=$(FLUX_VERSION) && curl -s https://fluxcd.io/install.sh | sudo -E bash + @./.github/actions/install-flux/install-flux.sh $(FLUX_VERSION) + +GITEA_VERSION ?= v11.0.0 +GITEA_USERNAME ?= "testuser" +GITEA_EMAIL ?= "testuser@radapp.io" +GITEA_ACCESS_TOKEN_NAME ?= "radius-functional-test" +GITEA_PASSWORD ?= "testpassword" +.PHONY: install-gitea +install-gitea: ## Installs gitea + @echo "$(ARROW) Installing gitea" + @export GITEA_PASSWORD=$(GITEA_PASSWORD) && .github/actions/install-gitea/install-gitea.sh $(GITEA_VERSION) $(GITEA_USERNAME) $(GITEA_EMAIL) $(GITEA_ACCESS_TOKEN_NAME) \ No newline at end of file diff --git a/build/test.sh b/build/test.sh index b469375397..2e72aa60de 100755 --- a/build/test.sh +++ b/build/test.sh @@ -56,8 +56,36 @@ check_azure_cli() { fi } +set_test_env() { + + # Required environment variables + # You must be connected to a kubernetes cluster + # Radius must be installed locally + + export AZURE_SUBSCRIPTION_ID="${AZURE_SUBSCRIPTION_ID:-$(az account show --query id -o tsv)}" + export AZURE_SP_TESTS_APPID="960d45e2-3636-46f7-ac3a-57262dc5e9c5" + export AZURE_SP_TESTS_TENANTID=${AZURE_SP_TESTS_TENANTID:-$(az account show --query tenantId -o tsv)} + export TEST_BICEP_TYPES_REGISTRY="${TEST_BICEP_TYPES_REGISTRY:-testuserdefinedbiceptypes.azurecr.io}" + RAD_VERSION="${RAD_VERSION:-$(rad version -o json | jq -r ".release //empty")}" + export RAD_VERSION + export BICEP_RECIPE_TAG_VERSION="${BICEP_RECIPE_TAG_VERSION:-$RAD_VERSION}" # Use the RAD version as the tag for recipes by default + export BICEP_RECIPE_REGISTRY="${BICEP_RECIPE_REGISTRY:-ghcr.io/radius-project/dev/test/recipes}" + + # Resource group where tests will deploy resources + local id="${GITHUB_RUN_NUMBER:-$(whoami)}" + TEST_RESOURCE_GROUP=${TEST_RESOURCE_GROUP:-$(whoami)-test-$(echo "$id" | sha1sum | head -c 5)} + export TEST_RESOURCE_GROUP + export TEST_RESOURCE_GROUP_LOCATION="${TEST_RESOURCE_GROUP_LOCATION:-westus3}" + +} + # Deploy long-running test cluster deploy_lrt_cluster() { + set_test_env + + # Install latest Radius CLI release + make install-latest + print_info "Deploying long-running test cluster to Azure..." # Default values (can be overridden by environment variables) @@ -77,6 +105,13 @@ deploy_lrt_cluster() { az provider register --namespace Microsoft.ContainerService fi + # Check if resource group exists and delete it if it does + if az group exists --name "$resource_group" --output tsv | grep -q "true"; then + print_warning "Resource group '$resource_group' already exists. Deleting it..." + az group delete --name "$resource_group" --yes + print_success "Resource group '$resource_group' deleted successfully." + fi + print_info "Creating resource group '$resource_group' in location '$location'..." az group create --location "$location" --resource-group "$resource_group" --output none print_success "Resource group created successfully." @@ -105,35 +140,7 @@ deploy_lrt_cluster() { print_error "Deployment failed!" exit 1 fi -} -set_test_env() { - - # Required environment variables - # You must be connected to a kubernetes cluster - # Radius must be installed locally - - export AZURE_SUBSCRIPTION_ID="${AZURE_SUBSCRIPTION_ID:-$(az account show --query id -o tsv)}" - export AZURE_SP_TESTS_APPID="960d45e2-3636-46f7-ac3a-57262dc5e9c5" - export AZURE_SP_TESTS_TENANTID=${AZURE_SP_TESTS_TENANTID:-$(az account show --query tenantId -o tsv)} - export TEST_BICEP_TYPES_REGISTRY="${TEST_BICEP_TYPES_REGISTRY:-testuserdefinedbiceptypes.azurecr.io}" - RAD_VERSION="${RAD_VERSION:-$(rad version -o json | jq -r ".release //empty")}" - export RAD_VERSION - export BICEP_RECIPE_TAG_VERSION="${BICEP_RECIPE_TAG_VERSION:-$RAD_VERSION}" # Use the RAD version as the tag for recipes by default - export BICEP_RECIPE_REGISTRY="${BICEP_RECIPE_REGISTRY:-ghcr.io/radius-project/dev/test/recipes}" - - # Resource group where tests will deploy resources - local id="${GITHUB_RUN_NUMBER:-$(whoami)}" - TEST_RESOURCE_GROUP=${TEST_RESOURCE_GROUP:-($(whoami)-test-$(echo "$id" | sha1sum | head -c 5))} - export TEST_RESOURCE_GROUP - export TEST_RESOURCE_GROUP_LOCATION="${TEST_RESOURCE_GROUP_LOCATION:-westus3}" -} - -run_lrt() { - set_test_env - - print_info "Running long-running tests against the AKS cluster..." - print_info "Publishing Bicep types to registry..." rad bicep publish-extension -f ./test/functional-portable/dynamicrp/noncloud/resources/testdata/testresourcetypes.yaml --target types.tgz --force make publish-test-bicep-recipes @@ -159,12 +166,6 @@ run_lrt() { # rad credential register aws access-key \ # --access-key-id ${{ secrets.FUNCTEST_AWS_ACCESS_KEY_ID }} --secret-access-key ${{ secrets.FUNCTEST_AWS_SECRET_ACCESS_KEY }} - # curl -s https://fluxcd.io/install.sh | FLUX_VERSION=2.5.1 sudo bash - # flux install --namespace=flux-system --version=v2.5.1 --components=source-controller --network-policy=false - # kubectl wait --for=condition=available deployment -l app.kubernetes.io/component=source-controller -n flux-system --timeout=120s - - # Install Gitea - make publish-test-terraform-recipes # FUNC_TEST_OIDC_ISSUER not used @@ -174,12 +175,43 @@ run_lrt() { bicep restore ./test/functional-portable/corerp/cloud/resources/testdata/corerp-azure-connection-database-service.bicep --force # Restore AWS Bicep types bicep restore ./test/functional-portable/corerp/cloud/resources/testdata/aws-s3-bucket.bicep --force + make install-flux + make install-gitea +} +run_lrt() { + set_test_env + + print_info "Running long-running tests against the AKS cluster..." + # make test-functional-all + #make test-functional-ucp + # make test-functional-kubernetes + + # Time out and one failure + # make test-functional-corerp + + # No return + #make test-functional-cli + + # 4 tests, 4 failures + #make test-functional-msgrp + + # 8 failures + #make test-functional-daprrp + + # 6 failures + #make test-functional-datastoresrp + + # Needs path to samples repo + #make test-functional-samples + + # 4 failures + #make test-functional-dynamicrp-noncloud #Delete the resource group after tests - print_info "Deleting resource group '$TEST_RESOURCE_GROUP'..." - az group delete --name "$TEST_RESOURCE_GROUP" --yes --no-wait + #print_info "Deleting resource group '$TEST_RESOURCE_GROUP'..." + #az group delete --name "$TEST_RESOURCE_GROUP" --yes --no-wait } main() { From ee5811f2f145f4aa8608560ee810bfafbecc7ec4 Mon Sep 17 00:00:00 2001 From: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> Date: Sat, 14 Jun 2025 19:13:14 -0700 Subject: [PATCH 09/14] env file Signed-off-by: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> --- build/.gitignore | 2 + build/test.mk | 8 ++- build/test.sh | 131 +++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 119 insertions(+), 22 deletions(-) create mode 100644 build/.gitignore diff --git a/build/.gitignore b/build/.gitignore new file mode 100644 index 0000000000..bb5e46a28a --- /dev/null +++ b/build/.gitignore @@ -0,0 +1,2 @@ +# Exclude environment files +*.env diff --git a/build/test.mk b/build/test.mk index 9fdb022192..2901325737 100644 --- a/build/test.mk +++ b/build/test.mk @@ -156,8 +156,12 @@ test-ucp-spec-examples: oav-installed ## Validates UCP examples conform to UCP O .PHONY: test-deploy-aks-cluster test-deploy-aks-cluster: ## Deploys an AKS cluster to Azure for the long-running tests. Optional parameters: [LRT_AZURE_LOCATION=] [LRT_RG=] - @bash ./build/test.sh deploy-lrt-cluster + @bash ./build/test.sh deploy-aks-cluster .PHONY: test-lrt test-lrt: ## Runs the long-running tests against the AKS cluster deployed by test-deploy-lrt-cluster using the currently installed version of the Radius CLI and the current az authenticated subscription. - @bash ./build/test.sh run-lrt \ No newline at end of file + @bash ./build/test.sh run-lrt + +.PHONY: test-create-env-file +test-create-env-file: ## Creates a test.env file with environment variables for testing + ./build/test.sh create-env-file \ No newline at end of file diff --git a/build/test.sh b/build/test.sh index 2e72aa60de..310ca0a21d 100755 --- a/build/test.sh +++ b/build/test.sh @@ -56,32 +56,101 @@ check_azure_cli() { fi } -set_test_env() { - - # Required environment variables - # You must be connected to a kubernetes cluster - # Radius must be installed locally - +# All environment variables required for the tests +get_env_vars() { + + local env_vars=( + "AZURE_SUBSCRIPTION_ID" + "AZURE_SP_TESTS_APPID" + "AZURE_SP_TESTS_TENANTID" + "TEST_BICEP_TYPES_REGISTRY" + "RAD_VERSION" + "BICEP_RECIPE_TAG_VERSION" + "BICEP_RECIPE_REGISTRY" + "TEST_RESOURCE_GROUP" + "TEST_RESOURCE_GROUP_LOCATION" + ) + + printf '%s\n' "${env_vars[@]}" +} + +set_env_defaults(){ + # Set default values for environment variables if not already set export AZURE_SUBSCRIPTION_ID="${AZURE_SUBSCRIPTION_ID:-$(az account show --query id -o tsv)}" - export AZURE_SP_TESTS_APPID="960d45e2-3636-46f7-ac3a-57262dc5e9c5" - export AZURE_SP_TESTS_TENANTID=${AZURE_SP_TESTS_TENANTID:-$(az account show --query tenantId -o tsv)} + export AZURE_SP_TESTS_APPID="${AZURE_SP_TESTS_APPID:-960d45e2-3636-46f7-ac3a-57262dc5e9c5}" + export AZURE_SP_TESTS_TENANTID="${AZURE_SP_TESTS_TENANTID:-$(az account show --query tenantId -o tsv)}" export TEST_BICEP_TYPES_REGISTRY="${TEST_BICEP_TYPES_REGISTRY:-testuserdefinedbiceptypes.azurecr.io}" - RAD_VERSION="${RAD_VERSION:-$(rad version -o json | jq -r ".release //empty")}" - export RAD_VERSION - export BICEP_RECIPE_TAG_VERSION="${BICEP_RECIPE_TAG_VERSION:-$RAD_VERSION}" # Use the RAD version as the tag for recipes by default + if [[ -n "${RAD_VERSION:-}" ]]; then + export BICEP_RECIPE_TAG_VERSION="${BICEP_RECIPE_TAG_VERSION:-$RAD_VERSION}" # Use the RAD version as the tag for recipes by default + fi export BICEP_RECIPE_REGISTRY="${BICEP_RECIPE_REGISTRY:-ghcr.io/radius-project/dev/test/recipes}" # Resource group where tests will deploy resources local id="${GITHUB_RUN_NUMBER:-$(whoami)}" - TEST_RESOURCE_GROUP=${TEST_RESOURCE_GROUP:-$(whoami)-test-$(echo "$id" | sha1sum | head -c 5)} + TEST_RESOURCE_GROUP="${TEST_RESOURCE_GROUP:-$(whoami)-test-$(echo "$id" | sha1sum | head -c 5)}" export TEST_RESOURCE_GROUP export TEST_RESOURCE_GROUP_LOCATION="${TEST_RESOURCE_GROUP_LOCATION:-westus3}" +} + +# Create a test.env file with the required environment variables from the get_env_vars function +create_env_file() { + print_info " Creating test.env file with default values. Check the file contents to ensure accuracy." + set_env_defaults + local env_file_path="./build/test.env" + local env_vars + mapfile -t env_vars < <(get_env_vars) + { + echo "# Environment variables for tests" + + for var in "${env_vars[@]}"; do + echo "$var=\"${!var:-}\"" + done + } > $env_file_path || { + print_error "Failed to create test.env file." + exit 1 + } + + print_success "test.env file created successfully" + cat $env_file_path +} + +# Load environment variables from the test.env file if it exists. +# Validate that all required environment variables have values. +load_environment() { + + # Source the test environment file if it exists + if [[ -f "./build/test.env" ]]; then + # shellcheck source=/dev/null + source "./build/test.env" + fi + + # Validate that all required environment variables have values + print_info "Validating environment variables..." + local env_vars + mapfile -t env_vars < <(get_env_vars) + local missing_vars=() + for var in "${env_vars[@]}"; do + if [[ -z "${!var:-}" ]]; then + print_error "$var is not set or is empty" + missing_vars+=("$var") + else + print_success "$var is set" + fi + done + + if [[ ${#missing_vars[@]} -gt 0 ]]; then + print_error "Missing ${#missing_vars[@]} required environment variable(s). Exiting." + exit 1 + fi + + print_success "All required environment variables are properly set" } # Deploy long-running test cluster -deploy_lrt_cluster() { - set_test_env +deploy_aks_cluster() { + + load_environment # Install latest Radius CLI release make install-latest @@ -180,10 +249,11 @@ deploy_lrt_cluster() { } run_lrt() { - set_test_env print_info "Running long-running tests against the AKS cluster..." - + + load_environment + # make test-functional-all #make test-functional-ucp # make test-functional-kubernetes @@ -214,10 +284,25 @@ run_lrt() { #az group delete --name "$TEST_RESOURCE_GROUP" --yes --no-wait } +tear_down_aks_cluster() { + print_info "Tearing down AKS cluster and resource group..." + + load_environment + + if az group exists --name "$TEST_RESOURCE_GROUP" --output tsv | grep -q "true"; then + print_info "Deleting resource group '$TEST_RESOURCE_GROUP'..." + az group delete --name "$TEST_RESOURCE_GROUP" --yes --no-wait + print_success "Resource group '$TEST_RESOURCE_GROUP' deleted successfully." + else + print_warning "Resource group '$TEST_RESOURCE_GROUP' does not exist." + fi +} + main() { if [[ $# -eq 0 ]]; then print_error "No command specified." - print_info "Available commands: deploy-lrt-cluster, run-lrt" + local available_commands="create-env-file, deploy-aks-cluster, run-lrt" + print_info "Available commands: $available_commands" exit 1 fi @@ -225,15 +310,21 @@ main() { check_azure_cli case "$command" in - "deploy-lrt-cluster") - deploy_lrt_cluster + "load-environment") + load_environment + ;; + "create-env-file") + create_env_file + ;; + "deploy-aks-cluster") + deploy_aks_cluster ;; "run-lrt") run_lrt ;; *) print_error "Unknown command: $command" - print_info "Available commands: deploy-lrt-cluster, run-lrt" + print_info "Available commands: $available_commands" exit 1 ;; esac From ad71a8887865c66e18ae06a75bcd9c63a62ea603 Mon Sep 17 00:00:00 2001 From: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> Date: Sat, 14 Jun 2025 21:36:11 -0700 Subject: [PATCH 10/14] gh validation Signed-off-by: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> --- build/test.sh | 44 +++++++++++++++++++++++++++++++++++++------- 1 file changed, 37 insertions(+), 7 deletions(-) diff --git a/build/test.sh b/build/test.sh index 310ca0a21d..c9702af4db 100755 --- a/build/test.sh +++ b/build/test.sh @@ -74,17 +74,15 @@ get_env_vars() { printf '%s\n' "${env_vars[@]}" } +# Set default values for environment variables if not already set set_env_defaults(){ - # Set default values for environment variables if not already set export AZURE_SUBSCRIPTION_ID="${AZURE_SUBSCRIPTION_ID:-$(az account show --query id -o tsv)}" - export AZURE_SP_TESTS_APPID="${AZURE_SP_TESTS_APPID:-960d45e2-3636-46f7-ac3a-57262dc5e9c5}" export AZURE_SP_TESTS_TENANTID="${AZURE_SP_TESTS_TENANTID:-$(az account show --query tenantId -o tsv)}" export TEST_BICEP_TYPES_REGISTRY="${TEST_BICEP_TYPES_REGISTRY:-testuserdefinedbiceptypes.azurecr.io}" if [[ -n "${RAD_VERSION:-}" ]]; then export BICEP_RECIPE_TAG_VERSION="${BICEP_RECIPE_TAG_VERSION:-$RAD_VERSION}" # Use the RAD version as the tag for recipes by default fi export BICEP_RECIPE_REGISTRY="${BICEP_RECIPE_REGISTRY:-ghcr.io/radius-project/dev/test/recipes}" - # Resource group where tests will deploy resources local id="${GITHUB_RUN_NUMBER:-$(whoami)}" TEST_RESOURCE_GROUP="${TEST_RESOURCE_GROUP:-$(whoami)-test-$(echo "$id" | sha1sum | head -c 5)}" @@ -103,7 +101,7 @@ create_env_file() { echo "# Environment variables for tests" for var in "${env_vars[@]}"; do - echo "$var=\"${!var:-}\"" + echo "export $var=\"${!var:-}\"" done } > $env_file_path || { print_error "Failed to create test.env file." @@ -132,10 +130,10 @@ load_environment() { local missing_vars=() for var in "${env_vars[@]}"; do if [[ -z "${!var:-}" ]]; then - print_error "$var is not set or is empty" + print_error "$var" missing_vars+=("$var") else - print_success "$var is set" + print_success "$var" fi done @@ -298,6 +296,37 @@ tear_down_aks_cluster() { fi } +# Check if GitHub CLI is installed and authenticated +check_gh_auth_status() { + print_info "Checking GitHub CLI authentication status..." + if ! command -v gh &> /dev/null; then + print_error "GitHub CLI (gh) is required but not installed." + exit 1 + fi + + # Check if user is authenticated and has required scopes + if ! gh auth status &> /dev/null; then + print_error "GitHub CLI is not authenticated." + print_info "Please run 'gh auth login' to authenticate." + exit 1 + elif ! gh auth status 2>/dev/null | grep -q "write:packages"; then + print_warning "GitHub CLI does not have 'write:packages' scope. Please run 'gh auth refresh --scopes write:packages'." + exit 1 + fi + + # Docker must be available + if ! docker info &> /dev/null; then + print_error "Docker is not running or not accessible." + exit 1 + fi + + # Authenticate to ghcr.io in docker + gh_user=$(gh api user --jq .login) + print_info "Authenticating to ghcr.io as user: $gh_user" + docker_login_message=$(gh auth token | docker login ghcr.io -u "$gh_user" --password-stdin) + print_success "$docker_login_message" +} + main() { if [[ $# -eq 0 ]]; then print_error "No command specified." @@ -306,9 +335,10 @@ main() { exit 1 fi - local command="$1" check_azure_cli + check_gh_auth_status + local command="$1" case "$command" in "load-environment") load_environment From 7f7e16c79152c815b0492b7e92c9249f7284d372 Mon Sep 17 00:00:00 2001 From: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> Date: Mon, 16 Jun 2025 07:43:08 -0700 Subject: [PATCH 11/14] recipe version Signed-off-by: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> --- build/test.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build/test.sh b/build/test.sh index c9702af4db..32326e57e4 100755 --- a/build/test.sh +++ b/build/test.sh @@ -79,6 +79,8 @@ set_env_defaults(){ export AZURE_SUBSCRIPTION_ID="${AZURE_SUBSCRIPTION_ID:-$(az account show --query id -o tsv)}" export AZURE_SP_TESTS_TENANTID="${AZURE_SP_TESTS_TENANTID:-$(az account show --query tenantId -o tsv)}" export TEST_BICEP_TYPES_REGISTRY="${TEST_BICEP_TYPES_REGISTRY:-testuserdefinedbiceptypes.azurecr.io}" + RAD_VERSION=$(gh release list -R radius-project/radius --limit 1 --exclude-drafts --exclude-pre-releases --json tagName --jq ".[0].tagName") + export RAD_VERSION if [[ -n "${RAD_VERSION:-}" ]]; then export BICEP_RECIPE_TAG_VERSION="${BICEP_RECIPE_TAG_VERSION:-$RAD_VERSION}" # Use the RAD version as the tag for recipes by default fi From 934efdc84f358b73d13a3df79d7a96606b5c4764 Mon Sep 17 00:00:00 2001 From: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> Date: Mon, 16 Jun 2025 08:33:56 -0700 Subject: [PATCH 12/14] clearer output Signed-off-by: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> --- build/test.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/build/test.sh b/build/test.sh index 32326e57e4..85b9e8abd4 100755 --- a/build/test.sh +++ b/build/test.sh @@ -100,6 +100,7 @@ create_env_file() { local env_vars mapfile -t env_vars < <(get_env_vars) { + echo "# shellcheck disable=SC2148" echo "# Environment variables for tests" for var in "${env_vars[@]}"; do @@ -246,6 +247,7 @@ deploy_aks_cluster() { bicep restore ./test/functional-portable/corerp/cloud/resources/testdata/aws-s3-bucket.bicep --force make install-flux make install-gitea + print_success "Radius and test tools installed to cluster '$aks_cluster'." } run_lrt() { @@ -332,7 +334,7 @@ check_gh_auth_status() { main() { if [[ $# -eq 0 ]]; then print_error "No command specified." - local available_commands="create-env-file, deploy-aks-cluster, run-lrt" + local available_commands="load-environment, create-env-file, deploy-aks-cluster, run-lrt" print_info "Available commands: $available_commands" exit 1 fi From 0a43cb727536ab88652d97cf4d75cf877e7879db Mon Sep 17 00:00:00 2001 From: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> Date: Fri, 20 Jun 2025 17:53:37 -0400 Subject: [PATCH 13/14] working Signed-off-by: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> --- .../actions/install-gitea/install-gitea.sh | 2 + .../workflows/long-running-test-deploy.yaml | 34 ++++++++ build/install.mk | 2 +- build/test.mk | 6 +- build/test.sh | 86 ++++++++++++++++--- test/infra/azure/main.bicep | 9 ++ .../azure/modules/mongodb.bicep} | 4 +- 7 files changed, 130 insertions(+), 13 deletions(-) create mode 100644 .github/workflows/long-running-test-deploy.yaml rename test/{createAzureTestResources.bicep => infra/azure/modules/mongodb.bicep} (94%) diff --git a/.github/actions/install-gitea/install-gitea.sh b/.github/actions/install-gitea/install-gitea.sh index 7e22a17344..bd3c126bcf 100755 --- a/.github/actions/install-gitea/install-gitea.sh +++ b/.github/actions/install-gitea/install-gitea.sh @@ -75,4 +75,6 @@ echo "$output" if [ -n "$GITHUB_OUTPUT" ]; then echo "gitea-access-token=$output" >> "$GITHUB_OUTPUT" +else + export GITEA_ACCESS_TOKEN="$output" fi diff --git a/.github/workflows/long-running-test-deploy.yaml b/.github/workflows/long-running-test-deploy.yaml new file mode 100644 index 0000000000..4772a53d9c --- /dev/null +++ b/.github/workflows/long-running-test-deploy.yaml @@ -0,0 +1,34 @@ +# ------------------------------------------------------------ +# Copyright 2023 The Radius Authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# ------------------------------------------------------------ + +name: Long-running test on Azure + +permissions: + contents: read + packages: read + +on: + # Enable manual trigger to deploy the latest changes from main. + workflow_dispatch: + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Check Environment + run: make test-check-environment \ No newline at end of file diff --git a/build/install.mk b/build/install.mk index 0dfa2c9601..1b3de58163 100644 --- a/build/install.mk +++ b/build/install.mk @@ -39,7 +39,7 @@ GITEA_VERSION ?= v11.0.0 GITEA_USERNAME ?= "testuser" GITEA_EMAIL ?= "testuser@radapp.io" GITEA_ACCESS_TOKEN_NAME ?= "radius-functional-test" -GITEA_PASSWORD ?= "testpassword" +GITEA_PASSWORD ?= "" .PHONY: install-gitea install-gitea: ## Installs gitea @echo "$(ARROW) Installing gitea" diff --git a/build/test.mk b/build/test.mk index 2901325737..2d43ec74e3 100644 --- a/build/test.mk +++ b/build/test.mk @@ -164,4 +164,8 @@ test-lrt: ## Runs the long-running tests against the AKS cluster deployed by tes .PHONY: test-create-env-file test-create-env-file: ## Creates a test.env file with environment variables for testing - ./build/test.sh create-env-file \ No newline at end of file + ./build/test.sh create-env-file + +.PHONY: test-check-environment +test-check-environment: ## Checks the environment for required tools and configurations for testing + @bash ./build/test.sh check-environment \ No newline at end of file diff --git a/build/test.sh b/build/test.sh index 85b9e8abd4..177f4ebc1d 100755 --- a/build/test.sh +++ b/build/test.sh @@ -69,6 +69,7 @@ get_env_vars() { "BICEP_RECIPE_REGISTRY" "TEST_RESOURCE_GROUP" "TEST_RESOURCE_GROUP_LOCATION" + "AZURE_COSMOS_MONGODB_ACCOUNT_ID" ) printf '%s\n' "${env_vars[@]}" @@ -92,6 +93,60 @@ set_env_defaults(){ export TEST_RESOURCE_GROUP_LOCATION="${TEST_RESOURCE_GROUP_LOCATION:-westus3}" } +# Add a secret to kubernetes using kubectl +add_secret() { + local key="$1" + local value="$2" + local secret_name="lrt-secrets" + + if [[ -z "$key" || -z "$value" ]]; then + print_error "Both key and value parameters are required" + print_info "Usage: add_secret " + return 1 + fi + + print_info "Adding secret '$key' to Kubernetes secret '$secret_name'..." + + # Create or update the secret + if kubectl get secret "$secret_name" &>/dev/null; then + # Secret exists, patch it to add the new key + if kubectl patch secret "$secret_name" --type='merge' -p="{\"data\":{\"$key\":\"$(echo -n "$value" | base64 -w 0)\"}}"; then + print_success "Secret '$key' added to existing '$secret_name' successfully" + fi + else + # Secret doesn't exist, create it + if kubectl create secret generic "$secret_name" --from-literal="$key=$value"; then + print_success "Secret '$secret_name' created with '$key' successfully" + fi + fi +} + +# Load secrets from Kubernetes secret and export as environment variables +load_secrets() { + local secret_name="lrt-secrets" + + print_info "Loading secrets from Kubernetes secret '$secret_name'..." + + # Get all key-value pairs from the secret. This will fail if the secret does not exist. + local secret_data + secret_data=$(kubectl get secret "$secret_name" -o jsonpath='{.data}' 2>/dev/null) + + if [[ -z "$secret_data" || "$secret_data" == "{}" ]]; then + print_error "Secret '$secret_name' exists but contains no data." + exit 1 + fi + + # Parse and export each key-value pair + local keys + keys=$(echo "$secret_data" | jq -r 'keys[]' 2>/dev/null) + + for key in $keys; do + value=$(echo "$secret_data" | jq -r ".$key" | base64 -d 2>/dev/null) + print_success "$key" + export "$key"="$value" + done +} + # Create a test.env file with the required environment variables from the get_env_vars function create_env_file() { print_info " Creating test.env file with default values. Check the file contents to ensure accuracy." @@ -115,9 +170,8 @@ create_env_file() { cat $env_file_path } -# Load environment variables from the test.env file if it exists. # Validate that all required environment variables have values. -load_environment() { +check_environment() { # Source the test environment file if it exists if [[ -f "./build/test.env" ]]; then @@ -151,7 +205,7 @@ load_environment() { # Deploy long-running test cluster deploy_aks_cluster() { - load_environment + check_environment # Install latest Radius CLI release make install-latest @@ -193,7 +247,7 @@ deploy_aks_cluster() { --template-file "$template_file"; then print_success "Deployment completed successfully!" - # Connect to the AKS cluster + # Connect to the AKS cluster, assumes one cluster in the resource group local aks_cluster aks_cluster=$(az aks list --resource-group "$resource_group" --query '[0].name' -o tsv 2>/dev/null || echo "") az aks get-credentials --resource-group "$resource_group" --name "$aks_cluster" --admin --overwrite-existing --output none @@ -254,10 +308,16 @@ run_lrt() { print_info "Running long-running tests against the AKS cluster..." - load_environment + check_environment + + make test-functional-corerp + make test-functional-msgrp + make test-functional-daprrp + make test-functional-datastoresrp + # make test-functional-all - #make test-functional-ucp + # make test-functional-ucp # make test-functional-kubernetes # Time out and one failure @@ -289,7 +349,7 @@ run_lrt() { tear_down_aks_cluster() { print_info "Tearing down AKS cluster and resource group..." - load_environment + check_environment if az group exists --name "$TEST_RESOURCE_GROUP" --output tsv | grep -q "true"; then print_info "Deleting resource group '$TEST_RESOURCE_GROUP'..." @@ -334,7 +394,7 @@ check_gh_auth_status() { main() { if [[ $# -eq 0 ]]; then print_error "No command specified." - local available_commands="load-environment, create-env-file, deploy-aks-cluster, run-lrt" + local available_commands="load-secrets, add-secret, load-environment, create-env-file, deploy-aks-cluster, run-lrt" print_info "Available commands: $available_commands" exit 1 fi @@ -344,8 +404,8 @@ main() { local command="$1" case "$command" in - "load-environment") - load_environment + "check-environment") + check_environment ;; "create-env-file") create_env_file @@ -356,6 +416,12 @@ main() { "run-lrt") run_lrt ;; + "add-secret") + add_secret "$2" "$3" + ;; + "load-secrets") + load_secrets + ;; *) print_error "Unknown command: $command" print_info "Available commands: $available_commands" diff --git a/test/infra/azure/main.bicep b/test/infra/azure/main.bicep index a28c0a3936..54204bb26d 100644 --- a/test/infra/azure/main.bicep +++ b/test/infra/azure/main.bicep @@ -202,5 +202,14 @@ module deploymentScript './modules/deployment-script.bicep' = if (installKuberne ] } +module mongoDB './modules/mongodb.bicep' = { + name: 'mongodb' + params: { + name: '${prefix}-mongodb' + location: location + } +} + +output mongodbAccountID string = mongoDB.outputs.cosmosMongoAccountID output aksControlPlaneFQDN string = aksCluster.outputs.controlPlaneFQDN output grafanaDashboardFQDN string = grafanaEnabled ? grafanaDashboard.outputs.dashboardFQDN : '' diff --git a/test/createAzureTestResources.bicep b/test/infra/azure/modules/mongodb.bicep similarity index 94% rename from test/createAzureTestResources.bicep rename to test/infra/azure/modules/mongodb.bicep index 2bb507fa2f..c214e3d16e 100644 --- a/test/createAzureTestResources.bicep +++ b/test/infra/azure/modules/mongodb.bicep @@ -1,7 +1,9 @@ +param name string + param location string = resourceGroup().location resource account 'Microsoft.DocumentDB/databaseAccounts@2020-04-01' = { - name: 'account-radiustest' + name: name location: location kind: 'MongoDB' tags: { From 07e420ddb644706ea80637de552a02584450b937 Mon Sep 17 00:00:00 2001 From: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> Date: Fri, 27 Jun 2025 10:42:16 -0400 Subject: [PATCH 14/14] bicep warnings Signed-off-by: Brooke Hamilton <45323234+brooke-hamilton@users.noreply.github.com> --- test/infra/azure/main.bicep | 9 ++++----- test/infra/azure/modules/datacollection.bicep | 3 --- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/test/infra/azure/main.bicep b/test/infra/azure/main.bicep index 54204bb26d..9d8165a2d3 100644 --- a/test/infra/azure/main.bicep +++ b/test/infra/azure/main.bicep @@ -47,6 +47,8 @@ param azureMonitorWorkspaceName string = '${prefix}-azm-workspace' param azureMonitorWorkspaceLocation string = 'westus2' @description('Specifies the name of aks cluster. Default is {prefix}-aks.') +@minLength(1) +@maxLength(63) param aksClusterName string = '${prefix}-aks' @description('Enables Azure Monitoring and Grafana Dashboard. Default is false.') @@ -170,7 +172,7 @@ module alertManagement './modules/alert-management.bicep' = if (grafanaEnabled) } // This is a workaround to get the AKS cluster resource created by aksCluster module -resource aks 'Microsoft.ContainerService/managedClusters@2023-05-01' existing = { +resource aks 'Microsoft.ContainerService/managedClusters@2023-10-01' existing = { name: aksCluster.name } @@ -181,7 +183,7 @@ module promConfigMap './modules/ama-metrics-setting-configmap.bicep' = if (grafa kubeConfig: aks.listClusterAdminCredential().kubeconfigs[0].value } dependsOn: [ - aks, aksCluster, dataCollection, alertManagement + aks, dataCollection, alertManagement ] } @@ -197,9 +199,6 @@ module deploymentScript './modules/deployment-script.bicep' = if (installKuberne location: location tags: defaultTags } - dependsOn: [ - aksCluster - ] } module mongoDB './modules/mongodb.bicep' = { diff --git a/test/infra/azure/modules/datacollection.bicep b/test/infra/azure/modules/datacollection.bicep index d96e8eadbf..e26d6f7e22 100644 --- a/test/infra/azure/modules/datacollection.bicep +++ b/test/infra/azure/modules/datacollection.bicep @@ -95,9 +95,6 @@ module azureMonitorMetricsDcraClusterResourceId './datacollection-dcra.bicep' = dcraName: dcraName clusterLocation: clusterLocation } - dependsOn: [ - dce - ] } // Output