Skip to content
Merged
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
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased]
- Add unit testing support
- Add scope configuration
- Improve **k8s/backup** logging format with detailed error messages and fix suggestions
- Add unit tests for **k8s/backup** module (backup_templates and s3 operations)

## [1.10.0] - 2026-01-14
- Add support to configure the traffic manager nginx through a configmap.
Expand Down
13 changes: 10 additions & 3 deletions k8s/backup/backup_templates
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ BACKUP_ENABLED=$(echo "$MANIFEST_BACKUP" | jq -r .ENABLED)
TYPE=$(echo "$MANIFEST_BACKUP" | jq -r .TYPE)

if [[ "$BACKUP_ENABLED" == "false" || "$BACKUP_ENABLED" == "null" ]]; then
echo "No manifest backup enabled. Skipping manifest backup"
echo "📋 Manifest backup is disabled, skipping"
return
fi

Expand Down Expand Up @@ -40,7 +40,14 @@ case "$TYPE" in
source "$SERVICE_PATH/backup/s3" --action="$ACTION" --files "${FILES[@]}"
;;
*)
echo "Error: Unsupported manifest backup type type '$TYPE'"
echo "❌ Unsupported manifest backup type: '$TYPE'"
echo ""
echo "💡 Possible causes:"
echo " The MANIFEST_BACKUP.TYPE configuration is invalid"
echo ""
echo "🔧 How to fix:"
echo " • Set MANIFEST_BACKUP.TYPE to 's3' in values.yaml"
echo ""
exit 1
;;
esac
esac
55 changes: 43 additions & 12 deletions k8s/backup/s3
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,16 @@ done
BUCKET=$(echo "$MANIFEST_BACKUP" | jq -r .BUCKET)
PREFIX=$(echo "$MANIFEST_BACKUP" | jq -r .PREFIX)

echo "[INFO] Initializing S3 manifest backup operation - Action: $ACTION | Bucket: $BUCKET | Prefix: $PREFIX | Files: ${#FILES[@]}"
echo "📝 Starting S3 manifest backup..."
echo "📋 Action: $ACTION"
echo "📋 Bucket: $BUCKET"
echo "📋 Prefix: $PREFIX"
echo "📋 Files: ${#FILES[@]}"
echo ""

# Now you can iterate over the files
for file in "${FILES[@]}"; do
echo "[DEBUG] Processing manifest file: $file"
echo "📝 Processing: $(basename "$file")"

# Extract the path after 'output/' and remove the action folder (apply/delete)
# Example: /root/.np/services/k8s/output/1862688057-34121609/apply/secret-1862688057-34121609.yaml
Expand All @@ -54,34 +59,60 @@ for file in "${FILES[@]}"; do


if [[ "$ACTION" == "apply" ]]; then
echo "[INFO] Uploading manifest to S3: s3://$BUCKET/$s3_key"
echo " 📡 Uploading to s3://$BUCKET/$s3_key"

# Upload to S3
if aws s3 cp --region "$REGION" "$file" "s3://$BUCKET/$s3_key"; then
echo "[SUCCESS] Manifest upload completed successfully: $file"
if aws s3 cp --region "$REGION" "$file" "s3://$BUCKET/$s3_key" >/dev/null; then
echo " ✅ Upload successful"
else
echo "[ERROR] Manifest upload failed: $file" >&2
echo " ❌ Upload failed"
echo ""
echo "💡 Possible causes:"
echo " • S3 bucket does not exist or is not accessible"
echo " • IAM permissions are missing for s3:PutObject"
echo ""
echo "🔧 How to fix:"
echo " • Verify bucket '$BUCKET' exists and is accessible"
echo " • Check IAM permissions for the agent"
echo ""
exit 1
fi

elif [[ "$ACTION" == "delete" ]]; then
echo "[INFO] Removing manifest from S3: s3://$BUCKET/$s3_key"
echo " 📡 Deleting s3://$BUCKET/$s3_key"

# Delete from S3 with error handling
aws_output=$(aws s3 rm --region "$REGION" "s3://$BUCKET/$s3_key" 2>&1)
aws_exit_code=$?

if [[ $aws_exit_code -eq 0 ]]; then
echo "[SUCCESS] Manifest deletion completed successfully: s3://$BUCKET/$s3_key"
echo " ✅ Deletion successful"
elif [[ "$aws_output" == *"NoSuchKey"* ]] || [[ "$aws_output" == *"Not Found"* ]]; then
echo "[WARN] Manifest not found in S3, skipping deletion: s3://$BUCKET/$s3_key"
echo " 📋 File not found in S3, skipping"
else
echo "[ERROR] Manifest deletion failed: s3://$BUCKET/$s3_key - $aws_output" >&2
echo " ❌ Deletion failed"
echo "📋 AWS Error: $aws_output"
echo ""
echo "💡 Possible causes:"
echo " • S3 bucket does not exist or is not accessible"
echo " • IAM permissions are missing for s3:DeleteObject"
echo ""
echo "🔧 How to fix:"
echo " • Verify bucket '$BUCKET' exists and is accessible"
echo " • Check IAM permissions for the agent"
echo ""
exit 1
fi

else
echo "[ERROR] Invalid action specified: $ACTION" >&2
echo "❌ Invalid action: '$ACTION'"
echo ""
echo "💡 Possible causes:"
echo " The action parameter must be 'apply' or 'delete'"
echo ""
exit 1
fi
done
done

echo ""
echo "✨ S3 backup operation completed successfully"
174 changes: 174 additions & 0 deletions k8s/backup/tests/backup_templates.bats
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
#!/usr/bin/env bats
# =============================================================================
# Unit tests for backup/backup_templates - manifest backup orchestration
# =============================================================================

setup() {
# Get project root directory
export PROJECT_ROOT="$(cd "$BATS_TEST_DIRNAME/../../.." && pwd)"

# Source assertions
source "$PROJECT_ROOT/testing/assertions.sh"

# Set required environment variables
export SERVICE_PATH="$PROJECT_ROOT/k8s"
}

teardown() {
unset MANIFEST_BACKUP
unset SERVICE_PATH
}

# =============================================================================
# Test: Skips when backup is disabled (false)
# =============================================================================
@test "backup_templates: skips when BACKUP_ENABLED is false" {
export MANIFEST_BACKUP='{"ENABLED":"false","TYPE":"s3"}'

# Use a subshell to capture the return statement behavior
run bash -c '
source "$SERVICE_PATH/backup/backup_templates" --action=apply --files /tmp/test.yaml
'

assert_equal "$status" "0"
assert_equal "$output" "📋 Manifest backup is disabled, skipping"
}

# =============================================================================
# Test: Skips when backup is disabled (null)
# =============================================================================
@test "backup_templates: skips when BACKUP_ENABLED is null" {
export MANIFEST_BACKUP='{"TYPE":"s3"}'

run bash -c '
source "$SERVICE_PATH/backup/backup_templates" --action=apply --files /tmp/test.yaml
'

assert_equal "$status" "0"
assert_equal "$output" "📋 Manifest backup is disabled, skipping"
}

# =============================================================================
# Test: Skips when MANIFEST_BACKUP is empty
# =============================================================================
@test "backup_templates: skips when MANIFEST_BACKUP is empty" {
export MANIFEST_BACKUP='{}'

run bash -c '
source "$SERVICE_PATH/backup/backup_templates" --action=apply --files /tmp/test.yaml
'

assert_equal "$status" "0"
assert_equal "$output" "📋 Manifest backup is disabled, skipping"
}

# =============================================================================
# Test: Fails with unsupported backup type - Error message
# =============================================================================
@test "backup_templates: fails with unsupported backup type error" {
export MANIFEST_BACKUP='{"ENABLED":"true","TYPE":"gcs"}'

run bash "$SERVICE_PATH/backup/backup_templates" --action=apply --files /tmp/test.yaml

assert_equal "$status" "1"
assert_contains "$output" "❌ Unsupported manifest backup type: 'gcs'"
assert_contains "$output" "💡 Possible causes:"
assert_contains "$output" "MANIFEST_BACKUP.TYPE configuration is invalid"
assert_contains "$output" "🔧 How to fix:"
assert_contains "$output" "• Set MANIFEST_BACKUP.TYPE to 's3' in values.yaml"
}

# =============================================================================
# Test: Parses action argument correctly
# =============================================================================
@test "backup_templates: parses action argument" {
export MANIFEST_BACKUP='{"ENABLED":"true","TYPE":"s3","BUCKET":"test","PREFIX":"manifests"}'

# Mock aws to avoid actual calls
aws() {
return 0
}
export -f aws
export REGION="us-east-1"

run bash -c '
source "$SERVICE_PATH/backup/backup_templates" --action=apply --files /tmp/output/123/apply/test.yaml
'

assert_contains "$output" "📋 Action: apply"
}

# =============================================================================
# Test: Parses files argument correctly
# =============================================================================
@test "backup_templates: parses files argument" {
export MANIFEST_BACKUP='{"ENABLED":"true","TYPE":"s3","BUCKET":"test","PREFIX":"manifests"}'

# Mock aws to avoid actual calls
aws() {
return 0
}
export -f aws
export REGION="us-east-1"

run bash -c '
source "$SERVICE_PATH/backup/backup_templates" --action=apply --files /tmp/output/123/apply/file1.yaml /tmp/output/123/apply/file2.yaml
'

assert_contains "$output" "📋 Files: 2"
}

# =============================================================================
# Test: Calls s3 backup for s3 type
# =============================================================================
@test "backup_templates: calls s3 backup for s3 type" {
export MANIFEST_BACKUP='{"ENABLED":"true","TYPE":"s3","BUCKET":"my-bucket","PREFIX":"backups"}'

# Mock aws to avoid actual calls
aws() {
return 0
}
export -f aws
export REGION="us-east-1"

run bash -c '
source "$SERVICE_PATH/backup/backup_templates" --action=apply --files /tmp/output/123/apply/test.yaml
'

assert_equal "$status" "0"
assert_contains "$output" "📝 Starting S3 manifest backup..."
}

@test "backup_templates: shows bucket name when calling s3" {
export MANIFEST_BACKUP='{"ENABLED":"true","TYPE":"s3","BUCKET":"my-bucket","PREFIX":"backups"}'

aws() {
return 0
}
export -f aws
export REGION="us-east-1"

run bash -c '
source "$SERVICE_PATH/backup/backup_templates" --action=apply --files /tmp/output/123/apply/test.yaml
'

assert_equal "$status" "0"
assert_contains "$output" "📋 Bucket: my-bucket"
}

@test "backup_templates: shows prefix when calling s3" {
export MANIFEST_BACKUP='{"ENABLED":"true","TYPE":"s3","BUCKET":"my-bucket","PREFIX":"backups"}'

aws() {
return 0
}
export -f aws
export REGION="us-east-1"

run bash -c '
source "$SERVICE_PATH/backup/backup_templates" --action=apply --files /tmp/output/123/apply/test.yaml
'

assert_equal "$status" "0"
assert_contains "$output" "📋 Prefix: backups"
}
Loading