New backup role

There is a new backup role in the roles folder:

    roles/ipabackup

This role allows to backup an IPA server, to copy a backup from the
server to the controller, to copy all backups from the server to the
controller, to remove a backup from the server, to remove all backups
from the server, to restore an IPA server locally and from the controller
and also to copy a backup from the controller to the server.

Here is the documentation for the role:

    roles/ipabackup/README.md

New example playbooks have been added:

    playbooks/backup-server.yml
    playbooks/backup-server-to-controller.yml
    playbooks/copy-backup-from-server.yml
    playbooks/copy-all-backups-from-server.yml
    playbooks/remove-backup-from-server.yml
    playbooks/remove-all-backups-from-server.yml
    playbooks/copy-backup-to-server.yml
    playbooks/restore-server-from-controller.yml
    playbooks/restore-server.yml
This commit is contained in:
Thomas Woerner
2020-10-22 13:02:21 +02:00
parent 698bd81475
commit 59afa28260
29 changed files with 947 additions and 0 deletions

View File

@@ -0,0 +1,39 @@
---
# tasks file for ipabackup
- name: Create backup
shell: >
ipa-backup
{{ "--gpg" if ipabackup_gpg | bool }}
{{ "--gpg-keyring="+ipabackup_gpg_keyring if ipabackup_gpg_keyring is defined }}
{{ "--data" if ipabackup_data | bool }}
{{ "--logs" if ipabackup_logs | bool }}
{{ "--online" if ipabackup_online | bool }}
{{ "--disable-role-check" if ipabackup_disable_role_check | bool }}
{{ "--log-file="+ipabackup_log_file if ipabackup_log_file is defined }}
register: result_ipabackup
- block:
- name: Get ipabackup_item from stderr or stdout output
set_fact:
ipabackup_item: "{{ item | regex_search('\n.*/([^\n]+)','\\1') | first }}"
when: item.find("Backed up to "+ipabackup_dir+"/") > 0
with_items:
- "{{ result_ipabackup.stderr }}"
- "{{ result_ipabackup.stdout }}"
loop_control:
label: ""
- name: Fail on missing ipabackup_item
fail: msg="Failed to get ipabackup_item"
when: ipabackup_item is not defined
- name: Copy backup to controller
include_tasks: "{{ role_path }}/tasks/copy_backup_from_server.yml"
when: state|default("present") == "present"
- name: Remove backup on server
include_tasks: "{{ role_path }}/tasks/remove_backup_from_server.yml"
when: not ipabackup_keep_on_server
when: ipabackup_to_controller

View File

@@ -0,0 +1,46 @@
---
- name: Fail on invalid ipabackup_item
fail: msg="ipabackup_item {{ ipabackup_item }} is not valid"
when: ipabackup_item is not defined or
ipabackup_item | length < 1 or
(ipabackup_item.find("ipa-full-") == -1 and
ipabackup_item.find("ipa-data-") == -1)
- name: Set controller destination directory
set_fact:
ipabackup_controller_dir:
"{{ ipabackup_controller_path | default(lookup('env','PWD')) }}/{{
ipabackup_name_prefix | default(ansible_fqdn) }}_{{
ipabackup_item }}/"
- name: Stat backup on server
stat:
path: "{{ ipabackup_dir }}/{{ ipabackup_item }}"
register: result_backup_stat
- name: Fail on missing backup directory
fail: msg="Unable to find backup {{ ipabackup_item }}"
when: result_backup_stat.stat.isdir is not defined
- name: Get backup files to copy for "{{ ipabackup_item }}"
shell:
find . -type f | cut -d"/" -f 2
args:
chdir: "{{ ipabackup_dir }}/{{ ipabackup_item }}"
register: result_find_backup_files
- name: Copy server backup files to controller
fetch:
flat: yes
src: "{{ ipabackup_dir }}/{{ ipabackup_item }}/{{ item }}"
dest: "{{ ipabackup_controller_dir }}"
with_items:
- "{{ result_find_backup_files.stdout_lines }}"
- name: Fix file modes for backup on controller
file:
dest: "{{ ipabackup_controller_dir }}"
mode: u=rwX,go=
recurse: yes
delegate_to: localhost
become: no

View File

@@ -0,0 +1,43 @@
---
- name: Fail on invalid ipabackup_name
fail: msg="ipabackup_name {{ ipabackup_name }} is not valid"
when: ipabackup_name is not defined or
ipabackup_name | length < 1 or
(ipabackup_name.find("ipa-full-") == -1 and
ipabackup_name.find("ipa-data-") == -1)
- name: Set controller source directory
set_fact:
ipabackup_controller_dir:
"{{ ipabackup_controller_path | default(lookup('env','PWD')) }}"
- name: Set ipabackup_item
set_fact:
ipabackup_item:
"{{ ipabackup_name | regex_search('.*_(ipa-.+)','\\1') | first }}"
when: "'_ipa-' in ipabackup_name"
- name: Set ipabackup_item
set_fact:
ipabackup_item: "{{ ipabackup_name }}"
when: "'_ipa-' not in ipabackup_name"
- name: Stat backup to copy
stat:
path: "{{ ipabackup_controller_dir }}/{{ ipabackup_name }}"
register: result_backup_stat
delegate_to: localhost
become: no
- name: Fail on missing backup to copy
fail: msg="Unable to find backup {{ ipabackup_name }}"
when: result_backup_stat.stat.isdir is not defined
- name: Copy backup files to server for "{{ ipabackup_item }}"
copy:
src: "{{ ipabackup_controller_dir }}/{{ ipabackup_name }}/"
dest: "{{ ipabackup_dir }}/{{ ipabackup_item }}"
owner: root
group: root
mode: u=rw,go=r
directory_mode: u=rwx,go=

View File

@@ -0,0 +1,12 @@
---
- name: Get IPA_BACKUP_DIR dir from ipaplatform
command: "{{ ansible_playbook_python }}"
args:
stdin: |
from ipaplatform.paths import paths
print(paths.IPA_BACKUP_DIR)
register: result_ipaplatform_backup_dir
- name: Set IPA backup dir
set_fact:
ipabackup_dir: "{{ result_ipaplatform_backup_dir.stdout_lines | first }}"

View File

@@ -0,0 +1,138 @@
---
# tasks file for ipabackup
- name: Check for empty vars
fail: msg="Variable {{ item }} is empty"
when: "item in vars and not vars[item]"
with_items: "{{ ipabackup_empty_var_checks }}"
vars:
ipabackup_empty_var_checks:
- ipabackup_backend
- ipabackup_gpg_keyring
- ipabackup_instance
- ipabackup_log_file
- ipabackup_password
- ipabackup_name
- ipabackup_controller_path
- ipabackup_name_prefix
- ipabackup_firewalld_zone
- name: Set ipabackup_data if ipabackup_data is not set but ipabackup_online is
set_fact:
ipabackup_data: yes
when: ipabackup_online | bool and not ipabackup_data | bool
- name: Fail if ipabackup_from_controller and ipabackup_to_controller are set
fail: msg="ipabackup_from_controller and ipabackup_to_controller are set"
when: ipabackup_from_controller | bool and ipabackup_to_controller | bool
- name: Get ipabackup_dir from IPA installation
include_tasks: "{{ role_path }}/tasks/get_ipabackup_dir.yml"
- name: Backup IPA server
include_tasks: "{{ role_path }}/tasks/backup.yml"
when: state|default("present") == "present"
- name: Fail for given ipabackup_name if state is not copied, restored or absent
fail: msg="ipabackup_name is given and state is not copied, restored or absent"
when: state is not defined or
(state != "copied" and state != "restored" and state != "absent") and
ipabackup_name is defined
- name: Fail on missing ipabackup_name
fail: msg="ipabackup_name is not set"
when: (ipabackup_name is not defined or not ipabackup_name) and
state is defined and
(state == "copied" or state == "restored" or state == "absent")
- block:
- name: Get list of all backups on IPA server
shell:
find . -name "ipa-full-*" -o -name "ipa-data-*" | cut -d"/" -f 2
args:
chdir: "{{ ipabackup_dir }}/"
register: result_backup_find_backup_files
- name: Set ipabackup_names using backup list
set_fact:
ipabackup_names: "{{ result_backup_find_backup_files.stdout_lines }}"
when: state is defined and
((state == "copied" and ipabackup_to_controller) or
state == "absent") and
ipabackup_name is defined and ipabackup_name == "all"
- block:
- name: Fail on ipabackup_name all
fail: msg="ipabackup_name can not be all in this case"
when: ipabackup_name is defined and ipabackup_name == "all"
- name: Set ipabackup_names from ipabackup_name string
set_fact:
ipabackup_names: ["{{ ipabackup_name }}"]
when: ipabackup_name | type_debug != "list"
- name: Set ipabackup_names from ipabackup_name list
set_fact:
ipabackup_names: "{{ ipabackup_name }}"
when: ipabackup_name | type_debug == "list"
when: ipabackup_names is not defined and ipabackup_name is defined
- name: Set empty ipabackup_names if ipabackup_name is not defined
set_fact:
ipabackup_names: []
when: ipabackup_names is not defined and ipabackup_name is not defined
- block:
- name: Copy backup from IPA server
include_tasks: "{{ role_path }}/tasks/copy_backup_from_server.yml"
vars:
ipabackup_item: "{{ main_item | basename }}"
with_items:
- "{{ ipabackup_names }}"
loop_control:
loop_var: main_item
when: state is defined and state == "copied"
- name: Remove backup from IPA server
include_tasks: "{{ role_path }}/tasks/remove_backup_from_server.yml"
vars:
ipabackup_item: "{{ main_item | basename }}"
with_items:
- "{{ ipabackup_names }}"
loop_control:
loop_var: main_item
when: state is defined and state == "absent"
when: state is defined and
((state == "copied" and ipabackup_to_controller) or state == "absent")
# Fail with more than one entry in ipabackup_names for copy to sever and
# restore.
- name: Fail to copy or restore more than one backup on the server
fail: msg="Only one backup can be copied to the server or restored"
when: state is defined and (state == "copied" or state == "restored") and
ipabackup_from_controller | bool and ipabackup_names | length != 1
# Use only first item in ipabackup_names for copy to server and for restore.
- block:
- name: Copy backup to server
include_tasks: "{{ role_path }}/tasks/copy_backup_to_server.yml"
- name: Restore IPA server after copy
include_tasks: "{{ role_path }}/tasks/restore.yml"
when: state|default("present") == "restored"
vars:
ipabackup_name: "{{ ipabackup_names[0] }}"
when: ipabackup_from_controller or
(state|default("present") == "copied" and not ipabackup_to_controller)
- name: Restore IPA server
include_tasks: "{{ role_path }}/tasks/restore.yml"
vars:
ipabackup_item: "{{ ipabackup_names[0] | basename }}"
when: not ipabackup_from_controller and
state|default("present") == "restored"

View File

@@ -0,0 +1,5 @@
---
- name: Remove backup "{{ ipabackup_item }}"
file:
path: "{{ ipabackup_dir }}/{{ ipabackup_item }}"
state: absent

View File

@@ -0,0 +1,147 @@
---
# tasks file for ipabackup
### VARIABLES
- name: Import variables specific to distribution
include_vars: "{{ item }}"
with_first_found:
- "{{ role_path }}/vars/{{ ansible_distribution }}-{{ ansible_distribution_version }}.yml"
- "{{ role_path }}/vars/{{ ansible_distribution }}-{{ ansible_distribution_major_version }}.yml"
- "{{ role_path }}/vars/{{ ansible_distribution }}.yml"
- "{{ role_path }}/vars/default.yml"
### GET SERVICES FROM BACKUP
- name: Stat backup on server
stat:
path: "{{ ipabackup_dir }}/{{ ipabackup_item }}"
register: result_backup_stat
- name: Fail on missing backup directory
fail: msg="Unable to find backup {{ ipabackup_item }}"
when: result_backup_stat.stat.isdir is not defined
- name: Stat header file in backup "{{ ipabackup_item }}"
stat:
path: "{{ ipabackup_dir }}/{{ ipabackup_item }}/header"
register: result_backup_header_stat
- name: Fail on missing header file in backup
fail: msg="Unable to find backup {{ ipabackup_item }} header file"
when: result_backup_header_stat.stat.isreg is not defined
- name: Get services from backup
shell: >
grep "^services = " "{{ ipabackup_dir }}/{{ ipabackup_item }}/header" | cut -d"=" -f2 | tr -d '[:space:]'
register: result_services_grep
- name: Set ipabackup_services
set_fact:
ipabackup_services: "{{ result_services_grep.stdout.split(',') }}"
ipabackup_service_dns: DNS
ipabackup_service_adtrust: ADTRUST
ipabackup_service_ntp: NTP
### INSTALL PACKAGES
- block:
- name: Ensure that IPA server packages are installed
package:
name: "{{ ipaserver_packages }}"
state: present
- name: Ensure that IPA server packages for dns are installed
package:
name: "{{ ipaserver_packages_dns }}"
state: present
when: ipabackup_service_dns in ipabackup_services
- name: Ensure that IPA server packages for adtrust are installed
package:
name: "{{ ipaserver_packages_adtrust }}"
state: present
when: ipabackup_service_adtrust in ipabackup_services
- name: Ensure that firewalld packages are installed
package:
name: "{{ ipaserver_packages_firewalld }}"
state: present
when: ipabackup_setup_firewalld | bool
when: ipabackup_install_packages | bool
### START FIREWALLD
- block:
- name: Ensure that firewalld is running
systemd:
name: firewalld
enabled: yes
state: started
- name: Firewalld - Verify runtime zone "{{ ipabackup_firewalld_zone }}"
shell: >
firewall-cmd
--info-zone="{{ ipabackup_firewalld_zone }}"
>/dev/null
when: ipabackup_firewalld_zone is defined
- name: Firewalld - Verify permanent zone "{{ ipabackup_firewalld_zone }}"
shell: >
firewall-cmd
--permanent
--info-zone="{{ ipabackup_firewalld_zone }}"
>/dev/null
when: ipabackup_firewalld_zone is defined
when: ipabackup_setup_firewalld | bool
### RESTORE
- name: Restore backup
no_log: True
shell: >
ipa-restore
{{ ipabackup_item }}
--unattended
{{ "--password="+ipabackup_password if ipabackup_password is defined }}
{{ "--data" if ipabackup_data | bool }}
{{ "--online" if ipabackup_online | bool }}
{{ "--instance="+ipabackup_instance if ipabackup_instance is defined }}
{{ "--backend="+ipabackup_backend if ipabackup_backend is defined }}
{{ "--no-logs" if ipabackup_no_logs | bool }}
{{ "--log-file="+ipabackup_log_file if ipabackup_log_file is defined }}
register: result_iparestore
ignore_errors: yes
- name: Report error for restore operation
debug:
msg: "{{ result_iparestore.stderr }}"
when: result_iparestore is failed
failed_when: yes
### CONFIGURE FIREWALLD
- name: Configure firewalld
command: >
firewall-cmd
--permanent
--zone="{{ ipabackup_firewalld_zone if ipabackup_firewalld_zone is defined }}"
--add-service=freeipa-ldap
--add-service=freeipa-ldaps
{{ "--add-service=freeipa-trust" if ipabackup_service_adtrust in ipabackup_services }}
{{ "--add-service=dns" if ipabackup_service_dns in ipabackup_services }}
{{ "--add-service=ntp" if ipabackup_service_ntp in ipabackup_services }}
when: ipabackup_setup_firewalld | bool
- name: Configure firewalld runtime
command: >
firewall-cmd
--zone="{{ ipabackup_firewalld_zone if ipabackup_firewalld_zone is defined }}"
--add-service=freeipa-ldap
--add-service=freeipa-ldaps
{{ "--add-service=freeipa-trust" if ipabackup_service_adtrust in ipabackup_services }}
{{ "--add-service=dns" if ipabackup_service_dns in ipabackup_services }}
{{ "--add-service=ntp" if ipabackup_service_ntp in ipabackup_services }}
when: ipabackup_setup_firewalld | bool