Skip to content

Commit

Permalink
feat: Add missing topologySpreadConstraints (hashicorp#2429)
Browse files Browse the repository at this point in the history
* Add minDomains topologySpreadConstraint

* Add node affinity and taints policy

* Add match_label_keys to topologySpreadConstraint
  • Loading branch information
appilon authored Feb 27, 2024
1 parent 06a0123 commit 75da873
Show file tree
Hide file tree
Showing 6 changed files with 130 additions and 4 deletions.
3 changes: 3 additions & 0 deletions .changelog/2429.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
`resource/kubernetes_pod_v1`: add missing `topology_spread_constraints`: `node_affinity_policy`, `node_taints_policy`, `match_label_keys`, `min_domains`
```
69 changes: 65 additions & 4 deletions kubernetes/resource_kubernetes_pod_v1_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1440,7 +1440,6 @@ func TestAccKubernetesPodV1_topologySpreadConstraint(t *testing.T) {
resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
skipIfClusterVersionGreaterThanOrEqual(t, "1.17.0")
},
ProviderFactories: testAccProviderFactories,
CheckDestroy: testAccCheckKubernetesPodV1Destroy,
Expand All @@ -1450,7 +1449,10 @@ func TestAccKubernetesPodV1_topologySpreadConstraint(t *testing.T) {
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckKubernetesPodV1Exists(resourceName, &conf1),
resource.TestCheckResourceAttr(resourceName, "spec.0.topology_spread_constraint.#", "1"),
resource.TestCheckTypeSetElemAttr(resourceName, "spec.0.topology_spread_constraint.0.match_label_keys.*", "pod-template-hash"),
resource.TestCheckResourceAttr(resourceName, "spec.0.topology_spread_constraint.0.max_skew", "1"),
resource.TestCheckResourceAttr(resourceName, "spec.0.topology_spread_constraint.0.node_affinity_policy", "Ignore"),
resource.TestCheckResourceAttr(resourceName, "spec.0.topology_spread_constraint.0.node_taints_policy", "Honor"),
resource.TestCheckResourceAttr(resourceName, "spec.0.topology_spread_constraint.0.topology_key", "topology.kubernetes.io/zone"),
resource.TestCheckResourceAttr(resourceName, "spec.0.topology_spread_constraint.0.when_unsatisfiable", "ScheduleAnyway"),
),
Expand All @@ -1465,6 +1467,38 @@ func TestAccKubernetesPodV1_topologySpreadConstraint(t *testing.T) {
})
}

func TestAccKubernetesPodV1_topologySpreadConstraintMinDomains(t *testing.T) {
var conf1 api.Pod

podName := acctest.RandomWithPrefix("tf-acc-test")
resourceName := "kubernetes_pod_v1.test"
imageName := busyboxImage

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
testAccPreCheck(t)
},
ProviderFactories: testAccProviderFactories,
CheckDestroy: testAccCheckKubernetesPodV1Destroy,
Steps: []resource.TestStep{
{
Config: testAccKubernetesPodV1TopologySpreadConstraintConfigMinDomains(podName, imageName),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckKubernetesPodV1Exists(resourceName, &conf1),
resource.TestCheckResourceAttr(resourceName, "spec.0.topology_spread_constraint.#", "1"),
resource.TestCheckResourceAttr(resourceName, "spec.0.topology_spread_constraint.0.min_domains", "1"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"metadata.0.resource_version"},
},
},
})
}

func TestAccKubernetesPodV1_runtimeClassName(t *testing.T) {
var conf1 api.Pod

Expand Down Expand Up @@ -3219,9 +3253,12 @@ func testAccKubernetesPodV1TopologySpreadConstraintConfig(podName, imageName str
name = "containername"
}
topology_spread_constraint {
max_skew = 1
topology_key = "topology.kubernetes.io/zone"
when_unsatisfiable = "ScheduleAnyway"
match_label_keys = ["pod-template-hash"]
max_skew = 1
node_affinity_policy = "Ignore"
node_taints_policy = "Honor"
topology_key = "topology.kubernetes.io/zone"
when_unsatisfiable = "ScheduleAnyway"
label_selector {
match_labels = {
"app.kubernetes.io/instance" = "terraform-example"
Expand All @@ -3233,6 +3270,30 @@ func testAccKubernetesPodV1TopologySpreadConstraintConfig(podName, imageName str
`, podName, imageName)
}

func testAccKubernetesPodV1TopologySpreadConstraintConfigMinDomains(podName, imageName string) string {
return fmt.Sprintf(`resource "kubernetes_pod_v1" "test" {
metadata {
name = "%s"
}
spec {
container {
image = "%s"
name = "containername"
}
topology_spread_constraint {
min_domains = 1
topology_key = "kubernetes.io/hostname"
label_selector {
match_labels = {
"test" = "test"
}
}
}
}
}
`, podName, imageName)
}

func testAccKubernetesPodV1ConfigRuntimeClassName(name, imageName, runtimeHandler string) string {
return fmt.Sprintf(`resource "kubernetes_runtime_class_v1" "test" {
metadata {
Expand Down
30 changes: 30 additions & 0 deletions kubernetes/schema_pod_spec.go
Original file line number Diff line number Diff line change
Expand Up @@ -497,13 +497,43 @@ func podSpecFields(isUpdatable, isComputed bool) map[string]*schema.Schema {
Description: "describes how a group of pods ought to spread across topology domains. Scheduler will schedule pods in a way which abides by the constraints.",
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"match_label_keys": {
Type: schema.TypeSet,
Description: "is a set of pod label keys to select the pods over which spreading will be calculated.",
Optional: true,
ForceNew: !isUpdatable,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"max_skew": {
Type: schema.TypeInt,
Description: "describes the degree to which pods may be unevenly distributed.",
Optional: true,
Default: 1,
ValidateFunc: validation.IntAtLeast(1),
},
"min_domains": {
Type: schema.TypeInt,
Description: "indicates a minimum number of eligible domains.",
Optional: true,
ForceNew: !isUpdatable,
ValidateFunc: validation.IntAtLeast(1),
},
"node_affinity_policy": {
Type: schema.TypeString,
Description: "indicates how we will treat Pod's nodeAffinity/nodeSelector when calculating pod topology spread skew.",
Optional: true,
ForceNew: !isUpdatable,
ValidateFunc: validation.StringInSlice([]string{string(corev1.NodeInclusionPolicyHonor), string(corev1.NodeInclusionPolicyIgnore)}, false),
},
"node_taints_policy": {
Type: schema.TypeString,
Description: "indicates how we will treat node taints when calculating pod topology spread skew.",
Optional: true,
ForceNew: !isUpdatable,
ValidateFunc: validation.StringInSlice([]string{string(corev1.NodeInclusionPolicyHonor), string(corev1.NodeInclusionPolicyIgnore)}, false),
},
"topology_key": {
Type: schema.TypeString,
Description: "the key of node labels. Nodes that have a label with this key and identical values are considered to be in the same topology.",
Expand Down
24 changes: 24 additions & 0 deletions kubernetes/structures_pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -331,9 +331,21 @@ func flattenTopologySpreadConstraints(tsc []v1.TopologySpreadConstraint) []inter
if v.TopologyKey != "" {
obj["topology_key"] = v.TopologyKey
}
if len(v.MatchLabelKeys) != 0 {
obj["match_label_keys"] = newStringSet(schema.HashString, v.MatchLabelKeys)
}
if v.MaxSkew != 0 {
obj["max_skew"] = v.MaxSkew
}
if v.MinDomains != nil && *v.MinDomains != 0 {
obj["min_domains"] = int(*v.MinDomains)
}
if v.NodeAffinityPolicy != nil && *v.NodeAffinityPolicy != "" {
obj["node_affinity_policy"] = string(*v.NodeAffinityPolicy)
}
if v.NodeTaintsPolicy != nil && *v.NodeAffinityPolicy != "" {
obj["node_taints_policy"] = string(*v.NodeTaintsPolicy)
}
if v.WhenUnsatisfiable != "" {
obj["when_unsatisfiable"] = string(v.WhenUnsatisfiable)
}
Expand Down Expand Up @@ -1493,9 +1505,21 @@ func expandTopologySpreadConstraints(tsc []interface{}) []v1.TopologySpreadConst
ts[i].WhenUnsatisfiable = v1.UnsatisfiableConstraintAction(value)
}

if value, ok := m["match_label_keys"].(*schema.Set); ok && value != nil {
ts[i].MatchLabelKeys = sliceOfString(value.List())
}
if value, ok := m["max_skew"].(int); ok {
ts[i].MaxSkew = int32(value)
}
if value, ok := m["min_domains"].(int); ok && value != 0 {
ts[i].MinDomains = ptr.To(int32(value))
}
if value, ok := m["node_affinity_policy"].(string); ok && value != "" {
ts[i].NodeAffinityPolicy = ptr.To(v1.NodeInclusionPolicy(value))
}
if value, ok := m["node_taints_policy"].(string); ok && value != "" {
ts[i].NodeTaintsPolicy = ptr.To(v1.NodeInclusionPolicy(value))
}

}
return ts
Expand Down
4 changes: 4 additions & 0 deletions website/docs/r/pod.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -863,7 +863,11 @@ The `items` block supports the following:

#### Arguments

* `match_label_keys` - (Optional) Is a set of pod label keys to select the pods over which spreading will be calculated. The keys are used to lookup values from the incoming pod labels, those key-value labels are ANDed with labelSelector to select the group of existing pods over which spreading will be calculated for the incoming pod. The same key is forbidden to exist in both `match_label_keys` and `label_selector`. `match_label_keys` cannot be set when `label_selector` isn't set. Keys that don't exist in the incoming pod labels will be ignored. A null or empty list means only match against `label_selector`.
* `max_skew` - (Optional) Describes the degree to which pods may be unevenly distributed. Default value is `1`.
* `min_domains` - (Optional) Indicates a minimum number of eligible domains. Must be number greater than `0`. When set, `when_unsatisfiable` must be set to `DoNotSchedule`.
* `node_affinity_policy` - (Optional) Indicates how we will treat Pod's nodeAffinity/nodeSelector when calculating pod topology spread skew. Valid values are `Honor` and `Ignore`. When unset, behavior defaults to `Honor`.
* `node_taints_policy` - (Optional) Indicates how we will treat node taints when calculating pod topology spread skew. Valid values are `Honor` and `Ignore`. When unset, behavior defaults to `Ignore`.
* `topology_key` - (Optional) The key of node labels. Nodes that have a label with this key and identical values are considered to be in the same topology.
* `when_unsatisfiable` - (Optional) Indicates how to deal with a pod if it doesn't satisfy the spread constraint. Valid values are `DoNotSchedule` and `ScheduleAnyway`. Default value is `DoNotSchedule`.
* `label_selector` - (Optional) A label query over a set of resources, in this case pods.
Expand Down
4 changes: 4 additions & 0 deletions website/docs/r/pod_v1.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -852,7 +852,11 @@ The `items` block supports the following:

#### Arguments

* `match_label_keys` - (Optional) Is a set of pod label keys to select the pods over which spreading will be calculated. The keys are used to lookup values from the incoming pod labels, those key-value labels are ANDed with labelSelector to select the group of existing pods over which spreading will be calculated for the incoming pod. The same key is forbidden to exist in both `match_label_keys` and `label_selector`. `match_label_keys` cannot be set when `label_selector` isn't set. Keys that don't exist in the incoming pod labels will be ignored. A null or empty list means only match against `label_selector`.
* `max_skew` - (Optional) Describes the degree to which pods may be unevenly distributed. Default value is `1`.
* `min_domains` - (Optional) Indicates a minimum number of eligible domains. Must be number greater than `0`. When set, `when_unsatisfiable` must be set to `DoNotSchedule`.
* `node_affinity_policy` - (Optional) Indicates how we will treat Pod's nodeAffinity/nodeSelector when calculating pod topology spread skew. Valid values are `Honor` and `Ignore`. When unset, behavior defaults to `Honor`.
* `node_taints_policy` - (Optional) Indicates how we will treat node taints when calculating pod topology spread skew. Valid values are `Honor` and `Ignore`. When unset, behavior defaults to `Ignore`.
* `topology_key` - (Optional) The key of node labels. Nodes that have a label with this key and identical values are considered to be in the same topology.
* `when_unsatisfiable` - (Optional) Indicates how to deal with a pod if it doesn't satisfy the spread constraint. Valid values are `DoNotSchedule` and `ScheduleAnyway`. Default value is `DoNotSchedule`.
* `label_selector` - (Optional) A label query over a set of resources, in this case pods.
Expand Down

0 comments on commit 75da873

Please sign in to comment.