mirror of
https://github.com/freeipa/ansible-freeipa.git
synced 2026-07-31 11:54:47 +00:00
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:
39
roles/ipabackup/tasks/backup.yml
Normal file
39
roles/ipabackup/tasks/backup.yml
Normal 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
|
||||
46
roles/ipabackup/tasks/copy_backup_from_server.yml
Normal file
46
roles/ipabackup/tasks/copy_backup_from_server.yml
Normal 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
|
||||
43
roles/ipabackup/tasks/copy_backup_to_server.yml
Normal file
43
roles/ipabackup/tasks/copy_backup_to_server.yml
Normal 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=
|
||||
12
roles/ipabackup/tasks/get_ipabackup_dir.yml
Normal file
12
roles/ipabackup/tasks/get_ipabackup_dir.yml
Normal 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 }}"
|
||||
138
roles/ipabackup/tasks/main.yml
Normal file
138
roles/ipabackup/tasks/main.yml
Normal 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"
|
||||
5
roles/ipabackup/tasks/remove_backup_from_server.yml
Normal file
5
roles/ipabackup/tasks/remove_backup_from_server.yml
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
- name: Remove backup "{{ ipabackup_item }}"
|
||||
file:
|
||||
path: "{{ ipabackup_dir }}/{{ ipabackup_item }}"
|
||||
state: absent
|
||||
147
roles/ipabackup/tasks/restore.yml
Normal file
147
roles/ipabackup/tasks/restore.yml
Normal 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
|
||||
Reference in New Issue
Block a user