I am setting up an autoinstall environment with PXE boot. To install Linux this way, one basically needs to download linux
and initrd.gz
files which are buried deeply in the repository structure and also supply a pxelinux and/or pxegrub configuration which will reference these files. This is for Debian; other distros should be similar. I did that before by hand.
I wrote the following basic playbook to download files from the server and put them into tftp server:
- name: test download
hosts: test-netinstsrv
gather_facts: false
vars:
netboot:
base: https://deb.debian.org/debian/dists/bullseye/main/installer-amd64/current/images/
files_base: netboot/debian-installer/amd64/
files: [ linux, initrd.gz ]
tasks:
- name: Create a temporary directory
ansible.builtin.tempfile:
state: directory
suffix: netboot
register: tmpdir
delegate_to: localhost
run_once: true
changed_when: false
- name: Set permissions
ansible.builtin.file:
path: "{{ tmpdir.path }}"
mode: 0755
delegate_to: localhost
run_once: true
changed_when: false
- name: Download files
ansible.builtin.uri:
url: "{{ netboot.base }}{{ netboot.files_base }}{{ item }}"
dest: "{{ tmpdir.path }}/{{ item }}"
method: "get"
loop: "{{ netboot.files }}"
delegate_to: localhost
run_once: true
register: downloaded_file
changed_when: false
- name: Copy files to the remote
ansible.builtin.copy:
src: "{{ tmpdir.path }}/{{ item }}"
dest: "/tmp/"
loop: "{{ netboot.files }}"
- name: Remove temporary directory
ansible.builtin.file:
path: "{{ tmpdir.path }}"
state: absent
delegate_to: localhost
run_once: true
changed_when: false
(The actual playbook is much more massive, this is an extract.)
This works, but what is inefficient is that for every play it always downloads both files, even if nothing has changed. I had to put changed_when
almost everywhere so not to see bogus changes in a play recap; the only real change could be is the one copy
module can make. As I plan to extend this to several versions of Debian (all currently supported) and add other distributions, the amount of download will become excessive.
I use an uri
module to download files, but I didn't find in the documentation how to make this download conditional. What I want to achieve is for the download module to make something like If-Modified-Since request to which repository web server can return 304 Not Modified and this would imply a skip of the update of boot images on target servers, saving from a download.
This is slightly complicated by the fact it is expected there is no Internet access from target servers. All downloading is therefore has to be done by the controller machine, so I delegate most tasks to localhost.
One idea was to first fetch those files from one of my target servers to the controller and then hope that uri module will detect that files are already there and won't re-download them unless they are changed. Will it work? Is there any other way to achieve this?
Update
I tried with get_url
module (even before answer appeared). The changes to the playbook basically are:
- name: Create required subdirectories
ansible.builtin.file:
path: "{{ tmpdir.path }}/{{ netboot.files_base }}"
state: directory
delegate_to: localhost
run_once: true
- name: Download files
ansible.builtin.get_url:
url: "{{ netboot.base }}{{ netboot.files_base }}{{ item }}"
dest: "{{ tmpdir.path }}/{{ netboot.files_base }}{{ item }}"
checksum: "sha256:{{ netboot.base }}SHA256SUMS"
loop: "{{ netboot.files }}"
delegate_to: localhost
run_once: true
register: downloaded_file
This fails:
failed: [test-netinstsrv -> localhost] (item=linux) => {"ansible_loop_var": "item", "changed": false, "item": "linux", "msg": "Unable to find a checksum for file 'linux' in 'https://deb.debian.org/debian/dists/bullseye/main/installer-amd64/current/images/SHA256SUMS'"}
failed: [test-netinstsrv -> localhost] (item=initrd.gz) => {"ansible_loop_var": "item", "changed": false, "item": "initrd.gz", "msg": "Unable to find a checksum for file 'initrd.gz' in 'https://deb.debian.org/debian/dists/bullseye/main/installer-amd64/current/images/SHA256SUMS'"}
Probably, because SHA256SUMS
has the following structure:
...
52eb21964231223563a59656708270c5708c8dcf5b3a1c5cccb1924af9964332 ./netboot/debian-installer/amd64/initrd.gz
b00b339f8b1aada1841d86650377dd8e7299eaa7f34d0bbf21deb561467015cd ./netboot/debian-installer/amd64/linux
...
Probably, if I download that file and re-format it, it helps...