Skip to content

Commit 39a8de6

Browse files
committed
review changes
1 parent 7ccc5c9 commit 39a8de6

File tree

6 files changed

+209
-99
lines changed

6 files changed

+209
-99
lines changed

docs/data-sources/image.md

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,14 @@ data "stackit_image" "name_match" {
2424
}
2525
2626
data "stackit_image" "name_regex_latest" {
27-
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
28-
name_regex = "^Ubuntu .*"
29-
sort_descending = true
27+
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
28+
name_regex = "^Ubuntu .*"
3029
}
3130
3231
data "stackit_image" "name_regex_oldest" {
33-
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
34-
name_regex = "^Ubuntu .*"
35-
sort_descending = false
32+
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
33+
name_regex = "^Ubuntu .*"
34+
sort_ascending = true
3635
}
3736
3837
data "stackit_image" "filter_distro_version" {
@@ -55,9 +54,9 @@ data "stackit_image" "filter_distro_version" {
5554

5655
- `filter` (Attributes) Additional filtering options based on image properties. Can be used independently or in conjunction with `name` or `name_regex`. (see [below for nested schema](#nestedatt--filter))
5756
- `image_id` (String) Image ID to fetch directly
58-
- `name` (String) Exact image name to match. Optionally applies a `filter` block to further refine results in case multiple images share the same name. The first match is returned, optionally sorted by name in descending order. Cannot be used together with `name_regex`.
59-
- `name_regex` (String) Regular expression to match against image names. Optionally applies a `filter` block to narrow down results when multiple image names match the regex. The first match is returned, optionally sorted by name in descending order. Cannot be used together with `name`.
60-
- `sort_descending` (Boolean) If set to `true`, images are sorted in descending lexicographical order by image name before selecting the first match. Defaults to `false` (ascending).
57+
- `name` (String) Exact image name to match. Optionally applies a `filter` block to further refine results in case multiple images share the same name. The first match is returned, optionally sorted by name in ascending order. Cannot be used together with `name_regex`.
58+
- `name_regex` (String) Regular expression to match against image names. Optionally applies a `filter` block to narrow down results when multiple image names match the regex. The first match is returned, optionally sorted by name in ascending order. Cannot be used together with `name`.
59+
- `sort_ascending` (Boolean) If set to `true`, images are sorted in ascending lexicographical order by image name (such as `Ubuntu 18.04`, `Ubuntu 20.04`, `Ubuntu 22.04`) before selecting the first match. Defaults to `false` (descending such as `Ubuntu 22.04`, `Ubuntu 20.04`, `Ubuntu 18.04`).
6160

6261
### Read-Only
6362

examples/data-sources/stackit_image/data-source.tf

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,14 @@ data "stackit_image" "name_match" {
99
}
1010

1111
data "stackit_image" "name_regex_latest" {
12-
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
13-
name_regex = "^Ubuntu .*"
14-
sort_descending = true
12+
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
13+
name_regex = "^Ubuntu .*"
1514
}
1615

1716
data "stackit_image" "name_regex_oldest" {
18-
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
19-
name_regex = "^Ubuntu .*"
20-
sort_descending = false
17+
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
18+
name_regex = "^Ubuntu .*"
19+
sort_ascending = true
2120
}
2221

2322
data "stackit_image" "filter_distro_version" {

stackit/internal/services/iaas/iaas_acc_test.go

Lines changed: 49 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3332,46 +3332,29 @@ func TestAccImageMin(t *testing.T) {
33323332
Config: fmt.Sprintf(`
33333333
%s
33343334
%s
3335-
3336-
data "stackit_image" "image_id_match" {
3335+
3336+
data "stackit_image" "image" {
33373337
project_id = stackit_image.image.project_id
33383338
image_id = stackit_image.image.image_id
33393339
}
3340-
3341-
data "stackit_image" "exact_match" {
3342-
project_id = var.project_id
3343-
name = "Ubuntu 22.04"
3344-
}
3345-
3346-
data "stackit_image" "ubuntu_latest" {
3347-
project_id = stackit_image.image.project_id
3348-
name_regex = "^Ubuntu .*"
3349-
sort_descending = true
3350-
}
3351-
3352-
data "stackit_image" "ubuntu_oldest" {
3353-
project_id = stackit_image.image.project_id
3354-
name_regex = "^Ubuntu .*"
3355-
sort_descending = false
3356-
}
33573340
`,
33583341
resourceImageMinConfig, testutil.IaaSProviderConfig(),
33593342
),
33603343
Check: resource.ComposeAggregateTestCheckFunc(
33613344
// Instance
3362-
resource.TestCheckResourceAttr("data.stackit_image.image_id_match", "project_id", testutil.ConvertConfigVariable(testConfigImageVarsMin["project_id"])),
3363-
resource.TestCheckResourceAttrPair("data.stackit_image.image_id_match", "image_id", "stackit_image.image", "image_id"),
3364-
resource.TestCheckResourceAttrPair("data.stackit_image.image_id_match", "name", "stackit_image.image", "name"),
3365-
resource.TestCheckResourceAttrPair("data.stackit_image.image_id_match", "disk_format", "stackit_image.image", "disk_format"),
3366-
resource.TestCheckResourceAttrPair("data.stackit_image.image_id_match", "min_disk_size", "stackit_image.image", "min_disk_size"),
3367-
resource.TestCheckResourceAttrPair("data.stackit_image.image_id_match", "min_ram", "stackit_image.image", "min_ram"),
3368-
resource.TestCheckResourceAttrPair("data.stackit_image.image_id_match", "protected", "stackit_image.image", "protected"),
3369-
resource.TestCheckResourceAttrSet("data.stackit_image.image_id_match", "protected"),
3370-
resource.TestCheckResourceAttrSet("data.stackit_image.image_id_match", "scope"),
3371-
resource.TestCheckResourceAttrSet("data.stackit_image.image_id_match", "checksum.algorithm"),
3372-
resource.TestCheckResourceAttrSet("data.stackit_image.image_id_match", "checksum.digest"),
3373-
resource.TestCheckResourceAttrSet("data.stackit_image.image_id_match", "checksum.algorithm"),
3374-
resource.TestCheckResourceAttrSet("data.stackit_image.image_id_match", "checksum.digest"),
3345+
resource.TestCheckResourceAttr("data.stackit_image.image", "project_id", testutil.ConvertConfigVariable(testConfigImageVarsMin["project_id"])),
3346+
resource.TestCheckResourceAttrPair("data.stackit_image.image", "image_id", "stackit_image.image", "image_id"),
3347+
resource.TestCheckResourceAttrPair("data.stackit_image.image", "name", "stackit_image.image", "name"),
3348+
resource.TestCheckResourceAttrPair("data.stackit_image.image", "disk_format", "stackit_image.image", "disk_format"),
3349+
resource.TestCheckResourceAttrPair("data.stackit_image.image", "min_disk_size", "stackit_image.image", "min_disk_size"),
3350+
resource.TestCheckResourceAttrPair("data.stackit_image.image", "min_ram", "stackit_image.image", "min_ram"),
3351+
resource.TestCheckResourceAttrPair("data.stackit_image.image", "protected", "stackit_image.image", "protected"),
3352+
resource.TestCheckResourceAttrSet("data.stackit_image.image", "protected"),
3353+
resource.TestCheckResourceAttrSet("data.stackit_image.image", "scope"),
3354+
resource.TestCheckResourceAttrSet("data.stackit_image.image", "checksum.algorithm"),
3355+
resource.TestCheckResourceAttrSet("data.stackit_image.image", "checksum.digest"),
3356+
resource.TestCheckResourceAttrSet("data.stackit_image.image", "checksum.algorithm"),
3357+
resource.TestCheckResourceAttrSet("data.stackit_image.image", "checksum.digest"),
33753358
),
33763359
},
33773360
// Import
@@ -3582,6 +3565,16 @@ func TestAccImageDatasourceSearchVariants(t *testing.T) {
35823565
resource.TestCheckResourceAttrSet("data.stackit_image.name_match_ubuntu_22_04", "checksum.algorithm"),
35833566
resource.TestCheckResourceAttrSet("data.stackit_image.name_match_ubuntu_22_04", "checksum.digest"),
35843567

3568+
resource.TestCheckResourceAttr("data.stackit_image.ubuntu_by_image_id", "project_id", testutil.ConvertConfigVariable(testConfigImageVarsMax["project_id"])),
3569+
resource.TestCheckResourceAttrSet("data.stackit_image.ubuntu_by_image_id", "image_id"),
3570+
resource.TestCheckResourceAttrSet("data.stackit_image.ubuntu_by_image_id", "name"),
3571+
resource.TestCheckResourceAttrSet("data.stackit_image.ubuntu_by_image_id", "min_disk_size"),
3572+
resource.TestCheckResourceAttrSet("data.stackit_image.ubuntu_by_image_id", "min_ram"),
3573+
resource.TestCheckResourceAttrSet("data.stackit_image.ubuntu_by_image_id", "protected"),
3574+
resource.TestCheckResourceAttrSet("data.stackit_image.ubuntu_by_image_id", "scope"),
3575+
resource.TestCheckResourceAttrSet("data.stackit_image.ubuntu_by_image_id", "checksum.algorithm"),
3576+
resource.TestCheckResourceAttrSet("data.stackit_image.ubuntu_by_image_id", "checksum.digest"),
3577+
35853578
resource.TestCheckResourceAttr("data.stackit_image.regex_match_ubuntu_22_04", "project_id", testutil.ConvertConfigVariable(testConfigImageVarsMax["project_id"])),
35863579
resource.TestCheckResourceAttrSet("data.stackit_image.regex_match_ubuntu_22_04", "image_id"),
35873580
resource.TestCheckResourceAttrSet("data.stackit_image.regex_match_ubuntu_22_04", "name"),
@@ -3650,7 +3643,30 @@ func TestAccImageDatasourceSearchVariants(t *testing.T) {
36503643
resource.TestCheckResourceAttrSet("data.stackit_image.ubuntu_arm64_oldest", "protected"),
36513644
resource.TestCheckResourceAttrSet("data.stackit_image.ubuntu_arm64_oldest", "scope"),
36523645
resource.TestCheckResourceAttrSet("data.stackit_image.ubuntu_arm64_oldest", "checksum.algorithm"),
3653-
resource.TestCheckResourceAttrSet("data.stackit_image.ubuntu_arm64_oldest", "checksum.digest")),
3646+
resource.TestCheckResourceAttrSet("data.stackit_image.ubuntu_arm64_oldest", "checksum.digest"),
3647+
3648+
// e2e test that ascending sort is working
3649+
func(s *terraform.State) error {
3650+
latest := s.RootModule().Resources["data.stackit_image.ubuntu_arm64_latest"]
3651+
oldest := s.RootModule().Resources["data.stackit_image.ubuntu_arm64_oldest"]
3652+
3653+
if latest == nil {
3654+
return fmt.Errorf("datasource 'data.stackit_image.ubuntu_arm64_latest' not found")
3655+
}
3656+
if oldest == nil {
3657+
return fmt.Errorf("datasource 'data.stackit_image.ubuntu_arm64_oldest' not found")
3658+
}
3659+
3660+
nameLatest := latest.Primary.Attributes["name"]
3661+
nameOldest := oldest.Primary.Attributes["name"]
3662+
3663+
if nameLatest == nameOldest {
3664+
return fmt.Errorf("expected image names to differ, but both are %q", nameLatest)
3665+
}
3666+
3667+
return nil
3668+
},
3669+
),
36543670
},
36553671
},
36563672
})

stackit/internal/services/iaas/image/datasource.go

Lines changed: 56 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,13 @@ var (
3434
)
3535

3636
type DataSourceModel struct {
37-
Id types.String `tfsdk:"id"` // needed by TF
38-
ProjectId types.String `tfsdk:"project_id"`
39-
ImageId types.String `tfsdk:"image_id"`
40-
Name types.String `tfsdk:"name"`
41-
NameRegex types.String `tfsdk:"name_regex"`
42-
SortDescending types.Bool `tfsdk:"sort_descending"`
43-
Filter types.Object `tfsdk:"filter"`
37+
Id types.String `tfsdk:"id"` // needed by TF
38+
ProjectId types.String `tfsdk:"project_id"`
39+
ImageId types.String `tfsdk:"image_id"`
40+
Name types.String `tfsdk:"name"`
41+
NameRegex types.String `tfsdk:"name_regex"`
42+
SortAscending types.Bool `tfsdk:"sort_ascending"`
43+
Filter types.Object `tfsdk:"filter"`
4444

4545
DiskFormat types.String `tfsdk:"disk_format"`
4646
MinDiskSize types.Int64 `tfsdk:"min_disk_size"`
@@ -133,15 +133,15 @@ func (d *imageDataSource) Schema(_ context.Context, _ datasource.SchemaRequest,
133133
},
134134
},
135135
"name": schema.StringAttribute{
136-
Description: "Exact image name to match. Optionally applies a `filter` block to further refine results in case multiple images share the same name. The first match is returned, optionally sorted by name in descending order. Cannot be used together with `name_regex`.",
136+
Description: "Exact image name to match. Optionally applies a `filter` block to further refine results in case multiple images share the same name. The first match is returned, optionally sorted by name in ascending order. Cannot be used together with `name_regex`.",
137137
Optional: true,
138138
},
139139
"name_regex": schema.StringAttribute{
140-
Description: "Regular expression to match against image names. Optionally applies a `filter` block to narrow down results when multiple image names match the regex. The first match is returned, optionally sorted by name in descending order. Cannot be used together with `name`.",
140+
Description: "Regular expression to match against image names. Optionally applies a `filter` block to narrow down results when multiple image names match the regex. The first match is returned, optionally sorted by name in ascending order. Cannot be used together with `name`.",
141141
Optional: true,
142142
},
143-
"sort_descending": schema.BoolAttribute{
144-
Description: "If set to `true`, images are sorted in descending lexicographical order by image name before selecting the first match. Defaults to `false` (ascending).",
143+
"sort_ascending": schema.BoolAttribute{
144+
Description: "If set to `true`, images are sorted in ascending lexicographical order by image name (such as `Ubuntu 18.04`, `Ubuntu 20.04`, `Ubuntu 22.04`) before selecting the first match. Defaults to `false` (descending such as `Ubuntu 22.04`, `Ubuntu 20.04`, `Ubuntu 18.04`).",
145145
Optional: true,
146146
},
147147
"filter": schema.SingleNestedAttribute{
@@ -284,7 +284,7 @@ func (d *imageDataSource) Read(ctx context.Context, req datasource.ReadRequest,
284284
imageID := model.ImageId.ValueString()
285285
name := model.Name.ValueString()
286286
nameRegex := model.NameRegex.ValueString()
287-
sortDescending := model.SortDescending.ValueBool()
287+
sortAscending := model.SortAscending.ValueBool()
288288

289289
var filter Filter
290290
if !model.Filter.IsNull() && !model.Filter.IsUnknown() {
@@ -298,7 +298,7 @@ func (d *imageDataSource) Read(ctx context.Context, req datasource.ReadRequest,
298298
ctx = tflog.SetField(ctx, "image_id", imageID)
299299
ctx = tflog.SetField(ctx, "name", name)
300300
ctx = tflog.SetField(ctx, "name_regex", nameRegex)
301-
ctx = tflog.SetField(ctx, "sort_descending", sortDescending)
301+
ctx = tflog.SetField(ctx, "sort_ascending", sortAscending)
302302

303303
var imageResp *iaas.Image
304304
var err error
@@ -350,21 +350,9 @@ func (d *imageDataSource) Read(ctx context.Context, req datasource.ReadRequest,
350350
}
351351
}
352352

353-
// Step 2: Sort matched images by name (optional, based on sortDescending flag)
353+
// Step 2: Sort matched images by name (optional, based on sortAscending flag)
354354
if len(matchedImages) > 1 {
355-
sort.SliceStable(matchedImages, func(i, j int) bool {
356-
a, b := matchedImages[i].Name, matchedImages[j].Name
357-
if a == nil {
358-
return false
359-
}
360-
if b == nil {
361-
return true
362-
}
363-
if sortDescending {
364-
return *a > *b
365-
}
366-
return *a < *b
367-
})
355+
sortImagesByName(matchedImages, sortAscending)
368356
}
369357

370358
// Step 3: Apply additional filtering based on OS, distro, version, UEFI, secure boot, etc.
@@ -517,37 +505,56 @@ func imageMatchesFilter(img *iaas.Image, filter *Filter) bool {
517505

518506
cfg := img.Config
519507

520-
if !filter.OS.IsNull() {
521-
if cfg.OperatingSystem == nil || filter.OS.ValueString() != *cfg.OperatingSystem {
522-
return false
523-
}
508+
if !filter.OS.IsNull() &&
509+
(cfg.OperatingSystem == nil || filter.OS.ValueString() != *cfg.OperatingSystem) {
510+
return false
524511
}
525512

526-
if !filter.Distro.IsNull() {
527-
if cfg.OperatingSystemDistro == nil || cfg.OperatingSystemDistro.Get() == nil ||
528-
filter.Distro.ValueString() != *cfg.OperatingSystemDistro.Get() {
529-
return false
530-
}
513+
if !filter.Distro.IsNull() &&
514+
(cfg.OperatingSystemDistro == nil || cfg.OperatingSystemDistro.Get() == nil ||
515+
filter.Distro.ValueString() != *cfg.OperatingSystemDistro.Get()) {
516+
return false
531517
}
532518

533-
if !filter.Version.IsNull() {
534-
if cfg.OperatingSystemVersion == nil || cfg.OperatingSystemVersion.Get() == nil ||
535-
filter.Version.ValueString() != *cfg.OperatingSystemVersion.Get() {
536-
return false
537-
}
519+
if !filter.Version.IsNull() &&
520+
(cfg.OperatingSystemVersion == nil || cfg.OperatingSystemVersion.Get() == nil ||
521+
filter.Version.ValueString() != *cfg.OperatingSystemVersion.Get()) {
522+
return false
538523
}
539524

540-
if !filter.UEFI.IsNull() {
541-
if cfg.Uefi == nil || filter.UEFI.ValueBool() != *cfg.Uefi {
542-
return false
543-
}
525+
if !filter.UEFI.IsNull() &&
526+
(cfg.Uefi == nil || filter.UEFI.ValueBool() != *cfg.Uefi) {
527+
return false
544528
}
545529

546-
if !filter.SecureBoot.IsNull() {
547-
if cfg.SecureBoot == nil || filter.SecureBoot.ValueBool() != *cfg.SecureBoot {
548-
return false
549-
}
530+
if !filter.SecureBoot.IsNull() &&
531+
(cfg.SecureBoot == nil || filter.SecureBoot.ValueBool() != *cfg.SecureBoot) {
532+
return false
550533
}
551534

552535
return true
553536
}
537+
538+
// sortImagesByName sorts a slice of images by name, respecting nils and order direction.
539+
func sortImagesByName(images []*iaas.Image, sortAscending bool) {
540+
if len(images) <= 1 {
541+
return
542+
}
543+
544+
sort.SliceStable(images, func(i, j int) bool {
545+
a, b := images[i].Name, images[j].Name
546+
547+
switch {
548+
case a == nil && b == nil:
549+
return false // Equal
550+
case a == nil:
551+
return false // Nil goes after non-nil
552+
case b == nil:
553+
return true // Non-nil goes before nil
554+
case sortAscending:
555+
return *a < *b
556+
default:
557+
return *a > *b
558+
}
559+
})
560+
}

0 commit comments

Comments
 (0)