Chapter 10: Automating Linux Administration Tasks
Archiving and restoring files
Backups, releases and log collections all end up as archives. Ansible has one module to pack files on a managed host and another to unpack them, and with a few options both behave predictably on every run. A backup is only useful if you can restore it, so you will also check that a restore gives back the same files.
- Create compressed archives on managed hosts with
community.general.archive. - Extract archives with
ansible.builtin.unarchive, from the control node or from the managed host. - Control what goes into an archive and where its files land.
- Prove that a restore gives back the right content, owner and mode.
Two modules, two directions
community.general.archive | ansible.builtin.unarchive | |
|---|---|---|
| Does | Packs files into an archive | Unpacks an archive into a directory |
| Source | Files on the managed host | An archive on the control node, or on the managed host with remote_src: true |
| Result | An archive file on the managed host | Files in an existing directory on the managed host |
| Formats | gz (default), bz2, xz, zip, tar | tar (any of those compressions) and zip |
archive is in the community.general collection, which is installed on workstation. unarchive is part of ansible-core. Both need the archiving tools on the managed host, such as tar and gzip, which every RHEL system has.
Create an archive
- name: The release is packaged
community.general.archive:
path: /srv/release/
dest: /tmp/release.tar.gz
format: gz
mode: "0644"pathis what to pack: a file, a directory, a list, or a wildcard such as/var/log/*.log.destis the archive to create.formatchooses the compression;gzgives a.tar.gzfile.mode,ownerandgroupapply to the archive file itself.
The trailing slash decides the layout
path | The archive contains | Extracted into /srv/restored |
|---|---|---|
/srv/release | the directory release/ and its files | /srv/restored/release/version.txt |
/srv/release/ | only the directory's contents | /srv/restored/version.txt |
Decide where the files must land after a restore, then choose the slash.
Extract an archive
- name: The restore directory exists
ansible.builtin.file:
path: /srv/restored
state: directory
mode: "0755"
- name: The release is restored
ansible.builtin.unarchive:
src: /tmp/release.tar.gz
dest: /srv/restored
remote_src: true
owner: root
group: rootdestmust already exist:unarchivedoes not create it.remote_src: truesays the archive is already on the managed host. Without it,unarchivelooks forsrcon the control node and copies it across first, which is how you ship a release that you built on the control node.owner,groupandmodeapply to the extracted files.
Check the restore, not just the archive
An archive that exists is not proof of anything. Check that the restored files match the originals in content and in access:
[student@workstation ~]$ ssh devops@servera.lab.example.com \
'cmp /srv/release/version.txt /srv/restored/version.txt && stat -c "%a %U:%G" /srv/restored/version.txt'
644 root:rootcmp prints nothing and succeeds when two files are identical. If you put checks like these in a playbook, add changed_when: false: they only read, so they must not inflate the change count.
- The archive `/tmp/site.tar.gz` is already on servera. What must the `unarchive` task include so that Ansible does not look for it on the control node?
- You archive `path: /var/www/html/` and extract into `/srv/site`. Where does `index.html` end up?
- An `unarchive` task fails because `/srv/site` does not exist. What is the fix?