diff --git a/docs/data-sources/ske_cluster.md b/docs/data-sources/ske_cluster.md
index ae41da4e..86dbbbaf 100644
--- a/docs/data-sources/ske_cluster.md
+++ b/docs/data-sources/ske_cluster.md
@@ -40,6 +40,7 @@ This should be used with care since it also disables a couple of other features
- `kubernetes_version_min` (String) The minimum Kubernetes version, this field is always nil. SKE automatically updates the cluster Kubernetes version if you have set `maintenance.enable_kubernetes_version_updates` to true or if there is a mandatory update, as described in [Updates for Kubernetes versions and Operating System versions in SKE](https://docs.stackit.cloud/stackit/en/version-updates-in-ske-10125631.html). To get the current kubernetes version being used for your cluster, use the `kubernetes_version_used` field.
- `kubernetes_version_used` (String) Full Kubernetes version used. For example, if `1.22` was selected, this value may result to `1.22.15`
- `maintenance` (Attributes) A single maintenance block as defined below (see [below for nested schema](#nestedatt--maintenance))
+- `network` (Attributes) Network block as defined below. (see [below for nested schema](#nestedatt--network))
- `node_pools` (Attributes List) One or more `node_pool` block as defined below. (see [below for nested schema](#nestedatt--node_pools))
@@ -90,6 +91,14 @@ Read-Only:
- `start` (String) Date time for maintenance window start.
+
+### Nested Schema for `network`
+
+Read-Only:
+
+- `id` (String) ID of the STACKIT Network Area (SNA) network into which the cluster will be deployed.
+
+
### Nested Schema for `node_pools`
diff --git a/docs/resources/ske_cluster.md b/docs/resources/ske_cluster.md
index 8db3bb25..9c049cfa 100644
--- a/docs/resources/ske_cluster.md
+++ b/docs/resources/ske_cluster.md
@@ -55,6 +55,7 @@ Deprecated as of Kubernetes 1.25 and later
- `kubernetes_version` (String, Deprecated) Kubernetes version. Must only contain major and minor version (e.g. 1.22). This field is deprecated, use `kubernetes_version_min instead`
- `kubernetes_version_min` (String) The minimum Kubernetes version. This field will be used to set the minimum kubernetes version on creation/update of the cluster. If unset, the latest supported Kubernetes version will be used. SKE automatically updates the cluster Kubernetes version if you have set `maintenance.enable_kubernetes_version_updates` to true or if there is a mandatory update, as described in [Updates for Kubernetes versions and Operating System versions in SKE](https://docs.stackit.cloud/stackit/en/version-updates-in-ske-10125631.html). To get the current kubernetes version being used for your cluster, use the read-only `kubernetes_version_used` field.
- `maintenance` (Attributes) A single maintenance block as defined below. (see [below for nested schema](#nestedatt--maintenance))
+- `network` (Attributes) Network block as defined below. (see [below for nested schema](#nestedatt--network))
### Read-Only
@@ -162,3 +163,11 @@ Optional:
- `enable_kubernetes_version_updates` (Boolean) Flag to enable/disable auto-updates of the Kubernetes version. Defaults to `true`. SKE automatically updates the cluster Kubernetes version if you have set `maintenance.enable_kubernetes_version_updates` to true or if there is a mandatory update, as described in [Updates for Kubernetes versions and Operating System versions in SKE](https://docs.stackit.cloud/stackit/en/version-updates-in-ske-10125631.html).
- `enable_machine_image_version_updates` (Boolean) Flag to enable/disable auto-updates of the OS image version. Defaults to `true`. SKE automatically updates the cluster Kubernetes version if you have set `maintenance.enable_kubernetes_version_updates` to true or if there is a mandatory update, as described in [Updates for Kubernetes versions and Operating System versions in SKE](https://docs.stackit.cloud/stackit/en/version-updates-in-ske-10125631.html).
+
+
+
+### Nested Schema for `network`
+
+Optional:
+
+- `id` (String) ID of the STACKIT Network Area (SNA) network into which the cluster will be deployed.
diff --git a/docs/resources/ske_project.md b/docs/resources/ske_project.md
index a5088a58..502091b4 100644
--- a/docs/resources/ske_project.md
+++ b/docs/resources/ske_project.md
@@ -3,12 +3,12 @@
page_title: "stackit_ske_project Resource - stackit"
subcategory: ""
description: |-
- SKE project resource schema. Must have a region specified in the provider configuration. This resource allows you to enable the SKE service and you can only have one per project. Before deleting this resource, all SKE clusters associated to the project must be deleted. Otherwise, error would occur due to the existing clusters. In such case, it is highly recommended to remove the SKE project from the state, directly using the "terraform state rm". Warning: SKE project resource is no longer in use and will be removed with the next minor release. SKE service enablement is done automatically when a new cluster is created.
+ SKE project resource schema. Must have a region specified in the provider configuration. This resource allows you to enable the SKE service and you can only have one per project. Before deleting this resource, all SKE clusters associated to the project must be deleted. Otherwise, error would occur due to the existing clusters. In such case, it is highly recommended to remove the SKE project from the state, directly using the "terraform state rm". Warning: SKE project resource is no longer in use and will be removed after October 10th 2024. SKE service enablement is done automatically when a new cluster is created.
---
# stackit_ske_project (Resource)
-SKE project resource schema. Must have a `region` specified in the provider configuration. This resource allows you to enable the SKE service and you can only have one per project. Before deleting this resource, all SKE clusters associated to the project must be deleted. Otherwise, error would occur due to the existing clusters. In such case, it is highly recommended to remove the SKE project from the state, directly using the "`terraform state rm`". Warning: SKE project resource is no longer in use and will be removed with the next minor release. SKE service enablement is done automatically when a new cluster is created.
+SKE project resource schema. Must have a `region` specified in the provider configuration. This resource allows you to enable the SKE service and you can only have one per project. Before deleting this resource, all SKE clusters associated to the project must be deleted. Otherwise, error would occur due to the existing clusters. In such case, it is highly recommended to remove the SKE project from the state, directly using the "`terraform state rm`". Warning: SKE project resource is no longer in use and will be removed after October 10th 2024. SKE service enablement is done automatically when a new cluster is created.
## Example Usage
diff --git a/stackit/internal/services/ske/cluster/datasource.go b/stackit/internal/services/ske/cluster/datasource.go
index 5fa217e7..5fbd69e8 100644
--- a/stackit/internal/services/ske/cluster/datasource.go
+++ b/stackit/internal/services/ske/cluster/datasource.go
@@ -228,6 +228,20 @@ func (r *clusterDataSource) Schema(_ context.Context, _ datasource.SchemaRequest
},
},
+ "network": schema.SingleNestedAttribute{
+ Description: "Network block as defined below.",
+ Computed: true,
+ Attributes: map[string]schema.Attribute{
+ "id": schema.StringAttribute{
+ Description: "ID of the STACKIT Network Area (SNA) network into which the cluster will be deployed.",
+ Computed: true,
+ Validators: []validator.String{
+ validate.UUID(),
+ },
+ },
+ },
+ },
+
"hibernations": schema.ListNestedAttribute{
Description: "One or more hibernation block as defined below.",
Computed: true,
diff --git a/stackit/internal/services/ske/cluster/resource.go b/stackit/internal/services/ske/cluster/resource.go
index 58da1046..80797b85 100644
--- a/stackit/internal/services/ske/cluster/resource.go
+++ b/stackit/internal/services/ske/cluster/resource.go
@@ -73,6 +73,7 @@ type Model struct {
AllowPrivilegedContainers types.Bool `tfsdk:"allow_privileged_containers"`
NodePools types.List `tfsdk:"node_pools"`
Maintenance types.Object `tfsdk:"maintenance"`
+ Network types.Object `tfsdk:"network"`
Hibernations types.List `tfsdk:"hibernations"`
Extensions types.Object `tfsdk:"extensions"`
KubeConfig types.String `tfsdk:"kube_config"`
@@ -148,6 +149,16 @@ var maintenanceTypes = map[string]attr.Type{
"end": basetypes.StringType{},
}
+// Struct corresponding to Model.Network
+type network struct {
+ ID types.String `tfsdk:"id"`
+}
+
+// Types corresponding to network
+var networkTypes = map[string]attr.Type{
+ "id": basetypes.StringType{},
+}
+
// Struct corresponding to Model.Hibernations[i]
type hibernation struct {
Start types.String `tfsdk:"start"`
@@ -491,6 +502,22 @@ func (r *clusterResource) Schema(_ context.Context, _ resource.SchemaRequest, re
},
},
},
+ "network": schema.SingleNestedAttribute{
+ Description: "Network block as defined below.",
+ Optional: true,
+ Attributes: map[string]schema.Attribute{
+ "id": schema.StringAttribute{
+ Description: "ID of the STACKIT Network Area (SNA) network into which the cluster will be deployed.",
+ Optional: true,
+ Validators: []validator.String{
+ validate.UUID(),
+ },
+ PlanModifiers: []planmodifier.String{
+ stringplanmodifier.RequiresReplace(),
+ },
+ },
+ },
+ },
"hibernations": schema.ListNestedAttribute{
Description: "One or more hibernation block as defined below.",
Optional: true,
@@ -731,6 +758,11 @@ func (r *clusterResource) createOrUpdateCluster(ctx context.Context, diags *diag
core.LogAndAddError(ctx, diags, "Error creating/updating cluster", fmt.Sprintf("Creating maintenance API payload: %v", err))
return
}
+ network, err := toNetworkPayload(ctx, model)
+ if err != nil {
+ core.LogAndAddError(ctx, diags, "Error creating/updating cluster", fmt.Sprintf("Creating network API payload: %v", err))
+ return
+ }
hibernations, err := toHibernationsPayload(ctx, model)
if err != nil {
core.LogAndAddError(ctx, diags, "Error creating/updating cluster", fmt.Sprintf("Creating hibernations API payload: %v", err))
@@ -747,6 +779,7 @@ func (r *clusterResource) createOrUpdateCluster(ctx context.Context, diags *diag
Hibernation: hibernations,
Kubernetes: kubernetes,
Maintenance: maintenance,
+ Network: network,
Nodepools: &nodePools,
}
_, err = r.client.CreateOrUpdateCluster(ctx, projectId, name).CreateOrUpdateClusterPayload(payload).Execute()
@@ -1174,6 +1207,22 @@ func toMaintenancePayload(ctx context.Context, m *Model) (*ske.Maintenance, erro
}, nil
}
+func toNetworkPayload(ctx context.Context, m *Model) (*ske.V1Network, error) {
+ if m.Network.IsNull() || m.Network.IsUnknown() {
+ return nil, nil
+ }
+
+ network := network{}
+ diags := m.Network.As(ctx, &network, basetypes.ObjectAsOptions{})
+ if diags.HasError() {
+ return nil, fmt.Errorf("converting network object: %v", diags.Errors())
+ }
+
+ return &ske.V1Network{
+ Id: conversion.StringValueToPointer(network.ID),
+ }, nil
+}
+
func mapFields(ctx context.Context, cl *ske.Cluster, m *Model) error {
if cl == nil {
return fmt.Errorf("response input is nil")
@@ -1206,19 +1255,23 @@ func mapFields(ctx context.Context, cl *ske.Cluster, m *Model) error {
err := mapNodePools(ctx, cl, m)
if err != nil {
- return fmt.Errorf("mapping node_pools: %w", err)
+ return fmt.Errorf("map node_pools: %w", err)
}
err = mapMaintenance(ctx, cl, m)
if err != nil {
- return fmt.Errorf("mapping maintenance: %w", err)
+ return fmt.Errorf("map maintenance: %w", err)
+ }
+ err = mapNetwork(cl, m)
+ if err != nil {
+ return fmt.Errorf("map network: %w", err)
}
err = mapHibernations(cl, m)
if err != nil {
- return fmt.Errorf("mapping hibernations: %w", err)
+ return fmt.Errorf("map hibernations: %w", err)
}
err = mapExtensions(ctx, cl, m)
if err != nil {
- return fmt.Errorf("mapping extensions: %w", err)
+ return fmt.Errorf("map extensions: %w", err)
}
return nil
}
@@ -1421,12 +1474,33 @@ func mapMaintenance(ctx context.Context, cl *ske.Cluster, m *Model) error {
}
maintenanceObject, diags := types.ObjectValue(maintenanceTypes, maintenanceValues)
if diags.HasError() {
- return fmt.Errorf("creating flavor: %w", core.DiagsToError(diags))
+ return fmt.Errorf("create maintenance object: %w", core.DiagsToError(diags))
}
m.Maintenance = maintenanceObject
return nil
}
+func mapNetwork(cl *ske.Cluster, m *Model) error {
+ if cl.Network == nil {
+ m.Network = types.ObjectNull(networkTypes)
+ return nil
+ }
+
+ id := types.StringNull()
+ if cl.Network.Id != nil {
+ id = types.StringValue(*cl.Network.Id)
+ }
+ networkValues := map[string]attr.Value{
+ "id": id,
+ }
+ networkObject, diags := types.ObjectValue(networkTypes, networkValues)
+ if diags.HasError() {
+ return fmt.Errorf("create network object: %w", core.DiagsToError(diags))
+ }
+ m.Network = networkObject
+ return nil
+}
+
func getMaintenanceTimes(ctx context.Context, cl *ske.Cluster, m *Model) (startTime, endTime string, err error) {
startTimeAPI, err := time.Parse(time.RFC3339, *cl.Maintenance.TimeWindow.Start)
if err != nil {
diff --git a/stackit/internal/services/ske/cluster/resource_test.go b/stackit/internal/services/ske/cluster/resource_test.go
index 959a5d95..c33849fa 100644
--- a/stackit/internal/services/ske/cluster/resource_test.go
+++ b/stackit/internal/services/ske/cluster/resource_test.go
@@ -49,6 +49,7 @@ func TestMapFields(t *testing.T) {
AllowPrivilegedContainers: types.BoolNull(),
NodePools: types.ListNull(types.ObjectType{AttrTypes: nodePoolTypes}),
Maintenance: types.ObjectNull(maintenanceTypes),
+ Network: types.ObjectNull(networkTypes),
Hibernations: types.ListNull(types.ObjectType{AttrTypes: hibernationTypes}),
Extensions: types.ObjectNull(extensionsTypes),
KubeConfig: types.StringNull(),
@@ -92,6 +93,9 @@ func TestMapFields(t *testing.T) {
End: utils.Ptr("0010-11-12T13:14:15Z"),
},
},
+ Network: &ske.V1Network{
+ Id: utils.Ptr("nid"),
+ },
Name: utils.Ptr("name"),
Nodepools: &[]ske.Nodepool{
{
@@ -194,6 +198,9 @@ func TestMapFields(t *testing.T) {
"start": types.StringValue("03:04:05+06:00"),
"end": types.StringValue("13:14:15Z"),
}),
+ Network: types.ObjectValueMust(networkTypes, map[string]attr.Value{
+ "id": types.StringValue("nid"),
+ }),
Hibernations: types.ListValueMust(
types.ObjectType{AttrTypes: hibernationTypes},
[]attr.Value{
@@ -223,6 +230,30 @@ func TestMapFields(t *testing.T) {
},
true,
},
+ {
+ "nil_network_id",
+ types.ObjectNull(extensionsTypes),
+ &ske.Cluster{
+ Name: utils.Ptr("name"),
+ Network: &ske.V1Network{},
+ },
+ Model{
+ Id: types.StringValue("pid,name"),
+ ProjectId: types.StringValue("pid"),
+ Name: types.StringValue("name"),
+ KubernetesVersion: types.StringNull(),
+ AllowPrivilegedContainers: types.BoolNull(),
+ NodePools: types.ListNull(types.ObjectType{AttrTypes: nodePoolTypes}),
+ Maintenance: types.ObjectNull(maintenanceTypes),
+ Network: types.ObjectValueMust(networkTypes, map[string]attr.Value{
+ "id": types.StringNull(),
+ }),
+ Hibernations: types.ListNull(types.ObjectType{AttrTypes: hibernationTypes}),
+ Extensions: types.ObjectNull(extensionsTypes),
+ KubeConfig: types.StringNull(),
+ },
+ true,
+ },
{
"extensions_mixed_values",
types.ObjectNull(extensionsTypes),
@@ -1936,3 +1967,63 @@ func TestGetLatestSupportedMachineVersion(t *testing.T) {
})
}
}
+
+func TestToNetworkPayload(t *testing.T) {
+ tests := []struct {
+ description string
+ model *Model
+ expected *ske.V1Network
+ isValid bool
+ }{
+ {
+ "base",
+ &Model{
+ ProjectId: types.StringValue("pid"),
+ Name: types.StringValue("name"),
+ Network: types.ObjectValueMust(networkTypes, map[string]attr.Value{
+ "id": types.StringValue("nid"),
+ }),
+ },
+ &ske.V1Network{
+ Id: utils.Ptr("nid"),
+ },
+ true,
+ },
+ {
+ "no_id",
+ &Model{
+ ProjectId: types.StringValue("pid"),
+ Name: types.StringValue("name"),
+ Network: types.ObjectValueMust(networkTypes, map[string]attr.Value{
+ "id": types.StringNull(),
+ }),
+ },
+ &ske.V1Network{},
+ true,
+ },
+ {
+ "no_network",
+ &Model{
+ ProjectId: types.StringValue("pid"),
+ Name: types.StringValue("name"),
+ Network: types.ObjectNull(networkTypes),
+ },
+ nil,
+ true,
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.description, func(t *testing.T) {
+ payload, err := toNetworkPayload(context.Background(), tt.model)
+ if !tt.isValid && err == nil {
+ t.Fatalf("Should have failed")
+ }
+ if tt.isValid {
+ diff := cmp.Diff(payload, tt.expected)
+ if diff != "" {
+ t.Fatalf("Data does not match: %s", diff)
+ }
+ }
+ })
+ }
+}