feat: hypervisor_backup_config role and playbook
This commit is contained in:
51
roles/hypervisor_backup_config/defaults/main.yml
Normal file
51
roles/hypervisor_backup_config/defaults/main.yml
Normal file
@@ -0,0 +1,51 @@
|
||||
---
|
||||
# =============================================================================
|
||||
# hypervisor_backup_config — defaults
|
||||
# =============================================================================
|
||||
|
||||
# Backup destinations — list, supports git | local | sftp
|
||||
# All configured destinations are used in sequence
|
||||
pve_config_backup_destinations:
|
||||
- type: git
|
||||
|
||||
# Number of backups to retain for local and sftp destinations
|
||||
# git retention is managed by git history
|
||||
pve_config_backup_keep: 10
|
||||
|
||||
# Date string used in filenames
|
||||
pve_config_backup_date: "{{ ansible_date_time.date }}"
|
||||
|
||||
# Filename template (no extension — .tar.gz added for local/sftp)
|
||||
# e.g. proxmox_client_local_eng_pm-node-01_config_2026-03-13
|
||||
pve_config_backup_filename: "{{ hypervisor_type }}_{{ client_id | lower | replace('-','_') | replace(' ','_') }}_{{ inventory_hostname }}_config_{{ pve_config_backup_date }}"
|
||||
|
||||
# Files/dirs to back up per hypervisor type
|
||||
pve_config_backup_paths_proxmox:
|
||||
- /etc/pve
|
||||
- /etc/network/interfaces
|
||||
- /etc/hosts
|
||||
- /etc/hostname
|
||||
- /etc/apt/sources.list
|
||||
- /etc/apt/sources.list.d
|
||||
|
||||
pve_config_backup_paths_xcpng:
|
||||
- /etc/xensource
|
||||
- /etc/network/interfaces
|
||||
- /etc/hosts
|
||||
- /etc/hostname
|
||||
|
||||
# Git settings
|
||||
pve_config_git_repo_dir: /opt/ansible-msp-automations
|
||||
pve_config_git_branch: main
|
||||
pve_config_git_base_path: "hypervisor_configs/{{ client_id | lower | replace(' ','_') }}/{{ hypervisor_type }}/{{ inventory_hostname }}"
|
||||
pve_config_git_commit_message: "[{{ client_id }}] {{ inventory_hostname }} pre-upgrade config backup {{ pve_config_backup_date }}"
|
||||
|
||||
# Local settings
|
||||
pve_config_local_backup_dir: /var/backups
|
||||
|
||||
# SFTP settings
|
||||
pve_config_sftp_host: ""
|
||||
pve_config_sftp_user: ""
|
||||
pve_config_sftp_key: ""
|
||||
pve_config_sftp_remote_dir: "."
|
||||
|
||||
151
roles/hypervisor_backup_config/tasks/main.yml
Normal file
151
roles/hypervisor_backup_config/tasks/main.yml
Normal file
@@ -0,0 +1,151 @@
|
||||
---
|
||||
# =============================================================================
|
||||
# hypervisor_backup_config — main tasks
|
||||
# =============================================================================
|
||||
|
||||
- name: Gather date/time facts
|
||||
ansible.builtin.setup:
|
||||
gather_subset:
|
||||
- date_time
|
||||
when: ansible_date_time is not defined
|
||||
|
||||
# ── Set backup paths based on hypervisor type ─────────────────────────────────
|
||||
- name: Set backup paths for proxmox
|
||||
ansible.builtin.set_fact:
|
||||
pve_config_backup_paths: "{{ pve_config_backup_paths_proxmox }}"
|
||||
when: hypervisor_type == 'proxmox'
|
||||
|
||||
- name: Set backup paths for xcpng
|
||||
ansible.builtin.set_fact:
|
||||
pve_config_backup_paths: "{{ pve_config_backup_paths_xcpng }}"
|
||||
when: hypervisor_type == 'xcpng'
|
||||
|
||||
- name: Fail if hypervisor_type not supported
|
||||
ansible.builtin.fail:
|
||||
msg: "hypervisor_type '{{ hypervisor_type }}' is not supported. Use proxmox or xcpng."
|
||||
when: hypervisor_type not in ['proxmox', 'xcpng']
|
||||
|
||||
# ── Git backup ────────────────────────────────────────────────────────────────
|
||||
- name: Git backup
|
||||
when: "'git' in (pve_config_backup_destinations | map(attribute='type') | list)"
|
||||
block:
|
||||
- name: Git | Ensure git base path exists on Semaphore host
|
||||
ansible.builtin.file:
|
||||
path: "{{ pve_config_git_repo_dir }}/{{ pve_config_git_base_path }}"
|
||||
state: directory
|
||||
mode: '0755'
|
||||
delegate_to: localhost
|
||||
|
||||
- name: Git | Copy config files from node to repo
|
||||
ansible.builtin.fetch:
|
||||
src: "{{ item }}"
|
||||
dest: "{{ pve_config_git_repo_dir }}/{{ pve_config_git_base_path }}/"
|
||||
flat: false
|
||||
fail_on_missing: false
|
||||
loop: "{{ pve_config_backup_paths }}"
|
||||
ignore_errors: true
|
||||
|
||||
- name: Git | Check if there are changes to commit
|
||||
ansible.builtin.shell: |
|
||||
cd {{ pve_config_git_repo_dir }}
|
||||
git status --porcelain {{ pve_config_git_base_path }}/
|
||||
register: git_status
|
||||
delegate_to: localhost
|
||||
changed_when: false
|
||||
|
||||
- name: Git | Stage backup files
|
||||
ansible.builtin.shell: |
|
||||
cd {{ pve_config_git_repo_dir }}
|
||||
git add {{ pve_config_git_base_path }}/
|
||||
delegate_to: localhost
|
||||
when: git_status.stdout != ""
|
||||
|
||||
- name: Git | Commit backup
|
||||
ansible.builtin.shell: |
|
||||
cd {{ pve_config_git_repo_dir }}
|
||||
git -c user.name="ansible-msp" -c user.email="ansible@msp.local" \
|
||||
commit -m "{{ pve_config_git_commit_message }}"
|
||||
delegate_to: localhost
|
||||
when: git_status.stdout != ""
|
||||
register: git_commit
|
||||
|
||||
- name: Git | Push to remote
|
||||
ansible.builtin.shell: |
|
||||
cd {{ pve_config_git_repo_dir }}
|
||||
git push origin {{ pve_config_git_branch }}
|
||||
delegate_to: localhost
|
||||
when: git_status.stdout != ""
|
||||
|
||||
- name: Git | Log result
|
||||
ansible.builtin.debug:
|
||||
msg: "{{ 'Config backed up to git: ' + pve_config_git_base_path if git_status.stdout != '' else 'No config changes since last backup — git commit skipped' }}"
|
||||
|
||||
# ── Local backup ──────────────────────────────────────────────────────────────
|
||||
- name: Local backup
|
||||
when: "'local' in (pve_config_backup_destinations | map(attribute='type') | list)"
|
||||
block:
|
||||
- name: Local | Ensure backup dir exists
|
||||
ansible.builtin.file:
|
||||
path: "{{ pve_config_local_backup_dir }}"
|
||||
state: directory
|
||||
mode: '0700'
|
||||
|
||||
- name: Local | Create gzipped tarball of config paths
|
||||
ansible.builtin.shell: |
|
||||
tar czf {{ pve_config_local_backup_dir }}/{{ pve_config_backup_filename }}.tar.gz \
|
||||
--ignore-failed-read \
|
||||
{% for path in pve_config_backup_paths %}{{ path }} {% endfor %}
|
||||
|
||||
echo "Created: {{ pve_config_backup_filename }}.tar.gz"
|
||||
register: local_backup_result
|
||||
changed_when: true
|
||||
|
||||
- name: Local | Remove old backups beyond keep limit
|
||||
ansible.builtin.shell: |
|
||||
ls -1t {{ pve_config_local_backup_dir }}/{{ hypervisor_type }}_{{ client_id | lower | replace('-','_') | replace(' ','_') }}_{{ inventory_hostname }}_config_*.tar.gz 2>/dev/null \
|
||||
| tail -n +{{ (pve_config_backup_keep | int) + 1 }} \
|
||||
| xargs -r rm -f
|
||||
echo "Rotation complete"
|
||||
changed_when: false
|
||||
|
||||
- name: Local | Log result
|
||||
ansible.builtin.debug:
|
||||
msg: "Config backed up locally: {{ pve_config_local_backup_dir }}/{{ pve_config_backup_filename }}.tar.gz"
|
||||
|
||||
# ── SFTP backup ───────────────────────────────────────────────────────────────
|
||||
- name: SFTP backup
|
||||
when: "'sftp' in (pve_config_backup_destinations | map(attribute='type') | list)"
|
||||
block:
|
||||
- name: SFTP | Validate required vars are set
|
||||
ansible.builtin.fail:
|
||||
msg: "sftp destination requires pve_config_sftp_host, pve_config_sftp_user to be set"
|
||||
when: pve_config_sftp_host == "" or pve_config_sftp_user == ""
|
||||
|
||||
- name: SFTP | Create local temp tarball first
|
||||
ansible.builtin.shell: |
|
||||
tar czf /tmp/{{ pve_config_backup_filename }}.tar.gz \
|
||||
--ignore-failed-read \
|
||||
{% for path in pve_config_backup_paths %}{{ path }} {% endfor %}
|
||||
changed_when: true
|
||||
|
||||
- name: SFTP | Transfer tarball to remote host
|
||||
ansible.builtin.shell: |
|
||||
sftp_opts="-o StrictHostKeyChecking=no -o BatchMode=yes"
|
||||
{% if pve_config_sftp_key != "" %}
|
||||
sftp_opts="$sftp_opts -i {{ pve_config_sftp_key }}"
|
||||
{% endif %}
|
||||
sftp $sftp_opts {{ pve_config_sftp_user }}@{{ pve_config_sftp_host }} << EOF
|
||||
cd {{ pve_config_sftp_remote_dir }}
|
||||
put /tmp/{{ pve_config_backup_filename }}.tar.gz
|
||||
EOF
|
||||
changed_when: true
|
||||
|
||||
- name: SFTP | Remove temp tarball
|
||||
ansible.builtin.file:
|
||||
path: "/tmp/{{ pve_config_backup_filename }}.tar.gz"
|
||||
state: absent
|
||||
|
||||
- name: SFTP | Log result
|
||||
ansible.builtin.debug:
|
||||
msg: "Config backed up via sftp: {{ pve_config_sftp_host }}:{{ pve_config_sftp_remote_dir }}/{{ pve_config_backup_filename }}.tar.gz"
|
||||
|
||||
Reference in New Issue
Block a user