Skip to content

Commit f694b8b

Browse files
committed
Helm: Add API server rollout restart CronJob
1 parent 1d50c07 commit f694b8b

9 files changed

Lines changed: 679 additions & 0 deletions

chart/templates/_helpers.yaml

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -423,6 +423,10 @@ If release name contains chart name it will be used as a full name.
423423
{{- printf "%s:%s" .Values.images.otelCollector.repository .Values.images.otelCollector.tag }}
424424
{{- end }}
425425

426+
{{- define "kubectl_image" -}}
427+
{{- printf "%s:%s" .Values.images.kubectl.repository .Values.images.kubectl.tag }}
428+
{{- end }}
429+
426430
{{- define "fernet_key_secret" -}}
427431
{{- default (printf "%s-fernet-key" (include "airflow.fullname" .)) .Values.fernetKeySecretName }}
428432
{{- end }}
@@ -763,6 +767,16 @@ server_tls_key_file = /etc/pgbouncer/server.key
763767
{{- include "_serviceAccountName" (merge (dict "key" "databaseCleanup" "nameSuffix" "database-cleanup") .) -}}
764768
{{- end }}
765769

770+
{{/* Create the name of the API server rollout restart service account to use */}}
771+
{{- define "apiServerRolloutRestart.serviceAccountName" -}}
772+
{{- $sa := .Values.apiServer.rolloutRestart.serviceAccount -}}
773+
{{- if $sa.create -}}
774+
{{- default (printf "%s-%s" (include "airflow.serviceAccountName" .) "api-server-rollout-restart") $sa.name | quote -}}
775+
{{- else -}}
776+
{{- default "default" $sa.name | quote -}}
777+
{{- end -}}
778+
{{- end }}
779+
766780
{{- define "wait-for-migrations-command" }}
767781
- airflow
768782
- db
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
{{/*
2+
Licensed to the Apache Software Foundation (ASF) under one
3+
or more contributor license agreements. See the NOTICE file
4+
distributed with this work for additional information
5+
regarding copyright ownership. The ASF licenses this file
6+
to you under the Apache License, Version 2.0 (the
7+
"License"); you may not use this file except in compliance
8+
with the License. You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing,
13+
software distributed under the License is distributed on an
14+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
KIND, either express or implied. See the License for the
16+
specific language governing permissions and limitations
17+
under the License.
18+
*/}}
19+
20+
################################
21+
## Airflow API Server Rollout Restart CronJob
22+
#################################
23+
{{- if and .Values.apiServer.enabled .Values.apiServer.rolloutRestart.enabled }}
24+
{{- $nodeSelector := or .Values.apiServer.rolloutRestart.nodeSelector .Values.nodeSelector }}
25+
{{- $affinity := or .Values.apiServer.rolloutRestart.affinity .Values.affinity }}
26+
{{- $tolerations := or .Values.apiServer.rolloutRestart.tolerations .Values.tolerations }}
27+
{{- $topologySpreadConstraints := or .Values.apiServer.rolloutRestart.topologySpreadConstraints .Values.topologySpreadConstraints }}
28+
{{- $securityContext := include "airflowPodSecurityContext" (list .Values.apiServer.rolloutRestart .Values) }}
29+
{{- $containerSecurityContext := include "containerSecurityContext" (list .Values.apiServer.rolloutRestart .Values) }}
30+
{{- $deploymentName := .Values.apiServer.rolloutRestart.deploymentName | default (printf "%s-api-server" (include "airflow.fullname" .)) }}
31+
apiVersion: batch/v1
32+
kind: CronJob
33+
metadata:
34+
name: {{ include "airflow.fullname" . }}-api-server-rollout-restart
35+
labels:
36+
tier: airflow
37+
component: api-server-rollout-restart
38+
release: {{ .Release.Name }}
39+
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
40+
heritage: {{ .Release.Service }}
41+
{{- with .Values.labels }}
42+
{{- toYaml . | nindent 4 }}
43+
{{- end }}
44+
{{- with .Values.apiServer.rolloutRestart.jobAnnotations }}
45+
annotations: {{- toYaml . | nindent 4 }}
46+
{{- end }}
47+
spec:
48+
schedule: "{{ tpl .Values.apiServer.rolloutRestart.schedule . }}"
49+
# The cron job does not allow concurrent runs; if it is time for a new job run and the previous job run hasn't finished yet, the cron job skips the new job run
50+
concurrencyPolicy: Forbid
51+
{{- if not (eq .Values.apiServer.rolloutRestart.failedJobsHistoryLimit nil) }}
52+
failedJobsHistoryLimit: {{ .Values.apiServer.rolloutRestart.failedJobsHistoryLimit }}
53+
{{- end }}
54+
{{- if not (eq .Values.apiServer.rolloutRestart.successfulJobsHistoryLimit nil) }}
55+
successfulJobsHistoryLimit: {{ .Values.apiServer.rolloutRestart.successfulJobsHistoryLimit }}
56+
{{- end }}
57+
jobTemplate:
58+
spec:
59+
backoffLimit: 1
60+
template:
61+
metadata:
62+
labels:
63+
tier: airflow
64+
component: api-server-rollout-restart
65+
release: {{ .Release.Name }}
66+
{{- if or .Values.labels .Values.apiServer.rolloutRestart.labels }}
67+
{{- mustMerge .Values.apiServer.rolloutRestart.labels .Values.labels | toYaml | nindent 12 }}
68+
{{- end }}
69+
annotations:
70+
{{- if .Values.airflowPodAnnotations }}
71+
{{- tpl (toYaml .Values.airflowPodAnnotations) . | nindent 12 }}
72+
{{- end }}
73+
{{- if .Values.apiServer.rolloutRestart.podAnnotations }}
74+
{{- tpl (toYaml .Values.apiServer.rolloutRestart.podAnnotations) . | nindent 12 }}
75+
{{- end }}
76+
spec:
77+
restartPolicy: Never
78+
{{- if .Values.apiServer.rolloutRestart.priorityClassName }}
79+
priorityClassName: {{ .Values.apiServer.rolloutRestart.priorityClassName }}
80+
{{- end }}
81+
nodeSelector: {{- toYaml $nodeSelector | nindent 12 }}
82+
affinity: {{- toYaml $affinity | nindent 12 }}
83+
{{- if .Values.schedulerName }}
84+
schedulerName: {{ .Values.schedulerName }}
85+
{{- end }}
86+
tolerations: {{- toYaml $tolerations | nindent 12 }}
87+
topologySpreadConstraints: {{- toYaml $topologySpreadConstraints | nindent 12 }}
88+
serviceAccountName: {{ include "apiServerRolloutRestart.serviceAccountName" . }}
89+
imagePullSecrets: {{- include "image_pull_secrets" . | nindent 12 }}
90+
securityContext: {{ $securityContext | nindent 12 }}
91+
containers:
92+
- name: api-server-rollout-restart
93+
image: {{ template "kubectl_image" . }}
94+
imagePullPolicy: {{ .Values.images.kubectl.pullPolicy }}
95+
securityContext: {{ $containerSecurityContext | nindent 16 }}
96+
{{- if .Values.apiServer.rolloutRestart.command }}
97+
command: {{ tpl (toYaml .Values.apiServer.rolloutRestart.command) . | nindent 16 }}
98+
{{- end }}
99+
{{- if .Values.apiServer.rolloutRestart.args }}
100+
args: {{ tpl (toYaml .Values.apiServer.rolloutRestart.args) . | nindent 16 }}
101+
{{- else }}
102+
args:
103+
- rollout
104+
- restart
105+
- deployment/{{ $deploymentName }}
106+
- --namespace
107+
- {{ .Release.Namespace }}
108+
{{- end }}
109+
resources: {{- toYaml .Values.apiServer.rolloutRestart.resources | nindent 16 }}
110+
{{- end }}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
{{/*
2+
Licensed to the Apache Software Foundation (ASF) under one
3+
or more contributor license agreements. See the NOTICE file
4+
distributed with this work for additional information
5+
regarding copyright ownership. The ASF licenses this file
6+
to you under the Apache License, Version 2.0 (the
7+
"License"); you may not use this file except in compliance
8+
with the License. You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing,
13+
software distributed under the License is distributed on an
14+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
KIND, either express or implied. See the License for the
16+
specific language governing permissions and limitations
17+
under the License.
18+
*/}}
19+
20+
################################
21+
## Airflow API Server Rollout Restart ServiceAccount
22+
#################################
23+
{{- if and .Values.apiServer.enabled .Values.apiServer.rolloutRestart.enabled .Values.apiServer.rolloutRestart.serviceAccount.create }}
24+
apiVersion: v1
25+
kind: ServiceAccount
26+
automountServiceAccountToken: {{ .Values.apiServer.rolloutRestart.serviceAccount.automountServiceAccountToken }}
27+
metadata:
28+
name: {{ include "apiServerRolloutRestart.serviceAccountName" . }}
29+
labels:
30+
tier: airflow
31+
component: api-server-rollout-restart
32+
release: {{ .Release.Name }}
33+
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
34+
heritage: {{ .Release.Service }}
35+
{{- if or .Values.labels .Values.apiServer.rolloutRestart.labels }}
36+
{{- mustMerge .Values.apiServer.rolloutRestart.labels .Values.labels | toYaml | nindent 4 }}
37+
{{- end }}
38+
{{- with .Values.apiServer.rolloutRestart.serviceAccount.annotations }}
39+
annotations:
40+
{{- include "airflow.tplDict" (dict "values" . "context" $) | nindent 4 }}
41+
{{- end }}
42+
{{- end }}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{{/*
2+
Licensed to the Apache Software Foundation (ASF) under one
3+
or more contributor license agreements. See the NOTICE file
4+
distributed with this work for additional information
5+
regarding copyright ownership. The ASF licenses this file
6+
to you under the Apache License, Version 2.0 (the
7+
"License"); you may not use this file except in compliance
8+
with the License. You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing,
13+
software distributed under the License is distributed on an
14+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
KIND, either express or implied. See the License for the
16+
specific language governing permissions and limitations
17+
under the License.
18+
*/}}
19+
20+
################################
21+
## Airflow API Server Rollout Restart Role
22+
#################################
23+
{{- if and .Values.rbac.create .Values.apiServer.enabled .Values.apiServer.rolloutRestart.enabled }}
24+
apiVersion: rbac.authorization.k8s.io/v1
25+
kind: Role
26+
metadata:
27+
name: {{ include "airflow.fullname" . }}-api-server-rollout-restart-role
28+
labels:
29+
tier: airflow
30+
release: {{ .Release.Name }}
31+
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
32+
heritage: {{ .Release.Service }}
33+
{{- with .Values.labels }}
34+
{{- toYaml . | nindent 4 }}
35+
{{- end }}
36+
rules:
37+
- apiGroups:
38+
- "apps"
39+
resources:
40+
- "deployments"
41+
verbs:
42+
- "get"
43+
- "patch"
44+
{{- end }}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
{{/*
2+
Licensed to the Apache Software Foundation (ASF) under one
3+
or more contributor license agreements. See the NOTICE file
4+
distributed with this work for additional information
5+
regarding copyright ownership. The ASF licenses this file
6+
to you under the Apache License, Version 2.0 (the
7+
"License"); you may not use this file except in compliance
8+
with the License. You may obtain a copy of the License at
9+
10+
http://www.apache.org/licenses/LICENSE-2.0
11+
12+
Unless required by applicable law or agreed to in writing,
13+
software distributed under the License is distributed on an
14+
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15+
KIND, either express or implied. See the License for the
16+
specific language governing permissions and limitations
17+
under the License.
18+
*/}}
19+
20+
################################
21+
## Airflow API Server Rollout Restart Role Binding
22+
#################################
23+
{{- if and .Values.rbac.create .Values.apiServer.enabled .Values.apiServer.rolloutRestart.enabled }}
24+
apiVersion: rbac.authorization.k8s.io/v1
25+
kind: RoleBinding
26+
metadata:
27+
name: {{ include "airflow.fullname" . }}-api-server-rollout-restart-rolebinding
28+
labels:
29+
tier: airflow
30+
release: {{ .Release.Name }}
31+
chart: "{{ .Chart.Name }}-{{ .Chart.Version }}"
32+
heritage: {{ .Release.Service }}
33+
{{- with .Values.labels }}
34+
{{- toYaml . | nindent 4 }}
35+
{{- end }}
36+
roleRef:
37+
apiGroup: rbac.authorization.k8s.io
38+
kind: Role
39+
name: {{ include "airflow.fullname" . }}-api-server-rollout-restart-role
40+
subjects:
41+
- kind: ServiceAccount
42+
name: {{ include "apiServerRolloutRestart.serviceAccountName" . }}
43+
namespace: "{{ .Release.Namespace }}"
44+
{{- end }}
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
# Licensed to the Apache Software Foundation (ASF) under one
2+
# or more contributor license agreements. See the NOTICE file
3+
# distributed with this work for additional information
4+
# regarding copyright ownership. The ASF licenses this file
5+
# to you under the Apache License, Version 2.0 (the
6+
# "License"); you may not use this file except in compliance
7+
# with the License. You may obtain a copy of the License at
8+
#
9+
# http://www.apache.org/licenses/LICENSE-2.0
10+
#
11+
# Unless required by applicable law or agreed to in writing,
12+
# software distributed under the License is distributed on an
13+
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
# KIND, either express or implied. See the License for the
15+
# specific language governing permissions and limitations
16+
# under the License.
17+
from __future__ import annotations
18+
19+
import jmespath
20+
from chart_utils.helm_template_generator import render_chart
21+
22+
23+
class TestAPIServerRolloutRestartCronJob:
24+
"""Tests API Server rollout restart CronJob."""
25+
26+
def test_should_create_cronjob_when_enabled(self):
27+
docs = render_chart(
28+
values={
29+
"apiServer": {
30+
"enabled": True,
31+
"rolloutRestart": {
32+
"enabled": True,
33+
},
34+
},
35+
},
36+
show_only=["templates/api-server/api-server-rollout-restart-cronjob.yaml"],
37+
)
38+
39+
assert len(docs) == 1
40+
assert docs[0]["kind"] == "CronJob"
41+
assert docs[0]["metadata"]["name"] == "release-name-api-server-rollout-restart"
42+
43+
containers = jmespath.search("spec.jobTemplate.spec.template.spec.containers", docs[0])
44+
assert len(containers) == 1
45+
assert containers[0]["name"] == "api-server-rollout-restart"
46+
assert containers[0]["image"] == "bitnami/kubectl:1.30.2"
47+
assert containers[0]["args"] == [
48+
"rollout",
49+
"restart",
50+
"deployment/release-name-api-server",
51+
"--namespace",
52+
"default",
53+
]
54+
55+
def test_should_not_create_cronjob_when_disabled(self):
56+
docs = render_chart(
57+
values={
58+
"apiServer": {
59+
"enabled": True,
60+
"rolloutRestart": {
61+
"enabled": False,
62+
},
63+
},
64+
},
65+
show_only=["templates/api-server/api-server-rollout-restart-cronjob.yaml"],
66+
)
67+
68+
assert len(docs) == 0
69+
70+
def test_should_use_custom_deployment_name(self):
71+
docs = render_chart(
72+
values={
73+
"apiServer": {
74+
"enabled": True,
75+
"rolloutRestart": {
76+
"enabled": True,
77+
"deploymentName": "my-custom-deployment-name",
78+
},
79+
},
80+
},
81+
show_only=["templates/api-server/api-server-rollout-restart-cronjob.yaml"],
82+
)
83+
84+
containers = jmespath.search("spec.jobTemplate.spec.template.spec.containers", docs[0])
85+
assert containers[0]["args"] == [
86+
"rollout",
87+
"restart",
88+
"deployment/my-custom-deployment-name",
89+
"--namespace",
90+
"default",
91+
]

0 commit comments

Comments
 (0)