- name: image name debug: msg: "checking for image {{ image.name }}" # Set some convenience variables here to avoid boilerplate code # elsewhere in this file. These are all set unconditionally to avoid # any cruft leftover from a previous call to this file. - name: set local variables set_fact: _force_cached_image: >- {{ force_cached_images|default(false)|bool or image.force_cached|default(false)|bool }} _latest: >- {{ image_cache_dir }}/latest-{{ image.name }}.{{ image.type }} cacheable: true # This looks for the latest image symlink that may have been created # by a previous run of this tasklist. - name: Check if we have a latest image command: > test -f {{ _latest }} args: chdir: "{{ image_cache_dir }}" ignore_errors: true register: latest_exists changed_when: false # If we want to use the most recent image in the local cache # (`_force_cached_image` is `true`) *and* such an image exists, point # `image_cache_path` at `latest-{{image.name}}.qcow2`. - name: Set path to cached image [local] set_fact: image_cache_path: "{{ _latest }}" cacheable: true when: latest_exists is success and _force_cached_image # The md5sum for base OS images are not hosted, they are defined in a configuration file. # Handle base os images slightly differently - when: image.md5sum is defined block: # Get the expected checksum from settings vs. pulling the md5sum. - name: Get image expected checksum for base OS images set_fact: md5_expected: "{{ image.md5sum.split()[0] }}" cacheable: true - name: Set path to cached image set_fact: image_cache_path: "{{ image_cache_dir }}/{{ md5_expected }}.{{ image.type }}" cacheable: true # See if a matching image exists locally. - name: Check for base OS image in cache command: > test -f {{ image_cache_path }} args: chdir: "{{ image_cache_dir }}" ignore_errors: true register: base_image_exists changed_when: false # Otherwise, check if there's a new image available. - when: - image.md5sum is not defined - not _force_cached_image or latest_exists is failed block: # Get the expected checksum for the remote image. - name: Get image expected checksum command: > curl -sfL {{ image.url }}.md5 register: md5_expected - name: sanitize the md5sum set_fact: md5_expected: "{{ md5_expected.stdout.split()[0] }}" cacheable: true - name: Set path to cached image [upstream] set_fact: image_cache_path: "{{ image_cache_dir }}/{{ md5_expected }}.{{ image.type }}" cacheable: true # See if a matching image exists locally. - name: Check for image in cache command: > test -f {{ image_cache_path }} args: chdir: "{{ image_cache_dir }}" ignore_errors: true register: image_exists changed_when: false # Looks like we're going to have to download the image after all. # Note.. image_exists and base_image_exists are required variables because # even unused variables will overwrite each other. - when: image_exists is defined and (image_exists is failed or base_image_exists is failed) block: # This task will download the image. We're using `curl` here # rather than `wget` because while `wget` has built-in retry # capabilities, it is unable to handle `file://` URLs. We instead # use an ansible `until` loop, combined with curl's `-C-` option # to continue interrupted downloads. - name: Get image command: > curl -sfL -C- -o _{{ image.name }}.{{ image.type}} {{ image.url }} args: chdir: "{{ image_cache_dir }}" register: curl_result until: curl_result.rc not in [18, 56] retries: 20 delay: 5 # Compute the md5 checksum of the image we just downloaded - name: Get actual md5 checksum of image command: > md5sum -b _{{ image.name }}.{{ image.type}} args: chdir: "{{ image_cache_dir }}" register: md5_actual - name: sanitize the md5sum for the downloaded image set_fact: md5_actual: "{{ md5_actual.stdout.split()[0] }}" cacheable: true # Verify that what we have is what we wanted. - name: Verify image checksum fail: msg: image checksum does not match when: > image_exists is failed and (md5_expected != md5_actual) - name: Cache image by checksum command: > mv _{{ image.name }}.{{ image.type}} {{ image_cache_path }} args: chdir: "{{ image_cache_dir }}" - name: Update "latest" symlink file: path: "{{ _latest }}" state: link src: "{{ image_cache_path }}" # This is a workaround for ansible issue [15625][]. # # [15625]: https://github.com/ansible/ansible/issues/15625 rescue: - name: Note that there was a failure. set_fact: image_fetch_failed: true cacheable: true # Ensure that even if there are failures we still clean up our # temporary image file. always: - name: Clean up temporary image file file: path: "{{ image_cache_dir }}/_{{ image.name }}.{{ image.type }}" state: absent - name: Propagate failure fail: when: image_fetch_failed|default(false) # Use `image_cache_path`, which was set by one of the above tasks, and # copy it to `undercloud.qcow2 in our `{{ image_fetch_dir }}`. - name: Get qcow2 image from cache command: > cp {{ image_cache_path }} {{ image_fetch_dir }}/{{ image.name }}.{{ image.type }} when: image.type == "qcow2" and image.md5sum is not defined # Same as the above just copy the base os image to the fetch_dir as undercloud - name: Get base OS qcow2 image from cache command: > cp {{ image_cache_path }} {{ image_fetch_dir }}/undercloud.{{ image.type }} when: image.type == "qcow2" and image.md5sum is defined - name: Get tar images from cache unarchive: src: "{{ image_cache_path }}" copy: no dest: "{{ image_fetch_dir }}" list_files: yes when: image.type == "tar" - name: Clean image cache directory shell: >- find {{ image_cache_dir }} -type f {% if not image_cache_dir_cleanup|bool %} -mtime +{{ image_cache_expire_days|int - 1 }} {% endif %}| xargs --no-run-if-empty -t rm -rf