From 6af37ff0c30a6d079073b16a55b89d913111e6b5 Mon Sep 17 00:00:00 2001 From: Jaylon McShan Date: Mon, 18 Nov 2024 15:52:39 -0600 Subject: [PATCH 1/4] Adding traffic_distribution_field --- kubernetes/resource_kubernetes_service_v1.go | 8 +++ .../resource_kubernetes_service_v1_test.go | 53 +++++++++++++++++++ kubernetes/structure_service_spec.go | 14 ++++- 3 files changed, 74 insertions(+), 1 deletion(-) diff --git a/kubernetes/resource_kubernetes_service_v1.go b/kubernetes/resource_kubernetes_service_v1.go index 934f038082..a1151bdadb 100644 --- a/kubernetes/resource_kubernetes_service_v1.go +++ b/kubernetes/resource_kubernetes_service_v1.go @@ -268,6 +268,14 @@ func resourceKubernetesServiceSchemaV1() map[string]*schema.Schema { }, }, }, + "traffic_distribution": { + Type: schema.TypeString, + Description: "Specifies the preferred strategy for distributing traffic to Service endpoints. When set to PreferClose, the Kubernetes will prioritize routing traffic to endpoints that are topologically closer", + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + "PreferClose", + }, false), + }, "type": { Type: schema.TypeString, Description: "Determines how the service is exposed. Defaults to `ClusterIP`. Valid options are `ExternalName`, `ClusterIP`, `NodePort`, and `LoadBalancer`. `ExternalName` maps to the specified `external_name`. More info: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types", diff --git a/kubernetes/resource_kubernetes_service_v1_test.go b/kubernetes/resource_kubernetes_service_v1_test.go index 0cbf4b4b56..cf88b97e07 100644 --- a/kubernetes/resource_kubernetes_service_v1_test.go +++ b/kubernetes/resource_kubernetes_service_v1_test.go @@ -819,6 +819,36 @@ func TestAccKubernetesServiceV1_ipFamilies(t *testing.T) { }) } +func TestAccKubernetesServiceV1_trafficDistribution(t *testing.T) { + var conf corev1.Service + name := acctest.RandomWithPrefix("tf-acc-test") + resourceName := "kubernetes_service_v1.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + IDRefreshIgnore: []string{"metadata.0.resource_version"}, + ProviderFactories: testAccProviderFactories, + CheckDestroy: testAccCheckKubernetesServiceV1Destroy, + Steps: []resource.TestStep{ + { + Config: testAccKubernetesServiceV1Config_trafficDistribution(name, "PreferClose"), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckKubernetesServiceV1Exists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "metadata.0.name", name), + resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.traffic_distribution", "PreferClose"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"metadata.0.resource_version", "wait_for_load_balancer"}, + }, + }, + }) +} + func testAccCheckServiceV1Ports(svc *corev1.Service, expected []corev1.ServicePort) resource.TestCheckFunc { return func(s *terraform.State) error { if len(expected) == 0 && len(svc.Spec.Ports) == 0 { @@ -1417,3 +1447,26 @@ func testAccKubernetesServiceV1ConfigV1_ipFamilies(prefix string) string { } `, prefix) } + +func testAccKubernetesServiceV1Config_trafficDistribution(name, trafficDistribution string) string { + return fmt.Sprintf(` +resource "kubernetes_service_v1" "test" { + metadata { + name = "%s" + } + + spec { + traffic_distribution = "%s" + + port { + port = 8080 + target_port = 80 + } + + selector = { + app = "MyApp" + } + } +} +`, name, trafficDistribution) +} diff --git a/kubernetes/structure_service_spec.go b/kubernetes/structure_service_spec.go index ab0b869616..68b0f4c27b 100644 --- a/kubernetes/structure_service_spec.go +++ b/kubernetes/structure_service_spec.go @@ -116,6 +116,9 @@ func flattenServiceSpec(in v1.ServiceSpec) []interface{} { if in.ExternalTrafficPolicy != "" { att["external_traffic_policy"] = string(in.ExternalTrafficPolicy) } + if in.TrafficDistribution != nil { + att["traffic_distribution"] = *in.TrafficDistribution + } att["health_check_node_port"] = int(in.HealthCheckNodePort) @@ -281,7 +284,9 @@ func expandServiceSpec(l []interface{}) v1.ServiceSpec { if v, ok := in["health_check_node_port"].(int); ok { obj.HealthCheckNodePort = int32(v) } - + if v, ok := in["traffic_distribution"].(string); ok && v != "" { + obj.TrafficDistribution = &v + } return obj } @@ -427,5 +432,12 @@ func patchServiceSpec(keyPrefix, pathPrefix string, d *schema.ResourceData, kv * Value: int32(d.Get(keyPrefix + "health_check_node_port").(int)), }) } + if d.HasChange(keyPrefix + "traffic_distribution") { + ops = append(ops, &ReplaceOperation{ + Path: pathPrefix + "trafficDistribution", + Value: d.Get(keyPrefix + "traffic_distribution").(string), + }) + } + return ops } From 72d6cadb17dccae61987cbae92054756576dd954 Mon Sep 17 00:00:00 2001 From: Jaylon McShan Date: Wed, 20 Nov 2024 10:59:19 -0600 Subject: [PATCH 2/4] Adding traffic_distrubition field to MD, and changelog --- .changelog/2625.txt | 3 +++ docs/data-sources/service.md | 1 + docs/data-sources/service_v1.md | 1 + docs/resources/service.md | 1 + docs/resources/service_v1.md | 1 + 5 files changed, 7 insertions(+) create mode 100644 .changelog/2625.txt diff --git a/.changelog/2625.txt b/.changelog/2625.txt new file mode 100644 index 0000000000..bf14a476b9 --- /dev/null +++ b/.changelog/2625.txt @@ -0,0 +1,3 @@ +```release-note:enhancement + +``` \ No newline at end of file diff --git a/docs/data-sources/service.md b/docs/data-sources/service.md index 97e0508286..ab08f4f5cb 100644 --- a/docs/data-sources/service.md +++ b/docs/data-sources/service.md @@ -50,6 +50,7 @@ Read-Only: - `external_ips` (Set of String) - `external_name` (String) - `external_traffic_policy` (String) +- `traffic_distribution` (String) - `health_check_node_port` (Number) - `internal_traffic_policy` (String) - `ip_families` (List of String) diff --git a/docs/data-sources/service_v1.md b/docs/data-sources/service_v1.md index 6d56bc0c77..be9d82b0d2 100644 --- a/docs/data-sources/service_v1.md +++ b/docs/data-sources/service_v1.md @@ -50,6 +50,7 @@ Read-Only: - `external_ips` (Set of String) - `external_name` (String) - `external_traffic_policy` (String) +- `traffic_distribution` (String) - `health_check_node_port` (Number) - `internal_traffic_policy` (String) - `ip_families` (List of String) diff --git a/docs/resources/service.md b/docs/resources/service.md index b35b2ba51a..24a84da8b7 100644 --- a/docs/resources/service.md +++ b/docs/resources/service.md @@ -56,6 +56,7 @@ Optional: - `external_ips` (Set of String) A list of IP addresses for which nodes in the cluster will also accept traffic for this service. These IPs are not managed by Kubernetes. The user is responsible for ensuring that traffic arrives at a node with this IP. A common example is external load-balancers that are not part of the Kubernetes system. - `external_name` (String) The external reference that kubedns or equivalent will return as a CNAME record for this service. No proxying will be involved. Must be a valid DNS name and requires `type` to be `ExternalName`. - `external_traffic_policy` (String) Denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints. `Local` preserves the client source IP and avoids a second hop for LoadBalancer and Nodeport type services, but risks potentially imbalanced traffic spreading. `Cluster` obscures the client source IP and may cause a second hop to another node, but should have good overall load-spreading. More info: https://kubernetes.io/docs/tutorials/services/source-ip/ +- `traffic_distribution` (String) Specifies the preferred strategy for distributing traffic to Service endpoints. When set to PreferClose, the Kubernetes will prioritize routing traffic to endpoints that are topologically closer - `health_check_node_port` (Number) Specifies the Healthcheck NodePort for the service. Only effects when type is set to `LoadBalancer` and external_traffic_policy is set to `Local`. - `internal_traffic_policy` (String) Specifies if the cluster internal traffic should be routed to all endpoints or node-local endpoints only. `Cluster` routes internal traffic to a Service to all endpoints. `Local` routes traffic to node-local endpoints only, traffic is dropped if no node-local endpoints are ready. The default value is `Cluster`. - `ip_families` (List of String) IPFamilies is a list of IP families (e.g. IPv4, IPv6) assigned to this service. This field is usually assigned automatically based on cluster configuration and the ipFamilyPolicy field. If this field is specified manually, the requested family is available in the cluster, and ipFamilyPolicy allows it, it will be used; otherwise creation of the service will fail. This field is conditionally mutable: it allows for adding or removing a secondary IP family, but it does not allow changing the primary IP family of the Service. diff --git a/docs/resources/service_v1.md b/docs/resources/service_v1.md index 006428ce48..57598475ee 100644 --- a/docs/resources/service_v1.md +++ b/docs/resources/service_v1.md @@ -56,6 +56,7 @@ Optional: - `external_ips` (Set of String) A list of IP addresses for which nodes in the cluster will also accept traffic for this service. These IPs are not managed by Kubernetes. The user is responsible for ensuring that traffic arrives at a node with this IP. A common example is external load-balancers that are not part of the Kubernetes system. - `external_name` (String) The external reference that kubedns or equivalent will return as a CNAME record for this service. No proxying will be involved. Must be a valid DNS name and requires `type` to be `ExternalName`. - `external_traffic_policy` (String) Denotes if this Service desires to route external traffic to node-local or cluster-wide endpoints. `Local` preserves the client source IP and avoids a second hop for LoadBalancer and Nodeport type services, but risks potentially imbalanced traffic spreading. `Cluster` obscures the client source IP and may cause a second hop to another node, but should have good overall load-spreading. More info: https://kubernetes.io/docs/tutorials/services/source-ip/ +- `traffic_distribution` (String) Specifies the preferred strategy for distributing traffic to Service endpoints. When set to PreferClose, the Kubernetes will prioritize routing traffic to endpoints that are topologically closer - `health_check_node_port` (Number) Specifies the Healthcheck NodePort for the service. Only effects when type is set to `LoadBalancer` and external_traffic_policy is set to `Local`. - `internal_traffic_policy` (String) Specifies if the cluster internal traffic should be routed to all endpoints or node-local endpoints only. `Cluster` routes internal traffic to a Service to all endpoints. `Local` routes traffic to node-local endpoints only, traffic is dropped if no node-local endpoints are ready. The default value is `Cluster`. - `ip_families` (List of String) IPFamilies is a list of IP families (e.g. IPv4, IPv6) assigned to this service. This field is usually assigned automatically based on cluster configuration and the ipFamilyPolicy field. If this field is specified manually, the requested family is available in the cluster, and ipFamilyPolicy allows it, it will be used; otherwise creation of the service will fail. This field is conditionally mutable: it allows for adding or removing a secondary IP family, but it does not allow changing the primary IP family of the Service. From 7ec763bcf88711de0471a09826a1e71dd0d9c1e4 Mon Sep 17 00:00:00 2001 From: Jaylon McShan Date: Thu, 21 Nov 2024 07:50:03 -0600 Subject: [PATCH 3/4] Adding changelog message --- .changelog/2625.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/2625.txt b/.changelog/2625.txt index bf14a476b9..2ddc6a7ced 100644 --- a/.changelog/2625.txt +++ b/.changelog/2625.txt @@ -1,3 +1,3 @@ ```release-note:enhancement - +Added the `traffic_distribution` field to the `kubernetes_service_v1` resource ``` \ No newline at end of file From d6a2d50c0b2bfea7b570800bfe5ebca23a2c3923 Mon Sep 17 00:00:00 2001 From: Jaylon McShan Date: Fri, 22 Nov 2024 07:37:25 -0600 Subject: [PATCH 4/4] Tidying up test config, changelog message and schema import --- .changelog/2625.txt | 6 +++++- kubernetes/resource_kubernetes_service_v1.go | 2 +- kubernetes/resource_kubernetes_service_v1_test.go | 5 ++++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/.changelog/2625.txt b/.changelog/2625.txt index 2ddc6a7ced..9528ae9d35 100644 --- a/.changelog/2625.txt +++ b/.changelog/2625.txt @@ -1,3 +1,7 @@ ```release-note:enhancement -Added the `traffic_distribution` field to the `kubernetes_service_v1` resource +`resource/kubernetes_service`: add a new field `traffic_distribution`. +``` + +``` +`resource/kubernetes_service_v1`: add a new field `traffic_distribution`. ``` \ No newline at end of file diff --git a/kubernetes/resource_kubernetes_service_v1.go b/kubernetes/resource_kubernetes_service_v1.go index a1151bdadb..5628a8e400 100644 --- a/kubernetes/resource_kubernetes_service_v1.go +++ b/kubernetes/resource_kubernetes_service_v1.go @@ -273,7 +273,7 @@ func resourceKubernetesServiceSchemaV1() map[string]*schema.Schema { Description: "Specifies the preferred strategy for distributing traffic to Service endpoints. When set to PreferClose, the Kubernetes will prioritize routing traffic to endpoints that are topologically closer", Optional: true, ValidateFunc: validation.StringInSlice([]string{ - "PreferClose", + corev1.ServiceTrafficDistributionPreferClose, }, false), }, "type": { diff --git a/kubernetes/resource_kubernetes_service_v1_test.go b/kubernetes/resource_kubernetes_service_v1_test.go index cf88b97e07..166c891f0d 100644 --- a/kubernetes/resource_kubernetes_service_v1_test.go +++ b/kubernetes/resource_kubernetes_service_v1_test.go @@ -825,7 +825,10 @@ func TestAccKubernetesServiceV1_trafficDistribution(t *testing.T) { resourceName := "kubernetes_service_v1.test" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { testAccPreCheck(t) }, + PreCheck: func() { + testAccPreCheck(t) + skipIfClusterVersionLessThan(t, "1.31") + }, IDRefreshIgnore: []string{"metadata.0.resource_version"}, ProviderFactories: testAccProviderFactories, CheckDestroy: testAccCheckKubernetesServiceV1Destroy,