diff --git a/roles/nebulous-promote-container-image/defaults/main.yaml b/roles/nebulous-promote-container-image/defaults/main.yaml new file mode 100644 index 0000000..deda4a5 --- /dev/null +++ b/roles/nebulous-promote-container-image/defaults/main.yaml @@ -0,0 +1,2 @@ +zuul_work_dir: "{{ zuul.project.src_dir }}" +promote_container_image_query: "change={{ zuul.change }}&patchset={{ zuul.patchset }}&pipeline={{ promote_container_image_pipeline }}&job_name={{ promote_container_image_job }}" diff --git a/roles/nebulous-promote-container-image/tasks/main.yaml b/roles/nebulous-promote-container-image/tasks/main.yaml new file mode 100644 index 0000000..19c21e2 --- /dev/null +++ b/roles/nebulous-promote-container-image/tasks/main.yaml @@ -0,0 +1,30 @@ +- name: Verify repository names + when: | + container_registry_credentials is defined + and zj_image.registry not in container_registry_credentials + loop: "{{ container_images }}" + loop_control: + loop_var: zj_image + fail: + msg: "{{ zj_image.registry }} credentials not found" + +- name: Verify repository permission + when: | + container_registry_credentials[zj_image.registry].repository is defined and + not zj_image.repository | regex_search(container_registry_credentials[zj_image.registry].repository) + loop: "{{ container_images }}" + loop_control: + loop_var: zj_image + fail: + msg: "{{ zj_image.repository }} not permitted by {{ container_registry_credentials[zj_image.registry].repository }}" + +- name: Promote image + when: promote_container_image_method|default('tag') == 'tag' + loop: "{{ container_images }}" + loop_control: + loop_var: zj_image + include_tasks: promote-retag.yaml + +- name: Promote container image with intermediate registry + when: promote_container_image_method|default('tag') == 'intermediate-registry' + include_tasks: promote-from-intermediate-registry.yaml diff --git a/roles/nebulous-promote-container-image/tasks/promote-from-intermediate-registry.yaml b/roles/nebulous-promote-container-image/tasks/promote-from-intermediate-registry.yaml new file mode 100644 index 0000000..9305842 --- /dev/null +++ b/roles/nebulous-promote-container-image/tasks/promote-from-intermediate-registry.yaml @@ -0,0 +1,21 @@ +- name: Query Zuul API for image information + uri: + url: "{{ promote_container_image_api }}/builds?{{ promote_container_image_query }}" + register: build + +- name: Parse build response + set_fact: + build: "{{ build.json[0] }}" + +- name: Map image artifacts + set_fact: + zj_artifact_map: "{{ zj_artifact_map | default({}) | combine({zj_map_item.metadata.repository + ':' + zj_map_item.metadata.tag: zj_map_item.url}) }}" + loop_control: + loop_var: zj_map_item + loop: "{{ build | json_query(\"artifacts[?metadata.type=='container_image']\")}}" + +- name: Promote image + loop: "{{ container_images }}" + loop_control: + loop_var: zj_image + include_tasks: promote-registry.yaml diff --git a/roles/nebulous-promote-container-image/tasks/promote-registry.yaml b/roles/nebulous-promote-container-image/tasks/promote-registry.yaml new file mode 100644 index 0000000..2af30ca --- /dev/null +++ b/roles/nebulous-promote-container-image/tasks/promote-registry.yaml @@ -0,0 +1,37 @@ +- name: Log in to registry + no_log: true + command: >- + skopeo login {{ zj_image.registry }} -u {{ container_registry_credentials[zj_image.registry].username }} -p {{ container_registry_credentials[zj_image.registry].password }} + register: result + until: result.rc == 0 + retries: 3 + delay: 30 + +- name: Copy image + block: + + - name: Copy image using the commit id + loop: "{{ zj_image.tags | default(['latest']) }}" + loop_control: + loop_var: zj_image_tag + command: >- + skopeo --insecure-policy copy --all {{ zj_artifact_map[zj_image.repository + ':' + zj_image_tag] }} docker://{{ zj_image.repository }}:{{ zuul.commit_id }} + register: result + until: result.rc == 0 + retries: 3 + delay: 30 + + - name: Copy image using the tag + loop: "{{ zj_image.tags | default(['latest']) }}" + loop_control: + loop_var: zj_image_tag + command: >- + skopeo --insecure-policy copy --all {{ zj_artifact_map[zj_image.repository + ':' + zj_image_tag] }} docker://{{ zj_image.repository }}:{{ zj_image_tag }} + register: result + until: result.rc == 0 + retries: 3 + delay: 30 + + always: + - name: Log out of registry + command: "skopeo logout {{ zj_image.registry }}" diff --git a/roles/nebulous-promote-container-image/tasks/promote-retag-inner.yaml b/roles/nebulous-promote-container-image/tasks/promote-retag-inner.yaml new file mode 100644 index 0000000..5a4dfee --- /dev/null +++ b/roles/nebulous-promote-container-image/tasks/promote-retag-inner.yaml @@ -0,0 +1,19 @@ +- name: Set promote_tag_prefix + set_fact: + promote_tag_prefix: "{{ ('change_' + zuul.change) if (zuul.change is defined) else zuul.pipeline }}" + +- name: Create the final image tag + command: >- + skopeo --insecure-policy copy --all docker://{{ zj_image.repository }}:{{ promote_tag_prefix }}_{{ zj_image_tag }} docker://{{ zj_image.repository }}:{{ zj_image_tag }} + register: result + until: result.rc == 0 + retries: 3 + delay: 30 + +- name: Delete the temporary change tag we just renamed + include_role: + name: remove-registry-tag + vars: + remove_registry_tag_repository: '{{ zj_image.repository }}' + remove_registry_tag_tag: '{{ promote_tag_prefix }}_{{ zj_image_tag }}' + no_log: true diff --git a/roles/nebulous-promote-container-image/tasks/promote-retag.yaml b/roles/nebulous-promote-container-image/tasks/promote-retag.yaml new file mode 100644 index 0000000..dbe4538 --- /dev/null +++ b/roles/nebulous-promote-container-image/tasks/promote-retag.yaml @@ -0,0 +1,28 @@ +- name: Log in to registry + no_log: true + command: >- + skopeo login {{ zj_image.registry }} -u {{ container_registry_credentials[zj_image.registry].username }} -p {{ container_registry_credentials[zj_image.registry].password }} + register: result + until: result.rc == 0 + retries: 3 + delay: 30 + +- name: Retag image + block: + - name: Retag image + loop: "{{ zj_image.tags | default(['latest']) }}" + loop_control: + loop_var: zj_image_tag + include_tasks: promote-retag-inner.yaml + always: + - name: Log out of registry + command: "skopeo logout {{ zj_image.registry }}" + +# If a gate job failed, we might have uploaded and leaked tags. This +# cleans up anything around for more than 24 hours +- name: Cleanup leaked images + include_role: + name: remove-registry-tag + vars: + remove_registry_tag_repository: '{{ zj_image.repository }}' + no_log: true