backup-automation/kestra/workflows/backup-provision.yaml

204 lines
6.2 KiB
YAML

id: backup-provision
namespace: automation
description: "Netbox → Ansible → Borg Backup Provisioning"
version: 1
triggers:
- id: daily-backup-sync
type: schedule
cron: "0 2 * * *" # Täglich 02:00 Uhr
timezone: "Europe/Berlin"
variables:
netbox_url: "https://netbox.mbo-tech-it.de"
netbox_api_token: "{{ secret('NETBOX_TOKEN') }}"
# Basis-TAG für automatische Backups (erforderlich)
backup_tag_base: "auto-backup"
# Optional: Weitere TAGs können hinzugefügt werden
# z.B. env:prod, tenant:kunde1, backup-server:primary
ansible_inventory_file: "/tmp/netbox_inventory.ini"
git_repo: "https://gitea.mbo-tech-it.de/claude/backup-automation.git"
tasks:
# Task 1: Netbox Abfrage - Alle Systems mit "auto-backup" TAG
- id: fetch-backup-systems
type: io.kestra.plugin.core.http.Request
uri: "{{ vars.netbox_url }}/api/dcim/devices/?tag={{ vars.backup_tag_base }}&limit=500"
headers:
Authorization: "Token {{ vars.netbox_api_token }}"
method: GET
# Task 2: Verarbeite Netbox Response
- id: parse-devices
type: io.kestra.plugin.core.script.Groovy
script: |
def response = json(tasks.fetchBackupSystems.body)
def devices = []
response.results.each { device ->
devices.add([
name: device.name,
ip: device.primary_ip4?.address?.split('/')[0] ?: null,
os: device.device_type?.manufacturer?.name ?: "unknown",
status: device.status?.value
])
}
// Filtern: nur active und mit IP
def activeDevices = devices.findAll { it.ip && it.status == 'active' }
kestra.logger.info("Found ${activeDevices.size()} devices for backup")
return activeDevices
# Task 3: Git-Repo pullen
- id: pull-backup-scripts
type: io.kestra.plugin.core.tasks.bash.BashScript
script: |
#!/bin/bash
set -e
REPO_DIR="/tmp/backup-automation"
if [ -d "$REPO_DIR" ]; then
cd "$REPO_DIR"
git pull origin main
else
git clone {{ vars.git_repo }} "$REPO_DIR"
cd "$REPO_DIR"
fi
echo "Repo synced successfully"
exit 0
# Task 4: Generiere Ansible Inventory aus Netbox-Daten
- id: generate-ansible-inventory
type: io.kestra.plugin.core.script.Groovy
script: |
def devices = tasks.parseDevices.output
def inventory = """[all]
[backup_clients]
"""
devices.each { device ->
inventory += """${device.name} ansible_host=${device.ip} ansible_user=root
"""
}
inventory += """
[backup_clients:vars]
ansible_python_interpreter=/usr/bin/python3
backup_repo_server=backup01.mbotechit.de
backup_repo_base=/backup/repos
"""
// Schreibe zu Datei
new File('/tmp/netbox_inventory.ini').text = inventory
kestra.logger.info("Ansible inventory generated")
return true
# Task 5: Führe Ansible Playbook aus (parallel pro Host)
- id: run-ansible-playbook
type: io.kestra.plugin.core.tasks.bash.BashScript
script: |
#!/bin/bash
set -e
cd /tmp/backup-automation
# Installiere Ansible + Netbox Module falls nötig
pip install -q ansible netaddr jinja2 &>/dev/null || true
# Führe Playbook aus
ansible-playbook \
-i {{ vars.ansible_inventory_file }} \
ansible/playbooks/install-borg-client.yaml \
-e "backup_repo_server=backup01.mbotechit.de" \
-e "backup_repo_base=/backup/repos" \
--diff
echo "Ansible playbook completed"
exit 0
# Task 6: Trigger Backup-Server Borg Repo Init (falls neu)
- id: initialize-backup-repos
type: io.kestra.plugin.core.tasks.bash.BashScript
script: |
#!/bin/bash
cd /tmp/backup-automation
# SSH zum Backup-Server
ssh -i ~/.ssh/id_ed25519 backup@backup01.mbotechit.de << 'EOF'
source /home/backup/.bashrc
# Hole Device-Liste aus Netbox (nur Systems mit auto-backup TAG)
DEVICES=$(curl -s -H "Authorization: Token {{ vars.netbox_api_token }}" \
"{{ vars.netbox_url }}/api/dcim/devices/?tag={{ vars.backup_tag_base }}&limit=500" \
| jq -r '.results[].name')
for device in $DEVICES; do
REPO_PATH="/backup/repos/$device"
if [ ! -d "$REPO_PATH" ]; then
mkdir -p "$REPO_PATH"
borg init --encryption=repokey "$REPO_PATH"
echo "Initialized $REPO_PATH"
fi
done
EOF
exit 0
# Task 7: Trigger Backups auf allen Hosts
- id: trigger-backups
type: io.kestra.plugin.core.tasks.bash.BashScript
script: |
#!/bin/bash
DEVICES="{{ tasks.parseDevices.output | json }}"
echo "$DEVICES" | jq -r '.[] | .name' | while read device; do
kestra.logger.info "Triggering backup for $device..."
# SSH zum Host und starte systemd service
ssh -i ~/.ssh/id_ed25519 root@$device \
"systemctl start mbo-backup.service" 2>/dev/null || true
done
echo "Backup triggers sent"
exit 0
# Task 8: Status Reporting
- id: backup-status-report
type: io.kestra.plugin.core.script.Groovy
script: |
def devices = tasks.parseDevices.output
def report = """
╔══════════════════════════════════════════════════╗
║ BACKUP PROVISION REPORT ║
╠══════════════════════════════════════════════════╣
"""
report += "║ Total Devices Found: ${devices.size()}\n"
report += "║ Timestamp: ${new Date()}\n"
report += "║ Status: PROVISIONING INITIATED\n"
report += "╚══════════════════════════════════════════════════╝\n\n"
devices.each { device ->
report += "✓ ${device.name} (${device.ip})\n"
}
kestra.logger.info(report)
return report
outputs:
- id: device_count
type: STRING
value: "{{ tasks.parseDevices.output.size() }}"
- id: backup_report
type: STRING
value: "{{ tasks.backupStatusReport.output }}"