diff options
Diffstat (limited to 'digitalocean-synchronize')
-rw-r--r-- | digitalocean-synchronize | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/digitalocean-synchronize b/digitalocean-synchronize new file mode 100644 index 000000000000..35593fa1900f --- /dev/null +++ b/digitalocean-synchronize @@ -0,0 +1,162 @@ +#!/bin/bash + +meta_base=http://169.254.169.254/metadata/v1/ + +set -eu +set -o pipefail +shopt -s nullglob +shopt -s dotglob +umask 022 + +log() { + logger -t digitalocean-synchronize "$@" || \ + echo "[$(date)]" "$@" >&2 +} + +netmask_to_prefix() { + local pfx=0 cmp msk + for cmp in ${1//./ } 0; do + for msk in 128 64 32 16 8 4 2 1; do + if (( cmp & msk )); then + (( pfx += 1 )) + else + echo ${pfx} + return + fi + done + done +} + +update_shadow_if_changed() { + local etcdir=$1/etc + mkdir -p ${etcdir} || return 0 + if [ -e ${etcdir}/shadow ]; then + # change password if file was touched + local encrypted_password=$(awk -F: '$1 == "root" { print $2 }' ${etcdir}/shadow) + if [ "${encrypted_password}" != "z" ]; then + log "Snapshot restore detected." + usermod -p "${encrypted_password}" root + if [ ${#encrypted_password} -gt 1 ]; then + chage -d 0 root + fi + log "Password has been reset." + rm -f /etc/ssh/ssh_host_key /etc/ssh/ssh_host_*_key + log "SSH host keys will be regenerated." + fi + fi + cat > ${etcdir}/shadow <<-EOF + root:z:1:::::: + nobody:z:1:::::: + EOF + chmod 0600 ${etcdir}/shadow +} + +process_interface() { + local url=$1 + local attrs=$2 + local mac=$(curl -Ssf ${url}mac) + local type=$(curl -Ssf ${url}type) + local interface= + local cand path + for cand in $(ls /sys/class/net); do + path=/sys/class/net/${cand}/address + if [ -e ${path} ] && [ "$(<${path})" = "${mac}" ]; then + interface=${cand} + break + fi + done + [ -n "${interface}" ] || return 0 + mkdir -p /run/systemd/network + { + cat <<-EOF + # Generated by digitalocean-synchronize + [Match] + Name=${interface} + [Network] + EOF + if [[ " ${attrs} " =~ " ipv4/ " ]]; then + local address=$(curl -sf ${url}ipv4/address) + local prefix=$(netmask_to_prefix $(curl -sf ${url}ipv4/netmask)) + echo "Address=${address}/${prefix}" + if [ "${type}" != "private" ]; then + echo "Gateway=$(curl -sf ${url}ipv4/gateway)" + fi + log "Added IPv4 address ${address}/${prefix} on ${interface}." + fi + if [[ " ${attrs} " =~ " ipv6/ " ]]; then + local address=$(curl -sf ${url}ipv6/address) + local prefix=$(curl -sf ${url}ipv6/cidr) + echo "Address=${address}/${prefix}" + if [ "${type}" != "private" ]; then + echo "Gateway=$(curl -sf ${url}ipv6/gateway)" + fi + log "Added IPv6 address ${address}/${prefix} on ${interface}." + fi + local network_tail=/etc/systemd/network/template/dosync-${interface}.network.tail + if [[ -r "${network_tail}" ]]; then + cat ${network_tail} + log "Appended user specified config for ${interface}." + fi + } > /run/systemd/network/dosync-${interface}.network +} + +traverse_interfaces() { + local url=$1 + set -- $(curl -Ssf ${url}) + if [[ " $* " =~ " mac " ]]; then + process_interface ${url} "$*" + else + local dir + for dir in $*; do + # only want dirs with slash suffix + [ "${dir}" = "${dir%/}" ] && continue + traverse_interfaces ${url}${dir} + done + fi +} + +setup_from_metadata_service() { + local sshkeys + if sshkeys=$(curl -Ssf ${meta_base}public-keys) && test -n "${sshkeys}"; then + [ -d /root/.ssh ] || mkdir -m 0700 /root/.ssh + [ -e /root/.ssh/authorized_keys ] || touch /root/.ssh/authorized_keys + if ! grep -q "${sshkeys}" /root/.ssh/authorized_keys; then + printf '\n%s\n' "${sshkeys}" >> /root/.ssh/authorized_keys + log "Added SSH public keys from metadata service." + fi + fi + local hostname + if ! test -e /etc/hostname && hostname=$(curl -Ssf ${meta_base}hostname); then + echo "${hostname}" > /etc/hostname + hostname "${hostname}" + log "Hostname set to ${hostname} from metadata service." + fi + traverse_interfaces ${meta_base}interfaces/ +} + +digitalocean_synchronize() { + if test -e /dev/disk/by-label/DOROOT && mkdir -p /mnt/doroot; then + mount /dev/disk/by-label/DOROOT /mnt/doroot + update_shadow_if_changed /mnt/doroot + umount /mnt/doroot + else + log "Unable to check DOROOT for snapshot check!" + fi + + ip link set dev eth0 up + ip addr add dev eth0 169.254.169.252/30 2>/dev/null || true + local retry + for retry in {1..20}; do + log "Attempting to connect to metadata service ..." + if curl -Ssf -m 1 ${meta_base} >/dev/null; then + setup_from_metadata_service + break + else + log "Unable to connect to metadata service!" + sleep 1 + fi + done + ip addr del dev eth0 169.254.169.252/30 2>/dev/null || true +} + +digitalocean_synchronize |