Skip to content

Commit fb11d0f

Browse files
committed
Merge branch 'feat/add-iaas-image-selection' into staging
2 parents 2e920bb + f65f027 commit fb11d0f

File tree

5 files changed

+152
-12
lines changed

5 files changed

+152
-12
lines changed

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
#
77
# (c) Kurt Garloff <[email protected]>, 7/2025
88
# SPDX-License-Identifier: MIT
9-
"This module finds the a vanilla distribution image"
9+
"This module finds the a distribution image with a given purpose"
1010

1111
import os
1212
import sys

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

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#!/usr/bin/env tofu apply -auto-approve
22
# Pass variables with -var os_purpose=minimal
3+
# (c) Kurt Garloff <[email protected]>
4+
# SPDX-License-Identifier: MIT
35

46
variable "os_distro" {
57
type = string
@@ -26,17 +28,20 @@ terraform {
2628
}
2729

2830
provider "openstack" {
29-
# Your cloud config (or use environment variables OS_CLOUD)
31+
# Your cloud config (or use environment variable OS_CLOUD)
3032
}
3133

3234
data "openstack_images_image_v2" "my_image" {
3335
most_recent = true
34-
36+
3537
properties = {
36-
os_distro = "${var.os_distro}"
37-
os_version = "${var.os_version}"
38-
os_purpose = "${var.os_purpose}"
38+
os_distro = "${var.os_distro}"
39+
os_version = "${var.os_version}"
40+
os_purpose = "${var.os_purpose}"
3941
}
42+
#sort = "name:desc,created_at:desc"
43+
#sort_key = "name"
44+
#sort_direction = "desc"
4045
}
4146

4247
# Output the results for inspection
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/usr/bin/env python3
2+
#
3+
# find_img2.py
4+
#
5+
# Find images for opentofu/terraform
6+
#
7+
# (c) Kurt Garloff <[email protected]>, 11/2025
8+
# SPDX-License-Identifier: MIT
9+
"This module finds the a distribution image with a given purpose"
10+
11+
import sys
12+
import json
13+
import find_img
14+
15+
try:
16+
in_data = json.loads(sys.stdin.read())
17+
conn = find_img.openstack.connect() # cloud=os.environ["OS_CLOUD"])
18+
images = find_img.find_image(conn, in_data["os_distro"], in_data["os_version"], in_data["os_purpose"])
19+
for img in images:
20+
print(f"DEBUG: {img[0]} {img[1]}", file=sys.stderr)
21+
if not (len(images)):
22+
print(f"No image found for {in_data}", file=sys.stderr)
23+
sys.exit(1)
24+
output = { "image_id": images[0][0],
25+
"image_name": images[0][1] }
26+
print(json.dumps(output))
27+
28+
except Exception as e:
29+
print(f"Error: {str(e)}", file=sys.stderr)
30+
sys.exit(2)
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#!/usr/bin/env tofu apply -auto-approve
2+
# Pass variables with -var os_purpose=minimal
3+
# (c) Kurt Garloff <[email protected]>
4+
# SPDX-License-Identifier: MIT
5+
6+
variable "os_distro2" {
7+
type = string
8+
default = "ubuntu"
9+
}
10+
11+
variable "os_version2" {
12+
type = string
13+
default = "24.04"
14+
}
15+
16+
variable "os_purpose2" {
17+
type = string
18+
default = "generic"
19+
}
20+
21+
#terraform {
22+
# required_providers {
23+
# openstack = {
24+
# source = "terraform-provider-openstack/openstack"
25+
# version = "~> 1.54.0"
26+
# }
27+
# }
28+
#}
29+
30+
#provider "openstack" {
31+
# # Your cloud config (or use environment variables OS_CLOUD)
32+
#}
33+
34+
# Call python find_img.py to find best image
35+
data "external" "my_image2" {
36+
program = ["python3", "${path.module}/find_img2.py"]
37+
38+
query = {
39+
os_distro = "${var.os_distro2}"
40+
os_version = "${var.os_version2}"
41+
os_purpose = "${var.os_purpose2}"
42+
}
43+
}
44+
45+
# Output the results for inspection
46+
output "selected_image2" {
47+
value = {
48+
id = data.external.my_image2.result.image_id
49+
name = data.external.my_image2.result.image_name
50+
}
51+
}
52+

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

Lines changed: 59 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -125,8 +125,9 @@ data "openstack_images_image_v2" "my_image" {
125125
os_version = "24.04"
126126
os_purpose = "generic"
127127
}
128-
# sort_key = "name"
129-
# sort_direction = "desc"
128+
# sort = "name:desc,created_at:desc"
129+
# sort_key = "name"
130+
# sort_direction = "desc"
130131
}
131132
132133
# Use the selected image
@@ -138,11 +139,63 @@ resource "openstack_compute_instance_v2" "instance" {
138139

139140
This will find the most recent image wtih the `os_` variables set to `ubuntu`, `24.04`, `generic`.
140141
Note that unlike the python and shell examples, we can not easily sort for name and creation
141-
date at the same time; the name sorting is thus commented out here. To use name sorting you can
142-
enable it — using it and then selecting the latest if the name is identical requires some
143-
HCL magic using `locals` and `reverse(sort(...))` calls or calling an external program.
142+
date at the same time; the only option to deal with several matches is to tell opentofu's
143+
openstack provider to return the latest (the one with the newest `created_at` date).
144144

145145
An example can be found in [find_img.tf](find_img.tf). Call it with `tofu apply -auto-approve`
146146
(after you ran `tofu init` in this directory once).
147147

148-
The fallback to name matching is harder.
148+
The fallback to name matching for clouds that don't have `os_purpose` yet is harder.
149+
150+
We use an external program, the python script from before to select the right image and just create
151+
a little wrapper around it: [find_img2.py](find_img2.py). The HCL then looks like this:
152+
153+
```hcl
154+
# Call python find_img.py to find best image
155+
data "external" "my_image2" {
156+
program = ["python3", "${path.module}/find_img2.py"]
157+
158+
query = {
159+
os_distro = "${var.os_distro2}"
160+
os_version = "${var.os_version2}"
161+
os_purpose = "${var.os_purpose2}"
162+
}
163+
}
164+
165+
# Output the results for inspection
166+
output "selected_image2" {
167+
value = {
168+
id = data.external.my_image2.result.image_id
169+
name = data.external.my_image2.result.image_name
170+
}
171+
}
172+
```
173+
174+
Note that I have appended a `2` to the variable names, so they don't clash in case you have the
175+
original example in the same directory.
176+
177+
## heat
178+
179+
I did not find a good way to select an image based on its properties in heat.
180+
Obviously, you can use the python (or shell) script above and pass the image name
181+
or ID as a parameter when invoking heat.
182+
183+
```yaml
184+
heat_template_version: 2018-08-31
185+
186+
parameters:
187+
image:
188+
type: string
189+
description: Image ID or name
190+
constraints:
191+
- custom_constraint: glance.image
192+
193+
resources:
194+
my_instance:
195+
type: OS::Nova::Server
196+
properties:
197+
image: { get_param: image }
198+
# ... other properties
199+
```
200+
201+
and call `openstack stack create --parameter image=$ID $TEMPLATE $STACKNAME`.

0 commit comments

Comments
 (0)