Skip to content

Commit 730a3ee

Browse files
committed
review changes
1 parent ede4e85 commit 730a3ee

6 files changed

Lines changed: 209 additions & 99 deletions

File tree

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
@@ -3812,46 +3812,29 @@ func TestAccImageMin(t *testing.T) {
38123812
Config: fmt.Sprintf(`
38133813
%s
38143814
%s
3815-
3816-
data "stackit_image" "image_id_match" {
3815+
3816+
data "stackit_image" "image" {
38173817
project_id = stackit_image.image.project_id
38183818
image_id = stackit_image.image.image_id
38193819
}
3820-
3821-
data "stackit_image" "exact_match" {
3822-
project_id = var.project_id
3823-
name = "Ubuntu 22.04"
3824-
}
3825-
3826-
data "stackit_image" "ubuntu_latest" {
3827-
project_id = stackit_image.image.project_id
3828-
name_regex = "^Ubuntu .*"
3829-
sort_descending = true
3830-
}
3831-
3832-
data "stackit_image" "ubuntu_oldest" {
3833-
project_id = stackit_image.image.project_id
3834-
name_regex = "^Ubuntu .*"
3835-
sort_descending = false
3836-
}
38373820
`,
38383821
resourceImageMinConfig, testutil.IaaSProviderConfig(),
38393822
),
38403823
Check: resource.ComposeAggregateTestCheckFunc(
38413824
// Instance
3842-
resource.TestCheckResourceAttr("data.stackit_image.image_id_match", "project_id", testutil.ConvertConfigVariable(testConfigImageVarsMin["project_id"])),
3843-
resource.TestCheckResourceAttrPair("data.stackit_image.image_id_match", "image_id", "stackit_image.image", "image_id"),
3844-
resource.TestCheckResourceAttrPair("data.stackit_image.image_id_match", "name", "stackit_image.image", "name"),
3845-
resource.TestCheckResourceAttrPair("data.stackit_image.image_id_match", "disk_format", "stackit_image.image", "disk_format"),
3846-
resource.TestCheckResourceAttrPair("data.stackit_image.image_id_match", "min_disk_size", "stackit_image.image", "min_disk_size"),
3847-
resource.TestCheckResourceAttrPair("data.stackit_image.image_id_match", "min_ram", "stackit_image.image", "min_ram"),
3848-
resource.TestCheckResourceAttrPair("data.stackit_image.image_id_match", "protected", "stackit_image.image", "protected"),
3849-
resource.TestCheckResourceAttrSet("data.stackit_image.image_id_match", "protected"),
3850-
resource.TestCheckResourceAttrSet("data.stackit_image.image_id_match", "scope"),
3851-
resource.TestCheckResourceAttrSet("data.stackit_image.image_id_match", "checksum.algorithm"),
3852-
resource.TestCheckResourceAttrSet("data.stackit_image.image_id_match", "checksum.digest"),
3853-
resource.TestCheckResourceAttrSet("data.stackit_image.image_id_match", "checksum.algorithm"),
3854-
resource.TestCheckResourceAttrSet("data.stackit_image.image_id_match", "checksum.digest"),
3825+
resource.TestCheckResourceAttr("data.stackit_image.image", "project_id", testutil.ConvertConfigVariable(testConfigImageVarsMin["project_id"])),
3826+
resource.TestCheckResourceAttrPair("data.stackit_image.image", "image_id", "stackit_image.image", "image_id"),
3827+
resource.TestCheckResourceAttrPair("data.stackit_image.image", "name", "stackit_image.image", "name"),
3828+
resource.TestCheckResourceAttrPair("data.stackit_image.image", "disk_format", "stackit_image.image", "disk_format"),
3829+
resource.TestCheckResourceAttrPair("data.stackit_image.image", "min_disk_size", "stackit_image.image", "min_disk_size"),
3830+
resource.TestCheckResourceAttrPair("data.stackit_image.image", "min_ram", "stackit_image.image", "min_ram"),
3831+
resource.TestCheckResourceAttrPair("data.stackit_image.image", "protected", "stackit_image.image", "protected"),
3832+
resource.TestCheckResourceAttrSet("data.stackit_image.image", "protected"),
3833+
resource.TestCheckResourceAttrSet("data.stackit_image.image", "scope"),
3834+
resource.TestCheckResourceAttrSet("data.stackit_image.image", "checksum.algorithm"),
3835+
resource.TestCheckResourceAttrSet("data.stackit_image.image", "checksum.digest"),
3836+
resource.TestCheckResourceAttrSet("data.stackit_image.image", "checksum.algorithm"),
3837+
resource.TestCheckResourceAttrSet("data.stackit_image.image", "checksum.digest"),
38553838
),
38563839
},
38573840
// Import
@@ -4062,6 +4045,16 @@ func TestAccImageDatasourceSearchVariants(t *testing.T) {
40624045
resource.TestCheckResourceAttrSet("data.stackit_image.name_match_ubuntu_22_04", "checksum.algorithm"),
40634046
resource.TestCheckResourceAttrSet("data.stackit_image.name_match_ubuntu_22_04", "checksum.digest"),
40644047

4048+
resource.TestCheckResourceAttr("data.stackit_image.ubuntu_by_image_id", "project_id", testutil.ConvertConfigVariable(testConfigImageVarsMax["project_id"])),
4049+
resource.TestCheckResourceAttrSet("data.stackit_image.ubuntu_by_image_id", "image_id"),
4050+
resource.TestCheckResourceAttrSet("data.stackit_image.ubuntu_by_image_id", "name"),
4051+
resource.TestCheckResourceAttrSet("data.stackit_image.ubuntu_by_image_id", "min_disk_size"),
4052+
resource.TestCheckResourceAttrSet("data.stackit_image.ubuntu_by_image_id", "min_ram"),
4053+
resource.TestCheckResourceAttrSet("data.stackit_image.ubuntu_by_image_id", "protected"),
4054+
resource.TestCheckResourceAttrSet("data.stackit_image.ubuntu_by_image_id", "scope"),
4055+
resource.TestCheckResourceAttrSet("data.stackit_image.ubuntu_by_image_id", "checksum.algorithm"),
4056+
resource.TestCheckResourceAttrSet("data.stackit_image.ubuntu_by_image_id", "checksum.digest"),
4057+
40654058
resource.TestCheckResourceAttr("data.stackit_image.regex_match_ubuntu_22_04", "project_id", testutil.ConvertConfigVariable(testConfigImageVarsMax["project_id"])),
40664059
resource.TestCheckResourceAttrSet("data.stackit_image.regex_match_ubuntu_22_04", "image_id"),
40674060
resource.TestCheckResourceAttrSet("data.stackit_image.regex_match_ubuntu_22_04", "name"),
@@ -4130,7 +4123,30 @@ func TestAccImageDatasourceSearchVariants(t *testing.T) {
41304123
resource.TestCheckResourceAttrSet("data.stackit_image.ubuntu_arm64_oldest", "protected"),
41314124
resource.TestCheckResourceAttrSet("data.stackit_image.ubuntu_arm64_oldest", "scope"),
41324125
resource.TestCheckResourceAttrSet("data.stackit_image.ubuntu_arm64_oldest", "checksum.algorithm"),
4133-
resource.TestCheckResourceAttrSet("data.stackit_image.ubuntu_arm64_oldest", "checksum.digest")),
4126+
resource.TestCheckResourceAttrSet("data.stackit_image.ubuntu_arm64_oldest", "checksum.digest"),
4127+
4128+
// e2e test that ascending sort is working
4129+
func(s *terraform.State) error {
4130+
latest := s.RootModule().Resources["data.stackit_image.ubuntu_arm64_latest"]
4131+
oldest := s.RootModule().Resources["data.stackit_image.ubuntu_arm64_oldest"]
4132+
4133+
if latest == nil {
4134+
return fmt.Errorf("datasource 'data.stackit_image.ubuntu_arm64_latest' not found")
4135+
}
4136+
if oldest == nil {
4137+
return fmt.Errorf("datasource 'data.stackit_image.ubuntu_arm64_oldest' not found")
4138+
}
4139+
4140+
nameLatest := latest.Primary.Attributes["name"]
4141+
nameOldest := oldest.Primary.Attributes["name"]
4142+
4143+
if nameLatest == nameOldest {
4144+
return fmt.Errorf("expected image names to differ, but both are %q", nameLatest)
4145+
}
4146+
4147+
return nil
4148+
},
4149+
),
41344150
},
41354151
},
41364152
})

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.
@@ -511,37 +499,56 @@ func imageMatchesFilter(img *iaas.Image, filter *Filter) bool {
511499

512500
cfg := img.Config
513501

514-
if !filter.OS.IsNull() {
515-
if cfg.OperatingSystem == nil || filter.OS.ValueString() != *cfg.OperatingSystem {
516-
return false
517-
}
502+
if !filter.OS.IsNull() &&
503+
(cfg.OperatingSystem == nil || filter.OS.ValueString() != *cfg.OperatingSystem) {
504+
return false
518505
}
519506

520-
if !filter.Distro.IsNull() {
521-
if cfg.OperatingSystemDistro == nil || cfg.OperatingSystemDistro.Get() == nil ||
522-
filter.Distro.ValueString() != *cfg.OperatingSystemDistro.Get() {
523-
return false
524-
}
507+
if !filter.Distro.IsNull() &&
508+
(cfg.OperatingSystemDistro == nil || cfg.OperatingSystemDistro.Get() == nil ||
509+
filter.Distro.ValueString() != *cfg.OperatingSystemDistro.Get()) {
510+
return false
525511
}
526512

527-
if !filter.Version.IsNull() {
528-
if cfg.OperatingSystemVersion == nil || cfg.OperatingSystemVersion.Get() == nil ||
529-
filter.Version.ValueString() != *cfg.OperatingSystemVersion.Get() {
530-
return false
531-
}
513+
if !filter.Version.IsNull() &&
514+
(cfg.OperatingSystemVersion == nil || cfg.OperatingSystemVersion.Get() == nil ||
515+
filter.Version.ValueString() != *cfg.OperatingSystemVersion.Get()) {
516+
return false
532517
}
533518

534-
if !filter.UEFI.IsNull() {
535-
if cfg.Uefi == nil || filter.UEFI.ValueBool() != *cfg.Uefi {
536-
return false
537-
}
519+
if !filter.UEFI.IsNull() &&
520+
(cfg.Uefi == nil || filter.UEFI.ValueBool() != *cfg.Uefi) {
521+
return false
538522
}
539523

540-
if !filter.SecureBoot.IsNull() {
541-
if cfg.SecureBoot == nil || filter.SecureBoot.ValueBool() != *cfg.SecureBoot {
542-
return false
543-
}
524+
if !filter.SecureBoot.IsNull() &&
525+
(cfg.SecureBoot == nil || filter.SecureBoot.ValueBool() != *cfg.SecureBoot) {
526+
return false
544527
}
545528

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

0 commit comments

Comments
 (0)