Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions docs/data-sources/ske_cluster.md
Original file line number Diff line number Diff line change
Expand Up @@ -155,9 +155,27 @@ Read-Only:

Read-Only:

- `cni` (Attributes) Container Network Interface (CNI) of the cluster. (see [below for nested schema](#nestedatt--network--cni))
- `control_plane` (Attributes) Control plane for the cluster. (see [below for nested schema](#nestedatt--network--control_plane))
- `id` (String) ID of the STACKIT Network Area (SNA) network into which the cluster will be deployed.

<a id="nestedatt--network--cni"></a>
### Nested Schema for `network.cni`

Read-Only:

- `calico` (Attributes) Set if Calico is used as CNI. (see [below for nested schema](#nestedatt--network--cni--calico))
- `cilium` (Attributes) Set if Cilium is used as CNI. (see [below for nested schema](#nestedatt--network--cni--cilium))

<a id="nestedatt--network--cni--calico"></a>
### Nested Schema for `network.cni.calico`


<a id="nestedatt--network--cni--cilium"></a>
### Nested Schema for `network.cni.cilium`



<a id="nestedatt--network--control_plane"></a>
### Nested Schema for `network.control_plane`

Expand Down
21 changes: 21 additions & 0 deletions docs/resources/ske_cluster.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ resource "stackit_ske_cluster" "example" {
control_plane = {
access_scope = "PUBLIC"
}
cni = {
cilium = {}
}
}
# Cluster audit log forwarding to a Telemetry Router.
# Private preview: only configurable for enabled accounts.
Expand Down Expand Up @@ -240,9 +243,27 @@ Optional:

Optional:

- `cni` (Attributes) Container Network Interface (CNI) of the cluster. Exactly one of `calico` or `cilium` can be set. Defaults to Cilium. The field is immutable! (see [below for nested schema](#nestedatt--network--cni))
- `control_plane` (Attributes) Control plane for the cluster. (see [below for nested schema](#nestedatt--network--control_plane))
- `id` (String) ID of the STACKIT Network Area (SNA) network into which the cluster will be deployed.

<a id="nestedatt--network--cni"></a>
### Nested Schema for `network.cni`

Optional:

- `calico` (Attributes) Use Calico as CNI. Set to `{}` to enable. (see [below for nested schema](#nestedatt--network--cni--calico))
- `cilium` (Attributes) Use Cilium as CNI. Set to `{}` to enable. (see [below for nested schema](#nestedatt--network--cni--cilium))

<a id="nestedatt--network--cni--calico"></a>
### Nested Schema for `network.cni.calico`


<a id="nestedatt--network--cni--cilium"></a>
### Nested Schema for `network.cni.cilium`



<a id="nestedatt--network--control_plane"></a>
### Nested Schema for `network.control_plane`

Expand Down
3 changes: 3 additions & 0 deletions examples/resources/stackit_ske_cluster/resource.tf
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@ resource "stackit_ske_cluster" "example" {
control_plane = {
access_scope = "PUBLIC"
}
cni = {
cilium = {}
}
}
# Cluster audit log forwarding to a Telemetry Router.
# Private preview: only configurable for enabled accounts.
Expand Down
16 changes: 16 additions & 0 deletions stackit/internal/services/ske/cluster/datasource.go
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,22 @@ func (r *clusterDataSource) Schema(_ context.Context, _ datasource.SchemaRequest
},
},
},
"cni": schema.SingleNestedAttribute{
Description: "Container Network Interface (CNI) of the cluster.",
Computed: true,
Attributes: map[string]schema.Attribute{
"calico": schema.SingleNestedAttribute{
Description: "Set if Calico is used as CNI.",
Computed: true,
Attributes: map[string]schema.Attribute{},
},
"cilium": schema.SingleNestedAttribute{
Description: "Set if Cilium is used as CNI.",
Computed: true,
Attributes: map[string]schema.Attribute{},
},
},
},
},
},

Expand Down
111 changes: 110 additions & 1 deletion stackit/internal/services/ske/cluster/resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -179,14 +179,31 @@ var maintenanceTypes = map[string]attr.Type{
type network struct {
ID types.String `tfsdk:"id"`
ControlPlane types.Object `tfsdk:"control_plane"`
CNI types.Object `tfsdk:"cni"`
}

// Types corresponding to network
var networkTypes = map[string]attr.Type{
"id": basetypes.StringType{},
"control_plane": types.ObjectType{AttrTypes: controlPlaneTypes},
"cni": types.ObjectType{AttrTypes: cniTypes},
}

// Struct corresponding to network.CNI
type cni struct {
Calico types.Object `tfsdk:"calico"`
Cilium types.Object `tfsdk:"cilium"`
}

// Types corresponding to cni
var cniTypes = map[string]attr.Type{
"calico": types.ObjectType{AttrTypes: map[string]attr.Type{}},
"cilium": types.ObjectType{AttrTypes: map[string]attr.Type{}},
}

// The Cilium CNI is not modelled by the SDK yet and is sent as an additional property.
const ciliumCNIKey = "cilium"

type controlPlane struct {
AccessScope types.String `tfsdk:"access_scope"`
}
Expand Down Expand Up @@ -752,6 +769,36 @@ func (r *clusterResource) Schema(_ context.Context, _ resource.SchemaRequest, re
},
},
},
"cni": schema.SingleNestedAttribute{
Description: "Container Network Interface (CNI) of the cluster. Exactly one of `calico` or `cilium` can be set. Defaults to Cilium. The field is immutable!",
Optional: true,
Computed: true,
Default: objectdefault.StaticValue(types.ObjectValueMust(cniTypes, map[string]attr.Value{
"calico": types.ObjectNull(map[string]attr.Type{}),
"cilium": types.ObjectValueMust(map[string]attr.Type{}, map[string]attr.Value{}),
})),
PlanModifiers: []planmodifier.Object{
objectplanmodifier.RequiresReplace(),
},
Attributes: map[string]schema.Attribute{
"calico": schema.SingleNestedAttribute{
Description: "Use Calico as CNI. Set to `{}` to enable.",
Optional: true,
Validators: []validator.Object{
objectvalidator.ExactlyOneOf(path.MatchRelative().AtParent().AtName("cilium")),
},
Attributes: map[string]schema.Attribute{},
},
"cilium": schema.SingleNestedAttribute{
Description: "Use Cilium as CNI. Set to `{}` to enable.",
Optional: true,
Validators: []validator.Object{
objectvalidator.ExactlyOneOf(path.MatchRelative().AtParent().AtName("calico")),
},
Attributes: map[string]schema.Attribute{},
},
},
},
},
},
"hibernations": schema.ListNestedAttribute{
Expand Down Expand Up @@ -1556,7 +1603,7 @@ func toMaintenancePayload(ctx context.Context, m *Model) (*ske.Maintenance, erro

func toNetworkPayload(ctx context.Context, m *Model) (*ske.Network, error) {
if m.Network.IsNull() || m.Network.IsUnknown() {
return nil, nil
return &ske.Network{Cni: defaultCNIPayload()}, nil
}

network := network{}
Expand All @@ -1577,12 +1624,43 @@ func toNetworkPayload(ctx context.Context, m *Model) (*ske.Network, error) {
}
}

networkCNI, err := toCNIPayload(ctx, network.CNI)
if err != nil {
return nil, err
}

return &ske.Network{
Id: conversion.StringValueToPointer(network.ID),
ControlPlane: networkControlPlane,
Cni: networkCNI,
}, nil
}

func defaultCNIPayload() *ske.CNI {
return &ske.CNI{AdditionalProperties: map[string]interface{}{ciliumCNIKey: map[string]interface{}{}}}
}

func toCNIPayload(ctx context.Context, o types.Object) (*ske.CNI, error) {
if utils.IsUndefined(o) {
return defaultCNIPayload(), nil
}

cniModel := cni{}
diags := o.As(ctx, &cniModel, basetypes.ObjectAsOptions{})
if diags.HasError() {
return nil, fmt.Errorf("converting network cni: %w", core.DiagsToError(diags))
}

payload := &ske.CNI{}
switch {
case !utils.IsUndefined(cniModel.Calico):
payload.Calico = map[string]interface{}{}
case !utils.IsUndefined(cniModel.Cilium):
payload.AdditionalProperties = map[string]interface{}{ciliumCNIKey: map[string]interface{}{}}
}
return payload, nil
}

func mapFields(ctx context.Context, cl *ske.Cluster, m *Model, region string) error {
if cl == nil {
return fmt.Errorf("response input is nil")
Expand Down Expand Up @@ -1914,9 +1992,15 @@ func mapNetwork(cl *ske.Cluster, m *Model) error {
}
}

networkCNI, err := mapCNI(cl.Network.Cni)
if err != nil {
return err
}

networkValues := map[string]attr.Value{
"id": id,
"control_plane": networkControlPlane,
"cni": networkCNI,
}
networkObject, diags := types.ObjectValue(networkTypes, networkValues)
if diags.HasError() {
Expand All @@ -1926,6 +2010,31 @@ func mapNetwork(cl *ske.Cluster, m *Model) error {
return nil
}

func mapCNI(c *ske.CNI) (types.Object, error) {
if c == nil {
return types.ObjectNull(cniTypes), nil
}

emptyObject := types.ObjectValueMust(map[string]attr.Type{}, map[string]attr.Value{})
calico := types.ObjectNull(cniTypes["calico"].(types.ObjectType).AttrTypes)
cilium := types.ObjectNull(cniTypes["cilium"].(types.ObjectType).AttrTypes)
if c.Calico != nil {
calico = emptyObject
}
if _, ok := c.AdditionalProperties[ciliumCNIKey]; ok {
cilium = emptyObject
}

obj, diags := types.ObjectValue(cniTypes, map[string]attr.Value{
"calico": calico,
"cilium": cilium,
})
if diags.HasError() {
return types.ObjectNull(cniTypes), fmt.Errorf("create network cni object: %w", core.DiagsToError(diags))
}
return obj, nil
}

func getMaintenanceTimes(ctx context.Context, cl *ske.Cluster, m *Model) (startTime, endTime string, err error) {
var startTimeAPI, endTimeAPI time.Time
if cl.Maintenance.TimeWindow != nil {
Expand Down
34 changes: 29 additions & 5 deletions stackit/internal/services/ske/cluster/resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,8 @@ func TestMapFields(t *testing.T) {
"end": types.StringValue("13:14:15Z"),
}),
Network: types.ObjectValueMust(networkTypes, map[string]attr.Value{
"id": types.StringValue("nid"),
"cni": types.ObjectNull(cniTypes),
"id": types.StringValue("nid"),
"control_plane": types.ObjectValueMust(controlPlaneTypes, map[string]attr.Value{
"access_scope": types.StringValue("SNA"),
}),
Expand Down Expand Up @@ -770,7 +771,8 @@ func TestMapFields(t *testing.T) {
"end": types.StringValue("13:14:15Z"),
}),
Network: types.ObjectValueMust(networkTypes, map[string]attr.Value{
"id": types.StringValue("nid"),
"cni": types.ObjectNull(cniTypes),
"id": types.StringValue("nid"),
"control_plane": types.ObjectValueMust(controlPlaneTypes, map[string]attr.Value{
"access_scope": types.StringValue("SNA"),
}),
Expand Down Expand Up @@ -2365,7 +2367,8 @@ func TestToNetworkPayload(t *testing.T) {
ProjectId: types.StringValue("pid"),
Name: types.StringValue("name"),
Network: types.ObjectValueMust(networkTypes, map[string]attr.Value{
"id": types.StringValue("nid"),
"cni": types.ObjectNull(cniTypes),
"id": types.StringValue("nid"),
"control_plane": types.ObjectValueMust(controlPlaneTypes, map[string]attr.Value{
"access_scope": types.StringValue("SNA"),
}),
Expand All @@ -2376,6 +2379,7 @@ func TestToNetworkPayload(t *testing.T) {
ControlPlane: &ske.V2ControlPlaneNetwork{
AccessScope: ske.ACCESSSCOPE_SNA.Ptr(),
},
Cni: &ske.CNI{AdditionalProperties: map[string]interface{}{"cilium": map[string]interface{}{}}},
},
true,
},
Expand All @@ -2385,11 +2389,12 @@ func TestToNetworkPayload(t *testing.T) {
ProjectId: types.StringValue("pid"),
Name: types.StringValue("name"),
Network: types.ObjectValueMust(networkTypes, map[string]attr.Value{
"cni": types.ObjectNull(cniTypes),
"id": types.StringNull(),
"control_plane": types.ObjectNull(controlPlaneTypes),
}),
},
&ske.Network{},
&ske.Network{Cni: &ske.CNI{AdditionalProperties: map[string]interface{}{"cilium": map[string]interface{}{}}}},
true,
},
{
Expand All @@ -2398,13 +2403,15 @@ func TestToNetworkPayload(t *testing.T) {
ProjectId: types.StringValue("pid"),
Name: types.StringValue("name"),
Network: types.ObjectValueMust(networkTypes, map[string]attr.Value{
"cni": types.ObjectNull(cniTypes),
"id": types.StringValue("nid"),
"control_plane": types.ObjectNull(controlPlaneTypes),
}),
},
&ske.Network{
Id: new("nid"),
ControlPlane: nil,
Cni: &ske.CNI{AdditionalProperties: map[string]interface{}{"cilium": map[string]interface{}{}}},
},
true,
},
Expand All @@ -2415,7 +2422,24 @@ func TestToNetworkPayload(t *testing.T) {
Name: types.StringValue("name"),
Network: types.ObjectNull(networkTypes),
},
nil,
&ske.Network{Cni: &ske.CNI{AdditionalProperties: map[string]interface{}{"cilium": map[string]interface{}{}}}},
true,
},
{
"calico",
&Model{
ProjectId: types.StringValue("pid"),
Name: types.StringValue("name"),
Network: types.ObjectValueMust(networkTypes, map[string]attr.Value{
"id": types.StringNull(),
"control_plane": types.ObjectNull(controlPlaneTypes),
"cni": types.ObjectValueMust(cniTypes, map[string]attr.Value{
"calico": types.ObjectValueMust(map[string]attr.Type{}, map[string]attr.Value{}),
"cilium": types.ObjectNull(map[string]attr.Type{}),
}),
}),
},
&ske.Network{Cni: &ske.CNI{Calico: map[string]interface{}{}}},
true,
},
}
Expand Down
3 changes: 3 additions & 0 deletions stackit/internal/services/ske/ske_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,9 @@ resource "stackit_ske_cluster" "cluster" {
ControlPlane: new(ske.V2ControlPlaneNetwork{
AccessScope: new(ske.ACCESSSCOPE_PUBLIC),
}),
Cni: &ske.CNI{
AdditionalProperties: map[string]interface{}{"cilium": map[string]interface{}{}},
},
},
Maintenance: new(ske.Maintenance{
AutoUpdate: &ske.MaintenanceAutoUpdate{
Expand Down
2 changes: 1 addition & 1 deletion stackit/internal/services/ske/utils/util.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import (
)

func IsEmptyNetwork(network *ske.Network) bool {
if !network.HasId() && !network.HasControlPlane() {
if !network.HasId() && !network.HasControlPlane() && !network.HasCni() {
return true
}
return false
Expand Down