diff --git a/README.md b/README.md index d0aa194..baa938b 100644 --- a/README.md +++ b/README.md @@ -11,8 +11,8 @@ You can read the Hetzner Cloud API docs (e.g. [locations endpoint](https://docs. Then you can make requests and see what comes out. These values can then fed into this plugin as configurables. ```bash -$ export API_TOKEN= -$ curl -H "Authorization: Bearer $API_TOKEN" 'https://api.hetzner.cloud/v1/locations' | jq '.locations | .[] | .name'` +$ export HETZNER_API_TOKEN= +$ curl -H "Authorization: Bearer $HETZNER_API_TOKEN" 'https://api.hetzner.cloud/v1/locations' | jq '.locations | .[] | .name'` "fsn1" "nbg1" "hel1" diff --git a/abra-hetzner b/abra-hetzner index c19a164..98f3fa3 100755 --- a/abra-hetzner +++ b/abra-hetzner @@ -4,7 +4,7 @@ DOC=" Hetzner provider plugin for abra Usage: - abra-hetzner [--type=] [--image=] [--ssh-keys=] [--location=] [--datacenter=] + abra-hetzner [--ssh-keys=] [--location=] Reads your Hetzner API token from the \$HETZNER_API_TOKEN environment variable or prompts for it. @@ -88,34 +88,29 @@ 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:270} -usage=${DOC:35:138}; digest=9d76c; shorts=('' '' '' '' '') -longs=(--type --image --ssh-keys --location --datacenter); argcounts=(1 1 1 1 1) -node_0(){ value __type 0; }; node_1(){ value __image 1; }; node_2(){ -value __ssh_keys 2; }; node_3(){ value __location 3; }; node_4(){ -value __datacenter 4; }; node_5(){ value _name_ a; }; node_6(){ optional 0; } -node_7(){ optional 1; }; node_8(){ optional 2; }; node_9(){ optional 3; } -node_10(){ optional 4; }; node_11(){ required 5 6 7 8 9 10; }; node_12(){ -required 11; }; cat <<<' docopt_exit() { [[ -n $1 ]] && printf "%s\n" "$1" >&2 -printf "%s\n" "${DOC:35:138}" >&2; exit 1; }'; unset var___type var___image \ -var___ssh_keys var___location var___datacenter var__name_; parse 12 "$@" -local prefix=${DOCOPT_PREFIX:-''}; unset "${prefix}__type" "${prefix}__image" \ -"${prefix}__ssh_keys" "${prefix}__location" "${prefix}__datacenter" \ -"${prefix}_name_"; eval "${prefix}"'__type=${var___type:-}' -eval "${prefix}"'__image=${var___image:-}' +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:-}' -eval "${prefix}"'__datacenter=${var___datacenter:-}' -eval "${prefix}"'_name_=${var__name_:-}'; local docopt_i=1 +eval "${prefix}"'_name_=${var__name_:-}' +eval "${prefix}"'_type_=${var__type_:-}' +eval "${prefix}"'_image_=${var__image_:-}'; local docopt_i=1 [[ $BASH_VERSION =~ ^4.3 ]] && docopt_i=2; for ((;docopt_i>0;docopt_i--)); do -declare -p "${prefix}__type" "${prefix}__image" "${prefix}__ssh_keys" \ -"${prefix}__location" "${prefix}__datacenter" "${prefix}_name_"; done; } +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` abra_hetzner() { - # declare abra_hetzner__type_ abra_hetzner__image_ - # abra_hetzner__ssh_keys abra_hetzner__location \ - # abra_hetzner__datacenter + declare abra_hetzner__name_ abra_hetzner__type_ abra_hetzner__image_ \ + abra_hetzner___ssh_keys abra_hetzner___location DOCOPT_PREFIX=abra_hetzner_ @@ -125,19 +120,41 @@ abra_hetzner() { error "curl program is not installed" fi - if [[ -z "$ABRA_HETZNER_API_TOKEN" ]]; then + if [[ -z "$HETZNER_API_TOKEN" ]]; then read -rp "Hetzner API token: " HETZNER_API_TOKEN fi - # TYPE="$abra_hetzner__type_" - # IMAGE="$abra_hetzner__image_" + NAME="$abra_hetzner__name_" + TYPE="$abra_hetzner__type_" + IMAGE="$abra_hetzner__image_" - curl \ + SSH_KEYS="$abra_hetzner___ssh_keys" + LOCATION="${abra_hetzner___location:-hel1}" + + # shellcheck disable=SC2001 + ssh_keys=$(echo "$SSH_KEYS" | sed 's/[^[:space:],]\+/"&"/g') + + response=$(curl --silent \ -X POST \ -H "Authorization: Bearer $HETZNER_API_TOKEN" \ -H "Content-Type: application/json" \ - -d "{}" \ - 'https://api.hetzner.cloud/v1/servers' + -d "{\"name\":\"$NAME\", \ + \"server_type\": \"$TYPE\", \ + \"image\": \"$IMAGE\", \ + \"ssh_keys\": [$ssh_keys], \ + \"location\": \"$LOCATION\" \ + }" \ + 'https://api.hetzner.cloud/v1/servers') + + ip=$(echo "$response" | jq -r ".server .public_net .ipv4 .ip") + + if [[ ! -z "$ip" ]]; then + error_msg=$(echo "$response" | jq -r ".error .message") + echo "Oops, something went wrong. Hetzner Cloud API responded with: $error_msg" + exit 1 + fi + + echo "You new Hetzner Cloud VPS is up on $ip. Enjoy!" } abra_hetzner "$@"