Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding traffic_distribution field #2625

Open
wants to merge 4 commits into
base: v3-major-release
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 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
3 changes: 3 additions & 0 deletions .changelog/2625.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
Added the `traffic_distribution` field to the `kubernetes_service_v1` resource
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest to use imperative voice here and add kubernetes_service too, since both resources refer to the same code:

```release-note:enhancement
`resource/kubernetes_service`:  add a new field `traffic_distribution`.
```

```
`resource/kubernetes_service_v1`:  add a new field `traffic_distribution`.
```

```
1 change: 1 addition & 0 deletions docs/data-sources/service.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions docs/data-sources/service_v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
1 change: 1 addition & 0 deletions docs/resources/service.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
1 change: 1 addition & 0 deletions docs/resources/service_v1.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
8 changes: 8 additions & 0 deletions kubernetes/resource_kubernetes_service_v1.go
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest importing such predefined words from Kubernetes code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@arybolovlev Wow, that's a clever approach! Would this be considered best practice for the future? Due to the k8s api were to update / expand on the traffic_distrubtion field with additional options, our code would automatically align with those changes?

}, 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",
Expand Down
53 changes: 53 additions & 0 deletions kubernetes/resource_kubernetes_service_v1_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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) },
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please add here skipIfClusterVersionLessThan to make sure these test runs on Kubernetes 1.31+ only.

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 {
Expand Down Expand Up @@ -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)
}
14 changes: 13 additions & 1 deletion kubernetes/structure_service_spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand Down Expand Up @@ -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
}

Expand Down Expand Up @@ -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
}
Loading