diff --git a/docs/data-sources/ske_kubernetes_versions.md b/docs/data-sources/ske_kubernetes_versions.md
new file mode 100644
index 000000000..c64bab2aa
--- /dev/null
+++ b/docs/data-sources/ske_kubernetes_versions.md
@@ -0,0 +1,60 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "stackit_ske_kubernetes_versions Data Source - stackit"
+subcategory: ""
+description: |-
+ Returns Kubernetes versions as reported by the SKE provider options API for the given region.
+---
+
+# stackit_ske_kubernetes_versions (Data Source)
+
+Returns Kubernetes versions as reported by the SKE provider options API for the given region.
+
+## Example Usage
+
+```terraform
+data "stackit_ske_kubernetes_versions" "example" {
+ version_state = "SUPPORTED"
+}
+
+resource "stackit_ske_cluster" "example" {
+ project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
+ name = "example"
+ kubernetes_version = data.stackit_ske_kubernetes_versions.example.kubernetes_versions.0.version
+ node_pools = [
+ {
+ name = "np-example"
+ machine_type = "x.x"
+ os_version = "x.x.x"
+ os_name = "xxx"
+ minimum = "2"
+ maximum = "3"
+ availability_zones = ["eu01-1"]
+ volume_type = "storage_premium_perf6"
+ volume_size = "48"
+ }
+ ]
+}
+```
+
+
+## Schema
+
+### Optional
+
+- `region` (String) Region override. If omitted, the provider’s region will be used.
+- `version_state` (String) If specified, only returns Kubernetes versions with this version state. Possible values are: `UNSPECIFIED`, `SUPPORTED`.
+
+### Read-Only
+
+- `kubernetes_versions` (Attributes List) Kubernetes versions and their metadata. (see [below for nested schema](#nestedatt--kubernetes_versions))
+
+
+### Nested Schema for `kubernetes_versions`
+
+Read-Only:
+
+- `expiration_date` (String) Expiration date of the version in RFC3339 format.
+- `feature_gates` (Map of String) Map of available feature gates for this version.
+- `state` (String) State of the kubernetes version.
+- `version` (String) Kubernetes version string (e.g., `1.33.6`).
diff --git a/docs/data-sources/ske_machine_image_versions.md b/docs/data-sources/ske_machine_image_versions.md
new file mode 100644
index 000000000..eaab52642
--- /dev/null
+++ b/docs/data-sources/ske_machine_image_versions.md
@@ -0,0 +1,78 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "stackit_ske_machine_image_versions Data Source - stackit"
+subcategory: ""
+description: |-
+ Returns a list of supported Kubernetes machine image versions for the cluster nodes.
+---
+
+# stackit_ske_machine_image_versions (Data Source)
+
+Returns a list of supported Kubernetes machine image versions for the cluster nodes.
+
+## Example Usage
+
+```terraform
+data "stackit_ske_machine_image_versions" "example" {
+ version_state = "SUPPORTED"
+}
+
+locals {
+ flatcar_supported_version = one(flatten([
+ for mi in data.stackit_ske_machine_image_versions.example.machine_images : [
+ for v in mi.versions :
+ v.version
+ if mi.name == "flatcar" # or ubuntu
+ ]
+ ]))
+}
+
+resource "stackit_ske_cluster" "example" {
+ project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
+ name = "example"
+ kubernetes_version = "x.x"
+ node_pools = [
+ {
+ name = "np-example"
+ machine_type = "x.x"
+ os_version = local.flatcar_supported_version
+ os_name = "flatcar"
+ minimum = "2"
+ maximum = "3"
+ availability_zones = ["eu01-1"]
+ volume_type = "storage_premium_perf6"
+ volume_size = "48"
+ }
+ ]
+}
+```
+
+
+## Schema
+
+### Optional
+
+- `region` (String) Region override. If omitted, the provider’s region will be used.
+- `version_state` (String) Filter returned machine image versions by their state. Possible values are: `UNSPECIFIED`, `SUPPORTED`.
+
+### Read-Only
+
+- `machine_images` (Attributes List) Supported machine image types and versions. (see [below for nested schema](#nestedatt--machine_images))
+
+
+### Nested Schema for `machine_images`
+
+Read-Only:
+
+- `name` (String) Name of the OS image (e.g., `ubuntu` or `flatcar`).
+- `versions` (Attributes List) Supported versions of the image. (see [below for nested schema](#nestedatt--machine_images--versions))
+
+
+### Nested Schema for `machine_images.versions`
+
+Read-Only:
+
+- `cri` (List of String) Container runtimes supported (e.g., `containerd`).
+- `expiration_date` (String) Expiration date of the version in RFC3339 format.
+- `state` (String) State of the image version.
+- `version` (String) Machine image version string.
diff --git a/docs/resources/ske_cluster.md b/docs/resources/ske_cluster.md
index b8b681405..44616c9be 100644
--- a/docs/resources/ske_cluster.md
+++ b/docs/resources/ske_cluster.md
@@ -25,9 +25,12 @@ resource "stackit_ske_cluster" "example" {
name = "np-example"
machine_type = "x.x"
os_version = "x.x.x"
+ os_name = "xxx"
minimum = "2"
maximum = "3"
availability_zones = ["eu01-3"]
+ volume_type = "storage_premium_perf6"
+ volume_size = "48"
}
]
maintenance = {
diff --git a/examples/data-sources/stackit_ske_kubernetes_versions/data-source.tf b/examples/data-sources/stackit_ske_kubernetes_versions/data-source.tf
new file mode 100644
index 000000000..28d306e99
--- /dev/null
+++ b/examples/data-sources/stackit_ske_kubernetes_versions/data-source.tf
@@ -0,0 +1,22 @@
+data "stackit_ske_kubernetes_versions" "example" {
+ version_state = "SUPPORTED"
+}
+
+resource "stackit_ske_cluster" "example" {
+ project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
+ name = "example"
+ kubernetes_version = data.stackit_ske_kubernetes_versions.example.kubernetes_versions.0.version
+ node_pools = [
+ {
+ name = "np-example"
+ machine_type = "x.x"
+ os_version = "x.x.x"
+ os_name = "xxx"
+ minimum = "2"
+ maximum = "3"
+ availability_zones = ["eu01-1"]
+ volume_type = "storage_premium_perf6"
+ volume_size = "48"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/examples/data-sources/stackit_ske_machine_image_versions/data-source.tf b/examples/data-sources/stackit_ske_machine_image_versions/data-source.tf
new file mode 100644
index 000000000..c4238496d
--- /dev/null
+++ b/examples/data-sources/stackit_ske_machine_image_versions/data-source.tf
@@ -0,0 +1,32 @@
+data "stackit_ske_machine_image_versions" "example" {
+ version_state = "SUPPORTED"
+}
+
+locals {
+ flatcar_supported_version = one(flatten([
+ for mi in data.stackit_ske_machine_image_versions.example.machine_images : [
+ for v in mi.versions :
+ v.version
+ if mi.name == "flatcar" # or ubuntu
+ ]
+ ]))
+}
+
+resource "stackit_ske_cluster" "example" {
+ project_id = "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx"
+ name = "example"
+ kubernetes_version = "x.x"
+ node_pools = [
+ {
+ name = "np-example"
+ machine_type = "x.x"
+ os_version = local.flatcar_supported_version
+ os_name = "flatcar"
+ minimum = "2"
+ maximum = "3"
+ availability_zones = ["eu01-1"]
+ volume_type = "storage_premium_perf6"
+ volume_size = "48"
+ }
+ ]
+}
\ No newline at end of file
diff --git a/examples/resources/stackit_ske_cluster/resource.tf b/examples/resources/stackit_ske_cluster/resource.tf
index cabf801ac..e87958fd2 100644
--- a/examples/resources/stackit_ske_cluster/resource.tf
+++ b/examples/resources/stackit_ske_cluster/resource.tf
@@ -7,9 +7,12 @@ resource "stackit_ske_cluster" "example" {
name = "np-example"
machine_type = "x.x"
os_version = "x.x.x"
+ os_name = "xxx"
minimum = "2"
maximum = "3"
availability_zones = ["eu01-3"]
+ volume_type = "storage_premium_perf6"
+ volume_size = "48"
}
]
maintenance = {
diff --git a/stackit/internal/services/ske/provideroptions/kubernetesversions/datasource.go b/stackit/internal/services/ske/provideroptions/kubernetesversions/datasource.go
new file mode 100644
index 000000000..a4ea5a848
--- /dev/null
+++ b/stackit/internal/services/ske/provideroptions/kubernetesversions/datasource.go
@@ -0,0 +1,239 @@
+package kubernetesversions
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+ "time"
+
+ "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
+ "github.com/hashicorp/terraform-plugin-framework/attr"
+ "github.com/hashicorp/terraform-plugin-framework/datasource"
+ "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/schema/validator"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+ "github.com/hashicorp/terraform-plugin-log/tflog"
+ "github.com/stackitcloud/stackit-sdk-go/services/ske"
+ "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/conversion"
+ "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
+ skeUtils "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/ske/utils"
+ "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
+)
+
+// Model types
+type Model struct {
+ Region types.String `tfsdk:"region"`
+ VersionState types.String `tfsdk:"version_state"`
+ KubernetesVersions types.List `tfsdk:"kubernetes_versions"`
+}
+
+var (
+ kubernetesVersionType = map[string]attr.Type{
+ "version": types.StringType,
+ "expiration_date": types.StringType,
+ "feature_gates": types.MapType{ElemType: types.StringType},
+ "state": types.StringType,
+ }
+
+ versionStateOptions = []string{"UNSPECIFIED", "SUPPORTED"}
+)
+
+// Ensure implementation satisfies interface
+var _ datasource.DataSource = &kubernetesVersionsDataSource{}
+
+// NewKubernetesVersionsDataSource creates the data source instance
+func NewKubernetesVersionsDataSource() datasource.DataSource {
+ return &kubernetesVersionsDataSource{}
+}
+
+type kubernetesVersionsDataSource struct {
+ client *ske.APIClient
+ providerData core.ProviderData
+}
+
+// Metadata sets the data source type name
+func (d *kubernetesVersionsDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
+ resp.TypeName = req.ProviderTypeName + "_ske_kubernetes_versions"
+}
+
+func (d *kubernetesVersionsDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
+ var ok bool
+ d.providerData, ok = conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics)
+ if !ok {
+ return
+ }
+
+ d.client = skeUtils.ConfigureClient(ctx, &d.providerData, &resp.Diagnostics)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ tflog.Info(ctx, "SKE options client configured")
+}
+
+func (d *kubernetesVersionsDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
+ description := "Returns Kubernetes versions as reported by the SKE provider options API for the given region."
+
+ resp.Schema = schema.Schema{
+ Description: description,
+ Attributes: map[string]schema.Attribute{
+ "region": schema.StringAttribute{
+ Optional: true,
+ Description: "Region override. If omitted, the provider’s region will be used.",
+ },
+ "version_state": schema.StringAttribute{
+ Optional: true,
+ Description: "If specified, only returns Kubernetes versions with this version state. " + utils.FormatPossibleValues(versionStateOptions...),
+ Validators: []validator.String{
+ stringvalidator.OneOf(versionStateOptions...),
+ },
+ },
+ "kubernetes_versions": schema.ListNestedAttribute{
+ Computed: true,
+ Description: "Kubernetes versions and their metadata.",
+ NestedObject: schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "version": schema.StringAttribute{
+ Computed: true,
+ Description: "Kubernetes version string (e.g., `1.33.6`).",
+ },
+ "expiration_date": schema.StringAttribute{
+ Computed: true,
+ Description: "Expiration date of the version in RFC3339 format.",
+ },
+ "state": schema.StringAttribute{
+ Computed: true,
+ Description: "State of the kubernetes version.",
+ },
+ "feature_gates": schema.MapAttribute{
+ Computed: true,
+ ElementType: types.StringType,
+ Description: "Map of available feature gates for this version.",
+ },
+ },
+ },
+ },
+ },
+ }
+}
+
+// Read refreshes the Terraform state with the latest data.
+func (d *kubernetesVersionsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { // nolint:gocritic // function signature required by Terraform
+ var model Model
+ diags := req.Config.Get(ctx, &model)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ region := d.providerData.GetRegionWithOverride(model.Region)
+
+ ctx = core.InitProviderContext(ctx)
+ ctx = tflog.SetField(ctx, "region", region)
+
+ listProviderOptionsReq := d.client.ListProviderOptions(ctx, region)
+
+ if !utils.IsUndefined(model.VersionState) {
+ listProviderOptionsReq = listProviderOptionsReq.VersionState(model.VersionState.ValueString())
+ }
+
+ optionsResp, err := listProviderOptionsReq.Execute()
+ if err != nil {
+ utils.LogError(
+ ctx,
+ &resp.Diagnostics,
+ err,
+ "Reading SKE provider options failed",
+ "Unable to read SKE provider options",
+ map[int]string{
+ http.StatusForbidden: "Forbidden access",
+ },
+ )
+ return
+ }
+
+ if err := mapFields(ctx, optionsResp, &model); err != nil {
+ core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading provider options", fmt.Sprintf("Mapping API payload: %v", err))
+ return
+ }
+
+ diags = resp.State.Set(ctx, model)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ tflog.Info(ctx, "Read SKE provider options successfully", map[string]interface{}{
+ "region": region,
+ "versionState": model.VersionState.ValueString(),
+ })
+}
+
+func mapFields(_ context.Context, optionsResp *ske.ProviderOptions, model *Model) error {
+ if optionsResp == nil {
+ return fmt.Errorf("response input is nil")
+ }
+ if model == nil {
+ return fmt.Errorf("model input is nil")
+ }
+
+ if optionsResp.KubernetesVersions == nil {
+ emptyList, diags := types.ListValue(
+ types.ObjectType{AttrTypes: kubernetesVersionType},
+ []attr.Value{},
+ )
+ if diags.HasError() {
+ return core.DiagsToError(diags)
+ }
+ model.KubernetesVersions = emptyList
+ return nil
+ }
+
+ kvSlice := *optionsResp.KubernetesVersions
+ kvList := make([]attr.Value, 0, len(kvSlice))
+
+ for _, kv := range kvSlice {
+ expDate := types.StringNull()
+ if kv.ExpirationDate != nil {
+ expDate = types.StringValue(kv.ExpirationDate.Format(time.RFC3339))
+ }
+
+ featureGateValues := map[string]attr.Value{}
+ if kv.FeatureGates != nil {
+ for k, v := range *kv.FeatureGates {
+ featureGateValues[k] = types.StringValue(v)
+ }
+ }
+
+ featureGatesMap, diags := types.MapValue(types.StringType, featureGateValues)
+ if diags.HasError() {
+ return core.DiagsToError(diags)
+ }
+
+ obj, diags := types.ObjectValue(
+ kubernetesVersionType,
+ map[string]attr.Value{
+ "version": types.StringPointerValue(kv.Version),
+ "state": types.StringPointerValue(kv.State),
+ "expiration_date": expDate,
+ "feature_gates": featureGatesMap,
+ },
+ )
+ if diags.HasError() {
+ return core.DiagsToError(diags)
+ }
+
+ kvList = append(kvList, obj)
+ }
+
+ kvs, diags := types.ListValue(
+ types.ObjectType{AttrTypes: kubernetesVersionType},
+ kvList,
+ )
+ if diags.HasError() {
+ return core.DiagsToError(diags)
+ }
+ model.KubernetesVersions = kvs
+
+ return nil
+}
diff --git a/stackit/internal/services/ske/provideroptions/kubernetesversions/datasource_test.go b/stackit/internal/services/ske/provideroptions/kubernetesversions/datasource_test.go
new file mode 100644
index 000000000..bf7d8a482
--- /dev/null
+++ b/stackit/internal/services/ske/provideroptions/kubernetesversions/datasource_test.go
@@ -0,0 +1,304 @@
+package kubernetesversions
+
+import (
+ "context"
+ "testing"
+ "time"
+
+ "github.com/google/go-cmp/cmp"
+ "github.com/hashicorp/terraform-plugin-framework/attr"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+ skeutils "github.com/stackitcloud/stackit-sdk-go/core/utils"
+ "github.com/stackitcloud/stackit-sdk-go/services/ske"
+)
+
+func TestMapFields(t *testing.T) {
+ expDeprecated1 := time.Date(2026, 1, 28, 8, 0, 0, 0, time.UTC)
+ expDeprecated2 := time.Date(2026, 1, 14, 8, 0, 0, 0, time.UTC)
+
+ expDeprecated1Str := expDeprecated1.Format(time.RFC3339)
+ expDeprecated2Str := expDeprecated2.Format(time.RFC3339)
+
+ tests := []struct {
+ name string
+ input *ske.ProviderOptions
+ model *Model
+ expected *Model
+ isValid bool
+ }{
+ {
+ name: "nil input provider options",
+ input: nil,
+ model: &Model{},
+ expected: &Model{}, // not used, we expect an error
+ isValid: false,
+ },
+ {
+ name: "multiple versions realistic payload",
+ input: &ske.ProviderOptions{
+ KubernetesVersions: &[]ske.KubernetesVersion{
+ {
+ Version: skeutils.Ptr("1.31.14"),
+ State: skeutils.Ptr("deprecated"),
+ ExpirationDate: &expDeprecated1,
+ FeatureGates: &map[string]string{},
+ },
+ {
+ Version: skeutils.Ptr("1.32.10"),
+ State: skeutils.Ptr("deprecated"),
+ ExpirationDate: &expDeprecated2,
+ FeatureGates: &map[string]string{},
+ },
+ {
+ Version: skeutils.Ptr("1.33.6"),
+ State: skeutils.Ptr("deprecated"),
+ ExpirationDate: &expDeprecated2,
+ FeatureGates: &map[string]string{},
+ },
+ {
+ Version: skeutils.Ptr("1.34.2"),
+ State: skeutils.Ptr("deprecated"),
+ ExpirationDate: &expDeprecated2,
+ FeatureGates: &map[string]string{},
+ },
+ {
+ Version: skeutils.Ptr("1.32.11"),
+ State: skeutils.Ptr("supported"),
+ ExpirationDate: nil,
+ FeatureGates: &map[string]string{},
+ },
+ {
+ Version: skeutils.Ptr("1.33.7"),
+ State: skeutils.Ptr("supported"),
+ ExpirationDate: nil,
+ FeatureGates: &map[string]string{},
+ },
+ {
+ Version: skeutils.Ptr("1.34.3"),
+ State: skeutils.Ptr("supported"),
+ ExpirationDate: nil,
+ FeatureGates: &map[string]string{},
+ },
+ },
+ },
+ model: &Model{},
+ expected: &Model{
+ KubernetesVersions: types.ListValueMust(
+ types.ObjectType{AttrTypes: kubernetesVersionType},
+ []attr.Value{
+ types.ObjectValueMust(kubernetesVersionType, map[string]attr.Value{
+ "version": types.StringValue("1.31.14"),
+ "state": types.StringValue("deprecated"),
+ "expiration_date": types.StringValue(expDeprecated1Str),
+ "feature_gates": types.MapValueMust(
+ types.StringType,
+ map[string]attr.Value{},
+ ),
+ }),
+ types.ObjectValueMust(kubernetesVersionType, map[string]attr.Value{
+ "version": types.StringValue("1.32.10"),
+ "state": types.StringValue("deprecated"),
+ "expiration_date": types.StringValue(expDeprecated2Str),
+ "feature_gates": types.MapValueMust(
+ types.StringType,
+ map[string]attr.Value{},
+ ),
+ }),
+ types.ObjectValueMust(kubernetesVersionType, map[string]attr.Value{
+ "version": types.StringValue("1.33.6"),
+ "state": types.StringValue("deprecated"),
+ "expiration_date": types.StringValue(expDeprecated2Str),
+ "feature_gates": types.MapValueMust(
+ types.StringType,
+ map[string]attr.Value{},
+ ),
+ }),
+ types.ObjectValueMust(kubernetesVersionType, map[string]attr.Value{
+ "version": types.StringValue("1.34.2"),
+ "state": types.StringValue("deprecated"),
+ "expiration_date": types.StringValue(expDeprecated2Str),
+ "feature_gates": types.MapValueMust(
+ types.StringType,
+ map[string]attr.Value{},
+ ),
+ }),
+ types.ObjectValueMust(kubernetesVersionType, map[string]attr.Value{
+ "version": types.StringValue("1.32.11"),
+ "state": types.StringValue("supported"),
+ "expiration_date": types.StringNull(),
+ "feature_gates": types.MapValueMust(
+ types.StringType,
+ map[string]attr.Value{},
+ ),
+ }),
+ types.ObjectValueMust(kubernetesVersionType, map[string]attr.Value{
+ "version": types.StringValue("1.33.7"),
+ "state": types.StringValue("supported"),
+ "expiration_date": types.StringNull(),
+ "feature_gates": types.MapValueMust(
+ types.StringType,
+ map[string]attr.Value{},
+ ),
+ }),
+ types.ObjectValueMust(kubernetesVersionType, map[string]attr.Value{
+ "version": types.StringValue("1.34.3"),
+ "state": types.StringValue("supported"),
+ "expiration_date": types.StringNull(),
+ "feature_gates": types.MapValueMust(
+ types.StringType,
+ map[string]attr.Value{},
+ ),
+ }),
+ },
+ ),
+ },
+ isValid: true,
+ },
+ {
+ name: "mixed fields with nil feature gates and nil state",
+ input: &ske.ProviderOptions{
+ KubernetesVersions: &[]ske.KubernetesVersion{
+ {
+ Version: skeutils.Ptr("1.32.11"),
+ State: skeutils.Ptr("supported"),
+ ExpirationDate: nil,
+ FeatureGates: &map[string]string{
+ "SomeGate": "foo",
+ },
+ },
+ {
+ Version: nil,
+ State: nil,
+ ExpirationDate: nil,
+ FeatureGates: nil,
+ },
+ },
+ },
+ model: &Model{},
+ expected: &Model{
+ KubernetesVersions: types.ListValueMust(
+ types.ObjectType{AttrTypes: kubernetesVersionType},
+ []attr.Value{
+ types.ObjectValueMust(kubernetesVersionType, map[string]attr.Value{
+ "version": types.StringValue("1.32.11"),
+ "state": types.StringValue("supported"),
+ "expiration_date": types.StringNull(),
+ "feature_gates": types.MapValueMust(
+ types.StringType,
+ map[string]attr.Value{
+ "SomeGate": types.StringValue("foo"),
+ },
+ ),
+ }),
+ types.ObjectValueMust(kubernetesVersionType, map[string]attr.Value{
+ "version": types.StringNull(),
+ "state": types.StringNull(),
+ "expiration_date": types.StringNull(),
+ // nil feature gates => empty map
+ "feature_gates": types.MapValueMust(
+ types.StringType,
+ map[string]attr.Value{},
+ ),
+ }),
+ },
+ ),
+ },
+ isValid: true,
+ },
+ {
+ name: "nil kubernetes versions slice",
+ input: &ske.ProviderOptions{
+ KubernetesVersions: nil,
+ },
+ model: &Model{},
+ expected: &Model{
+ KubernetesVersions: types.ListValueMust(
+ types.ObjectType{AttrTypes: kubernetesVersionType},
+ []attr.Value{},
+ ),
+ },
+ isValid: true,
+ },
+ {
+ name: "empty kubernetes versions slice",
+ input: &ske.ProviderOptions{
+ KubernetesVersions: &[]ske.KubernetesVersion{},
+ },
+ model: &Model{},
+ expected: &Model{
+ KubernetesVersions: types.ListValueMust(
+ types.ObjectType{AttrTypes: kubernetesVersionType},
+ []attr.Value{},
+ ),
+ },
+ isValid: true,
+ },
+ {
+ name: "feature gates empty map",
+ input: &ske.ProviderOptions{
+ KubernetesVersions: &[]ske.KubernetesVersion{
+ {
+ Version: skeutils.Ptr("1.33.7"),
+ State: skeutils.Ptr("supported"),
+ ExpirationDate: nil,
+ FeatureGates: &map[string]string{},
+ },
+ },
+ },
+ model: &Model{},
+ expected: &Model{
+ KubernetesVersions: types.ListValueMust(
+ types.ObjectType{AttrTypes: kubernetesVersionType},
+ []attr.Value{
+ types.ObjectValueMust(kubernetesVersionType, map[string]attr.Value{
+ "version": types.StringValue("1.33.7"),
+ "state": types.StringValue("supported"),
+ "expiration_date": types.StringNull(),
+ // empty map from API => empty map in Terraform
+ "feature_gates": types.MapValueMust(
+ types.StringType,
+ map[string]attr.Value{},
+ ),
+ }),
+ },
+ ),
+ },
+ isValid: true,
+ },
+ {
+ name: "nil model",
+ input: &ske.ProviderOptions{
+ KubernetesVersions: &[]ske.KubernetesVersion{
+ {
+ Version: skeutils.Ptr("1.32.11"),
+ State: skeutils.Ptr("supported"),
+ ExpirationDate: nil,
+ FeatureGates: &map[string]string{},
+ },
+ },
+ },
+ model: nil,
+ expected: nil, // not used, we expect an error
+ isValid: false,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ err := mapFields(context.Background(), tt.input, tt.model)
+
+ if tt.isValid && err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if !tt.isValid && err == nil {
+ t.Fatal("expected error but got none")
+ }
+
+ if tt.isValid {
+ if diff := cmp.Diff(tt.expected, tt.model); diff != "" {
+ t.Fatalf("mismatch (-want +got):\n%s", diff)
+ }
+ }
+ })
+ }
+}
diff --git a/stackit/internal/services/ske/provideroptions/machineimages/datasource.go b/stackit/internal/services/ske/provideroptions/machineimages/datasource.go
new file mode 100644
index 000000000..a5b96c09d
--- /dev/null
+++ b/stackit/internal/services/ske/provideroptions/machineimages/datasource.go
@@ -0,0 +1,264 @@
+package machineimages
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+ "time"
+
+ "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
+ "github.com/hashicorp/terraform-plugin-framework/attr"
+ "github.com/hashicorp/terraform-plugin-framework/datasource"
+ "github.com/hashicorp/terraform-plugin-framework/datasource/schema"
+ "github.com/hashicorp/terraform-plugin-framework/schema/validator"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+ "github.com/hashicorp/terraform-plugin-log/tflog"
+ "github.com/stackitcloud/stackit-sdk-go/services/ske"
+ "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/conversion"
+ "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/core"
+ skeUtils "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/ske/utils"
+ "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/utils"
+)
+
+// Model types
+type Model struct {
+ Region types.String `tfsdk:"region"`
+ VersionState types.String `tfsdk:"version_state"`
+ MachineImages types.List `tfsdk:"machine_images"`
+}
+
+var (
+ versionStateOptions = []string{
+ "UNSPECIFIED",
+ "SUPPORTED",
+ }
+
+ machineImageVersionType = map[string]attr.Type{
+ "version": types.StringType,
+ "state": types.StringType,
+ "expiration_date": types.StringType,
+ "cri": types.ListType{ElemType: types.StringType},
+ }
+
+ machineImageType = map[string]attr.Type{
+ "name": types.StringType,
+ "versions": types.ListType{ElemType: types.ObjectType{AttrTypes: machineImageVersionType}},
+ }
+)
+
+// Ensure implementation satisfies interface
+var _ datasource.DataSource = &optionsDataSource{}
+
+// NewKubernetesMachineImageVersionDataSource creates the data source instance
+func NewKubernetesMachineImageVersionDataSource() datasource.DataSource {
+ return &optionsDataSource{}
+}
+
+type optionsDataSource struct {
+ client *ske.APIClient
+ providerData core.ProviderData
+}
+
+// Metadata sets the data source type name.
+func (d *optionsDataSource) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) {
+ resp.TypeName = req.ProviderTypeName + "_ske_machine_image_versions"
+}
+
+func (d *optionsDataSource) Configure(ctx context.Context, req datasource.ConfigureRequest, resp *datasource.ConfigureResponse) {
+ if req.ProviderData == nil {
+ return
+ }
+
+ var ok bool
+ d.providerData, ok = conversion.ParseProviderData(ctx, req.ProviderData, &resp.Diagnostics)
+ if !ok {
+ return
+ }
+
+ d.client = skeUtils.ConfigureClient(ctx, &d.providerData, &resp.Diagnostics)
+ if d.client == nil {
+ return
+ }
+
+ tflog.Info(ctx, "SKE machine image versions client configured")
+}
+
+func (d *optionsDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
+ description := "Returns a list of supported Kubernetes machine image versions for the cluster nodes."
+
+ resp.Schema = schema.Schema{
+ Description: description,
+ Attributes: map[string]schema.Attribute{
+ "region": schema.StringAttribute{
+ Optional: true,
+ Description: "Region override. If omitted, the provider’s region will be used.",
+ },
+ "version_state": schema.StringAttribute{
+ Optional: true,
+ Description: "Filter returned machine image versions by their state. " + utils.FormatPossibleValues(versionStateOptions...),
+ Validators: []validator.String{
+ stringvalidator.OneOf(versionStateOptions...),
+ },
+ },
+ "machine_images": schema.ListNestedAttribute{
+ Computed: true,
+ Description: "Supported machine image types and versions.",
+ NestedObject: schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "name": schema.StringAttribute{
+ Computed: true,
+ Description: "Name of the OS image (e.g., `ubuntu` or `flatcar`).",
+ },
+ "versions": schema.ListNestedAttribute{
+ Computed: true,
+ Description: "Supported versions of the image.",
+ NestedObject: schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "version": schema.StringAttribute{
+ Computed: true,
+ Description: "Machine image version string.",
+ },
+ "state": schema.StringAttribute{
+ Computed: true,
+ Description: "State of the image version.",
+ },
+ "expiration_date": schema.StringAttribute{
+ Computed: true,
+ Description: "Expiration date of the version in RFC3339 format.",
+ },
+ "cri": schema.ListAttribute{
+ Computed: true,
+ ElementType: types.StringType,
+ Description: "Container runtimes supported (e.g., `containerd`).",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ }
+}
+
+// Read refreshes the Terraform state with the latest data.
+func (d *optionsDataSource) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { // nolint:gocritic // function signature required by Terraform
+ var model Model
+ diags := req.Config.Get(ctx, &model)
+ resp.Diagnostics.Append(diags...)
+ if resp.Diagnostics.HasError() {
+ return
+ }
+
+ region := d.providerData.GetRegionWithOverride(model.Region)
+ ctx = core.InitProviderContext(ctx)
+ ctx = tflog.SetField(ctx, "region", region)
+
+ listProviderOptionsReq := d.client.ListProviderOptions(ctx, region)
+
+ if !utils.IsUndefined(model.VersionState) {
+ listProviderOptionsReq = listProviderOptionsReq.VersionState(model.VersionState.ValueString())
+ }
+
+ optionsResp, err := listProviderOptionsReq.Execute()
+ if err != nil {
+ utils.LogError(
+ ctx,
+ &resp.Diagnostics,
+ err,
+ "Reading SKE provider options failed",
+ "Unable to read SKE provider options",
+ map[int]string{
+ http.StatusForbidden: "Forbidden access",
+ },
+ )
+ resp.State.RemoveResource(ctx)
+ return
+ }
+
+ if err := mapFields(ctx, optionsResp, &model); err != nil {
+ core.LogAndAddError(ctx, &resp.Diagnostics, "Error reading provider options", fmt.Sprintf("Mapping API payload: %v", err))
+ return
+ }
+
+ // Set final state
+ diags = resp.State.Set(ctx, model)
+ resp.Diagnostics.Append(diags...)
+ tflog.Info(ctx, "Read SKE provider options successfully", map[string]interface{}{
+ "region": region,
+ "versionState": model.VersionState.ValueString(),
+ })
+}
+
+func mapFields(ctx context.Context, optionsResp *ske.ProviderOptions, model *Model) error {
+ if optionsResp == nil {
+ return fmt.Errorf("response input is nil")
+ }
+ if model == nil {
+ return fmt.Errorf("model input is nil")
+ }
+
+ // Machine Images
+ miList := make([]attr.Value, 0)
+ if optionsResp.MachineImages != nil {
+ for _, img := range *optionsResp.MachineImages {
+ versionsList := make([]attr.Value, 0)
+ if img.Versions != nil {
+ for _, ver := range *img.Versions {
+ // CRI list
+ criList := make([]types.String, 0)
+ if ver.Cri != nil {
+ for _, cri := range *ver.Cri {
+ if cri.Name != nil {
+ criList = append(criList, types.StringValue(string(*cri.Name.Ptr())))
+ }
+ }
+ }
+ criVal, diags := types.ListValueFrom(ctx, types.StringType, criList)
+ if diags.HasError() {
+ return core.DiagsToError(diags)
+ }
+
+ // Expiration date
+ expDate := types.StringNull()
+ if ver.ExpirationDate != nil {
+ expDate = types.StringValue(ver.ExpirationDate.Format(time.RFC3339))
+ }
+
+ versionObj, diags := types.ObjectValue(machineImageVersionType, map[string]attr.Value{
+ "version": types.StringPointerValue(ver.Version),
+ "state": types.StringPointerValue(ver.State),
+ "expiration_date": expDate,
+ "cri": criVal,
+ })
+ if diags.HasError() {
+ return core.DiagsToError(diags)
+ }
+ versionsList = append(versionsList, versionObj)
+ }
+ }
+
+ versions, diags := types.ListValue(types.ObjectType{AttrTypes: machineImageVersionType}, versionsList)
+ if diags.HasError() {
+ return core.DiagsToError(diags)
+ }
+
+ imgObj, diags := types.ObjectValue(machineImageType, map[string]attr.Value{
+ "name": types.StringPointerValue(img.Name),
+ "versions": versions,
+ })
+ if diags.HasError() {
+ return core.DiagsToError(diags)
+ }
+ miList = append(miList, imgObj)
+ }
+ }
+
+ mis, diags := types.ListValue(types.ObjectType{AttrTypes: machineImageType}, miList)
+ if diags.HasError() {
+ return core.DiagsToError(diags)
+ }
+ model.MachineImages = mis
+
+ return nil
+}
diff --git a/stackit/internal/services/ske/provideroptions/machineimages/datasource_test.go b/stackit/internal/services/ske/provideroptions/machineimages/datasource_test.go
new file mode 100644
index 000000000..385b57c2b
--- /dev/null
+++ b/stackit/internal/services/ske/provideroptions/machineimages/datasource_test.go
@@ -0,0 +1,358 @@
+package machineimages
+
+import (
+ "context"
+ "testing"
+ "time"
+
+ "github.com/google/go-cmp/cmp"
+ "github.com/hashicorp/terraform-plugin-framework/attr"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+ skeutils "github.com/stackitcloud/stackit-sdk-go/core/utils"
+ "github.com/stackitcloud/stackit-sdk-go/services/ske"
+)
+
+func TestMapFields(t *testing.T) {
+ timestamp := time.Date(2026, 1, 14, 8, 0, 0, 0, time.UTC)
+ expDate := timestamp.Format(time.RFC3339)
+
+ tests := []struct {
+ name string
+ input *ske.ProviderOptions
+ expected *Model
+ isValid bool
+ }{
+ {
+ name: "nil input provider options",
+ input: nil,
+ expected: &Model{},
+ isValid: false,
+ },
+ {
+ name: "single machine image single version full fields",
+ input: &ske.ProviderOptions{
+ MachineImages: &[]ske.MachineImage{
+ {
+ Name: skeutils.Ptr("flatcar"),
+ Versions: &[]ske.MachineImageVersion{
+ {
+ Version: skeutils.Ptr("4230.2.1"),
+ State: skeutils.Ptr("supported"),
+ ExpirationDate: ×tamp,
+ Cri: &[]ske.CRI{
+ {
+ Name: skeutils.Ptr(ske.CRINAME_CONTAINERD),
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ expected: &Model{
+ MachineImages: types.ListValueMust(
+ types.ObjectType{AttrTypes: machineImageType},
+ []attr.Value{
+ types.ObjectValueMust(machineImageType, map[string]attr.Value{
+ "name": types.StringValue("flatcar"),
+ "versions": types.ListValueMust(
+ types.ObjectType{AttrTypes: machineImageVersionType},
+ []attr.Value{
+ types.ObjectValueMust(machineImageVersionType, map[string]attr.Value{
+ "version": types.StringValue("4230.2.1"),
+ "state": types.StringValue("supported"),
+ "expiration_date": types.StringValue(expDate),
+ "cri": types.ListValueMust(
+ types.StringType,
+ []attr.Value{
+ types.StringValue(string(ske.CRINAME_CONTAINERD)),
+ },
+ ),
+ }),
+ },
+ ),
+ }),
+ },
+ ),
+ },
+ isValid: true,
+ },
+ {
+ name: "single machine image multiple versions mixed fields",
+ input: &ske.ProviderOptions{
+ MachineImages: &[]ske.MachineImage{
+ {
+ Name: skeutils.Ptr("flatcar"),
+ Versions: &[]ske.MachineImageVersion{
+ {
+ Version: skeutils.Ptr("4230.2.1"),
+ State: skeutils.Ptr("supported"),
+ ExpirationDate: ×tamp,
+ Cri: &[]ske.CRI{
+ {
+ Name: skeutils.Ptr(ske.CRINAME_CONTAINERD),
+ },
+ },
+ },
+ {
+ // nil version, nil state, no expiration date, no CRI
+ Version: nil,
+ State: nil,
+ ExpirationDate: nil,
+ Cri: nil,
+ },
+ },
+ },
+ },
+ },
+ expected: &Model{
+ MachineImages: types.ListValueMust(
+ types.ObjectType{AttrTypes: machineImageType},
+ []attr.Value{
+ types.ObjectValueMust(machineImageType, map[string]attr.Value{
+ "name": types.StringValue("flatcar"),
+ "versions": types.ListValueMust(
+ types.ObjectType{AttrTypes: machineImageVersionType},
+ []attr.Value{
+ types.ObjectValueMust(machineImageVersionType, map[string]attr.Value{
+ "version": types.StringValue("4230.2.1"),
+ "state": types.StringValue("supported"),
+ "expiration_date": types.StringValue(expDate),
+ "cri": types.ListValueMust(
+ types.StringType,
+ []attr.Value{
+ types.StringValue(string(ske.CRINAME_CONTAINERD)),
+ },
+ ),
+ }),
+ types.ObjectValueMust(machineImageVersionType, map[string]attr.Value{
+ "version": types.StringNull(),
+ "state": types.StringNull(),
+ "expiration_date": types.StringNull(),
+ // nil CRI => empty list
+ "cri": types.ListValueMust(
+ types.StringType,
+ []attr.Value{},
+ ),
+ }),
+ },
+ ),
+ }),
+ },
+ ),
+ },
+ isValid: true,
+ },
+ {
+ name: "multiple machine images mixed versions",
+ input: &ske.ProviderOptions{
+ MachineImages: &[]ske.MachineImage{
+ {
+ Name: skeutils.Ptr("flatcar"),
+ Versions: &[]ske.MachineImageVersion{
+ {
+ Version: skeutils.Ptr("4230.2.1"),
+ State: skeutils.Ptr("deprecated"),
+ ExpirationDate: ×tamp,
+ Cri: &[]ske.CRI{
+ {
+ Name: skeutils.Ptr(ske.CRINAME_CONTAINERD),
+ },
+ },
+ },
+ {
+ Version: skeutils.Ptr("4230.2.3"),
+ State: skeutils.Ptr("supported"),
+ ExpirationDate: nil, // no expiration
+ Cri: &[]ske.CRI{
+ {
+ Name: skeutils.Ptr(ske.CRINAME_CONTAINERD),
+ },
+ },
+ },
+ {
+ Version: skeutils.Ptr("4459.2.1"),
+ State: skeutils.Ptr("preview"),
+ ExpirationDate: nil,
+ Cri: &[]ske.CRI{
+ {
+ Name: skeutils.Ptr(ske.CRINAME_CONTAINERD),
+ },
+ },
+ },
+ },
+ },
+ {
+ Name: skeutils.Ptr("ubuntu"),
+ Versions: &[]ske.MachineImageVersion{
+ {
+ Version: skeutils.Ptr("2204.20250728.0"),
+ State: skeutils.Ptr("supported"),
+ ExpirationDate: nil,
+ // empty CRI slice
+ Cri: &[]ske.CRI{},
+ },
+ },
+ },
+ },
+ },
+ expected: &Model{
+ MachineImages: types.ListValueMust(
+ types.ObjectType{AttrTypes: machineImageType},
+ []attr.Value{
+ types.ObjectValueMust(machineImageType, map[string]attr.Value{
+ "name": types.StringValue("flatcar"),
+ "versions": types.ListValueMust(
+ types.ObjectType{AttrTypes: machineImageVersionType},
+ []attr.Value{
+ types.ObjectValueMust(machineImageVersionType, map[string]attr.Value{
+ "version": types.StringValue("4230.2.1"),
+ "state": types.StringValue("deprecated"),
+ "expiration_date": types.StringValue(expDate),
+ "cri": types.ListValueMust(
+ types.StringType,
+ []attr.Value{
+ types.StringValue(string(ske.CRINAME_CONTAINERD)),
+ },
+ ),
+ }),
+ types.ObjectValueMust(machineImageVersionType, map[string]attr.Value{
+ "version": types.StringValue("4230.2.3"),
+ "state": types.StringValue("supported"),
+ "expiration_date": types.StringNull(),
+ "cri": types.ListValueMust(
+ types.StringType,
+ []attr.Value{
+ types.StringValue(string(ske.CRINAME_CONTAINERD)),
+ },
+ ),
+ }),
+ types.ObjectValueMust(machineImageVersionType, map[string]attr.Value{
+ "version": types.StringValue("4459.2.1"),
+ "state": types.StringValue("preview"),
+ "expiration_date": types.StringNull(),
+ "cri": types.ListValueMust(
+ types.StringType,
+ []attr.Value{
+ types.StringValue(string(ske.CRINAME_CONTAINERD)),
+ },
+ ),
+ }),
+ },
+ ),
+ }),
+ types.ObjectValueMust(machineImageType, map[string]attr.Value{
+ "name": types.StringValue("ubuntu"),
+ "versions": types.ListValueMust(
+ types.ObjectType{AttrTypes: machineImageVersionType},
+ []attr.Value{
+ types.ObjectValueMust(machineImageVersionType, map[string]attr.Value{
+ "version": types.StringValue("2204.20250728.0"),
+ "state": types.StringValue("supported"),
+ "expiration_date": types.StringNull(),
+ // empty CRI slice => empty list
+ "cri": types.ListValueMust(
+ types.StringType,
+ []attr.Value{},
+ ),
+ }),
+ },
+ ),
+ }),
+ },
+ ),
+ },
+ isValid: true,
+ },
+ {
+ name: "nil machine images slice",
+ input: &ske.ProviderOptions{
+ MachineImages: nil,
+ },
+ expected: &Model{
+ // Expect an empty list, not null
+ MachineImages: types.ListValueMust(
+ types.ObjectType{AttrTypes: machineImageType},
+ []attr.Value{},
+ ),
+ },
+ isValid: true,
+ },
+ {
+ name: "empty machine images slice",
+ input: &ske.ProviderOptions{
+ MachineImages: &[]ske.MachineImage{},
+ },
+ expected: &Model{
+ MachineImages: types.ListValueMust(
+ types.ObjectType{AttrTypes: machineImageType},
+ []attr.Value{},
+ ),
+ },
+ isValid: true,
+ },
+ {
+ name: "version without cri and without expiration",
+ input: &ske.ProviderOptions{
+ MachineImages: &[]ske.MachineImage{
+ {
+ Name: skeutils.Ptr("ubuntu"),
+ Versions: &[]ske.MachineImageVersion{
+ {
+ Version: skeutils.Ptr("2204.20250728.0"),
+ State: skeutils.Ptr("supported"),
+ ExpirationDate: nil,
+ Cri: nil, // explicit nil => empty list
+ },
+ },
+ },
+ },
+ },
+ expected: &Model{
+ MachineImages: types.ListValueMust(
+ types.ObjectType{AttrTypes: machineImageType},
+ []attr.Value{
+ types.ObjectValueMust(machineImageType, map[string]attr.Value{
+ "name": types.StringValue("ubuntu"),
+ "versions": types.ListValueMust(
+ types.ObjectType{AttrTypes: machineImageVersionType},
+ []attr.Value{
+ types.ObjectValueMust(machineImageVersionType, map[string]attr.Value{
+ "version": types.StringValue("2204.20250728.0"),
+ "state": types.StringValue("supported"),
+ "expiration_date": types.StringNull(),
+ "cri": types.ListValueMust(
+ types.StringType,
+ []attr.Value{},
+ ),
+ }),
+ },
+ ),
+ }),
+ },
+ ),
+ },
+ isValid: true,
+ },
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ model := &Model{}
+ err := mapFields(context.Background(), tt.input, model)
+
+ if tt.isValid && err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if !tt.isValid && err == nil {
+ t.Fatal("expected error but got none")
+ }
+
+ if tt.isValid {
+ if diff := cmp.Diff(tt.expected, model); diff != "" {
+ t.Fatalf("mismatch (-want +got):\n%s", diff)
+ }
+ }
+ })
+ }
+}
diff --git a/stackit/internal/services/ske/ske_acc_test.go b/stackit/internal/services/ske/ske_acc_test.go
index b5a2d1796..c862daa98 100644
--- a/stackit/internal/services/ske/ske_acc_test.go
+++ b/stackit/internal/services/ske/ske_acc_test.go
@@ -31,6 +31,9 @@ var (
//go:embed testdata/resource-max.tf
resourceMax string
+
+ //go:embed testdata/provider-options.tf
+ dataSourceProviderOptions string
)
var skeProviderOptions = NewSkeProviderOptions("flatcar")
@@ -91,6 +94,10 @@ var testConfigVarsMax = config.Variables{
"dns_name": config.StringVariable("acc-" + acctest.RandStringFromCharSet(6, acctest.CharSetAlpha) + ".runs.onstackit.cloud"),
}
+var testConfigDatasource = config.Variables{
+ "region": config.StringVariable(testutil.Region),
+}
+
func configVarsMinUpdated() config.Variables {
updatedConfig := maps.Clone(testConfigVarsMin)
updatedConfig["kubernetes_version_min"] = config.StringVariable(skeProviderOptions.GetUpdateK8sVersion())
@@ -455,6 +462,36 @@ func TestAccSKEMax(t *testing.T) {
})
}
+func TestAccProviderOption(t *testing.T) {
+ t.Logf("TestAccProviderOption")
+ resource.ParallelTest(t, resource.TestCase{
+ ProtoV6ProviderFactories: testutil.TestAccProtoV6ProviderFactories,
+ Steps: []resource.TestStep{
+ {
+ ConfigVariables: testConfigDatasource,
+ Config: testutil.SKEProviderConfig() + "\n" + dataSourceProviderOptions,
+ Check: resource.ComposeTestCheckFunc(
+ resource.TestCheckResourceAttr("data.stackit_ske_kubernetes_versions.example", "version_state", "SUPPORTED"),
+ resource.TestCheckResourceAttrSet("data.stackit_ske_kubernetes_versions.example", "kubernetes_versions.0.version"),
+ resource.TestCheckResourceAttrSet("data.stackit_ske_kubernetes_versions.example", "kubernetes_versions.0.state"),
+ resource.TestCheckResourceAttr("data.stackit_ske_kubernetes_versions.example", "kubernetes_versions.0.state", "supported"),
+
+ resource.TestCheckResourceAttr("data.stackit_ske_machine_image_versions.example", "version_state", "SUPPORTED"),
+ resource.TestCheckResourceAttrSet("data.stackit_ske_machine_image_versions.example", "machine_images.0.name"),
+ resource.TestCheckResourceAttrSet("data.stackit_ske_machine_image_versions.example", "machine_images.0.versions.0.version"),
+ resource.TestCheckResourceAttrSet("data.stackit_ske_machine_image_versions.example", "machine_images.0.versions.0.state"),
+ resource.TestCheckResourceAttrSet("data.stackit_ske_machine_image_versions.example", "machine_images.0.versions.0.cri.0"),
+ resource.TestCheckResourceAttr("data.stackit_ske_machine_image_versions.example", "machine_images.0.versions.0.state", "supported"),
+
+ resource.TestCheckResourceAttrSet("data.stackit_ske_machine_image_versions.example", "machine_images.1.name"),
+ resource.TestCheckResourceAttrSet("data.stackit_ske_machine_image_versions.example", "machine_images.1.versions.0.version"),
+ resource.TestCheckResourceAttrSet("data.stackit_ske_machine_image_versions.example", "machine_images.1.versions.0.state"),
+ ),
+ },
+ },
+ })
+}
+
func testAccCheckSKEDestroy(s *terraform.State) error {
ctx := context.Background()
var client *ske.APIClient
diff --git a/stackit/internal/services/ske/testdata/provider-options.tf b/stackit/internal/services/ske/testdata/provider-options.tf
new file mode 100644
index 000000000..610c97bf6
--- /dev/null
+++ b/stackit/internal/services/ske/testdata/provider-options.tf
@@ -0,0 +1,7 @@
+data "stackit_ske_kubernetes_versions" "example" {
+ version_state = "SUPPORTED"
+}
+
+data "stackit_ske_machine_image_versions" "example" {
+ version_state = "SUPPORTED"
+}
diff --git a/stackit/provider.go b/stackit/provider.go
index e5b3e505d..da4e3b893 100644
--- a/stackit/provider.go
+++ b/stackit/provider.go
@@ -98,6 +98,8 @@ import (
"github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/sfs/snapshots"
skeCluster "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/ske/cluster"
skeKubeconfig "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/ske/kubeconfig"
+ skeKubernetesVersion "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/ske/provideroptions/kubernetesversions"
+ skeMachineImages "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/ske/provideroptions/machineimages"
sqlServerFlexInstance "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/sqlserverflex/instance"
sqlServerFlexUser "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/sqlserverflex/user"
)
@@ -570,6 +572,8 @@ func (p *Provider) DataSources(_ context.Context) []func() datasource.DataSource
serverUpdateSchedule.NewSchedulesDataSource,
serviceAccount.NewServiceAccountDataSource,
skeCluster.NewClusterDataSource,
+ skeKubernetesVersion.NewKubernetesVersionsDataSource,
+ skeMachineImages.NewKubernetesMachineImageVersionDataSource,
resourcepool.NewResourcePoolDataSource,
share.NewShareDataSource,
exportpolicy.NewExportPolicyDataSource,