Skip to content
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())
})
})

})