diff --git a/charts/jupyter-hub-customizations/Chart.yaml b/charts/jupyter-hub-customizations/Chart.yaml index 0cf0103b2a38511eeadd15eec0de6aa5d788e729..969ea4fa089d683023ef8b1eaa4700a9328d646c 100644 --- a/charts/jupyter-hub-customizations/Chart.yaml +++ b/charts/jupyter-hub-customizations/Chart.yaml @@ -15,7 +15,7 @@ type: application # This is the chart version. This version number should be incremented each time you make changes # to the chart and its templates, including the app version. # Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.12.8 +version: 0.13.0 # This is the version number of the application being deployed. This version number should be # incremented each time you make changes to the application. Versions are not expected to diff --git a/charts/jupyter-hub-customizations/templates/configmap_check_frontend_files.yaml b/charts/jupyter-hub-customizations/templates/configmap_check_frontend_files.yaml new file mode 100644 index 0000000000000000000000000000000000000000..92121461accabb48ea0fbc9427d6b0c718fbb5e5 --- /dev/null +++ b/charts/jupyter-hub-customizations/templates/configmap_check_frontend_files.yaml @@ -0,0 +1,125 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Values.global.name }}-check-frontend-files + labels: + {{- include "jupyter-hub-customizations.labels" . | nindent 4 }} +data: + run.sh: | + #!/bin/bash + + # Variables used for git clone commands + SHARE_BASE_DIR="/tmp/share_base" + SHARE_OVERLAYS_DIR="/tmp/share_overlays" + + # Prepare base + overlays in this directory, before moving it to /mnt/shared-data + SHARE_COPY_DIR="/tmp/share_copy" + + # In this directory JupyterHub will look for the template files + SHARE_JHUB_DIR="/mnt/shared-data/share/jupyterhub" + mkdir -p ${SHARE_JHUB_DIR} + + # In this directory nginx will look for the static files + SHARE_NGINX_DIR="/mnt/shared-data/static-files" + mkdir -p ${SHARE_NGINX_DIR} + + # create temporary folders + mkdir -p $(dirname ${SHARE_BASE_DIR}) + + if [[ -e ${SHARE_BASE_DIR} ]]; then + rm -rf ${SHARE_BASE_DIR} + fi + + cd $(dirname ${SHARE_BASE_DIR}) + git clone --single-branch --branch ${SHARE_BASE_GIT_BRANCH} https://${SHARE_BASE_GIT_USERNAME}:${SHARE_BASE_GIT_PASSWORD}@${SHARE_BASE_GIT_REPO#"https://"} $(basename ${SHARE_BASE_DIR}) + + if [[ -n ${SHARE_OVERLAYS_GIT_REPO} ]]; then + mkdir -p $(dirname ${SHARE_OVERLAYS_DIR}) + + if [[ -e ${SHARE_OVERLAYS_DIR} ]]; then + rm -rf ${SHARE_OVERLAYS_DIR} + fi + + cd $(dirname ${SHARE_OVERLAYS_DIR}) + if [[ -n ${SHARE_OVERLAYS_GIT_USERNAME} && -n ${SHARE_OVERLAYS_GIT_PASSWORD} ]]; then + git clone --single-branch --branch ${SHARE_OVERLAYS_GIT_BRANCH} https://${SHARE_OVERLAYS_GIT_USERNAME}:${SHARE_OVERLAYS_GIT_PASSWORD}@${SHARE_OVERLAYS_GIT_REPO#"https://"} $(basename ${SHARE_OVERLAYS_DIR}) + else + git clone --single-branch --branch ${SHARE_OVERLAYS_GIT_BRANCH} ${SHARE_OVERLAYS_GIT_REPO} $(basename ${SHARE_OVERLAYS_DIR}) + fi + fi + + git config --global pull.ff only + + + update() { + echo "$(date) - Check for updates in templates and static files" + + if [[ ${1} == "force" ]]; then + FORCE=1 + else + FORCE=0 + fi + + # Check if base templates got an update + + check_git_update() { + # Check for changes on remote origin + cd ${1} + git fetch -q + test "$(git rev-parse HEAD)" == "$(git rev-parse @{u})" + echo $? + } + + SHARE_BASE_UPDATED=$(check_git_update ${SHARE_BASE_DIR}) + if [[ -n ${SHARE_OVERLAYS_GIT_REPO} ]]; then + SHARE_OVERLAYS_UPDATED=$(check_git_update ${SHARE_OVERLAYS_DIR}) + else + SHARE_OVERLAYS_UPDATED=0 + fi + + # If one was updated, we have to prepare a new directory + if [[ ${SHARE_BASE_UPDATED} -eq 1 || ${SHARE_OVERLAYS_UPDATED} -eq 1 || ${FORCE} -eq 1 ]]; then + echo "$(date) - Shared files update (Base: ${SHARE_BASE_UPDATED} , Overlays: ${SHARE_OVERLAYS_UPDATED}, Force ${FORCE})" + mkdir -p ${SHARE_COPY_DIR} + cd ${SHARE_BASE_DIR} + git pull origin ${SHARE_BASE_GIT_BRANCH} + cp -r ${SHARE_BASE_DIR}/* ${SHARE_COPY_DIR}/. + + if [[ ${SHARE_OVERLAYS_UPDATED} -eq 1 || (${FORCE} -eq 1 && -d ${SHARE_OVERLAYS_DIR}) ]]; then + cd ${SHARE_OVERLAYS_DIR} + git pull origin ${SHARE_OVERLAYS_GIT_BRANCH} + + copy_overlays_subdir() { + if [[ -d ${SHARE_OVERLAYS_DIR}/${1} ]]; then + if [[ ! -d ${SHARE_COPY_DIR}/${1} ]]; then + mkdir -p ${SHARE_COPY_DIR}/${1} + fi + cp -r ${SHARE_OVERLAYS_DIR}/${1}/* ${SHARE_COPY_DIR}/${1}/. + fi + } + copy_overlays_subdir templates + copy_overlays_subdir static + + fi + # Remove footer.systems images. These are managed by check_incidents in antoher script. + if [[ -d ${SHARE_COPY_DIR}/static/images/footer/systems ]]; then + rm -r ${SHARE_COPY_DIR}/static/images/footer/systems/* + fi + + chown -R 1000:1000 ${SHARE_COPY_DIR} + cp -r ${SHARE_COPY_DIR}/* ${SHARE_JHUB_DIR}/. + cp -r ${SHARE_COPY_DIR}/static/* ${SHARE_NGINX_DIR}/. + chown -R 1000:1000 ${SHARE_JHUB_DIR} + chown -R 1000:1000 ${SHARE_NGINX_DIR} + rm -rf ${SHARE_COPY_DIR} + fi + } + + update force + + if [[ ! ${1} == "once" ]]; then + while true; do + sleep 60 + update + done + fi diff --git a/charts/jupyter-hub-customizations/templates/configmap_init_script.yaml b/charts/jupyter-hub-customizations/templates/configmap_init_script.yaml new file mode 100644 index 0000000000000000000000000000000000000000..00d152c56a507016e08e40091cdbf3d57ec427ae --- /dev/null +++ b/charts/jupyter-hub-customizations/templates/configmap_init_script.yaml @@ -0,0 +1,60 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Values.global.name }}-init-script + labels: + {{- include "jupyter-hub-customizations.labels" . | nindent 4 }} +data: + run.sh: | + #!/bin/bash + + preparation() { + # Internal ssl variables + INTERNAL_SSL_SRC="/mnt/internal_ssl/*" + INTERNAL_SSL_DEST="/mnt/persistent/internal-ssl" + } + + internal_ssl_dir() { + # Take the given internal_ssl (mounted via secret) + # and prepare it for JupyterHub in a persistent storage + mkdir -p ${INTERNAL_SSL_DEST} + for f in ${INTERNAL_SSL_SRC}; do + filename=$(basename $f) + if [[ ${filename} = certipy.json ]]; then + cp $f ${INTERNAL_SSL_DEST}/${filename} + elif [[ ! ${filename} = *_trust.crt ]]; then + dirname=${filename%%_*} + mkdir -p ${INTERNAL_SSL_DEST}/${dirname} + filename=${filename##*_} + cp $f ${INTERNAL_SSL_DEST}/${dirname}/${filename} + else + cp $f ${INTERNAL_SSL_DEST}/${filename} + fi + done + } + + twofa_setup() { + # Fix twofa ssh keys permissions + if [[ -f /mnt/twofa_keypair/..data/twofa ]]; then + mkdir -p /mnt/shared-data/twofa + cp -r /mnt/twofa_keypair/..data/twofa /mnt/shared-data/twofa/twofa + chmod 400 /mnt/shared-data/twofa/twofa + fi + + if [[ -f /mnt/twofa_remove_keypair/..data/twofa ]]; then + mkdir -p /mnt/shared-data/twofa + cp -r /mnt/twofa_remove_keypair/..data/twofa /mnt/shared-data/twofa/twofaremove + chmod 400 /mnt/shared-data/twofa/twofaremove + fi + } + + wrap_up() { + # set ownership + chown -R 1000:100 /mnt/shared-data + chown -R 1000:100 /mnt/persistent + } + + preparation + internal_ssl_dir + twofa_setup + wrap_up diff --git a/charts/jupyter-hub-customizations/templates/configmap_sidecar_nginx.yaml b/charts/jupyter-hub-customizations/templates/configmap_sidecar_nginx.yaml new file mode 100644 index 0000000000000000000000000000000000000000..0655ab514df3ea9cfeae141c95d374238a4de198 --- /dev/null +++ b/charts/jupyter-hub-customizations/templates/configmap_sidecar_nginx.yaml @@ -0,0 +1,90 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Values.global.name }}-sidecar-nginx-config + labels: + {{- include "jupyter-hub-customizations.labels" . | nindent 4 }} +data: + nginx.conf: | + user nginx; + worker_processes auto; + + error_log /var/log/nginx/error.log notice; + pid /var/run/nginx.pid; + + + events { + worker_connections 1024; + } + + + http { + include /etc/nginx/mime.types; + default_type text/html; + + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + access_log /var/log/nginx/access.log main; + + sendfile on; + #tcp_nopush on; + + keepalive_timeout 65; + + #gzip on; + + include /etc/nginx/conf.d/*.conf; + } + jupyter.conf: | + server { + listen 8070 default_server; + server_name _; + + access_log /var/log/nginx/host.access.log main; + + location ^~ /hub/static { + alias /mnt/shared-data/share/jupyterhub/static/; + # root /usr/share/nginx/html; + # index index.html index.htm; + } + + location / { + alias /mnt/shared-data/share/jupyterhub/static/redirects/; + # root /usr/share/nginx/html; + # index index.html index.htm; + } + + #error_page 404 /404.html; + + # redirect server error pages to the static page /50x.html + # + error_page 500 502 503 504 /50x.html; + location = /50x.html { + root /usr/share/nginx/html; + } + + # proxy the PHP scripts to Apache listening on 127.0.0.1:80 + # + #location ~ \.php$ { + # proxy_pass http://127.0.0.1; + #} + + # pass the PHP scripts to FastCGI server listening on 127.0.0.1:9000 + # + #location ~ \.php$ { + # root html; + # fastcgi_pass 127.0.0.1:9000; + # fastcgi_index index.php; + # fastcgi_param SCRIPT_FILENAME /scripts$fastcgi_script_name; + # include fastcgi_params; + #} + + # deny access to .htaccess files, if Apache's document root + # concurs with nginx's one + # + #location ~ /\.ht { + # deny all; + #} + } diff --git a/charts/jupyter-hub-customizations/templates/configmap_values.yaml b/charts/jupyter-hub-customizations/templates/configmap_values.yaml index de6a3e0b25a103fae0095d47caa4b58341d1fac6..1c023c96311a254ab91770e3b108950bd857c999 100644 --- a/charts/jupyter-hub-customizations/templates/configmap_values.yaml +++ b/charts/jupyter-hub-customizations/templates/configmap_values.yaml @@ -39,6 +39,114 @@ data: secretKeyRef: name: {{ .Values.oauthSecret }} key: client_secret + extraVolumes: + - name: shared-data + emptyDir: {} + - name: init-script + configMap: + defaultMode: 400 + name: {{ .Values.global.name }}-init-script + - name: check-frontend-files + configMap: + defaultMode: 400 + name: {{ .Values.global.name }}-check-frontend-files + - name: sidecar-nginx-config + configMap: + defaultMode: 400 + name: {{ .Values.global.name }}-sidecar-nginx-config + - name: reservation-keypair + secret: + secretName: reservation-keypair + - name: tunnel-certs + secret: + secretName: tunnel-certs-public + items: + - key: tls.ca + path: ca.pem + - name: twofa-keypair + secret: + secretName: twofa-keypair + items: + - key: ssh-privatekey + path: twofa + mode: 0400 + - name: twofa-remove-keypair + secret: + secretName: twofa-remove-keypair + items: + - key: ssh-privatekey + path: twofa + mode: 0400 + - name: tz-config + hostPath: + path: /usr/share/zoneinfo/Europe/Berlin + initContainers: + - name: prepare-shared-data + image: alpine:3.18 + imagePullPolicy: Always + command: ["/bin/sh"] + args: + - -c + - >- + apk add bash git && + /bin/bash /mnt/init_script/..data/run.sh && + /bin/bash /mnt/check_frontend_files/..data/run.sh once && + mkdir -p /mnt/shared-data/reservation_key && + cp -rp /mnt/reservation-keypair/..data/* /mnt/shared-data/reservation_key/. && + chown 1000:1000 -R /mnt/shared-data/reservation_key && + chmod 400 /mnt/shared-data/reservation_key/* + volumeMounts: + - name: shared-data + mountPath: /mnt/shared-data + - name: persistent + mountPath: /mnt/persistent + - name: internal-ssl + mountPath: /mnt/internal_ssl + readOnly: true + - name: reservation-keypair + mountPath: /mnt/reservation-keypair + - name: init-script + mountPath: /mnt/init_script + - name: check-frontend-files + mountPath: /mnt/check_frontend_files + - name: twofa-keypair + mountPath: /mnt/twofa_keypair + - name: twofa-remove-keypair + mountPath: /mnt/twofa_remove_keypair + extraContainers: + - name: check-frontend-files + image: alpine:3.18 + imagePullPolicy: Always + command: ["/bin/sh"] + args: + - -c + - >- + apk add bash git && + /bin/bash /mnt/check_frontend_files/..data/run.sh + volumeMounts: + - name: shared-data + mountPath: /mnt/shared-data + - name: check-frontend-files + mountPath: /mnt/check_frontend_files + - name: tz-config + mountPath: /etc/localtime + - name: sidecar-nginx + image: nginx:1.25.3-alpine3.18-slim + imagePullPolicy: Always + ports: + - containerPort: 8070 + protocol: TCP + volumeMounts: + - name: shared-data + mountPath: /mnt/shared-data + - name: sidecar-nginx-config + mountPath: /etc/nginx/nginx.conf + subPath: nginx.conf + - name: sidecar-nginx-config + mountPath: /etc/nginx/conf.d/jupyter.conf + subPath: jupyter.conf + - name: tz-config + mountPath: /etc/localtime proxy: chp: defaultTarget: "https://{{ .Values.global.name }}-hub:8081"