generates a config based on the configmap and secrets in the cluster. this config is intended to be used to add an external node to the cluster.
226 lines
6.4 KiB
Bash
Executable File
226 lines
6.4 KiB
Bash
Executable File
#!/bin/bash
|
|
|
|
set -e -o pipefail
|
|
|
|
shq() {(
|
|
while [ $# -gt 0 ];do
|
|
echo -n "'$(echo -n "$1" | sed -e "s/'/'\"'\"'/g")'"
|
|
shift
|
|
done
|
|
)}
|
|
|
|
json() {( # json encode the argument
|
|
jq -n --arg v "$@" '$v'
|
|
)}
|
|
|
|
GARAGE_NAMESPACE="${GARAGE_NAMESPACE-garage}"
|
|
|
|
ARGS="$(shq "$@")"
|
|
ZERO="$0"
|
|
ONE="$1"
|
|
ONE_UNDER="$(echo -n "$ONE" | tr - _)"
|
|
NL="$(echo)"
|
|
|
|
enumerate_pods() { # enumerate kubernetes-based garage pods
|
|
kubectl get pod -n "$GARAGE_NAMESPACE" -l app=garage -o json | yq -ot '.items[] | [
|
|
.metadata.name,
|
|
.status.podIP,
|
|
.spec.containers[].ports[]|select(.name == "rpc")|.hostPort,
|
|
.spec.nodeName
|
|
]' | while read -r pod ip port node;do
|
|
gnid="$(grun "$pod" node id -q)"
|
|
printf "%${#pod}s %25s %s\n" $pod $node "$gnid@$ip:$port"
|
|
done
|
|
|
|
}
|
|
|
|
get_ids() { # get the public id of all discoverable servers
|
|
enumerate_pods | while read -r pod node gnid;do
|
|
echo "$gnid"
|
|
done
|
|
}
|
|
|
|
iterstats() { # get stats from running garage nodes via iteration over discovered ids
|
|
get_ids | while read -r id;do
|
|
garage -h "$id" stats
|
|
done
|
|
}
|
|
|
|
grun() {
|
|
TARGET="$1"
|
|
shift
|
|
kubectl exec -n "$GARAGE_NAMESPACE" -c garage "$TARGET" -- garage "$@"
|
|
}
|
|
|
|
garage() { # run an arbitrary garage command via a random garage pod
|
|
grun ds/garage "$@"
|
|
}
|
|
|
|
generate_secrets() { # generates secrets required to run garage
|
|
kubectl create secret -n "$GARAGE_NAMESPACE" generic garage-secrets \
|
|
--from-literal=admin-token="$( openssl rand -base64 32 )" \
|
|
--from-literal=metrics-token="$( openssl rand -base64 32 )" \
|
|
--from-literal=rpc-secret="$( openssl rand -hex 32 )"
|
|
}
|
|
|
|
generate_layout() {( # generates a sample layout, (args are included verbatim, e.g. -t k8s)
|
|
enumerate_pods | while read -r pod node gnid;do
|
|
kubectl get node/$node -o json | jq -r --arg zero "$ZERO" --arg gnid "${gnid%%@*}" '
|
|
[
|
|
$zero,
|
|
"garage", "layout", "assign", $gnid,
|
|
"-t", .metadata.name,
|
|
"-c", "\((.metadata.labels["strudelline.net/garage-data-free-bytes"]//"10737418240")|tonumber/1024/1024/1024|floor)G"
|
|
]+$ARGS.positional
|
|
| @sh' --args -- "$@" | while read -r cmd;do
|
|
eval "set $cmd"
|
|
printf " %q" "$@" | cut -c 2-
|
|
done
|
|
done
|
|
)}
|
|
|
|
generate_external_config() {( # generate a config for an external node
|
|
jq -rn \
|
|
--argjson secret "$(kubectl -n "$GARAGE_NAMESPACE" get secret garage-secrets -o json)" \
|
|
--argjson cm "$(kubectl -n "$GARAGE_NAMESPACE" get configmap garage-config -o json)" \
|
|
--argjson peers "$(get_ids | jq -R | jq -s)" \
|
|
'
|
|
# FUNCTIONS
|
|
|
|
def prettyjson:
|
|
if type != "array" then [tojson] else
|
|
if length < 2 then [tojson] else
|
|
[ (.[0] | "[\n \(tojson),\n")
|
|
, (.[1:-1][] | " \(tojson),\n")
|
|
, (.[-1] | " \(tojson)\n")
|
|
, "]"
|
|
]
|
|
end
|
|
end | add;
|
|
|
|
# gencfg: generates a toml line which will use a raw json value if possible or a string if not.
|
|
# to guarantee a string, double encode it.
|
|
def gencfg:
|
|
( (.value | fromjson?) // .value) as $v
|
|
| (if .key == "bootstrap_peers" then ($v + $peers) else ($v) end) as $v
|
|
| "\(.key) = \($v | prettyjson)";
|
|
|
|
# secval: get the value of the $secret, base64 decoded.
|
|
# will emit 0 items (not an empty list!) if no matching key is found.
|
|
# try jq -n "[[][],1,[][]]" (and figure it out) for a more clear understanding.
|
|
def secval($k): $secret.data | to_entries[] | select(.key == $k) | .value | @base64d;
|
|
|
|
# SETUP VARIABLES
|
|
[ $cm | .data | to_entries[]
|
|
, {"key": "rpc_secret", "value": secval("rpc-secret")}
|
|
, {"key": "admin.admin_token", "value": secval("admin-token")}
|
|
, {"key": "admin.metrics_token", "value": secval("metrics-token")}
|
|
] | group_by(.key | test("[.]"))
|
|
as $asec
|
|
# data format now: [[{k,v},...],[{s.k,v},...]]
|
|
| $asec[0]
|
|
as $nsec
|
|
| [$asec[1][] | (.key | split(".")) as $k | {"section": $k[0], "key": $k[1], "value": .value}]
|
|
as $ysec
|
|
| [$ysec[] | .section] | unique
|
|
as $sections
|
|
|
|
| [][] # EMIT DATA -- [][] is to allow all outputs to start with ,
|
|
|
|
# emit unsectioned data
|
|
,(
|
|
$nsec[] |
|
|
gencfg
|
|
)
|
|
# emit sectioned data
|
|
,(
|
|
$sections[] as $section | (
|
|
"\n[\($section)]"
|
|
, ($ysec[] | select(.section == $section) | gencfg)
|
|
)
|
|
)
|
|
'
|
|
)}
|
|
|
|
make_bucket() { # make a bucket along with metadata in a namespace
|
|
TARGETBUCKET="$1"
|
|
TARGETKEYNAME="${2-$TARGETBUCKET}-app-key"
|
|
TARGETNS="${3-$TARGETBUCKET}"
|
|
TARGETSECRET="${3-$TARGETKEYNAME}"
|
|
|
|
kubectl get namespace "$TARGETNS" > /dev/null
|
|
|
|
garage bucket create "$TARGETBUCKET"
|
|
eval "$(
|
|
(garage key info "$TARGETKEYNAME" 2> /dev/null || garage key create "$TARGETKEYNAME") | awk '
|
|
/^key id: /i {printf("KID=%s\n", $3);}
|
|
/^secret key: /i {printf("SK=%s\n", $3);}
|
|
')"
|
|
garage bucket allow --read --write --owner "$TARGETBUCKET" --key "$TARGETKEYNAME"
|
|
|
|
kubectl create secret generic \
|
|
-n "$TARGETNS" "$TARGETSECRET" \
|
|
--type kubernetes.io/basic-auth \
|
|
--from-literal=username="$KID" \
|
|
--from-literal=password="$SK" \
|
|
--from-literal=AWS_ACCESS_KEY_ID="$KID" \
|
|
--from-literal=AWS_SECRET_ACCESS_KEY="$SK" \
|
|
--from-literal=bucket="$TARGETBUCKET"
|
|
|
|
kubectl label -n "$TARGETNS" secret/$TARGETSECRET bucket="$TARGETBUCKET" key="$TARGETKEYNAME"
|
|
}
|
|
|
|
connect() { # attempt to connect all nodes
|
|
allids="$(get_ids)"
|
|
primary="$(echo "$allids" | head -1)"
|
|
echo "$allids" | sed 1d | while read -r id;do
|
|
garage -h $primary node connect "$id"
|
|
done
|
|
}
|
|
|
|
env() { # generate alias to use cluster garage cli.
|
|
case "$1" in
|
|
bash | sh | zsh | '' )
|
|
printf "\nalias garage=%q\n" "$(printf "%q garage" "$PWD/tools")"
|
|
;;
|
|
*)
|
|
1>&2 echo "unknown shell"
|
|
exit 1
|
|
;;
|
|
esac
|
|
}
|
|
|
|
help() {( # this help
|
|
exec 1>&2
|
|
|
|
echo "usage: $0 <subcmd> [options]"
|
|
echo
|
|
echo GARAGE SUBCOMMANDS:
|
|
( 2>&1 garage --help || true ) | awk 'p==1&&/^ / {print lc,$0;next} p==1 {lc=$1;print;} /^SUBCOMMANDS:$/ {p=1}' | while read -r cmd help;do
|
|
printf " %-25s %s\n" "garage $cmd" "$help"
|
|
done
|
|
echo
|
|
echo "GARAGE CLUSTER TOOLS:"
|
|
grep -E "^[a-z_]+[(][)] {[(]? # .*" "$ZERO" | sed -Ee 's@[(][)] [{][(]? # @: @' |
|
|
while read cmd help;do
|
|
printf " %-25s %s\n" "$(echo -n $cmd | tr _ -)" "$help"
|
|
done
|
|
echo
|
|
)}
|
|
|
|
if [ "x$1" = x ];then
|
|
help
|
|
exit 1
|
|
fi
|
|
|
|
# we translate - to _ to allow enumerate-pods or enumerate_pods.
|
|
# it also changes -h to _h.
|
|
|
|
if [ "x$ONE" = "x-h" ];then
|
|
help
|
|
exit 0
|
|
fi
|
|
|
|
shift 1
|
|
"$ONE_UNDER" "$@"
|