feat(loadbalancer): support for idle timeout (TCP and UDP) (#1039)

This commit is contained in:
Björn Fischer 2025-10-27 18:43:56 +01:00 committed by GitHub
parent e0b2c098f2
commit e4e2e55e94
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 371 additions and 75 deletions

View file

@ -107,6 +107,10 @@ func (r *loadBalancerDataSource) Schema(_ context.Context, _ datasource.SchemaRe
"targets.display_name": "Target display name",
"ip": "Target IP",
"region": "The resource region. If not defined, the provider region is used.",
"tcp_options": "Options that are specific to the TCP protocol.",
"tcp_options_idle_timeout": "Time after which an idle connection is closed. The default value is set to 5 minutes, and the maximum value is one hour.",
"udp_options": "Options that are specific to the UDP protocol.",
"udp_options_idle_timeout": "Time after which an idle session is closed. The default value is set to 1 minute, and the maximum value is 2 minutes.",
}
resp.Schema = schema.Schema{
@ -171,6 +175,26 @@ func (r *loadBalancerDataSource) Schema(_ context.Context, _ datasource.SchemaRe
Description: descriptions["target_pool"],
Computed: true,
},
"tcp": schema.SingleNestedAttribute{
Description: descriptions["tcp_options"],
Computed: true,
Attributes: map[string]schema.Attribute{
"idle_timeout": schema.StringAttribute{
Description: descriptions["tcp_options_idle_timeout"],
Computed: true,
},
},
},
"udp": schema.SingleNestedAttribute{
Description: descriptions["udp_options"],
Computed: true,
Attributes: map[string]schema.Attribute{
"idle_timeout": schema.StringAttribute{
Description: descriptions["udp_options_idle_timeout"],
Computed: true,
},
},
},
},
},
},

View file

@ -72,6 +72,8 @@ type listener struct {
Protocol types.String `tfsdk:"protocol"`
ServerNameIndicators types.List `tfsdk:"server_name_indicators"`
TargetPool types.String `tfsdk:"target_pool"`
TCP types.Object `tfsdk:"tcp"`
UDP types.Object `tfsdk:"udp"`
}
// Types corresponding to listener
@ -81,6 +83,8 @@ var listenerTypes = map[string]attr.Type{
"protocol": types.StringType,
"server_name_indicators": types.ListType{ElemType: types.ObjectType{AttrTypes: serverNameIndicatorTypes}},
"target_pool": types.StringType,
"tcp": types.ObjectType{AttrTypes: tcpTypes},
"udp": types.ObjectType{AttrTypes: udpTypes},
}
// Struct corresponding to listener.ServerNameIndicators[i]
@ -93,6 +97,22 @@ var serverNameIndicatorTypes = map[string]attr.Type{
"name": types.StringType,
}
type tcp struct {
IdleTimeout types.String `tfsdk:"idle_timeout"`
}
var tcpTypes = map[string]attr.Type{
"idle_timeout": types.StringType,
}
type udp struct {
IdleTimeout types.String `tfsdk:"idle_timeout"`
}
var udpTypes = map[string]attr.Type{
"idle_timeout": types.StringType,
}
// Struct corresponding to Model.Networks[i]
type network struct {
NetworkId types.String `tfsdk:"network_id"`
@ -345,6 +365,10 @@ func (r *loadBalancerResource) Schema(_ context.Context, _ resource.SchemaReques
"ip": "Target IP",
"region": "The resource region. If not defined, the provider region is used.",
"security_group_id": "The ID of the egress security group assigned to the Load Balancer's internal machines. This ID is essential for allowing traffic from the Load Balancer to targets in different networks or STACKIT network areas (SNA). To enable this, create a security group rule for your target VMs and set the `remote_security_group_id` of that rule to this value. This is typically used when `disable_security_group_assignment` is set to `true`.",
"tcp_options": "Options that are specific to the TCP protocol.",
"tcp_options_idle_timeout": "Time after which an idle connection is closed. The default value is set to 300 seconds, and the maximum value is 3600 seconds. The format is a duration and the unit must be seconds. Example: 30s",
"udp_options": "Options that are specific to the UDP protocol.",
"udp_options_idle_timeout": "Time after which an idle session is closed. The default value is set to 1 minute, and the maximum value is 2 minutes. The format is a duration and the unit must be seconds. Example: 30s",
}
resp.Schema = schema.Schema{
@ -456,6 +480,27 @@ The example below creates the supporting infrastructure using the STACKIT Terraf
stringplanmodifier.UseStateForUnknown(),
},
},
"tcp": schema.SingleNestedAttribute{
Description: descriptions["tcp_options"],
Optional: true,
Attributes: map[string]schema.Attribute{
"idle_timeout": schema.StringAttribute{
Description: descriptions["tcp_options_idle_timeout"],
Optional: true,
},
},
},
"udp": schema.SingleNestedAttribute{
Description: descriptions["udp_options"],
Optional: true,
Computed: false,
Attributes: map[string]schema.Attribute{
"idle_timeout": schema.StringAttribute{
Description: descriptions["udp_options_idle_timeout"],
Optional: true,
},
},
},
},
},
},
@ -907,6 +952,7 @@ func (r *loadBalancerResource) ImportState(ctx context.Context, req resource.Imp
tflog.Info(ctx, "Load balancer state imported")
}
// toCreatePayload and all other toX functions in this file turn a Terraform load balancer model into a createLoadBalancerPayload to be used with the load balancer API.
func toCreatePayload(ctx context.Context, model *Model) (*loadbalancer.CreateLoadBalancerPayload, error) {
if model == nil {
return nil, fmt.Errorf("nil model")
@ -963,12 +1009,22 @@ func toListenersPayload(ctx context.Context, model *Model) (*[]loadbalancer.List
if err != nil {
return nil, fmt.Errorf("converting index %d: converting server_name_indicator: %w", i, err)
}
tcp, err := toTCP(ctx, &listenerModel)
if err != nil {
return nil, fmt.Errorf("converting index %d: converting tcp: %w", i, err)
}
udp, err := toUDP(ctx, &listenerModel)
if err != nil {
return nil, fmt.Errorf("converting index %d: converting udp: %w", i, err)
}
payload = append(payload, loadbalancer.Listener{
DisplayName: conversion.StringValueToPointer(listenerModel.DisplayName),
Port: conversion.Int64ValueToPointer(listenerModel.Port),
Protocol: loadbalancer.ListenerGetProtocolAttributeType(conversion.StringValueToPointer(listenerModel.Protocol)),
ServerNameIndicators: serverNameIndicatorsPayload,
TargetPool: conversion.StringValueToPointer(listenerModel.TargetPool),
Tcp: tcp,
Udp: udp,
})
}
@ -997,6 +1053,44 @@ func toServerNameIndicatorsPayload(ctx context.Context, l *listener) (*[]loadbal
return &payload, nil
}
func toTCP(ctx context.Context, listener *listener) (*loadbalancer.OptionsTCP, error) {
if listener.TCP.IsNull() || listener.TCP.IsUnknown() {
return nil, nil
}
tcp := tcp{}
diags := listener.TCP.As(ctx, &tcp, basetypes.ObjectAsOptions{})
if diags.HasError() {
return nil, core.DiagsToError(diags)
}
if tcp.IdleTimeout.IsNull() || tcp.IdleTimeout.IsUnknown() {
return nil, nil
}
return &loadbalancer.OptionsTCP{
IdleTimeout: tcp.IdleTimeout.ValueStringPointer(),
}, nil
}
func toUDP(ctx context.Context, listener *listener) (*loadbalancer.OptionsUDP, error) {
if listener.UDP.IsNull() || listener.UDP.IsUnknown() {
return nil, nil
}
udp := udp{}
diags := listener.UDP.As(ctx, &udp, basetypes.ObjectAsOptions{})
if diags.HasError() {
return nil, core.DiagsToError(diags)
}
if udp.IdleTimeout.IsNull() || udp.IdleTimeout.IsUnknown() {
return nil, nil
}
return &loadbalancer.OptionsUDP{
IdleTimeout: udp.IdleTimeout.ValueStringPointer(),
}, nil
}
func toNetworksPayload(ctx context.Context, model *Model) (*[]loadbalancer.Network, error) {
if model.Networks.IsNull() || model.Networks.IsUnknown() {
return nil, nil
@ -1222,6 +1316,7 @@ func toTargetsPayload(ctx context.Context, tp *targetPool) (*[]loadbalancer.Targ
return &payload, nil
}
// mapFields and all other map functions in this file translate an API resource into a Terraform model.
func mapFields(ctx context.Context, lb *loadbalancer.LoadBalancer, m *Model, region string) error {
if lb == nil {
return fmt.Errorf("response input is nil")
@ -1292,6 +1387,16 @@ func mapListeners(loadBalancerResp *loadbalancer.LoadBalancer, m *Model) error {
return fmt.Errorf("mapping index %d, field serverNameIndicators: %w", i, err)
}
err = mapTCP(listenerResp.Tcp, listenerMap)
if err != nil {
return fmt.Errorf("mapping index %d, field tcp: %w", i, err)
}
err = mapUDP(listenerResp.Udp, listenerMap)
if err != nil {
return fmt.Errorf("mapping index %d, field udp: %w", i, err)
}
listenerTF, diags := types.ObjectValue(listenerTypes, listenerMap)
if diags.HasError() {
return fmt.Errorf("mapping index %d: %w", i, core.DiagsToError(diags))
@ -1344,6 +1449,40 @@ func mapServerNameIndicators(serverNameIndicatorsResp *[]loadbalancer.ServerName
return nil
}
func mapTCP(tcp *loadbalancer.OptionsTCP, listener map[string]attr.Value) error {
if tcp == nil || tcp.IdleTimeout == nil || *tcp.IdleTimeout == "" {
listener["tcp"] = types.ObjectNull(tcpTypes)
return nil
}
tcpAttr, diags := types.ObjectValue(tcpTypes, map[string]attr.Value{
"idle_timeout": types.StringValue(*tcp.IdleTimeout),
})
if diags.HasError() {
return core.DiagsToError(diags)
}
listener["tcp"] = tcpAttr
return nil
}
func mapUDP(udp *loadbalancer.OptionsUDP, listener map[string]attr.Value) error {
if udp == nil || udp.IdleTimeout == nil || *udp.IdleTimeout == "" {
listener["udp"] = types.ObjectNull(udpTypes)
return nil
}
udpAttr, diags := types.ObjectValue(udpTypes, map[string]attr.Value{
"idle_timeout": types.StringValue(*udp.IdleTimeout),
})
if diags.HasError() {
return core.DiagsToError(diags)
}
listener["udp"] = udpAttr
return nil
}
func mapNetworks(loadBalancerResp *loadbalancer.LoadBalancer, m *Model) error {
if loadBalancerResp.Networks == nil {
m.Networks = types.ListNull(types.ObjectType{AttrTypes: networkTypes})

View file

@ -62,6 +62,12 @@ func TestToCreatePayload(t *testing.T) {
},
),
"target_pool": types.StringValue("target_pool"),
"tcp": types.ObjectValueMust(tcpTypes, map[string]attr.Value{
"idle_timeout": types.StringValue("50s"),
}),
"udp": types.ObjectValueMust(udpTypes, map[string]attr.Value{
"idle_timeout": types.StringValue("50s"),
}),
}),
}),
Name: types.StringValue("name"),
@ -130,6 +136,12 @@ func TestToCreatePayload(t *testing.T) {
},
},
TargetPool: utils.Ptr("target_pool"),
Tcp: &loadbalancer.OptionsTCP{
IdleTimeout: utils.Ptr("50s"),
},
Udp: &loadbalancer.OptionsUDP{
IdleTimeout: utils.Ptr("50s"),
},
},
},
Name: utils.Ptr("name"),
@ -204,6 +216,8 @@ func TestToCreatePayload(t *testing.T) {
},
),
"target_pool": types.StringValue("target_pool"),
"tcp": types.ObjectNull(tcpTypes),
"udp": types.ObjectNull(udpTypes),
}),
}),
Name: types.StringValue("name"),
@ -511,6 +525,12 @@ func TestMapFields(t *testing.T) {
},
},
TargetPool: utils.Ptr("target_pool"),
Tcp: &loadbalancer.OptionsTCP{
IdleTimeout: utils.Ptr("50s"),
},
Udp: &loadbalancer.OptionsUDP{
IdleTimeout: utils.Ptr("50s"),
},
},
}),
Name: utils.Ptr("name"),
@ -586,6 +606,12 @@ func TestMapFields(t *testing.T) {
},
),
"target_pool": types.StringValue("target_pool"),
"tcp": types.ObjectValueMust(tcpTypes, map[string]attr.Value{
"idle_timeout": types.StringValue("50s"),
}),
"udp": types.ObjectValueMust(udpTypes, map[string]attr.Value{
"idle_timeout": types.StringValue("50s"),
}),
}),
}),
Name: types.StringValue("name"),
@ -730,6 +756,8 @@ func TestMapFields(t *testing.T) {
},
),
"target_pool": types.StringValue("target_pool"),
"tcp": types.ObjectNull(tcpTypes),
"udp": types.ObjectNull(udpTypes),
}),
}),
Name: types.StringValue("name"),

View file

@ -52,25 +52,35 @@ var testConfigVarsMax = config.Variables{
"plan_id": config.StringVariable("p10"),
"disable_security_group_assignment": config.BoolVariable(true),
"network_name": config.StringVariable(fmt.Sprintf("tf-acc-n%s", acctest.RandStringFromCharSet(7, acctest.CharSetAlphaNum))),
"network_role": config.StringVariable("ROLE_LISTENERS_AND_TARGETS"),
"server_name": config.StringVariable(fmt.Sprintf("tf-acc-s%s", acctest.RandStringFromCharSet(7, acctest.CharSetAlphaNum))),
"loadbalancer_name": config.StringVariable(fmt.Sprintf("tf-acc-l%s", acctest.RandStringFromCharSet(7, acctest.CharSetAlphaNum))),
"target_pool_name": config.StringVariable("example-target-pool"),
"target_port": config.StringVariable("5432"),
"target_display_name": config.StringVariable("example-target"),
"listener_port": config.StringVariable("5432"),
"listener_protocol": config.StringVariable("PROTOCOL_TLS_PASSTHROUGH"),
"network_role": config.StringVariable("ROLE_LISTENERS_AND_TARGETS"),
"listener_display_name": config.StringVariable("example-listener"),
"listener_server_name_indicators": config.StringVariable("acc-test.runs.onstackit.cloud"),
"healthy_threshold": config.StringVariable("3"),
"health_interval": config.StringVariable("10s"),
"health_interval_jitter": config.StringVariable("5s"),
"health_timeout": config.StringVariable("10s"),
"unhealthy_threshold": config.StringVariable("3"),
"use_source_ip_address": config.StringVariable("true"),
"private_network_only": config.StringVariable("false"),
"acl": config.StringVariable("192.168.0.0/24"),
"target_display_name": config.StringVariable("example-target"),
"sni_target_pool_name": config.StringVariable("example-target-pool"),
"sni_target_port": config.StringVariable("5432"),
"sni_listener_port": config.StringVariable("5432"),
"sni_listener_protocol": config.StringVariable("PROTOCOL_TLS_PASSTHROUGH"),
"sni_idle_timeout": config.StringVariable("42s"),
"sni_listener_display_name": config.StringVariable("example-listener"),
"sni_listener_server_name_indicators": config.StringVariable("acc-test.runs.onstackit.cloud"),
"sni_healthy_threshold": config.StringVariable("3"),
"sni_health_interval": config.StringVariable("10s"),
"sni_health_interval_jitter": config.StringVariable("5s"),
"sni_health_timeout": config.StringVariable("10s"),
"sni_unhealthy_threshold": config.StringVariable("3"),
"sni_use_source_ip_address": config.StringVariable("true"),
"udp_target_pool_name": config.StringVariable("udp-target-pool"),
"udp_target_port": config.StringVariable("53"),
"udp_listener_port": config.StringVariable("53"),
"udp_listener_protocol": config.StringVariable("PROTOCOL_UDP"),
"udp_idle_timeout": config.StringVariable("43s"),
"udp_listener_display_name": config.StringVariable("udp-listener"),
"private_network_only": config.StringVariable("false"),
"acl": config.StringVariable("192.168.0.0/24"),
"observability_logs_push_url": config.StringVariable("https://logs.observability.dummy.stackit.cloud"),
"observability_metrics_push_url": config.StringVariable("https://metrics.observability.dummy.stackit.cloud"),
@ -92,7 +102,7 @@ func configVarsMinUpdated() config.Variables {
func configVarsMaxUpdated() config.Variables {
tempConfig := make(config.Variables, len(testConfigVarsMax))
maps.Copy(tempConfig, testConfigVarsMax)
tempConfig["target_port"] = config.StringVariable("5431")
tempConfig["sni_target_port"] = config.StringVariable("5431")
return tempConfig
}
@ -235,27 +245,39 @@ func TestAccLoadBalancerResourceMax(t *testing.T) {
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "project_id", testutil.ConvertConfigVariable(testConfigVarsMax["project_id"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "name", testutil.ConvertConfigVariable(testConfigVarsMax["loadbalancer_name"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "plan_id", testutil.ConvertConfigVariable(testConfigVarsMax["plan_id"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "target_pools.0.name", testutil.ConvertConfigVariable(testConfigVarsMax["target_pool_name"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "target_pools.0.target_port", testutil.ConvertConfigVariable(testConfigVarsMax["target_port"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "target_pools.0.targets.0.display_name", testutil.ConvertConfigVariable(testConfigVarsMax["target_display_name"])),
resource.TestCheckResourceAttrSet("stackit_loadbalancer.loadbalancer", "target_pools.0.targets.0.ip"),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "listeners.0.display_name", testutil.ConvertConfigVariable(testConfigVarsMax["listener_display_name"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "listeners.0.port", testutil.ConvertConfigVariable(testConfigVarsMax["listener_port"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "listeners.0.protocol", testutil.ConvertConfigVariable(testConfigVarsMax["listener_protocol"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "listeners.0.target_pool", testutil.ConvertConfigVariable(testConfigVarsMax["target_pool_name"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "listeners.0.server_name_indicators.0.name", testutil.ConvertConfigVariable(testConfigVarsMax["listener_server_name_indicators"])),
resource.TestCheckResourceAttrSet("stackit_loadbalancer.loadbalancer", "networks.0.network_id"),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "networks.0.role", testutil.ConvertConfigVariable(testConfigVarsMax["network_role"])),
resource.TestCheckResourceAttrSet("stackit_loadbalancer.loadbalancer", "external_address"),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "disable_security_group_assignment", testutil.ConvertConfigVariable(testConfigVarsMax["disable_security_group_assignment"])),
resource.TestCheckResourceAttrSet("stackit_loadbalancer.loadbalancer", "security_group_id"),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "target_pools.0.active_health_check.healthy_threshold", testutil.ConvertConfigVariable(testConfigVarsMax["healthy_threshold"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "target_pools.0.active_health_check.interval", testutil.ConvertConfigVariable(testConfigVarsMax["health_interval"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "target_pools.0.active_health_check.interval_jitter", testutil.ConvertConfigVariable(testConfigVarsMax["health_interval_jitter"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "target_pools.0.active_health_check.timeout", testutil.ConvertConfigVariable(testConfigVarsMax["health_timeout"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "target_pools.0.active_health_check.unhealthy_threshold", testutil.ConvertConfigVariable(testConfigVarsMax["unhealthy_threshold"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "target_pools.0.session_persistence.use_source_ip_address", testutil.ConvertConfigVariable(testConfigVarsMax["use_source_ip_address"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "listeners.0.display_name", testutil.ConvertConfigVariable(testConfigVarsMax["sni_listener_display_name"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "listeners.0.port", testutil.ConvertConfigVariable(testConfigVarsMax["sni_listener_port"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "listeners.0.protocol", testutil.ConvertConfigVariable(testConfigVarsMax["sni_listener_protocol"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "listeners.0.target_pool", testutil.ConvertConfigVariable(testConfigVarsMax["sni_target_pool_name"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "listeners.0.server_name_indicators.0.name", testutil.ConvertConfigVariable(testConfigVarsMax["sni_listener_server_name_indicators"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "listeners.0.tcp.idle_timeout", testutil.ConvertConfigVariable(testConfigVarsMax["sni_idle_timeout"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "target_pools.0.name", testutil.ConvertConfigVariable(testConfigVarsMax["sni_target_pool_name"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "target_pools.0.target_port", testutil.ConvertConfigVariable(testConfigVarsMax["sni_target_port"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "target_pools.0.targets.0.display_name", testutil.ConvertConfigVariable(testConfigVarsMax["target_display_name"])),
resource.TestCheckResourceAttrSet("stackit_loadbalancer.loadbalancer", "target_pools.0.targets.0.ip"),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "target_pools.0.active_health_check.healthy_threshold", testutil.ConvertConfigVariable(testConfigVarsMax["sni_healthy_threshold"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "target_pools.0.active_health_check.interval", testutil.ConvertConfigVariable(testConfigVarsMax["sni_health_interval"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "target_pools.0.active_health_check.interval_jitter", testutil.ConvertConfigVariable(testConfigVarsMax["sni_health_interval_jitter"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "target_pools.0.active_health_check.timeout", testutil.ConvertConfigVariable(testConfigVarsMax["sni_health_timeout"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "target_pools.0.active_health_check.unhealthy_threshold", testutil.ConvertConfigVariable(testConfigVarsMax["sni_unhealthy_threshold"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "listeners.1.display_name", testutil.ConvertConfigVariable(testConfigVarsMax["udp_listener_display_name"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "listeners.1.port", testutil.ConvertConfigVariable(testConfigVarsMax["udp_listener_port"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "listeners.1.protocol", testutil.ConvertConfigVariable(testConfigVarsMax["udp_listener_protocol"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "listeners.1.target_pool", testutil.ConvertConfigVariable(testConfigVarsMax["udp_target_pool_name"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "listeners.1.udp.idle_timeout", testutil.ConvertConfigVariable(testConfigVarsMax["udp_idle_timeout"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "target_pools.1.name", testutil.ConvertConfigVariable(testConfigVarsMax["udp_target_pool_name"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "target_pools.1.target_port", testutil.ConvertConfigVariable(testConfigVarsMax["udp_target_port"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "target_pools.1.targets.0.display_name", testutil.ConvertConfigVariable(testConfigVarsMax["target_display_name"])),
resource.TestCheckResourceAttrSet("stackit_loadbalancer.loadbalancer", "target_pools.1.targets.0.ip"),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "target_pools.0.session_persistence.use_source_ip_address", testutil.ConvertConfigVariable(testConfigVarsMax["sni_use_source_ip_address"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "options.private_network_only", testutil.ConvertConfigVariable(testConfigVarsMax["private_network_only"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "options.acl.0", testutil.ConvertConfigVariable(testConfigVarsMax["acl"])),
@ -306,26 +328,35 @@ func TestAccLoadBalancerResourceMax(t *testing.T) {
"stackit_loadbalancer.loadbalancer", "name",
),
// Load balancer instance
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "target_pools.0.name", testutil.ConvertConfigVariable(testConfigVarsMax["target_pool_name"])),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "target_pools.0.target_port", testutil.ConvertConfigVariable(testConfigVarsMax["target_port"])),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "target_pools.0.targets.0.display_name", testutil.ConvertConfigVariable(testConfigVarsMax["target_display_name"])),
resource.TestCheckResourceAttrSet("data.stackit_loadbalancer.loadbalancer", "target_pools.0.targets.0.ip"),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "listeners.0.display_name", testutil.ConvertConfigVariable(testConfigVarsMax["listener_display_name"])),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "listeners.0.port", testutil.ConvertConfigVariable(testConfigVarsMax["listener_port"])),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "listeners.0.protocol", testutil.ConvertConfigVariable(testConfigVarsMax["listener_protocol"])),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "listeners.0.target_pool", testutil.ConvertConfigVariable(testConfigVarsMax["target_pool_name"])),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "listeners.0.server_name_indicators.0.name", testutil.ConvertConfigVariable(testConfigVarsMax["listener_server_name_indicators"])),
resource.TestCheckResourceAttrSet("data.stackit_loadbalancer.loadbalancer", "networks.0.network_id"),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "networks.0.role", testutil.ConvertConfigVariable(testConfigVarsMax["network_role"])),
resource.TestCheckResourceAttrSet("data.stackit_loadbalancer.loadbalancer", "external_address"),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "disable_security_group_assignment", testutil.ConvertConfigVariable(testConfigVarsMax["disable_security_group_assignment"])),
resource.TestCheckResourceAttrSet("stackit_loadbalancer.loadbalancer", "security_group_id"),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "target_pools.0.active_health_check.healthy_threshold", testutil.ConvertConfigVariable(testConfigVarsMax["healthy_threshold"])),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "target_pools.0.active_health_check.interval", testutil.ConvertConfigVariable(testConfigVarsMax["health_interval"])),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "target_pools.0.active_health_check.interval_jitter", testutil.ConvertConfigVariable(testConfigVarsMax["health_interval_jitter"])),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "target_pools.0.active_health_check.timeout", testutil.ConvertConfigVariable(testConfigVarsMax["health_timeout"])),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "target_pools.0.active_health_check.unhealthy_threshold", testutil.ConvertConfigVariable(testConfigVarsMax["unhealthy_threshold"])),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "target_pools.0.session_persistence.use_source_ip_address", testutil.ConvertConfigVariable(testConfigVarsMax["use_source_ip_address"])),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "target_pools.0.name", testutil.ConvertConfigVariable(testConfigVarsMax["sni_target_pool_name"])),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "target_pools.0.target_port", testutil.ConvertConfigVariable(testConfigVarsMax["sni_target_port"])),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "target_pools.0.targets.0.display_name", testutil.ConvertConfigVariable(testConfigVarsMax["target_display_name"])),
resource.TestCheckResourceAttrSet("data.stackit_loadbalancer.loadbalancer", "target_pools.0.targets.0.ip"),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "listeners.0.display_name", testutil.ConvertConfigVariable(testConfigVarsMax["sni_listener_display_name"])),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "listeners.0.port", testutil.ConvertConfigVariable(testConfigVarsMax["sni_listener_port"])),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "listeners.0.protocol", testutil.ConvertConfigVariable(testConfigVarsMax["sni_listener_protocol"])),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "listeners.0.target_pool", testutil.ConvertConfigVariable(testConfigVarsMax["sni_target_pool_name"])),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "listeners.0.server_name_indicators.0.name", testutil.ConvertConfigVariable(testConfigVarsMax["sni_listener_server_name_indicators"])),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "listeners.0.tcp.idle_timeout", testutil.ConvertConfigVariable(testConfigVarsMax["sni_idle_timeout"])),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "target_pools.0.active_health_check.healthy_threshold", testutil.ConvertConfigVariable(testConfigVarsMax["sni_healthy_threshold"])),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "target_pools.0.active_health_check.interval", testutil.ConvertConfigVariable(testConfigVarsMax["sni_health_interval"])),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "target_pools.0.active_health_check.interval_jitter", testutil.ConvertConfigVariable(testConfigVarsMax["sni_health_interval_jitter"])),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "target_pools.0.active_health_check.timeout", testutil.ConvertConfigVariable(testConfigVarsMax["sni_health_timeout"])),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "target_pools.0.active_health_check.unhealthy_threshold", testutil.ConvertConfigVariable(testConfigVarsMax["sni_unhealthy_threshold"])),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "target_pools.0.session_persistence.use_source_ip_address", testutil.ConvertConfigVariable(testConfigVarsMax["sni_use_source_ip_address"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "listeners.1.display_name", testutil.ConvertConfigVariable(testConfigVarsMax["udp_listener_display_name"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "listeners.1.port", testutil.ConvertConfigVariable(testConfigVarsMax["udp_listener_port"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "listeners.1.protocol", testutil.ConvertConfigVariable(testConfigVarsMax["udp_listener_protocol"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "listeners.1.target_pool", testutil.ConvertConfigVariable(testConfigVarsMax["udp_target_pool_name"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "listeners.1.udp.idle_timeout", testutil.ConvertConfigVariable(testConfigVarsMax["udp_idle_timeout"])),
resource.TestCheckResourceAttr("data.stackit_loadbalancer.loadbalancer", "options.acl.0", testutil.ConvertConfigVariable(testConfigVarsMax["acl"])),
resource.TestCheckResourceAttrSet("data.stackit_loadbalancer.loadbalancer", "options.observability.logs.credentials_ref"),
resource.TestCheckResourceAttrPair("stackit_loadbalancer_observability_credential.logs", "credentials_ref", "data.stackit_loadbalancer.loadbalancer", "options.observability.logs.credentials_ref"),
@ -368,7 +399,7 @@ func TestAccLoadBalancerResourceMax(t *testing.T) {
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "project_id", testutil.ConvertConfigVariable(testConfigVarsMax["project_id"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "name", testutil.ConvertConfigVariable(testConfigVarsMax["loadbalancer_name"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "target_pools.0.target_port", testutil.ConvertConfigVariable(configVarsMaxUpdated()["target_port"])),
resource.TestCheckResourceAttr("stackit_loadbalancer.loadbalancer", "target_pools.0.target_port", testutil.ConvertConfigVariable(configVarsMaxUpdated()["sni_target_port"])),
),
},
// Deletion is done by the framework implicitly

View file

@ -1,26 +1,36 @@
variable "project_id" {}
variable "network_name" {}
variable "network_role" {}
variable "server_name" {}
variable "loadbalancer_name" {}
variable "plan_id" {}
variable "target_pool_name" {}
variable "target_port" {}
variable "target_display_name" {}
variable "listener_port" {}
variable "listener_protocol" {}
variable "network_role" {}
variable "disable_security_group_assignment" {}
variable "listener_display_name" {}
variable "listener_server_name_indicators" {}
variable "healthy_threshold" {}
variable "health_interval" {}
variable "health_interval_jitter" {}
variable "health_timeout" {}
variable "unhealthy_threshold" {}
variable "use_source_ip_address" {}
variable "target_display_name" {}
variable "sni_target_pool_name" {}
variable "sni_target_port" {}
variable "sni_listener_port" {}
variable "sni_listener_protocol" {}
variable "sni_idle_timeout" {}
variable "sni_listener_display_name" {}
variable "sni_listener_server_name_indicators" {}
variable "sni_healthy_threshold" {}
variable "sni_health_interval" {}
variable "sni_health_interval_jitter" {}
variable "sni_health_timeout" {}
variable "sni_unhealthy_threshold" {}
variable "sni_use_source_ip_address" {}
variable "udp_target_pool_name" {}
variable "udp_target_port" {}
variable "udp_listener_port" {}
variable "udp_listener_protocol" {}
variable "udp_idle_timeout" {}
variable "udp_listener_display_name" {}
variable "private_network_only" {}
variable "acl" {}
@ -84,8 +94,8 @@ resource "stackit_loadbalancer" "loadbalancer" {
disable_security_group_assignment = var.disable_security_group_assignment
target_pools = [
{
name = var.target_pool_name
target_port = var.target_port
name = var.sni_target_pool_name
target_port = var.sni_target_port
targets = [
{
display_name = var.target_display_name
@ -93,28 +103,50 @@ resource "stackit_loadbalancer" "loadbalancer" {
}
]
active_health_check = {
healthy_threshold = var.healthy_threshold
interval = var.health_interval
interval_jitter = var.health_interval_jitter
timeout = var.health_timeout
unhealthy_threshold = var.unhealthy_threshold
healthy_threshold = var.sni_healthy_threshold
interval = var.sni_health_interval
interval_jitter = var.sni_health_interval_jitter
timeout = var.sni_health_timeout
unhealthy_threshold = var.sni_unhealthy_threshold
}
session_persistence = {
use_source_ip_address = var.use_source_ip_address
use_source_ip_address = var.sni_use_source_ip_address
}
},
{
name = var.udp_target_pool_name
target_port = var.udp_target_port
targets = [
{
display_name = var.target_display_name
ip = stackit_network_interface.network_interface.ipv4
}
]
}
]
listeners = [
{
display_name = var.listener_display_name
port = var.listener_port
protocol = var.listener_protocol
target_pool = var.target_pool_name
display_name = var.sni_listener_display_name
port = var.sni_listener_port
protocol = var.sni_listener_protocol
target_pool = var.sni_target_pool_name
server_name_indicators = [
{
name = var.listener_server_name_indicators
name = var.sni_listener_server_name_indicators
}
]
tcp = {
idle_timeout = var.sni_idle_timeout
}
},
{
display_name = var.udp_listener_display_name
port = var.udp_listener_port
protocol = var.udp_listener_protocol
target_pool = var.udp_target_pool_name
udp = {
idle_timeout = var.udp_idle_timeout
}
}
]
networks = [