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

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 135 additions & 0 deletions .github/actions/run-zathras-test/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
name: 'Run Zathras Test'
description: 'Execute Zathras benchmark test and validate results'

inputs:
scenario-file:
description: 'Path to the test scenario file'
required: true
cloud-os-id:
description: 'Cloud OS ID (AMI, image, etc.)'
required: false
additional-args:
description: 'Additional arguments to pass to burden'
required: false
default: ''

outputs:
test-status:
description: 'Test execution status (success/failure)'
value: ${{ steps.validate.outputs.status }}
results-path:
description: 'Path to test results directory'
value: ${{ steps.run.outputs.results_path }}

runs:
using: "composite"
steps:
- name: Prepare scenario file
id: prepare
shell: bash
env:
SCENARIO_FILE: ${{ inputs.scenario-file }}
CLOUD_OS_ID: ${{ inputs.cloud-os-id }}
run: |
# Copy scenario file to temporary location and inject runtime values
SCENARIO_TEMP="/tmp/zathras_ci_scenario_${{ github.run_id }}.yml"
cp "$SCENARIO_FILE" "$SCENARIO_TEMP"

# Inject cloud_os_id if provided
if [ -n "$CLOUD_OS_ID" ]; then
# Use yq to add cloud_os_id to global section
python3 -c "
import yaml
import sys
with open('$SCENARIO_TEMP', 'r') as f:
data = yaml.safe_load(f)
if 'global' not in data:
data['global'] = {}
data['global']['cloud_os_id'] = '$CLOUD_OS_ID'
data['global']['ssh_key_file'] = '$ZATHRAS_SSH_KEY'
with open('$SCENARIO_TEMP', 'w') as f:
yaml.dump(data, f, default_flow_style=False)
"
fi

echo "scenario_path=$SCENARIO_TEMP" >> $GITHUB_OUTPUT
echo "Using scenario file: $SCENARIO_TEMP"
cat "$SCENARIO_TEMP"

- name: Run Zathras test
id: run
shell: bash
env:
SCENARIO_PATH: ${{ steps.prepare.outputs.scenario_path }}
ADDITIONAL_ARGS: ${{ inputs.additional-args }}
run: |
# Execute burden with scenario file
echo "Starting Zathras test..."
echo "Scenario: $SCENARIO_PATH"
echo "Additional args: $ADDITIONAL_ARGS"

# Run burden and capture output
set +e # Don't exit on error, we want to capture the exit code
./bin/burden --scenario "$SCENARIO_PATH" $ADDITIONAL_ARGS
BURDEN_EXIT_CODE=$?
set -e

echo "burden_exit_code=$BURDEN_EXIT_CODE" >> $GITHUB_OUTPUT

# Find results directory (burden creates timestamped directories)
RESULTS_DIR=$(find . -maxdepth 1 -type d -name "zathras_*" -printf '%T@ %p\n' | sort -n | tail -1 | cut -d' ' -f2-)
if [ -z "$RESULTS_DIR" ]; then
RESULTS_DIR="./results"
fi
echo "results_path=$RESULTS_DIR" >> $GITHUB_OUTPUT

exit $BURDEN_EXIT_CODE

- name: Validate test results
id: validate
shell: bash
env:
RESULTS_PATH: ${{ steps.run.outputs.results_path }}
BURDEN_EXIT_CODE: ${{ steps.run.outputs.burden_exit_code }}
run: |
echo "Validating test results..."
echo "Results directory: $RESULTS_PATH"
echo "Burden exit code: $BURDEN_EXIT_CODE"

# Check if burden succeeded
if [ "$BURDEN_EXIT_CODE" -ne 0 ]; then
echo "❌ Burden failed with exit code: $BURDEN_EXIT_CODE"
echo "status=failure" >> $GITHUB_OUTPUT
exit 1
fi

# Check if results directory exists
if [ ! -d "$RESULTS_PATH" ]; then
echo "❌ Results directory not found: $RESULTS_PATH"
echo "status=failure" >> $GITHUB_OUTPUT
exit 1
fi

# Check if any result files were generated
RESULT_FILES=$(find "$RESULTS_PATH" -type f -name "*.json" -o -name "*.csv" -o -name "*.txt" | wc -l)
if [ "$RESULT_FILES" -eq 0 ]; then
echo "⚠️ Warning: No result files found in $RESULTS_PATH"
else
echo "✅ Found $RESULT_FILES result files"
fi

# List results
echo "Results directory contents:"
ls -lah "$RESULTS_PATH" || true

echo "✅ Test completed successfully"
echo "status=success" >> $GITHUB_OUTPUT

- name: Upload test results
if: always()
uses: actions/upload-artifact@v4
with:
name: zathras-results-${{ github.run_id }}-${{ strategy.job-index || '0' }}
path: ${{ steps.run.outputs.results_path }}
retention-days: 30
if-no-files-found: warn
80 changes: 80 additions & 0 deletions .github/actions/setup-zathras/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
name: 'Setup Zathras'
description: 'Install Zathras dependencies and prepare for testing'

inputs:
ssh-private-key:
description: 'SSH private key for accessing cloud instances'
required: true

outputs:
zathras-version:
description: 'Zathras git commit SHA'
value: ${{ steps.version.outputs.sha }}

runs:
using: "composite"
steps:
- name: Check out repository
uses: actions/checkout@v4

- name: Get Zathras version
id: version
shell: bash
run: echo "sha=$(git rev-parse HEAD)" >> $GITHUB_OUTPUT

- name: Install system dependencies
shell: bash
run: |
# Install required system packages
sudo dnf install -y \
ansible-core \
git \
jq \
python3 \
python3-pip \
unzip \
wget

- name: Install Terraform
shell: bash
run: |
# Install Terraform 1.9.8
TERRAFORM_VERSION="1.9.8"
wget -q https://releases.hashicorp.com/terraform/${TERRAFORM_VERSION}/terraform_${TERRAFORM_VERSION}_linux_amd64.zip
unzip -q terraform_${TERRAFORM_VERSION}_linux_amd64.zip
sudo mv terraform /usr/local/bin/
terraform --version

- name: Install Python dependencies
shell: bash
run: |
# Install required Python packages
pip install --user boto boto3 yq==2.10.0

- name: Install Ansible collections
shell: bash
run: |
# Install required Ansible collections
ansible-galaxy collection install amazon.aws:9.1.0
ansible-galaxy collection install ansible.posix
ansible-galaxy collection install community.aws
ansible-galaxy collection install community.general

- name: Set up SSH key
shell: bash
env:
SSH_PRIVATE_KEY: ${{ inputs.ssh-private-key }}
run: |
# Configure SSH key for cloud instance access
mkdir -p ~/.ssh
echo "$SSH_PRIVATE_KEY" > ~/.ssh/zathras_ci_key
chmod 600 ~/.ssh/zathras_ci_key
echo "ZATHRAS_SSH_KEY=$HOME/.ssh/zathras_ci_key" >> $GITHUB_ENV

- name: Verify Zathras installation
shell: bash
run: |
# Verify bin/burden exists and is executable
ls -la bin/burden
file bin/burden
head -n 5 bin/burden
132 changes: 132 additions & 0 deletions .github/workflows/test-aws.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
name: Test AWS

on:
# Manual trigger
workflow_dispatch:
inputs:
aws_region:
description: 'AWS region for testing'
required: false
default: 'us-east-1'
instance_type:
description: 'EC2 instance type (leave empty for default m5.xlarge)'
required: false
ami_id:
description: 'AMI ID (leave empty for default RHEL 9)'
required: false

# Automatic trigger on PR to main
pull_request:
branches:
- main
paths:
- 'bin/**'
- 'ansible_roles/**'
- 'config/**'
- 'ci/test_scenarios/aws_ci_test.yml'
- '.github/workflows/test-aws.yml'
- '.github/actions/**'

# Permissions required for OIDC authentication to AWS
permissions:
id-token: write # Required for requesting JWT
contents: read # Required for actions/checkout
pull-requests: write # Required for commenting on PRs

env:
AWS_REGION: ${{ inputs.aws_region || 'us-east-1' }}
SCENARIO_FILE: ci/test_scenarios/aws_ci_test.yml

jobs:
test-aws:
name: Test on AWS
runs-on: ubuntu-latest
timeout-minutes: 60 # Prevent runaway costs

steps:
- name: Configure AWS credentials via OIDC
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_OIDC_ROLE_ARN }}
aws-region: ${{ env.AWS_REGION }}
role-session-name: ZathrasCI-${{ github.run_id }}

- name: Verify AWS authentication
run: |
echo "Verifying AWS credentials..."
aws sts get-caller-identity
echo "AWS CLI configured successfully"

- name: Set up Zathras
uses: ./.github/actions/setup-zathras
with:
ssh-private-key: ${{ secrets.AWS_SSH_PRIVATE_KEY }}

- name: Determine AMI ID
id: ami
run: |
# Use provided AMI or find latest RHEL 9 AMI
if [ -n "${{ inputs.ami_id }}" ]; then
AMI_ID="${{ inputs.ami_id }}"
echo "Using provided AMI: $AMI_ID"
else
# Find latest RHEL 9 AMI in the region
AMI_ID=$(aws ec2 describe-images \
--region ${{ env.AWS_REGION }} \
--owners 309956199498 \
--filters "Name=name,Values=RHEL-9.*_HVM-*-x86_64-*" \
"Name=state,Values=available" \
--query 'Images | sort_by(@, &CreationDate) | [-1].ImageId' \
--output text)
echo "Found latest RHEL 9 AMI: $AMI_ID"
fi
echo "ami_id=$AMI_ID" >> $GITHUB_OUTPUT

- name: Run Zathras test on AWS
id: test
uses: ./.github/actions/run-zathras-test
with:
scenario-file: ${{ env.SCENARIO_FILE }}
cloud-os-id: ${{ steps.ami.outputs.ami_id }}
additional-args: ${{ inputs.instance_type && format('--host_config {0}', inputs.instance_type) || '' }}

- name: Check for orphaned resources
if: always()
run: |
echo "Checking for orphaned EC2 instances..."
aws ec2 describe-instances \
--region ${{ env.AWS_REGION }} \
--filters "Name=tag:ManagedBy,Values=Zathras" \
"Name=instance-state-name,Values=running,pending,stopping,stopped" \
--query 'Reservations[*].Instances[*].[InstanceId,State.Name,Tags[?Key==`Name`].Value|[0]]' \
--output table || true

- name: Post results to PR
if: github.event_name == 'pull_request' && always()
uses: actions/github-script@v7
with:
script: |
const status = '${{ steps.test.outputs.test-status }}';
const emoji = status === 'success' ? '✅' : '❌';
const body = `## ${emoji} AWS Test Results

**Status:** ${status}
**Region:** ${{ env.AWS_REGION }}
**AMI:** ${{ steps.ami.outputs.ami_id }}
**Workflow:** [Run #${{ github.run_number }}](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})

${status === 'success' ? 'All tests passed successfully!' : 'Tests failed. Check workflow logs for details.'}
`;

github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: body
});

- name: Fail workflow if tests failed
if: steps.test.outputs.test-status != 'success'
run: |
echo "❌ AWS tests failed"
exit 1
Loading
Loading