Skip to content

Commit e5e7b52

Browse files
committed
Merge branch 'feat/add-iaas-image-selection' into staging
2 parents c695bf4 + 517337b commit e5e7b52

File tree

2 files changed

+120
-96
lines changed

2 files changed

+120
-96
lines changed

user-docs/usage-hints/find-image/find_img.yaml

Lines changed: 86 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
os_version: '24.04'
1515
os_distro: 'ubuntu'
1616
os_purpose: 'generic'
17-
cloud_name: "{{ lookup('env', 'OS_CLOUD'} | default('openstack') }}"
17+
cloud_name: "{{ lookup('env', 'OS_CLOUD') | default('openstack') }}"
1818

1919
tasks:
2020
- name: Get available images matching os_distro and os_version
@@ -25,6 +25,10 @@
2525
os_version: '{{ os_version }}'
2626
register: _distro_images
2727

28+
- name: 'Show images that match {{os_distro}} {{os_version}}'
29+
debug:
30+
msg: '{{ _distro_images.images | to_nice_json }}'
31+
2832
- name: 'First choice: Match os_purpose'
2933
set_fact:
3034
_primary_images: >-
@@ -33,102 +37,110 @@
3337
| selectattr('properties.os_purpose', 'defined')
3438
| selectattr('properties.os_purpose', 'equalto', os_purpose)
3539
| list
36-
| sort(attribute='created_at', reverse=true)
37-
| sort(attribute='name', reverse=true)
3840
}}
3941
4042
- name: 'Select primary image if found'
4143
set_fact:
42-
selected_image_id: '{{ _primary_images[0].id }}'
43-
selected_image_name: '{{ _primary_images[0].name }}'
44-
selected_image: '{{ _primary_images[0] }}'
44+
selected_image: >-
45+
{{
46+
_primary_images
47+
| sort(attribute='created_at', reverse=true)
48+
| sort(attribute='name', reverse=true)
49+
| first
50+
}}
4551
match_type: 'primary'
4652
when: _primary_images | length > 0
4753

4854
# 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-
}}
55+
- block:
56+
- name: 'Fallback 1 pattern'
57+
set_fact:
58+
_pattern1: "(?i){{ os_distro | regex_escape }}\\s+{{ os_version | regex_escape }}\\s+{{ os_purpose | regex_escape }}.*"
59+
- name: "Fallback 1: Filter images without os_purpose, matching name pattern '{{ os_distro }} {{ os_version }} {{ os_purpose }}'"
60+
set_fact:
61+
_fallback1_images: >-
62+
{{
63+
_distro_images.images
64+
| rejectattr('properties.os_purpose', 'defined')
65+
| selectattr('name', 'search', _pattern1)
66+
| list
67+
}}
68+
- name: Select fallback 1 match if found
69+
set_fact:
70+
selected_image: >-
71+
{{
72+
_fallback1_images
73+
| sort(attribute='created_at', reverse=true)
74+
| sort(attribute='name', reverse=true)
75+
| first
76+
}}
77+
match_type: 'fallback_pattern1'
78+
when: _fallback1_images | length > 0
6079
when: _primary_images | length == 0
6180

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-
}}
81+
- block:
82+
- name: 'Fallback 2 pattern'
83+
set_fact:
84+
_pattern2: "(?i){{ os_distro | regex_escape }}\\s+{{ os_purpose | regex_escape }}\\s+{{ os_version | regex_escape }}.*"
85+
- name: "Fallback 2: Filter images without os_purpose, matching name pattern '{{ os_distro }} {{ os_purpose }} {{ os_version }}'"
86+
set_fact:
87+
_fallback2_images: >-
88+
{{
89+
_distro_images.images
90+
| rejectattr('properties.os_purpose', 'defined')
91+
| selectattr('name', 'search', _pattern2)
92+
| list
93+
}}
94+
- name: Select fallback 2 match if found
95+
set_fact:
96+
selected_image: >-
97+
{{
98+
_fallback2_images
99+
| sort(attribute='created_at', reverse=true)
100+
| sort(attribute='name', reverse=true)
101+
| first
102+
}}
103+
match_type: 'fallback_pattern2'
104+
when: _fallback2_images | length > 0
83105
when:
84106
- _primary_images | length == 0
85107
- _fallback1_images | default([]) | length == 0
86108

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'
109+
- block:
110+
- name: 'Fallback 3 pattern'
111+
set_fact:
112+
_pattern3: "(?i){{ os_distro | regex_escape }}\\s+{{ os_version | regex_escape }}.*"
113+
- name: "Fallback 3: Filter images without os_purpose, matching name pattern '{{ os_distro }} {{ os_version }}'"
114+
set_fact:
115+
_fallback3_images: >-
116+
{{
117+
_distro_images.images
118+
| rejectattr('properties.os_purpose', 'defined')
119+
| selectattr('name', 'search', _pattern3)
120+
| list
121+
}}
122+
- name: Select fallback 3 match if found
123+
set_fact:
124+
selected_image: >-
125+
{{
126+
_fallback3_images
127+
| sort(attribute='created_at', reverse=true)
128+
| sort(attribute='name', reverse=true)
129+
| first
130+
}}
131+
match_type: 'fallback_pattern3'
132+
when: _fallback3_images | length > 0
120133
when:
121134
- _primary_images | length == 0
122135
- _fallback1_images | default([]) | length == 0
123136
- _fallback2_images | default([]) | length == 0
124-
- _fallback3_images | length > 0
125137

126138
- name: Display selected image
127139
debug:
128140
msg:
129141
- 'Match Type: {{ match_type }}'
130-
- 'Image Name: {{ selected_image_name }}'
131-
- 'Image ID: {{ selected_image_id }}'
142+
- 'Image Name: {{ selected_image.name }}'
143+
- 'Image ID: {{ selected_image.id }}'
132144
- 'Created: {{ selected_image.created_at }}'
133145
- 'Properties: {{ selected_image.properties }}'
134146
when: selected_image is defined

user-docs/usage-hints/find-image/index.md

Lines changed: 34 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -205,31 +205,43 @@ and call `openstack stack create --parameter image=$ID $TEMPLATE $STACKNAME`.
205205
Finding the right image in ansible can be done with a task that matches the properties
206206
in a straight forward way.
207207

208-
<!--TODO: The ansible stuff needs testing -->
209-
210208
```yaml
211-
tasks:
212-
- name: Get available images matching os_distro and os_version
213-
openstack.cloud.image_info:
214-
cloud: '{{ cloud_name }}'
215-
properties:
216-
os_distro: '{{ os_distro }}'
217-
os_version: '{{ os_version }}'
218-
os_purpose: '{{ os_purpose }}'
219-
register: _distro_purpose_images
220-
- name: Select image with proper multi-key sort (single task)
221-
set_fact:
222-
selected_image: >-
223-
{{
224-
(_distro_purpose_images.images
225-
| list
226-
| sort(attribute='created_at', reverse=true)
227-
| sort(attribute='name', reverse=true))[0]
228-
| first
229-
}}
209+
---
210+
- name: Select Image with purpose
211+
hosts: localhost
212+
gather_facts: false
213+
vars:
214+
# Primary selection criteria
215+
os_version: '24.04'
216+
os_distro: 'ubuntu'
217+
os_purpose: 'generic'
218+
cloud_name: "{{ lookup('env', 'OS_CLOUD') | default('openstack') }}"
219+
220+
tasks:
221+
- name: Get available images matching os_distro and os_version and os_purpose
222+
openstack.cloud.image_info:
223+
cloud: '{{ cloud_name }}'
224+
properties:
225+
os_distro: '{{ os_distro }}'
226+
os_version: '{{ os_version }}'
227+
register: _distro_images
228+
- name: Select image with proper multi-key sort (single task)
229+
set_fact:
230+
selected_image: >-
231+
{{
232+
_distro_images.images
233+
| selectattr('properties.os_purpose', 'defined')
234+
| selectattr('properties.os_purpose', 'equalto', os_purpose)
235+
| list
236+
| sort(attribute='created_at', reverse=true)
237+
| sort(attribute='name', reverse=true)
238+
| first
239+
}}
230240
```
231241
232242
The fallback to name matching (for older clouds not yet complying to scs-0102-v2)
233243
can be done in ansible, but gets a bit complex. Find the ansible tasks in
234244
[find_img.yaml](find_img.yaml).
235-
Full disclosure: This has been produced with the help of Claude AI.
245+
So, while ansible YAML proves to be more expressive than HCL here, the by far
246+
simplest code is the python implementation.
247+
Full disclosure: The ansible YAML has been produced with the help of Claude AI.

0 commit comments

Comments
 (0)