Allow specifying network ID in SKE cluster (#368)
This commit is contained in:
parent
e2e5f19a29
commit
ac0840fceb
6 changed files with 204 additions and 7 deletions
|
|
@ -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))
|
||||
|
||||
<a id="nestedatt--extensions"></a>
|
||||
|
|
@ -90,6 +91,14 @@ Read-Only:
|
|||
- `start` (String) Date time for maintenance window start.
|
||||
|
||||
|
||||
<a id="nestedatt--network"></a>
|
||||
### Nested Schema for `network`
|
||||
|
||||
Read-Only:
|
||||
|
||||
- `id` (String) ID of the STACKIT Network Area (SNA) network into which the cluster will be deployed.
|
||||
|
||||
|
||||
<a id="nestedatt--node_pools"></a>
|
||||
### Nested Schema for `node_pools`
|
||||
|
||||
|
|
|
|||
|
|
@ -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).
|
||||
|
||||
|
||||
<a id="nestedatt--network"></a>
|
||||
### Nested Schema for `network`
|
||||
|
||||
Optional:
|
||||
|
||||
- `id` (String) ID of the STACKIT Network Area (SNA) network into which the cluster will be deployed.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue