diff --git a/docs/data-sources/ske_provider_options.md b/docs/data-sources/ske_provider_options.md
new file mode 100644
index 000000000..e5840961e
--- /dev/null
+++ b/docs/data-sources/ske_provider_options.md
@@ -0,0 +1,101 @@
+---
+# generated by https://github.com/hashicorp/terraform-plugin-docs
+page_title: "stackit_ske_provider_options Data Source - stackit"
+subcategory: ""
+description: |-
+ Returns a list of supported Kubernetes versions and a list of supported machine types for the cluster nodes.
+---
+
+# stackit_ske_provider_options (Data Source)
+
+Returns a list of supported Kubernetes versions and a list of supported machine types for the cluster nodes.
+
+## Example Usage
+
+```terraform
+data "stackit_ske_provider_options" "default" {}
+
+data "stackit_ske_provider_options" "eu02" {
+ region = "eu02"
+}
+
+locals {
+ k8s_versions = [
+ for v in data.stackit_ske_provider_options.default.kubernetes_versions :
+ v.version if v.state == "supported"
+ ]
+ first_k8s_version = length(local.k8s_versions) > 0 ? local.k8s_versions[0] : ""
+ last_k8s_version = length(local.k8s_versions) > 0 ? local.k8s_versions[length(local.k8s_versions) - 1] : ""
+
+
+ flatcar_supported_versions = flatten([
+ for mi in data.stackit_ske_provider_options.default.machine_images : [
+ for v in mi.versions :
+ v.version if mi.name == "flatcar" && v.state == "supported"
+ ]
+ ])
+
+ ubuntu_supported_versions = flatten([
+ for mi in data.stackit_ske_provider_options.default.machine_images : [
+ for v in mi.versions :
+ v.version if mi.name == "ubuntu" && v.state == "supported"
+ ]
+ ])
+}
+```
+
+
+## Schema
+
+### Optional
+
+- `region` (String) Region override. If omitted, the provider’s region will be used.
+
+### Read-Only
+
+- `availability_zones` (List of String) List of availability zones in the selected region.
+- `kubernetes_versions` (Attributes List) Supported Kubernetes versions. (see [below for nested schema](#nestedatt--kubernetes_versions))
+- `machine_images` (Attributes List) Supported machine image types and software versions. (see [below for nested schema](#nestedatt--machine_images))
+- `machine_types` (Attributes List) List of machine types (node sizes) available in the region. (see [below for nested schema](#nestedatt--machine_types))
+- `volume_types` (List of String) Supported root volume types (e.g., `storage_premium_perf1`).
+
+
+### Nested Schema for `kubernetes_versions`
+
+Read-Only:
+
+- `expiration_date` (String) Expiration date of the version in RFC3339 format.
+- `state` (String) Version state, such as `supported`, `preview`, or `deprecated`.
+- `version` (String) Kubernetes version string (e.g., `1.33`).
+
+
+
+### Nested Schema for `machine_images`
+
+Read-Only:
+
+- `name` (String) Name of the OS image (e.g., `ubuntu`).
+- `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 (e.g., `supported`, `preview`, `deprecated`).
+- `version` (String) Machine image version string.
+
+
+
+
+### Nested Schema for `machine_types`
+
+Read-Only:
+
+- `architecture` (String) CPU architecture (e.g., `x86_64`, `arm64`).
+- `cpu` (Number) Number of virtual CPUs.
+- `gpu` (Number) Number of GPUs included.
+- `memory` (Number) Memory size in GB.
+- `name` (String) Machine type name (e.g., `c2i.2`).
diff --git a/examples/data-sources/stackit_ske_provider_options/data-source.tf b/examples/data-sources/stackit_ske_provider_options/data-source.tf
new file mode 100644
index 000000000..8160eec1d
--- /dev/null
+++ b/examples/data-sources/stackit_ske_provider_options/data-source.tf
@@ -0,0 +1,29 @@
+data "stackit_ske_provider_options" "default" {}
+
+data "stackit_ske_provider_options" "eu02" {
+ region = "eu02"
+}
+
+locals {
+ k8s_versions = [
+ for v in data.stackit_ske_provider_options.default.kubernetes_versions :
+ v.version if v.state == "supported"
+ ]
+ first_k8s_version = length(local.k8s_versions) > 0 ? local.k8s_versions[0] : ""
+ last_k8s_version = length(local.k8s_versions) > 0 ? local.k8s_versions[length(local.k8s_versions) - 1] : ""
+
+
+ flatcar_supported_versions = flatten([
+ for mi in data.stackit_ske_provider_options.default.machine_images : [
+ for v in mi.versions :
+ v.version if mi.name == "flatcar" && v.state == "supported"
+ ]
+ ])
+
+ ubuntu_supported_versions = flatten([
+ for mi in data.stackit_ske_provider_options.default.machine_images : [
+ for v in mi.versions :
+ v.version if mi.name == "ubuntu" && v.state == "supported"
+ ]
+ ])
+}
\ No newline at end of file
diff --git a/stackit/internal/services/ske/provideroptions/datasource.go b/stackit/internal/services/ske/provideroptions/datasource.go
new file mode 100644
index 000000000..f157364cc
--- /dev/null
+++ b/stackit/internal/services/ske/provideroptions/datasource.go
@@ -0,0 +1,384 @@
+package providerOptions
+
+import (
+ "context"
+ "fmt"
+ "net/http"
+ "time"
+
+ "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/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 for nested structures
+type Model struct {
+ Region types.String `tfsdk:"region"`
+ AvailabilityZones types.List `tfsdk:"availability_zones"`
+ KubernetesVersions types.List `tfsdk:"kubernetes_versions"`
+ MachineTypes types.List `tfsdk:"machine_types"`
+ MachineImages types.List `tfsdk:"machine_images"`
+ VolumeTypes types.List `tfsdk:"volume_types"`
+}
+
+var (
+ kubernetesVersionType = map[string]attr.Type{
+ "version": types.StringType,
+ "expiration_date": types.StringType,
+ "state": types.StringType,
+ }
+
+ machineTypeAttributeType = map[string]attr.Type{
+ "name": types.StringType,
+ "architecture": types.StringType,
+ "cpu": types.Int64Type,
+ "gpu": types.Int64Type,
+ "memory": types.Int64Type,
+ }
+
+ 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{}
+
+// NewOptionsDataSource creates the data source instance
+func NewOptionsDataSource() 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_provider_options"
+}
+
+func (d *optionsDataSource) 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)
+ tflog.Info(ctx, "SKE options client configured")
+}
+
+func (d *optionsDataSource) Schema(_ context.Context, _ datasource.SchemaRequest, resp *datasource.SchemaResponse) {
+ description := "Returns a list of supported Kubernetes versions and a list of supported machine types 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.",
+ },
+ "availability_zones": schema.ListAttribute{
+ Computed: true,
+ ElementType: types.StringType,
+ Description: "List of availability zones in the selected region.",
+ },
+ "kubernetes_versions": schema.ListNestedAttribute{
+ Computed: true,
+ Description: "Supported Kubernetes versions.",
+ NestedObject: schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "version": schema.StringAttribute{
+ Computed: true,
+ Description: "Kubernetes version string (e.g., `1.33`).",
+ },
+ "expiration_date": schema.StringAttribute{
+ Computed: true,
+ Description: "Expiration date of the version in RFC3339 format.",
+ },
+ "state": schema.StringAttribute{
+ Computed: true,
+ Description: "Version state, such as `supported`, `preview`, or `deprecated`.",
+ },
+ },
+ },
+ },
+ "machine_types": schema.ListNestedAttribute{
+ Computed: true,
+ Description: "List of machine types (node sizes) available in the region.",
+ NestedObject: schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "name": schema.StringAttribute{
+ Computed: true,
+ Description: "Machine type name (e.g., `c2i.2`).",
+ },
+ "architecture": schema.StringAttribute{
+ Computed: true,
+ Description: "CPU architecture (e.g., `x86_64`, `arm64`).",
+ },
+ "cpu": schema.Int64Attribute{
+ Computed: true,
+ Description: "Number of virtual CPUs.",
+ },
+ "gpu": schema.Int64Attribute{
+ Computed: true,
+ Description: "Number of GPUs included.",
+ },
+ "memory": schema.Int64Attribute{
+ Computed: true,
+ Description: "Memory size in GB.",
+ },
+ },
+ },
+ },
+ "machine_images": schema.ListNestedAttribute{
+ Computed: true,
+ Description: "Supported machine image types and software versions.",
+ NestedObject: schema.NestedAttributeObject{
+ Attributes: map[string]schema.Attribute{
+ "name": schema.StringAttribute{
+ Computed: true,
+ Description: "Name of the OS image (e.g., `ubuntu`).",
+ },
+ "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 (e.g., `supported`, `preview`, `deprecated`).",
+ },
+ "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`).",
+ },
+ },
+ },
+ },
+ },
+ },
+ },
+ "volume_types": schema.ListAttribute{
+ Computed: true,
+ ElementType: types.StringType,
+ Description: "Supported root volume types (e.g., `storage_premium_perf1`).",
+ },
+ },
+ }
+}
+
+// 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 = tflog.SetField(ctx, "region", region)
+
+ optionsResp, err := d.client.ListProviderOptions(ctx, region).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
+ }
+
+ err = mapFields(ctx, optionsResp, &model)
+ if err != nil {
+ core.LogAndAddError(ctx, &diags, "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")
+}
+
+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")
+ }
+
+ // Availability Zones
+ azList := make([]types.String, 0)
+ if optionsResp.AvailabilityZones != nil {
+ for _, az := range *optionsResp.AvailabilityZones {
+ if az.Name != nil {
+ azList = append(azList, types.StringValue(*az.Name))
+ }
+ }
+ }
+ avZones, diags := types.ListValueFrom(ctx, types.StringType, azList)
+ if diags.HasError() {
+ return core.DiagsToError(diags)
+ }
+ model.AvailabilityZones = avZones
+
+ // Volume Types
+ volList := make([]types.String, 0)
+ if optionsResp.VolumeTypes != nil {
+ for _, vt := range *optionsResp.VolumeTypes {
+ if vt.Name != nil {
+ volList = append(volList, types.StringValue(*vt.Name))
+ }
+ }
+ }
+ volTypes, diags := types.ListValueFrom(ctx, types.StringType, volList)
+ if diags.HasError() {
+ return core.DiagsToError(diags)
+ }
+ model.VolumeTypes = volTypes
+
+ // Kubernetes Versions
+ kvList := make([]attr.Value, 0)
+ if optionsResp.KubernetesVersions != nil {
+ for _, kv := range *optionsResp.KubernetesVersions {
+ expDate := types.StringNull()
+ if kv.ExpirationDate != nil {
+ expDate = types.StringValue(kv.ExpirationDate.Format(time.RFC3339))
+ }
+
+ obj, diags := types.ObjectValue(kubernetesVersionType, map[string]attr.Value{
+ "version": types.StringPointerValue(kv.Version),
+ "state": types.StringPointerValue(kv.State),
+ "expiration_date": expDate,
+ })
+ 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
+
+ // Machine Types
+ mtList := make([]attr.Value, 0)
+ if optionsResp.MachineTypes != nil {
+ for _, mt := range *optionsResp.MachineTypes {
+ vals := map[string]attr.Value{
+ "name": types.StringPointerValue(mt.Name),
+ "architecture": types.StringPointerValue(mt.Architecture),
+ "cpu": types.Int64PointerValue(mt.Cpu),
+ "gpu": types.Int64PointerValue(mt.Gpu),
+ "memory": types.Int64PointerValue(mt.Memory),
+ }
+ obj, diags := types.ObjectValue(machineTypeAttributeType, vals)
+ if diags.HasError() {
+ return core.DiagsToError(diags)
+ }
+ mtList = append(mtList, obj)
+ }
+ }
+ mts, diags := types.ListValue(types.ObjectType{AttrTypes: machineTypeAttributeType}, mtList)
+ if diags.HasError() {
+ return core.DiagsToError(diags)
+ }
+ model.MachineTypes = mts
+
+ // 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 {
+ 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)
+ }
+
+ 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/datasource_test.go b/stackit/internal/services/ske/provideroptions/datasource_test.go
new file mode 100644
index 000000000..de6a845ba
--- /dev/null
+++ b/stackit/internal/services/ske/provideroptions/datasource_test.go
@@ -0,0 +1,337 @@
+package providerOptions
+
+import (
+ "context"
+ "testing"
+ "time"
+
+ "github.com/google/go-cmp/cmp"
+ "github.com/hashicorp/terraform-plugin-framework/attr"
+ "github.com/hashicorp/terraform-plugin-framework/types"
+ "github.com/stackitcloud/stackit-sdk-go/core/utils"
+ "github.com/stackitcloud/stackit-sdk-go/services/ske"
+)
+
+func TestMapFields(t *testing.T) {
+ timestamp := time.Date(2025, 2, 5, 10, 20, 30, 0, time.UTC)
+ expDate := timestamp.Format(time.RFC3339)
+
+ tests := []struct {
+ name string
+ input *ske.ProviderOptions
+ expected *Model
+ isValid bool
+ }{
+ {
+ name: "normal_case",
+ input: &ske.ProviderOptions{
+ AvailabilityZones: &[]ske.AvailabilityZone{
+ {Name: utils.Ptr("eu01-01")},
+ {Name: utils.Ptr("eu01-02")},
+ },
+ VolumeTypes: &[]ske.VolumeType{
+ {Name: utils.Ptr("storage_premium_perf1")},
+ {Name: utils.Ptr("storage_premium_perf2")},
+ },
+ KubernetesVersions: &[]ske.KubernetesVersion{
+ {
+ Version: utils.Ptr("1.33.5"),
+ State: utils.Ptr("supported"),
+ ExpirationDate: ×tamp,
+ },
+ },
+ MachineTypes: &[]ske.MachineType{
+ {
+ Name: utils.Ptr("n2.56d.g4"),
+ Architecture: utils.Ptr("amd64"),
+ Cpu: utils.Ptr(int64(4)),
+ Gpu: utils.Ptr(int64(1)),
+ Memory: utils.Ptr(int64(16)),
+ },
+ },
+ MachineImages: &[]ske.MachineImage{
+ {
+ Name: utils.Ptr("ubuntu"),
+ Versions: &[]ske.MachineImageVersion{
+ {
+ Version: utils.Ptr("2204.20250620.0"),
+ State: utils.Ptr("supported"),
+ ExpirationDate: ×tamp,
+ Cri: &[]ske.CRI{
+ {Name: utils.Ptr(ske.CRINAME_CONTAINERD)},
+ },
+ },
+ },
+ },
+ },
+ },
+ expected: &Model{
+ AvailabilityZones: types.ListValueMust(
+ types.StringType,
+ []attr.Value{
+ types.StringValue("eu01-01"),
+ types.StringValue("eu01-02"),
+ },
+ ),
+ VolumeTypes: types.ListValueMust(
+ types.StringType,
+ []attr.Value{
+ types.StringValue("storage_premium_perf1"),
+ types.StringValue("storage_premium_perf2"),
+ },
+ ),
+ KubernetesVersions: types.ListValueMust(
+ types.ObjectType{AttrTypes: kubernetesVersionType},
+ []attr.Value{
+ types.ObjectValueMust(kubernetesVersionType, map[string]attr.Value{
+ "version": types.StringValue("1.33.5"),
+ "state": types.StringValue("supported"),
+ "expiration_date": types.StringValue(expDate),
+ }),
+ },
+ ),
+ MachineTypes: types.ListValueMust(
+ types.ObjectType{AttrTypes: machineTypeAttributeType},
+ []attr.Value{
+ types.ObjectValueMust(machineTypeAttributeType, map[string]attr.Value{
+ "name": types.StringValue("n2.56d.g4"),
+ "architecture": types.StringValue("amd64"),
+ "cpu": types.Int64Value(4),
+ "gpu": types.Int64Value(1),
+ "memory": types.Int64Value(16),
+ }),
+ },
+ ),
+ 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.20250620.0"),
+ "state": types.StringValue("supported"),
+ "expiration_date": types.StringValue(expDate),
+ "cri": types.ListValueMust(
+ types.StringType,
+ []attr.Value{
+ types.StringValue("containerd"),
+ },
+ ),
+ }),
+ },
+ ),
+ }),
+ },
+ ),
+ },
+ isValid: true,
+ },
+ {
+ name: "partial_fields",
+ input: &ske.ProviderOptions{
+ AvailabilityZones: &[]ske.AvailabilityZone{
+ {Name: utils.Ptr("eu01-01")},
+ },
+ MachineTypes: &[]ske.MachineType{
+ {
+ Name: utils.Ptr("g1a.16d"),
+ Cpu: utils.Ptr(int64(2)),
+ },
+ },
+ },
+ expected: &Model{
+ AvailabilityZones: types.ListValueMust(types.StringType,
+ []attr.Value{types.StringValue("eu01-01")},
+ ),
+ VolumeTypes: types.ListValueMust(types.StringType, []attr.Value{}),
+ KubernetesVersions: types.ListValueMust(types.ObjectType{AttrTypes: kubernetesVersionType}, []attr.Value{}),
+ MachineImages: types.ListValueMust(types.ObjectType{AttrTypes: machineImageType}, []attr.Value{}),
+ MachineTypes: types.ListValueMust(
+ types.ObjectType{AttrTypes: machineTypeAttributeType},
+ []attr.Value{
+ types.ObjectValueMust(machineTypeAttributeType, map[string]attr.Value{
+ "name": types.StringValue("g1a.16d"),
+ "architecture": types.StringNull(),
+ "cpu": types.Int64Value(2),
+ "gpu": types.Int64Null(),
+ "memory": types.Int64Null(),
+ }),
+ },
+ ),
+ },
+ isValid: true,
+ },
+ {
+ name: "az_with_nil_name",
+ input: &ske.ProviderOptions{
+ AvailabilityZones: &[]ske.AvailabilityZone{
+ {Name: nil},
+ {Name: utils.Ptr("eu01-01")},
+ },
+ },
+ expected: &Model{
+ AvailabilityZones: types.ListValueMust(
+ types.StringType,
+ []attr.Value{types.StringValue("eu01-01")},
+ ),
+ VolumeTypes: types.ListValueMust(types.StringType, []attr.Value{}),
+ KubernetesVersions: types.ListValueMust(types.ObjectType{AttrTypes: kubernetesVersionType}, []attr.Value{}),
+ MachineTypes: types.ListValueMust(types.ObjectType{AttrTypes: machineTypeAttributeType}, []attr.Value{}),
+ MachineImages: types.ListValueMust(types.ObjectType{AttrTypes: machineImageType}, []attr.Value{}),
+ },
+ isValid: true,
+ },
+ {
+ name: "machine_image_with_nil_versions",
+ input: &ske.ProviderOptions{
+ MachineImages: &[]ske.MachineImage{
+ {
+ Name: utils.Ptr("ubuntu"),
+ Versions: nil,
+ },
+ },
+ },
+ expected: &Model{
+ AvailabilityZones: types.ListValueMust(types.StringType, []attr.Value{}),
+ VolumeTypes: types.ListValueMust(types.StringType, []attr.Value{}),
+ KubernetesVersions: types.ListValueMust(types.ObjectType{AttrTypes: kubernetesVersionType}, []attr.Value{}),
+ MachineTypes: types.ListValueMust(types.ObjectType{AttrTypes: machineTypeAttributeType}, []attr.Value{}),
+ 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{}),
+ }),
+ },
+ ),
+ },
+ isValid: true,
+ },
+ {
+ name: "image_version_with_nil_cri",
+ input: &ske.ProviderOptions{
+ MachineImages: &[]ske.MachineImage{
+ {
+ Name: utils.Ptr("ubuntu"),
+ Versions: &[]ske.MachineImageVersion{
+ {
+ Version: utils.Ptr("1.1"),
+ State: utils.Ptr("deprecated"),
+ ExpirationDate: ×tamp,
+ Cri: nil,
+ },
+ },
+ },
+ },
+ },
+ expected: &Model{
+ AvailabilityZones: types.ListValueMust(types.StringType, []attr.Value{}),
+ VolumeTypes: types.ListValueMust(types.StringType, []attr.Value{}),
+ KubernetesVersions: types.ListValueMust(types.ObjectType{AttrTypes: kubernetesVersionType}, []attr.Value{}),
+ MachineTypes: types.ListValueMust(types.ObjectType{AttrTypes: machineTypeAttributeType}, []attr.Value{}),
+ 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("1.1"),
+ "state": types.StringValue("deprecated"),
+ "expiration_date": types.StringValue(expDate),
+ "cri": types.ListValueMust(types.StringType, []attr.Value{}),
+ }),
+ }),
+ }),
+ }),
+ },
+ isValid: true,
+ },
+ {
+ name: "machine_type_null_fields",
+ input: &ske.ProviderOptions{
+ MachineTypes: &[]ske.MachineType{
+ {}, // all pointer fields are nil
+ },
+ },
+ expected: &Model{
+ AvailabilityZones: types.ListValueMust(types.StringType, []attr.Value{}),
+ VolumeTypes: types.ListValueMust(types.StringType, []attr.Value{}),
+ KubernetesVersions: types.ListValueMust(types.ObjectType{AttrTypes: kubernetesVersionType}, []attr.Value{}),
+ MachineImages: types.ListValueMust(types.ObjectType{AttrTypes: machineImageType}, []attr.Value{}),
+ MachineTypes: types.ListValueMust(types.ObjectType{AttrTypes: machineTypeAttributeType}, []attr.Value{
+ types.ObjectValueMust(machineTypeAttributeType, map[string]attr.Value{
+ "name": types.StringNull(),
+ "architecture": types.StringNull(),
+ "cpu": types.Int64Null(),
+ "gpu": types.Int64Null(),
+ "memory": types.Int64Null(),
+ }),
+ }),
+ },
+ isValid: true,
+ },
+ {
+ name: "all_nil_fields",
+ input: &ske.ProviderOptions{
+ AvailabilityZones: nil,
+ VolumeTypes: nil,
+ KubernetesVersions: nil,
+ MachineImages: nil,
+ MachineTypes: nil,
+ },
+ expected: &Model{
+ AvailabilityZones: types.ListValueMust(types.StringType, []attr.Value{}),
+ VolumeTypes: types.ListValueMust(types.StringType, []attr.Value{}),
+ KubernetesVersions: types.ListValueMust(types.ObjectType{AttrTypes: kubernetesVersionType}, []attr.Value{}),
+ MachineTypes: types.ListValueMust(types.ObjectType{AttrTypes: machineTypeAttributeType}, []attr.Value{}),
+ MachineImages: types.ListValueMust(types.ObjectType{AttrTypes: machineImageType}, []attr.Value{}),
+ },
+ isValid: true,
+ },
+ {
+ name: "all_empty_fields",
+ input: &ske.ProviderOptions{
+ AvailabilityZones: &[]ske.AvailabilityZone{},
+ VolumeTypes: &[]ske.VolumeType{},
+ KubernetesVersions: &[]ske.KubernetesVersion{},
+ MachineImages: &[]ske.MachineImage{},
+ MachineTypes: &[]ske.MachineType{},
+ },
+ expected: &Model{
+ AvailabilityZones: types.ListValueMust(types.StringType, []attr.Value{}),
+ VolumeTypes: types.ListValueMust(types.StringType, []attr.Value{}),
+ KubernetesVersions: types.ListValueMust(types.ObjectType{AttrTypes: kubernetesVersionType}, []attr.Value{}),
+ MachineTypes: types.ListValueMust(types.ObjectType{AttrTypes: machineTypeAttributeType}, []attr.Value{}),
+ MachineImages: types.ListValueMust(types.ObjectType{AttrTypes: machineImageType}, []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..9408de0e8 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,41 @@ 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(
+ // Availability Zones
+ resource.TestCheckResourceAttrSet("data.stackit_ske_provider_options.this", "availability_zones.0"),
+
+ // Volume Types
+ resource.TestCheckResourceAttrSet("data.stackit_ske_provider_options.this", "volume_types.0"),
+
+ // Kubernetes Versions
+ resource.TestCheckResourceAttrSet("data.stackit_ske_provider_options.this", "kubernetes_versions.0.version"),
+ resource.TestCheckResourceAttrSet("data.stackit_ske_provider_options.this", "kubernetes_versions.0.state"),
+
+ // Machine Images
+ resource.TestCheckResourceAttrSet("data.stackit_ske_provider_options.this", "machine_images.0.name"),
+ resource.TestCheckResourceAttrSet("data.stackit_ske_provider_options.this", "machine_images.0.versions.0.state"),
+ resource.TestCheckResourceAttrSet("data.stackit_ske_provider_options.this", "machine_images.0.versions.0.version"),
+
+ // Machine Types
+ resource.TestCheckResourceAttrSet("data.stackit_ske_provider_options.this", "machine_types.0.name"),
+ resource.TestCheckResourceAttrSet("data.stackit_ske_provider_options.this", "machine_types.0.cpu"),
+ resource.TestCheckResourceAttrSet("data.stackit_ske_provider_options.this", "machine_types.0.gpu"),
+ resource.TestCheckResourceAttrSet("data.stackit_ske_provider_options.this", "machine_types.0.memory"),
+ ),
+ },
+ },
+ })
+}
+
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..f359b0457
--- /dev/null
+++ b/stackit/internal/services/ske/testdata/provider-options.tf
@@ -0,0 +1 @@
+data "stackit_ske_provider_options" "this" {}
\ No newline at end of file
diff --git a/stackit/provider.go b/stackit/provider.go
index 5f51fc33c..ab2e90040 100644
--- a/stackit/provider.go
+++ b/stackit/provider.go
@@ -88,6 +88,7 @@ import (
serviceAccountToken "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/serviceaccount/token"
skeCluster "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/ske/cluster"
skeKubeconfig "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/ske/kubeconfig"
+ skeProviderOptions "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/ske/provideroptions"
sqlServerFlexInstance "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/sqlserverflex/instance"
sqlServerFlexUser "github.com/stackitcloud/terraform-provider-stackit/stackit/internal/services/sqlserverflex/user"
)
@@ -524,6 +525,7 @@ func (p *Provider) DataSources(_ context.Context) []func() datasource.DataSource
serverUpdateSchedule.NewSchedulesDataSource,
serviceAccount.NewServiceAccountDataSource,
skeCluster.NewClusterDataSource,
+ skeProviderOptions.NewOptionsDataSource,
}
}