PSA/ee/appliance/scripts/install-storage.sh
Hermes 284313f908
Some checks are pending
Bidi Control Character Guard / bidi-control-guard (push) Waiting to run
Circular Dependency Check / Check for new circular dependencies (push) Waiting to run
Citus Migration Smoke / Combined migrations on single-node Citus (push) Waiting to run
E2E Fresh Install Tests / fresh-install-e2e (push) Waiting to run
ext-v2 guardrails / Run ext-v2 guard and ESLint (push) Waiting to run
Integration Tests / Check for relevant changes (push) Waiting to run
Integration Tests / ${{ (github.event_name == 'schedule' || github.event.inputs.suite == 'full') && 'Full integration suite' || 'Tier-1 integration subset' }} (push) Blocked by required conditions
Mobile checks / Mobile lint + typecheck (push) Waiting to run
Mobile checks / Mobile unit tests (push) Waiting to run
Mobile checks / Mobile dependency audit (report) (push) Waiting to run
Mobile checks / Mobile reproducibility checks (push) Waiting to run
Secrets guard (env backups) / Ensure no tracked env backup files (push) Waiting to run
Temporal Readiness / fast-readiness (push) Waiting to run
Temporal Readiness / docker-parity (push) Waiting to run
TypeScript Type Check / Nx affected typecheck (push) Waiting to run
Unit Tests / Skipped-test budget (push) Waiting to run
Unit Tests / Nx affected unit tests (push) Waiting to run
Unit Tests / Server unit coverage (informational) (push) Waiting to run
Validate Tenant Management Schema / Check for relevant changes (push) Waiting to run
Validate Tenant Management Schema / Validate Tenant Management Schema (push) Blocked by required conditions
EE Workflows Build Guard / ee-workflows-build-guard (push) Waiting to run
Initial import of AlgaPSA codebase from PSA server
Excluded: .git, node_modules, secrets/, compose.env, assemblyscript tgz

Source: /opt/alga-psa on psa.joliet.tech
2026-06-22 16:12:17 -05:00

271 lines
7.2 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
KUBECONFIG_PATH="${KUBECONFIG:-}"
APPLIANCE_ROOT="$(CDPATH= cd -- "$(dirname -- "$0")/.." && pwd)"
STORAGE_MANIFEST="$APPLIANCE_ROOT/manifests/local-path-storage.yaml"
STORAGE_PATH="/var/mnt/alga-data/local-path-provisioner"
SMOKE_NAMESPACE="storage-smoke"
DRY_RUN=false
usage() {
cat <<'EOF'
Usage:
install-storage.sh --kubeconfig <path> [options]
Options:
--kubeconfig <path> Kubeconfig path
--dry-run Print the commands without mutating the cluster
--help Show this help
EOF
}
require_command() {
if ! command -v "$1" >/dev/null 2>&1; then
echo "Required command not found: $1" >&2
exit 1
fi
}
run_cmd() {
if $DRY_RUN; then
printf '+'
for arg in "$@"; do
printf ' %q' "$arg"
done
printf '\n'
return 0
fi
"$@"
}
kubectl_cmd() {
run_cmd kubectl --kubeconfig "$KUBECONFIG_PATH" "$@"
}
wait_for_rollout() {
if $DRY_RUN; then
echo "+ kubectl --kubeconfig $KUBECONFIG_PATH -n local-path-storage rollout status deployment/local-path-provisioner --timeout=5m"
return 0
fi
kubectl --kubeconfig "$KUBECONFIG_PATH" -n local-path-storage rollout status deployment/local-path-provisioner --timeout=5m
}
prepare_storage_path() {
local manifest
if $DRY_RUN; then
cat <<EOF
+ kubectl --kubeconfig $KUBECONFIG_PATH apply -f -
apiVersion: batch/v1
kind: Job
metadata:
name: local-path-storage-prepare
namespace: local-path-storage
EOF
return 0
fi
manifest="$(cat <<EOF
apiVersion: batch/v1
kind: Job
metadata:
name: local-path-storage-prepare
namespace: local-path-storage
spec:
ttlSecondsAfterFinished: 300
backoffLimit: 0
template:
spec:
restartPolicy: Never
containers:
- name: prepare
image: busybox:1.36
securityContext:
privileged: true
command:
- sh
- -ec
- |
mkdir -p /host${STORAGE_PATH}
chmod 0777 /host${STORAGE_PATH}
volumeMounts:
- name: host-root
mountPath: /host
volumes:
- name: host-root
hostPath:
path: /
type: Directory
EOF
)"
printf '%s\n' "$manifest" | kubectl --kubeconfig "$KUBECONFIG_PATH" apply -f -
kubectl --kubeconfig "$KUBECONFIG_PATH" -n local-path-storage wait --for=condition=complete --timeout=5m job/local-path-storage-prepare
}
reconcile_existing_storage_class() {
if $DRY_RUN; then
echo "+ inspect existing local-path StorageClass and delete it only when it is incompatible and unused"
return 0
fi
if ! kubectl --kubeconfig "$KUBECONFIG_PATH" get storageclass local-path >/dev/null 2>&1; then
return 0
fi
local reclaim_policy=""
reclaim_policy="$(kubectl --kubeconfig "$KUBECONFIG_PATH" get storageclass local-path -o jsonpath='{.reclaimPolicy}' 2>/dev/null || true)"
if [ "$reclaim_policy" = "Retain" ]; then
return 0
fi
local pv_count pvc_count
pv_count="$(kubectl --kubeconfig "$KUBECONFIG_PATH" get pv -o jsonpath='{range .items[?(@.spec.storageClassName=="local-path")]}x{end}' 2>/dev/null | wc -c | tr -d ' ')"
pvc_count="$(kubectl --kubeconfig "$KUBECONFIG_PATH" get pvc -A -o jsonpath='{range .items[?(@.spec.storageClassName=="local-path")]}x{end}' 2>/dev/null | wc -c | tr -d ' ')"
if [ "${pv_count:-0}" != "0" ] || [ "${pvc_count:-0}" != "0" ]; then
echo "Existing local-path StorageClass has reclaimPolicy=$reclaim_policy and is already in use; refusing to replace it automatically." >&2
exit 1
fi
echo "Replacing unused local-path StorageClass with appliance Retain policy."
kubectl --kubeconfig "$KUBECONFIG_PATH" delete storageclass local-path
}
run_smoke_test() {
local manifest
if $DRY_RUN; then
cat <<EOF
+ kubectl --kubeconfig $KUBECONFIG_PATH create namespace $SMOKE_NAMESPACE --dry-run=client -o yaml | kubectl apply -f -
+ kubectl --kubeconfig $KUBECONFIG_PATH label namespace $SMOKE_NAMESPACE pod-security.kubernetes.io/enforce=privileged pod-security.kubernetes.io/audit=privileged pod-security.kubernetes.io/warn=privileged --overwrite
+ kubectl --kubeconfig $KUBECONFIG_PATH apply -f -
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: storage-smoke-pvc
namespace: $SMOKE_NAMESPACE
---
apiVersion: batch/v1
kind: Job
metadata:
name: storage-smoke
namespace: $SMOKE_NAMESPACE
EOF
return 0
fi
kubectl --kubeconfig "$KUBECONFIG_PATH" create namespace "$SMOKE_NAMESPACE" --dry-run=client -o yaml | kubectl --kubeconfig "$KUBECONFIG_PATH" apply -f -
kubectl --kubeconfig "$KUBECONFIG_PATH" label namespace "$SMOKE_NAMESPACE" \
pod-security.kubernetes.io/enforce=privileged \
pod-security.kubernetes.io/audit=privileged \
pod-security.kubernetes.io/warn=privileged \
--overwrite
manifest="$(cat <<EOF
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: storage-smoke-pvc
namespace: $SMOKE_NAMESPACE
spec:
accessModes:
- ReadWriteOnce
storageClassName: local-path
resources:
requests:
storage: 1Gi
---
apiVersion: batch/v1
kind: Job
metadata:
name: storage-smoke
namespace: $SMOKE_NAMESPACE
spec:
backoffLimit: 0
template:
spec:
restartPolicy: Never
containers:
- name: smoke
image: busybox:1.36
command:
- sh
- -c
- echo ok > /data/ready && cat /data/ready
volumeMounts:
- name: data
mountPath: /data
volumes:
- name: data
persistentVolumeClaim:
claimName: storage-smoke-pvc
EOF
)"
printf '%s\n' "$manifest" | kubectl --kubeconfig "$KUBECONFIG_PATH" apply -f -
kubectl --kubeconfig "$KUBECONFIG_PATH" -n "$SMOKE_NAMESPACE" wait --for=condition=complete --timeout=5m job/storage-smoke
kubectl --kubeconfig "$KUBECONFIG_PATH" -n "$SMOKE_NAMESPACE" logs job/storage-smoke >/dev/null
kubectl --kubeconfig "$KUBECONFIG_PATH" delete namespace "$SMOKE_NAMESPACE" --ignore-not-found >/dev/null
}
while [ "$#" -gt 0 ]; do
case "$1" in
--kubeconfig)
KUBECONFIG_PATH="$2"
shift 2
;;
--dry-run)
DRY_RUN=true
shift
;;
--help|-h)
usage
exit 0
;;
*)
echo "Unknown argument: $1" >&2
usage >&2
exit 1
;;
esac
done
require_command kubectl
if [ -z "$KUBECONFIG_PATH" ]; then
echo "Kubeconfig path is required via --kubeconfig or KUBECONFIG." >&2
exit 1
fi
if [ ! -f "$KUBECONFIG_PATH" ] && ! $DRY_RUN; then
echo "Kubeconfig file not found: $KUBECONFIG_PATH" >&2
exit 1
fi
if [ ! -f "$STORAGE_MANIFEST" ]; then
echo "Storage manifest not found: $STORAGE_MANIFEST" >&2
exit 1
fi
reconcile_existing_storage_class
kubectl_cmd apply -f "$STORAGE_MANIFEST"
if $DRY_RUN; then
echo "+ kubectl --kubeconfig $KUBECONFIG_PATH create namespace msp --dry-run=client -o yaml | kubectl --kubeconfig $KUBECONFIG_PATH apply -f -"
else
kubectl --kubeconfig "$KUBECONFIG_PATH" create namespace msp --dry-run=client -o yaml | kubectl --kubeconfig "$KUBECONFIG_PATH" apply -f -
fi
kubectl_cmd label namespace msp \
pod-security.kubernetes.io/enforce=privileged \
pod-security.kubernetes.io/audit=privileged \
pod-security.kubernetes.io/warn=privileged \
--overwrite
prepare_storage_path
wait_for_rollout
run_smoke_test
echo "Storage prerequisites are ready."