From 367c391a61091817cf34475f91a23ca286eec334 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Isma=C3=ABl=20Bouya?= Date: Sat, 18 Aug 2018 13:09:29 +0200 Subject: Add hetzner server scripts --- bin/install_script.sh | 10 ++++ python/get_initial_configuration_hetzner_server.py | 21 ++++++++ python/hetzner_helper.py | 59 ++++++++++++++++++++++ python/list_servers.py | 6 +++ python/reboot_hetzner_server.py | 18 +++++++ scripts/hetzner_server/arch_chroot_script.sh | 18 +++++++ .../arch_host_puppet_configuration_script.sh | 13 +++++ scripts/hetzner_server/arch_host_script.sh | 49 ++++++++++++++++++ 8 files changed, 194 insertions(+) create mode 100644 python/get_initial_configuration_hetzner_server.py create mode 100644 python/hetzner_helper.py create mode 100644 python/reboot_hetzner_server.py create mode 100755 scripts/hetzner_server/arch_chroot_script.sh create mode 100755 scripts/hetzner_server/arch_host_puppet_configuration_script.sh create mode 100755 scripts/hetzner_server/arch_host_script.sh diff --git a/bin/install_script.sh b/bin/install_script.sh index 36cc594..322a1ed 100755 --- a/bin/install_script.sh +++ b/bin/install_script.sh @@ -11,6 +11,7 @@ $(basename $0) [options] One of the following options is necessary: --instance-id id Id of the cloud instance --vps-id id Id of the vps + --hetzner-id id Id of the Hetzner server Optional arguments: --password password Password of the host (only useful in case of no reboot and vps) @@ -53,6 +54,15 @@ while [ -n "$1" ]; do T="ovh_vps_ssd" shift ;; + --hetzner-id) + host_id="$2" + if [ -z "$host_user" ]; then + host_user="root" + fi + [ -n "$T" ] && usage && exit 1 + T="hetzner_server" + shift + ;; --password) password="$2" shift diff --git a/python/get_initial_configuration_hetzner_server.py b/python/get_initial_configuration_hetzner_server.py new file mode 100644 index 0000000..71583ff --- /dev/null +++ b/python/get_initial_configuration_hetzner_server.py @@ -0,0 +1,21 @@ +import sys +import json +import hetzner_helper + +instance = sys.argv[-1] +instance = hetzner_helper.get("servers/{}".format(instance))[1]["server"] + +infos = {} +infos["ips"] = { + "v4": { + "ipAddress": instance["public_net"]["ipv4"]["ip"], + "gateway": "172.31.1.1", + }, + "v6": { + "ipAddress": instance["public_net"]["ipv6"]["ip"].split("/")[0], + "gateway": "fe80::1", + "mask": instance["public_net"]["ipv6"]["ip"].split("/")[1], + } + } + +print(json.dumps(infos)) diff --git a/python/hetzner_helper.py b/python/hetzner_helper.py new file mode 100644 index 0000000..496e14d --- /dev/null +++ b/python/hetzner_helper.py @@ -0,0 +1,59 @@ +import json +import requests +import os + +from configparser import RawConfigParser, NoSectionError, NoOptionError + +class AuthenticationException(Exception): + pass + +class RateLimitExceeded(Exception): + pass + +class InternalServer(Exception): + pass + +class HetznerConfig: + def __init__(self): + config = RawConfigParser() + config.read([os.path.expanduser('~/.hetzner.conf')]) + + self.api_key = config.get("default", "api_key") + +config = HetznerConfig() + +def call(endpoint, url_params=None, body=None, method="GET"): + api = "https://api.hetzner.cloud/v1/{}".format(endpoint) + headers = {"Authorization": "Bearer {}".format(config.api_key)} + data = json.dumps(body) if body is not None else None + + if method == "GET": + request = requests.get(api, headers=headers, params=url_params) + elif method == "POST" or (method == "GET" and body is not None): + request = requests.post(api, data=data, headers=headers, params=url_params) + elif method == "DELETE": + request = requests.delete(api, headers=headers) + elif method == "PUT": + request = requests.put(api, headers=headers, data=data) + + if request.status_code == 401 or request.status_code == 403: + raise AuthenticationException() + + if request.status_code == 429: + raise RateLimitExceeded() + + if request.status_code == 500: + raise InternalServer(request.text) + + if not request.text: + return request.status_code, "" + + js = request.json() + + return request.status_code, js + +def get(*args, **kwargs): + return call(*args, method="GET", **kwargs) + +def post(*args, **kwargs): + return call(*args, method="POST", **kwargs) diff --git a/python/list_servers.py b/python/list_servers.py index e7bd2af..6d22a56 100644 --- a/python/list_servers.py +++ b/python/list_servers.py @@ -21,3 +21,9 @@ print("OVH VPS SSD servers:") for vps in vps_list: print("\t{}".format(vps)) +import hetzner_helper + +print("Hetzner VPS servers:") +return_code, json = hetzner_helper.call("servers") +for server in json["servers"]: + print("\t{}: {}".format(server["name"], server["id"])) diff --git a/python/reboot_hetzner_server.py b/python/reboot_hetzner_server.py new file mode 100644 index 0000000..7452afe --- /dev/null +++ b/python/reboot_hetzner_server.py @@ -0,0 +1,18 @@ +import sys +import hetzner_helper + +instance = sys.argv[-1] +actions = [] +if "--rescue" in sys.argv: + actions.append("enable_rescue") +elif "--local" in sys.argv: + actions.append("disable_rescue") + +if "--hard" in sys.argv: + actions.append("reset") +else: + actions.append("reboot") + +for action in actions: + result = hetzner_helper.post("servers/{}/actions/{}".format(instance, action)) + print(result) diff --git a/scripts/hetzner_server/arch_chroot_script.sh b/scripts/hetzner_server/arch_chroot_script.sh new file mode 100755 index 0000000..afc78e2 --- /dev/null +++ b/scripts/hetzner_server/arch_chroot_script.sh @@ -0,0 +1,18 @@ +#!/bin/bash + +pacman-key --init +pacman-key --populate archlinux + +UUID=$(cat /device_uuid) +PART="/dev/disk/by-uuid/$UUID" +DEVICE=$(realpath "$PART") + +mkfs.ext4 -F -U "$UUID" "$DEVICE" +mount "$DEVICE" /mnt + +pacstrap -G /mnt base git puppet + +echo "$PART / auto defaults 0 1" > /mnt/etc/fstab + +umount /mnt + diff --git a/scripts/hetzner_server/arch_host_puppet_configuration_script.sh b/scripts/hetzner_server/arch_host_puppet_configuration_script.sh new file mode 100755 index 0000000..3ca2b51 --- /dev/null +++ b/scripts/hetzner_server/arch_host_puppet_configuration_script.sh @@ -0,0 +1,13 @@ +#!/bin/bash + +git_branch="$1" +environment="$2" + +DEVICE="/dev/sda1" +MOUNTPOINT="/mnt" + +cp /tmp/arch_puppet_configuration_script.sh "$MOUNTPOINT/root/" + +/tmp/root.x86_64/bin/arch-chroot "$MOUNTPOINT" /root/arch_puppet_configuration_script.sh "$git_branch" "$environment" + +umount "$MOUNTPOINT" diff --git a/scripts/hetzner_server/arch_host_script.sh b/scripts/hetzner_server/arch_host_script.sh new file mode 100755 index 0000000..23fbc32 --- /dev/null +++ b/scripts/hetzner_server/arch_host_script.sh @@ -0,0 +1,49 @@ +#!/bin/bash + +set -e + +git_branch="$1" +environment="$2" + +# Randomizer +haveged & +# /Randomizer + +# Prepare an arch chroot +cd /tmp + +LATEST=$(curl -L https://mirrors.kernel.org/archlinux/iso/latest/sha1sums.txt | grep "bootstrap" | head -n1) +SHA1=$(echo "$LATEST" | cut -d' ' -f1) +NAME=$(echo "$LATEST" | cut -d' ' -f3) + +curl -L -O "https://mirrors.kernel.org/archlinux/iso/latest/$NAME" + +tar -xzf "$NAME" + +echo 'Server = http://archlinux.mirrors.ovh.net/archlinux/$repo/os/$arch' > /tmp/root.x86_64/etc/pacman.d/mirrorlist +# /Prepare an arch chroot + +# Prepare device information (not available in chroot) +DEVICE="/dev/sda1" +MOUNTPOINT="/mnt" + +UUID=$(lsblk -rno UUID "$DEVICE") + +echo "$UUID" > /tmp/root.x86_64/device_uuid +# /Prepare device information + +# Install very basic system via chroot (base git puppet) +cp /tmp/arch_chroot_script.sh /tmp/root.x86_64/ + +/tmp/root.x86_64/bin/arch-chroot /tmp/root.x86_64/ /arch_chroot_script.sh +# /Install very basic system via chroot + +# Mount and install rest of system (via puppet) +mount "$DEVICE" "$MOUNTPOINT" + +cp /tmp/arch_install_script.sh "$MOUNTPOINT/root/" +cp /tmp/puppet_variables.json "$MOUNTPOINT/root/" + +/tmp/root.x86_64/bin/arch-chroot "$MOUNTPOINT" /root/arch_install_script.sh "$git_branch" "$environment" +# /Mount and install rest of system + -- cgit v1.2.3