433 lines
15 KiB
Smarty
433 lines
15 KiB
Smarty
{{- /*
|
|
## About
|
|
This file contains helpers to systematically name, label and select Kubernetes
|
|
objects we define in the .yaml template files.
|
|
|
|
|
|
## How helpers work
|
|
Helm helper functions is a good way to avoid repeating something. They will
|
|
generate some output based on one single dictionary of input that we call the
|
|
helpers scope. When you are in helm, you access your current scope with a
|
|
single a single punctuation (.).
|
|
|
|
When you ask a helper to render its content, one often forward the current
|
|
scope to the helper in order to allow it to access .Release.Name,
|
|
.Values.rbac.create and similar values.
|
|
|
|
#### Example - Passing the current scope
|
|
{{ include "jupyterhub.commonLabels" . }}
|
|
|
|
It would be possible to pass something specific instead of the current scope
|
|
(.), but that would make .Release.Name etc. inaccessible by the helper which
|
|
is something we aim to avoid.
|
|
|
|
#### Example - Passing a new scope
|
|
{{ include "demo.bananaPancakes" (dict "pancakes" 5 "bananas" 3) }}
|
|
|
|
To let a helper access the current scope along with additional values we have
|
|
opted to create dictionary containing additional values that is then populated
|
|
with additional values from the current scope through a the merge function.
|
|
|
|
#### Example - Passing a new scope augmented with the old
|
|
{{- $_ := merge (dict "appLabel" "kube-lego") . }}
|
|
{{- include "jupyterhub.matchLabels" $_ | nindent 6 }}
|
|
|
|
In this way, the code within the definition of `jupyterhub.matchLabels` will
|
|
be able to access .Release.Name and .appLabel.
|
|
|
|
NOTE:
|
|
The ordering of merge is crucial, the latter argument is merged into the
|
|
former. So if you would swap the order you would influence the current scope
|
|
risking unintentional behavior. Therefore, always put the fresh unreferenced
|
|
dictionary (dict "key1" "value1") first and the current scope (.) last.
|
|
|
|
|
|
## Declared helpers
|
|
- appLabel |
|
|
- componentLabel |
|
|
- commonLabels | uses appLabel
|
|
- labels | uses commonLabels
|
|
- matchLabels | uses labels
|
|
|
|
|
|
## Example usage
|
|
```yaml
|
|
# Excerpt from proxy/autohttps/deployment.yaml
|
|
apiVersion: apps/v1
|
|
kind: Deployment
|
|
metadata:
|
|
name: {{ include "jupyterhub.autohttps.fullname" . }}
|
|
labels:
|
|
{{- include "jupyterhub.labels" . | nindent 4 }}
|
|
spec:
|
|
selector:
|
|
matchLabels:
|
|
{{- include "jupyterhub.matchLabels" $_ | nindent 6 }}
|
|
template:
|
|
metadata:
|
|
labels:
|
|
{{- include "jupyterhub.labels" $_ | nindent 8 }}
|
|
hub.jupyter.org/network-access-proxy-http: "true"
|
|
```
|
|
|
|
NOTE:
|
|
The "jupyterhub.matchLabels" and "jupyterhub.labels" is passed an augmented
|
|
scope that will influence the helpers' behavior. It get the current scope
|
|
"." but merged with a dictionary containing extra key/value pairs. In this
|
|
case the "." scope was merged with a small dictionary containing only one
|
|
key/value pair "appLabel: kube-lego". It is required for kube-lego to
|
|
function properly. It is a way to override the default app label's value.
|
|
*/}}
|
|
|
|
|
|
{{- /*
|
|
jupyterhub.appLabel:
|
|
Used by "jupyterhub.labels".
|
|
*/}}
|
|
{{- define "jupyterhub.appLabel" -}}
|
|
{{ .Values.nameOverride | default .Chart.Name | trunc 63 | trimSuffix "-" }}
|
|
{{- end }}
|
|
|
|
|
|
{{- /*
|
|
jupyterhub.componentLabel:
|
|
Used by "jupyterhub.labels".
|
|
|
|
NOTE: The component label is determined by either...
|
|
- 1: The provided scope's .componentLabel
|
|
- 2: The template's filename if living in the root folder
|
|
- 3: The template parent folder's name
|
|
- : ...and is combined with .componentPrefix and .componentSuffix
|
|
*/}}
|
|
{{- define "jupyterhub.componentLabel" -}}
|
|
{{- $file := .Template.Name | base | trimSuffix ".yaml" -}}
|
|
{{- $parent := .Template.Name | dir | base | trimPrefix "templates" -}}
|
|
{{- $component := .componentLabel | default $parent | default $file -}}
|
|
{{- $component := print (.componentPrefix | default "") $component (.componentSuffix | default "") -}}
|
|
{{ $component }}
|
|
{{- end }}
|
|
|
|
|
|
{{- /*
|
|
jupyterhub.commonLabels:
|
|
Foundation for "jupyterhub.labels".
|
|
|
|
Provides old labels:
|
|
app
|
|
release
|
|
chart (omitted for matchLabels)
|
|
heritage (omitted for matchLabels)
|
|
Provides modern labels (omitted for matchLabels):
|
|
app.kubernetes.io/name ("app")
|
|
app.kubernetes.io/instance ("release")
|
|
helm.sh/chart ("chart")
|
|
app.kubernetes.io/managed-by ("heritage")
|
|
*/}}
|
|
{{- define "jupyterhub.commonLabels" -}}
|
|
app: {{ .appLabel | default (include "jupyterhub.appLabel" .) | quote }}
|
|
release: {{ .Release.Name | quote }}
|
|
{{- if not .matchLabels }}
|
|
chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
|
heritage: {{ .Release.Service }}
|
|
app.kubernetes.io/name: {{ .appLabel | default (include "jupyterhub.appLabel" .) | quote }}
|
|
app.kubernetes.io/instance: {{ .Release.Name | quote }}
|
|
helm.sh/chart: {{ .Chart.Name }}-{{ .Chart.Version | replace "+" "_" }}
|
|
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
|
{{- end }}
|
|
{{- end }}
|
|
|
|
|
|
{{- /*
|
|
jupyterhub.labels:
|
|
Provides old labels:
|
|
component
|
|
app
|
|
release
|
|
chart (omitted for matchLabels)
|
|
heritage (omitted for matchLabels)
|
|
Provides modern labels (omitted for matchLabels):
|
|
app.kubernetes.io/component ("component")
|
|
app.kubernetes.io/name ("app")
|
|
app.kubernetes.io/instance release ("release")
|
|
helm.sh/chart ("chart")
|
|
app.kubernetes.io/managed-by ("heritage")
|
|
*/}}
|
|
{{- define "jupyterhub.labels" -}}
|
|
component: {{ include "jupyterhub.componentLabel" . }}
|
|
{{- if not .matchLabels }}
|
|
app.kubernetes.io/component: {{ include "jupyterhub.componentLabel" . }}
|
|
{{- end }}
|
|
{{ include "jupyterhub.commonLabels" . }}
|
|
{{- end }}
|
|
|
|
|
|
{{- /*
|
|
jupyterhub.matchLabels:
|
|
Provides old labels:
|
|
component
|
|
app
|
|
release
|
|
*/}}
|
|
{{- define "jupyterhub.matchLabels" -}}
|
|
{{- $_ := merge (dict "matchLabels" true) . -}}
|
|
{{ include "jupyterhub.labels" $_ }}
|
|
{{- end }}
|
|
|
|
|
|
{{- /*
|
|
jupyterhub.dockerconfigjson:
|
|
Creates a base64 encoded docker registry json blob for use in a image pull
|
|
secret, just like the `kubectl create secret docker-registry` command does
|
|
for the generated secrets data.dockerconfigjson field. The output is
|
|
verified to be exactly the same even if you have a password spanning
|
|
multiple lines as you may need to use a private GCR registry.
|
|
|
|
- https://kubernetes.io/docs/concepts/containers/images/#specifying-imagepullsecrets-on-a-pod
|
|
*/}}
|
|
{{- define "jupyterhub.dockerconfigjson" -}}
|
|
{{ include "jupyterhub.dockerconfigjson.yaml" . | b64enc }}
|
|
{{- end }}
|
|
|
|
{{- define "jupyterhub.dockerconfigjson.yaml" -}}
|
|
{{- with .Values.imagePullSecret -}}
|
|
{
|
|
"auths": {
|
|
{{ .registry | default "https://index.docker.io/v1/" | quote }}: {
|
|
"username": {{ .username | quote }},
|
|
"password": {{ .password | quote }},
|
|
{{- if .email }}
|
|
"email": {{ .email | quote }},
|
|
{{- end }}
|
|
"auth": {{ (print .username ":" .password) | b64enc | quote }}
|
|
}
|
|
}
|
|
}
|
|
{{- end }}
|
|
{{- end }}
|
|
|
|
{{- /*
|
|
jupyterhub.imagePullSecrets
|
|
Augments passed .pullSecrets with $.Values.imagePullSecrets
|
|
*/}}
|
|
{{- define "jupyterhub.imagePullSecrets" -}}
|
|
{{- /*
|
|
We have implemented a trick to allow a parent chart depending on this
|
|
chart to call this named templates.
|
|
|
|
Caveats and notes:
|
|
|
|
1. While parent charts can reference these, grandparent charts can't.
|
|
2. Parent charts must not use an alias for this chart.
|
|
3. There is no failsafe workaround to above due to
|
|
https://github.com/helm/helm/issues/9214.
|
|
4. .Chart is of its own type (*chart.Metadata) and needs to be casted
|
|
using "toYaml | fromYaml" in order to be able to use normal helm
|
|
template functions on it.
|
|
*/}}
|
|
{{- $jupyterhub_values := .root.Values }}
|
|
{{- if ne .root.Chart.Name "jupyterhub" }}
|
|
{{- if .root.Values.jupyterhub }}
|
|
{{- $jupyterhub_values = .root.Values.jupyterhub }}
|
|
{{- end }}
|
|
{{- end }}
|
|
|
|
{{- /* Populate $_.list with all relevant entries */}}
|
|
{{- $_ := dict "list" (concat .image.pullSecrets $jupyterhub_values.imagePullSecrets | uniq) }}
|
|
{{- if and $jupyterhub_values.imagePullSecret.create $jupyterhub_values.imagePullSecret.automaticReferenceInjection }}
|
|
{{- $__ := set $_ "list" (append $_.list (include "jupyterhub.image-pull-secret.fullname" .root) | uniq) }}
|
|
{{- end }}
|
|
|
|
{{- /* Decide if something should be written */}}
|
|
{{- if not (eq ($_.list | toJson) "[]") }}
|
|
|
|
{{- /* Process the $_.list where strings become dicts with a name key and the
|
|
strings become the name keys' values into $_.res */}}
|
|
{{- $_ := set $_ "res" list }}
|
|
{{- range $_.list }}
|
|
{{- if eq (typeOf .) "string" }}
|
|
{{- $__ := set $_ "res" (append $_.res (dict "name" .)) }}
|
|
{{- else }}
|
|
{{- $__ := set $_ "res" (append $_.res .) }}
|
|
{{- end }}
|
|
{{- end }}
|
|
|
|
{{- /* Write the results */}}
|
|
{{- $_.res | toJson }}
|
|
|
|
{{- end }}
|
|
{{- end }}
|
|
|
|
{{- /*
|
|
jupyterhub.singleuser.resources:
|
|
The resource request of a singleuser.
|
|
*/}}
|
|
{{- define "jupyterhub.singleuser.resources" -}}
|
|
{{- $r1 := .Values.singleuser.cpu.guarantee -}}
|
|
{{- $r2 := .Values.singleuser.memory.guarantee -}}
|
|
{{- $r3 := .Values.singleuser.extraResource.guarantees -}}
|
|
{{- $r := or $r1 $r2 $r3 -}}
|
|
{{- $l1 := .Values.singleuser.cpu.limit -}}
|
|
{{- $l2 := .Values.singleuser.memory.limit -}}
|
|
{{- $l3 := .Values.singleuser.extraResource.limits -}}
|
|
{{- $l := or $l1 $l2 $l3 -}}
|
|
{{- if $r -}}
|
|
requests:
|
|
{{- if $r1 }}
|
|
cpu: {{ .Values.singleuser.cpu.guarantee }}
|
|
{{- end }}
|
|
{{- if $r2 }}
|
|
memory: {{ .Values.singleuser.memory.guarantee }}
|
|
{{- end }}
|
|
{{- if $r3 }}
|
|
{{- range $key, $value := .Values.singleuser.extraResource.guarantees }}
|
|
{{ $key | quote }}: {{ $value | quote }}
|
|
{{- end }}
|
|
{{- end }}
|
|
{{- end }}
|
|
|
|
{{- if $l }}
|
|
limits:
|
|
{{- if $l1 }}
|
|
cpu: {{ .Values.singleuser.cpu.limit }}
|
|
{{- end }}
|
|
{{- if $l2 }}
|
|
memory: {{ .Values.singleuser.memory.limit }}
|
|
{{- end }}
|
|
{{- if $l3 }}
|
|
{{- range $key, $value := .Values.singleuser.extraResource.limits }}
|
|
{{ $key | quote }}: {{ $value | quote }}
|
|
{{- end }}
|
|
{{- end }}
|
|
{{- end }}
|
|
{{- end }}
|
|
|
|
{{- /*
|
|
jupyterhub.extraEnv:
|
|
Output YAML formatted EnvVar entries for use in a containers env field.
|
|
*/}}
|
|
{{- define "jupyterhub.extraEnv" -}}
|
|
{{- include "jupyterhub.extraEnv.withTrailingNewLine" . | trimSuffix "\n" }}
|
|
{{- end }}
|
|
|
|
{{- define "jupyterhub.extraEnv.withTrailingNewLine" -}}
|
|
{{- if . }}
|
|
{{- /* If extraEnv is a list, we inject it as it is. */}}
|
|
{{- if eq (typeOf .) "[]interface {}" }}
|
|
{{- . | toYaml }}
|
|
|
|
{{- /* If extraEnv is a map, we differentiate two cases: */}}
|
|
{{- else if eq (typeOf .) "map[string]interface {}" }}
|
|
{{- range $key, $value := . }}
|
|
{{- /*
|
|
- If extraEnv.someKey has a map value, then we add the value as a YAML
|
|
parsed list element and use the key as the name value unless its
|
|
explicitly set.
|
|
*/}}
|
|
{{- if eq (typeOf $value) "map[string]interface {}" }}
|
|
{{- merge (dict) $value (dict "name" $key) | list | toYaml | println }}
|
|
{{- /*
|
|
- If extraEnv.someKey has a string value, then we use the key as the
|
|
environment variable name for the value.
|
|
*/}}
|
|
{{- else if eq (typeOf $value) "string" -}}
|
|
- name: {{ $key | quote }}
|
|
value: {{ $value | quote | println }}
|
|
{{- else }}
|
|
{{- printf "?.extraEnv.%s had an unexpected type (%s)" $key (typeOf $value) | fail }}
|
|
{{- end }}
|
|
{{- end }} {{- /* end of range */}}
|
|
{{- end }}
|
|
{{- end }} {{- /* end of: if . */}}
|
|
{{- end }} {{- /* end of definition */}}
|
|
|
|
{{- /*
|
|
jupyterhub.extraFiles.data:
|
|
Renders content for a k8s Secret's data field, coming from extraFiles with
|
|
binaryData entries.
|
|
*/}}
|
|
{{- define "jupyterhub.extraFiles.data.withNewLineSuffix" -}}
|
|
{{- range $file_key, $file_details := . }}
|
|
{{- include "jupyterhub.extraFiles.validate-file" (list $file_key $file_details) }}
|
|
{{- if $file_details.binaryData }}
|
|
{{- $file_key | quote }}: {{ $file_details.binaryData | nospace | quote }}{{ println }}
|
|
{{- end }}
|
|
{{- end }}
|
|
{{- end }}
|
|
{{- define "jupyterhub.extraFiles.data" -}}
|
|
{{- include "jupyterhub.extraFiles.data.withNewLineSuffix" . | trimSuffix "\n" }}
|
|
{{- end }}
|
|
|
|
{{- /*
|
|
jupyterhub.extraFiles.stringData:
|
|
Renders content for a k8s Secret's stringData field, coming from extraFiles
|
|
with either data or stringData entries.
|
|
*/}}
|
|
{{- define "jupyterhub.extraFiles.stringData.withNewLineSuffix" -}}
|
|
{{- range $file_key, $file_details := . }}
|
|
{{- include "jupyterhub.extraFiles.validate-file" (list $file_key $file_details) }}
|
|
{{- $file_name := $file_details.mountPath | base }}
|
|
{{- if $file_details.stringData }}
|
|
{{- $file_key | quote }}: |
|
|
{{- $file_details.stringData | trimSuffix "\n" | nindent 2 }}{{ println }}
|
|
{{- end }}
|
|
{{- if $file_details.data }}
|
|
{{- $file_key | quote }}: |
|
|
{{- if or (eq (ext $file_name) ".yaml") (eq (ext $file_name) ".yml") }}
|
|
{{- $file_details.data | toYaml | nindent 2 }}{{ println }}
|
|
{{- else if eq (ext $file_name) ".json" }}
|
|
{{- $file_details.data | toJson | nindent 2 }}{{ println }}
|
|
{{- else if eq (ext $file_name) ".toml" }}
|
|
{{- $file_details.data | toToml | trimSuffix "\n" | nindent 2 }}{{ println }}
|
|
{{- else }}
|
|
{{- print "\n\nextraFiles entries with 'data' (" $file_key " > " $file_details.mountPath ") needs to have a filename extension of .yaml, .yml, .json, or .toml!" | fail }}
|
|
{{- end }}
|
|
{{- end }}
|
|
{{- end }}
|
|
{{- end }}
|
|
{{- define "jupyterhub.extraFiles.stringData" -}}
|
|
{{- include "jupyterhub.extraFiles.stringData.withNewLineSuffix" . | trimSuffix "\n" }}
|
|
{{- end }}
|
|
|
|
{{- define "jupyterhub.extraFiles.validate-file" -}}
|
|
{{- $file_key := index . 0 }}
|
|
{{- $file_details := index . 1 }}
|
|
|
|
{{- /* Use of mountPath. */}}
|
|
{{- if not ($file_details.mountPath) }}
|
|
{{- print "\n\nextraFiles entries (" $file_key ") must contain the field 'mountPath'." | fail }}
|
|
{{- end }}
|
|
|
|
{{- /* Use one of stringData, binaryData, data. */}}
|
|
{{- $field_count := 0 }}
|
|
{{- if $file_details.data }}
|
|
{{- $field_count = add1 $field_count }}
|
|
{{- end }}
|
|
{{- if $file_details.stringData }}
|
|
{{- $field_count = add1 $field_count }}
|
|
{{- end }}
|
|
{{- if $file_details.binaryData }}
|
|
{{- $field_count = add1 $field_count }}
|
|
{{- end }}
|
|
{{- if ne $field_count 1 }}
|
|
{{- print "\n\nextraFiles entries (" $file_key ") must only contain one of the fields: 'data', 'stringData', and 'binaryData'." | fail }}
|
|
{{- end }}
|
|
{{- end }}
|
|
|
|
{{- /*
|
|
jupyterhub.chart-version-to-git-ref:
|
|
Renders a valid git reference from a chartpress generated version string.
|
|
In practice, either a git tag or a git commit hash will be returned.
|
|
|
|
- The version string will follow a chartpress pattern, see
|
|
https://github.com/jupyterhub/chartpress#examples-chart-versions-and-image-tags.
|
|
|
|
- The regexReplaceAll function is a sprig library function, see
|
|
https://masterminds.github.io/sprig/strings.html.
|
|
|
|
- The regular expression is in golang syntax, but \d had to become \\d for
|
|
example.
|
|
*/}}
|
|
{{- define "jupyterhub.chart-version-to-git-ref" -}}
|
|
{{- regexReplaceAll ".*[.-]n\\d+[.]h(.*)" . "${1}" }}
|
|
{{- end }}
|