diff --git a/roles/os_images/README.md b/roles/os_images/README.md index 1f956f0..316b8d3 100644 --- a/roles/os_images/README.md +++ b/roles/os_images/README.md @@ -85,6 +85,8 @@ mutually exclusive where each contain: * `use_import`: (optional) Whether to use an import workflow instead of direct upload. Useful in conjuction with an [interoperable image import](https://docs.openstack.org/glance/latest/admin/interoperable-image-import.html). Defaults to 'false'. +* `protected`: (optional) Whether the uploaded image should be protected from deletion. + Existing protected images are automatically unprotected before a forced rebuild. `os_images_common`: A set of elements to include in every image listed. Defaults to `cloud-init enable-serial-console stable-interface-names`. diff --git a/roles/os_images/tasks/upload.yml b/roles/os_images/tasks/upload.yml index b8a0e56..ad7e4de 100644 --- a/roles/os_images/tasks/upload.yml +++ b/roles/os_images/tasks/upload.yml @@ -1,4 +1,33 @@ --- +- name: Gather existing cloud tenant images + openstack.cloud.image_info: + auth_type: "{{ os_images_auth_type }}" + auth: "{{ os_images_auth }}" + cacert: "{{ os_images_cacert | default(omit) }}" + interface: "{{ os_images_interface | default(omit, true) }}" + region_name: "{{ os_images_region | default(omit) }}" + register: existing_images + tags: always + +- name: Unprotect existing cloud tenant kernel + ansible.builtin.command: + argv: >- + {{ + [os_images_venv ~ '/bin/openstack' if os_images_venv else 'openstack', + 'image', 'set', '--unprotected', item.name ~ '-kernel'] + }} + environment: "{{ os_images_connection_env }}" + with_items: "{{ os_images_list | list }}" + loop_control: + label: "{{ item.name }}" + when: + - item.elements is defined + - '"baremetal" in item.elements' + - item.force_rebuild | default(os_images_force_rebuild) | bool + - item.name ~ '-kernel' in existing_images.images | map(attribute='name') | list + changed_when: true + tags: clean + - name: Ensure existing cloud tenant kernel does not exist openstack.cloud.image: auth_type: "{{ os_images_auth_type }}" @@ -30,6 +59,7 @@ container_format: aki disk_format: aki filename: "{{ os_images_cache }}/{{ item.name }}/{{ item.name }}.vmlinuz" + protected: "{{ item.protected | default(omit) }}" with_items: "{{ os_images_list | list }}" vars: visibility: "{{ item.visibility | default(item.is_public | ternary('public', 'private') if item.is_public is defined else os_images_visibility) }}" @@ -40,6 +70,25 @@ - '"baremetal" in item.elements' register: kernel_result +- name: Unprotect existing cloud tenant ramdisk + ansible.builtin.command: + argv: >- + {{ + [os_images_venv ~ '/bin/openstack' if os_images_venv else 'openstack', + 'image', 'set', '--unprotected', item.name ~ '-ramdisk'] + }} + environment: "{{ os_images_connection_env }}" + with_items: "{{ os_images_list | list }}" + loop_control: + label: "{{ item.name }}" + when: + - item.elements is defined + - '"baremetal" in item.elements' + - item.force_rebuild | default(os_images_force_rebuild) | bool + - item.name ~ '-ramdisk' in existing_images.images | map(attribute='name') | list + changed_when: true + tags: clean + - name: Ensure existing cloud tenant ramdisk does not exist openstack.cloud.image: auth_type: "{{ os_images_auth_type }}" @@ -71,6 +120,7 @@ container_format: ari disk_format: ari filename: "{{ os_images_cache }}/{{ item.name }}/{{ item.name }}.initrd" + protected: "{{ item.protected | default(omit) }}" with_items: "{{ os_images_list | list }}" vars: visibility: "{{ item.visibility | default(item.is_public | ternary('public', 'private') if item.is_public is defined else os_images_visibility) }}" @@ -81,6 +131,23 @@ - '"baremetal" in item.elements' register: ramdisk_result +- name: Unprotect existing cloud tenant image + ansible.builtin.command: + argv: >- + {{ + [os_images_venv ~ '/bin/openstack' if os_images_venv else 'openstack', + 'image', 'set', '--unprotected', item.name] + }} + environment: "{{ os_images_connection_env }}" + with_items: "{{ os_images_list | list }}" + loop_control: + label: "{{ item.name }}" + when: + - item.force_rebuild | default(os_images_force_rebuild) | bool + - item.name in existing_images.images | map(attribute='name') | list + changed_when: true + tags: clean + - name: Ensure existing cloud tenant image does not exist openstack.cloud.image: auth_type: "{{ os_images_auth_type }}" @@ -114,6 +181,7 @@ kernel: "{{ item.1.id if is_baremetal else omit }}" ramdisk: "{{ item.2.id if is_baremetal else omit }}" use_import: "{{ item.0.use_import | default(omit) }}" + protected: "{{ item.0.protected | default(omit) }}" vars: # NOTE(m-anson): When architecture isn't defined for an # image, assume that we should set cpu_arch: x86_64 as diff --git a/roles/os_images/vars/main.yml b/roles/os_images/vars/main.yml new file mode 100644 index 0000000..753ab85 --- /dev/null +++ b/roles/os_images/vars/main.yml @@ -0,0 +1,15 @@ +--- +os_images_connection_env: >- + {{ + dict( + (os_images_auth | default({}, true)).keys() | list + | map('regex_replace', '^', 'OS_') + | map('upper') + | list + | zip((os_images_auth | default({}, true)).values() | list) + ) + | combine({'OS_AUTH_TYPE': os_images_auth_type} if os_images_auth_type | default('', true) else {}) + | combine({'OS_CACERT': os_images_cacert} if os_images_cacert | default('', true) else {}) + | combine({'OS_INTERFACE': os_images_interface} if os_images_interface | default('', true) else {}) + | combine({'OS_REGION_NAME': os_images_region} if os_images_region | default('', true) else {}) + }}