Skip to content

Commit 63516a1

Browse files
committed
HCP: fix handling of tolerations with no key/value
Fixes rendering of tolerations that do not include a key/value.
1 parent ad26055 commit 63516a1

File tree

2 files changed

+154
-12
lines changed

2 files changed

+154
-12
lines changed

pkg/hypershift/hypershift.go

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -331,19 +331,52 @@ func tolerationsToStringSliceYaml(tolerations []corev1.Toleration) ([]string, er
331331
return nil, nil
332332
}
333333

334-
yamlBytes, err := yaml.Marshal(tolerations)
335-
if err != nil {
336-
return nil, err
337-
}
334+
var result []string
335+
336+
for _, toleration := range tolerations {
337+
// Marshal single toleration
338+
yamlBytes, err := yaml.Marshal(toleration)
339+
if err != nil {
340+
return nil, err
341+
}
342+
343+
// Process the single toleration's YAML lines
344+
lines := strings.Split(string(yamlBytes), "\n")
345+
var tolerationLines []string
346+
347+
for _, line := range lines {
348+
// Skip empty lines
349+
if strings.TrimSpace(line) == "" {
350+
continue
351+
}
338352

339-
yamlStrs := []string{}
340-
for _, arg := range strings.Split(string(yamlBytes), "\n") {
353+
// filter out empty strings but keep null values as they are valid for tolerations
354+
if strings.Contains(line, ": \"\"") {
355+
continue
356+
}
357+
358+
// filter out null values including tolerationseconds: null
359+
if strings.Contains(line, ": null") {
360+
continue
361+
}
362+
363+
tolerationLines = append(tolerationLines, line)
364+
}
341365

342-
// filter out null and empty strings
343-
if strings.Contains(arg, ": null") || strings.Contains(arg, ": \"\"") {
344-
continue
366+
// Add array marker to the first line and proper indentation to all lines
367+
for i := range tolerationLines {
368+
if i == 0 {
369+
// First line gets the array marker
370+
tolerationLines[i] = "- " + strings.TrimSpace(tolerationLines[i])
371+
} else {
372+
// Subsequent lines get proper indentation (2 spaces)
373+
tolerationLines[i] = " " + strings.TrimSpace(tolerationLines[i])
374+
}
345375
}
346-
yamlStrs = append(yamlStrs, arg)
376+
377+
// Add all lines from this toleration to the result
378+
result = append(result, tolerationLines...)
347379
}
348-
return yamlStrs, nil
380+
381+
return result, nil
349382
}

pkg/hypershift/hypershift_test.go

Lines changed: 110 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package hypershift
22

33
import (
4+
"testing"
5+
46
. "github.com/onsi/gomega"
7+
corev1 "k8s.io/api/core/v1"
58
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
69
"k8s.io/apimachinery/pkg/runtime"
710
"k8s.io/apimachinery/pkg/util/yaml"
8-
"testing"
911
)
1012

1113
func TestParseHostedControlPlane(t *testing.T) {
@@ -103,3 +105,110 @@ spec:
103105
g.Expect(actualOutput).To(Equal(tc.expectedOutput))
104106
}
105107
}
108+
109+
func TestTolerationsToStringSliceYaml(t *testing.T) {
110+
g := NewGomegaWithT(t)
111+
112+
testCases := []struct {
113+
name string
114+
tolerations []corev1.Toleration
115+
expected []string
116+
}{
117+
{
118+
name: "operator Exists with no key or value should generate valid YAML",
119+
tolerations: []corev1.Toleration{
120+
{
121+
Operator: corev1.TolerationOpExists,
122+
},
123+
},
124+
expected: []string{
125+
"- operator: Exists",
126+
},
127+
},
128+
{
129+
name: "operator Equal with key and value should include all fields",
130+
tolerations: []corev1.Toleration{
131+
{
132+
Key: "node-role.kubernetes.io/master",
133+
Operator: corev1.TolerationOpEqual,
134+
Value: "true",
135+
Effect: corev1.TaintEffectNoSchedule,
136+
},
137+
},
138+
expected: []string{
139+
"- key: node-role.kubernetes.io/master",
140+
" operator: Equal",
141+
" value: \"true\"",
142+
" effect: NoSchedule",
143+
},
144+
},
145+
{
146+
name: "empty string values should be filtered out",
147+
tolerations: []corev1.Toleration{
148+
{
149+
Key: "test-key",
150+
Operator: corev1.TolerationOpEqual,
151+
Value: "",
152+
Effect: corev1.TaintEffectNoSchedule,
153+
},
154+
},
155+
expected: []string{
156+
"- key: test-key",
157+
" operator: Equal",
158+
" effect: NoSchedule",
159+
},
160+
},
161+
{
162+
name: "operator Exists with key should not include null value",
163+
tolerations: []corev1.Toleration{
164+
{
165+
Key: "node.kubernetes.io/unreachable",
166+
Operator: corev1.TolerationOpExists,
167+
Effect: corev1.TaintEffectNoExecute,
168+
},
169+
},
170+
expected: []string{
171+
"- key: node.kubernetes.io/unreachable",
172+
" operator: Exists",
173+
" effect: NoExecute",
174+
},
175+
},
176+
{
177+
name: "multiple tolerations should generate proper YAML array",
178+
tolerations: []corev1.Toleration{
179+
{
180+
Key: "node-role.kubernetes.io/master",
181+
Operator: corev1.TolerationOpEqual,
182+
Value: "true",
183+
Effect: corev1.TaintEffectNoSchedule,
184+
},
185+
{
186+
Operator: corev1.TolerationOpExists,
187+
},
188+
{
189+
Key: "node.kubernetes.io/unreachable",
190+
Operator: corev1.TolerationOpExists,
191+
Effect: corev1.TaintEffectNoExecute,
192+
},
193+
},
194+
expected: []string{
195+
"- key: node-role.kubernetes.io/master",
196+
" operator: Equal",
197+
" value: \"true\"",
198+
" effect: NoSchedule",
199+
"- operator: Exists",
200+
"- key: node.kubernetes.io/unreachable",
201+
" operator: Exists",
202+
" effect: NoExecute",
203+
},
204+
},
205+
}
206+
207+
for _, tc := range testCases {
208+
t.Run(tc.name, func(t *testing.T) {
209+
result, err := tolerationsToStringSliceYaml(tc.tolerations)
210+
g.Expect(err).NotTo(HaveOccurred())
211+
g.Expect(result).To(Equal(tc.expected), "Expected exact YAML format match")
212+
})
213+
}
214+
}

0 commit comments

Comments
 (0)