Skip to content

Commit 9ac92b7

Browse files
authored
Feat/implement advanced image search options (#967)
* feat: implement advanced search options for images Signed-off-by: Mauritz Uphoff <mauritz.uphoff@stackit.cloud> * review changes Signed-off-by: Mauritz Uphoff <mauritz.uphoff@stackit.cloud> --------- Signed-off-by: Mauritz Uphoff <mauritz.uphoff@stackit.cloud>
1 parent 01fb599 commit 9ac92b7

File tree

8 files changed

+1471
-5
lines changed

8 files changed

+1471
-5
lines changed

docs/data-sources/image_v2.md

Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
---
2+
# generated by https://github.com/hashicorp/terraform-plugin-docs
3+
page_title: "stackit_image_v2 Data Source - stackit"
4+
subcategory: ""
5+
description: |-
6+
Image datasource schema. Must have a region specified in the provider configuration.
7+
~> Important: When using the name, name_regex, or filter attributes to select images dynamically, be aware that image IDs may change frequently. Each OS patch or update results in a new unique image ID. If this data source is used to populate fields like boot_volume.source_id in a server resource, it may cause Terraform to detect changes and recreate the associated resource.
8+
To avoid unintended updates or resource replacements:
9+
Prefer using a static image_id to pin a specific image version.If you accept automatic image updates but wish to suppress resource changes, use a lifecycle block to ignore relevant changes. For example:
10+
11+
resource "stackit_server" "example" {
12+
boot_volume = {
13+
size = 64
14+
source_type = "image"
15+
source_id = data.stackit_image.latest.id
16+
}
17+
18+
lifecycle {
19+
ignore_changes = [boot_volume[0].source_id]
20+
}
21+
}
22+
23+
~> This datasource is in beta and may be subject to breaking changes in the future. Use with caution. See our guide https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/guides/opting_into_beta_resources for how to opt-in to use beta resources.
24+
---
25+
26+
# stackit_image_v2 (Data Source)
27+
28+
Image datasource schema. Must have a `region` specified in the provider configuration.
29+
30+
~> Important: When using the `name`, `name_regex`, or `filter` attributes to select images dynamically, be aware that image IDs may change frequently. Each OS patch or update results in a new unique image ID. If this data source is used to populate fields like `boot_volume.source_id` in a server resource, it may cause Terraform to detect changes and recreate the associated resource.
31+
32+
To avoid unintended updates or resource replacements:
33+
- Prefer using a static `image_id` to pin a specific image version.
34+
- If you accept automatic image updates but wish to suppress resource changes, use a `lifecycle` block to ignore relevant changes. For example:
35+
36+
```hcl
37+
resource "stackit_server" "example" {
38+
boot_volume = {
39+
size = 64
40+
source_type = "image"
41+
source_id = data.stackit_image.latest.id
42+
}
43+
44+
lifecycle {
45+
ignore_changes = [boot_volume[0].source_id]
46+
}
47+
}
48+
```
49+
50+
~> This datasource is in beta and may be subject to breaking changes in the future. Use with caution. See our [guide](https://registry.terraform.io/providers/stackitcloud/stackit/latest/docs/guides/opting_into_beta_resources) for how to opt-in to use beta resources.
51+
52+
## Example Usage
53+
54+
```terraform
55+
data "stackit_image_v2" "default" {
56+
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
57+
image_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
58+
}
59+
60+
data "stackit_image_v2" "name_match" {
61+
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
62+
name = "Ubuntu 22.04"
63+
}
64+
65+
data "stackit_image_v2" "name_regex_latest" {
66+
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
67+
name_regex = "^Ubuntu .*"
68+
}
69+
70+
data "stackit_image_v2" "name_regex_oldest" {
71+
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
72+
name_regex = "^Ubuntu .*"
73+
sort_ascending = true
74+
}
75+
76+
data "stackit_image_v2" "filter_distro_version" {
77+
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
78+
filter = {
79+
distro = "debian"
80+
version = "11"
81+
}
82+
}
83+
```
84+
85+
<!-- schema generated by tfplugindocs -->
86+
## Schema
87+
88+
### Required
89+
90+
- `project_id` (String) STACKIT project ID to which the image is associated.
91+
92+
### Optional
93+
94+
- `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))
95+
- `image_id` (String) Image ID to fetch directly
96+
- `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`.
97+
- `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`.
98+
- `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`).
99+
100+
### Read-Only
101+
102+
- `checksum` (Attributes) Representation of an image checksum. (see [below for nested schema](#nestedatt--checksum))
103+
- `config` (Attributes) Properties to set hardware and scheduling settings for an image. (see [below for nested schema](#nestedatt--config))
104+
- `disk_format` (String) The disk format of the image.
105+
- `id` (String) Terraform's internal resource ID. It is structured as "`project_id`,`image_id`".
106+
- `labels` (Map of String) Labels are key-value string pairs which can be attached to a resource container
107+
- `min_disk_size` (Number) The minimum disk size of the image in GB.
108+
- `min_ram` (Number) The minimum RAM of the image in MB.
109+
- `protected` (Boolean) Whether the image is protected.
110+
- `scope` (String) The scope of the image.
111+
112+
<a id="nestedatt--filter"></a>
113+
### Nested Schema for `filter`
114+
115+
Optional:
116+
117+
- `distro` (String) Filter images by operating system distribution. For example: `ubuntu`, `ubuntu-arm64`, `debian`, `rhel`, etc.
118+
- `os` (String) Filter images by operating system type, such as `linux` or `windows`.
119+
- `secure_boot` (Boolean) Filter images with Secure Boot support. Set to `true` to match images that support Secure Boot.
120+
- `uefi` (Boolean) Filter images based on UEFI support. Set to `true` to match images that support UEFI.
121+
- `version` (String) Filter images by OS distribution version, such as `22.04`, `11`, or `9.1`.
122+
123+
124+
<a id="nestedatt--checksum"></a>
125+
### Nested Schema for `checksum`
126+
127+
Read-Only:
128+
129+
- `algorithm` (String) Algorithm for the checksum of the image data.
130+
- `digest` (String) Hexdigest of the checksum of the image data.
131+
132+
133+
<a id="nestedatt--config"></a>
134+
### Nested Schema for `config`
135+
136+
Read-Only:
137+
138+
- `boot_menu` (Boolean) Enables the BIOS bootmenu.
139+
- `cdrom_bus` (String) Sets CDROM bus controller type.
140+
- `disk_bus` (String) Sets Disk bus controller type.
141+
- `nic_model` (String) Sets virtual network interface model.
142+
- `operating_system` (String) Enables operating system specific optimizations.
143+
- `operating_system_distro` (String) Operating system distribution.
144+
- `operating_system_version` (String) Version of the operating system.
145+
- `rescue_bus` (String) Sets the device bus when the image is used as a rescue image.
146+
- `rescue_device` (String) Sets the device when the image is used as a rescue image.
147+
- `secure_boot` (Boolean) Enables Secure Boot.
148+
- `uefi` (Boolean) Enables UEFI boot.
149+
- `video_model` (String) Sets Graphic device model.
150+
- `virtio_scsi` (Boolean) Enables the use of VirtIO SCSI to provide block device access. By default instances use VirtIO Block.
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
data "stackit_image_v2" "default" {
2+
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
3+
image_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
4+
}
5+
6+
data "stackit_image_v2" "name_match" {
7+
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
8+
name = "Ubuntu 22.04"
9+
}
10+
11+
data "stackit_image_v2" "name_regex_latest" {
12+
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
13+
name_regex = "^Ubuntu .*"
14+
}
15+
16+
data "stackit_image_v2" "name_regex_oldest" {
17+
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
18+
name_regex = "^Ubuntu .*"
19+
sort_ascending = true
20+
}
21+
22+
data "stackit_image_v2" "filter_distro_version" {
23+
project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
24+
filter = {
25+
distro = "debian"
26+
version = "11"
27+
}
28+
}

stackit/internal/services/iaas/iaas_acc_test.go

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,9 @@ var (
3535
//go:embed testdata/resource-security-group-max.tf
3636
resourceSecurityGroupMaxConfig string
3737

38+
//go:embed testdata/datasource-image-v2-variants.tf
39+
dataSourceImageVariants string
40+
3841
//go:embed testdata/resource-image-min.tf
3942
resourceImageMinConfig string
4043

@@ -4029,6 +4032,133 @@ func TestAccImageMax(t *testing.T) {
40294032
})
40304033
}
40314034

4035+
func TestAccImageV2DatasourceSearchVariants(t *testing.T) {
4036+
t.Log("TestDataSource Image V2 Variants")
4037+
resource.ParallelTest(t, resource.TestCase{
4038+
ProtoV6ProviderFactories: testutil.TestAccProtoV6ProviderFactories,
4039+
Steps: []resource.TestStep{
4040+
// Creation
4041+
{
4042+
ConfigVariables: config.Variables{"project_id": config.StringVariable(testutil.ProjectId)},
4043+
Config: fmt.Sprintf("%s\n%s", dataSourceImageVariants, testutil.IaaSProviderConfigWithBetaResourcesEnabled()),
4044+
Check: resource.ComposeAggregateTestCheckFunc(
4045+
resource.TestCheckResourceAttr("data.stackit_image_v2.name_match_ubuntu_22_04", "project_id", testutil.ConvertConfigVariable(testConfigImageVarsMax["project_id"])),
4046+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.name_match_ubuntu_22_04", "image_id"),
4047+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.name_match_ubuntu_22_04", "name"),
4048+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.name_match_ubuntu_22_04", "min_disk_size"),
4049+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.name_match_ubuntu_22_04", "min_ram"),
4050+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.name_match_ubuntu_22_04", "protected"),
4051+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.name_match_ubuntu_22_04", "scope"),
4052+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.name_match_ubuntu_22_04", "checksum.algorithm"),
4053+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.name_match_ubuntu_22_04", "checksum.digest"),
4054+
4055+
resource.TestCheckResourceAttr("data.stackit_image_v2.ubuntu_by_image_id", "project_id", testutil.ConvertConfigVariable(testConfigImageVarsMax["project_id"])),
4056+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.ubuntu_by_image_id", "image_id"),
4057+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.ubuntu_by_image_id", "name"),
4058+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.ubuntu_by_image_id", "min_disk_size"),
4059+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.ubuntu_by_image_id", "min_ram"),
4060+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.ubuntu_by_image_id", "protected"),
4061+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.ubuntu_by_image_id", "scope"),
4062+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.ubuntu_by_image_id", "checksum.algorithm"),
4063+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.ubuntu_by_image_id", "checksum.digest"),
4064+
4065+
resource.TestCheckResourceAttr("data.stackit_image_v2.regex_match_ubuntu_22_04", "project_id", testutil.ConvertConfigVariable(testConfigImageVarsMax["project_id"])),
4066+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.regex_match_ubuntu_22_04", "image_id"),
4067+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.regex_match_ubuntu_22_04", "name"),
4068+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.regex_match_ubuntu_22_04", "min_disk_size"),
4069+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.regex_match_ubuntu_22_04", "min_ram"),
4070+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.regex_match_ubuntu_22_04", "protected"),
4071+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.regex_match_ubuntu_22_04", "scope"),
4072+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.regex_match_ubuntu_22_04", "checksum.algorithm"),
4073+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.regex_match_ubuntu_22_04", "checksum.digest"),
4074+
4075+
resource.TestCheckResourceAttr("data.stackit_image_v2.filter_debian_11", "project_id", testutil.ConvertConfigVariable(testConfigImageVarsMax["project_id"])),
4076+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.filter_debian_11", "image_id"),
4077+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.filter_debian_11", "name"),
4078+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.filter_debian_11", "min_disk_size"),
4079+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.filter_debian_11", "min_ram"),
4080+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.filter_debian_11", "protected"),
4081+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.filter_debian_11", "scope"),
4082+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.filter_debian_11", "checksum.algorithm"),
4083+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.filter_debian_11", "checksum.digest"),
4084+
4085+
resource.TestCheckResourceAttr("data.stackit_image_v2.filter_uefi_ubuntu", "project_id", testutil.ConvertConfigVariable(testConfigImageVarsMax["project_id"])),
4086+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.filter_uefi_ubuntu", "image_id"),
4087+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.filter_uefi_ubuntu", "name"),
4088+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.filter_uefi_ubuntu", "min_disk_size"),
4089+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.filter_uefi_ubuntu", "min_ram"),
4090+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.filter_uefi_ubuntu", "protected"),
4091+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.filter_uefi_ubuntu", "scope"),
4092+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.filter_uefi_ubuntu", "checksum.algorithm"),
4093+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.filter_uefi_ubuntu", "checksum.digest"),
4094+
4095+
resource.TestCheckResourceAttr("data.stackit_image_v2.name_regex_and_filter_rhel_9_1", "project_id", testutil.ConvertConfigVariable(testConfigImageVarsMax["project_id"])),
4096+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.name_regex_and_filter_rhel_9_1", "image_id"),
4097+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.name_regex_and_filter_rhel_9_1", "name"),
4098+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.name_regex_and_filter_rhel_9_1", "min_disk_size"),
4099+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.name_regex_and_filter_rhel_9_1", "min_ram"),
4100+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.name_regex_and_filter_rhel_9_1", "protected"),
4101+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.name_regex_and_filter_rhel_9_1", "scope"),
4102+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.name_regex_and_filter_rhel_9_1", "checksum.algorithm"),
4103+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.name_regex_and_filter_rhel_9_1", "checksum.digest"),
4104+
4105+
resource.TestCheckResourceAttr("data.stackit_image_v2.name_windows_2022_standard", "project_id", testutil.ConvertConfigVariable(testConfigImageVarsMax["project_id"])),
4106+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.name_windows_2022_standard", "image_id"),
4107+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.name_windows_2022_standard", "name"),
4108+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.name_windows_2022_standard", "min_disk_size"),
4109+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.name_windows_2022_standard", "min_ram"),
4110+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.name_windows_2022_standard", "protected"),
4111+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.name_windows_2022_standard", "scope"),
4112+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.name_windows_2022_standard", "checksum.algorithm"),
4113+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.name_windows_2022_standard", "checksum.digest"),
4114+
4115+
resource.TestCheckResourceAttr("data.stackit_image_v2.ubuntu_arm64_latest", "project_id", testutil.ConvertConfigVariable(testConfigImageVarsMax["project_id"])),
4116+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.ubuntu_arm64_latest", "image_id"),
4117+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.ubuntu_arm64_latest", "name"),
4118+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.ubuntu_arm64_latest", "min_disk_size"),
4119+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.ubuntu_arm64_latest", "min_ram"),
4120+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.ubuntu_arm64_latest", "protected"),
4121+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.ubuntu_arm64_latest", "scope"),
4122+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.ubuntu_arm64_latest", "checksum.algorithm"),
4123+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.ubuntu_arm64_latest", "checksum.digest"),
4124+
4125+
resource.TestCheckResourceAttr("data.stackit_image_v2.ubuntu_arm64_oldest", "project_id", testutil.ConvertConfigVariable(testConfigImageVarsMax["project_id"])),
4126+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.ubuntu_arm64_oldest", "image_id"),
4127+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.ubuntu_arm64_oldest", "name"),
4128+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.ubuntu_arm64_oldest", "min_disk_size"),
4129+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.ubuntu_arm64_oldest", "min_ram"),
4130+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.ubuntu_arm64_oldest", "protected"),
4131+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.ubuntu_arm64_oldest", "scope"),
4132+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.ubuntu_arm64_oldest", "checksum.algorithm"),
4133+
resource.TestCheckResourceAttrSet("data.stackit_image_v2.ubuntu_arm64_oldest", "checksum.digest"),
4134+
4135+
// e2e test that ascending sort is working
4136+
func(s *terraform.State) error {
4137+
latest := s.RootModule().Resources["data.stackit_image_v2.ubuntu_arm64_latest"]
4138+
oldest := s.RootModule().Resources["data.stackit_image_v2.ubuntu_arm64_oldest"]
4139+
4140+
if latest == nil {
4141+
return fmt.Errorf("datasource 'data.stackit_image_v2.ubuntu_arm64_latest' not found")
4142+
}
4143+
if oldest == nil {
4144+
return fmt.Errorf("datasource 'data.stackit_image_v2.ubuntu_arm64_oldest' not found")
4145+
}
4146+
4147+
nameLatest := latest.Primary.Attributes["name"]
4148+
nameOldest := oldest.Primary.Attributes["name"]
4149+
4150+
if nameLatest == nameOldest {
4151+
return fmt.Errorf("expected image names to differ, but both are %q", nameLatest)
4152+
}
4153+
4154+
return nil
4155+
},
4156+
),
4157+
},
4158+
},
4159+
})
4160+
}
4161+
40324162
func TestAccProject(t *testing.T) {
40334163
projectId := testutil.ProjectId
40344164
resource.ParallelTest(t, resource.TestCase{

0 commit comments

Comments
 (0)