From 5a7b000aac20971644f51bba713dfa9760776dc0 Mon Sep 17 00:00:00 2001 From: ezilber-akamai Date: Thu, 16 Jan 2025 10:00:47 -0500 Subject: [PATCH] Added support for NodeBalancers UDP --- docs/data-sources/nodebalancer.md | 2 + docs/data-sources/nodebalancer_config.md | 4 + docs/data-sources/nodebalancer_configs.md | 4 + docs/resources/nodebalancer.md | 3 + docs/resources/nodebalancer_config.md | 5 ++ go.mod | 4 +- go.sum | 8 +- linode/nb/datasource_test.go | 1 + linode/nb/framework_datasource_schema.go | 4 + linode/nb/framework_models.go | 59 ++++++------ linode/nb/framework_models_unit_test.go | 20 +++-- linode/nb/framework_resource.go | 29 ++++-- linode/nb/framework_resource_schema.go | 9 ++ linode/nb/resource_test.go | 20 +++++ linode/nb/tmpl/basic.gotf | 1 + linode/nb/tmpl/updates.gotf | 1 + linode/nbconfig/datasource_test.go | 2 + linode/nbconfig/framework_models.go | 90 +++++++++++-------- .../nbconfig/framework_schema_datasource.go | 8 ++ linode/nbconfig/framework_schema_resource.go | 16 ++++ linode/nbconfig/resource_test.go | 3 + linode/nbconfig/tmpl/updates.gotf | 1 + linode/nbconfigs/datasource_test.go | 2 + 23 files changed, 213 insertions(+), 83 deletions(-) diff --git a/docs/data-sources/nodebalancer.md b/docs/data-sources/nodebalancer.md index 91aae122e..4475f96dd 100644 --- a/docs/data-sources/nodebalancer.md +++ b/docs/data-sources/nodebalancer.md @@ -31,6 +31,8 @@ In addition to all arguments above, the following attributes are exported: * `client_conn_throttle` - Throttle connections per second (0-20). +* `client_udp_sess_throttle` - Throttle UDP sessions per second (0-20). + * `created` – When this Linode NodeBalancer was created * `linode_id` - The ID of a Linode Instance where the NodeBalancer should be attached. diff --git a/docs/data-sources/nodebalancer_config.md b/docs/data-sources/nodebalancer_config.md index 7d3c38efa..60cb49b63 100644 --- a/docs/data-sources/nodebalancer_config.md +++ b/docs/data-sources/nodebalancer_config.md @@ -54,6 +54,10 @@ In addition to all arguments above, the following attributes are exported: * `check_passive` - If true, any response from this backend with a 5xx status code will be enough for it to be considered unhealthy and taken out of rotation. +* `udp_check_port` - Specifies the port on the backend node used for active health checks, which may differ from the port serving traffic. + +* `udp_session_timeout` - The idle time in seconds after which a session that hasn’t received packets is destroyed. + * `cipher_suite` - What ciphers to use for SSL connections served by this NodeBalancer. `legacy` is considered insecure and should only be used if necessary. (`recommended`, `legacy`) * `ssl_commonname` - The read-only common name automatically derived from the SSL certificate assigned to this NodeBalancerConfig. Please refer to this field to verify that the appropriate certificate is assigned to your NodeBalancerConfig. diff --git a/docs/data-sources/nodebalancer_configs.md b/docs/data-sources/nodebalancer_configs.md index 1cd65055c..1a6136c01 100644 --- a/docs/data-sources/nodebalancer_configs.md +++ b/docs/data-sources/nodebalancer_configs.md @@ -79,6 +79,10 @@ Each Linode NodeBalancer Config will be stored in the `nodebalancer_configs` att * `check_passive` - If true, any response from this backend with a 5xx status code will be enough for it to be considered unhealthy and taken out of rotation. +* `udp_check_port` - Specifies the port on the backend node used for active health checks, which may differ from the port serving traffic. + +* `udp_session_timeout` - The idle time in seconds after which a session that hasn’t received packets is destroyed. + * `cipher_suite` - What ciphers to use for SSL connections served by this NodeBalancer. `legacy` is considered insecure and should only be used if necessary. (`recommended`, `legacy`) * `ssl_commonname` - The read-only common name automatically derived from the SSL certificate assigned to this NodeBalancerConfig. Please refer to this field to verify that the appropriate certificate is assigned to your NodeBalancerConfig. diff --git a/docs/resources/nodebalancer.md b/docs/resources/nodebalancer.md index 9c899a391..d3e0cb167 100644 --- a/docs/resources/nodebalancer.md +++ b/docs/resources/nodebalancer.md @@ -20,6 +20,7 @@ resource "linode_nodebalancer" "foobar" { label = "mynodebalancer" region = "us-east" client_conn_throttle = 20 + client_udp_sess_throttle = 10 tags = ["foobar"] } ``` @@ -36,6 +37,8 @@ The following arguments are supported: * `client_conn_throttle` - (Optional) Throttle connections per second (0-20). Set to 0 (default) to disable throttling. +* `client_udp_sess_throttle` - Throttle UDP sessions per second (0-20). Set to 0 (default) to disable throttling. + * `tags` - (Optional) A list of tags applied to this object. Tags are case-insensitive and are for organizational purposes only. ## Attributes Reference diff --git a/docs/resources/nodebalancer_config.md b/docs/resources/nodebalancer_config.md index 8e40b13cd..0c33c2745 100644 --- a/docs/resources/nodebalancer_config.md +++ b/docs/resources/nodebalancer_config.md @@ -30,6 +30,7 @@ resource "linode_nodebalancer_config" "foofig" { check_path = "/foo" check_attempts = 3 check_timeout = 30 + udp_check_port = 12345 stickiness = "http_cookie" algorithm = "source" } @@ -65,6 +66,8 @@ The following arguments are supported: * `check_passive` - (Optional) If true, any response from this backend with a 5xx status code will be enough for it to be considered unhealthy and taken out of rotation. +* `udp_check_port` - (Optional) Specifies the port on the backend node used for active health checks, which may differ from the port serving traffic. + * `cipher_suite` - (Optional) What ciphers to use for SSL connections served by this NodeBalancer. `legacy` is considered insecure and should only be used if necessary. * `ssl_cert` - (Optional) The certificate this port is serving. This is not returned. If set, this field will come back as ``. Please use the ssl_commonname and ssl_fingerprint to identify the certificate. @@ -75,6 +78,8 @@ The following arguments are supported: This resource exports the following attributes: +* `udp_session_timeout` - The read-only idle time in seconds after which a session that hasn’t received packets is destroyed. + * `ssl_commonname` - The read-only common name automatically derived from the SSL certificate assigned to this NodeBalancerConfig. Please refer to this field to verify that the appropriate certificate is assigned to your NodeBalancerConfig. * `ssl_fingerprint` - The read-only fingerprint automatically derived from the SSL certificate assigned to this NodeBalancerConfig. Please refer to this field to verify that the appropriate certificate is assigned to your NodeBalancerConfig. diff --git a/go.mod b/go.mod index e82a28d49..39c9fb20e 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.4 github.com/aws/aws-sdk-go-v2/service/s3 v1.72.2 github.com/aws/smithy-go v1.22.1 - github.com/go-resty/resty/v2 v2.16.2 + github.com/go-resty/resty/v2 v2.16.3 github.com/google/go-cmp v0.6.0 github.com/hashicorp/go-cty v1.4.1-0.20200723130312-85980079f637 github.com/hashicorp/go-hclog v1.6.3 @@ -32,6 +32,8 @@ require ( golang.org/x/sync v0.10.0 ) +replace github.com/linode/linodego => github.com/linode/linodego v0.0.0-20250115202254-23f71617a419 + require ( github.com/ProtonMail/go-crypto v1.1.0-alpha.2 // indirect github.com/agext/levenshtein v1.2.2 // indirect diff --git a/go.sum b/go.sum index 9547504ef..5056ab2c5 100644 --- a/go.sum +++ b/go.sum @@ -79,8 +79,8 @@ github.com/go-openapi/jsonreference v0.20.2 h1:3sVjiK66+uXK/6oQ8xgcRKcFgQ5KXa2Kv github.com/go-openapi/jsonreference v0.20.2/go.mod h1:Bl1zwGIM8/wsvqjsOQLJ/SH+En5Ap4rVB5KVcIDZG2k= github.com/go-openapi/swag v0.22.3 h1:yMBqmnQ0gyZvEb/+KzuWZOXgllrXT4SADYbvDaXHv/g= github.com/go-openapi/swag v0.22.3/go.mod h1:UzaqsxGiab7freDnrUUra0MwWfN/q7tE4j+VcZ0yl14= -github.com/go-resty/resty/v2 v2.16.2 h1:CpRqTjIzq/rweXUt9+GxzzQdlkqMdt8Lm/fuK/CAbAg= -github.com/go-resty/resty/v2 v2.16.2/go.mod h1:0fHAoK7JoBy/Ch36N8VFeMsK7xQOHhvWaC3iOktwmIU= +github.com/go-resty/resty/v2 v2.16.3 h1:zacNT7lt4b8M/io2Ahj6yPypL7bqx9n1iprfQuodV+E= +github.com/go-resty/resty/v2 v2.16.3/go.mod h1:hkJtXbA2iKHzJheXYvQ8snQES5ZLGKMwQ07xAwp/fiA= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572 h1:tfuBGBXKqDEevZMzYi5KSi8KkcZtzBcTgAUUtapy0OI= github.com/go-task/slim-sprig v0.0.0-20230315185526-52ccab3ef572/go.mod h1:9Pwr4B2jHnOSGXyyzV8ROjYa2ojvAY6HCGYYfMoC3Ls= github.com/go-test/deep v1.0.3 h1:ZrJSEWsXzPOxaZnFteGEfooLba+ju3FYIbOrS+rQd68= @@ -192,8 +192,8 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/linode/linodego v1.45.0 h1:jds704+yDlxX+1s854Bhyeonzde3MBZksp3Yvgi49L0= -github.com/linode/linodego v1.45.0/go.mod h1:J5qs5Qg8KafUbE9ltYzwxcNpJXaGwLcvOVyDJNZS2As= +github.com/linode/linodego v0.0.0-20250115202254-23f71617a419 h1:6PD2j8vXmWVGNiVMdyYOYvBkerVRRRwMi/d0FI09qao= +github.com/linode/linodego v0.0.0-20250115202254-23f71617a419/go.mod h1:vyklQRzZUWhFVBZdYx4dcYJU/gG9yKB9VUcUs6ub0Lk= github.com/linode/linodego/k8s v1.25.2 h1:PY6S0sAD3xANVvM9WY38bz9GqMTjIbytC8IJJ9Cv23o= github.com/linode/linodego/k8s v1.25.2/go.mod h1:DC1XCSRZRGsmaa/ggpDPSDUmOM6aK1bhSIP6+f9Cwhc= github.com/mailru/easyjson v0.7.7 h1:UGYAvKxe3sBsEDzO8ZeWOSlIQfWFlxbzLZe7hwFURr0= diff --git a/linode/nb/datasource_test.go b/linode/nb/datasource_test.go index c9c948402..d5daf698b 100644 --- a/linode/nb/datasource_test.go +++ b/linode/nb/datasource_test.go @@ -30,6 +30,7 @@ func TestAccDataSourceNodeBalancer_basic(t *testing.T) { checkNodeBalancerExists, resource.TestCheckResourceAttr(resName, "label", nodebalancerName), resource.TestCheckResourceAttr(resName, "client_conn_throttle", "20"), + resource.TestCheckResourceAttr(resName, "client_udp_sess_throttle", "0"), resource.TestCheckResourceAttr(resName, "region", testRegion), resource.TestCheckResourceAttrSet(resName, "hostname"), resource.TestCheckResourceAttrSet(resName, "ipv4"), diff --git a/linode/nb/framework_datasource_schema.go b/linode/nb/framework_datasource_schema.go index 0e615b2dc..b2b798151 100644 --- a/linode/nb/framework_datasource_schema.go +++ b/linode/nb/framework_datasource_schema.go @@ -33,6 +33,10 @@ var NodeBalancerAttributes = map[string]schema.Attribute{ Description: "Throttle connections per second (0-20). Set to 0 (zero) to disable throttling.", Computed: true, }, + "client_udp_sess_throttle": schema.Int64Attribute{ + Description: "Throttle UDP sessions per second (0-20). Set to 0 (zero) to disable throttling.", + Computed: true, + }, "hostname": schema.StringAttribute{ Description: "This NodeBalancer's hostname, ending with .nodebalancer.linode.com", Computed: true, diff --git a/linode/nb/framework_models.go b/linode/nb/framework_models.go index 29d52d3ca..464ff4f8f 100644 --- a/linode/nb/framework_models.go +++ b/linode/nb/framework_models.go @@ -17,19 +17,20 @@ import ( // NodeBalancerModel describes the Terraform resource data model to match the // resource schema. type NodeBalancerModel struct { - ID types.String `tfsdk:"id"` - Label types.String `tfsdk:"label"` - Region types.String `tfsdk:"region"` - ClientConnThrottle types.Int64 `tfsdk:"client_conn_throttle"` - FirewallID types.Int64 `tfsdk:"firewall_id"` - Hostname types.String `tfsdk:"hostname"` - IPv4 types.String `tfsdk:"ipv4"` - IPv6 types.String `tfsdk:"ipv6"` - Created timetypes.RFC3339 `tfsdk:"created"` - Updated timetypes.RFC3339 `tfsdk:"updated"` - Transfer types.List `tfsdk:"transfer"` - Tags types.Set `tfsdk:"tags"` - Firewalls types.List `tfsdk:"firewalls"` + ID types.String `tfsdk:"id"` + Label types.String `tfsdk:"label"` + Region types.String `tfsdk:"region"` + ClientConnThrottle types.Int64 `tfsdk:"client_conn_throttle"` + ClientUDPSessThrottle types.Int64 `tfsdk:"client_udp_sess_throttle"` + FirewallID types.Int64 `tfsdk:"firewall_id"` + Hostname types.String `tfsdk:"hostname"` + IPv4 types.String `tfsdk:"ipv4"` + IPv6 types.String `tfsdk:"ipv6"` + Created timetypes.RFC3339 `tfsdk:"created"` + Updated timetypes.RFC3339 `tfsdk:"updated"` + Transfer types.List `tfsdk:"transfer"` + Tags types.Set `tfsdk:"tags"` + Firewalls types.List `tfsdk:"firewalls"` } type FirewallModel struct { @@ -78,6 +79,9 @@ func (data *NodeBalancerModel) FlattenNodeBalancer( data.ClientConnThrottle = helper.KeepOrUpdateInt64( data.ClientConnThrottle, int64(nodebalancer.ClientConnThrottle), preserveKnown, ) + data.ClientUDPSessThrottle = helper.KeepOrUpdateInt64( + data.ClientUDPSessThrottle, int64(nodebalancer.ClientUDPSessThrottle), preserveKnown, + ) data.Hostname = helper.KeepOrUpdateStringPointer(data.Hostname, nodebalancer.Hostname, preserveKnown) data.IPv4 = helper.KeepOrUpdateStringPointer(data.IPv4, nodebalancer.IPv4, preserveKnown) data.IPv6 = helper.KeepOrUpdateStringPointer(data.IPv6, nodebalancer.IPv6, preserveKnown) @@ -112,6 +116,9 @@ func (data *NodeBalancerModel) CopyFrom(other NodeBalancerModel, preserveKnown b data.ClientConnThrottle = helper.KeepOrUpdateValue( data.ClientConnThrottle, other.ClientConnThrottle, preserveKnown, ) + data.ClientUDPSessThrottle = helper.KeepOrUpdateValue( + data.ClientUDPSessThrottle, other.ClientUDPSessThrottle, preserveKnown, + ) data.FirewallID = helper.KeepOrUpdateValue(data.FirewallID, other.FirewallID, preserveKnown) data.Hostname = helper.KeepOrUpdateValue(data.Hostname, other.Hostname, preserveKnown) data.IPv4 = helper.KeepOrUpdateValue(data.IPv4, other.IPv4, preserveKnown) @@ -210,18 +217,19 @@ func UpgradeResourceStateValue(val string) (types.Float64, diag.Diagnostic) { // NodeBalancerDataSourceModel describes the Terraform data model to match the // data source schema. type NodeBalancerDataSourceModel struct { - ID types.Int64 `tfsdk:"id"` - Label types.String `tfsdk:"label"` - Region types.String `tfsdk:"region"` - ClientConnThrottle types.Int64 `tfsdk:"client_conn_throttle"` - Hostname types.String `tfsdk:"hostname"` - IPv4 types.String `tfsdk:"ipv4"` - IPv6 types.String `tfsdk:"ipv6"` - Created timetypes.RFC3339 `tfsdk:"created"` - Updated timetypes.RFC3339 `tfsdk:"updated"` - Transfer types.List `tfsdk:"transfer"` - Tags types.Set `tfsdk:"tags"` - Firewalls []NBFirewallModel `tfsdk:"firewalls"` + ID types.Int64 `tfsdk:"id"` + Label types.String `tfsdk:"label"` + Region types.String `tfsdk:"region"` + ClientConnThrottle types.Int64 `tfsdk:"client_conn_throttle"` + ClientUDPSessThrottle types.Int64 `tfsdk:"client_udp_sess_throttle"` + Hostname types.String `tfsdk:"hostname"` + IPv4 types.String `tfsdk:"ipv4"` + IPv6 types.String `tfsdk:"ipv6"` + Created timetypes.RFC3339 `tfsdk:"created"` + Updated timetypes.RFC3339 `tfsdk:"updated"` + Transfer types.List `tfsdk:"transfer"` + Tags types.Set `tfsdk:"tags"` + Firewalls []NBFirewallModel `tfsdk:"firewalls"` } type NBFirewallModel struct { @@ -246,6 +254,7 @@ func (data *NodeBalancerDataSourceModel) flattenNodeBalancer( data.Label = types.StringPointerValue(nodebalancer.Label) data.Region = types.StringValue(nodebalancer.Region) data.ClientConnThrottle = types.Int64Value(int64(nodebalancer.ClientConnThrottle)) + data.ClientUDPSessThrottle = types.Int64Value(int64(nodebalancer.ClientUDPSessThrottle)) data.Hostname = types.StringPointerValue(nodebalancer.Hostname) data.IPv4 = types.StringPointerValue(nodebalancer.IPv4) data.IPv6 = types.StringPointerValue(nodebalancer.IPv6) diff --git a/linode/nb/framework_models_unit_test.go b/linode/nb/framework_models_unit_test.go index 88ace08d2..0c33e86cf 100644 --- a/linode/nb/framework_models_unit_test.go +++ b/linode/nb/framework_models_unit_test.go @@ -48,15 +48,16 @@ func TestFlattenNodeBalancer(t *testing.T) { label := "test-nodebalancer" nodeBalancer := &linodego.NodeBalancer{ - ID: 123, - Label: &label, - Region: "us-east", - ClientConnThrottle: 10, - Hostname: &hostname, - IPv4: &IPv4, - IPv6: &IPv6, - Created: &createdTime, - Updated: &updatedTime, + ID: 123, + Label: &label, + Region: "us-east", + ClientConnThrottle: 10, + ClientUDPSessThrottle: 5, + Hostname: &hostname, + IPv4: &IPv4, + IPv6: &IPv6, + Created: &createdTime, + Updated: &updatedTime, Transfer: linodego.NodeBalancerTransfer{ In: &transferIn, Out: &transferOut, @@ -73,6 +74,7 @@ func TestFlattenNodeBalancer(t *testing.T) { assert.Equal(t, types.StringValue("123"), nodeBalancerModel.ID) assert.Equal(t, types.StringValue("us-east"), nodeBalancerModel.Region) assert.Equal(t, types.Int64Value(10), nodeBalancerModel.ClientConnThrottle) + assert.Equal(t, types.Int64Value(5), nodeBalancerModel.ClientUDPSessThrottle) assert.Equal(t, types.StringPointerValue(&hostname), nodeBalancerModel.Hostname) assert.Equal(t, types.StringPointerValue(&IPv4), nodeBalancerModel.IPv4) assert.Equal(t, types.StringPointerValue(&IPv6), nodeBalancerModel.IPv6) diff --git a/linode/nb/framework_resource.go b/linode/nb/framework_resource.go index aa3594aa6..18677836c 100644 --- a/linode/nb/framework_resource.go +++ b/linode/nb/framework_resource.go @@ -55,10 +55,19 @@ func (r *Resource) Create( return } + clientUDPSessThrottle := helper.FrameworkSafeInt64ToInt( + data.ClientUDPSessThrottle.ValueInt64(), + &resp.Diagnostics, + ) + if resp.Diagnostics.HasError() { + return + } + createOpts := linodego.NodeBalancerCreateOptions{ - Region: data.Region.ValueString(), - Label: data.Label.ValueStringPointer(), - ClientConnThrottle: &clientConnThrottle, + Region: data.Region.ValueString(), + Label: data.Label.ValueStringPointer(), + ClientConnThrottle: &clientConnThrottle, + ClientUDPSessThrottle: &clientUDPSessThrottle, } if !data.FirewallID.IsNull() { @@ -198,7 +207,7 @@ func (r *Resource) Update( isEqual := state.Label.Equal(plan.Label) && state.ClientConnThrottle.Equal(plan.ClientConnThrottle) && - state.Tags.Equal(plan.Tags) + state.Tags.Equal(plan.Tags) && state.ClientUDPSessThrottle.Equal(plan.ClientUDPSessThrottle) if !isEqual { clientConnThrottle := helper.FrameworkSafeInt64ToInt( @@ -208,9 +217,17 @@ func (r *Resource) Update( if resp.Diagnostics.HasError() { return } + clientUDPSessThrottle := helper.FrameworkSafeInt64ToInt( + plan.ClientUDPSessThrottle.ValueInt64(), + &resp.Diagnostics, + ) + if resp.Diagnostics.HasError() { + return + } updateOpts := linodego.NodeBalancerUpdateOptions{ - Label: plan.Label.ValueStringPointer(), - ClientConnThrottle: &clientConnThrottle, + Label: plan.Label.ValueStringPointer(), + ClientConnThrottle: &clientConnThrottle, + ClientUDPSessThrottle: &clientUDPSessThrottle, } resp.Diagnostics.Append(plan.Tags.ElementsAs(ctx, &updateOpts.Tags, false)...) if resp.Diagnostics.HasError() { diff --git a/linode/nb/framework_resource_schema.go b/linode/nb/framework_resource_schema.go index 93c0c04b0..ec4f9648e 100644 --- a/linode/nb/framework_resource_schema.go +++ b/linode/nb/framework_resource_schema.go @@ -74,6 +74,15 @@ var frameworkResourceSchema = schema.Schema{ Computed: true, Default: int64default.StaticInt64(0), }, + "client_udp_sess_throttle": schema.Int64Attribute{ + Description: "Throttle UDP sessions per second (0-20). Set to 0 (zero) to disable throttling.", + Validators: []validator.Int64{ + int64validator.Between(0, 20), + }, + Optional: true, + Computed: true, + Default: int64default.StaticInt64(0), + }, "firewall_id": schema.Int64Attribute{ Description: "ID for the firewall you'd like to use with this NodeBalancer.", Optional: true, diff --git a/linode/nb/resource_test.go b/linode/nb/resource_test.go index 1c2554e71..af6d70d9a 100644 --- a/linode/nb/resource_test.go +++ b/linode/nb/resource_test.go @@ -93,6 +93,7 @@ func TestAccResourceNodeBalancer_basic_smoke(t *testing.T) { checkNodeBalancerExists, resource.TestCheckResourceAttr(resName, "label", nodebalancerName), resource.TestCheckResourceAttr(resName, "client_conn_throttle", "20"), + resource.TestCheckResourceAttr(resName, "client_udp_sess_throttle", "10"), resource.TestCheckResourceAttr(resName, "region", testRegion), resource.TestCheckResourceAttrSet(resName, "hostname"), @@ -133,6 +134,7 @@ func TestAccResourceNodeBalancer_update(t *testing.T) { checkNodeBalancerExists, resource.TestCheckResourceAttr(resName, "label", nodebalancerName), resource.TestCheckResourceAttr(resName, "client_conn_throttle", "20"), + resource.TestCheckResourceAttr(resName, "client_udp_sess_throttle", "10"), resource.TestCheckResourceAttr(resName, "region", testRegion), resource.TestCheckResourceAttrSet(resName, "hostname"), @@ -144,7 +146,25 @@ func TestAccResourceNodeBalancer_update(t *testing.T) { resource.TestCheckResourceAttr(resName, "tags.0", "tf_test"), ), }, + { + Config: tmpl.Updates(t, nodebalancerName, testRegion), + Check: resource.ComposeTestCheckFunc( + checkNodeBalancerExists, + resource.TestCheckResourceAttr(resName, "label", nodebalancerName+"_r"), + resource.TestCheckResourceAttr(resName, "client_conn_throttle", "0"), + resource.TestCheckResourceAttr(resName, "client_udp_sess_throttle", "5"), + resource.TestCheckResourceAttr(resName, "region", testRegion), + resource.TestCheckResourceAttrSet(resName, "hostname"), + resource.TestCheckResourceAttrSet(resName, "ipv4"), + resource.TestCheckResourceAttrSet(resName, "ipv6"), + resource.TestCheckResourceAttrSet(resName, "created"), + resource.TestCheckResourceAttrSet(resName, "updated"), + resource.TestCheckResourceAttr(resName, "tags.#", "2"), + resource.TestCheckResourceAttr(resName, "tags.0", "tf_test"), + resource.TestCheckResourceAttr(resName, "tags.1", "tf_test_2"), + ), + }, { ResourceName: resName, ImportState: true, diff --git a/linode/nb/tmpl/basic.gotf b/linode/nb/tmpl/basic.gotf index b78b8008d..4c30b6400 100644 --- a/linode/nb/tmpl/basic.gotf +++ b/linode/nb/tmpl/basic.gotf @@ -6,6 +6,7 @@ resource "linode_nodebalancer" "foobar" { label = "{{.Label}}" region = "{{ .Region }}" client_conn_throttle = 20 + client_udp_sess_throttle = 10 tags = ["tf_test"] firewall_id = linode_firewall.e2e_test_firewall.id } diff --git a/linode/nb/tmpl/updates.gotf b/linode/nb/tmpl/updates.gotf index c3534ab37..1200300b5 100644 --- a/linode/nb/tmpl/updates.gotf +++ b/linode/nb/tmpl/updates.gotf @@ -6,6 +6,7 @@ resource "linode_nodebalancer" "foobar" { label = "{{.Label}}_r" region = "{{ .Region }}" client_conn_throttle = 0 + client_udp_sess_throttle = 5 tags = ["tf_test", "tf_test_2"] firewall_id = linode_firewall.e2e_test_firewall.id } diff --git a/linode/nbconfig/datasource_test.go b/linode/nbconfig/datasource_test.go index ea8927028..e28c60a12 100644 --- a/linode/nbconfig/datasource_test.go +++ b/linode/nbconfig/datasource_test.go @@ -39,6 +39,8 @@ func TestAccDataSourceNodeBalancerConfig_basic(t *testing.T) { resource.TestCheckResourceAttrSet(resName, "check_timeout"), resource.TestCheckResourceAttrSet(resName, "check_interval"), resource.TestCheckResourceAttrSet(resName, "check_passive"), + resource.TestCheckResourceAttrSet(resName, "udp_check_port"), + resource.TestCheckResourceAttrSet(resName, "udp_session_timeout"), resource.TestCheckResourceAttrSet(resName, "cipher_suite"), resource.TestCheckNoResourceAttr(resName, "ssl_common"), resource.TestCheckNoResourceAttr(resName, "ssl_ciphersuite"), diff --git a/linode/nbconfig/framework_models.go b/linode/nbconfig/framework_models.go index 984c48da0..acd1063be 100644 --- a/linode/nbconfig/framework_models.go +++ b/linode/nbconfig/framework_models.go @@ -13,24 +13,26 @@ import ( ) type DataSourceModel struct { - ID types.Int64 `tfsdk:"id"` - NodeBalancerID types.Int64 `tfsdk:"nodebalancer_id"` - Protocol types.String `tfsdk:"protocol"` - ProxyProtocol types.String `tfsdk:"proxy_protocol"` - Port types.Int64 `tfsdk:"port"` - CheckInterval types.Int64 `tfsdk:"check_interval"` - CheckTimeout types.Int64 `tfsdk:"check_timeout"` - CheckAttempts types.Int64 `tfsdk:"check_attempts"` - Algorithm types.String `tfsdk:"algorithm"` - Stickiness types.String `tfsdk:"stickiness"` - Check types.String `tfsdk:"check"` - CheckPath types.String `tfsdk:"check_path"` - CheckBody types.String `tfsdk:"check_body"` - CheckPassive types.Bool `tfsdk:"check_passive"` - CipherSuite types.String `tfsdk:"cipher_suite"` - SSLCommonName types.String `tfsdk:"ssl_commonname"` - SSLFingerprint types.String `tfsdk:"ssl_fingerprint"` - NodesStatus types.List `tfsdk:"node_status"` + ID types.Int64 `tfsdk:"id"` + NodeBalancerID types.Int64 `tfsdk:"nodebalancer_id"` + Protocol types.String `tfsdk:"protocol"` + ProxyProtocol types.String `tfsdk:"proxy_protocol"` + Port types.Int64 `tfsdk:"port"` + CheckInterval types.Int64 `tfsdk:"check_interval"` + CheckTimeout types.Int64 `tfsdk:"check_timeout"` + CheckAttempts types.Int64 `tfsdk:"check_attempts"` + Algorithm types.String `tfsdk:"algorithm"` + Stickiness types.String `tfsdk:"stickiness"` + Check types.String `tfsdk:"check"` + CheckPath types.String `tfsdk:"check_path"` + CheckBody types.String `tfsdk:"check_body"` + CheckPassive types.Bool `tfsdk:"check_passive"` + UDPCheckPort types.Int64 `tfsdk:"udp_check_port"` + UDPSessionTimeout types.Int64 `tfsdk:"udp_session_timeout"` + CipherSuite types.String `tfsdk:"cipher_suite"` + SSLCommonName types.String `tfsdk:"ssl_commonname"` + SSLFingerprint types.String `tfsdk:"ssl_fingerprint"` + NodesStatus types.List `tfsdk:"node_status"` } func (data *DataSourceModel) ParseNodebalancerConfig( @@ -46,6 +48,8 @@ func (data *DataSourceModel) ParseNodebalancerConfig( data.CheckInterval = types.Int64Value(int64(config.CheckInterval)) data.CheckTimeout = types.Int64Value(int64(config.CheckTimeout)) data.CheckPassive = types.BoolValue(config.CheckPassive) + data.UDPCheckPort = types.Int64Value(int64(config.UDPCheckPort)) + data.UDPSessionTimeout = types.Int64Value(int64(config.UDPSessionTimeout)) data.CheckPath = types.StringValue(config.CheckPath) data.CipherSuite = types.StringValue(string(config.CipherSuite)) data.Port = types.Int64Value(int64(config.Port)) @@ -99,26 +103,28 @@ type ResourceModelV0 struct { } type ResourceModelV1 struct { - ID types.String `tfsdk:"id"` - NodeBalancerID types.Int64 `tfsdk:"nodebalancer_id"` - Protocol types.String `tfsdk:"protocol"` - ProxyProtocol types.String `tfsdk:"proxy_protocol"` - Port types.Int64 `tfsdk:"port"` - CheckInterval types.Int64 `tfsdk:"check_interval"` - CheckTimeout types.Int64 `tfsdk:"check_timeout"` - CheckAttempts types.Int64 `tfsdk:"check_attempts"` - Algorithm types.String `tfsdk:"algorithm"` - Stickiness types.String `tfsdk:"stickiness"` - Check types.String `tfsdk:"check"` - CheckPath types.String `tfsdk:"check_path"` - CheckBody types.String `tfsdk:"check_body"` - CheckPassive types.Bool `tfsdk:"check_passive"` - CipherSuite types.String `tfsdk:"cipher_suite"` - SSLCommonName types.String `tfsdk:"ssl_commonname"` - SSLFingerprint types.String `tfsdk:"ssl_fingerprint"` - NodesStatus types.List `tfsdk:"node_status"` - SSLCert types.String `tfsdk:"ssl_cert"` - SSLKey types.String `tfsdk:"ssl_key"` + ID types.String `tfsdk:"id"` + NodeBalancerID types.Int64 `tfsdk:"nodebalancer_id"` + Protocol types.String `tfsdk:"protocol"` + ProxyProtocol types.String `tfsdk:"proxy_protocol"` + Port types.Int64 `tfsdk:"port"` + CheckInterval types.Int64 `tfsdk:"check_interval"` + CheckTimeout types.Int64 `tfsdk:"check_timeout"` + CheckAttempts types.Int64 `tfsdk:"check_attempts"` + Algorithm types.String `tfsdk:"algorithm"` + Stickiness types.String `tfsdk:"stickiness"` + Check types.String `tfsdk:"check"` + CheckPath types.String `tfsdk:"check_path"` + CheckBody types.String `tfsdk:"check_body"` + CheckPassive types.Bool `tfsdk:"check_passive"` + UDPCheckPort types.Int64 `tfsdk:"udp_check_port"` + UDPSessionTimeout types.Int64 `tfsdk:"udp_session_timeout"` + CipherSuite types.String `tfsdk:"cipher_suite"` + SSLCommonName types.String `tfsdk:"ssl_commonname"` + SSLFingerprint types.String `tfsdk:"ssl_fingerprint"` + NodesStatus types.List `tfsdk:"node_status"` + SSLCert types.String `tfsdk:"ssl_cert"` + SSLKey types.String `tfsdk:"ssl_key"` } func (data *ResourceModelV1) FlattenNodeBalancerConfig( @@ -135,6 +141,8 @@ func (data *ResourceModelV1) FlattenNodeBalancerConfig( data.CheckTimeout = helper.KeepOrUpdateInt64(data.CheckTimeout, int64(config.CheckTimeout), preserveKnown) data.CheckPassive = helper.KeepOrUpdateBool(data.CheckPassive, config.CheckPassive, preserveKnown) data.CheckPath = helper.KeepOrUpdateString(data.CheckPath, config.CheckPath, preserveKnown) + data.UDPCheckPort = helper.KeepOrUpdateInt64(data.UDPCheckPort, int64(config.UDPCheckPort), preserveKnown) + data.UDPSessionTimeout = helper.KeepOrUpdateInt64(data.UDPSessionTimeout, int64(config.UDPSessionTimeout), preserveKnown) data.CipherSuite = helper.KeepOrUpdateString(data.CipherSuite, string(config.CipherSuite), preserveKnown) data.Port = helper.KeepOrUpdateInt64(data.Port, int64(config.Port), preserveKnown) data.Protocol = helper.KeepOrUpdateString(data.Protocol, string(config.Protocol), preserveKnown) @@ -165,6 +173,8 @@ func (data *ResourceModelV1) CopyFrom(other ResourceModelV1, preserveKnown bool) data.CheckTimeout = helper.KeepOrUpdateValue(data.CheckTimeout, other.CheckTimeout, preserveKnown) data.CheckPassive = helper.KeepOrUpdateValue(data.CheckPassive, other.CheckPassive, preserveKnown) data.CheckPath = helper.KeepOrUpdateValue(data.CheckPath, other.CheckPath, preserveKnown) + data.UDPCheckPort = helper.KeepOrUpdateValue(data.UDPCheckPort, other.UDPCheckPort, preserveKnown) + data.UDPSessionTimeout = helper.KeepOrUpdateValue(data.UDPSessionTimeout, other.UDPSessionTimeout, preserveKnown) data.CipherSuite = helper.KeepOrUpdateValue(data.CipherSuite, other.CipherSuite, preserveKnown) data.Port = helper.KeepOrUpdateValue(data.Port, other.Port, preserveKnown) data.Protocol = helper.KeepOrUpdateValue(data.Protocol, other.Protocol, preserveKnown) @@ -252,6 +262,7 @@ func (data *ResourceModelV1) GetNodeBalancerConfigCreateOptions( checkAttempts := helper.FrameworkSafeInt64ToInt(data.CheckAttempts.ValueInt64(), diags) checkInterval := helper.FrameworkSafeInt64ToInt(data.CheckInterval.ValueInt64(), diags) checkTimeout := helper.FrameworkSafeInt64ToInt(data.CheckTimeout.ValueInt64(), diags) + udpCheckPort := helper.FrameworkSafeInt64ToInt(data.UDPCheckPort.ValueInt64(), diags) port := helper.FrameworkSafeInt64ToInt(data.Port.ValueInt64(), diags) if diags.HasError() { return nil @@ -265,6 +276,7 @@ func (data *ResourceModelV1) GetNodeBalancerConfigCreateOptions( CheckInterval: checkInterval, CheckPath: data.CheckPath.ValueString(), CheckTimeout: checkTimeout, + UDPCheckPort: &udpCheckPort, Port: port, Protocol: linodego.ConfigProtocol(strings.ToLower(data.Protocol.ValueString())), ProxyProtocol: linodego.ConfigProxyProtocol(data.ProxyProtocol.ValueString()), @@ -285,6 +297,7 @@ func (data *ResourceModelV1) GetNodeBalancerConfigUpdateOptions( checkAttempts := helper.FrameworkSafeInt64ToInt(data.CheckAttempts.ValueInt64(), diags) checkInterval := helper.FrameworkSafeInt64ToInt(data.CheckInterval.ValueInt64(), diags) checkTimeout := helper.FrameworkSafeInt64ToInt(data.CheckTimeout.ValueInt64(), diags) + udpCheckPort := helper.FrameworkSafeInt64ToInt(data.UDPCheckPort.ValueInt64(), diags) port := helper.FrameworkSafeInt64ToInt(data.Port.ValueInt64(), diags) if diags.HasError() { return nil @@ -299,6 +312,7 @@ func (data *ResourceModelV1) GetNodeBalancerConfigUpdateOptions( CheckInterval: checkInterval, CheckPath: data.CheckPath.ValueString(), CheckTimeout: checkTimeout, + UDPCheckPort: &udpCheckPort, Port: port, Protocol: linodego.ConfigProtocol(strings.ToLower(data.Protocol.ValueString())), ProxyProtocol: linodego.ConfigProxyProtocol(data.ProxyProtocol.ValueString()), diff --git a/linode/nbconfig/framework_schema_datasource.go b/linode/nbconfig/framework_schema_datasource.go index 2873a7b29..51c7703a8 100644 --- a/linode/nbconfig/framework_schema_datasource.go +++ b/linode/nbconfig/framework_schema_datasource.go @@ -48,6 +48,14 @@ var NBConfigAttributes = map[string]schema.Attribute{ Description: "How long, in seconds, to wait for a check attempt before considering it failed. (1-30)", Computed: true, }, + "udp_check_port": schema.Int64Attribute{ + Description: "Specifies the port on the backend node used for active health checks, which may differ from the port serving traffic.", + Computed: true, + }, + "udp_session_timeout": schema.Int64Attribute{ + Description: "The idle time in seconds after which a session that hasn’t received packets is destroyed.", + Computed: true, + }, "check_attempts": schema.Int64Attribute{ Description: "How many times to attempt a check before considering a backend to be down. (1-30)", Computed: true, diff --git a/linode/nbconfig/framework_schema_resource.go b/linode/nbconfig/framework_schema_resource.go index f0c7261f3..b5a9a0108 100644 --- a/linode/nbconfig/framework_schema_resource.go +++ b/linode/nbconfig/framework_schema_resource.go @@ -111,6 +111,22 @@ func getSchemaAttributes(version int) map[string]schema.Attribute { Optional: true, Computed: true, }, + "udp_check_port": schema.Int64Attribute{ + Description: "Specifies the port on the backend node used for active health checks, which may differ from the port serving traffic.", + Validators: []validator.Int64{ + int64validator.Between(1, 65535), + }, + Default: int64default.StaticInt64(80), + Optional: true, + Computed: true, + }, + "udp_session_timeout": schema.Int64Attribute{ + Description: "The read-only idle time in seconds after which a session that hasn’t received packets is destroyed.", + PlanModifiers: []planmodifier.Int64{ + int64planmodifier.UseStateForUnknown(), + }, + Computed: true, + }, "check_attempts": schema.Int64Attribute{ Description: "How many times to attempt a check before considering a backend to be down. (1-30)", Validators: []validator.Int64{ diff --git a/linode/nbconfig/resource_test.go b/linode/nbconfig/resource_test.go index 10d8571f7..7c8095b1d 100644 --- a/linode/nbconfig/resource_test.go +++ b/linode/nbconfig/resource_test.go @@ -60,6 +60,8 @@ func TestAccResourceNodeBalancerConfig_basic(t *testing.T) { resource.TestCheckResourceAttrSet(resName, "check_timeout"), resource.TestCheckResourceAttrSet(resName, "check_interval"), resource.TestCheckResourceAttrSet(resName, "check_passive"), + resource.TestCheckResourceAttrSet(resName, "udp_check_port"), + resource.TestCheckResourceAttrSet(resName, "udp_session_timeout"), resource.TestCheckResourceAttrSet(resName, "cipher_suite"), resource.TestCheckNoResourceAttr(resName, "ssl_common"), resource.TestCheckNoResourceAttr(resName, "ssl_ciphersuite"), @@ -150,6 +152,7 @@ func TestAccResourceNodeBalancerConfig_update(t *testing.T) { resource.TestCheckResourceAttr(resName, "check_attempts", "3"), resource.TestCheckResourceAttr(resName, "check_timeout", "30"), resource.TestCheckResourceAttr(resName, "check_interval", "31"), + resource.TestCheckResourceAttr(resName, "udp_check_port", "1234"), resource.TestCheckResourceAttr(resName, "check_passive", "false"), resource.TestCheckResourceAttr(resName, "stickiness", string(linodego.StickinessHTTPCookie)), diff --git a/linode/nbconfig/tmpl/updates.gotf b/linode/nbconfig/tmpl/updates.gotf index 4b10d4642..4ada28708 100644 --- a/linode/nbconfig/tmpl/updates.gotf +++ b/linode/nbconfig/tmpl/updates.gotf @@ -11,6 +11,7 @@ resource "linode_nodebalancer_config" "foofig" { check_attempts = 3 check_timeout = 30 check_interval = 31 + udp_check_port = 1234 check_passive = false stickiness = "http_cookie" algorithm = "source" diff --git a/linode/nbconfigs/datasource_test.go b/linode/nbconfigs/datasource_test.go index 02175b225..4cc13bff7 100644 --- a/linode/nbconfigs/datasource_test.go +++ b/linode/nbconfigs/datasource_test.go @@ -42,6 +42,8 @@ func TestAccDataSourceNodeBalancerConfigs_basic(t *testing.T) { resource.TestCheckResourceAttrSet(resourceName, "nodebalancer_configs.0.port"), resource.TestCheckResourceAttrSet(resourceName, "nodebalancer_configs.0.check_interval"), resource.TestCheckResourceAttrSet(resourceName, "nodebalancer_configs.0.check_passive"), + resource.TestCheckResourceAttrSet(resourceName, "nodebalancer_configs.0.udp_check_port"), + resource.TestCheckResourceAttrSet(resourceName, "nodebalancer_configs.0.udp_session_timeout"), resource.TestCheckResourceAttrSet(resourceName, "nodebalancer_configs.0.cipher_suite"), resource.TestCheckNoResourceAttr(resourceName, "nodebalancer_configs.0.ssl_common"), resource.TestCheckNoResourceAttr(resourceName, "nodebalancer_configs.0.ssl_ciphersuite"),