#! /usr/bin/env bash # [LICENSE: GPL3](https://www.gnu.org/licenses/gpl-3.0.en.html) # Author: [Lockszmith](https://stackexchange.com/users/421248/lockszmith) 2023-10(Oct)-08 set -e eval "$SETX" ZELLIJ_PATH="${ZELLIJ_PATH:-$(which zellij)}" || true NOZELLIJ=${NOZELLIJ:-$NOWATCH} NOWATCH=${NOWATCH:-$NOZELLIJ} main() { if [[ -n "${ZELLIJ_PATH}" && -x "${ZELLIJ_PATH}" && -z "$NOZELLIJ" ]]; then printf "Starting zellij layout..." >&2 $ZELLIJ_PATH ${INTAB:+action new-tab} --layout <( get_zellij_layout # ZELLIJ_PATH="$ZELLIJ_PATH" APP="$APP" NS="$NS" TAIL="$TAIL" \ # envsubst < ~/watch-k3s-app.kdl ) else unset ZELLIJ_PATH export NOZELLIJ=1 APP="$APP" $0 -- "charts" $0 -- "pvc" $0 -- "apps" $0 -- "services" $0 -- "events" $0 -- "pods" $0 -- "cnpg" $0 -- "logs" fi } get_zellij_layout() { cat - <<ZELLIJ_LAYOUT layout { pane_template name="watch_k3s_app" { command "$HOME/bin/watch-k3s-app" } pane_template name="charts" { watch_k3s_app name="CHARTS" size=5 { args "--" "charts" "KUBECONFIG=${KUBECONFIG}" "NS=${NS}" "APP=${APP}" "TAIL=${TAIL}" "SETX=${SETX}" } } pane_template name="pvc" { watch_k3s_app name="PERSISTENT VOLUME CLAIMS (PVC)" size=9 { args "--" "pvc" "KUBECONFIG=${KUBECONFIG}" "NS=${NS}" "APP=${APP}" "TAIL=${TAIL}" "SETX=${SETX}" } } pane_template name="apps" { watch_k3s_app name="DEPLOYMENT.APPS" { args "--" "apps" "KUBECONFIG=${KUBECONFIG}" "NS=${NS}" "APP=${APP}" "TAIL=${TAIL}" "SETX=${SETX}" } } pane_template name="services" { watch_k3s_app name="SERVICES" size=9 { args "--" "services" "KUBECONFIG=${KUBECONFIG}" "NS=${NS}" "APP=${APP}" "TAIL=${TAIL}" "SETX=${SETX}" } } pane_template name="services_and_apps" { pane split_direction="vertical" { apps size="35%" services } } pane_template name="events" { watch_k3s_app name="EVENTS" size=9 { args "--" "events" "KUBECONFIG=${KUBECONFIG}" "NS=${NS}" "APP=${APP}" "TAIL=${TAIL}" "SETX=${SETX}" } } pane_template name="pods" { watch_k3s_app name="PODS" { args "--" "pods" "KUBECONFIG=${KUBECONFIG}" "NS=${NS}" "APP=${APP}" "TAIL=${TAIL}" "SETX=${SETX}" } } pane_template name="pods_and_events" { pane split_direction="vertical" { pods size="40%" events } } pane_template name="logs" { watch_k3s_app name="LOGS ${APP}" { args "--" "logs" "KUBECONFIG=${KUBECONFIG}" "NS=${NS}" "APP=${APP}" "TAIL=${TAIL}" "SETX=${SETX}" } } pane_template name="cnpg" { watch_k3s_app name="CLOUDNATIVE POSTGRESQL" size=9 { args "--" "cnpg" "KUBECONFIG=${KUBECONFIG}" "NS=${NS}" "APP=${APP}" "TAIL=${TAIL}" "SETX=${SETX}" } } pane_template name="logs_and_cnpg" { pane split_direction="vertical" { logs size="65%" cnpg } } pane split_direction="horizontal" { pane size=1 command="printf" borderless=true { args "### Watching kubernetes environment ${NS} --- [Ctrl+x] to close | [mouse-click]+[F11] Expand Pane | [Ctrl-C]+[Enter] to refersh" } // pane stacked=true { charts pvc // } services_and_apps pods_and_events logs_and_cnpg } } keybinds { shared { bind "Ctrl x" { CloseTab; } bind "F11" { ToggleFocusFullscreen; } } } pane_frames true ZELLIJ_LAYOUT } repeat_out() { dd if=/dev/zero bs=${2:-10} count=1 2>/dev/null | tr '\0' "${1:?Repeat character missing}" } visual_sleep() { local SLEEP=$(( 0 + ${1:-2} )) MSG="${MSG:-Restarting in %s %s}" tput sc; while (( SLEEP > 0 )); do tput el; printf "$MSG" "${SLEEP}s" "$(repeat_out . ${SLEEP})" sleep 1s tput rc 1; tput el; (( SLEEP-=1 )) || true done } [[ "$1" == "--" ]] || APP=${APP:-${1}} NS=${APP:+--namespace=ix-}${APP:---all-namespaces} case $1 in "--help") cat - <<USAGE Watch k3s apps (with zellij support) for TrueChart Apps on TrueNAS SCALE Usage: $(basename $0) [Installed App Name] $(basename $0) -- <output type> [<Set Expression1> [<Set Expression...>]] Invokation modifiers (environment variable): [NOREPEAT=1] [NOWATCH=1] [SLEEP=3] $(basename $0) ... Description: This script will pull from k3s the follwing: charts (helm charts) pvc apps (deployment.apps) services events pods cnpg status (applicable for APP only) contianer-logs (applicable for APP only) By default, if zellij exists, it will WATCH all of these for changes in parallel. If zellij doesn't exist, it will list all, SLEEP for a few seconds, then REPEAT. To produce output to share in bug reports, calling with NOREPEAT=1 NOWATCH=1 ... will output all the details and exit. If an APP is specified, output is confined to the specific namespace and service. Otherwise, it will output information about k3s all-namespaces. * For cnpg status, the cnpg plugin needs to be installed. On TrueNAS SCALE, this install might be required after a reboot. Zellij specific support When zellij exists and running, zellij will create a set of panes with the above list of views watching for changes in parallel. It maps <Ctrl>-<X> as the exit key. and it maps <F11> as a Full-Screen toggle, to use it you need to select inside a pane with a mouse, and then click the key. USAGE ;; "--") eval "${*:3}" export KUBECONFIG K_WATCH="${ZELLIJ_PATH:+--watch-only --no-headers}" C_WATCH="watch -tcn4" [[ -z "$NOZELLIJ" && -z "$NOWATCH" ]] || { K_WATCH=''; C_WATCH='eval'; } case "$2" in "charts") ${C_WATCH} "helm list ${NS} | sort" ;; "pvc") k3s kubectl get pvc ${NS} --sort-by='.metadata.creationTimestamp' [[ -z "${K_WATCH}" ]] || k3s kubectl get pvc ${NS} ${K_WATCH} ;; "apps") k3s kubectl get deployment.apps ${NS} --sort-by='.metadata.creationTimestamp' [[ -z "${K_WATCH}" ]] || k3s kubectl get deployment.apps ${NS} ${K_WATCH} ;; "services") k3s kubectl get services ${NS} --sort-by='.metadata.creationTimestamp' [[ -z "${K_WATCH}" ]] || k3s kubectl get services ${NS} ${K_WATCH} ;; "events") k3s kubectl get events ${NS} --sort-by='.metadata.creationTimestamp' [[ -z "${K_WATCH}" ]] || k3s kubectl get events ${NS} ${K_WATCH} \ ;; "pods") k3s kubectl get pods ${NS} --sort-by='.metadata.creationTimestamp' [[ -z "${K_WATCH}" ]] || k3s kubectl get pods ${NS} \ ${K_WATCH}; ;; "cnpg") sleep 0.4s; [[ -n "${APP}" ]] \ && ${C_WATCH} "k3s kubectl cnpg status ${NS} ${APP}-cnpg-main" \ || k3s kubectl get clusters.postgresql.cnpg.io ${NS} ${K_WATCH} ;; "logs") MSG='N/A with --all-namespaces' if [[ -n "${APP}" ]]; then MSG="no pods active for $APP" APP=($(k3s kubectl get pods ${NS} --output name | grep -E "^pod/$APP(-[^-]+){2}$")) FOLLOW='--follow' [[ -z "$NOWATCH" ]] || { FOLLOW=''; TAIL=${TAIL:-40}; } while ! k3s kubectl logs ${NS} ${FOLLOW} ${TAIL:+--tail=${TAIL}} \ "${APP}"; do printf 'could not load logs, checking for previous logs...\n' k3s kubectl logs ${NS} -p ${TAIL:+--tail=${TAIL}} "${APP}" \ || printf "${MSG}" [[ -z "$NOWATCH" ]] || break; visual_sleep ${SLEEP:-3} done fi ;; *) printf "Don't know how to handle $2\n" 1>&2; false; ;; esac ;; *) while main "$1" && [[ -z "$NOREPEAT" ]]; do tput cuu1; visual_sleep ${SLEEP:-3} done esac