Some checks failed
Rust CI / Security Audit (push) Has been cancelled
Rust CI / Check + Test + Lint (nightly) (push) Has been cancelled
Rust CI / Check + Test + Lint (stable) (push) Has been cancelled
mdBook Build & Deploy / Build mdBook (push) Has been cancelled
Nickel Type Check / Nickel Type Checking (push) Has been cancelled
mdBook Build & Deploy / Documentation Quality Check (push) Has been cancelled
mdBook Build & Deploy / Deploy to GitHub Pages (push) Has been cancelled
mdBook Build & Deploy / Notification (push) Has been cancelled
336 lines
8.5 KiB
Plaintext
336 lines
8.5 KiB
Plaintext
#!/usr/bin/env nu
|
|
|
|
# VAPORA Configuration Backup Script
|
|
# Backs up Kubernetes ConfigMaps, Secrets, and deployment configs
|
|
# Follows NUSHELL_GUIDELINES.md - 17 rules
|
|
|
|
# Get current timestamp
|
|
def get-timestamp []: string {
|
|
date now | format date "%Y%m%d-%H%M%S"
|
|
}
|
|
|
|
# Get Kubernetes namespace from environment or use default
|
|
def get-namespace []: string {
|
|
if ("VAPORA_NAMESPACE" in $env) {
|
|
$env.VAPORA_NAMESPACE
|
|
} else {
|
|
"vapora"
|
|
}
|
|
}
|
|
|
|
# Backup ConfigMaps
|
|
def backup-configmaps [
|
|
output_dir: string
|
|
namespace: string
|
|
]: record {
|
|
print $"Backing up ConfigMaps from namespace [$namespace]..."
|
|
|
|
let output_file = $"($output_dir)/configmaps-$(get-timestamp).yaml"
|
|
let result = do {
|
|
^kubectl get configmaps \
|
|
-n $namespace \
|
|
-o yaml \
|
|
> $output_file \
|
|
2>&1
|
|
} | complete
|
|
|
|
if ($result.exit_code == 0) {
|
|
{
|
|
success: true,
|
|
file: $output_file,
|
|
count: (
|
|
do {
|
|
^kubectl get configmaps -n $namespace --no-headers 2>/dev/null
|
|
} | complete | if ($in.exit_code == 0) {
|
|
($in.stdout | lines | length)
|
|
} else {
|
|
0
|
|
}
|
|
),
|
|
error: null
|
|
}
|
|
} else {
|
|
{
|
|
success: false,
|
|
file: $output_file,
|
|
count: 0,
|
|
error: ($result.stderr | str trim)
|
|
}
|
|
}
|
|
}
|
|
|
|
# Backup Secrets
|
|
def backup-secrets [
|
|
output_dir: string
|
|
namespace: string
|
|
]: record {
|
|
print $"Backing up Secrets from namespace [$namespace]..."
|
|
|
|
let output_file = $"($output_dir)/secrets-$(get-timestamp).yaml"
|
|
let result = do {
|
|
^kubectl get secrets \
|
|
-n $namespace \
|
|
-o yaml \
|
|
> $output_file \
|
|
2>&1
|
|
} | complete
|
|
|
|
if ($result.exit_code == 0) {
|
|
{
|
|
success: true,
|
|
file: $output_file,
|
|
count: (
|
|
do {
|
|
^kubectl get secrets -n $namespace --no-headers 2>/dev/null
|
|
} | complete | if ($in.exit_code == 0) {
|
|
($in.stdout | lines | length)
|
|
} else {
|
|
0
|
|
}
|
|
),
|
|
error: null
|
|
}
|
|
} else {
|
|
{
|
|
success: false,
|
|
file: $output_file,
|
|
count: 0,
|
|
error: ($result.stderr | str trim)
|
|
}
|
|
}
|
|
}
|
|
|
|
# Backup Deployment manifests
|
|
def backup-deployments [
|
|
output_dir: string
|
|
namespace: string
|
|
]: record {
|
|
print $"Backing up Deployments from namespace [$namespace]..."
|
|
|
|
let output_file = $"($output_dir)/deployments-$(get-timestamp).yaml"
|
|
let result = do {
|
|
^kubectl get deployments,statefulsets,daemonsets \
|
|
-n $namespace \
|
|
-o yaml \
|
|
> $output_file \
|
|
2>&1
|
|
} | complete
|
|
|
|
if ($result.exit_code == 0) {
|
|
{
|
|
success: true,
|
|
file: $output_file,
|
|
resource_types: ["deployments", "statefulsets", "daemonsets"],
|
|
error: null
|
|
}
|
|
} else {
|
|
{
|
|
success: false,
|
|
file: $output_file,
|
|
resource_types: [],
|
|
error: ($result.stderr | str trim)
|
|
}
|
|
}
|
|
}
|
|
|
|
# Backup Services and Ingress
|
|
def backup-networking [
|
|
output_dir: string
|
|
namespace: string
|
|
]: record {
|
|
print $"Backing up Services and Ingress from namespace [$namespace]..."
|
|
|
|
let output_file = $"($output_dir)/networking-$(get-timestamp).yaml"
|
|
let result = do {
|
|
^kubectl get services,ingresses \
|
|
-n $namespace \
|
|
-o yaml \
|
|
> $output_file \
|
|
2>&1
|
|
} | complete
|
|
|
|
if ($result.exit_code == 0) {
|
|
{
|
|
success: true,
|
|
file: $output_file,
|
|
resource_types: ["services", "ingresses"],
|
|
error: null
|
|
}
|
|
} else {
|
|
{
|
|
success: false,
|
|
file: $output_file,
|
|
resource_types: [],
|
|
error: ($result.stderr | str trim)
|
|
}
|
|
}
|
|
}
|
|
|
|
# Compress all backup files
|
|
def compress-backups [output_dir: string]: record {
|
|
print $"Compressing backup files..."
|
|
|
|
let archive_name = $"configs-$(get-timestamp).tar.gz"
|
|
let result = do {
|
|
^tar -czf $archive_name -C $output_dir . 2>&1
|
|
} | complete
|
|
|
|
if ($result.exit_code == 0) {
|
|
{
|
|
success: true,
|
|
archive: $archive_name,
|
|
size: (
|
|
do {
|
|
^ls -lh $archive_name 2>/dev/null
|
|
} | complete | if ($in.exit_code == 0) {
|
|
($in.stdout | str trim)
|
|
} else {
|
|
"unknown"
|
|
}
|
|
),
|
|
error: null
|
|
}
|
|
} else {
|
|
{
|
|
success: false,
|
|
archive: $archive_name,
|
|
size: null,
|
|
error: ($result.stderr | str trim)
|
|
}
|
|
}
|
|
}
|
|
|
|
# Upload to S3
|
|
def upload-to-s3 [
|
|
file_path: string
|
|
s3_bucket: string
|
|
s3_prefix: string
|
|
]: record {
|
|
print $"Uploading to S3 [$s3_bucket]..."
|
|
|
|
let s3_key = $"($s3_prefix)/configs-$(get-timestamp).tar.gz"
|
|
let result = do {
|
|
^aws s3 cp $file_path \
|
|
$"s3://($s3_bucket)/($s3_key)" \
|
|
--sse AES256 \
|
|
--metadata "backup-type=config,timestamp=$(get-timestamp)"
|
|
} | complete
|
|
|
|
if ($result.exit_code == 0) {
|
|
{
|
|
success: true,
|
|
s3_location: $"s3://($s3_bucket)/($s3_key)",
|
|
error: null
|
|
}
|
|
} else {
|
|
{
|
|
success: false,
|
|
s3_location: $"s3://($s3_bucket)/($s3_key)",
|
|
error: ($result.stderr | str trim)
|
|
}
|
|
}
|
|
}
|
|
|
|
# Main backup function
|
|
def main [
|
|
--namespace: string = ""
|
|
--s3-bucket: string = ""
|
|
--s3-prefix: string = "backups/config"
|
|
--work-dir: string = "/tmp/vapora-config-backups"
|
|
--keep-local: bool = false
|
|
]: void {
|
|
print "=== VAPORA Configuration Backup ==="
|
|
print ""
|
|
|
|
# Get namespace
|
|
let ns = if ($namespace == "") {
|
|
get-namespace
|
|
} else {
|
|
$namespace
|
|
}
|
|
|
|
# Validate environment
|
|
if ($s3_bucket == "") {
|
|
print "ERROR: --s3-bucket is required"
|
|
exit 1
|
|
}
|
|
|
|
# Create working directory
|
|
let work_path = $"($work_dir)/$(get-timestamp)"
|
|
let result_create = do {
|
|
^mkdir -p $work_path 2>&1
|
|
} | complete
|
|
|
|
if ($result_create.exit_code != 0) {
|
|
print "ERROR: Failed to create working directory"
|
|
exit 1
|
|
}
|
|
|
|
# Backup all configuration types
|
|
let configmaps_result = (backup-configmaps $work_path $ns)
|
|
if (not $configmaps_result.success) {
|
|
print $"WARNING: ConfigMap backup failed: ($configmaps_result.error)"
|
|
} else {
|
|
print $"✓ Backed up ($configmaps_result.count) ConfigMaps"
|
|
}
|
|
|
|
let secrets_result = (backup-secrets $work_path $ns)
|
|
if (not $secrets_result.success) {
|
|
print $"WARNING: Secret backup failed: ($secrets_result.error)"
|
|
} else {
|
|
print $"✓ Backed up ($secrets_result.count) Secrets"
|
|
}
|
|
|
|
let deployments_result = (backup-deployments $work_path $ns)
|
|
if (not $deployments_result.success) {
|
|
print $"WARNING: Deployment backup failed: ($deployments_result.error)"
|
|
} else {
|
|
print $"✓ Backed up deployments"
|
|
}
|
|
|
|
let networking_result = (backup-networking $work_path $ns)
|
|
if (not $networking_result.success) {
|
|
print $"WARNING: Networking backup failed: ($networking_result.error)"
|
|
} else {
|
|
print $"✓ Backed up networking resources"
|
|
}
|
|
|
|
# Compress backups
|
|
let compress_result = (compress-backups $work_path)
|
|
if (not $compress_result.success) {
|
|
print $"ERROR: Compression failed: ($compress_result.error)"
|
|
exit 1
|
|
}
|
|
|
|
print "✓ Backups compressed successfully"
|
|
|
|
# Upload to S3
|
|
let upload_result = (upload-to-s3 $compress_result.archive $s3_bucket $s3_prefix)
|
|
if (not $upload_result.success) {
|
|
print $"ERROR: S3 upload failed: ($upload_result.error)"
|
|
exit 1
|
|
}
|
|
|
|
print "✓ Configuration backup uploaded to S3"
|
|
|
|
# Cleanup unless requested to keep
|
|
if (not $keep_local) {
|
|
let cleanup = do {
|
|
^rm -rf $work_dir 2>&1
|
|
} | complete
|
|
|
|
if ($cleanup.exit_code == 0) {
|
|
print "✓ Temporary files cleaned up"
|
|
}
|
|
} else {
|
|
print $"Local backup kept at: ($work_dir)"
|
|
}
|
|
|
|
# Summary
|
|
print ""
|
|
print "=== Backup Complete ==="
|
|
print $"Location: ($upload_result.s3_location)"
|
|
print $"Namespace: ($ns)"
|
|
print $"Timestamp: $(get-timestamp)"
|
|
}
|