blob: 790c72351fdc49faedc06fdae6a3527b6e175063 (
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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
#!/usr/bin/env bash
set -eu
set -o pipefail
if [[ "${1:-}" == "--help" ]] || [[ "${1:-}" == "-h" ]]; then
cat <<EOF
Usage: capo-shell <namespace> <name> [command...]
Opens a shell with kubeconfig and OpenStack environment variables set for
a CAPO-managed CAPI cluster.
Arguments:
namespace Kubernetes namespace of the cluster
name Name of the cluster
command Command to run (default: \$SHELL or bash)
Environment variables (override config file):
KUBECONFIG_CONTEXT kubectl context to use for the management cluster
CAPO_SHELL_KUBECONFIG_FILTER yq expression to filter the workload kubeconfig
CAPO_SHELL_SSHUTTLE_HOST SSH host to proxy API server traffic via sshuttle
Config file: \${XDG_CONFIG_HOME:-\$HOME/.config}/capo-shell/config.yaml
transforms.{clusters,contexts,users} jq expressions applied to workload kubeconfig sections
sshuttle_host global SSH proxy host
management_clusters[].sshuttle_host per-cluster SSH proxy host (matched by KUBECONFIG path)
EOF
exit 0
fi
namespace="${1?}"
name="${2?}"
shift
shift
envs=()
_capo_config="${XDG_CONFIG_HOME:-$HOME/.config}/capo-shell/config.yaml"
if [[ -f "$_capo_config" ]]; then
if [[ ! -v CAPO_SHELL_SSHUTTLE_HOST ]]; then
_sshuttle=""
if [[ -v KUBECONFIG ]]; then
while IFS= read -r _kc && IFS= read -r _sh; do
if [[ "$(envsubst <<< "$_kc")" == "$KUBECONFIG" ]] && [[ -n "$_sh" ]]; then
_sshuttle="$(envsubst <<< "$_sh")"
break
fi
done < <(yq -r '.management_clusters[] | (.kubeconfig, (.sshuttle_host // ""))' "$_capo_config")
fi
if [[ -z "$_sshuttle" ]]; then
_sshuttle="$(yq -r '.sshuttle_host // empty' "$_capo_config")"
[[ -n "$_sshuttle" ]] && _sshuttle="$(envsubst <<< "$_sshuttle")"
fi
[[ -n "$_sshuttle" ]] && CAPO_SHELL_SSHUTTLE_HOST="$_sshuttle"
fi
if [[ ! -v CAPO_SHELL_KUBECONFIG_FILTER ]]; then
_filter=""
_t="$(yq -r '.transforms.clusters // empty' "$_capo_config")"
[[ -n "$_t" ]] && _filter="${_filter:+$_filter | }.clusters |= map($_t)"
_t="$(yq -r '.transforms.contexts // empty' "$_capo_config")"
[[ -n "$_t" ]] && _filter="${_filter:+$_filter | }.contexts |= map($_t)"
_t="$(yq -r '.transforms.users // empty' "$_capo_config")"
[[ -n "$_t" ]] && _filter="${_filter:+$_filter | }.users |= map($_t)"
[[ -n "$_filter" ]] && CAPO_SHELL_KUBECONFIG_FILTER="$_filter"
fi
fi
function cleanup() {
[[ -v NEW_KUBECONFIG ]] && [[ -f "$NEW_KUBECONFIG" ]] && rm -f "$NEW_KUBECONFIG"
[[ -v PROXY_PID ]] && kill "$PROXY_PID"
}
trap 'EC=$?; cleanup || true; exit $EC' EXIT INT TERM
NEW_KUBECONFIG="$(mktemp -p "$XDG_RUNTIME_DIR")"
if [[ -v KUBECONFIG_CONTEXT ]]; then
function kubectl() {
command kubectl --context "$KUBECONFIG_CONTEXT" "$@"
}
fi
if kubectl -n "$namespace" get secrets "${name}-kubeconfig" -o jsonpath='{.data.value}' 2>/dev/null | base64 -d >"$NEW_KUBECONFIG"; then
hasKubeconfig=true
envs+=(KUBECONFIG="$NEW_KUBECONFIG")
if [[ -v CAPO_SHELL_KUBECONFIG_FILTER ]]; then
yq -Y "$CAPO_SHELL_KUBECONFIG_FILTER" "$NEW_KUBECONFIG" | sponge "$NEW_KUBECONFIG"
fi
else
hasKubeconfig=false
envs+=(KUBECONFIG="")
fi
if secretName="$(kubectl -n "$namespace" get openstackcluster -l cluster.x-k8s.io/cluster-name="$name" -o yaml 2>/dev/null | yq -er '.items[0].spec.identityRef.name')"; then
hasOSConfig=true
mapfile -t osEnvs < <(kubectl -n "$namespace" get secret "$secretName" -o jsonpath='{.data.clouds\.yaml}' | base64 -d | yq -er '.clouds.openstack | {OS_AUTH_TYPE: .["auth_type"], OS_AUTH_URL: .auth["auth_url"], OS_APPLICATION_CREDENTIAL_ID: .auth["application_credential_id"], OS_APPLICATION_CREDENTIAL_SECRET: .auth["application_credential_secret"], OS_REGION_NAME: .["region_name"], OS_INTERFACE: .interface, OS_IDENTITY_API_VERSION: .["identity_api_version"]} | to_entries[] | "\(.key)=\(.value)"')
envs+=(OS_SHELL=true "${osEnvs[@]}")
else
hasOSConfig=false
envs+=(OS_AUTH_URL="")
fi
if [[ "$hasOSConfig" == false ]] && [[ "$hasKubeconfig" == false ]]; then
echo "All secrets are missing!" >/dev/stderr
exit 1
fi
if [[ "$hasOSConfig" == false ]]; then
echo "OpenStack config missing, only setting KUBECONFIG" >/dev/stderr
fi
if [[ "$hasKubeconfig" == false ]]; then
echo "KUBECONFIG missing, only setting OpenStack env" >/dev/stderr
elif clusterEndpoint="$(kubectl -n "$namespace" get openstackcluster -l cluster.x-k8s.io/cluster-name="$name" -o yaml 2>/dev/null | yq -er '.items[0] | if .spec.apiServerLoadBalancer.allowedCIDRs then .spec.controlPlaneEndpoint | "\(.host) \(.port)" else null end')"; then
read -r apiServerIP apiServerPort <<< "$clusterEndpoint"
if [[ -v CAPO_SHELL_SSHUTTLE_HOST ]]; then
sshuttle -r "$CAPO_SHELL_SSHUTTLE_HOST" "$apiServerIP:$apiServerPort" &>/dev/null &
PROXY_PID=$!
fi
fi
env -u KUBECONFIG -u KUBECONFIG_CONTEXT -u PROXY_PID "${envs[@]}" "${@:-${SHELL:-/usr/bin/env bash}}"
|