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

Add Tolerations spec to chart configuration #221

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions pkg/apis/helm.cattle.io/v1/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ type HelmChartSpec struct {

PodSecurityContext *corev1.PodSecurityContext `json:"podSecurityContext,omitempty"`
SecurityContext *corev1.SecurityContext `json:"securityContext,omitempty"`

Tolerations []corev1.Toleration `json:"tolerations,omitempty"`
}

type HelmChartStatus struct {
Expand Down
57 changes: 31 additions & 26 deletions pkg/controllers/chart/chart.go
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,35 @@ var (
}
)

var (
bootstrapTolerations = []corev1.Toleration{
{
Key: corev1.TaintNodeNotReady,
Effect: corev1.TaintEffectNoSchedule,
},
{
Key: TaintExternalCloudProvider,
Operator: corev1.TolerationOpEqual,
Value: "true",
Effect: corev1.TaintEffectNoSchedule,
},
{
Key: "CriticalAddonsOnly",
Operator: corev1.TolerationOpExists,
},
{
Key: LabelNodeRolePrefix + LabelEtcdSuffix,
Operator: corev1.TolerationOpExists,
Effect: corev1.TaintEffectNoExecute,
},
{
Key: LabelNodeRolePrefix + LabelControlPlaneSuffix,
Operator: corev1.TolerationOpExists,
Effect: corev1.TaintEffectNoSchedule,
},
}
)

type Controller struct {
systemNamespace string
jobClusterRole string
Expand Down Expand Up @@ -525,32 +554,7 @@ func job(chart *v1.HelmChart, apiServerPort string) (*batch.Job, *corev1.Secret,
if chart.Spec.Bootstrap {
job.Spec.Template.Spec.NodeSelector[LabelNodeRolePrefix+LabelControlPlaneSuffix] = "true"
job.Spec.Template.Spec.HostNetwork = true
job.Spec.Template.Spec.Tolerations = []corev1.Toleration{
{
Key: corev1.TaintNodeNotReady,
Effect: corev1.TaintEffectNoSchedule,
},
{
Key: TaintExternalCloudProvider,
Operator: corev1.TolerationOpEqual,
Value: "true",
Effect: corev1.TaintEffectNoSchedule,
},
{
Key: "CriticalAddonsOnly",
Operator: corev1.TolerationOpExists,
},
{
Key: LabelNodeRolePrefix + LabelEtcdSuffix,
Operator: corev1.TolerationOpExists,
Effect: corev1.TaintEffectNoExecute,
},
{
Key: LabelNodeRolePrefix + LabelControlPlaneSuffix,
Operator: corev1.TolerationOpExists,
Effect: corev1.TaintEffectNoSchedule,
},
}
job.Spec.Template.Spec.Tolerations = bootstrapTolerations
job.Spec.Template.Spec.Containers[0].Env = append(job.Spec.Template.Spec.Containers[0].Env, []corev1.EnvVar{
{
Name: "KUBERNETES_SERVICE_HOST",
Expand All @@ -563,6 +567,7 @@ func job(chart *v1.HelmChart, apiServerPort string) (*batch.Job, *corev1.Secret,
Value: "true"},
}...)
}
job.Spec.Template.Spec.Tolerations = append(job.Spec.Template.Spec.Tolerations, chart.Spec.Tolerations...)

setProxyEnv(job)
setAuthSecret(job, chart)
Expand Down
253 changes: 253 additions & 0 deletions test/suite/helm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,33 @@ import (
"k8s.io/utils/pointer"
)

var bootstrapTolerations = &[]corev1.Toleration{
{
Key: "node.kubernetes.io/not-ready",
Effect: "NoSchedule",
},
{
Key: "node.cloudprovider.kubernetes.io/uninitialized",
Operator: "Equal",
Value: "true",
Effect: "NoSchedule",
},
{
Key: "CriticalAddonsOnly",
Operator: "Exists",
},
{
Key: "node-role.kubernetes.io/etcd",
Operator: "Exists",
Effect: "NoExecute",
},
{
Key: "node-role.kubernetes.io/control-plane",
Operator: "Exists",
Effect: "NoSchedule",
},
}

var _ = Describe("Helm Tests", Ordered, func() {
framework, _ := framework.New()

Expand Down Expand Up @@ -755,4 +782,230 @@ var _ = Describe("Helm Tests", Ordered, func() {
}, 120*time.Second, 5*time.Second).Should(BeTrue())
})
})

Context("When no tolerations are specified (non-boostrap)", func() {
var (
err error
chart *v1.HelmChart
job *batchv1.Job
)
BeforeEach(func() {
chart = framework.NewHelmChart("traefik-example-no-tolerations",
"stable/traefik",
"1.86.1",
"v3",
map[string]intstr.IntOrString{
"rbac.enabled": {
Type: intstr.String,
StrVal: "true",
},
"ssl.enabled": {
Type: intstr.String,
StrVal: "true",
},
})
chart, err = framework.CreateHelmChart(chart, framework.Namespace)
Expect(err).ToNot(HaveOccurred())

labelSelector := labels.SelectorFromSet(labels.Set{
"owner": "helm",
"name": chart.Name,
})
_, err = framework.WaitForRelease(chart, labelSelector, 120*time.Second, 1)
Expect(err).ToNot(HaveOccurred())

chart, err = framework.GetHelmChart(chart.Name, chart.Namespace)
Expect(err).ToNot(HaveOccurred())
job, err = framework.GetJob(chart)
Expect(err).ToNot(HaveOccurred())
})
It("Should have no tolerations set", func() {
Expect(job.Spec.Template.Spec.Tolerations).To(BeEmpty())
})
AfterEach(func() {
err = framework.DeleteHelmChart(chart.Name, framework.Namespace)
Expect(err).ToNot(HaveOccurred())

Eventually(func() bool {
_, err := framework.GetHelmChart(chart.Name, framework.Namespace)
return err != nil && apierrors.IsNotFound(err)
}, 120*time.Second, 5*time.Second).Should(BeTrue())
})
})

Context("When custom tolerations are specified (non-boostrap)", func() {
var (
err error
chart *v1.HelmChart
job *batchv1.Job
tolerations = &[]corev1.Toleration{
{
Key: "test-1",
Effect: corev1.TaintEffectNoSchedule,
},
{
Key: "test-2",
Effect: corev1.TaintEffectNoExecute,
},
}
)
BeforeEach(func() {
chart = framework.NewHelmChart("traefik-example-custom-tolerations",
"stable/traefik",
"1.86.1",
"v3",
map[string]intstr.IntOrString{
"rbac.enabled": {
Type: intstr.String,
StrVal: "true",
},
"ssl.enabled": {
Type: intstr.String,
StrVal: "true",
},
})
chart.Spec.Tolerations = *tolerations
chart, err = framework.CreateHelmChart(chart, framework.Namespace)
Expect(err).ToNot(HaveOccurred())

labelSelector := labels.SelectorFromSet(labels.Set{
"owner": "helm",
"name": chart.Name,
})
_, err = framework.WaitForRelease(chart, labelSelector, 120*time.Second, 1)
Expect(err).ToNot(HaveOccurred())

chart, err = framework.GetHelmChart(chart.Name, chart.Namespace)
Expect(err).ToNot(HaveOccurred())
job, err = framework.GetJob(chart)
Expect(err).ToNot(HaveOccurred())
})
It("Should have tolerations set", func() {
Expect(job.Spec.Template.Spec.Tolerations).To(Equal(*tolerations))
})
AfterEach(func() {
err = framework.DeleteHelmChart(chart.Name, framework.Namespace)
Expect(err).ToNot(HaveOccurred())

Eventually(func() bool {
_, err := framework.GetHelmChart(chart.Name, framework.Namespace)
return err != nil && apierrors.IsNotFound(err)
}, 120*time.Second, 5*time.Second).Should(BeTrue())
})
})

Context("When no tolerations are specified (boostrap)", func() {
var (
err error
chart *v1.HelmChart
job *batchv1.Job
)
BeforeEach(func() {
chart = framework.NewHelmChart("traefik-example-bootstrap-default-tolerations",
"stable/traefik",
"1.86.1",
"v3",
map[string]intstr.IntOrString{
"rbac.enabled": {
Type: intstr.String,
StrVal: "true",
},
"ssl.enabled": {
Type: intstr.String,
StrVal: "true",
},
})
chart.Spec.Bootstrap = true
chart, err = framework.CreateHelmChart(chart, framework.Namespace)
Expect(err).ToNot(HaveOccurred())

labelSelector := labels.SelectorFromSet(labels.Set{
"owner": "helm",
"name": chart.Name,
})
_, err = framework.WaitForRelease(chart, labelSelector, 120*time.Second, 1)
Expect(err).ToNot(HaveOccurred())

chart, err = framework.GetHelmChart(chart.Name, chart.Namespace)
Expect(err).ToNot(HaveOccurred())
job, err = framework.GetJob(chart)
Expect(err).ToNot(HaveOccurred())
})
It("Should have default tolerations set", func() {
Expect(job.Spec.Template.Spec.Tolerations).To(Equal(*bootstrapTolerations))
})
AfterEach(func() {
err = framework.DeleteHelmChart(chart.Name, framework.Namespace)
Expect(err).ToNot(HaveOccurred())

Eventually(func() bool {
_, err := framework.GetHelmChart(chart.Name, framework.Namespace)
return err != nil && apierrors.IsNotFound(err)
}, 120*time.Second, 5*time.Second).Should(BeTrue())
})
})

Context("When custom tolerations are specified (boostrap)", func() {
var (
err error
chart *v1.HelmChart
job *batchv1.Job
specTolerations = &[]corev1.Toleration{
{
Key: "test-1",
Effect: corev1.TaintEffectNoSchedule,
},
{
Key: "test-2",
Effect: corev1.TaintEffectNoExecute,
},
}
finalTolerations = append(*bootstrapTolerations, *specTolerations...)
)
BeforeEach(func() {
chart = framework.NewHelmChart("traefik-example-bootstrap-custom-tolerations",
"stable/traefik",
"1.86.1",
"v3",
map[string]intstr.IntOrString{
"rbac.enabled": {
Type: intstr.String,
StrVal: "true",
},
"ssl.enabled": {
Type: intstr.String,
StrVal: "true",
},
})
chart.Spec.Tolerations = *specTolerations
chart.Spec.Bootstrap = true
chart, err = framework.CreateHelmChart(chart, framework.Namespace)
Expect(err).ToNot(HaveOccurred())

labelSelector := labels.SelectorFromSet(labels.Set{
"owner": "helm",
"name": chart.Name,
})
_, err = framework.WaitForRelease(chart, labelSelector, 120*time.Second, 1)
Expect(err).ToNot(HaveOccurred())

chart, err = framework.GetHelmChart(chart.Name, chart.Namespace)
Expect(err).ToNot(HaveOccurred())
job, err = framework.GetJob(chart)
Expect(err).ToNot(HaveOccurred())
})
It("Should have tolerations set", func() {
Expect(job.Spec.Template.Spec.Tolerations).To(Equal(finalTolerations))
})
AfterEach(func() {
err = framework.DeleteHelmChart(chart.Name, framework.Namespace)
Expect(err).ToNot(HaveOccurred())

Eventually(func() bool {
_, err := framework.GetHelmChart(chart.Name, framework.Namespace)
return err != nil && apierrors.IsNotFound(err)
}, 120*time.Second, 5*time.Second).Should(BeTrue())
})
})

})