diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ef81b1e --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/.venv/ diff --git a/abra-hetzner b/abra-capsul similarity index 68% rename from abra-hetzner rename to abra-capsul index c6a5106..1b6a9f3 100755 --- a/abra-hetzner +++ b/abra-capsul @@ -1,16 +1,18 @@ #!/usr/bin/env bash DOC=" -Hetzner provider plugin for abra +Capsul provider plugin for abra Usage: - abra-hetzner [--ssh-keys=] [--location=] + abra-capsul -Reads your Hetzner API token from the \$HETZNER_API_TOKEN environment variable -or prompts for it. +ENVIRONMENT +Read configuration from these variables, or prompt if unset: +- \$CAPSUL_API_TOKEN +- \$CAPSUL_SERVER " -# docopt parser below, refresh this parser with `docopt.sh abra-hetzner` +# docopt parser below, refresh this parser with `docopt.sh abra-capsul` # shellcheck disable=2016,1075 docopt() { parse() { if ${DOCOPT_DOC_CHECK:-true}; then local doc_hash if doc_hash=$(printf "%s" "$DOC" | (sha256sum 2>/dev/null || shasum -a 256)); then @@ -77,9 +79,7 @@ local node_idx; ((testdepth++)) || true; for node_idx in "$@"; do if ! "node_$node_idx"; then left=("${initial_left[@]}"); ((testdepth--)) || true return 1; fi; done; if [[ $((--testdepth)) -eq 0 ]]; then left=("${initial_left[@]}"); for node_idx in "$@"; do "node_$node_idx"; done; fi -return 0; }; optional() { local node_idx; for node_idx in "$@"; do -"node_$node_idx"; done; return 0; }; value() { local i -for i in "${!left[@]}"; do local l=${left[$i]} +return 0; }; value() { local i; for i in "${!left[@]}"; do local l=${left[$i]} if [[ ${parsed_params[$l]} = "$2" ]]; then left=("${left[@]:0:$i}" "${left[@]:((i+1))}") [[ $testdepth -gt 0 ]] && return 0; local value @@ -88,35 +88,31 @@ eval "var_$1+=($value)"; else eval "var_$1=$value"; fi; return 0; fi; done return 1; }; stdout() { printf -- "cat <<'EOM'\n%s\nEOM\n" "$1"; }; stderr() { printf -- "cat <<'EOM' >&2\n%s\nEOM\n" "$1"; }; error() { [[ -n $1 ]] && stderr "$1"; stderr "$usage"; _return 1; }; _return() { -printf -- "exit %d\n" "$1"; exit "$1"; }; set -e; trimmed_doc=${DOC:1:223} -usage=${DOC:35:91}; digest=0f15e; shorts=('' ''); longs=(--ssh-keys --location) -argcounts=(1 1); node_0(){ value __ssh_keys 0; }; node_1(){ value __location 1 -}; node_2(){ value _name_ a; }; node_3(){ value _type_ a; }; node_4(){ -value _image_ a; }; node_5(){ optional 0; }; node_6(){ optional 1; }; node_7(){ -required 2 3 4 5 6; }; node_8(){ required 7; }; cat <<<' docopt_exit() { -[[ -n $1 ]] && printf "%s\n" "$1" >&2; printf "%s\n" "${DOC:35:91}" >&2; exit 1 -}'; unset var___ssh_keys var___location var__name_ var__type_ var__image_ -parse 8 "$@"; local prefix=${DOCOPT_PREFIX:-''}; unset "${prefix}__ssh_keys" \ -"${prefix}__location" "${prefix}_name_" "${prefix}_type_" "${prefix}_image_" -eval "${prefix}"'__ssh_keys=${var___ssh_keys:-}' -eval "${prefix}"'__location=${var___location:-}' +printf -- "exit %d\n" "$1"; exit "$1"; }; set -e; trimmed_doc=${DOC:1:193} +usage=${DOC:34:49}; digest=9b8b6; shorts=(); longs=(); argcounts=(); node_0(){ +value _name_ a; }; node_1(){ value _size_ a; }; node_2(){ value _os_ a; } +node_3(){ value _ssh_key_ a; }; node_4(){ required 0 1 2 3; }; node_5(){ +required 4; }; cat <<<' docopt_exit() { [[ -n $1 ]] && printf "%s\n" "$1" >&2 +printf "%s\n" "${DOC:34:49}" >&2; exit 1; }'; unset var__name_ var__size_ \ +var__os_ var__ssh_key_; parse 5 "$@"; local prefix=${DOCOPT_PREFIX:-''} +unset "${prefix}_name_" "${prefix}_size_" "${prefix}_os_" "${prefix}_ssh_key_" eval "${prefix}"'_name_=${var__name_:-}' -eval "${prefix}"'_type_=${var__type_:-}' -eval "${prefix}"'_image_=${var__image_:-}'; local docopt_i=1 +eval "${prefix}"'_size_=${var__size_:-}'; eval "${prefix}"'_os_=${var__os_:-}' +eval "${prefix}"'_ssh_key_=${var__ssh_key_:-}'; local docopt_i=1 [[ $BASH_VERSION =~ ^4.3 ]] && docopt_i=2; for ((;docopt_i>0;docopt_i--)); do -declare -p "${prefix}__ssh_keys" "${prefix}__location" "${prefix}_name_" \ -"${prefix}_type_" "${prefix}_image_"; done; } -# docopt parser above, complete command for generating this parser is `docopt.sh abra-hetzner` +declare -p "${prefix}_name_" "${prefix}_size_" "${prefix}_os_" \ +"${prefix}_ssh_key_"; done; } +# docopt parser above, complete command for generating this parser is `docopt.sh abra-capsul` ABRA_DIR="${ABRA_DIR:-$HOME/.abra}" ABRA_VENDOR_DIR="$ABRA_DIR/vendor" JQ="$ABRA_VENDOR_DIR/jq" -abra_hetzner() { - declare abra_hetzner__name_ abra_hetzner__type_ abra_hetzner__image_ \ - abra_hetzner___ssh_keys abra_hetzner___location +abra_capsul() { + declare abra_capsul__name_ abra_capsul__size_ abra_capsul__os_ \ + abra_capsul__ssh_key_ - DOCOPT_PREFIX=abra_hetzner_ + DOCOPT_PREFIX=abra_capsul_ eval "$(docopt "$@")" @@ -124,41 +120,41 @@ abra_hetzner() { error "curl program is not installed" fi - if [[ -z "$HETZNER_API_TOKEN" ]]; then - read -rp "Hetzner API token: " HETZNER_API_TOKEN + if [[ -z "$CAPSUL_API_TOKEN" ]]; then + read -rp "Capsul API token: " CAPSUL_API_TOKEN fi - NAME="$abra_hetzner__name_" - TYPE="$abra_hetzner__type_" - IMAGE="$abra_hetzner__image_" + if [[ -z "$CAPSUL_SERVER" ]]; then + read -rp "Capsul server address: " CAPSUL_SERVER + fi - SSH_KEYS="$abra_hetzner___ssh_keys" - LOCATION="${abra_hetzner___location:-hel1}" + NAME="$abra_capsul__name_" + SIZE="$abra_capsul__size_" + OS="$abra_capsul__os_" - # shellcheck disable=SC2001 - ssh_keys=$(echo "$SSH_KEYS" | sed 's/[^[:space:],]\+/"&"/g') + SSH_KEY="$abra_capsul__ssh_key_" response=$(curl --silent \ -X POST \ - -H "Authorization: Bearer $HETZNER_API_TOKEN" \ + -H "Authorization: $CAPSUL_API_TOKEN" \ -H "Content-Type: application/json" \ -d "{\"name\":\"$NAME\", \ - \"server_type\": \"$TYPE\", \ - \"image\": \"$IMAGE\", \ - \"ssh_keys\": [$ssh_keys], \ - \"location\": \"$LOCATION\" \ + \"size\": \"$SIZE\", \ + \"os\": \"$OS\", \ + \"ssh_authorized_key_count\": \"1\", \ + \"ssh_key_0\": \"$SSH_KEY\" \ }" \ - 'https://api.hetzner.cloud/v1/servers') + "$CAPSUL_SERVER/api/capsul/create") - ip=$(echo "$response" | $JQ -r ".server .public_net .ipv4 .ip") + id=$(echo "$response" | $JQ -r ".id") - if [[ "$ip" == "null" ]]; then - error_msg=$(echo "$response" | jq -r ".error .message") - echo "Oops, something went wrong. Hetzner Cloud API responded with: $error_msg" + if [[ "$id" == "null" ]]; then + error_msg=$(echo "$response" | jq -r ".errors") + echo "Oops, something went wrong. Capsul API responded with: $error_msg" exit 1 fi - echo "You new Hetzner Cloud VPS is up on $ip. Enjoy!" + echo "You new Capsul VPS is up, with ID $id. Enjoy!" } -abra_hetzner "$@" +abra_capsul "$@" diff --git a/makefile b/makefile index 45d14cf..143fe8a 100644 --- a/makefile +++ b/makefile @@ -6,7 +6,7 @@ shellcheck: --rm \ -v $$(pwd):/workdir \ koalaman/shellcheck-alpine \ - shellcheck /workdir/abra-hetzner + shellcheck /workdir/abra-capsul docopt: @if [ ! -d ".venv" ]; then \ @@ -14,4 +14,4 @@ docopt: .venv/bin/pip install -U pip setuptools wheel && \ .venv/bin/pip install docopt-sh; \ fi - .venv/bin/docopt.sh abra-hetzner + .venv/bin/docopt.sh abra-capsul