Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
21 changes: 21 additions & 0 deletions charts/k8s-job/.helmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
11 changes: 11 additions & 0 deletions charts/k8s-job/Chart.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: v1
name: k8s-job
description: A Helm chart to package a job for Kubernetes
# This will be updated with the release tag in the CI/CD pipeline before publishing. This has to be a valid semver for
# the linter to accept.
version: 0.0.1-replace
home: https://github.com/gruntwork-io/helm-kubernetes-services
maintainers:
- name: Gruntwork
email: [email protected]
url: https://gruntwork.io
1,174 changes: 1,174 additions & 0 deletions charts/k8s-job/README.md

Large diffs are not rendered by default.

42 changes: 42 additions & 0 deletions charts/k8s-job/linter_values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#----------------------------------------------------------------------------------------------------------------------
# CHART PARAMETERS TO USE WITH HELM LINT
# This file declares a complete configuration value for this chart, with required values defined so that it can be used
# with helm lint to lint the chart. This should only specify the required values of the chart, and be combined with the
# default values of the chart.
# This is a YAML-formatted file.
#----------------------------------------------------------------------------------------------------------------------

#----------------------------------------------------------------------------------------------------------------------
# REQUIRED VALUES
# These values are expected to be defined and passed in by the operator when deploying this helm chart.
#----------------------------------------------------------------------------------------------------------------------

# containerImage is a map that describes the container image that should be used to serve the application managed by
# this chart.
# The expected keys are:
# - repository (string) (required) : The container image repository that should be used.
# E.g `nginx` ; `gcr.io/kubernetes-helm/tiller`
# - tag (string) (required) : The tag of the image (e.g `latest`) that should be used. We recommend using a
# fixed tag or the SHA of the image. Avoid using the tags `latest`, `head`,
# `canary`, or other tags that are designed to be “floating”.
# - pullPolicy (string) : The image pull policy to employ. Determines when the image will be pulled in. See
# the official Kubernetes docs for more info. If undefined, this will default to
# `IfNotPresent`.
#
# The following example deploys the `nginx:stable` image with a `IfNotPresent` image pull policy, which indicates that
# the image should only be pulled if it has not been pulled previously.
#
# EXAMPLE:
#
# containerImage:
# repository: nginx
# tag: stable
# pullPolicy: IfNotPresent
containerImage:
repository: nginx
tag: stable
pullPolicy: IfNotPresent

# applicationName is a string that names the application. This is used to label the pod and to name the main application
# container in the pod spec. The label is keyed under "gruntwork.io/app-name"
applicationName: "linter"
4 changes: 4 additions & 0 deletions charts/k8s-job/templates/_capabilities_helpers.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{{/* Allow KubeVersion to be overridden. This is mostly used for testing purposes. */}}
{{- define "gruntwork.kubeVersion" -}}
{{- default .Capabilities.KubeVersion.Version .Values.kubeVersionOverride -}}
{{- end -}}
73 changes: 73 additions & 0 deletions charts/k8s-job/templates/_helpers.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
{{/* vim: set filetype=mustache: */}}

{{/*
Expand the name of the chart.
*/}}
{{- define "k8s-job.name" -}}
{{- .Values.applicationName | required "applicationName is required" | trunc 63 | trimSuffix "-" -}}
{{- end -}}

{{/*
Create a default fully qualified app name.
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
If release name contains chart name it will be used as a full name.
*/}}
{{- define "k8s-job.fullname" -}}
{{- $name := required "applicationName is required" .Values.applicationName -}}
{{- if .Values.fullnameOverride -}}
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" -}}
{{- else if contains $name .Release.Name -}}
{{- .Release.Name | trunc 63 | trimSuffix "-" -}}
{{- else -}}
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}}
{{- end -}}
{{- end -}}

{{/*
Create chart name and version as used by the chart label.
*/}}
{{- define "k8s-job.chart" -}}
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" -}}
{{- end -}}

{{/*
Convert octal to decimal (e.g 644 => 420). For file permission modes, many people are more familiar with octal notation.
However, due to yaml/json limitations, all the Kubernetes resources require file modes to be reported in decimal.
*/}}
{{- define "k8s-job.fileModeOctalToDecimal" -}}
{{- $digits := splitList "" (toString .) -}}

{{/* Make sure there are exactly 3 digits */}}
{{- if ne (len $digits) 3 -}}
{{- fail (printf "File mode octal expects exactly 3 digits: %s" .) -}}
{{- end -}}

{{/* Go Templates do not support variable updating, so we simulate it using dictionaries */}}
{{- $accumulator := dict "res" 0 -}}
{{- range $idx, $digit := $digits -}}
{{- $digitI := atoi $digit -}}

{{/* atoi from sprig swallows conversion errors, so we double check to make sure it is a valid conversion */}}
{{- if and (eq $digitI 0) (ne $digit "0") -}}
{{- fail (printf "Digit %d of %s is not a number: %s" $idx . $digit) -}}
{{- end -}}

{{/* Make sure each digit is less than 8 */}}
{{- if ge $digitI 8 -}}
{{- fail (printf "%s is not a valid octal digit" $digit) -}}
{{- end -}}

{{/* Since we don't have math.Pow, we hard code */}}
{{- if eq $idx 0 -}}
{{/* 8^2 */}}
{{- $_ := set $accumulator "res" (add (index $accumulator "res") (mul $digitI 64)) -}}
{{- else if eq $idx 1 -}}
{{/* 8^1 */}}
{{- $_ := set $accumulator "res" (add (index $accumulator "res") (mul $digitI 8)) -}}
{{- else -}}
{{/* 8^0 */}}
{{- $_ := set $accumulator "res" (add (index $accumulator "res") (mul $digitI 1)) -}}
{{- end -}}
{{- end -}}
{{- "res" | index $accumulator | toString | printf -}}
{{- end -}}
207 changes: 207 additions & 0 deletions charts/k8s-job/templates/_job_spec.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,207 @@
{{- /*
Common job spec. This template requires the
context:
- Values
- Release
- Chart
You can construct this context using dict:
(dict "Values" .Values "Release" .Release "Chart" .Chart "isCanary" true)
*/ -}}
{{- define "k8s-job.jobSpec" -}}
{{- /*
We must decide whether or not there are volumes to inject. The logic to decide whether or not to inject is based on
whether or not there are configMaps OR secrets that are specified as volume mounts (`as: volume` attributes). We do this
by using a map to track whether or not we have seen a volume type. We have to use a map because we can't update a
variable in helm chart templates.

Similarly, we need to decide whether or not there are environment variables to add

We need this because certain sections are omitted if there are no volumes or environment variables to add.
*/ -}}

{{/* Go Templates do not support variable updating, so we simulate it using dictionaries */}}
{{- $hasInjectionTypes := dict "hasVolume" false "hasEnvVars" false "exposePorts" false -}}
{{- if .Values.envVars -}}
{{- $_ := set $hasInjectionTypes "hasEnvVars" true -}}
{{- end -}}
{{- if .Values.additionalContainerEnv -}}
{{- $_ := set $hasInjectionTypes "hasEnvVars" true -}}
{{- end -}}
{{- $allContainerPorts := values .Values.containerPorts -}}
{{- range $allContainerPorts -}}
{{/* We are exposing ports if there is at least one key in containerPorts that is not disabled (disabled = false or
omitted)
*/}}
{{- if or (not (hasKey . "disabled")) (not .disabled) -}}
{{- $_ := set $hasInjectionTypes "exposePorts" true -}}
{{- end -}}
{{- end -}}
{{- $allSecrets := values .Values.secrets -}}
{{- range $allSecrets -}}
{{- if eq (index . "as") "volume" -}}
{{- $_ := set $hasInjectionTypes "hasVolume" true -}}
{{- else if eq (index . "as") "environment" -}}
{{- $_ := set $hasInjectionTypes "hasEnvVars" true -}}
{{- else if eq (index . "as") "envFrom" }}
{{- $_ := set $hasInjectionTypes "hasEnvFrom" true -}}
{{- else if eq (index . "as") "none" -}}
{{- /* noop */ -}}
{{- else -}}
{{- fail printf "secrets config has unknown type: %s" (index . "as") -}}
{{- end -}}
{{- end -}}
{{- $allConfigMaps := values .Values.configMaps -}}
{{- range $allConfigMaps -}}
{{- if eq (index . "as") "volume" -}}
{{- $_ := set $hasInjectionTypes "hasVolume" true -}}
{{- else if eq (index . "as") "environment" -}}
{{- $_ := set $hasInjectionTypes "hasEnvVars" true -}}
{{- else if eq (index . "as") "envFrom" }}
{{- $_ := set $hasInjectionTypes "hasEnvFrom" true -}}
{{- else if eq (index . "as") "none" -}}
{{- /* noop */ -}}
{{- else -}}
{{- fail printf "configMaps config has unknown type: %s" (index . "as") -}}
{{- end -}}
{{- end -}}
{{- if gt (len .Values.persistentVolumes) 0 -}}
{{- $_ := set $hasInjectionTypes "hasVolume" true -}}
{{- end -}}
{{- if gt (len .Values.scratchPaths) 0 -}}
{{- $_ := set $hasInjectionTypes "hasVolume" true -}}
{{- end -}}
{{- if gt (len .Values.emptyDirs) 0 -}}
{{- $_ := set $hasInjectionTypes "hasVolume" true -}}
{{- end -}}
apiVersion: batch/v1
kind: Job
metadata:
name: {{ include "k8s-job.fullname" . }}
labels:
# These labels are required by helm. You can read more about required labels in the chart best practices guide:
# https://docs.helm.sh/chart_best_practices/#standard-labels
helm.sh/chart: {{ include "k8s-job.chart" . }}
app.kubernetes.io/name: {{ include "k8s-job.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
app.kubernetes.io/managed-by: {{ .Release.Service }}
{{- range $key, $value := .Values.additionalDeploymentLabels }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be renamed to additionalJobLabels.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, this is missing from the values.yaml file

{{ $key }}: {{ $value }}
{{- end}}
{{- with .Values.deploymentAnnotations }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be renamed to jobAnnotations

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, this is missing from the values.yaml file

annotations:
{{ toYaml . | indent 4 }}
{{- end }}
spec:
selector:
matchLabels:
app.kubernetes.io/name: {{ include "k8s-job.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
{{- if .isCanary }}
gruntwork.io/deployment-type: canary
{{- else }}
gruntwork.io/deployment-type: main
{{- end }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since we don't have canaries, can remove.

template:
metadata:
labels:
app.kubernetes.io/name: {{ include "k8s-job.name" . }}
app.kubernetes.io/instance: {{ .Release.Name }}
gruntwork.io/deployment-type: main
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This label is not necessary in k8s-job, as it is primarily used to differentiate with canaries, which doesn't apply for the job use case.

{{- end }}
{{- range $key, $value := .Values.additionalPodLabels }}
{{ $key }}: {{ $value }}
{{- end }}

{{- with .Values.podAnnotations }}
annotations:
{{ toYaml . | indent 8 }}
{{- end }}
spec:
{{- if .Values.podSecurityContext }}
securityContext:
{{ toYaml .Values.podSecurityContext | indent 8 }}
{{- end}}

restartPolicy: {{ toYaml .Values.restartPolicy | indent 12 }}
containers:
- name: {{ .Values.applicationName }}
{{- $repo := required ".Values.containerImage.repository is required" .Values.containerImage.repository }}
{{- $tag := required ".Values.containerImage.tag is required" .Values.containerImage.tag }}
image: "{{ $repo }}:{{ $tag }}"
imagePullPolicy: {{ .Values.containerImage.pullPolicy | default "IfNotPresent" }}
{{- end }}
{{- if .Values.containerCommand }}
command:
{{ toYaml .Values.containerCommand | indent 12 }}
{{- if .Values.containerArgs }}
args:
{{ toYaml .Values.containerArgs | indent 12 }}
{{- end }}
securityContext:
{{ toYaml .Values.securityContext | indent 12 }}
{{- end}}
resources:
{{ toYaml .Values.containerResources | indent 12 }}
{{- end }}

{{- /* START ENV VAR LOGIC */ -}}
{{- if index $hasInjectionTypes "hasEnvVars" }}
env:
{{- end }}
{{- range $key, $value := .Values.envVars }}
- name: {{ $key }}
value: {{ quote $value }}
{{- end }}
{{- if .Values.additionalContainerEnv }}
{{ toYaml .Values.additionalContainerEnv | indent 12 }}
{{- end }}
{{- range $name, $value := .Values.configMaps }}
{{- if eq $value.as "environment" }}
{{- range $configKey, $keyEnvVarConfig := $value.items }}
- name: {{ required "envVarName is required on configMaps items when using environment" $keyEnvVarConfig.envVarName | quote }}
valueFrom:
configMapKeyRef:
name: {{ $name }}
key: {{ $configKey }}
{{- end }}
{{- end }}
{{- end }}
{{- range $name, $value := .Values.secrets }}
{{- if eq $value.as "environment" }}
{{- range $secretKey, $keyEnvVarConfig := $value.items }}
- name: {{ required "envVarName is required on secrets items when using environment" $keyEnvVarConfig.envVarName | quote }}
valueFrom:
secretKeyRef:
name: {{ $name }}
key: {{ $secretKey }}
{{- end }}
{{- end }}
{{- end }}
{{- if index $hasInjectionTypes "hasEnvFrom" }}
envFrom:
{{- range $name, $value := .Values.configMaps }}
{{- if eq $value.as "envFrom" }}
- configMapRef:
name: {{ $name }}
{{- end }}
{{- end }}
{{- range $name, $value := .Values.secrets }}
{{- if eq $value.as "envFrom" }}
- secretRef:
name: {{ $name }}
{{- end }}
{{- end }}
{{- end }}
{{- /* END ENV VAR LOGIC */ -}}

{{- /* START IMAGE PULL SECRETS LOGIC */ -}}
{{- if gt (len .Values.imagePullSecrets) 0 }}
imagePullSecrets:
{{- range $secretName := .Values.imagePullSecrets }}
- name: {{ $secretName }}
{{- end }}
{{- end }}
{{- /* END IMAGE PULL SECRETS LOGIC */ -}}


{{- end -}}
5 changes: 5 additions & 0 deletions charts/k8s-job/templates/job.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{{- /*
The standalone Job to be deployed. This resource manages the creation and replacement
of Jobs you schedule.
*/ -}}
{{ include "k8s-job.jobSpec" }}
Loading