summarylogtreecommitdiffstats
path: root/multi-capo-shell
blob: 5e65fc35780af3c61bea72124a53551b05ce20fc (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#!/usr/bin/env bash

set -eu
set -o pipefail

if [[ "${1:-}" == "--help" ]] || [[ "${1:-}" == "-h" ]]; then
  cat <<EOF
Usage: multi-capo-shell [command...]

Interactively selects a CAPO cluster from all management clusters using
fzf, then opens a capo-shell for the selected cluster.

Arguments:
  command      Command to pass through to capo-shell (default: \$SHELL or bash)

Environment variables (override/extend config file):
  MANAGEMENT_KUBECONFIGS                    Semicolon-separated list of management kubeconfig paths
  KUBECONFIG                                Semicolon-separated management cluster kubeconfig paths (additional)
  MULTI_CAPO_SHELL_CUSTOM_COLUMN_<name>     yq expression for an extra fzf preview column (overrides config)
  MULTI_CAPO_SHELL_CUSTOM_NAME_EXPRESSION   yq expression for a custom cluster display name

Config file: \${XDG_CONFIG_HOME:-\$HOME/.config}/capo-shell/config.yaml
  management_clusters[].{kubeconfig,context}   cluster sources (merged with env vars above)
  custom_fields.<name>                          jq expressions for fzf preview columns (used if no env columns set)
EOF
  exit 0
fi

if ! command -v fzf &>/dev/null; then
  echo "fzf is required but not installed. Please install fzf to use this script." >&2
  exit 1
fi

_capo_config="${XDG_CONFIG_HOME:-$HOME/.config}/capo-shell/config.yaml"
declare -a _mgmt_kubeconfigs=()
declare -a _mgmt_contexts=()

while IFS= read -r _kc; do
  [[ -n "$_kc" ]] && _mgmt_kubeconfigs+=("$_kc") && _mgmt_contexts+=("")
done < <(
  [[ -v MANAGEMENT_KUBECONFIGS ]] && echo -e "${MANAGEMENT_KUBECONFIGS//;/\\n}"
  [[ -v KUBECONFIG ]] && echo -e "${KUBECONFIG//;/\\n}"
)

if [[ -f "$_capo_config" ]]; then
  while IFS= read -r _kc && IFS= read -r _ctx; do
    _expanded="$(envsubst <<< "$_kc")"
    [[ -n "$_expanded" ]] && _mgmt_kubeconfigs+=("$_expanded") && _mgmt_contexts+=("$_ctx")
  done < <(yq -r '.management_clusters[] | (.kubeconfig, (.context // ""))' "$_capo_config")
fi

declare -a custom_columns=()
for custom_column_var in ${!MULTI_CAPO_SHELL_CUSTOM_COLUMN_*}; do
  custom_columns+=("${!custom_column_var}")
done
if [[ "${#custom_columns[@]}" -eq 0 ]] && [[ -f "$_capo_config" ]]; then
  while IFS= read -r _expr; do
    [[ -n "$_expr" ]] && custom_columns+=("$_expr")
  done < <(yq -r '(.custom_fields // {}) | to_entries[] | select(.key != "friendly_name") | .value' "$_capo_config")
fi
if [[ "${#custom_columns[@]}" -gt 0 ]]; then
  printf -v custom_columns_string "\\(%s):" "${custom_columns[@]}"
else
  custom_columns_string=""
fi

if [[ ! -v MULTI_CAPO_SHELL_CUSTOM_NAME_EXPRESSION ]] && [[ -f "$_capo_config" ]]; then
  _friendly_expr="$(yq -r '.custom_fields.friendly_name // empty' "$_capo_config")"
  [[ -n "$_friendly_expr" ]] && MULTI_CAPO_SHELL_CUSTOM_NAME_EXPRESSION="$_friendly_expr"
fi
MULTI_CAPO_SHELL_CUSTOM_NAME_EXPRESSION="${MULTI_CAPO_SHELL_CUSTOM_NAME_EXPRESSION:-\"\"}"

if [[ "${#_mgmt_kubeconfigs[@]}" -gt 0 ]]; then
  shopt -s lastpipe
  for _i in "${!_mgmt_kubeconfigs[@]}"; do
    export KUBECONFIG="${_mgmt_kubeconfigs[$_i]}"
    if [[ -n "${_mgmt_contexts[$_i]}" ]]; then
      _contexts=("${_mgmt_contexts[$_i]}")
    else
      mapfile -t _contexts < <(kubectl config get-contexts -o name)
    fi
    for context in "${_contexts[@]}"; do
      (kubectl --context "$context" get cluster -A -o yaml || true) | yq -r --arg kubeconfig "$KUBECONFIG" --arg context "$context" '.items | map("\($kubeconfig):\($context):\(.metadata.namespace):\(.metadata.name):'"$custom_columns_string"'\(('"${MULTI_CAPO_SHELL_CUSTOM_NAME_EXPRESSION}"') as $custom_name | if $custom_name == "" then .metadata.name else "\($custom_name) (\(.metadata.name))" end)")[]'
    done
  done | fzf --sync --preview="awk -v name={} 'BEGIN{split(name,splitted,\":\"); print splitted[2] \"@\" splitted[1]}'" -d : --with-nth=5..$((5 + ${#custom_columns[@]})) | IFS=: read -r mgmt_kubeconfig mgmt_context namespace name _
  exec env KUBECONFIG="$mgmt_kubeconfig" KUBECONFIG_CONTEXT="$mgmt_context" capo-shell "$namespace" "$name" "${@}"
fi