diff options
21 files changed, 437 insertions, 15 deletions
diff --git a/chaos-at-home/cloud-install.yml b/chaos-at-home/cloud-install.yml new file mode 100644 index 00000000..24d8d9c2 --- /dev/null +++ b/chaos-at-home/cloud-install.yml @@ -0,0 +1,6 @@ +--- +- name: basic installation + hosts: "{{ hostname }}" + gather_facts: no + roles: + - role: cloud-install diff --git a/chaos-at-home/group_vars/all.yml b/chaos-at-home/group_vars/all.yml index 45690ced..e6e942c8 100644 --- a/chaos-at-home/group_vars/all.yml +++ b/chaos-at-home/group_vars/all.yml @@ -1,10 +1,17 @@ $ANSIBLE_VAULT;1.2;AES256;chaos-at-home -35386561313935656364616336626666346333343132326536313932373038336236653565653563 -3330303666363363636432346131376239376364666565340a336162666433336261363530386234 -34616535343962346530623533353764663336326132663633653065326436643736313537326466 -6261613462626334390a346638303832326534393231376262613033633136336238356439666131 -63663166623838346565393663363839373730326564333335396238613232313466313365346565 -66366262373438326138366466653035386637343763313637643536643265363736393435383132 -35376661393961383962353165626637313565323830336138663662336362333633363936666236 -62306538633362616466663938323033656634383563333534653936626566643932633032646538 -34623932653531383966326438343361393536373965346464616239303961656432 +62343537316165343061336664393031333732343935313430313338353133376264353632323332 +3232383539366231336137613731613734376666393339330a303565396239363265393262303966 +66386137643837316162653038623737326233356235356563363963643532653561313632663733 +3837316362393461380a386663333837323335666161353839623262633433643365653939373033 +63613532373333333266333134303961313362623862386630656463636634656633393137363837 +37623239343339373632663164393936363932333830346138323761386236623834383035393930 +65373638616161643664393865363239636664613161626364333631636464356362626435313333 +35313634323664653039396338653663323233633366363636376632663363626163613364373935 +35653733326465633831363039353362346630326534386566323430373335323233376236636437 +65333434316339633666376162386238393238336534656539663734656535666338353465376131 +33666438636137303265383532613433363135373561353734376636623938393031623461653630 +39633462663738346533663639303231363437366135643664336466613365303033633731343735 +65656534363431633733373932336664356632376234633163363334316539323261326463663566 +64643533336166633530323137616633663436393063316664356466306233343935353862326663 +39326662303462663533353939336239393362363961636336623632343839643262306430386439 +65623162343331616530 diff --git a/chaos-at-home/host_vars/mimas2.yml b/chaos-at-home/host_vars/mimas2.yml new file mode 100644 index 00000000..d0a9a782 --- /dev/null +++ b/chaos-at-home/host_vars/mimas2.yml @@ -0,0 +1,10 @@ +$ANSIBLE_VAULT;1.2;AES256;chaos-at-home +62306466306134666137366136316236626665313339613732376234346561383936363637636230 +3433383630616330653831643264623361643562383831650a333739333231326264383661613339 +64356463306263656263356438346132613438326635643936333039353836383538343331346637 +3633343931646331340a333738313261386130343266373735373461396466653236653130666536 +32303236346637303563623935373030376536666661363465623839613336356635623861376638 +35636563646266633863336263316633643662653961363632393866633137353236636234623463 +37313537613938363631333338646565376132626461666666653265343831383565663163343236 +30383165333961643366373334643432356435646432333338616362353139646639313034656433 +3261 diff --git a/chaos-at-home/mimas2.yml b/chaos-at-home/mimas2.yml new file mode 100644 index 00000000..bfbe8e57 --- /dev/null +++ b/chaos-at-home/mimas2.yml @@ -0,0 +1,8 @@ +--- +- name: Basic Setup + hosts: mimas2 + roles: + - role: base + - role: sshd + - role: zsh + - role: admin-user diff --git a/cloud-install.sh b/cloud-install.sh new file mode 120000 index 00000000..61e71e22 --- /dev/null +++ b/cloud-install.sh @@ -0,0 +1 @@ +install.sh
\ No newline at end of file diff --git a/dan/cloud-install.yml b/dan/cloud-install.yml new file mode 100644 index 00000000..24d8d9c2 --- /dev/null +++ b/dan/cloud-install.yml @@ -0,0 +1,6 @@ +--- +- name: basic installation + hosts: "{{ hostname }}" + gather_facts: no + roles: + - role: cloud-install diff --git a/dan/host_vars/sk-cloudia.yml b/dan/host_vars/sk-cloudia.yml new file mode 100644 index 00000000..53629208 --- /dev/null +++ b/dan/host_vars/sk-cloudia.yml @@ -0,0 +1,10 @@ +$ANSIBLE_VAULT;1.2;AES256;dan +64313638393461613535643731303830343539313333643462633232303936346665636536313630 +6261376532663565343434376633613930613331626530380a633235326261306166356166636363 +32636530656665303633373331353565626534646466666336636561376638323834646262633636 +3633656465366263640a653837613439363438653366643763323933366361323938326439373138 +36323638633530323630323133386332303965353866353831383961333363613933373132353663 +35393938326630356261336136633763316436366435313965306166656138393032306434363861 +62383632636239653233626535316361376637646564333861323936343833383030303139346135 +39303735623038633661626238616638373061643762336339366434303162633731646432626364 +3432 diff --git a/dan/sk-cloudia.yml b/dan/sk-cloudia.yml new file mode 100644 index 00000000..6d22afed --- /dev/null +++ b/dan/sk-cloudia.yml @@ -0,0 +1,7 @@ +--- +- name: Basic Setup + hosts: sk-cloudia + roles: + - role: base + - role: sshd + - role: zsh diff --git a/inventory/group_vars/chaos-at-home/main.yml b/inventory/group_vars/chaos-at-home/main.yml index 8b9ff936..1d44eb7d 100644 --- a/inventory/group_vars/chaos-at-home/main.yml +++ b/inventory/group_vars/chaos-at-home/main.yml @@ -1,7 +1,7 @@ --- zsh_banner: chaos-at-home -admin_user_host: +admin_user_group: - "{{ equinox_user }}" -ssh_allowusers_host: "{{ admin_user_host | map(attribute='name') | list }}" +ssh_allowusers_host: "{{ admin_user_group | map(attribute='name') | list }}" diff --git a/inventory/group_vars/hcloud/main.yml b/inventory/group_vars/hcloud/main.yml new file mode 100644 index 00000000..83219510 --- /dev/null +++ b/inventory/group_vars/hcloud/main.yml @@ -0,0 +1,4 @@ +--- +cloud_provider: hcloud + +hcloud_api_token: "{{ vault_hcloud_api_token }}" diff --git a/inventory/group_vars/hroot/main.yml b/inventory/group_vars/hroot/main.yml new file mode 100644 index 00000000..828a3720 --- /dev/null +++ b/inventory/group_vars/hroot/main.yml @@ -0,0 +1,4 @@ +--- +cloud_provider: hroot + +hroot_robot_account: "{{ vault_hroot_robot_account }}" diff --git a/inventory/hosts.ini b/inventory/hosts.ini index f0458932..df885051 100644 --- a/inventory/hosts.ini +++ b/inventory/hosts.ini @@ -18,6 +18,7 @@ ansible_host={{ host_name }}.{{ host_domain }} atlas keyserver pan ansible_host=ch-pan ansible_port=222 +mimas2 ansible_host=ch-mimas2 ansible_port=222 [chaos-at-home:children] mz-chaos-at-home @@ -79,10 +80,12 @@ emc-00 [skillz:vars] host_domain=skillz.biz env_group=dan +ansible_port=222 [skillz] -sk2013 host_name=2013 -sk2016 host_name=2016 +sk2013 host_name=2013 ansible_port=22000 +sk2016 host_name=2016 ansible_port=22000 +sk-cloudia host_name=cloudia [ele-ap] @@ -131,9 +134,16 @@ atlas sk2013 sk2016 -[hetzner] +[hroot] sk2013 sk2016 +sk-cloudia + +[hcloud] +emc-00 +mimas2 + +[hetzner] emc-stats emc-master k8s-test0 @@ -141,7 +151,8 @@ k8s-test2 [hetzner:children] emc-xx - +hroot +hcloud [scaleway-kernel] diff --git a/roles/cloud-install/defaults/main.yml b/roles/cloud-install/defaults/main.yml new file mode 100644 index 00000000..33e5d165 --- /dev/null +++ b/roles/cloud-install/defaults/main.yml @@ -0,0 +1,2 @@ +--- +hetzner_disk_config: "{% if cloud_provider == 'hroot' %}nvme_raid{% elif cloud_provider == 'hcloud' %}hcloud{% endif %}" diff --git a/roles/cloud-install/filter_plugins/hroot.py b/roles/cloud-install/filter_plugins/hroot.py new file mode 100644 index 00000000..d2abff1b --- /dev/null +++ b/roles/cloud-install/filter_plugins/hroot.py @@ -0,0 +1,33 @@ +from __future__ import (absolute_import, division, print_function) +__metaclass__ = type + + +from ansible import errors + + +def extract_ssh_key_fingerprints(data): + try: + return [k['key']['fingerprint'] for k in data] + except Exception as e: + raise errors.AnsibleFilterError("hroot_ssh_key_fingerprints(): %s" % str(e)) + + +def extract_serverip(data, server_name): + try: + ips = [s['server']['server_ip'] for s in data if s['server']['server_name'] == server_name] + if len(ips): + return ips[0] + raise errors.AnsibleFilterError("hroot_extract_serverip(): server %s not found" % server_name) + except Exception as e: + raise errors.AnsibleFilterError("hroot_extract_serverip(): %s" % str(e)) + + +class FilterModule(object): + + ''' Ansible math jinja2 filters ''' + + def filters(self): + return { + 'hroot_extract_ssh_key_fingerprints': extract_ssh_key_fingerprints, + 'hroot_extract_serverip': extract_serverip, + } diff --git a/roles/cloud-install/tasks/hetzner_installimage.yml b/roles/cloud-install/tasks/hetzner_installimage.yml new file mode 100644 index 00000000..f54a785b --- /dev/null +++ b/roles/cloud-install/tasks/hetzner_installimage.yml @@ -0,0 +1,38 @@ +--- +- name: determine latest image name + shell: | + set -o pipefail + shopt -s nocaseglob + ls /root/.oldroot/nfs/images/{{ install_distro }}-*-{{ install_codename }}-64-minimal.tar.gz | sort -r | head -n 1 + args: + executable: /bin/bash + check_mode: no + changed_when: false + register: latest_image + +- name: generate installimage config + template: + src: hetzner_installimage.conf.j2 + dest: /root/installimage.conf + +- name: generate postinst script + template: + src: hetzner_postinst.sh.j2 + dest: /root/postinst.sh + mode: 0755 + +- name: run installimage + command: /root/.oldroot/nfs/install/installimage -a -c installimage.conf -x postinst.sh + register: hetzner_installimage_cmd + changed_when: true + args: + chdir: /root + +- name: "print installimage output" + debug: + msg: "{{ hetzner_installimage_cmd.stdout_lines + hetzner_installimage_cmd.stderr_lines }}" + +- name: "check if installimage succeeded" + fail: + msg: "failed to run installimage" + when: "hetzner_installimage_cmd.rc != 0 or 'postinst.sh finished successfully' not in hetzner_installimage_cmd.stdout_lines" diff --git a/roles/cloud-install/tasks/install_hcloud.yml b/roles/cloud-install/tasks/install_hcloud.yml new file mode 100644 index 00000000..a4c61c0f --- /dev/null +++ b/roles/cloud-install/tasks/install_hcloud.yml @@ -0,0 +1,83 @@ +--- +- name: retrieve ssh key ids + uri: + url: "https://api.hetzner.cloud/v1/ssh_keys" + method: GET + headers: + Authorization: "Bearer {{ hcloud_api_token }}" + status_code: 200 + register: sshkeys + delegate_to: localhost + +- name: retrieve server id and check if rescue mode is already active + uri: + url: "https://api.hetzner.cloud/v1/servers?name={{ inventory_hostname }}" + method: GET + headers: + Authorization: "Bearer {{ hcloud_api_token }}" + status_code: 200 + register: serverstatus + delegate_to: localhost + +- name: do not continue in check mode + fail: + msg: "can not bootstrap new servers in check mode" + when: ansible_check_mode + check_mode: no + +### TODO: for now we add all ssh keys that are installed for this project - this might not be a good idea! +- name: activate rescue mode + when: not serverstatus.json.servers[0].rescue_enabled + uri: + url: "https://api.hetzner.cloud/v1/servers/{{ serverstatus.json.servers[0].id }}/actions/enable_rescue" + method: POST + body: "{{ {'type': 'linux64', 'ssh_keys': (sshkeys.json.ssh_keys | map(attribute='id') | list) } | to_nice_json }}" + headers: + Authorization: "Bearer {{ hcloud_api_token }}" + Content-Type: "application/json" + status_code: 201 + delegate_to: localhost + +- name: do a hardware reset + uri: + url: "https://api.hetzner.cloud/v1/servers/{{ serverstatus.json.servers[0].id }}/actions/reset" + method: POST + headers: + Authorization: "Bearer {{ hcloud_api_token }}" + status_code: 201 + delegate_to: localhost + +### TODO: would be nice to get the SSH host key from robot +- name: completely ignore ssh host keys for now + set_fact: + old_ansible_ssh_extra_args: "{{ ansible_ssh_extra_args | default('') }}" + ansible_ssh_extra_args: "{{ ansible_ssh_extra_args | default('') }} -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" + +- name: wait for rescue system to start up + wait_for_connection: + delay: 30 + timeout: 120 + +- import_tasks: hetzner_installimage.yml + +- name: reboot + shell: sleep 2 && shutdown -r now "triggered by ansible after running installimage" + async: 1 + poll: 0 + ignore_errors: True + changed_when: True + +### TODO: SSH host key handling needs to be improved +- name: automatically accept new ssh host key + set_fact: + ansible_ssh_extra_args: "{{ old_ansible_ssh_extra_args }} -o StrictHostKeyChecking=no" + +- name: wait for host to start up + wait_for_connection: + delay: 15 + timeout: 120 + +### TODO: SSH host key handling needs to be improved +- name: re-enable ssh host key checking + set_fact: + ansible_ssh_extra_args: "{{ old_ansible_ssh_extra_args }}" diff --git a/roles/cloud-install/tasks/install_hroot.yml b/roles/cloud-install/tasks/install_hroot.yml new file mode 100644 index 00000000..6d4d6017 --- /dev/null +++ b/roles/cloud-install/tasks/install_hroot.yml @@ -0,0 +1,124 @@ +--- +- name: retrieve ssh key fingerprints + uri: + url: "https://robot-ws.your-server.de/key" + method: GET + user: "{{ hroot_robot_account.username }}" + password: "{{ hroot_robot_account.password }}" + force_basic_auth: yes + status_code: 200 + register: sshkeys + delegate_to: localhost + check_mode: no + +- name: do not continue in check mode + fail: + msg: "can not bootstrap new servers in check mode" + when: ansible_check_mode + check_mode: no + +- block: + - name: retrieve server list from robot + uri: + url: "https://robot-ws.your-server.de/server" + method: GET + user: "{{ hroot_robot_account.username }}" + password: "{{ hroot_robot_account.password }}" + force_basic_auth: yes + status_code: 200 + register: servers + delegate_to: localhost + check_mode: no + + - name: extract server IP address from robot result + set_fact: + hetzner_main_ip: "{{ servers.json | hroot_extract_serverip(host_name) }}" + + when: hetzner_main_ip is not defined + +- name: display warning message + pause: + prompt: | + *** Danger **** + will be bootstraping host {{ inventory_hostname }} with main IP {{ hetzner_main_ip }} ... + ALL DATA WILL BE LOST!!! press CTRL-C then A to abort. + seconds: 15 + +- name: check if rescue mode is already active + uri: + url: "https://robot-ws.your-server.de/boot/{{ hetzner_main_ip }}/rescue" + method: GET + user: "{{ hroot_robot_account.username }}" + password: "{{ hroot_robot_account.password }}" + force_basic_auth: yes + status_code: 200 + register: rescuestatus + delegate_to: localhost + check_mode: no + +### TODO: for now we add all ssh keys that are installed in the robot - this might not be a good idea! +- name: activate rescue mode + when: not rescuestatus.json.rescue.active + uri: + url: "https://robot-ws.your-server.de/boot/{{ hetzner_main_ip }}/rescue" + method: POST + user: "{{ hroot_robot_account.username }}" + password: "{{ hroot_robot_account.password }}" + force_basic_auth: yes + body: "os=linux&arch=64&authorized_key[]={{ sshkeys.json | hroot_extract_ssh_key_fingerprints | join('&authorized_key[]=') }}" + status_code: 200 + headers: + Content-Type: "application/x-www-form-urlencoded" + delegate_to: localhost + +- name: wait for the rescue mode to become active + pause: + seconds: 5 + +- name: do a hardware reset + uri: + url: "https://robot-ws.your-server.de/reset/{{ hetzner_main_ip }}" + method: POST + user: "{{ hroot_robot_account.username }}" + password: "{{ hroot_robot_account.password }}" + force_basic_auth: yes + body: "type=hw" + status_code: 200 + headers: + Content-Type: "application/x-www-form-urlencoded" + delegate_to: localhost + +### TODO: would be nice to get the SSH host key from robot +- name: completely ignore ssh host keys for now + set_fact: + old_ansible_ssh_extra_args: "{{ ansible_ssh_extra_args | default('') }}" + ansible_ssh_extra_args: "{{ ansible_ssh_extra_args | default('') }} -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no" + +- name: wait for rescue system to start up + wait_for_connection: + delay: 30 + timeout: 120 + +- import_tasks: hetzner_installimage.yml + +- name: reboot + shell: sleep 2 && shutdown -r now "triggered by ansible after running installimage" + async: 1 + poll: 0 + ignore_errors: True + changed_when: True + +### TODO: SSH host key handling needs to be improved +- name: automatically accept new ssh host key + set_fact: + ansible_ssh_extra_args: "{{ old_ansible_ssh_extra_args }} -o StrictHostKeyChecking=no" + +- name: wait for host to start up + wait_for_connection: + delay: 15 + timeout: 120 + +### TODO: SSH host key handling needs to be improved +- name: re-enable ssh host key checking + set_fact: + ansible_ssh_extra_args: "{{ old_ansible_ssh_extra_args }}" diff --git a/roles/cloud-install/tasks/main.yml b/roles/cloud-install/tasks/main.yml new file mode 100644 index 00000000..ef6d42ae --- /dev/null +++ b/roles/cloud-install/tasks/main.yml @@ -0,0 +1,16 @@ +--- +- include_tasks: "{{ item }}" + static: no + with_first_found: + - files: + - "install_{{ cloud_provider }}.yml" + +- name: force facts cache to get updated + setup: + +- include_tasks: "{{ item }}" + static: no + with_first_found: + - files: + - "post_{{ cloud_provider }}.yml" + skip: True diff --git a/roles/cloud-install/tasks/post_hcloud.yml b/roles/cloud-install/tasks/post_hcloud.yml new file mode 100644 index 00000000..96108c58 --- /dev/null +++ b/roles/cloud-install/tasks/post_hcloud.yml @@ -0,0 +1,6 @@ +--- +- name: install additional packages + apt: + name: + - qemu-guest-agent + state: present diff --git a/roles/cloud-install/templates/hetzner_installimage.conf.j2 b/roles/cloud-install/templates/hetzner_installimage.conf.j2 new file mode 100644 index 00000000..4c834499 --- /dev/null +++ b/roles/cloud-install/templates/hetzner_installimage.conf.j2 @@ -0,0 +1,21 @@ +HOSTNAME {{ host_name }} +{% if hetzner_disk_config == "nvme_raid" %} +DRIVE1 /dev/nvme0n1 +DRIVE2 /dev/nvme1n1 +SWRAID 1 +SWRAIDLEVEL 1 +{% elif hetzner_disk_config == "sata_raid" %} +DRIVE1 /dev/sda +DRIVE2 /dev/sdb +SWRAID 1 +SWRAIDLEVEL 1 +{% elif hetzner_disk_config == "hcloud" %} +DRIVE1 /dev/sda +{% endif %} +BOOTLOADER grub +PART /boot ext4 512M +PART lvm {{ host_name }} all +LV {{ host_name }} root / ext4 2560M +LV {{ host_name }} var /var ext4 1280M +LV {{ host_name }} var+log /var/log ext4 768M +IMAGE {{ latest_image.stdout }} diff --git a/roles/cloud-install/templates/hetzner_postinst.sh.j2 b/roles/cloud-install/templates/hetzner_postinst.sh.j2 new file mode 100644 index 00000000..3aa33c76 --- /dev/null +++ b/roles/cloud-install/templates/hetzner_postinst.sh.j2 @@ -0,0 +1,25 @@ +#!/bin/bash +set -euf -o pipefail + +apt-get update +apt-get full-upgrade -y +apt-get install -y --no-install-recommends openssh-server python + +passwd -d root && passwd -l root +{% if install_distro == "debian" %} +sed -e 's/^allow-hotplug/auto/' -i /etc/network/interfaces +{% endif %} +sed -r 's#(\s+/var/log\s+ext4\s+)defaults#\1noatime,nodev,noexec#g' -i /etc/fstab + +mkdir -p -m 0700 /target/root/.ssh +cat <<EOK > /root/.ssh/authorized_keys +{{ ssh_keys_root | join('\n') }} +EOK +{% if hostvars[hostname].ansible_port is defined %} +sed -e 's/^\(\s*#*\s*Port.*\)/Port {{ hostvars[hostname].ansible_port }}/' -i /etc/ssh/sshd_config +{% endif %} + +{# this is actually only needed on ubuntu bionic and beyond but should not hurt on other installations either #} +swapoff -a; sed -e '/^\/swapfile/d' -i /etc/fstab; rm -f /swapfile + +echo "postinst.sh finished successfully" |