diff --git a/roles/download/defaults/main.yml b/roles/download/defaults/main.yml index ca0048673..dc06f73d9 100644 --- a/roles/download/defaults/main.yml +++ b/roles/download/defaults/main.yml @@ -138,6 +138,7 @@ etcd_download_url: "https://github.com/etcd-io/etcd/releases/download/{{ etcd_ve flannel_cni_download_url: "https://github.com/flannel-io/cni-plugin/releases/download/{{ flannel_cni_version }}/flannel-{{ image_arch }}" cni_download_url: "https://github.com/containernetworking/plugins/releases/download/{{ cni_version }}/cni-plugins-linux-{{ image_arch }}-{{ cni_version }}.tgz" calicoctl_download_url: "https://github.com/projectcalico/calicoctl/releases/download/{{ calico_ctl_version }}/calicoctl-linux-{{ image_arch }}" +calicoctl_alternate_download_url: "https://github.com/projectcalico/calico/releases/download/{{ calico_ctl_version }}/calicoctl-linux-{{ image_arch }}" calico_crds_download_url: "https://github.com/projectcalico/calico/archive/{{ calico_version }}.tar.gz" crictl_download_url: "https://github.com/kubernetes-sigs/cri-tools/releases/download/{{ crictl_version }}/crictl-{{ crictl_version }}-{{ ansible_system | lower }}-{{ image_arch }}.tar.gz" helm_download_url: "https://get.helm.sh/helm-{{ helm_version }}-linux-{{ image_arch }}.tar.gz" @@ -1120,6 +1121,9 @@ downloads: dest: "{{ local_release_dir }}/calicoctl" sha256: "{{ calicoctl_binary_checksum }}" url: "{{ calicoctl_download_url }}" + mirrors: + - "{{ calicoctl_alternate_download_url }}" + - "{{ calicoctl_download_url }}" unarchive: false owner: "root" mode: "0755" diff --git a/roles/download/tasks/download_file.yml b/roles/download/tasks/download_file.yml index f7dcfda10..d84098648 100644 --- a/roles/download/tasks/download_file.yml +++ b/roles/download/tasks/download_file.yml @@ -47,11 +47,40 @@ - download_force_cache - not download_localhost + # We check a number of mirrors that may hold the file and pick a working one at random + # This task will avoid logging it's parameters to not leak environment passwords in the log + - name: download_file | Validate mirrors + uri: + url: "{{ mirror }}" + method: HEAD + validate_certs: "{{ download_validate_certs }}" + url_username: "{{ download.username | default(omit) }}" + url_password: "{{ download.password | default(omit) }}" + force_basic_auth: "{{ download.force_basic_auth | default(omit) }}" + delegate_to: "{{ download_delegate if download_force_cache else inventory_hostname }}" + run_once: "{{ download_force_cache }}" + register: uri_result + until: uri_result is success + retries: 4 + delay: "{{ retry_stagger | default(5) }}" + environment: "{{ proxy_env }}" + no_log: true + loop: "{{ download.mirrors | default([download.url]) }}" + loop_control: + loop_var: mirror + ignore_errors: true + + # Ansible 2.9 requires we convert a generator to a list + - name: download_file | Get the list of working mirrors + set_fact: + valid_mirror_urls: "{{ uri_result.results | selectattr('failed', 'eq', False) | map(attribute='mirror') | list }}" + delegate_to: "{{ download_delegate if download_force_cache else inventory_hostname }}" + # This must always be called, to check if the checksum matches. On no-match the file is re-downloaded. # This task will avoid logging it's parameters to not leak environment passwords in the log - name: download_file | Download item get_url: - url: "{{ download.url }}" + url: "{{ valid_mirror_urls | random }}" dest: "{{ file_path_cached if download_force_cache else download.dest }}" owner: "{{ omit if download_localhost else (download.owner | default(omit)) }}" mode: "{{ omit if download_localhost else (download.mode | default(omit)) }}"