|
| 1 | +--- |
| 2 | +# Logic to identify image with given os_distro, os_version, os_purpose |
| 3 | +# Simply find the image for new SCS clouds that have os_purpose set. |
| 4 | +# Fall back to name matching otherwise. |
| 5 | +# (c) Kurt Garloff <[email protected]>, 11/2025 |
| 6 | +# SPDX-License-Identifier: MIT |
| 7 | +# Created with help from Claude AI |
| 8 | + |
| 9 | +- name: Select Image with purpose and fall back to name matching |
| 10 | + hosts: localhost |
| 11 | + gather_facts: false |
| 12 | + vars: |
| 13 | + # Primary selection criteria |
| 14 | + os_version: '24.04' |
| 15 | + os_distro: 'ubuntu' |
| 16 | + os_purpose: 'generic' |
| 17 | + cloud_name: "{{ lookup('env', 'OS_CLOUD'} | default('openstack') }}" |
| 18 | + |
| 19 | + tasks: |
| 20 | + - name: Get available images matching os_distro and os_version |
| 21 | + openstack.cloud.image_info: |
| 22 | + cloud: '{{ cloud_name }}' |
| 23 | + properties: |
| 24 | + os_distro: '{{ os_distro }}' |
| 25 | + os_version: '{{ os_version }}' |
| 26 | + register: _distro_images |
| 27 | + |
| 28 | + - name: 'First choice: Match os_purpose' |
| 29 | + set_fact: |
| 30 | + _primary_images: >- |
| 31 | + {{ |
| 32 | + _distro_images.images |
| 33 | + | selectattr('properties.os_purpose', 'defined') |
| 34 | + | selectattr('properties.os_purpose', 'equalto', os_purpose) |
| 35 | + | list |
| 36 | + | sort(attribute='created_at', reverse=true) |
| 37 | + | sort(attribute='name', reverse=true) |
| 38 | + }} |
| 39 | +
|
| 40 | + - name: 'Select primary image if found' |
| 41 | + set_fact: |
| 42 | + selected_image_id: '{{ _primary_images[0].id }}' |
| 43 | + selected_image_name: '{{ _primary_images[0].name }}' |
| 44 | + selected_image: '{{ _primary_images[0] }}' |
| 45 | + match_type: 'primary' |
| 46 | + when: _primary_images | length > 0 |
| 47 | + |
| 48 | + # Fallback logic - only executed if no primary match |
| 49 | + - name: "Fallback 1: Filter images without os_purpose, matching name pattern '{{ os_distro }} {{ os_version }} {{ os_purpose }}'" |
| 50 | + set_fact: |
| 51 | + _fallback1_images: >- |
| 52 | + {{ |
| 53 | + _distro_images.images |
| 54 | + | rejectattr('properties.os_purpose', 'defined') |
| 55 | + | selectattr('name', 'match', '(?i)^.*' + os_distro | regex_escape + '\\s+' + os_version | regex_escape + '\\s+' + os_purpose | regex_escape + '.*$') |
| 56 | + | list |
| 57 | + | sort(attribute='created_at', reverse=true) |
| 58 | + | sort(attribute='name', reverse=true) |
| 59 | + }} |
| 60 | + when: _primary_images | length == 0 |
| 61 | + |
| 62 | + - name: Select fallback 1 match if found |
| 63 | + set_fact: |
| 64 | + selected_image_id: '{{ _fallback1_matches[0].id }}' |
| 65 | + selected_image_name: '{{ _fallback1_matches[0].name }}' |
| 66 | + selected_image: '{{ _fallback1_matches[0] }}' |
| 67 | + match_type: 'fallback_pattern1' |
| 68 | + when: |
| 69 | + - _primary_images | length == 0 |
| 70 | + - _fallback1_images | length > 0 |
| 71 | + |
| 72 | + - name: "Fallback 2: Filter images without os_purpose, matching name pattern '{{ os_distro }} {{ os_purpose }} {{ os_version }}'" |
| 73 | + set_fact: |
| 74 | + _fallback2_images: >- |
| 75 | + {{ |
| 76 | + _distro_images.images |
| 77 | + | rejectattr('properties.os_purpose', 'defined') |
| 78 | + | selectattr('name', 'match', '(?i)^.*' + os_distro | regex_escape + '\\s+' + os_purpose | regex_escape + '\\s+' + os_version | regex_escape + '.*$') |
| 79 | + | list |
| 80 | + | sort(attribute='created_at', reverse=true) |
| 81 | + | sort(attribute='name', reverse=true) |
| 82 | + }} |
| 83 | + when: |
| 84 | + - _primary_images | length == 0 |
| 85 | + - _fallback1_images | default([]) | length == 0 |
| 86 | + |
| 87 | + - name: Select fallback 2 match if found |
| 88 | + set_fact: |
| 89 | + selected_image_id: '{{ _fallback2_matches[0].id }}' |
| 90 | + selected_image_name: '{{ _fallback2_matches[0].name }}' |
| 91 | + selected_image: '{{ _fallback2_matches[0] }}' |
| 92 | + match_type: 'fallback_pattern2' |
| 93 | + when: |
| 94 | + - _primary_images | length == 0 |
| 95 | + - _fallback1_images | default([]) | length == 0 |
| 96 | + - _fallback2_images | length > 0 |
| 97 | + |
| 98 | + - name: "Fallback 3: Filter images without os_purpose, matching name pattern '{{ os_distro }} {{ os_version }}'" |
| 99 | + set_fact: |
| 100 | + _fallback3_images: >- |
| 101 | + {{ |
| 102 | + _distro_images.images |
| 103 | + | rejectattr('properties.os_purpose', 'defined') |
| 104 | + | selectattr('name', 'match', '(?i)^.*' + os_distro | regex_escape + '\\s+' + os_version | regex_escape + '.*$') |
| 105 | + | list |
| 106 | + | sort(attribute='created_at', reverse=true) |
| 107 | + | sort(attribute='name', reverse=true) |
| 108 | + }} |
| 109 | + when: |
| 110 | + - _primary_images | length == 0 |
| 111 | + - _fallback1_images | default([]) | length == 0 |
| 112 | + - _fallback2_images | default([]) | length == 0 |
| 113 | + |
| 114 | + - name: Select fallback 3 match if found |
| 115 | + set_fact: |
| 116 | + selected_image_id: '{{ _fallback3_matches[0].id }}' |
| 117 | + selected_image_name: '{{ _fallback3_matches[0].name }}' |
| 118 | + selected_image: '{{ _fallback3_matches[0] }}' |
| 119 | + match_type: 'fallback_pattern3' |
| 120 | + when: |
| 121 | + - _primary_images | length == 0 |
| 122 | + - _fallback1_images | default([]) | length == 0 |
| 123 | + - _fallback2_images | default([]) | length == 0 |
| 124 | + - _fallback3_images | length > 0 |
| 125 | + |
| 126 | + - name: Display selected image |
| 127 | + debug: |
| 128 | + msg: |
| 129 | + - 'Match Type: {{ match_type }}' |
| 130 | + - 'Image Name: {{ selected_image_name }}' |
| 131 | + - 'Image ID: {{ selected_image_id }}' |
| 132 | + - 'Created: {{ selected_image.created_at }}' |
| 133 | + - 'Properties: {{ selected_image.properties }}' |
| 134 | + when: selected_image is defined |
| 135 | + |
| 136 | + - name: Fail if no suitable image found |
| 137 | + fail: |
| 138 | + msg: | |
| 139 | + No suitable image found matching criteria: |
| 140 | + - os_distro: {{ os_distro }} |
| 141 | + - os_version: {{ os_version }} |
| 142 | + - os_purpose: {{ os_purpose }} |
| 143 | +
|
| 144 | + Tried: |
| 145 | + 1. Images with os_purpose property = '{{ os_purpose }}' |
| 146 | + 2. Images matching name pattern '{{ os_distro }} {{ os_version }} {{ os_purpose }}' |
| 147 | + 3. Images matching name pattern '{{ os_distro }} {{ os_purpose }} {{ os_version }}' |
| 148 | + 4. Images matching name pattern '{{ os_distro }} {{ os_version }}' |
| 149 | + when: selected_image is not defined |
0 commit comments