diff --git a/charts/rstudio-workbench/Chart.yaml b/charts/rstudio-workbench/Chart.yaml index 9265b811..1d7b6abf 100644 --- a/charts/rstudio-workbench/Chart.yaml +++ b/charts/rstudio-workbench/Chart.yaml @@ -1,6 +1,6 @@ name: rstudio-workbench description: Official Helm chart for RStudio Workbench -version: 0.6.14 +version: 0.6.15 apiVersion: v2 appVersion: 2023.12.1 icon: https://rstudio.com/wp-content/uploads/2018/10/RStudio-Logo-Flat.png diff --git a/charts/rstudio-workbench/NEWS.md b/charts/rstudio-workbench/NEWS.md index 0946c074..11a94938 100644 --- a/charts/rstudio-workbench/NEWS.md +++ b/charts/rstudio-workbench/NEWS.md @@ -1,7 +1,11 @@ +# 0.6.15 + +- Added `ttlSecondsAfterFinished` to `job.tpl` for session jobs. + # 0.6.14 - Add option to set `pod.terminationGracePeriodSeconds` -- Add protection for `prestart-launcher.bash` to be OS-agnostic in certificate modification +- Add protection for `prestart-launcher.bash` to be OS-agnostic in certificate modification ([#453](https://github.com/rstudio/helm/pull/453)) # 0.6.13 @@ -32,7 +36,7 @@ # 0.6.7 - Add native session support for `pip.conf` - - In order to mount a `pip.conf` file to `/etc/pip.conf` on server and sessions, + - In order to mount a `pip.conf` file to `/etc/pip.conf` on server and sessions, just define the file in `config.session.pip\\.conf` # 0.6.6 diff --git a/charts/rstudio-workbench/README.md b/charts/rstudio-workbench/README.md index 5132c373..716cee28 100644 --- a/charts/rstudio-workbench/README.md +++ b/charts/rstudio-workbench/README.md @@ -1,6 +1,6 @@ # RStudio Workbench -![Version: 0.6.14](https://img.shields.io/badge/Version-0.6.14-informational?style=flat-square) ![AppVersion: 2023.12.1](https://img.shields.io/badge/AppVersion-2023.12.1-informational?style=flat-square) +![Version: 0.6.15](https://img.shields.io/badge/Version-0.6.15-informational?style=flat-square) ![AppVersion: 2023.12.1](https://img.shields.io/badge/AppVersion-2023.12.1-informational?style=flat-square) #### _Official Helm chart for RStudio Workbench_ @@ -27,11 +27,11 @@ To ensure a stable production deployment, please: ## Installing the Chart -To install the chart with the release name `my-release` at version 0.6.14: +To install the chart with the release name `my-release` at version 0.6.15: ```bash helm repo add rstudio https://helm.rstudio.com -helm upgrade --install my-release rstudio/rstudio-workbench --version=0.6.14 +helm upgrade --install my-release rstudio/rstudio-workbench --version=0.6.15 ``` To explore other chart versions, take a look at: @@ -448,7 +448,7 @@ Use of [Sealed Secrets](https://github.com/bitnami-labs/sealed-secrets) disables | launcher.includeTemplateValues | bool | `true` | whether to include the templateValues rendering process | | launcher.kubernetesHealthCheck | object | `{"enabled":true,"extraCurlArgs":["-fsSL"]}` | configuration for the "Kubernetes Health Check" that the launcher entrypoint runs at startup | | launcher.namespace | string | `""` | allow customizing the namespace that sessions are launched into. Note RBAC and some config issues today | -| launcher.templateValues | object | `{"job":{"annotations":{},"labels":{}},"pod":{"affinity":{},"annotations":{},"command":[],"containerSecurityContext":{},"defaultSecurityContext":{},"env":[],"extraContainers":[],"imagePullPolicy":"","imagePullSecrets":[],"initContainers":[],"labels":{},"nodeSelector":{},"securityContext":{},"serviceAccountName":"","tolerations":[],"volumeMounts":[],"volumes":[]},"service":{"annotations":{},"labels":{},"type":"ClusterIP"}}` | values that are passed along to the launcher job rendering process as a data object (in JSON). These values are then used within session templates. | +| launcher.templateValues | object | `{"job":{"annotations":{},"labels":{},"ttlSecondsAfterFinished":null},"pod":{"affinity":{},"annotations":{},"command":[],"containerSecurityContext":{},"defaultSecurityContext":{},"env":[],"extraContainers":[],"imagePullPolicy":"","imagePullSecrets":[],"initContainers":[],"labels":{},"nodeSelector":{},"securityContext":{},"serviceAccountName":"","tolerations":[],"volumeMounts":[],"volumes":[]},"service":{"annotations":{},"labels":{},"type":"ClusterIP"}}` | values that are passed along to the launcher job rendering process as a data object (in JSON). These values are then used within session templates. | | launcher.templateValues.pod.command | list | `[]` | command for all pods. This is really not something we should expose and will be removed once we have a better option | | launcher.useTemplates | bool | `false` | whether to render and use templates in the job launching process | | launcherPem | string | `""` | An inline launcher.pem key. If not provided, one will be auto-generated. See README for more details. | diff --git a/charts/rstudio-workbench/ci/launcher-template-values.yaml b/charts/rstudio-workbench/ci/launcher-template-values.yaml index f32ffbda..d6951a88 100644 --- a/charts/rstudio-workbench/ci/launcher-template-values.yaml +++ b/charts/rstudio-workbench/ci/launcher-template-values.yaml @@ -10,6 +10,7 @@ launcher: annotations: five: six job: + ttlSecondsAfterFinished: 99 annotations: seven: eight labels: diff --git a/charts/rstudio-workbench/files/job.tpl b/charts/rstudio-workbench/files/job.tpl index c8279a75..4288b5a6 100644 --- a/charts/rstudio-workbench/files/job.tpl +++ b/charts/rstudio-workbench/files/job.tpl @@ -1,6 +1,6 @@ # Version: 2.3.1 # DO NOT MODIFY the "Version: " key -# Helm Version: v3 +# Helm Version: v4 {{- $templateData := include "rstudio-library.templates.data" nil | mustFromJson }} apiVersion: batch/v1 kind: Job @@ -30,6 +30,9 @@ metadata: {{- end }} generateName: {{ toYaml .Job.generateName }} spec: + {{- if $templateData.job.ttlSecondsAfterFinished }} + ttlSecondsAfterFinished: {{ $templateData.job.ttlSecondsAfterFinished }} + {{- end }} backoffLimit: 0 template: metadata: diff --git a/charts/rstudio-workbench/files/service.tpl b/charts/rstudio-workbench/files/service.tpl index f2b506ae..30909985 100644 --- a/charts/rstudio-workbench/files/service.tpl +++ b/charts/rstudio-workbench/files/service.tpl @@ -1,6 +1,6 @@ # Version: 2.3.1 # DO NOT MODIFY the "Version: " key -# Helm Version: v3 +# Helm Version: v4 {{- $templateData := include "rstudio-library.templates.data" nil | mustFromJson }} apiVersion: v1 kind: Service diff --git a/charts/rstudio-workbench/values.yaml b/charts/rstudio-workbench/values.yaml index 64194972..efa5ad56 100644 --- a/charts/rstudio-workbench/values.yaml +++ b/charts/rstudio-workbench/values.yaml @@ -106,6 +106,7 @@ launcher: job: annotations: {} labels: {} + ttlSecondsAfterFinished: null homeStorage: # -- whether to create the persistentVolumeClaim for homeStorage diff --git a/examples/launcher-templates/helm/2.3.1-v4/job.tpl b/examples/launcher-templates/helm/2.3.1-v4/job.tpl new file mode 100644 index 00000000..4288b5a6 --- /dev/null +++ b/examples/launcher-templates/helm/2.3.1-v4/job.tpl @@ -0,0 +1,285 @@ +# Version: 2.3.1 +# DO NOT MODIFY the "Version: " key +# Helm Version: v4 +{{- $templateData := include "rstudio-library.templates.data" nil | mustFromJson }} +apiVersion: batch/v1 +kind: Job +metadata: + annotations: + {{- with .Job.metadata.job.annotations }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 4 | trimPrefix (repeat 4 " ") }} + {{- end }} + {{- end }} + {{- with $templateData.job.annotations }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 4 | trimPrefix (repeat 4 " ") }} + {{- end }} + {{- end }} + labels: + app.kubernetes.io/managed-by: "launcher" + {{- with .Job.metadata.job.labels }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 4 | trimPrefix (repeat 4 " ") }} + {{- end }} + {{- end }} + {{- with $templateData.job.labels }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 4 | trimPrefix (repeat 4 " ") }} + {{- end }} + {{- end }} + generateName: {{ toYaml .Job.generateName }} +spec: + {{- if $templateData.job.ttlSecondsAfterFinished }} + ttlSecondsAfterFinished: {{ $templateData.job.ttlSecondsAfterFinished }} + {{- end }} + backoffLimit: 0 + template: + metadata: + annotations: + {{- if .Job.tags }} + {{- $i := 0 }} + {{- range .Job.tags }} + USER_TAG_{{ $i }}: {{ toYaml . | indent 8 | trimPrefix (repeat 8 " ") }} + {{- $i = add $i 1 }} + {{- end }} + {{- end }} + stdin: {{ toYaml .Job.stdin | indent 8 | trimPrefix (repeat 8 " ") }} + user: {{ toYaml .Job.user }} + name: {{ toYaml .Job.name }} + service_ports: {{ toYaml .Job.servicePortsJson }} + {{- if .Job.metadata }} + user_metadata: {{ toJson .Job.metadata | toYaml | indent 8 | trimPrefix (repeat 8 " ") }} + {{- end }} + {{- with .Job.metadata.pod.annotations }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 8 | trimPrefix (repeat 8 " ") }} + {{- end }} + {{- end }} + {{- with $templateData.pod.annotations }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 8 | trimPrefix (repeat 8 " ") }} + {{- end }} + {{- end }} + labels: + {{- with .Job.metadata.pod.labels }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 8 | trimPrefix (repeat 8 " ") }} + {{- end }} + {{- end }} + {{- with $templateData.pod.labels }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 8 | trimPrefix (repeat 8 " ") }} + {{- end }} + {{- end }} + generateName: {{ toYaml .Job.generateName }} + spec: + {{- if .Job.host }} + nodeName: {{ toYaml .Job.host }} + {{- end }} + restartPolicy: Never + {{- if or $templateData.pod.serviceAccountName .Job.serviceAccountName }} + serviceAccountName: {{ .Job.serviceAccountName | default $templateData.pod.serviceAccountName | quote }} + {{- end }} + shareProcessNamespace: {{ .Job.shareProcessNamespace }} + {{- if or (ne (len .Job.volumes) 0) (ne (len $templateData.pod.volumes) 0) }} + volumes: + {{- range .Job.volumes }} + - {{ nindent 10 (toYaml .) | trim -}} + {{- end }} + {{- range $templateData.pod.volumes }} + - {{ nindent 10 (toYaml .) | trim -}} + {{- end }} + {{- end }} + {{- with $templateData.pod.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with $templateData.pod.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- if or (ne (len .Job.placementConstraints) 0) (ne (len $templateData.pod.nodeSelector) 0) }} + nodeSelector: + {{- range .Job.placementConstraints }} + {{ .name }}: {{ toYaml .value }} + {{- end }} + {{- range $key,$val := $templateData.pod.nodeSelector }} + {{ $key }}: {{- toYaml $val | nindent 10 }} + {{- end }} + {{- end }} + {{- with $templateData.pod.priorityClassName }} + priorityClassName: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- $securityContext := $templateData.pod.defaultSecurityContext }} + {{- if .Job.container.runAsUserId }} + {{- $_ := set $securityContext "runAsUser" .Job.container.runAsUserId }} + {{- end }} + {{- if .Job.container.runAsGroupId }} + {{- $_ := set $securityContext "runAsGroup" .Job.container.runAsGroupId }} + {{- end }} + {{- if .Job.container.supplementalGroupIds }} + {{- $groupIds := list }} + {{- range .Job.container.supplementalGroupIds }} + {{- $groupIds = append $groupIds . }} + {{- end }} + {{- $_ := set $securityContext "supplementalGroups" (cat "[" ($groupIds | join ", ") "]") }} + {{- $securityContext := mergeOverwrite $securityContext $templateData.pod.securityContext }} + {{- end }} + {{- if $securityContext }} + securityContext: + {{- range $key, $val := $securityContext }} + {{ $key }}: {{ $val }} + {{- end }} + {{- end }} + {{- with $templateData.pod.imagePullSecrets }} + imagePullSecrets: {{ toYaml . | nindent 12 }} + {{- end }} + initContainers: + {{- with .Job.metadata.pod.initContainers }} + {{- range . }} + - {{ toYaml . | indent 10 | trimPrefix (repeat 10 " ") }} + {{- end }} + {{- end }} + {{- with $templateData.pod.initContainers }} + {{- range . }} + - {{ toYaml . | indent 10 | trimPrefix (repeat 10 " ") }} + {{- end }} + {{- end }} + containers: + - name: rs-launcher-container + image: {{ toYaml .Job.container.image }} + {{- with $templateData.pod.imagePullPolicy }} + imagePullPolicy: {{- . | nindent 12 }} + {{- end }} + {{- $isShell := false }} + {{- if $templateData.pod.command }} + command: {{- toYaml $templateData.pod.command | nindent 12 }} + {{- if .Job.command }}{{- $isShell = true }}{{- end }} + {{- else if .Job.command }} + command: ['/bin/sh'] + {{- $isShell = true }} + {{- else }} + command: [{{ toYaml .Job.exe }}] + {{- $isShell = false }} + {{- end }} + {{- if .Job.stdin }} + stdin: true + {{- else }} + stdin: false + {{- end }} + stdinOnce: true + {{- if .Job.workingDirectory }} + workingDir: {{ toYaml .Job.workingDirectory }} + {{- end }} + {{- if or (ne (len .Job.args) 0) $isShell }} + args: + {{- if $isShell }} + - '-c' + {{- if ne (len .Job.args) 0 }} + - {{ .Job.args | join " " | cat .Job.command | toYaml | indent 12 | trimPrefix (repeat 12 " ") }} + {{- else }} + - {{ .Job.command | toYaml | indent 12 | trimPrefix (repeat 12 " ") }} + {{- end }} + {{- else }} + {{- range .Job.args }} + - {{ toYaml . | indent 12 | trimPrefix (repeat 12 " ") }} + {{- end }} + {{- end }} + {{- end }} + {{- $secrets := list }} + {{- range .Job.config }} + {{- if eq .name "secret" }} + {{- $packedSecret := .value }} + {{- $secret := dict }} + {{- $_ := set $secret "secret" (splitList ":" $packedSecret | first) }} + {{- $_ := set $secret "key" (slice (splitList ":" $packedSecret) 1 2 | first) }} + {{- $_ := set $secret "name" (splitList ":" $packedSecret | last) }} + {{- $secrets = append $secrets $secret }} + {{- end }} + {{- end }} + {{- if or (ne (len .Job.environment) 0) (ne (len $secrets) 0) (ne (len $templateData.pod.env) 0) }} + env: + {{- range .Job.environment }} + - name: {{ toYaml .name | indent 14 | trimPrefix (repeat 14 " ") }} + value: {{ toYaml .value | indent 14 | trimPrefix (repeat 14 " ") }} + {{- end }} + {{- range $secrets }} + - name: {{ get . "name"}} + valueFrom: + secretKeyRef: + name: {{ get . "secret" }} + key: {{ get . "key" }} + {{- end }} + {{- if $templateData.pod.env }} + {{- toYaml $templateData.pod.env | nindent 12 }} + {{- end }} + {{- end }} + {{- with $templateData.pod.containerSecurityContext }} + securityContext: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- $exposedPorts := list }} + {{- range .Job.exposedPorts }} + {{- if .publishedPort }} + {{- $exposedPorts = append $exposedPorts . }} + {{- end }} + {{- end }} + {{- if ne (len $exposedPorts) 0 }} + ports: + {{- range $exposedPorts }} + - containerPort: {{ .targetPort }} + hostPort: {{ .publishedPort }} + {{- end }} + {{- end }} + {{- $limits := dict }} + {{- $requests := dict }} + {{- range .Job.resourceLimits }} + {{- if eq .type "cpuCount" }} + {{- $_ := set $limits "cpu" .value }} + {{- else if eq .type "CPU Request" }} + {{- $_ := set $requests "cpu" .value }} + {{- else if eq .type "memory" }} + {{- $_ := set $limits "memory" (printf "%s%s" .value "M") }} + {{- else if eq .type "Memory Request" }} + {{- $_ := set $requests "memory" (printf "%s%s" .value "M") }} + {{- else if eq .type "NVIDIA GPUs" }} + {{- $val := float64 .value }} + {{- if ne $val 0.0 }} + {{- $_ := set $limits "nvidia.com/gpu" $val }} + {{- end }} + {{- else if eq .type "AMD GPUs" }} + {{- $val := float64 .value }} + {{- if ne $val 0.0 }} + {{- $_ := set $limits "amd.com/gpu" $val }} + {{- end }} + {{- end }} + {{- end }} + {{- if any (ne (len $requests) 0) (ne (len $limits) 0) }} + resources: + {{- if ne (len $requests) 0 }} + requests: + {{- range $key, $val := $requests }} + {{ $key }}: {{ toYaml $val }} + {{- end }} + {{- end }} + {{- if ne (len $limits) 0 }} + limits: + {{- range $key, $val := $limits }} + {{ $key }}: {{ toYaml $val }} + {{- end }} + {{- end }} + {{- end }} + {{- if or (ne (len .Job.volumes) 0) (ne (len $templateData.pod.volumeMounts) 0) }} + volumeMounts: + {{- range .Job.volumeMounts }} + - {{ nindent 14 (toYaml .) | trim -}} + {{- end }} + {{- range $templateData.pod.volumeMounts }} + - {{ nindent 14 (toYaml .) | trim -}} + {{- end }} + {{- end }} + {{- with $templateData.pod.extraContainers }} + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/examples/launcher-templates/helm/2.3.1-v4/service.tpl b/examples/launcher-templates/helm/2.3.1-v4/service.tpl new file mode 100644 index 00000000..30909985 --- /dev/null +++ b/examples/launcher-templates/helm/2.3.1-v4/service.tpl @@ -0,0 +1,48 @@ +# Version: 2.3.1 +# DO NOT MODIFY the "Version: " key +# Helm Version: v4 +{{- $templateData := include "rstudio-library.templates.data" nil | mustFromJson }} +apiVersion: v1 +kind: Service +metadata: + name: {{ .Job.serviceName }} + annotations: + {{- with .Job.metadata.service.annotations }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 4 | trimPrefix (repeat 4 " ") }} + {{- end }} + {{- end }} + {{- with $templateData.service.annotations }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 4 | trimPrefix (repeat 4 " ") }} + {{- end }} + {{- end }} + labels: + app.kubernetes.io/managed-by: "launcher" + job-name: {{ toYaml .Job.id }} + {{- with .Job.metadata.service.labels }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 8 | trimPrefix (repeat 8 " ") }} + {{- end }} + {{- end }} + {{- with $templateData.service.labels }} + {{- range $key, $val := . }} + {{ $key }}: {{ toYaml $val | indent 8 | trimPrefix (repeat 8 " ") }} + {{- end }} + {{- end }} +spec: + ports: + {{- $i := 0 }} + {{- range .Job.exposedPorts }} + {{- if not .publishedPort }} + - name: {{ printf "port%d" $i }} + protocol: {{ .protocol }} + port: {{ .targetPort }} + targetPort: {{ .targetPort }} + {{- $i = add $i 1 }} + {{- end }} + {{- end }} + selector: + job-name: {{toYaml .Job.id }} + clusterIP: '' + type: {{ $templateData.service.type }}