288 lines
8.1 KiB
Bash
Executable File
288 lines
8.1 KiB
Bash
Executable File
#!/bin/bash
|
|
#
|
|
# Business Central Backup Configuration Tester
|
|
# Validates setup and connectivity before running actual backups
|
|
#
|
|
|
|
set -euo pipefail
|
|
|
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
|
CONFIG_FILE="${SCRIPT_DIR}/bc-backup.conf"
|
|
|
|
# Colors
|
|
GREEN='\033[0;32m'
|
|
YELLOW='\033[1;33m'
|
|
RED='\033[0;31m'
|
|
BLUE='\033[0;34m'
|
|
NC='\033[0m'
|
|
|
|
pass_count=0
|
|
warn_count=0
|
|
fail_count=0
|
|
|
|
echo_info() {
|
|
echo -e "${BLUE}[INFO]${NC} $*"
|
|
}
|
|
|
|
echo_pass() {
|
|
echo -e "${GREEN}[PASS]${NC} $*"
|
|
((pass_count++))
|
|
}
|
|
|
|
echo_warn() {
|
|
echo -e "${YELLOW}[WARN]${NC} $*"
|
|
((warn_count++))
|
|
}
|
|
|
|
echo_fail() {
|
|
echo -e "${RED}[FAIL]${NC} $*"
|
|
((fail_count++))
|
|
}
|
|
|
|
check_command() {
|
|
if command -v "$1" &> /dev/null; then
|
|
echo_pass "$1 is installed ($(command -v "$1"))"
|
|
return 0
|
|
else
|
|
echo_fail "$1 is NOT installed"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
check_config_var() {
|
|
local var_name="$1"
|
|
local var_value="${!var_name:-}"
|
|
|
|
if [[ -z "$var_value" ]]; then
|
|
echo_fail "$var_name is not set"
|
|
return 1
|
|
elif [[ "$var_value" == *"your-"* ]] || [[ "$var_value" == *"example"* ]]; then
|
|
echo_warn "$var_name looks like a placeholder value"
|
|
return 1
|
|
else
|
|
echo_pass "$var_name is set"
|
|
return 0
|
|
fi
|
|
}
|
|
|
|
echo_info "=========================================="
|
|
echo_info "BC Backup Configuration Tester"
|
|
echo_info "=========================================="
|
|
echo ""
|
|
|
|
# Test 1: Configuration file exists
|
|
echo_info "=== Test 1: Configuration File ==="
|
|
if [[ -f "$CONFIG_FILE" ]]; then
|
|
echo_pass "Configuration file exists: $CONFIG_FILE"
|
|
|
|
# Check permissions
|
|
perms=$(stat -c "%a" "$CONFIG_FILE" 2>/dev/null || stat -f "%A" "$CONFIG_FILE" 2>/dev/null)
|
|
if [[ "$perms" == "600" ]] || [[ "$perms" == "400" ]]; then
|
|
echo_pass "Configuration file has secure permissions ($perms)"
|
|
else
|
|
echo_warn "Configuration file permissions are $perms (recommend 600)"
|
|
fi
|
|
|
|
# Load configuration
|
|
source "$CONFIG_FILE"
|
|
else
|
|
echo_fail "Configuration file not found: $CONFIG_FILE"
|
|
echo_info "Run: cp bc-backup.conf.template bc-backup.conf"
|
|
exit 1
|
|
fi
|
|
echo ""
|
|
|
|
# Test 2: Required commands
|
|
echo_info "=== Test 2: Required Commands ==="
|
|
check_command pwsh
|
|
check_command gpg
|
|
check_command aws || check_command s3cmd
|
|
check_command curl
|
|
echo ""
|
|
|
|
# Test 3: Configuration variables
|
|
echo_info "=== Test 3: Configuration Variables ==="
|
|
check_config_var "AZURE_TENANT_ID"
|
|
check_config_var "AZURE_CLIENT_ID"
|
|
check_config_var "AZURE_CLIENT_SECRET"
|
|
check_config_var "BC_ENVIRONMENT_NAME"
|
|
check_config_var "ENCRYPTION_PASSPHRASE"
|
|
check_config_var "S3_BUCKET"
|
|
check_config_var "S3_ENDPOINT"
|
|
check_config_var "AWS_ACCESS_KEY_ID"
|
|
check_config_var "AWS_SECRET_ACCESS_KEY"
|
|
echo ""
|
|
|
|
# Test 4: Azure AD Authentication
|
|
echo_info "=== Test 4: Azure AD Authentication ==="
|
|
if command -v pwsh &> /dev/null; then
|
|
echo_info "Testing Azure AD authentication..."
|
|
|
|
auth_test=$(pwsh -Command "
|
|
\$tokenUrl = 'https://login.microsoftonline.com/$AZURE_TENANT_ID/oauth2/v2.0/token'
|
|
\$body = @{
|
|
client_id = '$AZURE_CLIENT_ID'
|
|
client_secret = '$AZURE_CLIENT_SECRET'
|
|
scope = 'https://api.businesscentral.dynamics.com/.default'
|
|
grant_type = 'client_credentials'
|
|
}
|
|
try {
|
|
\$response = Invoke-RestMethod -Uri \$tokenUrl -Method Post -Body \$body -ContentType 'application/x-www-form-urlencoded' -ErrorAction Stop
|
|
Write-Output 'SUCCESS'
|
|
} catch {
|
|
Write-Output \"FAILED: \$_\"
|
|
}
|
|
" 2>&1)
|
|
|
|
if [[ "$auth_test" == "SUCCESS" ]]; then
|
|
echo_pass "Azure AD authentication successful"
|
|
else
|
|
echo_fail "Azure AD authentication failed"
|
|
echo " Error: $auth_test"
|
|
fi
|
|
else
|
|
echo_warn "Skipping Azure AD test (pwsh not installed)"
|
|
fi
|
|
echo ""
|
|
|
|
# Test 5: S3 Connectivity
|
|
echo_info "=== Test 5: S3 Connectivity ==="
|
|
|
|
export AWS_ACCESS_KEY_ID
|
|
export AWS_SECRET_ACCESS_KEY
|
|
export AWS_DEFAULT_REGION
|
|
|
|
if [[ "${S3_TOOL:-awscli}" == "awscli" ]] && command -v aws &> /dev/null; then
|
|
echo_info "Testing S3 connectivity with AWS CLI..."
|
|
|
|
if aws s3 ls "s3://${S3_BUCKET}/" --endpoint-url "${S3_ENDPOINT}" > /dev/null 2>&1; then
|
|
echo_pass "S3 bucket is accessible: ${S3_BUCKET}"
|
|
|
|
# Check Object Lock status
|
|
echo_info "Checking Object Lock configuration..."
|
|
lock_config=$(aws s3api get-object-lock-configuration \
|
|
--bucket "${S3_BUCKET}" \
|
|
--endpoint-url "${S3_ENDPOINT}" 2>&1 || echo "NOT_CONFIGURED")
|
|
|
|
if [[ "$lock_config" != "NOT_CONFIGURED" ]] && [[ "$lock_config" != *"ObjectLockConfigurationNotFoundError"* ]]; then
|
|
echo_pass "Object Lock is enabled on bucket"
|
|
else
|
|
echo_fail "Object Lock is NOT enabled on bucket"
|
|
echo " Object Lock must be enabled at bucket creation"
|
|
echo " See README.md for setup instructions"
|
|
fi
|
|
else
|
|
echo_fail "Cannot access S3 bucket: ${S3_BUCKET}"
|
|
echo " Check: S3_BUCKET, S3_ENDPOINT, AWS credentials"
|
|
fi
|
|
elif [[ "${S3_TOOL}" == "s3cmd" ]] && command -v s3cmd &> /dev/null; then
|
|
echo_info "Testing S3 connectivity with s3cmd..."
|
|
|
|
if s3cmd ls "s3://${S3_BUCKET}/" --host="${S3_ENDPOINT#*://}" > /dev/null 2>&1; then
|
|
echo_pass "S3 bucket is accessible: ${S3_BUCKET}"
|
|
echo_warn "s3cmd doesn't support Object Lock verification"
|
|
echo " Install aws-cli for full Object Lock support"
|
|
else
|
|
echo_fail "Cannot access S3 bucket: ${S3_BUCKET}"
|
|
fi
|
|
else
|
|
echo_warn "Skipping S3 test (no S3 tool available)"
|
|
fi
|
|
echo ""
|
|
|
|
# Test 6: Directory permissions
|
|
echo_info "=== Test 6: Directory Permissions ==="
|
|
|
|
for dir in "logs" "temp"; do
|
|
dir_path="${SCRIPT_DIR}/${dir}"
|
|
if [[ -d "$dir_path" ]] && [[ -w "$dir_path" ]]; then
|
|
echo_pass "Directory is writable: $dir"
|
|
else
|
|
echo_fail "Directory is not writable: $dir"
|
|
echo " Run: mkdir -p $dir_path && chmod 755 $dir_path"
|
|
fi
|
|
done
|
|
echo ""
|
|
|
|
# Test 7: Script permissions
|
|
echo_info "=== Test 7: Script Permissions ==="
|
|
|
|
for script in "bc-backup.sh" "bc-export.ps1"; do
|
|
script_path="${SCRIPT_DIR}/${script}"
|
|
if [[ -f "$script_path" ]] && [[ -x "$script_path" ]]; then
|
|
echo_pass "Script is executable: $script"
|
|
else
|
|
echo_warn "Script is not executable: $script"
|
|
echo " Run: chmod +x $script_path"
|
|
fi
|
|
done
|
|
echo ""
|
|
|
|
# Test 8: GPG encryption test
|
|
echo_info "=== Test 8: GPG Encryption Test ==="
|
|
|
|
test_file=$(mktemp)
|
|
test_encrypted=$(mktemp)
|
|
test_decrypted=$(mktemp)
|
|
|
|
echo "test data" > "$test_file"
|
|
|
|
if echo "$ENCRYPTION_PASSPHRASE" | gpg \
|
|
--batch \
|
|
--yes \
|
|
--passphrase-fd 0 \
|
|
--symmetric \
|
|
--cipher-algo AES256 \
|
|
--output "$test_encrypted" \
|
|
"$test_file" 2>/dev/null; then
|
|
|
|
echo_pass "GPG encryption successful"
|
|
|
|
# Test decryption
|
|
if echo "$ENCRYPTION_PASSPHRASE" | gpg \
|
|
--batch \
|
|
--yes \
|
|
--passphrase-fd 0 \
|
|
--decrypt \
|
|
--output "$test_decrypted" \
|
|
"$test_encrypted" 2>/dev/null; then
|
|
|
|
if diff -q "$test_file" "$test_decrypted" &>/dev/null; then
|
|
echo_pass "GPG decryption successful"
|
|
else
|
|
echo_fail "GPG decryption produced different output"
|
|
fi
|
|
else
|
|
echo_fail "GPG decryption failed"
|
|
fi
|
|
else
|
|
echo_fail "GPG encryption failed"
|
|
fi
|
|
|
|
rm -f "$test_file" "$test_encrypted" "$test_decrypted"
|
|
echo ""
|
|
|
|
# Summary
|
|
echo_info "=========================================="
|
|
echo_info "Test Summary"
|
|
echo_info "=========================================="
|
|
echo_pass "Passed: $pass_count"
|
|
echo_warn "Warnings: $warn_count"
|
|
echo_fail "Failed: $fail_count"
|
|
echo ""
|
|
|
|
if [[ $fail_count -eq 0 ]]; then
|
|
echo_info "Configuration looks good!"
|
|
echo_info "You can now run a test backup:"
|
|
echo " ${SCRIPT_DIR}/bc-backup.sh"
|
|
exit 0
|
|
elif [[ $fail_count -le 2 ]] && [[ $pass_count -ge 10 ]]; then
|
|
echo_warn "Configuration has minor issues but may work"
|
|
echo_warn "Review failed tests above"
|
|
exit 0
|
|
else
|
|
echo_fail "Configuration has significant issues"
|
|
echo_fail "Please fix the failed tests before running backups"
|
|
exit 1
|
|
fi
|