set fallback := true export LONGHORN_NAMESPACE := env("LONGHORN_NAMESPACE", "longhorn") export LONGHORN_VERSION := env("LONGHORN_VERSION", "1.10.1") export LONGHORN_HOST := env("LONGHORN_HOST", "") export LONGHORN_OIDC_CLIENT_ID := env("LONGHORN_OIDC_CLIENT_ID", "longhorn") export KEYCLOAK_REALM := env("KEYCLOAK_REALM", "") [private] default: @just --list --unsorted --list-submodules # Add Helm repository add-helm-repo: helm repo add longhorn https://charts.longhorn.io helm repo update # Remove Helm repository remove-helm-repo: helm repo remove longhorn # Create namespace create-namespace: #!/bin/bash set -euo pipefail if ! kubectl get namespace ${LONGHORN_NAMESPACE} &>/dev/null; then kubectl create namespace ${LONGHORN_NAMESPACE} else echo "Namespace ${LONGHORN_NAMESPACE} already exists." fi # Delete namespace delete-namespace: #!/bin/bash set -euo pipefail if kubectl get namespace ${LONGHORN_NAMESPACE} &>/dev/null; then kubectl delete namespace ${LONGHORN_NAMESPACE} --ignore-not-found else echo "Namespace ${LONGHORN_NAMESPACE} does not exist." fi # Install Longhorn install: #!/bin/bash set -euo pipefail # https://longhorn.io/docs/1.9.1/deploy/install/install-with-helm/ just add-helm-repo helm upgrade --cleanup-on-fail --install longhorn longhorn/longhorn \ --version ${LONGHORN_VERSION} -n ${LONGHORN_NAMESPACE} --create-namespace --wait \ -f longhorn-values.yaml just set-replicas 1 just patch-resources # Uninstall Longhorn uninstall: #!/bin/bash set -euxo pipefail if ! kubectl get -n ${LONGHORN_NAMESPACE} settings.longhorn.io \ deleting-confirmation-flag &>/dev/null; then kubectl apply -n ${LONGHORN_NAMESPACE} -f delete-setting.yaml fi helm uninstall longhorn -n ${LONGHORN_NAMESPACE} --ignore-not-found --wait just delete-namespace # Set Longhorn number of replicas set-replicas num='1': #!/bin/bash set -euo pipefail if ! command -v jq &>/dev/null; then echo "jq is not installed. Install jq." >&2 exit 1 fi yaml=$(kubectl get -n ${LONGHORN_NAMESPACE} configmap longhorn-storageclass \ -o jsonpath='{.data.storageclass\.yaml}') modified_yaml=$(echo "${yaml}" | sed 's/numberOfReplicas: "3"/numberOfReplicas: "{{ num }}"/') kubectl patch -n ${LONGHORN_NAMESPACE} configmap longhorn-storageclass \ --type merge -p "$(cat </dev/null; then echo "✓ Deployments are ready" break fi if [ $i -eq 30 ]; then echo "Warning: Timeout waiting for deployments. Skipping resource patching." exit 0 fi sleep 2 done # Patch csi-attacher deployment kubectl patch deployment csi-attacher -n ${LONGHORN_NAMESPACE} --type='json' -p='[ { "op": "replace", "path": "/spec/template/spec/containers/0/resources", "value": { "requests": {"cpu": "50m", "memory": "128Mi"}, "limits": {"cpu": "50m", "memory": "128Mi"} } } ]' # Patch csi-provisioner deployment kubectl patch deployment csi-provisioner -n ${LONGHORN_NAMESPACE} --type='json' -p='[ { "op": "replace", "path": "/spec/template/spec/containers/0/resources", "value": { "requests": {"cpu": "50m", "memory": "128Mi"}, "limits": {"cpu": "50m", "memory": "128Mi"} } } ]' # Patch csi-resizer deployment kubectl patch deployment csi-resizer -n ${LONGHORN_NAMESPACE} --type='json' -p='[ { "op": "replace", "path": "/spec/template/spec/containers/0/resources", "value": { "requests": {"cpu": "50m", "memory": "128Mi"}, "limits": {"cpu": "50m", "memory": "128Mi"} } } ]' # Patch csi-snapshotter deployment kubectl patch deployment csi-snapshotter -n ${LONGHORN_NAMESPACE} --type='json' -p='[ { "op": "replace", "path": "/spec/template/spec/containers/0/resources", "value": { "requests": {"cpu": "50m", "memory": "128Mi"}, "limits": {"cpu": "50m", "memory": "128Mi"} } } ]' # Find and patch engine-image daemonset (name includes hash) ENGINE_IMAGE_DS=$(kubectl get daemonset -n ${LONGHORN_NAMESPACE} -o name | grep engine-image) if [ -n "${ENGINE_IMAGE_DS}" ]; then kubectl patch ${ENGINE_IMAGE_DS} -n ${LONGHORN_NAMESPACE} --type='json' -p='[ { "op": "replace", "path": "/spec/template/spec/containers/0/resources", "value": { "requests": {"cpu": "50m", "memory": "128Mi"}, "limits": {"cpu": "50m", "memory": "128Mi"} } } ]' fi # Patch longhorn-csi-plugin daemonset (3 containers) kubectl patch daemonset longhorn-csi-plugin -n ${LONGHORN_NAMESPACE} --type='json' -p='[ { "op": "replace", "path": "/spec/template/spec/containers/0/resources", "value": { "requests": {"cpu": "50m", "memory": "64Mi"}, "limits": {"cpu": "50m", "memory": "64Mi"} } }, { "op": "replace", "path": "/spec/template/spec/containers/1/resources", "value": { "requests": {"cpu": "50m", "memory": "64Mi"}, "limits": {"cpu": "50m", "memory": "64Mi"} } }, { "op": "replace", "path": "/spec/template/spec/containers/2/resources", "value": { "requests": {"cpu": "50m", "memory": "64Mi"}, "limits": {"cpu": "50m", "memory": "64Mi"} } } ]' # Patch longhorn-driver-deployer deployment kubectl patch deployment longhorn-driver-deployer -n ${LONGHORN_NAMESPACE} --type='json' -p='[ { "op": "replace", "path": "/spec/template/spec/containers/0/resources", "value": { "requests": {"cpu": "50m", "memory": "128Mi"}, "limits": {"cpu": "50m", "memory": "128Mi"} } } ]' # Patch longhorn-manager daemonset (2 containers - core component, add extra headroom) kubectl patch daemonset longhorn-manager -n ${LONGHORN_NAMESPACE} --type='json' -p='[ { "op": "replace", "path": "/spec/template/spec/containers/0/resources", "value": { "requests": {"cpu": "50m", "memory": "512Mi"}, "limits": {"cpu": "100m", "memory": "512Mi"} } }, { "op": "replace", "path": "/spec/template/spec/containers/1/resources", "value": { "requests": {"cpu": "50m", "memory": "64Mi"}, "limits": {"cpu": "50m", "memory": "64Mi"} } } ]' # Patch longhorn-ui deployment kubectl patch deployment longhorn-ui -n ${LONGHORN_NAMESPACE} --type='json' -p='[ { "op": "replace", "path": "/spec/template/spec/containers/0/resources", "value": { "requests": {"cpu": "50m", "memory": "128Mi"}, "limits": {"cpu": "50m", "memory": "128Mi"} } } ]' echo "All Longhorn component resources have been patched successfully!" # Setup OAuth2-Proxy for Longhorn oauth2-proxy-install: #!/bin/bash set -euo pipefail export LONGHORN_HOST=${LONGHORN_HOST:-} while [ -z "${LONGHORN_HOST}" ]; do LONGHORN_HOST=$( gum input --prompt="Longhorn host (FQDN): " --width=100 \ --placeholder="e.g., longhorn.example.com" ) done echo "Setting up OAuth2-Proxy for Longhorn at https://${LONGHORN_HOST}..." just oauth2-proxy::setup-for-app longhorn "${LONGHORN_HOST}" "${LONGHORN_NAMESPACE}" "longhorn-frontend:80" echo "OAuth2-Proxy setup completed for Longhorn" echo "Longhorn Web UI at: https://${LONGHORN_HOST}" # Remove OAuth2-Proxy for Longhorn oauth2-proxy-uninstall: #!/bin/bash set -euo pipefail echo "Removing OAuth2-Proxy for Longhorn..." just oauth2-proxy::remove-for-app longhorn "${LONGHORN_NAMESPACE}" echo "OAuth2-Proxy removed from Longhorn" # Setup OAuth2-Proxy for Longhorn setup-oauth2-proxy: just oauth2-proxy-install # Remove OAuth2-Proxy for Longhorn remove-oauth2-proxy: just oauth2-proxy-uninstall