From 59afa2826095de1ff30cc308c0da459dcdb42817 Mon Sep 17 00:00:00 2001 From: Thomas Woerner <twoerner@redhat.com> Date: Thu, 22 Oct 2020 13:02:21 +0200 Subject: [PATCH] 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 --- playbooks/backup-server-to-controller.yml | 12 + playbooks/backup-server.yml | 8 + playbooks/copy-all-backups-from-server.yml | 12 + playbooks/copy-backup-from-controller.yml | 12 + playbooks/copy-backup-from-server.yml | 12 + playbooks/remove-all-backups-from-server.yml | 11 + playbooks/remove-backup-from-server.yml | 11 + playbooks/restore-server-from-controller.yml | 13 + playbooks/restore-server.yml | 12 + roles/ipabackup/README.md | 336 ++++++++++++++++++ roles/ipabackup/defaults/main.yml | 16 + roles/ipabackup/meta/main.yml | 20 ++ roles/ipabackup/tasks/backup.yml | 39 ++ .../tasks/copy_backup_from_server.yml | 46 +++ .../ipabackup/tasks/copy_backup_to_server.yml | 43 +++ roles/ipabackup/tasks/get_ipabackup_dir.yml | 12 + roles/ipabackup/tasks/main.yml | 138 +++++++ .../tasks/remove_backup_from_server.yml | 5 + roles/ipabackup/tasks/restore.yml | 147 ++++++++ roles/ipabackup/vars/CentOS-7.yml | 6 + roles/ipabackup/vars/CentOS-8.yml | 1 + roles/ipabackup/vars/Fedora.yml | 4 + roles/ipabackup/vars/OracleLinux-7.yml | 1 + roles/ipabackup/vars/OracleLinux-8.yml | 1 + roles/ipabackup/vars/RedHat-7.3.yml | 6 + roles/ipabackup/vars/RedHat-7.yml | 6 + roles/ipabackup/vars/RedHat-8.yml | 6 + roles/ipabackup/vars/Ubuntu.yml | 5 + roles/ipabackup/vars/default.yml | 6 + 29 files changed, 947 insertions(+) create mode 100644 playbooks/backup-server-to-controller.yml create mode 100644 playbooks/backup-server.yml create mode 100644 playbooks/copy-all-backups-from-server.yml create mode 100644 playbooks/copy-backup-from-controller.yml create mode 100644 playbooks/copy-backup-from-server.yml create mode 100644 playbooks/remove-all-backups-from-server.yml create mode 100644 playbooks/remove-backup-from-server.yml create mode 100644 playbooks/restore-server-from-controller.yml create mode 100644 playbooks/restore-server.yml create mode 100644 roles/ipabackup/README.md create mode 100644 roles/ipabackup/defaults/main.yml create mode 100644 roles/ipabackup/meta/main.yml create mode 100644 roles/ipabackup/tasks/backup.yml create mode 100644 roles/ipabackup/tasks/copy_backup_from_server.yml create mode 100644 roles/ipabackup/tasks/copy_backup_to_server.yml create mode 100644 roles/ipabackup/tasks/get_ipabackup_dir.yml create mode 100644 roles/ipabackup/tasks/main.yml create mode 100644 roles/ipabackup/tasks/remove_backup_from_server.yml create mode 100644 roles/ipabackup/tasks/restore.yml create mode 100644 roles/ipabackup/vars/CentOS-7.yml create mode 120000 roles/ipabackup/vars/CentOS-8.yml create mode 100644 roles/ipabackup/vars/Fedora.yml create mode 120000 roles/ipabackup/vars/OracleLinux-7.yml create mode 120000 roles/ipabackup/vars/OracleLinux-8.yml create mode 100644 roles/ipabackup/vars/RedHat-7.3.yml create mode 100644 roles/ipabackup/vars/RedHat-7.yml create mode 100644 roles/ipabackup/vars/RedHat-8.yml create mode 100644 roles/ipabackup/vars/Ubuntu.yml create mode 100644 roles/ipabackup/vars/default.yml diff --git a/playbooks/backup-server-to-controller.yml b/playbooks/backup-server-to-controller.yml new file mode 100644 index 00000000..c7a4348c --- /dev/null +++ b/playbooks/backup-server-to-controller.yml @@ -0,0 +1,12 @@ +--- +- name: Playbook to backup IPA server to controller + hosts: ipaserver + become: true + + vars: + ipabackup_to_controller: yes + # ipabackup_keep_on_server: yes + + roles: + - role: ipabackup + state: present diff --git a/playbooks/backup-server.yml b/playbooks/backup-server.yml new file mode 100644 index 00000000..44ad3327 --- /dev/null +++ b/playbooks/backup-server.yml @@ -0,0 +1,8 @@ +--- +- name: Playbook to backup IPA server + hosts: ipaserver + become: true + + roles: + - role: ipabackup + state: present diff --git a/playbooks/copy-all-backups-from-server.yml b/playbooks/copy-all-backups-from-server.yml new file mode 100644 index 00000000..93ad1abc --- /dev/null +++ b/playbooks/copy-all-backups-from-server.yml @@ -0,0 +1,12 @@ +--- +- name: Playbook to copy all backups from IPA server + hosts: ipaserver + become: true + + vars: + ipabackup_name: all + ipabackup_to_controller: yes + + roles: + - role: ipabackup + state: copied diff --git a/playbooks/copy-backup-from-controller.yml b/playbooks/copy-backup-from-controller.yml new file mode 100644 index 00000000..578050a9 --- /dev/null +++ b/playbooks/copy-backup-from-controller.yml @@ -0,0 +1,12 @@ +--- +- name: Playbook to copy a backup from controller to the IPA server + hosts: ipaserver + become: true + + vars: + ipabackup_name: ipaserver.test.local_ipa-full-2020-10-22-11-11-44 + ipabackup_from_controller: yes + + roles: + - role: ipabackup + state: copied diff --git a/playbooks/copy-backup-from-server.yml b/playbooks/copy-backup-from-server.yml new file mode 100644 index 00000000..22f117b6 --- /dev/null +++ b/playbooks/copy-backup-from-server.yml @@ -0,0 +1,12 @@ +--- +- name: Playbook to copy backup from IPA server + hosts: ipaserver + become: true + + vars: + ipabackup_name: ipa-full-2020-10-22-11-11-44 + ipabackup_to_controller: yes + + roles: + - role: ipabackup + state: copied diff --git a/playbooks/remove-all-backups-from-server.yml b/playbooks/remove-all-backups-from-server.yml new file mode 100644 index 00000000..032ea3d8 --- /dev/null +++ b/playbooks/remove-all-backups-from-server.yml @@ -0,0 +1,11 @@ +--- +- name: Playbook to remove all backups from IPA server + hosts: ipaserver + become: true + + vars: + ipabackup_name: all + + roles: + - role: ipabackup + state: absent diff --git a/playbooks/remove-backup-from-server.yml b/playbooks/remove-backup-from-server.yml new file mode 100644 index 00000000..7205174e --- /dev/null +++ b/playbooks/remove-backup-from-server.yml @@ -0,0 +1,11 @@ +--- +- name: Playbook to remove backup from IPA server + hosts: ipaserver + become: true + + vars: + ipabackup_name: ipa-full-2020-10-22-11-11-44 + + roles: + - role: ipabackup + state: absent diff --git a/playbooks/restore-server-from-controller.yml b/playbooks/restore-server-from-controller.yml new file mode 100644 index 00000000..2431bc71 --- /dev/null +++ b/playbooks/restore-server-from-controller.yml @@ -0,0 +1,13 @@ +--- +- name: Playbook to restore IPA server from controller + hosts: ipaserver + become: true + + vars: + ipabackup_name: ipaserver.el83.local_ipa-full-2020-10-22-11-11-44 + ipabackup_password: SomeDMpassword + ipabackup_from_controller: yes + + roles: + - role: ipabackup + state: restored diff --git a/playbooks/restore-server.yml b/playbooks/restore-server.yml new file mode 100644 index 00000000..fec18486 --- /dev/null +++ b/playbooks/restore-server.yml @@ -0,0 +1,12 @@ +--- +- name: Playbook to restore an IPA server + hosts: ipaserver + become: true + + vars: + ipabackup_name: ipa-full-2020-10-22-11-11-44 + ipabackup_password: SomeDMpassword + + roles: + - role: ipabackup + state: restored diff --git a/roles/ipabackup/README.md b/roles/ipabackup/README.md new file mode 100644 index 00000000..435c292d --- /dev/null +++ b/roles/ipabackup/README.md @@ -0,0 +1,336 @@ +ipabackup role +============== + +Description +----------- + +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. + + +**Note**: The ansible playbooks and role require a configured ansible environment where the ansible nodes are reachable and are properly set up to have an IP address and a working package manager. + + +Features +-------- +* Server backup +* Server backup to controller +* Copy backup from server to controller +* Copy all backups from server to controller +* Remove backup from the server +* Remove all backups from the server +* Server restore from server local backup. +* Server restore from controller. +* Copy a backup from the controller to the server. + + +Supported FreeIPA Versions +-------------------------- + +FreeIPA versions 4.5 and up are supported by the backup role. + + +Supported Distributions +----------------------- + +* RHEL/CentOS 7.6+ +* Fedora 26+ +* Ubuntu + + +Requirements +------------ + +**Controller** +* Ansible version: 2.8+ + +**Node** +* Supported FreeIPA version (see above) +* Supported distribution (needed for package installation only, see above) + + +Usage +===== + +Example inventory file with fixed domain and realm, setting up of the DNS server and using forwarders from /etc/resolv.conf: + +```ini +[ipaserver] +ipaserver.example.com +``` + +Example playbook to create a backup on the IPA server locally: + +```yaml +--- +- name: Playbook to backup IPA server + hosts: ipaserver + become: true + + roles: + - role: ipabackup + state: present +``` + + +Example playbook to create a backup of the IPA server that is transferred to the controller using the server name as prefix for the backup and removed on the server: + +```yaml +--- +- name: Playbook to backup IPA server to controller + hosts: ipaserver + become: true + + vars: + ipabackup_to_controller: yes + # ipabackup_keep_on_server: yes + + roles: + - role: ipabackup + state: present +``` + + +Example playbook to create a backup of the IPA server that is transferred to the controller using the server name as prefix for the backup and kept on the server: + +```yaml +--- +- name: Playbook to backup IPA server to controller + hosts: ipaserver + become: true + + vars: + ipabackup_to_controller: yes + ipabackup_keep_on_server: yes + + roles: + - role: ipabackup + state: present +``` + + +Copy backup `ipa-full-2020-10-01-10-00-00` from server to controller: + +```yaml +--- +- name: Playbook to copy backup from IPA server + hosts: ipaserver + become: true + + vars: + ipabackup_name: ipa-full-2020-10-01-10-00-00 + ipabackup_to_controller: yes + + roles: + - role: ipabackup + state: copied +``` + + +Copy backups `ipa-full-2020-10-01-10-00-00` and `ipa-full-2020-10-02-10-00-00` from server to controller: + +```yaml +--- +- name: Playbook to copy backup from IPA server + hosts: ipaserver + become: true + + vars: + ipabackup_name: + - ipa-full-2020-10-01-10-00-00 + - ipa-full-2020-10-02-10-00-00 + ipabackup_to_controller: yes + + roles: + - role: ipabackup + state: copied +``` + + +Copy all backups from server to controller that are following the backup naming scheme: + +```yaml +--- +- name: Playbook to copy all backups from IPA server + hosts: ipaserver + become: true + + vars: + ipabackup_name: all + ipabackup_to_controller: yes + + roles: + - role: ipabackup + state: copied +``` + + +Remove backup `ipa-full-2020-10-01-10-00-00` from server: + +```yaml +--- +- name: Playbook to remove backup from IPA server + hosts: ipaserver + become: true + + vars: + ipabackup_name: ipa-full-2020-10-01-10-00-00 + + roles: + - role: ipabackup + state: absent +``` + + +Remove backups `ipa-full-2020-10-01-10-00-00` and `ipa-full-2020-10-02-10-00-00` from server: + +```yaml +--- +- name: Playbook to remove backup from IPA server + hosts: ipaserver + become: true + + vars: + ipabackup_name: + - ipa-full-2020-10-01-10-00-00 + - ipa-full-2020-10-02-10-00-00 + + roles: + - role: ipabackup + state: absent +``` + + +Remove all backups from server that are following the backup naming scheme: + +```yaml +--- +- name: Playbook to remove all backups from IPA server + hosts: ipaserver + become: true + + vars: + ipabackup_name: all + + roles: + - role: ipabackup + state: absent +``` + + +Example playbook to restore an IPA server locally: + +```yaml +--- +- name: Playbook to restore an IPA server + hosts: ipaserver + become: true + + vars: + ipabackup_name: ipa-full-2020-10-22-11-11-44 + ipabackup_password: SomeDMpassword + + roles: + - role: ipabackup + state: restored +``` + + +Example playbook to restore IPA server from controller: + +```yaml +--- +- name: Playbook to restore IPA server from controller + hosts: ipaserver + become: true + + vars: + ipabackup_name: ipaserver.test.local_ipa-full-2020-10-22-11-11-44 + ipabackup_password: SomeDMpassword + ipabackup_from_controller: yes + + roles: + - role: ipabackup + state: restored +``` + + +Example playbook to copy a backup from controller to the IPA server: + +```yaml +--- +- name: Playbook to copy a backup from controller to the IPA server + hosts: ipaserver + become: true + + vars: + ipabackup_name: ipaserver.test.local_ipa-full-2020-10-22-11-11-44 + ipabackup_from_controller: yes + + roles: + - role: ipabackup + state: copied +``` + + +Playbooks +========= + +The example playbooks to do the backup, copy a backup and also to remove a backup, also to do the restore, copy a backup to the server are part of the repository in the playbooks folder. + +``` +backup-server.yml +backup-server-to-controller.yml +copy-all-backups-from-server.yml +copy-backup-from-server.yml +remove-all-backups-from-server.yml +remove-backup-from-server.yml +restore-server.yml +restore-server-from-controller.yml +copy-backup-from-controller.yml +``` + +Please remember to link or copy the playbooks to the base directory of ansible-freeipa if you want to use the roles within the source archive. + + +Variables +========= + +Base Variables +-------------- + +Variable | Description | Required +-------- | ----------- | -------- +ipabackup_backend | The backend to restore within the instance or instances, str | no +ipabackup_data | Backup only the data with `state: present` and restore only the data with `state: restored`, bool (default: `no`) | no +ipabackup_disable_role_check | Perform the backup even if this host does not have all the roles used in the cluster. This is not recommended, bool (default: `no`) | no +ipabackup_gpg | Encrypt the backup, bool (default: `no`) | no +ipabackup_gpg_keyring | Full path to the GPG keyring without the file extension, only for GPG 1 and up to IPA 4.6 str | no +ipabackup_instance | The 389-ds instance to restore (defaults to all found), str | no +ipabackup_log_file | Log to the given file on server for `state: present` and `state: restored` only, string | no +ipabackup_logs | Include log files in backup, bool (default: `no`) | no +ipabackup_no_logs | Do not restore log files from the backup, bool (default: `no`) | no +ipabackup_online | Perform the LDAP backups online for data only with `state: present` and perform the LDAP restore online for data only with `state: restored`. If `ipabackup_data` is not set it will automatically be enabled. bool (default: `no`) | no +ipabackup_password | The diretory manager password needed for restoring a backup with `state: restored`, str | no +state | `present` to make a new backup, `absent` to remove a backup and `copied` to copy a backup from the server to the controller or from the controller to the server, `restored` to restore a backup. string (default: `present`) | yes + + +Special Variables +----------------- + +Variable | Description | Required +-------- | ----------- | -------- +ipabackup_name | The IPA backup name(s). Only for removal of server local backup(s) with `state: absent`, to copy server local backup(s) to the controller with `state: copied` and `ipabackup_from_server` set, to copy a backup from the controller to the server with `state: copied` and `ipabackup_from_controller` set or to restore a backup with `state: restored` either locally on the server of from the controller with `ipabackup_from_controller` set. If `all` is used all available backups are copied or removed that are following the backup naming scheme. string list | no +ipabackup_keep_on_server | Keep local copy of backup on server with `state: present` and `ipabackup_to_controller`, bool (default: `no`) | no +ipabackup_to_controller | Copy backup to controller, prefixes backup with node name, remove backup on server if `ipabackup_keep_on_server` is not set, bool (default: `no`) | no +ipabackup_controller_path | Pre existing path on controller to store the backup in with `state: present`, path on the controller to copy the backup from with `state: copied` and `ipabackup_from_controller` set also for the restore with `state: restored` and `ipabackup_from_controller` set. If this is not set, the current working dir is used. string | no +ipabackup_name_prefix | Set prefix to use for backup directory on controller with `state: present` or `state: copied` and `ipabackup_to_controller` set, The default is the server FQDN, string | no +ipabackup_from_controller | Copy backup from controller to server, restore if `state: restored`, copy backup to server if `state: copied`, bool (default: `no`) | no +ipabackup_install_packages | Install needed packages to be able to apply the backup with `state: restored`, bool (default: `yes`) | no +ipabackup_firewalld_zone | The value defines the firewall zone that will be used with `state: restored`. This needs to be an existing runtime and permanent zone, bool (default: `no`) | no +ipabackup_setup_firewalld | The value defines if the needed services will automatically be opened in the firewall managed by firewalld with `state: restored`, bool (default: `yes`) | no + + +Authors +======= + +Thomas Woerner diff --git a/roles/ipabackup/defaults/main.yml b/roles/ipabackup/defaults/main.yml new file mode 100644 index 00000000..2debe18e --- /dev/null +++ b/roles/ipabackup/defaults/main.yml @@ -0,0 +1,16 @@ +--- +# defaults file for ipabackup + +ipabackup_gpg: no +ipabackup_data: no +ipabackup_logs: no +ipabackup_online: no +ipabackup_disable_role_check: no +ipabackup_no_logs: no + +### special ### +ipabackup_keep_on_server: no +ipabackup_to_controller: no +ipabackup_from_controller: no +ipabackup_install_packages: yes +ipabackup_setup_firewalld: yes diff --git a/roles/ipabackup/meta/main.yml b/roles/ipabackup/meta/main.yml new file mode 100644 index 00000000..db6732af --- /dev/null +++ b/roles/ipabackup/meta/main.yml @@ -0,0 +1,20 @@ +dependencies: [] + +galaxy_info: + author: Thomas Woerner + description: A role to backup and restore an IPA server + company: Red Hat, Inc + license: GPLv3 + min_ansible_version: 2.8 + platforms: + - name: Fedora + versions: + - all + - name: EL + versions: + - 7 + - 8 + galaxy_tags: + - identity + - ipa + - freeipa diff --git a/roles/ipabackup/tasks/backup.yml b/roles/ipabackup/tasks/backup.yml new file mode 100644 index 00000000..f2bce9f9 --- /dev/null +++ b/roles/ipabackup/tasks/backup.yml @@ -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 diff --git a/roles/ipabackup/tasks/copy_backup_from_server.yml b/roles/ipabackup/tasks/copy_backup_from_server.yml new file mode 100644 index 00000000..1cfef3de --- /dev/null +++ b/roles/ipabackup/tasks/copy_backup_from_server.yml @@ -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 diff --git a/roles/ipabackup/tasks/copy_backup_to_server.yml b/roles/ipabackup/tasks/copy_backup_to_server.yml new file mode 100644 index 00000000..73c6ef39 --- /dev/null +++ b/roles/ipabackup/tasks/copy_backup_to_server.yml @@ -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= diff --git a/roles/ipabackup/tasks/get_ipabackup_dir.yml b/roles/ipabackup/tasks/get_ipabackup_dir.yml new file mode 100644 index 00000000..41597e8d --- /dev/null +++ b/roles/ipabackup/tasks/get_ipabackup_dir.yml @@ -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 }}" diff --git a/roles/ipabackup/tasks/main.yml b/roles/ipabackup/tasks/main.yml new file mode 100644 index 00000000..148913f7 --- /dev/null +++ b/roles/ipabackup/tasks/main.yml @@ -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" diff --git a/roles/ipabackup/tasks/remove_backup_from_server.yml b/roles/ipabackup/tasks/remove_backup_from_server.yml new file mode 100644 index 00000000..52c071cc --- /dev/null +++ b/roles/ipabackup/tasks/remove_backup_from_server.yml @@ -0,0 +1,5 @@ +--- +- name: Remove backup "{{ ipabackup_item }}" + file: + path: "{{ ipabackup_dir }}/{{ ipabackup_item }}" + state: absent diff --git a/roles/ipabackup/tasks/restore.yml b/roles/ipabackup/tasks/restore.yml new file mode 100644 index 00000000..c7a491f6 --- /dev/null +++ b/roles/ipabackup/tasks/restore.yml @@ -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 diff --git a/roles/ipabackup/vars/CentOS-7.yml b/roles/ipabackup/vars/CentOS-7.yml new file mode 100644 index 00000000..11863757 --- /dev/null +++ b/roles/ipabackup/vars/CentOS-7.yml @@ -0,0 +1,6 @@ +# defaults file for ipaserver +# vars/rhel.yml +ipaserver_packages: [ "ipa-server", "libselinux-python" ] +ipaserver_packages_dns: [ "ipa-server-dns" ] +ipaserver_packages_adtrust: [ "ipa-server-trust-ad" ] +ipaserver_packages_firewalld: [ "firewalld" ] \ No newline at end of file diff --git a/roles/ipabackup/vars/CentOS-8.yml b/roles/ipabackup/vars/CentOS-8.yml new file mode 120000 index 00000000..d49e1cd5 --- /dev/null +++ b/roles/ipabackup/vars/CentOS-8.yml @@ -0,0 +1 @@ +RedHat-8.yml \ No newline at end of file diff --git a/roles/ipabackup/vars/Fedora.yml b/roles/ipabackup/vars/Fedora.yml new file mode 100644 index 00000000..77112041 --- /dev/null +++ b/roles/ipabackup/vars/Fedora.yml @@ -0,0 +1,4 @@ +ipaserver_packages: [ "freeipa-server" ] +ipaserver_packages_dns: [ "freeipa-server-dns" ] +ipaserver_packages_adtrust: [ "freeipa-server-trust-ad" ] +ipaserver_packages_firewalld: [ "firewalld" ] diff --git a/roles/ipabackup/vars/OracleLinux-7.yml b/roles/ipabackup/vars/OracleLinux-7.yml new file mode 120000 index 00000000..852b838d --- /dev/null +++ b/roles/ipabackup/vars/OracleLinux-7.yml @@ -0,0 +1 @@ +RedHat-7.yml \ No newline at end of file diff --git a/roles/ipabackup/vars/OracleLinux-8.yml b/roles/ipabackup/vars/OracleLinux-8.yml new file mode 120000 index 00000000..d49e1cd5 --- /dev/null +++ b/roles/ipabackup/vars/OracleLinux-8.yml @@ -0,0 +1 @@ +RedHat-8.yml \ No newline at end of file diff --git a/roles/ipabackup/vars/RedHat-7.3.yml b/roles/ipabackup/vars/RedHat-7.3.yml new file mode 100644 index 00000000..11863757 --- /dev/null +++ b/roles/ipabackup/vars/RedHat-7.3.yml @@ -0,0 +1,6 @@ +# defaults file for ipaserver +# vars/rhel.yml +ipaserver_packages: [ "ipa-server", "libselinux-python" ] +ipaserver_packages_dns: [ "ipa-server-dns" ] +ipaserver_packages_adtrust: [ "ipa-server-trust-ad" ] +ipaserver_packages_firewalld: [ "firewalld" ] \ No newline at end of file diff --git a/roles/ipabackup/vars/RedHat-7.yml b/roles/ipabackup/vars/RedHat-7.yml new file mode 100644 index 00000000..11863757 --- /dev/null +++ b/roles/ipabackup/vars/RedHat-7.yml @@ -0,0 +1,6 @@ +# defaults file for ipaserver +# vars/rhel.yml +ipaserver_packages: [ "ipa-server", "libselinux-python" ] +ipaserver_packages_dns: [ "ipa-server-dns" ] +ipaserver_packages_adtrust: [ "ipa-server-trust-ad" ] +ipaserver_packages_firewalld: [ "firewalld" ] \ No newline at end of file diff --git a/roles/ipabackup/vars/RedHat-8.yml b/roles/ipabackup/vars/RedHat-8.yml new file mode 100644 index 00000000..7f5ae464 --- /dev/null +++ b/roles/ipabackup/vars/RedHat-8.yml @@ -0,0 +1,6 @@ +# defaults file for ipaserver +# vars/RedHat-8.yml +ipaserver_packages: [ "@idm:DL1/server" ] +ipaserver_packages_dns: [ "@idm:DL1/dns" ] +ipaserver_packages_adtrust: [ "@idm:DL1/adtrust" ] +ipaserver_packages_firewalld: [ "firewalld" ] diff --git a/roles/ipabackup/vars/Ubuntu.yml b/roles/ipabackup/vars/Ubuntu.yml new file mode 100644 index 00000000..d0e01ea8 --- /dev/null +++ b/roles/ipabackup/vars/Ubuntu.yml @@ -0,0 +1,5 @@ +# vars/Ubuntu.yml +ipaserver_packages: [ "freeipa-server" ] +ipaserver_packages_dns: [ "freeipa-server-dns" ] +ipaserver_packages_adtrust: [ "freeipa-server-trust-ad" ] +ipaserver_packages_firewalld: [ "firewalld" ] diff --git a/roles/ipabackup/vars/default.yml b/roles/ipabackup/vars/default.yml new file mode 100644 index 00000000..4d28ac65 --- /dev/null +++ b/roles/ipabackup/vars/default.yml @@ -0,0 +1,6 @@ +# defaults file for ipaserver +# vars/default.yml +ipaserver_packages: [ "ipa-server" ] +ipaserver_packages_dns: [ "ipa-server-dns" ] +ipaserver_packages_adtrust: [ "freeipa-server-trust-ad" ] +ipaserver_packages_firewalld: [ "firewalld" ] -- GitLab