summarylogtreecommitdiffstats
path: root/digitalocean-synchronize
diff options
context:
space:
mode:
Diffstat (limited to 'digitalocean-synchronize')
-rw-r--r--digitalocean-synchronize162
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