Skip to content

Commit d20f679

Browse files
nejeceshepelyuk
authored andcommitted
feat: support topologySpreadConstraints in helm chart
- adding support for topologySpreadConstraints to allow configuring different topology strategies in OPA deployments Signed-off-by: Jernej Porenta <jernej.porenta@3fs.si>
1 parent 69e3d09 commit d20f679

File tree

5 files changed

+325
-0
lines changed

5 files changed

+325
-0
lines changed

charts/opa-kube-mgmt/templates/deployment.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -292,3 +292,5 @@ spec:
292292
{{ toYaml .Values.nodeSelector | indent 8 }}
293293
tolerations:
294294
{{ toYaml .Values.tolerations | indent 8 }}
295+
topologySpreadConstraints:
296+
{{ toYaml .Values.topologySpreadConstraints | indent 8 }}

charts/opa-kube-mgmt/values.schema.json

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,65 @@
4646
"default": null
4747
}
4848
}
49+
},
50+
"topologySpreadConstraints": {
51+
"type": "array",
52+
"items": {
53+
"type": "object",
54+
"required": ["maxSkew", "topologyKey", "whenUnsatisfiable"],
55+
"properties": {
56+
"maxSkew": {
57+
"type": "integer",
58+
"minimum": 1
59+
},
60+
"topologyKey": {
61+
"type": "string",
62+
"minLength": 1
63+
},
64+
"whenUnsatisfiable": {
65+
"type": "string",
66+
"enum": ["DoNotSchedule", "ScheduleAnyway"]
67+
},
68+
"labelSelector": {
69+
"type": "object",
70+
"properties": {
71+
"matchLabels": {
72+
"type": "object",
73+
"additionalProperties": {"type": "string"}
74+
},
75+
"matchExpressions": {
76+
"type": "array",
77+
"items": {
78+
"type": "object",
79+
"required": ["key", "operator"],
80+
"properties": {
81+
"key": {"type": "string"},
82+
"operator": {"type": "string", "enum": ["In", "NotIn", "Exists", "DoesNotExist"]},
83+
"values": {"type": "array", "items": {"type": "string"}}
84+
}
85+
}
86+
}
87+
}
88+
},
89+
"matchLabelKeys": {
90+
"type": "array",
91+
"items": {"type": "string"}
92+
},
93+
"minDomains": {
94+
"type": "integer",
95+
"minimum": 1
96+
},
97+
"nodeAffinityPolicy": {
98+
"type": "string",
99+
"enum": ["Honor", "Ignore"]
100+
},
101+
"nodeTaintsPolicy": {
102+
"type": "string",
103+
"enum": ["Honor", "Ignore"]
104+
}
105+
}
106+
},
107+
"default": []
49108
}
50109
}
51110
}

charts/opa-kube-mgmt/values.yaml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,6 +219,18 @@ affinity: {}
219219
tolerations: []
220220
nodeSelector: {}
221221

222+
# To control pod distribution across topology domains, set topologySpreadConstraints
223+
# below.
224+
#
225+
# topologySpreadConstraints:
226+
# - maxSkew: 1
227+
# topologyKey: topology.kubernetes.io/zone
228+
# whenUnsatisfiable: DoNotSchedule
229+
# labelSelector:
230+
# matchLabels:
231+
# app: opa
232+
topologySpreadConstraints: []
233+
222234
# To control the CPU and memory resource limits and requests for OPA, set the
223235
# field below.
224236
resources: {}

test/lint/tsc.yaml

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
suite: lint topologySpreadConstraints
2+
templates:
3+
- deployment.yaml
4+
tests:
5+
- it: fails when maxSkew is missing
6+
set:
7+
topologySpreadConstraints:
8+
- topologyKey: "kubernetes.io/hostname"
9+
whenUnsatisfiable: "DoNotSchedule"
10+
asserts:
11+
- failedTemplate: {}
12+
13+
- it: fails when maxSkew is null
14+
set:
15+
topologySpreadConstraints:
16+
- maxSkew: null
17+
topologyKey: "kubernetes.io/hostname"
18+
whenUnsatisfiable: "DoNotSchedule"
19+
asserts:
20+
- failedTemplate: {}
21+
22+
- it: fails when topologyKey is missing
23+
set:
24+
topologySpreadConstraints:
25+
- maxSkew: 1
26+
whenUnsatisfiable: "DoNotSchedule"
27+
asserts:
28+
- failedTemplate: {}
29+
30+
- it: fails when whenUnsatisfiable is missing
31+
set:
32+
topologySpreadConstraints:
33+
- maxSkew: 1
34+
topologyKey: "kubernetes.io/hostname"
35+
asserts:
36+
- failedTemplate: {}
37+
38+
- it: fails when maxSkew is not an integer
39+
set:
40+
topologySpreadConstraints:
41+
- maxSkew: "one"
42+
topologyKey: "kubernetes.io/hostname"
43+
whenUnsatisfiable: "DoNotSchedule"
44+
asserts:
45+
- failedTemplate: {}
46+
47+
- it: fails when topologyKey is empty string
48+
set:
49+
topologySpreadConstraints:
50+
- maxSkew: 1
51+
topologyKey: ""
52+
whenUnsatisfiable: "DoNotSchedule"
53+
asserts:
54+
- failedTemplate: {}
55+
56+
- it: fails when whenUnsatisfiable has invalid value
57+
set:
58+
topologySpreadConstraints:
59+
- maxSkew: 1
60+
topologyKey: "kubernetes.io/hostname"
61+
whenUnsatisfiable: "InvalidOption"
62+
asserts:
63+
- failedTemplate: {}
64+
65+
- it: renders with empty topologySpreadConstraints array
66+
set:
67+
topologySpreadConstraints: []
68+
asserts:
69+
- isKind:
70+
of: Deployment
71+
- isEmpty:
72+
path: spec.template.spec.topologySpreadConstraints
73+
74+
- it: renders without topologySpreadConstraints when not set
75+
asserts:
76+
- isKind:
77+
of: Deployment
78+
- isEmpty:
79+
path: spec.template.spec.topologySpreadConstraints

test/unit/tsc.yaml

Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
suite: test topologySpreadConstraints
2+
templates:
3+
- deployment.yaml
4+
tests:
5+
- it: renders with DoNotSchedule policy
6+
set:
7+
topologySpreadConstraints:
8+
- maxSkew: 1
9+
topologyKey: "kubernetes.io/hostname"
10+
whenUnsatisfiable: "DoNotSchedule"
11+
asserts:
12+
- isKind:
13+
of: Deployment
14+
- contains:
15+
path: spec.template.spec.topologySpreadConstraints
16+
content:
17+
maxSkew: 1
18+
topologyKey: "kubernetes.io/hostname"
19+
whenUnsatisfiable: "DoNotSchedule"
20+
21+
- it: renders multiple topologySpreadConstraints
22+
set:
23+
topologySpreadConstraints:
24+
- maxSkew: 1
25+
topologyKey: "traffic.kubernetes.io/region"
26+
whenUnsatisfiable: "ScheduleAnyway"
27+
- maxSkew: 2
28+
topologyKey: "topology.kubernetes.io/zone"
29+
whenUnsatisfiable: "DoNotSchedule"
30+
asserts:
31+
- lengthEqual:
32+
path: spec.template.spec.topologySpreadConstraints
33+
count: 2
34+
- contains:
35+
path: spec.template.spec.topologySpreadConstraints
36+
content:
37+
topologyKey: "traffic.kubernetes.io/region"
38+
any: true
39+
- contains:
40+
path: spec.template.spec.topologySpreadConstraints
41+
content:
42+
topologyKey: "topology.kubernetes.io/zone"
43+
any: true
44+
45+
- it: renders with labelSelector
46+
set:
47+
topologySpreadConstraints:
48+
- maxSkew: 1
49+
topologyKey: "kubernetes.io/hostname"
50+
whenUnsatisfiable: "DoNotSchedule"
51+
labelSelector:
52+
matchLabels:
53+
app: opa-kube-mgmt
54+
asserts:
55+
- contains:
56+
path: spec.template.spec.topologySpreadConstraints
57+
content:
58+
maxSkew: 1
59+
topologyKey: "kubernetes.io/hostname"
60+
whenUnsatisfiable: "DoNotSchedule"
61+
labelSelector:
62+
matchLabels:
63+
app: opa-kube-mgmt
64+
65+
- it: renders with minDomains
66+
set:
67+
topologySpreadConstraints:
68+
- maxSkew: 1
69+
topologyKey: "kubernetes.io/hostname"
70+
whenUnsatisfiable: "DoNotSchedule"
71+
minDomains: 3
72+
asserts:
73+
- contains:
74+
path: spec.template.spec.topologySpreadConstraints
75+
content:
76+
minDomains: 3
77+
any: true
78+
79+
- it: passes through constraint with labelSelector
80+
set:
81+
topologySpreadConstraints:
82+
- maxSkew: 1
83+
topologyKey: "kubernetes.io/hostname"
84+
whenUnsatisfiable: "DoNotSchedule"
85+
labelSelector:
86+
matchLabels:
87+
app: opa-kube-mgmt
88+
matchExpressions:
89+
- key: environment
90+
operator: In
91+
values:
92+
- production
93+
- staging
94+
asserts:
95+
- equal:
96+
path: spec.template.spec.topologySpreadConstraints[0].labelSelector
97+
value:
98+
matchLabels:
99+
app: opa-kube-mgmt
100+
matchExpressions:
101+
- key: environment
102+
operator: In
103+
values:
104+
- production
105+
- staging
106+
107+
- it: passes through constraint with nodeAffinityPolicy
108+
set:
109+
topologySpreadConstraints:
110+
- maxSkew: 1
111+
topologyKey: "kubernetes.io/hostname"
112+
whenUnsatisfiable: "DoNotSchedule"
113+
nodeAffinityPolicy: "Honor"
114+
asserts:
115+
- equal:
116+
path: spec.template.spec.topologySpreadConstraints[0].nodeAffinityPolicy
117+
value: "Honor"
118+
119+
- it: passes through constraint with nodeTaintsPolicy
120+
set:
121+
topologySpreadConstraints:
122+
- maxSkew: 1
123+
topologyKey: "kubernetes.io/hostname"
124+
whenUnsatisfiable: "DoNotSchedule"
125+
nodeTaintsPolicy: "Ignore"
126+
asserts:
127+
- equal:
128+
path: spec.template.spec.topologySpreadConstraints[0].nodeTaintsPolicy
129+
value: "Ignore"
130+
131+
- it: passes through constraint with matchLabelKeys
132+
set:
133+
topologySpreadConstraints:
134+
- maxSkew: 1
135+
topologyKey: "kubernetes.io/hostname"
136+
whenUnsatisfiable: "DoNotSchedule"
137+
matchLabelKeys:
138+
- config
139+
asserts:
140+
- equal:
141+
path: spec.template.spec.topologySpreadConstraints[0].matchLabelKeys
142+
value:
143+
- config
144+
145+
- it: passes through fully configured constraint
146+
set:
147+
topologySpreadConstraints:
148+
- maxSkew: 2
149+
topologyKey: "topology.kubernetes.io/zone"
150+
whenUnsatisfiable: "ScheduleAnyway"
151+
minDomains: 3
152+
nodeAffinityPolicy: "Honor"
153+
nodeTaintsPolicy: "Honor"
154+
matchLabelKeys:
155+
- pod-template-hash
156+
labelSelector:
157+
matchLabels:
158+
app: opa-kube-mgmt
159+
asserts:
160+
- equal:
161+
path: spec.template.spec.topologySpreadConstraints[0]
162+
value:
163+
maxSkew: 2
164+
topologyKey: "topology.kubernetes.io/zone"
165+
whenUnsatisfiable: "ScheduleAnyway"
166+
minDomains: 3
167+
nodeAffinityPolicy: "Honor"
168+
nodeTaintsPolicy: "Honor"
169+
matchLabelKeys:
170+
- pod-template-hash
171+
labelSelector:
172+
matchLabels:
173+
app: opa-kube-mgmt

0 commit comments

Comments
 (0)