mirror of
https://github.com/mulgadc/spinifex.git
synced 2026-10-20 03:11:46 +00:00
728 lines
25 KiB
Bash
Executable File
728 lines
25 KiB
Bash
Executable File
#!/bin/bash
|
|
set -e
|
|
|
|
# Source helper functions for SSH testing
|
|
source ./tests/e2e/lib/multinode-helpers.sh
|
|
|
|
# Ensure services are stopped on exit and print logs on failure
|
|
cleanup() {
|
|
EXIT_CODE=$?
|
|
if [ $EXIT_CODE -ne 0 ]; then
|
|
echo ""
|
|
echo "=== NATS Service Log ==="
|
|
if [ -f ~/hive/logs/nats.log ]; then
|
|
tail -100 ~/hive/logs/nats.log 2>/dev/null
|
|
fi
|
|
echo ""
|
|
echo "=== Predastore Service Log ==="
|
|
if [ -f ~/hive/logs/predastore.log ]; then
|
|
tail -100 ~/hive/logs/predastore.log 2>/dev/null
|
|
fi
|
|
echo ""
|
|
echo "=== Viperblock Service Log ==="
|
|
if [ -f ~/hive/logs/viperblock.log ]; then
|
|
tail -100 ~/hive/logs/viperblock.log 2>/dev/null
|
|
fi
|
|
echo ""
|
|
echo "=== Hive Daemon Log ==="
|
|
if [ -f ~/hive/logs/hive.log ]; then
|
|
tail -200 ~/hive/logs/hive.log 2>/dev/null
|
|
fi
|
|
echo ""
|
|
echo "=== AWS Gateway Log ==="
|
|
if [ -f ~/hive/logs/awsgw.log ]; then
|
|
tail -200 ~/hive/logs/awsgw.log 2>/dev/null
|
|
fi
|
|
fi
|
|
./scripts/stop-dev.sh
|
|
}
|
|
trap cleanup EXIT
|
|
|
|
# Use Hive profile
|
|
export AWS_PROFILE=hive
|
|
|
|
# Ensure we are in the project root
|
|
cd "$(dirname "$0")/../.."
|
|
|
|
# Phase 1: Environment Setup
|
|
echo "Phase 1: Environment Setup"
|
|
|
|
# Check for KVM support inside the container
|
|
echo "Checking for KVM support..."
|
|
if [ -e /dev/kvm ]; then
|
|
echo "✅ /dev/kvm exists"
|
|
if [ -w /dev/kvm ]; then
|
|
echo "✅ /dev/kvm is writable"
|
|
else
|
|
echo "❌ /dev/kvm is NOT writable. QEMU will fail."
|
|
exit 1
|
|
fi
|
|
else
|
|
echo "❌ /dev/kvm does NOT exist. Ensure --privileged and -v /dev/kvm:/dev/kvm are used."
|
|
exit 1
|
|
fi
|
|
|
|
./bin/hive admin init --region ap-southeast-2 --az ap-southeast-2a --node node1 --nodes 1
|
|
|
|
# Trust the Hive CA certificate for AWS CLI SSL verification
|
|
echo "Adding Hive CA certificate to system trust store..."
|
|
sudo cp ~/hive/config/ca.pem /usr/local/share/ca-certificates/hive-ca.crt
|
|
sudo update-ca-certificates
|
|
|
|
# Start all services
|
|
# Ensure logs directory exists for start-dev.sh
|
|
mkdir -p ~/hive/logs
|
|
mkdir -p /mnt/ramdisk
|
|
HIVE_SKIP_BUILD=true ./scripts/start-dev.sh
|
|
|
|
# Wait for health checks on https://localhost:9999 (AWS Gateway)
|
|
echo "Waiting for AWS Gateway..."
|
|
MAX_RETRIES=30
|
|
COUNT=0
|
|
|
|
until curl -s https://localhost:9999 > /dev/null || [ $COUNT -eq $MAX_RETRIES ]; do
|
|
echo "Waiting for gateway... ($COUNT/$MAX_RETRIES)"
|
|
sleep 2
|
|
COUNT=$((COUNT + 1))
|
|
done
|
|
|
|
if [ $COUNT -eq $MAX_RETRIES ]; then
|
|
echo "Gateway failed to start"
|
|
exit 1
|
|
fi
|
|
|
|
# Define common AWS CLI args
|
|
AWS_EC2="aws --endpoint-url https://localhost:9999 ec2"
|
|
|
|
# Phase 2: Discovery & Metadata
|
|
echo "Phase 2: Discovery & Metadata"
|
|
# Verify describe-regions (just ensure it returns at least one region)
|
|
$AWS_EC2 describe-regions | jq -e '.Regions | length > 0'
|
|
|
|
# Discover available instance types from Hive
|
|
# Hive generates these based on the host CPU (e.g., m7i.micro, m8g.small, etc.)
|
|
echo "Discovering available instance types..."
|
|
AVAILABLE_TYPES=$($AWS_EC2 describe-instance-types --query 'InstanceTypes[*].InstanceType' --output text)
|
|
echo "Available instance types: $AVAILABLE_TYPES"
|
|
|
|
# Pick the nano instance type for minimal resource usage in tests
|
|
INSTANCE_TYPE=$(echo $AVAILABLE_TYPES | tr ' ' '\n' | grep -m1 'nano')
|
|
if [ -z "$INSTANCE_TYPE" ] || [ "$INSTANCE_TYPE" == "None" ]; then
|
|
echo "No instance types found!"
|
|
exit 1
|
|
fi
|
|
echo "Selected instance type for test: $INSTANCE_TYPE"
|
|
|
|
# Get architecture for the selected instance type
|
|
ARCH=$($AWS_EC2 describe-instance-types --instance-types "$INSTANCE_TYPE" --query 'InstanceTypes[0].ProcessorInfo.SupportedArchitectures[0]' --output text)
|
|
echo "Detected architecture for $INSTANCE_TYPE: $ARCH"
|
|
|
|
# Verify describe-instance-types (ensure the chosen type is available)
|
|
$AWS_EC2 describe-instance-types | jq -e ".InstanceTypes[] | select(.InstanceType==\"$INSTANCE_TYPE\")"
|
|
|
|
# Phase 3: SSH Key Management
|
|
echo "Phase 3: SSH Key Management"
|
|
# Create test-key-1 (create-key-pair) and verify private key material is returned
|
|
KEY_MATERIAL=$($AWS_EC2 create-key-pair --key-name test-key-1 --query 'KeyMaterial' --output text)
|
|
if [ -z "$KEY_MATERIAL" ] || [ "$KEY_MATERIAL" == "None" ]; then
|
|
echo "Failed to create key pair test-key-1"
|
|
exit 1
|
|
fi
|
|
echo "$KEY_MATERIAL" > test-key-1.pem
|
|
chmod 600 test-key-1.pem
|
|
|
|
# Generate a local RSA key and import it as test-key-2 (import-key-pair)
|
|
ssh-keygen -t rsa -b 2048 -f test-key-2-local -N ""
|
|
$AWS_EC2 import-key-pair --key-name test-key-2 --public-key-material "fileb://test-key-2-local.pub"
|
|
|
|
# Verify both keys are present (describe-key-pairs)
|
|
$AWS_EC2 describe-key-pairs --query 'KeyPairs[*].KeyName' --output text | grep test-key-1
|
|
$AWS_EC2 describe-key-pairs --query 'KeyPairs[*].KeyName' --output text | grep test-key-2
|
|
|
|
# Delete test-key-2 (delete-key-pair) and verify only one remains
|
|
$AWS_EC2 delete-key-pair --key-name test-key-2
|
|
REMAINING_KEYS=$($AWS_EC2 describe-key-pairs --query 'KeyPairs[*].KeyName' --output text)
|
|
echo "Remaining keys: $REMAINING_KEYS"
|
|
echo "$REMAINING_KEYS" | grep test-key-1
|
|
if echo "$REMAINING_KEYS" | grep -q test-key-2; then
|
|
echo "test-key-2 was not deleted"
|
|
exit 1
|
|
fi
|
|
|
|
# Phase 4: Image Management
|
|
echo "Phase 4: Image Management"
|
|
# Detect correct image name based on architecture
|
|
if [ "$ARCH" = "x86_64" ]; then
|
|
IMAGE_NAME="ubuntu-24.04-x86_64"
|
|
else
|
|
IMAGE_NAME="ubuntu-24.04-arm64"
|
|
fi
|
|
echo "Using image: $IMAGE_NAME"
|
|
|
|
# Import the pre-downloaded Ubuntu image using file-based import
|
|
echo "Importing pre-cached Ubuntu image..."
|
|
IMPORT_LOG=$(./bin/hive admin images import \
|
|
--file /root/images/ubuntu-24.04.img \
|
|
--arch "$ARCH" \
|
|
--distro ubuntu \
|
|
--version 24.04 \
|
|
--force 2>/dev/null)
|
|
AMI_ID=$(echo "$IMPORT_LOG" | grep -o 'ami-[a-z0-9]\+')
|
|
|
|
if [ -z "$AMI_ID" ]; then
|
|
echo "Failed to capture AMI ID from import command"
|
|
exit 1
|
|
fi
|
|
echo "Captured AMI ID: $AMI_ID"
|
|
|
|
# Verify the AMI exists using its ID (describe-images)
|
|
echo "Verifying AMI availability..."
|
|
$AWS_EC2 describe-images --image-ids "$AMI_ID" | jq -e ".Images[0] | select(.ImageId==\"$AMI_ID\")"
|
|
|
|
# Phase 5: Instance Lifecycle
|
|
echo "Phase 5: Instance Lifecycle"
|
|
# Launch a VM (run-instances)
|
|
echo "Running: aws ec2 run-instances --image-id $AMI_ID --instance-type $INSTANCE_TYPE --key-name test-key-1"
|
|
# Capture full output for debugging
|
|
set +e # Temporarily disable exit on error to capture output
|
|
RUN_OUTPUT=$($AWS_EC2 run-instances --image-id "$AMI_ID" --instance-type "$INSTANCE_TYPE" --key-name test-key-1 2>&1)
|
|
RUN_EXIT_CODE=$?
|
|
set -e # Re-enable exit on error
|
|
echo "Run instances exit code: $RUN_EXIT_CODE"
|
|
echo "Run instances output: $RUN_OUTPUT"
|
|
if [ $RUN_EXIT_CODE -ne 0 ]; then
|
|
echo "❌ Failed to launch instance - AWS CLI returned error"
|
|
exit 1
|
|
fi
|
|
INSTANCE_ID=$(echo "$RUN_OUTPUT" | jq -r '.Instances[0].InstanceId')
|
|
if [ -z "$INSTANCE_ID" ] || [ "$INSTANCE_ID" == "None" ] || [ "$INSTANCE_ID" == "null" ]; then
|
|
echo "Failed to launch instance - no InstanceId in response"
|
|
exit 1
|
|
fi
|
|
echo "Launched Instance ID: $INSTANCE_ID"
|
|
|
|
# Poll until state is running (describe-instances)
|
|
echo "Polling for instance running state..."
|
|
COUNT=0
|
|
STATE="unknown"
|
|
while [ $COUNT -lt 60 ]; do
|
|
# Capture full output to check if instance even exists in the response
|
|
DESCRIBE_OUTPUT=$($AWS_EC2 describe-instances --instance-ids "$INSTANCE_ID") || {
|
|
echo "⚠️ Gateway request failed, retrying... ($COUNT/60)"
|
|
sleep 5
|
|
COUNT=$((COUNT + 1))
|
|
continue
|
|
}
|
|
|
|
if [ -z "$DESCRIBE_OUTPUT" ]; then
|
|
echo "⚠️ Gateway returned empty response, retrying..."
|
|
sleep 5
|
|
COUNT=$((COUNT + 1))
|
|
continue
|
|
fi
|
|
|
|
# Extract state using jq
|
|
STATE=$(echo "$DESCRIBE_OUTPUT" | jq -r '.Reservations[0].Instances[0].State.Name // "not-found"')
|
|
|
|
echo "Instance state: $STATE"
|
|
if [ "$STATE" == "running" ]; then
|
|
break
|
|
fi
|
|
|
|
if [ "$STATE" == "terminated" ]; then
|
|
echo "❌ Instance terminated unexpectedly!"
|
|
exit 1
|
|
fi
|
|
|
|
sleep 5
|
|
COUNT=$((COUNT + 1))
|
|
done
|
|
|
|
if [ "$STATE" != "running" ]; then
|
|
echo "Instance failed to reach running state"
|
|
exit 1
|
|
fi
|
|
|
|
# Verify root volume attached to the instance (describe-volumes)
|
|
VOLUME_ID=$($AWS_EC2 describe-volumes --query 'Volumes[0].VolumeId' --output text)
|
|
if [ -z "$VOLUME_ID" ] || [ "$VOLUME_ID" == "None" ]; then
|
|
echo "Failed to find volume for instance $INSTANCE_ID"
|
|
exit 1
|
|
fi
|
|
echo "Volume ID: $VOLUME_ID"
|
|
|
|
# Phase 5b: Volume Lifecycle (Attach/Detach)
|
|
echo "Phase 5b: Volume Lifecycle (Attach/Detach)"
|
|
echo "Testing volume create -> resize -> attach -> detach -> delete..."
|
|
|
|
# Create a test volume
|
|
echo "Creating 10GB volume in ap-southeast-2a..."
|
|
CREATE_OUTPUT=$($AWS_EC2 create-volume --size 10 --availability-zone ap-southeast-2a)
|
|
TEST_VOLUME_ID=$(echo "$CREATE_OUTPUT" | jq -r '.VolumeId')
|
|
|
|
if [ -z "$TEST_VOLUME_ID" ] || [ "$TEST_VOLUME_ID" == "null" ]; then
|
|
echo "Failed to create test volume"
|
|
echo "Output: $CREATE_OUTPUT"
|
|
exit 1
|
|
fi
|
|
echo "Created volume: $TEST_VOLUME_ID"
|
|
|
|
# Resize to 20GB
|
|
NEW_SIZE=20
|
|
echo "Modifying volume to ${NEW_SIZE}GB..."
|
|
$AWS_EC2 modify-volume --volume-id "$TEST_VOLUME_ID" --size "$NEW_SIZE"
|
|
|
|
# Verify resize
|
|
echo "Verifying resize..."
|
|
COUNT=0
|
|
while [ $COUNT -lt 30 ]; do
|
|
VOLUME_SIZE=$($AWS_EC2 describe-volumes --volume-ids "$TEST_VOLUME_ID" \
|
|
--query 'Volumes[0].Size' --output text)
|
|
|
|
if [ "$VOLUME_SIZE" -eq "$NEW_SIZE" ]; then
|
|
echo "Volume resized successfully to ${NEW_SIZE}GB"
|
|
break
|
|
fi
|
|
|
|
sleep 2
|
|
COUNT=$((COUNT + 1))
|
|
done
|
|
|
|
if [ "$VOLUME_SIZE" -ne "$NEW_SIZE" ]; then
|
|
echo "Volume failed to resize to ${NEW_SIZE}GB (current: ${VOLUME_SIZE}GB)"
|
|
exit 1
|
|
fi
|
|
|
|
# Attach volume to the running instance
|
|
echo "Attaching volume $TEST_VOLUME_ID to instance $INSTANCE_ID..."
|
|
$AWS_EC2 attach-volume --volume-id "$TEST_VOLUME_ID" --instance-id "$INSTANCE_ID" --device /dev/sdf
|
|
|
|
# Verify attachment
|
|
echo "Verifying volume attachment..."
|
|
COUNT=0
|
|
while [ $COUNT -lt 30 ]; do
|
|
ATTACH_STATE=$($AWS_EC2 describe-volumes --volume-ids "$TEST_VOLUME_ID" \
|
|
--query 'Volumes[0].Attachments[0].State' --output text)
|
|
ATTACH_INSTANCE=$($AWS_EC2 describe-volumes --volume-ids "$TEST_VOLUME_ID" \
|
|
--query 'Volumes[0].Attachments[0].InstanceId' --output text)
|
|
VOL_STATE=$($AWS_EC2 describe-volumes --volume-ids "$TEST_VOLUME_ID" \
|
|
--query 'Volumes[0].State' --output text)
|
|
|
|
if [ "$VOL_STATE" == "in-use" ] && [ "$ATTACH_STATE" == "attached" ] && [ "$ATTACH_INSTANCE" == "$INSTANCE_ID" ]; then
|
|
echo "Volume attached successfully (State=$VOL_STATE, AttachState=$ATTACH_STATE, Instance=$ATTACH_INSTANCE)"
|
|
break
|
|
fi
|
|
|
|
sleep 2
|
|
COUNT=$((COUNT + 1))
|
|
done
|
|
|
|
if [ "$ATTACH_STATE" != "attached" ] || [ "$ATTACH_INSTANCE" != "$INSTANCE_ID" ]; then
|
|
echo "Volume attachment verification failed (AttachState=$ATTACH_STATE, Instance=$ATTACH_INSTANCE)"
|
|
exit 1
|
|
fi
|
|
|
|
# Detach volume (without --instance-id to test gateway resolution path)
|
|
echo "Detaching volume $TEST_VOLUME_ID..."
|
|
$AWS_EC2 detach-volume --volume-id "$TEST_VOLUME_ID"
|
|
|
|
# Verify detachment
|
|
echo "Verifying volume detachment..."
|
|
COUNT=0
|
|
while [ $COUNT -lt 30 ]; do
|
|
VOL_STATE=$($AWS_EC2 describe-volumes --volume-ids "$TEST_VOLUME_ID" \
|
|
--query 'Volumes[0].State' --output text)
|
|
|
|
if [ "$VOL_STATE" == "available" ]; then
|
|
echo "Volume detached successfully (State=$VOL_STATE)"
|
|
break
|
|
fi
|
|
|
|
sleep 2
|
|
COUNT=$((COUNT + 1))
|
|
done
|
|
|
|
if [ "$VOL_STATE" != "available" ]; then
|
|
echo "Volume detachment verification failed (State=$VOL_STATE)"
|
|
exit 1
|
|
fi
|
|
|
|
# Delete the test volume
|
|
echo "Deleting test volume $TEST_VOLUME_ID..."
|
|
$AWS_EC2 delete-volume --volume-id "$TEST_VOLUME_ID"
|
|
|
|
# Verify deletion
|
|
echo "Verifying volume deletion..."
|
|
COUNT=0
|
|
while [ $COUNT -lt 30 ]; do
|
|
set +e
|
|
VOLUME_CHECK=$($AWS_EC2 describe-volumes --volume-ids "$TEST_VOLUME_ID" \
|
|
--query 'Volumes[0].VolumeId' --output text 2>&1)
|
|
DESCRIBE_EXIT=$?
|
|
set -e
|
|
|
|
if [ $DESCRIBE_EXIT -ne 0 ] || [ "$VOLUME_CHECK" == "None" ] || [ -z "$VOLUME_CHECK" ]; then
|
|
echo "Volume deleted successfully"
|
|
break
|
|
fi
|
|
|
|
sleep 2
|
|
COUNT=$((COUNT + 1))
|
|
done
|
|
|
|
if [ $COUNT -ge 30 ]; then
|
|
echo "Volume deletion verification timed out"
|
|
exit 1
|
|
fi
|
|
|
|
echo "Volume lifecycle test passed (create -> resize -> attach -> detach -> delete)"
|
|
|
|
# Phase 5c: Snapshot Lifecycle
|
|
echo "Phase 5c: Snapshot Lifecycle"
|
|
echo "Testing snapshot create -> describe -> copy -> delete..."
|
|
|
|
# Use the root volume from Phase 5 — it's already attached and mounted in
|
|
# viperblockd, which is required for create-snapshot (the ebs.snapshot handler
|
|
# needs a live VB instance to flush).
|
|
echo "Using root volume $VOLUME_ID (already attached to $INSTANCE_ID)"
|
|
ROOT_VOL_SIZE=$($AWS_EC2 describe-volumes --volume-ids "$VOLUME_ID" \
|
|
--query 'Volumes[0].Size' --output text)
|
|
|
|
# Create a snapshot from the attached root volume
|
|
echo "Creating snapshot from volume $VOLUME_ID..."
|
|
SNAP_OUTPUT=$($AWS_EC2 create-snapshot --volume-id "$VOLUME_ID" --description "e2e-test-snapshot")
|
|
SNAPSHOT_ID=$(echo "$SNAP_OUTPUT" | jq -r '.SnapshotId')
|
|
|
|
if [ -z "$SNAPSHOT_ID" ] || [ "$SNAPSHOT_ID" == "null" ]; then
|
|
echo "Failed to create snapshot"
|
|
echo "Output: $SNAP_OUTPUT"
|
|
exit 1
|
|
fi
|
|
echo "Created snapshot: $SNAPSHOT_ID"
|
|
|
|
# Verify snapshot fields from create response
|
|
SNAP_STATE=$(echo "$SNAP_OUTPUT" | jq -r '.State')
|
|
SNAP_VOL_REF=$(echo "$SNAP_OUTPUT" | jq -r '.VolumeId')
|
|
SNAP_SIZE=$(echo "$SNAP_OUTPUT" | jq -r '.VolumeSize')
|
|
SNAP_PROGRESS=$(echo "$SNAP_OUTPUT" | jq -r '.Progress')
|
|
|
|
if [ "$SNAP_VOL_REF" != "$VOLUME_ID" ]; then
|
|
echo "Snapshot VolumeId mismatch: expected $VOLUME_ID, got $SNAP_VOL_REF"
|
|
exit 1
|
|
fi
|
|
if [ "$SNAP_SIZE" -ne "$ROOT_VOL_SIZE" ]; then
|
|
echo "Snapshot VolumeSize mismatch: expected $ROOT_VOL_SIZE, got $SNAP_SIZE"
|
|
exit 1
|
|
fi
|
|
echo "Snapshot create response verified (State=$SNAP_STATE, VolumeId=$SNAP_VOL_REF, Size=$SNAP_SIZE, Progress=$SNAP_PROGRESS)"
|
|
|
|
# Poll until snapshot is completed (should be immediate in v1, but poll for forward-compat)
|
|
echo "Waiting for snapshot to complete..."
|
|
COUNT=0
|
|
while [ $COUNT -lt 30 ]; do
|
|
SNAP_STATE=$($AWS_EC2 describe-snapshots --snapshot-ids "$SNAPSHOT_ID" \
|
|
--query 'Snapshots[0].State' --output text)
|
|
|
|
if [ "$SNAP_STATE" == "completed" ]; then
|
|
echo "Snapshot completed"
|
|
break
|
|
fi
|
|
|
|
sleep 2
|
|
COUNT=$((COUNT + 1))
|
|
done
|
|
|
|
if [ "$SNAP_STATE" != "completed" ]; then
|
|
echo "Snapshot failed to reach completed state (State=$SNAP_STATE)"
|
|
exit 1
|
|
fi
|
|
|
|
# Describe snapshot by ID and verify fields
|
|
echo "Verifying snapshot via describe-snapshots..."
|
|
DESCRIBE_SNAP=$($AWS_EC2 describe-snapshots --snapshot-ids "$SNAPSHOT_ID")
|
|
DESC_VOL_ID=$(echo "$DESCRIBE_SNAP" | jq -r '.Snapshots[0].VolumeId')
|
|
DESC_SIZE=$(echo "$DESCRIBE_SNAP" | jq -r '.Snapshots[0].VolumeSize')
|
|
DESC_DESC=$(echo "$DESCRIBE_SNAP" | jq -r '.Snapshots[0].Description')
|
|
|
|
if [ "$DESC_VOL_ID" != "$VOLUME_ID" ]; then
|
|
echo "Describe snapshot VolumeId mismatch: expected $VOLUME_ID, got $DESC_VOL_ID"
|
|
exit 1
|
|
fi
|
|
if [ "$DESC_SIZE" -ne "$ROOT_VOL_SIZE" ]; then
|
|
echo "Describe snapshot VolumeSize mismatch: expected $ROOT_VOL_SIZE, got $DESC_SIZE"
|
|
exit 1
|
|
fi
|
|
if [ "$DESC_DESC" != "e2e-test-snapshot" ]; then
|
|
echo "Describe snapshot Description mismatch: expected 'e2e-test-snapshot', got '$DESC_DESC'"
|
|
exit 1
|
|
fi
|
|
echo "Describe snapshot verified (VolumeId=$DESC_VOL_ID, Size=$DESC_SIZE, Description=$DESC_DESC)"
|
|
|
|
# Copy the snapshot
|
|
echo "Copying snapshot $SNAPSHOT_ID..."
|
|
COPY_OUTPUT=$($AWS_EC2 copy-snapshot --source-snapshot-id "$SNAPSHOT_ID" --source-region ap-southeast-2 --description "e2e-copy")
|
|
COPY_SNAPSHOT_ID=$(echo "$COPY_OUTPUT" | jq -r '.SnapshotId')
|
|
|
|
if [ -z "$COPY_SNAPSHOT_ID" ] || [ "$COPY_SNAPSHOT_ID" == "null" ]; then
|
|
echo "Failed to copy snapshot"
|
|
echo "Output: $COPY_OUTPUT"
|
|
exit 1
|
|
fi
|
|
echo "Copied snapshot: $COPY_SNAPSHOT_ID"
|
|
|
|
# Verify the copy is a distinct snapshot
|
|
if [ "$COPY_SNAPSHOT_ID" == "$SNAPSHOT_ID" ]; then
|
|
echo "Copy snapshot ID should differ from original"
|
|
exit 1
|
|
fi
|
|
|
|
# Describe all snapshots — should see both original and copy
|
|
TOTAL_SNAPS=$($AWS_EC2 describe-snapshots \
|
|
--snapshot-ids "$SNAPSHOT_ID" "$COPY_SNAPSHOT_ID" \
|
|
--query 'length(Snapshots)' --output text)
|
|
|
|
if [ "$TOTAL_SNAPS" -ne 2 ]; then
|
|
echo "Expected 2 snapshots, got $TOTAL_SNAPS"
|
|
exit 1
|
|
fi
|
|
echo "Both snapshots visible via describe-snapshots"
|
|
|
|
# Verify copy has correct description
|
|
COPY_DESC=$($AWS_EC2 describe-snapshots --snapshot-ids "$COPY_SNAPSHOT_ID" \
|
|
--query 'Snapshots[0].Description' --output text)
|
|
if [ "$COPY_DESC" != "e2e-copy" ]; then
|
|
echo "Copy description mismatch: expected 'e2e-copy', got '$COPY_DESC'"
|
|
exit 1
|
|
fi
|
|
|
|
# Delete the original snapshot
|
|
echo "Deleting original snapshot $SNAPSHOT_ID..."
|
|
$AWS_EC2 delete-snapshot --snapshot-id "$SNAPSHOT_ID"
|
|
|
|
# Verify original is gone, copy remains
|
|
echo "Verifying snapshot deletion..."
|
|
COUNT=0
|
|
while [ $COUNT -lt 30 ]; do
|
|
set +e
|
|
SNAP_CHECK=$($AWS_EC2 describe-snapshots --snapshot-ids "$SNAPSHOT_ID" \
|
|
--query 'Snapshots[0].SnapshotId' --output text 2>&1)
|
|
SNAP_EXIT=$?
|
|
set -e
|
|
|
|
if [ $SNAP_EXIT -ne 0 ] || [ "$SNAP_CHECK" == "None" ] || [ -z "$SNAP_CHECK" ]; then
|
|
echo "Original snapshot deleted successfully"
|
|
break
|
|
fi
|
|
|
|
sleep 2
|
|
COUNT=$((COUNT + 1))
|
|
done
|
|
|
|
if [ $COUNT -ge 30 ]; then
|
|
echo "Snapshot deletion verification timed out"
|
|
exit 1
|
|
fi
|
|
|
|
# Verify copy still exists
|
|
COPY_STATE=$($AWS_EC2 describe-snapshots --snapshot-ids "$COPY_SNAPSHOT_ID" \
|
|
--query 'Snapshots[0].State' --output text)
|
|
if [ "$COPY_STATE" != "completed" ]; then
|
|
echo "Copy snapshot should still exist (State=$COPY_STATE)"
|
|
exit 1
|
|
fi
|
|
echo "Copy snapshot still intact after original deletion"
|
|
|
|
# Delete the copy
|
|
echo "Deleting copy snapshot $COPY_SNAPSHOT_ID..."
|
|
$AWS_EC2 delete-snapshot --snapshot-id "$COPY_SNAPSHOT_ID"
|
|
|
|
echo "Snapshot lifecycle test passed (create -> describe -> copy -> delete)"
|
|
|
|
# Phase 5d: Verify Snapshot-Backed Instance Launch
|
|
echo "Phase 5d: Verify Snapshot-Backed Instance Launch"
|
|
echo "All run-instances calls go through cloneAMIToVolume() -> OpenFromSnapshot(),"
|
|
echo "so the Phase 5 instance is already snapshot-backed. Verify its volume config."
|
|
|
|
AWS_S3="aws --endpoint-url https://localhost:8443 s3"
|
|
|
|
# Verify the AMI snapshot exists in Predastore
|
|
echo "Checking AMI snapshot in Predastore..."
|
|
SNAP_PREFIX="snap-$AMI_ID"
|
|
SNAP_FILES=$($AWS_S3 ls "s3://predastore/$SNAP_PREFIX/" 2>&1 || echo "")
|
|
if echo "$SNAP_FILES" | grep -q "config.json"; then
|
|
echo "AMI snapshot config found at $SNAP_PREFIX/"
|
|
else
|
|
echo "AMI snapshot config not found at $SNAP_PREFIX/"
|
|
exit 1
|
|
fi
|
|
|
|
# Verify the Phase 5 instance's root volume has SnapshotID and SourceVolumeName
|
|
echo "Verifying root volume $VOLUME_ID is snapshot-backed via Predastore config..."
|
|
VOL_CONFIG=$($AWS_S3 cp "s3://predastore/$VOLUME_ID/config.json" - 2>/dev/null || echo "{}")
|
|
VOL_SNAPSHOT_ID=$(echo "$VOL_CONFIG" | jq -r '.SnapshotID // empty')
|
|
VOL_SOURCE_NAME=$(echo "$VOL_CONFIG" | jq -r '.SourceVolumeName // empty')
|
|
|
|
if [ -z "$VOL_SNAPSHOT_ID" ]; then
|
|
echo "Volume config missing SnapshotID — launch was NOT snapshot-backed"
|
|
exit 1
|
|
fi
|
|
if [ -z "$VOL_SOURCE_NAME" ]; then
|
|
echo "Volume config missing SourceVolumeName — launch was NOT snapshot-backed"
|
|
exit 1
|
|
fi
|
|
echo "Volume is snapshot-backed (SnapshotID=$VOL_SNAPSHOT_ID, SourceVolumeName=$VOL_SOURCE_NAME)"
|
|
|
|
echo "Snapshot-backed instance launch verified"
|
|
|
|
# Phase 6: Tag Management
|
|
echo "Phase 6: Tag Management"
|
|
|
|
# 6a: Create tags on the instance
|
|
echo "Creating tags on instance $INSTANCE_ID..."
|
|
$AWS_EC2 create-tags --resources "$INSTANCE_ID" --tags Key=Name,Value=e2e-test Key=Environment,Value=testing Key=DeleteMe,Value=please
|
|
|
|
# 6b: Verify tags with describe-tags (resource-id filter)
|
|
echo "Verifying tags on instance..."
|
|
TAG_COUNT=$($AWS_EC2 describe-tags --filters "Name=resource-id,Values=$INSTANCE_ID" \
|
|
--query 'length(Tags || `[]`)' --output text)
|
|
if [ "$TAG_COUNT" -ne 3 ]; then
|
|
echo "Expected 3 tags on instance, got $TAG_COUNT"
|
|
exit 1
|
|
fi
|
|
echo "Instance has $TAG_COUNT tags"
|
|
|
|
# 6c: Create tags on the root volume
|
|
echo "Creating tags on volume $VOLUME_ID..."
|
|
$AWS_EC2 create-tags --resources "$VOLUME_ID" --tags Key=Name,Value=e2e-root-vol Key=Environment,Value=testing
|
|
|
|
# 6d: Filter by key
|
|
echo "Testing key filter..."
|
|
ENV_TAGS=$($AWS_EC2 describe-tags --filters "Name=key,Values=Environment" \
|
|
--query 'length(Tags || `[]`)' --output text)
|
|
if [ "$ENV_TAGS" -ne 2 ]; then
|
|
echo "Expected 2 'Environment' tags across resources, got $ENV_TAGS"
|
|
exit 1
|
|
fi
|
|
echo "Key filter returned $ENV_TAGS tags"
|
|
|
|
# 6e: Filter by resource-type
|
|
echo "Testing resource-type filter..."
|
|
INSTANCE_TAGS=$($AWS_EC2 describe-tags --filters "Name=resource-type,Values=instance" \
|
|
--query 'length(Tags || `[]`)' --output text)
|
|
if [ "$INSTANCE_TAGS" -ne 3 ]; then
|
|
echo "Expected 3 instance tags, got $INSTANCE_TAGS"
|
|
exit 1
|
|
fi
|
|
echo "Resource-type filter returned $INSTANCE_TAGS instance tags"
|
|
|
|
# 6f: Overwrite a tag value
|
|
echo "Overwriting Name tag on instance..."
|
|
$AWS_EC2 create-tags --resources "$INSTANCE_ID" --tags Key=Name,Value=e2e-test-updated
|
|
UPDATED_NAME=$($AWS_EC2 describe-tags \
|
|
--filters "Name=resource-id,Values=$INSTANCE_ID" "Name=key,Values=Name" \
|
|
--query 'Tags[0].Value' --output text)
|
|
if [ "$UPDATED_NAME" != "e2e-test-updated" ]; then
|
|
echo "Tag overwrite failed: expected 'e2e-test-updated', got '$UPDATED_NAME'"
|
|
exit 1
|
|
fi
|
|
echo "Tag overwrite verified"
|
|
|
|
# 6g: Delete tag by key (unconditional)
|
|
echo "Deleting DeleteMe tag unconditionally..."
|
|
$AWS_EC2 delete-tags --resources "$INSTANCE_ID" --tags Key=DeleteMe
|
|
REMAINING=$($AWS_EC2 describe-tags --filters "Name=resource-id,Values=$INSTANCE_ID" \
|
|
--query 'length(Tags || `[]`)' --output text)
|
|
if [ "$REMAINING" -ne 2 ]; then
|
|
echo "Expected 2 tags after unconditional delete, got $REMAINING"
|
|
exit 1
|
|
fi
|
|
echo "Unconditional delete verified ($REMAINING tags remaining)"
|
|
|
|
# 6h: Delete tag with wrong value (should NOT delete)
|
|
echo "Attempting delete with wrong value (should be no-op)..."
|
|
$AWS_EC2 delete-tags --resources "$INSTANCE_ID" --tags Key=Environment,Value=production
|
|
ENV_STILL=$($AWS_EC2 describe-tags \
|
|
--filters "Name=resource-id,Values=$INSTANCE_ID" "Name=key,Values=Environment" \
|
|
--query 'length(Tags || `[]`)' --output text)
|
|
if [ "$ENV_STILL" -ne 1 ]; then
|
|
echo "Value-conditional delete incorrectly removed tag"
|
|
exit 1
|
|
fi
|
|
echo "Value-conditional mismatch preserved tag"
|
|
|
|
# 6i: Delete tag with correct value
|
|
echo "Deleting Environment tag with correct value..."
|
|
$AWS_EC2 delete-tags --resources "$INSTANCE_ID" --tags Key=Environment,Value=testing
|
|
ENV_GONE=$($AWS_EC2 describe-tags \
|
|
--filters "Name=resource-id,Values=$INSTANCE_ID" "Name=key,Values=Environment" \
|
|
--query 'length(Tags || `[]`)' --output text)
|
|
if [ "$ENV_GONE" -ne 0 ]; then
|
|
echo "Value-conditional delete failed to remove matching tag"
|
|
exit 1
|
|
fi
|
|
echo "Value-conditional match deleted tag"
|
|
|
|
# 6j: Verify only Name tag remains on instance
|
|
FINAL_COUNT=$($AWS_EC2 describe-tags --filters "Name=resource-id,Values=$INSTANCE_ID" \
|
|
--query 'length(Tags || `[]`)' --output text)
|
|
if [ "$FINAL_COUNT" -ne 1 ]; then
|
|
echo "Expected 1 tag remaining on instance, got $FINAL_COUNT"
|
|
exit 1
|
|
fi
|
|
echo "Tag management tests passed"
|
|
|
|
# Stop instance (stop-instances) and verify transition to stopped (describe-instances)
|
|
echo "Stopping instance..."
|
|
$AWS_EC2 stop-instances --instance-ids "$INSTANCE_ID"
|
|
COUNT=0
|
|
while [ $COUNT -lt 30 ]; do
|
|
STATE=$($AWS_EC2 describe-instances --instance-ids "$INSTANCE_ID" --query 'Reservations[0].Instances[0].State.Name' --output text)
|
|
echo "Instance state: $STATE"
|
|
if [ "$STATE" == "stopped" ]; then
|
|
break
|
|
fi
|
|
sleep 5
|
|
COUNT=$((COUNT + 1))
|
|
done
|
|
|
|
if [ "$STATE" != "stopped" ]; then
|
|
echo "Instance failed to reach stopped state"
|
|
exit 1
|
|
fi
|
|
|
|
# Start instance (start-instances) and verify transition back to running (describe-instances)
|
|
echo "Starting instance..."
|
|
$AWS_EC2 start-instances --instance-ids "$INSTANCE_ID"
|
|
COUNT=0
|
|
while [ $COUNT -lt 30 ]; do
|
|
STATE=$($AWS_EC2 describe-instances --instance-ids "$INSTANCE_ID" --query 'Reservations[0].Instances[0].State.Name' --output text)
|
|
echo "Instance state: $STATE"
|
|
if [ "$STATE" == "running" ]; then
|
|
break
|
|
fi
|
|
sleep 5
|
|
COUNT=$((COUNT + 1))
|
|
done
|
|
|
|
if [ "$STATE" != "running" ]; then
|
|
echo "Instance failed to reach running state after restart"
|
|
exit 1
|
|
fi
|
|
|
|
# Terminate instance (terminate-instances) and verify termination (describe-instances)
|
|
echo "Terminating instance..."
|
|
$AWS_EC2 terminate-instances --instance-ids "$INSTANCE_ID"
|
|
COUNT=0
|
|
while [ $COUNT -lt 30 ]; do
|
|
STATE=$($AWS_EC2 describe-instances --instance-ids "$INSTANCE_ID" --query 'Reservations[0].Instances[0].State.Name' --output text)
|
|
echo "Instance state: $STATE"
|
|
if [ "$STATE" == "terminated" ] || [ "$STATE" == "None" ]; then
|
|
break
|
|
fi
|
|
sleep 5
|
|
COUNT=$((COUNT + 1))
|
|
done
|
|
|
|
echo "E2E Test Completed Successfully"
|
|
exit 0
|