diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..5b95360 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,18 @@ +# https://editorconfig.org +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 4 +indent_style = tab +insert_final_newline = true +trim_trailing_whitespace = true + +[Makefile] +indent_size = 8 +indent_style = tab + +[*.{md,yml,yaml}] +indent_style = space +indent_size = 2 diff --git a/bin/imds b/bin/imds index e1acd09..35ba0d6 100755 --- a/bin/imds +++ b/bin/imds @@ -1,5 +1,5 @@ #!/bin/sh -# vim:set ts=4 et ft=sh: +# vim:set ft=sh: # Tiny Cloud - Instance MetaData Service client @@ -9,43 +9,43 @@ . "$LIBDIR/tiny-cloud/common" if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then - cat < | } ... - -h : help - -e / +e : ignore / catch errors - +n / +s / +t : insert newline / space / tab - :- - hostname : instance hostname - local-hostname : instance local hostname - ssh-keys : instance SSH keys - userdata : instance user data - nics : instance NICs - nic:[, ...] : specific NIC interface - : network interface (i.e. eth1) - :- { -e | +e | +n | +s | +t | @ | } - :- - mac : mac address - ipv4 : ipv4 address(es) - ipv6 : ipv6 address(es) - ipv4-net : subnet ipv4 network(s) - ipv6-net : subnet ipv6 network(s) - ipv4-prefix : delegated ipv4 CIDR(s) - ipv6-prefix : delegated ipv6 CIDR(s) -EOT - exit 0 + cat <<-EOT + Usage: imds [-h] { -e | +e | +n | +s | +t | @ | } ... + -h : help + -e / +e : ignore / catch errors + +n / +s / +t : insert newline / space / tab + :- + hostname : instance hostname + local-hostname : instance local hostname + ssh-keys : instance SSH keys + userdata : instance user data + nics : instance NICs + nic:[, ...] : specific NIC interface + : network interface (i.e. eth1) + :- { -e | +e | +n | +s | +t | @ | } + :- + mac : mac address + ipv4 : ipv4 address(es) + ipv6 : ipv6 address(es) + ipv4-net : subnet ipv4 network(s) + ipv6-net : subnet ipv6 network(s) + ipv4-prefix : delegated ipv4 CIDR(s) + ipv6-prefix : delegated ipv6 CIDR(s) + EOT + exit 0 fi ### cloud-specific variables/functions unset \ - IMDS_HEADER \ - IMDS_URI \ - IMDS_QUERY + IMDS_HEADER \ + IMDS_URI \ + IMDS_QUERY unset -f \ - _imds_token \ - _imds_header \ - _imds_nic_index \ - 2>/dev/null || true + _imds_token \ + _imds_header \ + _imds_nic_index \ + 2>/dev/null || true ### default variables/functions @@ -67,19 +67,19 @@ IMDS_IPV4_PREFIX="ipv4-prefix" IMDS_IPV6_PREFIX="ipv6-prefix" _imds() { - wget --quiet --timeout 1 --output-document - \ - --header "$(_imds_header)" \ - "http://$IMDS_ENDPOINT/$IMDS_URI/$1$IMDS_QUERY" + wget --quiet --timeout 1 --output-document - \ + --header "$(_imds_header)" \ + "http://$IMDS_ENDPOINT/$IMDS_URI/$1$IMDS_QUERY" } _imds_userdata() { _imds "$IMDS_USERDATA"; } _imds_ssh_keys() { - local key - for key in $(_imds "$IMDS_SSH_KEYS"); do - _imds "$IMDS_SSH_KEYS/${key%=*}/openssh-key" - echo - done | sort -u + local key + for key in $(_imds "$IMDS_SSH_KEYS"); do + _imds "$IMDS_SSH_KEYS/${key%=*}/openssh-key" + echo + done | sort -u } _imds_nic_index() { cat "/sys/class/net/$1/address"; } @@ -87,71 +87,71 @@ _imds_nic_index() { cat "/sys/class/net/$1/address"; } ### load cloud-specific variables and functions if [ ! -d "$LIBDIR/tiny-cloud/cloud/$CLOUD" ]; then - echo "ERROR: Unknown Cloud '$CLOUD'" >&2 + echo "ERROR: Unknown Cloud '$CLOUD'" >&2 fi . "$LIBDIR/tiny-cloud/cloud/$CLOUD/imds" ### non-overrideable functions imds() { - local cmd args key rv err=1 - while [ -n "$1" ]; do - cmd=_imds - args= - key="$1"; shift - case $key in - # error handling - -e) err=0; continue ;; # ignore - +e) err=1; continue ;; # return - # TODO: retry/deadline - # output control - +n) printf "\n"; continue ;; # insert newline - +s) printf " "; continue ;; # insert space - +t) printf "\t"; continue ;; # insert tab - # key aliasing - @hostname) args="$IMDS_HOSTNAME" ;; - @local-hostname) args="$IMDS_LOCAL_HOSTNAME" ;; - @ssh-keys) cmd=_imds_ssh_keys ;; - @userdata) cmd=_imds_userdata ;; - @nics) args="$IMDS_NICS" ;; - @nic:*) - cmd=imds - args=$(_imds_nic_args $(echo "${key#@nic:}" | tr , ' ')) - ;; - # use key verbatim - *) args="$key" ;; - esac - # TODO: retry/deadline - "$cmd" $args - rv=$? - [ $err -eq 0 ] && continue - [ $rv = "0" ] || return $rv - done + local cmd args key rv err=1 + while [ -n "$1" ]; do + cmd=_imds + args= + key="$1"; shift + case $key in + # error handling + -e) err=0; continue ;; # ignore + +e) err=1; continue ;; # return + # TODO: retry/deadline + # output control + +n) printf "\n"; continue ;; # insert newline + +s) printf " "; continue ;; # insert space + +t) printf "\t"; continue ;; # insert tab + # key aliasing + @hostname) args="$IMDS_HOSTNAME" ;; + @local-hostname) args="$IMDS_LOCAL_HOSTNAME" ;; + @ssh-keys) cmd=_imds_ssh_keys ;; + @userdata) cmd=_imds_userdata ;; + @nics) args="$IMDS_NICS" ;; + @nic:*) + cmd=imds + args=$(_imds_nic_args $(echo "${key#@nic:}" | tr , ' ')) + ;; + # use key verbatim + *) args="$key" ;; + esac + # TODO: retry/deadline + "$cmd" $args + rv=$? + [ $err -eq 0 ] && continue + [ $rv = "0" ] || return $rv + done } _imds_nic_args() { - local key nic - nic=$(_imds_nic_index "$1") || return 1 - if [ -z "$2" ]; then - echo "$IMDS_NICS/$nic" - return - fi - while [ -n "$2" ]; do - key="$2" - shift - case "$key" in - @mac) key="$IMDS_MAC" ;; - @ipv4) key="$IMDS_IPV4" ;; - @ipv6) key="$IMDS_IPV6" ;; - @ipv4-net) key="$IMDS_IPV4_NET" ;; - @ipv6-net) key="$IMDS_IPV6_NET" ;; - @ipv4-prefix) key="$IMDS_IPV4_PREFIX" ;; - @ipv6-prefix) key="$IMDS_IPV6_PREFIX" ;; - # error/output control passthrough - -e|+[enst]) printf "$key\n"; continue ;; - esac - printf "$IMDS_NICS/$nic/$key\n" - done + local key nic + nic=$(_imds_nic_index "$1") || return 1 + if [ -z "$2" ]; then + echo "$IMDS_NICS/$nic" + return + fi + while [ -n "$2" ]; do + key="$2" + shift + case "$key" in + @mac) key="$IMDS_MAC" ;; + @ipv4) key="$IMDS_IPV4" ;; + @ipv6) key="$IMDS_IPV6" ;; + @ipv4-net) key="$IMDS_IPV4_NET" ;; + @ipv6-net) key="$IMDS_IPV6_NET" ;; + @ipv4-prefix) key="$IMDS_IPV4_PREFIX" ;; + @ipv6-prefix) key="$IMDS_IPV6_PREFIX" ;; + # error/output control passthrough + -e|+[enst]) printf "$key\n"; continue ;; + esac + printf "$IMDS_NICS/$nic/$key\n" + done } imds "$@" diff --git a/dist/openrc/tiny-cloud b/dist/openrc/tiny-cloud index 0fff2f9..1981baa 100755 --- a/dist/openrc/tiny-cloud +++ b/dist/openrc/tiny-cloud @@ -1,5 +1,5 @@ #!/sbin/openrc-run -# vim:set ts=8 noet ft=sh: +# vim:set ft=sh: # shellcheck shell=sh description="Tiny Cloud Bootstrap - main phase" diff --git a/dist/openrc/tiny-cloud-early b/dist/openrc/tiny-cloud-early index 20a20db..6354a55 100755 --- a/dist/openrc/tiny-cloud-early +++ b/dist/openrc/tiny-cloud-early @@ -1,5 +1,5 @@ #!/sbin/openrc-run -# vim:set ts=8 noet ft=sh: +# vim:set ft=sh: # shellcheck shell=sh description="Tiny Cloud Bootstrap - early phase" diff --git a/dist/openrc/tiny-cloud-final b/dist/openrc/tiny-cloud-final index 5169fc2..69fe797 100755 --- a/dist/openrc/tiny-cloud-final +++ b/dist/openrc/tiny-cloud-final @@ -1,5 +1,5 @@ #!/sbin/openrc-run -# vim:set ts=8 noet ft=sh: +# vim:set ft=sh: # shellcheck shell=sh description="Tiny Cloud Bootstrap - final phase" diff --git a/dist/openrc/tiny-cloud-net b/dist/openrc/tiny-cloud-net index d6659df..2394763 100755 --- a/dist/openrc/tiny-cloud-net +++ b/dist/openrc/tiny-cloud-net @@ -1,5 +1,5 @@ #!/sbin/openrc-run -# vim:set ts=8 noet ft=sh: +# vim:set ft=sh: # shellcheck shell=sh description="Tiny Cloud Bootstrap - net phase" diff --git a/lib/mdev/nvme-ebs-links b/lib/mdev/nvme-ebs-links index 1eee876..663a1e9 100755 --- a/lib/mdev/nvme-ebs-links +++ b/lib/mdev/nvme-ebs-links @@ -1,8 +1,8 @@ #!/bin/sh -# vim:set ts=2 et: +# vim:set ft=sh: # NOTE: The mdev-conf APK handles this now, but only for xvd or sd links (not -# both) +# both) : "${LIBDIR:=$PREFIX/lib}" . "$LIBDIR/tiny-cloud/common" @@ -11,39 +11,39 @@ [ -x /usr/sbin/nvme ] || log crit "nvme cli not installed" raw_ebs_alias() { - /usr/sbin/nvme id-ctrl "/dev/$BASE" -b 2>/dev/null | - dd bs=32 skip=96 count=1 2>/dev/null + /usr/sbin/nvme id-ctrl "/dev/$BASE" -b 2>/dev/null | + dd bs=32 skip=96 count=1 2>/dev/null } case $ACTION in - add|"") - BASE=$(echo "$MDEV" | sed -re 's/^(nvme[0-9]+n[0-9]+).*/\1/') - PART=$(echo "$MDEV" | sed -re 's/nvme[0-9]+n[0-9]+p?//g') - # TODO: deadline instead of max tries - MAXTRY=30 - TRY=0 - until [ -n "$EBS" ]; do - EBS=$(raw_ebs_alias | sed -nre '/^(\/dev\/)?(s|xv)d[a-z]{1,2} /p' | tr -d ' ') - [ -n "$EBS" ] && break - TRY=$((TRY + 1)) - if [ $TRY -eq $MAXTRY ]; then - log err "Failed to get EBS volume alias for $MDEV after $MAXTRY attempts ($(raw_ebs_alias))" - exit 1 - fi - sleep 0.1 - done - # remove any leading '/dev/', 'sd', or 'xvd', and append partition - EBS=${EBS#/dev/} - EBS=${EBS#sd} - EBS=${EBS#xvd}$PART - ln -sf "$MDEV" "sd$EBS" && log notice "Added sd$EBS symlink for $MDEV" - ln -sf "$MDEV" "xvd$EBS" && log notice "Added xvd$EBS symlink for $MDEV" - ;; - remove) - for TARGET in sd* xvd* - do - [ "$(readlink "$TARGET" 2>/dev/null)" = "$MDEV" ] && rm -f "$TARGET" && \ - log notice "Removed $TARGET symlink for $MDEV" - done - ;; + add|"") + BASE=$(echo "$MDEV" | sed -re 's/^(nvme[0-9]+n[0-9]+).*/\1/') + PART=$(echo "$MDEV" | sed -re 's/nvme[0-9]+n[0-9]+p?//g') + # TODO: deadline instead of max tries + MAXTRY=30 + TRY=0 + until [ -n "$EBS" ]; do + EBS=$(raw_ebs_alias | sed -nre '/^(\/dev\/)?(s|xv)d[a-z]{1,2} /p' | tr -d ' ') + [ -n "$EBS" ] && break + TRY=$((TRY + 1)) + if [ $TRY -eq $MAXTRY ]; then + log err "Failed to get EBS volume alias for $MDEV after $MAXTRY attempts ($(raw_ebs_alias))" + exit 1 + fi + sleep 0.1 + done + # remove any leading '/dev/', 'sd', or 'xvd', and append partition + EBS=${EBS#/dev/} + EBS=${EBS#sd} + EBS=${EBS#xvd}$PART + ln -sf "$MDEV" "sd$EBS" && log notice "Added sd$EBS symlink for $MDEV" + ln -sf "$MDEV" "xvd$EBS" && log notice "Added xvd$EBS symlink for $MDEV" + ;; + remove) + for TARGET in sd* xvd* + do + [ "$(readlink "$TARGET" 2>/dev/null)" = "$MDEV" ] && rm -f "$TARGET" && \ + log notice "Removed $TARGET symlink for $MDEV" + done + ;; esac diff --git a/lib/mdev/vnic-eth-hotplug b/lib/mdev/vnic-eth-hotplug index 160a5f0..72fb947 100755 --- a/lib/mdev/vnic-eth-hotplug +++ b/lib/mdev/vnic-eth-hotplug @@ -1,5 +1,5 @@ #!/bin/sh -# vim:set ts=4 et: +# vim:set ft=sh: set -e @@ -7,52 +7,52 @@ set -e . "$LIBDIR/tiny-cloud/common" if [ -z "$MDEV" ] || [ -z "$ACTION" ]; then - log crit "MDEV or ACTION undefined, aborting" + log crit "MDEV or ACTION undefined, aborting" fi IFACE_CFG=/etc/network/interfaces ip() { - local v=-4 lev=info - if [ "$1" = '-4' ] || [ "$1" = '-6' ]; then - v="$1" - shift - fi - local op="$2" + local v=-4 lev=info + if [ "$1" = '-4' ] || [ "$1" = '-6' ]; then + v="$1" + shift + fi + local op="$2" - [ "$op" = show ] && lev=debug - if /sbin/ip "$v" "$@" || [ -n "$FAIL_OK" ]; then - log "$lev" "OK: ip $v $*" - else - log err "FAIL: ip $v $*" - fi + [ "$op" = show ] && lev=debug + if /sbin/ip "$v" "$@" || [ -n "$FAIL_OK" ]; then + log "$lev" "OK: ip $v $*" + else + log err "FAIL: ip $v $*" + fi } interface_up() { - log info "Bringing up $MDEV" - # umask so udhcpc PID file isn't non-owner writeable - (umask 0022 && ifup "$MDEV") + log info "Bringing up $MDEV" + # umask so udhcpc PID file isn't non-owner writeable + (umask 0022 && ifup "$MDEV") } cleanup_interface() { - local v pref rtable="${MDEV#eth}" - let rtable+=10000 + local v pref rtable="${MDEV#eth}" + let rtable+=10000 - log info "Cleaning up $MDEV" + log info "Cleaning up $MDEV" - # kill related udhcpc, don't panic if it's not there - kill "$(cat "/run/udhcpc.$MDEV.pid")" || true + # kill related udhcpc, don't panic if it's not there + kill "$(cat "/run/udhcpc.$MDEV.pid")" || true - # tidy up /run/ifstate, if it exists - [ -f /run/ifstate ] && sed -i -e "/^$MDEV=/d" /run/ifstate - rm -f /run/ifstate."$MDEV".lock + # tidy up /run/ifstate, if it exists + [ -f /run/ifstate ] && sed -i -e "/^$MDEV=/d" /run/ifstate + rm -f /run/ifstate."$MDEV".lock - # remove related rules - for v in 4 6; do - for pref in $(ip -"$v" rule show table "$rtable" | cut -d: -f1); do - ip -"$v" rule del pref "$pref" - done - done + # remove related rules + for v in 4 6; do + for pref in $(ip -"$v" rule show table "$rtable" | cut -d: -f1); do + ip -"$v" rule del pref "$pref" + done + done } is_networking_started() { service networking status -q 2>/dev/null; } @@ -60,28 +60,28 @@ is_networking_started() { service networking status -q 2>/dev/null; } log info "STARTING: $ACTION $MDEV" if exec 200>>"$IFACE_CFG"; then - if flock 200; then - case $ACTION in - add|"") - assemble-interfaces - is_networking_started && interface_up - ;; - remove) - assemble-interfaces - is_networking_started && cleanup_interface - ;; - *) - log err "Unknown action '$ACTION'" - exit 1 - ;; - esac - else - log err "Unable to flock $IFACE_CFG" - exit 1 - fi + if flock 200; then + case $ACTION in + add|"") + assemble-interfaces + is_networking_started && interface_up + ;; + remove) + assemble-interfaces + is_networking_started && cleanup_interface + ;; + *) + log err "Unknown action '$ACTION'" + exit 1 + ;; + esac + else + log err "Unable to flock $IFACE_CFG" + exit 1 + fi else - log err "Unable to assign fd 200 to flock $IFACE_CFG" - exit 1 + log err "Unable to assign fd 200 to flock $IFACE_CFG" + exit 1 fi log info "FINISHED: $ACTION $MDEV" diff --git a/lib/tiny-cloud/cloud/alpine/init b/lib/tiny-cloud/cloud/alpine/init index 6081ba0..19fb994 100644 --- a/lib/tiny-cloud/cloud/alpine/init +++ b/lib/tiny-cloud/cloud/alpine/init @@ -1,27 +1,27 @@ # Tiny Cloud - Init Functions -# vim:set ts=4 et ft=sh: +# vim:set ft=sh: # shellcheck shell=sh INIT_ACTIONS_EARLY="$(replace_word set_default_interfaces set_network_interfaces $INIT_ACTIONS_EARLY)" set_resolv_conf() { - # resolv.conf - local nameservers="$(imds meta-data/resolv_conf/nameservers)" - for i in $nameservers; do - local server="$(imds meta-data/resolv_conf/nameservers/$i)" - add_once "$ROOT"/etc/resolv.conf "nameserver $server" - done + # resolv.conf + local nameservers="$(imds meta-data/resolv_conf/nameservers)" + for i in $nameservers; do + local server="$(imds meta-data/resolv_conf/nameservers/$i)" + add_once "$ROOT"/etc/resolv.conf "nameserver $server" + done } init__set_network_interfaces() { - local interfaces="$(imds meta-data/network-interfaces)" - mkdir -p "$ROOT"/etc/network - if [ -n "$interfaces" ]; then - printf "%s\n" "$interfaces" > "$ROOT"/etc/network/interfaces - elif ! [ -f "$ROOT"/etc/network/interfaces ]; then - init__set_default_interfaces - fi - if ! grep -q dhcp "$ROOT"/etc/network/interfaces; then - set_resolv_conf - fi + local interfaces="$(imds meta-data/network-interfaces)" + mkdir -p "$ROOT"/etc/network + if [ -n "$interfaces" ]; then + printf "%s\n" "$interfaces" > "$ROOT"/etc/network/interfaces + elif ! [ -f "$ROOT"/etc/network/interfaces ]; then + init__set_default_interfaces + fi + if ! grep -q dhcp "$ROOT"/etc/network/interfaces; then + set_resolv_conf + fi } diff --git a/lib/tiny-cloud/cloud/aws/imds b/lib/tiny-cloud/cloud/aws/imds index 94442d8..31daef3 100644 --- a/lib/tiny-cloud/cloud/aws/imds +++ b/lib/tiny-cloud/cloud/aws/imds @@ -1,5 +1,5 @@ # AWS Instance MetaData Service variables and functions -# vim:set ts=4 et ft=sh: +# vim:set ft=sh: # shellcheck shell=sh IMDS_HEADER="X-aws-ec2-metadata-token" @@ -8,11 +8,11 @@ IMDS_TOKEN_TTL_HEADER="X-aws-ec2-metadata-token-ttl-seconds" IMDS_URI="latest" _imds_token() { - printf "PUT /latest/api/token HTTP/1.0\r\n%s: %s\r\n\r\n" \ - "$IMDS_TOKEN_TTL_HEADER" "$IMDS_TOKEN_TTL" \ - | nc -w 1 "$IMDS_ENDPOINT" 80 | tail -n 1 + printf "PUT /latest/api/token HTTP/1.0\r\n%s: %s\r\n\r\n" \ + "$IMDS_TOKEN_TTL_HEADER" "$IMDS_TOKEN_TTL" \ + | nc -w 1 "$IMDS_ENDPOINT" 80 | tail -n 1 } _imds_header() { - echo "$IMDS_HEADER: $(_imds_token)" + echo "$IMDS_HEADER: $(_imds_token)" } diff --git a/lib/tiny-cloud/cloud/aws/mdev b/lib/tiny-cloud/cloud/aws/mdev index b1f6218..8ddd8a2 100644 --- a/lib/tiny-cloud/cloud/aws/mdev +++ b/lib/tiny-cloud/cloud/aws/mdev @@ -1,12 +1,12 @@ # AWS mdev Hotplug Modules -# vim:set ts=4 et ft=sh: +# vim:set ft=sh: # shellcheck shell=sh # makes symlinks for NVMe devices that correlate to AWS EBS sd/xvd devices mod__nvme_ebs_links() { - # nvme-cli not installed? - [ -x /usr/sbin/nvme ] || return 1 + # nvme-cli not installed? + [ -x /usr/sbin/nvme ] || return 1 - install_before '^nvme\.\*' \ - 'nvme[0-9]+n.* root:disk 0660 */lib/mdev/nvme-ebs-links' + install_before '^nvme\.\*' \ + 'nvme[0-9]+n.* root:disk 0660 */lib/mdev/nvme-ebs-links' } diff --git a/lib/tiny-cloud/cloud/azure/imds b/lib/tiny-cloud/cloud/azure/imds index ebedefd..8781b49 100644 --- a/lib/tiny-cloud/cloud/azure/imds +++ b/lib/tiny-cloud/cloud/azure/imds @@ -1,5 +1,5 @@ # Azure Instance MetaData Service variables and functions -# vim:set ts=4 et ft=sh: +# vim:set ft=sh: # shellcheck shell=sh IMDS_HEADER="Metadata" @@ -14,28 +14,28 @@ IMDS_NICS="network/interface" # TODO: flesh out networking unset \ - IMDS_MAC \ - IMDS_IPV4 \ - IMDS_IPV6 \ - IMDS_IPV4_NET \ - IMDS_IPV6_NET \ - IMDS_IPV4_PREFIX \ - IMDS_IPV6_PREFIX + IMDS_MAC \ + IMDS_IPV4 \ + IMDS_IPV6 \ + IMDS_IPV4_NET \ + IMDS_IPV6_NET \ + IMDS_IPV4_PREFIX \ + IMDS_IPV6_PREFIX _imds_header() { - echo "$IMDS_HEADER: true" + echo "$IMDS_HEADER: true" } # dig deeper than default _imds_ssh_keys() { - local key + local key - for key in $(imds "$IMDS_SSH_KEYS"); do - imds "$IMDS_SSH_KEYS/${key}/keyData" - done | sort -u + for key in $(imds "$IMDS_SSH_KEYS"); do + imds "$IMDS_SSH_KEYS/${key}/keyData" + done | sort -u } # decode userdata value _imds_userdata() { - imds "$IMDS_USERDATA" | base64 -d + imds "$IMDS_USERDATA" | base64 -d } diff --git a/lib/tiny-cloud/cloud/gcp/imds b/lib/tiny-cloud/cloud/gcp/imds index 7598b63..f6b1919 100644 --- a/lib/tiny-cloud/cloud/gcp/imds +++ b/lib/tiny-cloud/cloud/gcp/imds @@ -1,5 +1,5 @@ # Google Cloud Instance MetaData Service variables and functions -# vim:set ts=4 et ft=sh: +# vim:set ft=sh: # shellcheck shell=sh IMDS_HEADER="Metadata-Flavor" @@ -8,21 +8,21 @@ IMDS_URI="computeMetadata/v1" IMDS_HOSTNAME="instance/hostname" IMDS_LOCAL_HOSTNAME="$IMDS_HOSTNAME" IMDS_SSH_KEYS=" - project/attributes/ssh-keys - instance/attributes/ssh-keys + project/attributes/ssh-keys + instance/attributes/ssh-keys " IMDS_USERDATA="instance/attributes/user-data" _imds_header() { - echo "$IMDS_HEADER: Google" + echo "$IMDS_HEADER: Google" } # merge project and instance keys _imds_ssh_keys() { - local ssh_keys + local ssh_keys - for ssh_keys in $IMDS_SSH_KEYS; do - # ignore errors and strip leading ':' - imds -e "$ssh_keys" | cut -d: -f2- - done | sort -u + for ssh_keys in $IMDS_SSH_KEYS; do + # ignore errors and strip leading ':' + imds -e "$ssh_keys" | cut -d: -f2- + done | sort -u } diff --git a/lib/tiny-cloud/cloud/nocloud/imds b/lib/tiny-cloud/cloud/nocloud/imds index 0eef9bd..2c7a4f0 100644 --- a/lib/tiny-cloud/cloud/nocloud/imds +++ b/lib/tiny-cloud/cloud/nocloud/imds @@ -1,5 +1,5 @@ # NoCloud Instance Metadata -# vim: ts=4 et ft=sh: +# vim:set ft=sh: # shellcheck shell=sh NOCLOUD_FILES="meta-data user-data vendor-data network-config" @@ -7,100 +7,100 @@ NOCLOUD_FILES="meta-data user-data vendor-data network-config" is_nocloud_loaded() { [ -f "$TINY_CLOUD_VAR/.nocloud_loaded" ]; } _load_nocloud_cmdline() { - local kopt kv k v data + local kopt kv k v data - for kopt in $(cat "$ROOT/proc/cmdline" 2>/dev/null); do - echo "$kopt" | grep -qE '(^|=)ds=nocloud(-net)?;' || continue - for kv in $(echo "${kopt#*;}" | tr \; ' '); do - k=$(echo "$kv" | cut -d= -f1) - v=$(echo "$kv" | cut -d= -f2-) - case "$k" in - h|local-hostname) - printf "\nlocal-hostname: %s" "$v" >> "$TINY_CLOUD_VAR/meta-data" - ;; - i|instance-id) - printf "\ninstance-id: %s" "$v" >> "$TINY_CLOUD_VAR/meta-data" - ;; - s|seedfrom) - for data in $NOCLOUD_FILES; do - case "${v#file:/}" in - /*) - cat "$v/$data" >> "$TINY_CLOUD_VAR/$data" || continue - echo >> "$TINY_CLOUD_VAR/$data" - ;; - http://*|https://*) - wget -qO - "$v/$data" >> "$TINY_CLOUD_VAR/$data" || continue - echo >> "$TINY_CLOUD_VAR/$data" - ;; - *) log -s warning "Unknown NoCloud seedfrom value '$v'" - ;; - esac - done - ;; - *) log -s warning "Unknown NoCloud kernel cmdline key '$k'" - ;; - esac - done - return - done - return 1 + for kopt in $(cat "$ROOT/proc/cmdline" 2>/dev/null); do + echo "$kopt" | grep -qE '(^|=)ds=nocloud(-net)?;' || continue + for kv in $(echo "${kopt#*;}" | tr \; ' '); do + k=$(echo "$kv" | cut -d= -f1) + v=$(echo "$kv" | cut -d= -f2-) + case "$k" in + h|local-hostname) + printf "\nlocal-hostname: %s" "$v" >> "$TINY_CLOUD_VAR/meta-data" + ;; + i|instance-id) + printf "\ninstance-id: %s" "$v" >> "$TINY_CLOUD_VAR/meta-data" + ;; + s|seedfrom) + for data in $NOCLOUD_FILES; do + case "${v#file:/}" in + /*) + cat "$v/$data" >> "$TINY_CLOUD_VAR/$data" || continue + echo >> "$TINY_CLOUD_VAR/$data" + ;; + http://*|https://*) + wget -qO - "$v/$data" >> "$TINY_CLOUD_VAR/$data" || continue + echo >> "$TINY_CLOUD_VAR/$data" + ;; + *) log -s warning "Unknown NoCloud seedfrom value '$v'" + ;; + esac + done + ;; + *) log -s warning "Unknown NoCloud kernel cmdline key '$k'" + ;; + esac + done + return + done + return 1 } _load_nocloud_volume() { - mkdir -p "$ROOT"/run/tiny-cloud - local mntdir=$(mktemp -d "$ROOT/run/tiny-cloud/cidata-XXXXXX") - local data mounted + mkdir -p "$ROOT"/run/tiny-cloud + local mntdir=$(mktemp -d "$ROOT/run/tiny-cloud/cidata-XXXXXX") + local data mounted - mkdir -p "$mntdir" - for fstype in vfat iso9660; do - [ "$mounted" ] && break - for label in cidata CIDATA; do - [ -n "$mounted" ] && break - mount -o ro -t "$fstype" LABEL="$label" "$mntdir" && mounted=1 - done - done - if [ -n "$mounted" ]; then - for data in $NOCLOUD_FILES; do - # lack of source results in empty target - cat "$mntdir/$data" > "$TINY_CLOUD_VAR/$data" 2>/dev/null - done - umount "$mntdir" - else - return 1 - fi - rmdir "$mntdir" + mkdir -p "$mntdir" + for fstype in vfat iso9660; do + [ "$mounted" ] && break + for label in cidata CIDATA; do + [ -n "$mounted" ] && break + mount -o ro -t "$fstype" LABEL="$label" "$mntdir" && mounted=1 + done + done + if [ -n "$mounted" ]; then + for data in $NOCLOUD_FILES; do + # lack of source results in empty target + cat "$mntdir/$data" > "$TINY_CLOUD_VAR/$data" 2>/dev/null + done + umount "$mntdir" + else + return 1 + fi + rmdir "$mntdir" } load_nocloud() { - # start with a clean slate - (cd "$TINY_CLOUD_VAR" && rm -f $NOCLOUD_FILES) + # start with a clean slate + (cd "$TINY_CLOUD_VAR" && rm -f $NOCLOUD_FILES) - if _load_nocloud_cmdline || _load_nocloud_volume; then - touch "$TINY_CLOUD_VAR/.nocloud_loaded" - else - log -s err "Unable to load NoCloud datasource" - return 1 - fi + if _load_nocloud_cmdline || _load_nocloud_volume; then + touch "$TINY_CLOUD_VAR/.nocloud_loaded" + else + log -s err "Unable to load NoCloud datasource" + return 1 + fi - # minimally, we expect some content in meta-data - [ -s "$TINY_CLOUD_VAR/meta-data" ] || - log -s warning "NoCloud 'meta-data' is empty" + # minimally, we expect some content in meta-data + [ -s "$TINY_CLOUD_VAR/meta-data" ] || + log -s warning "NoCloud 'meta-data' is empty" } _imds() { - mkdir -p "$TINY_CLOUD_VAR" - local file="$TINY_CLOUD_VAR/$(echo "$1" | cut -d/ -f1)" - local keypath="$(echo "$1" | cut -d/ -f2- | tr / ' ')" + mkdir -p "$TINY_CLOUD_VAR" + local file="$TINY_CLOUD_VAR/$(echo "$1" | cut -d/ -f1)" + local keypath="$(echo "$1" | cut -d/ -f2- | tr / ' ')" - is_nocloud_loaded || load_nocloud + is_nocloud_loaded || load_nocloud - # does file exist? - [ -f "$file" ] || return 1 + # does file exist? + [ -f "$file" ] || return 1 - # use 'file/' to get top-level keys - if [ $(basename "$file") = "$keypath" ]; then - cat "$file" - else - yx -f "$file" $keypath - fi + # use 'file/' to get top-level keys + if [ $(basename "$file") = "$keypath" ]; then + cat "$file" + else + yx -f "$file" $keypath + fi } diff --git a/lib/tiny-cloud/cloud/oci/imds b/lib/tiny-cloud/cloud/oci/imds index 4d17c31..af94d68 100644 --- a/lib/tiny-cloud/cloud/oci/imds +++ b/lib/tiny-cloud/cloud/oci/imds @@ -1,5 +1,5 @@ # OCI Instance MetaData Service variables and functions -# vim:set ts=4 et ft=sh: +# vim:set ft=sh: # shellcheck shell=sh IMDS_HEADER="Authorization" @@ -13,25 +13,25 @@ IMDS_NICS="nics" # TODO: flesh out networking unset \ - IMDS_MAC \ - IMDS_IPV4 \ - IMDS_IPV6 \ - IMDS_IPV4_NET \ - IMDS_IPV6_NET \ - IMDS_IPV4_PREFIX \ - IMDS_IPV6_PREFIX + IMDS_MAC \ + IMDS_IPV4 \ + IMDS_IPV6 \ + IMDS_IPV4_NET \ + IMDS_IPV6_NET \ + IMDS_IPV4_PREFIX \ + IMDS_IPV6_PREFIX _imds_header() { - echo "$IMDS_HEADER: Bearer Oracle" + echo "$IMDS_HEADER: Bearer Oracle" } _imds_ssh_keys() { _imds "$IMDS_SSH_KEYS"; } _imds_nic_index() { - local m n=0 - local mac=$(cat "/sys/class/net/$1/mac") - while m=$(imds "$IMDS_NICS/$n/mac" | tr A-F a-f); do - [ "$m" = "$mac" ] && echo $n; return 0 - done - return 1 + local m n=0 + local mac=$(cat "/sys/class/net/$1/mac") + while m=$(imds "$IMDS_NICS/$n/mac" | tr A-F a-f); do + [ "$m" = "$mac" ] && echo $n; return 0 + done + return 1 } diff --git a/lib/tiny-cloud/common b/lib/tiny-cloud/common index fea28f3..6eaa8fc 100644 --- a/lib/tiny-cloud/common +++ b/lib/tiny-cloud/common @@ -1,5 +1,5 @@ # Tiny Cloud - common script functions -# vim: ts=4 et ft=sh: +# vim:set ft=sh: # shellcheck shell=sh # set defaults @@ -10,62 +10,62 @@ : "${TINY_CLOUD_VAR:=$ROOT/var/lib/cloud}" log() { - local facility="local7" - local stderr init - local tag=$(basename "$0") - while [ "${1#-}" != "$1" ]; do - case "$1" in - -i) init=1 ;; # TODO: value = indent? - -f) facility="$2"; shift ;; - -s) stderr=-s ;; - -t) tag="$tag/$2"; shift ;; - esac - shift - done - local level="$1" - [ -z "$DEBUG" ] && [ "$level" = debug ] && return - shift + local facility="local7" + local stderr init + local tag=$(basename "$0") + while [ "${1#-}" != "$1" ]; do + case "$1" in + -i) init=1 ;; # TODO: value = indent? + -f) facility="$2"; shift ;; + -s) stderr=-s ;; + -t) tag="$tag/$2"; shift ;; + esac + shift + done + local level="$1" + [ -z "$DEBUG" ] && [ "$level" = debug ] && return + shift - [ -n "$init" ] && echo "$@" >&2 - logger $stderr -p "$facility.$level" -t "${tag}[$$]" "$@" - case "$level" in - crit|alert|emerg) exit 1 ;; - esac + [ -n "$init" ] && echo "$@" >&2 + logger $stderr -p "$facility.$level" -t "${tag}[$$]" "$@" + case "$level" in + crit|alert|emerg) exit 1 ;; + esac } # usage: replace_word ... replace_word() { - local search="$1" replace="$2" - shift 2 - for word in "$@"; do - if [ "$word" = "$search" ]; then - echo "$replace" - else - echo "$word" - fi - done + local search="$1" replace="$2" + shift 2 + for word in "$@"; do + if [ "$word" = "$search" ]; then + echo "$replace" + else + echo "$word" + fi + done } # usage: insert_after ... insert_after() { - local search="$1" addition="$2" - shift 2 - for i in "$@"; do - echo "$i" - if [ "$i" = "$search" ]; then - echo "$addition" - fi - done + local search="$1" addition="$2" + shift 2 + for i in "$@"; do + echo "$i" + if [ "$i" = "$search" ]; then + echo "$addition" + fi + done } # usage: add_once ... add_once() { - local file="$1" - shift - for line; do - if ! grep -x -F "$line" "$file" 2>/dev/null; then - mkdir -p "${file%/*}" - printf "%s\n" "$line" >> "$file" - fi - done + local file="$1" + shift + for line; do + if ! grep -x -F "$line" "$file" 2>/dev/null; then + mkdir -p "${file%/*}" + printf "%s\n" "$line" >> "$file" + fi + done } diff --git a/lib/tiny-cloud/init b/lib/tiny-cloud/init index 4759977..79b8a4e 100644 --- a/lib/tiny-cloud/init +++ b/lib/tiny-cloud/init @@ -1,5 +1,5 @@ # Tiny Cloud - Init Functions -# vim:set ts=4 et ft=sh: +# vim:set ft=sh: # shellcheck shell=sh # set defaults @@ -12,18 +12,18 @@ ### default phase actions (without leading 'init__') DEFAULT_ACTIONS_EARLY=" - expand_root - install_hotplugs - set_default_interfaces - create_default_user - enable_sshd + expand_root + install_hotplugs + set_default_interfaces + create_default_user + enable_sshd " DEFAULT_ACTIONS_NET=" - save_userdata + save_userdata " DEFAULT_ACTIONS_MAIN=" - set_hostname - set_ssh_keys + set_hostname + set_ssh_keys " DEFAULT_ACTIONS_FINAL="" @@ -40,236 +40,236 @@ DEFAULT_ACTIONS_FINAL="" ### standard init-early functions... init__expand_root() { - local dev=$(awk '$2 == "/" {print $1}' "$ROOT"/proc/mounts 2>/dev/null) - local filesystem=$(awk '$2 == "/" {print $3}' "$ROOT"/proc/mounts 2>/dev/null) - local partition=$(cat "$ROOT/sys/class/block/${dev#/dev/}/partition" 2>/dev/null) + local dev=$(awk '$2 == "/" {print $1}' "$ROOT"/proc/mounts 2>/dev/null) + local filesystem=$(awk '$2 == "/" {print $3}' "$ROOT"/proc/mounts 2>/dev/null) + local partition=$(cat "$ROOT/sys/class/block/${dev#/dev/}/partition" 2>/dev/null) - # only support ext2/ext3/ext4 for now - case "$filesystem" in - ext*) ;; - *) return;; - esac + # only support ext2/ext3/ext4 for now + case "$filesystem" in + ext*) ;; + *) return;; + esac - if [ -n "$partition" ]; then - # it's a partition, resize it - local volume=$(readlink -f "$ROOT/sys/class/block/${dev#/dev/}/..") - volume="/dev/${volume##*/}" - echo ", +" | $MOCK sfdisk -q --no-reread -N "$partition" "$volume" - $MOCK partx -u "$volume" - fi - # resize filesystem - $MOCK resize2fs "$dev" + if [ -n "$partition" ]; then + # it's a partition, resize it + local volume=$(readlink -f "$ROOT/sys/class/block/${dev#/dev/}/..") + volume="/dev/${volume##*/}" + echo ", +" | $MOCK sfdisk -q --no-reread -N "$partition" "$volume" + $MOCK partx -u "$volume" + fi + # resize filesystem + $MOCK resize2fs "$dev" } init__install_hotplugs() { - local level result rc=0 + local level result rc=0 - [ ! -n "$HOTPLUG_MODULES" ] && return - if [ -f "$LIBDIR/tiny-cloud/$HOTPLUG_TYPE" ]; then - . "$LIBDIR/tiny-cloud/$HOTPLUG_TYPE" - fi + [ ! -n "$HOTPLUG_MODULES" ] && return + if [ -f "$LIBDIR/tiny-cloud/$HOTPLUG_TYPE" ]; then + . "$LIBDIR/tiny-cloud/$HOTPLUG_TYPE" + fi - for module in $HOTPLUG_MODULES; do - result='unknown' - level='err' - printf " >> " >&2 - log -i -t "$phase/$ACTION" info "$module: installing" - if type "mod__$module" | grep -q -w "function"; then - if "mod__$module"; then - result='installed' - level='info' - else - result='failed' - rc=1 - fi - fi - printf " >> " >&2 - log -i -t "$phase/$ACTION" info "$module: $result" - done - return $rc + for module in $HOTPLUG_MODULES; do + result='unknown' + level='err' + printf " >> " >&2 + log -i -t "$phase/$ACTION" info "$module: installing" + if type "mod__$module" | grep -q -w "function"; then + if "mod__$module"; then + result='installed' + level='info' + else + result='failed' + rc=1 + fi + fi + printf " >> " >&2 + log -i -t "$phase/$ACTION" info "$module: $result" + done + return $rc } # collect ethernet interfaces, sorted by index ethernets() { - for i in "$ROOT/sys/class/net/"*; do - local iface="${i##*/}" - case "$iface" in - eth*) echo "$(cat "$i/ifindex") $iface";; - esac - done | sort -n | awk '{print $2}' + for i in "$ROOT/sys/class/net/"*; do + local iface="${i##*/}" + case "$iface" in + eth*) echo "$(cat "$i/ifindex") $iface";; + esac + done | sort -n | awk '{print $2}' } # find the interface that is has operstate up find_first_interface_up() { - local n=0 - [ $# -eq 0 ] && return - while [ $n -le ${TINY_CLOUD_LINK_WAIT_MAX:-10} ]; do - for i in "$@"; do - if [ "$(cat "$ROOT/sys/class/net/$i/operstate")" = "up" ]; then - echo "$i" - return - fi - done - sleep 0.1 - n=$((n+1)) - done + local n=0 + [ $# -eq 0 ] && return + while [ $n -le ${TINY_CLOUD_LINK_WAIT_MAX:-10} ]; do + for i in "$@"; do + if [ "$(cat "$ROOT/sys/class/net/$i/operstate")" = "up" ]; then + echo "$i" + return + fi + done + sleep 0.1 + n=$((n+1)) + done } # auto detect which network interface to auto configure # check which is connected or fallback to first # This will set link to down to all eth* except the found auto_detect_ethernet_interface() { - local ifaces="$(ethernets)" - [ -z "$ifaces" ] && return + local ifaces="$(ethernets)" + [ -z "$ifaces" ] && return - # find first connected interface - for i in $ifaces; do - $MOCK ip link set dev $i up >/dev/null - done - local iface="$(find_first_interface_up $ifaces)" + # find first connected interface + for i in $ifaces; do + $MOCK ip link set dev $i up >/dev/null + done + local iface="$(find_first_interface_up $ifaces)" - # use first if all are disconnected - if [ -z "$iface" ]; then - set -- $ifaces - iface="$1" - fi + # use first if all are disconnected + if [ -z "$iface" ]; then + set -- $ifaces + iface="$1" + fi - # we will use the found interface later so lets keep it up - for i in $ifaces; do - if [ "$i" != "$iface" ]; then - $MOCK ip link set dev $i down >/dev/null - fi - done - echo "$iface" + # we will use the found interface later so lets keep it up + for i in $ifaces; do + if [ "$i" != "$iface" ]; then + $MOCK ip link set dev $i down >/dev/null + fi + done + echo "$iface" } init__set_default_interfaces() { - if [ -f "$ROOT"/etc/network/interfaces ]; then - log -i -t "$phase" info "$ACTION: already set up" - return - fi + if [ -f "$ROOT"/etc/network/interfaces ]; then + log -i -t "$phase" info "$ACTION: already set up" + return + fi - mkdir -p "$ROOT/etc/network" - printf "%s\n%s\n\n" \ - "auto lo" \ - "iface lo inet loopback" \ - > "$ROOT/etc/network/interfaces" + mkdir -p "$ROOT/etc/network" + printf "%s\n%s\n\n" \ + "auto lo" \ + "iface lo inet loopback" \ + > "$ROOT/etc/network/interfaces" - local iface="$(auto_detect_ethernet_interface)" - if [ -z "$iface" ]; then - # TODO: message/log? - return - fi - printf "%s\n%s\n\t%s\n\n" \ - "auto $iface" \ - "iface $iface" \ - "use dhcp" >> "$ROOT/etc/network/interfaces" + local iface="$(auto_detect_ethernet_interface)" + if [ -z "$iface" ]; then + # TODO: message/log? + return + fi + printf "%s\n%s\n\t%s\n\n" \ + "auto $iface" \ + "iface $iface" \ + "use dhcp" >> "$ROOT/etc/network/interfaces" } init__create_default_user() { - local user="$CLOUD_USER" - # don't do anything if it already exists - if getent passwd "$user" >/dev/null; then - log -i -t "$phase" info "$ACTION: already exists" - return - fi + local user="$CLOUD_USER" + # don't do anything if it already exists + if getent passwd "$user" >/dev/null; then + log -i -t "$phase" info "$ACTION: already exists" + return + fi - $MOCK addgroup "$user" - $MOCK adduser -h "/home/$user" -s /bin/sh -G "$user" -D "$user" - $MOCK addgroup "$user" wheel - echo "$user:*" | $MOCK chpasswd -e + $MOCK addgroup "$user" + $MOCK adduser -h "/home/$user" -s /bin/sh -G "$user" -D "$user" + $MOCK addgroup "$user" wheel + echo "$user:*" | $MOCK chpasswd -e - # setup sudo and/or doas - if [ -d "$ROOT/etc/sudoers.d" ]; then - echo '%wheel ALL=(ALL) NOPASSWD: ALL' > "$ROOT/etc/sudoers.d/wheel" - fi - if [ -d "$ROOT/etc/doas.d" ]; then - echo 'permit nopass :wheel' > "$TARGET/etc/doas.d/wheel.conf" - fi + # setup sudo and/or doas + if [ -d "$ROOT/etc/sudoers.d" ]; then + echo '%wheel ALL=(ALL) NOPASSWD: ALL' > "$ROOT/etc/sudoers.d/wheel" + fi + if [ -d "$ROOT/etc/doas.d" ]; then + echo 'permit nopass :wheel' > "$TARGET/etc/doas.d/wheel.conf" + fi } init__enable_sshd() { - $MOCK rc-update add sshd default - # in case something else has enabled/disabled dservices - $MOCK rc-update --update + $MOCK rc-update add sshd default + # in case something else has enabled/disabled dservices + $MOCK rc-update --update } ### standard init-main functions init__set_hostname() { - local fqdn=$(imds @hostname) - if [ -z "$fqdn" ]; then - log -i -t "$phase" info "$ACTION: no hostname set" - return - fi + local fqdn=$(imds @hostname) + if [ -z "$fqdn" ]; then + log -i -t "$phase" info "$ACTION: no hostname set" + return + fi - local host="${fqdn%%\.*}" - if [ -z "$host" ]; then - log -i -t "$phase" warn "$ACTION: invalid hostname '$fqdn'" - return 1 - fi + local host="${fqdn%%\.*}" + if [ -z "$host" ]; then + log -i -t "$phase" warn "$ACTION: invalid hostname '$fqdn'" + return 1 + fi - mkdir -p "$ROOT"/etc - echo "$host" > "$ROOT"/etc/hostname - $MOCK hostname -F "$ROOT"/etc/hostname - echo -e "127.0.1.1\t$fqdn $host" >> "$ROOT"/etc/hosts + mkdir -p "$ROOT"/etc + echo "$host" > "$ROOT"/etc/hostname + $MOCK hostname -F "$ROOT"/etc/hostname + echo -e "127.0.1.1\t$fqdn $host" >> "$ROOT"/etc/hosts } init__set_ssh_keys() { - local sshkeys="$(imds @ssh-keys)" - if [ -z "$sshkeys" ]; then - log -i -t "$phase" info "$ACTION: no ssh key found" - return - fi - local user="$CLOUD_USER" - local pwent="$(getent passwd "$user")" - if [ -z "$pwent" ]; then - log -i -t "$phase" err "$ACTION: failed to find user $user" - return 1 - fi - local group=$(echo "$pwent" | cut -d: -f4) - local ssh_dir="${ROOT}$(echo "$pwent" | cut -d: -f6)/.ssh" - local keys_file="$ssh_dir/authorized_keys" + local sshkeys="$(imds @ssh-keys)" + if [ -z "$sshkeys" ]; then + log -i -t "$phase" info "$ACTION: no ssh key found" + return + fi + local user="$CLOUD_USER" + local pwent="$(getent passwd "$user")" + if [ -z "$pwent" ]; then + log -i -t "$phase" err "$ACTION: failed to find user $user" + return 1 + fi + local group=$(echo "$pwent" | cut -d: -f4) + local ssh_dir="${ROOT}$(echo "$pwent" | cut -d: -f6)/.ssh" + local keys_file="$ssh_dir/authorized_keys" - if [ ! -d "$ssh_dir" ]; then - mkdir -p "$ssh_dir" - chmod 700 "$ssh_dir" - fi + if [ ! -d "$ssh_dir" ]; then + mkdir -p "$ssh_dir" + chmod 700 "$ssh_dir" + fi - touch "$keys_file" - chmod 600 "$keys_file" - $MOCK chown -R "$user:$group" "$ssh_dir" - echo "$sshkeys" > "$keys_file" + touch "$keys_file" + chmod 600 "$keys_file" + $MOCK chown -R "$user:$group" "$ssh_dir" + echo "$sshkeys" > "$keys_file" } init__save_userdata() { - local userdata="$TINY_CLOUD_VAR/user-data" - if [ -f "$userdata" ]; then - log -i -t "$phase" info "$ACTION: user-data already saved" - return - fi - local tmpfile=$(mktemp "$userdata.XXXXXX") + local userdata="$TINY_CLOUD_VAR/user-data" + if [ -f "$userdata" ]; then + log -i -t "$phase" info "$ACTION: user-data already saved" + return + fi + local tmpfile=$(mktemp "$userdata.XXXXXX") - imds -e @userdata > "$tmpfile" - if printf '\037\213\010' | cmp -s -n 3 "$tmpfile"; then - gzip -dc "$tmpfile" > "$userdata" - elif printf 'BZh' | cmp -s -n 3 "$tmpfile"; then - bzip2 -dc "$tmpfile" > "$userdata" - elif printf '\375\067\172\130\132\000' | cmp -s -n 6 "$tmpfile"; then - unxz -c "$tmpfile" > "$userdata" - elif printf '\135\000\000' | cmp -s -n 3 "$tmpfile"; then - lzma -dc "$tmpfile" > "$userdata" - elif printf '\211\114\132' | cmp -s -n 3 "$tmpfile"; then - lzop -dc "$tmpfile" > "$userdata" - elif printf '\004\042\115\030' | cmp -s -n 4 "$tmpfile"; then - lz4 -dc "$tmpfile" > "$userdata" - elif printf '(\265/\375' | cmp -s -n 4 "$tmpfile"; then - zstd -dc "$tmpfile" > "$userdata" - else - cp "$tmpfile" "$userdata" - fi - rm "$tmpfile" + imds -e @userdata > "$tmpfile" + if printf '\037\213\010' | cmp -s -n 3 "$tmpfile"; then + gzip -dc "$tmpfile" > "$userdata" + elif printf 'BZh' | cmp -s -n 3 "$tmpfile"; then + bzip2 -dc "$tmpfile" > "$userdata" + elif printf '\375\067\172\130\132\000' | cmp -s -n 6 "$tmpfile"; then + unxz -c "$tmpfile" > "$userdata" + elif printf '\135\000\000' | cmp -s -n 3 "$tmpfile"; then + lzma -dc "$tmpfile" > "$userdata" + elif printf '\211\114\132' | cmp -s -n 3 "$tmpfile"; then + lzop -dc "$tmpfile" > "$userdata" + elif printf '\004\042\115\030' | cmp -s -n 4 "$tmpfile"; then + lz4 -dc "$tmpfile" > "$userdata" + elif printf '(\265/\375' | cmp -s -n 4 "$tmpfile"; then + zstd -dc "$tmpfile" > "$userdata" + else + cp "$tmpfile" "$userdata" + fi + rm "$tmpfile" } @@ -279,26 +279,26 @@ init__save_userdata() { ### load cloud-specific init functions / vars (potentially overriding) if [ -f "$LIBDIR/tiny-cloud/cloud/$CLOUD/init" ]; then - . "$LIBDIR/tiny-cloud/cloud/$CLOUD/init" + . "$LIBDIR/tiny-cloud/cloud/$CLOUD/init" fi ### load user-data type-specific init functions / vars (potentially overriding) userdata_type() { - if [ ! -f "$TINY_CLOUD_VAR/user-data" ]; then - echo missing - return - fi - header=$(head -n1 "$TINY_CLOUD_VAR/user-data" | sed -e 's/[[:space:]].*//g') - case "$header" in - '#!'*) echo script;; - '#'*) echo ${header#\#};; - *) echo unknown;; - esac + if [ ! -f "$TINY_CLOUD_VAR/user-data" ]; then + echo missing + return + fi + header=$(head -n1 "$TINY_CLOUD_VAR/user-data" | sed -e 's/[[:space:]].*//g') + case "$header" in + '#!'*) echo script;; + '#'*) echo ${header#\#};; + *) echo unknown;; + esac } USERDATA_TYPE="$(userdata_type)" if [ -f "$LIBDIR/tiny-cloud/user-data/$USERDATA_TYPE" ]; then - . "$LIBDIR/tiny-cloud/user-data/$USERDATA_TYPE" + . "$LIBDIR/tiny-cloud/user-data/$USERDATA_TYPE" fi diff --git a/lib/tiny-cloud/mdev b/lib/tiny-cloud/mdev index fa8dc31..70e90dd 100644 --- a/lib/tiny-cloud/mdev +++ b/lib/tiny-cloud/mdev @@ -1,36 +1,36 @@ # Tiny Cloud - mdev hotplug functions -# vim:set ts=4 et ft=sh: +# vim:set ft=sh: # shellcheck shell=sh # generic helper function to install mdev rules install_before() { - local before="$1" - shift - local line="$*" + local before="$1" + shift + local line="$*" - # already installed - fgrep -q "$line" /etc/mdev.conf && return 0 + # already installed + fgrep -q "$line" /etc/mdev.conf && return 0 - if grep -q "$before" /etc/mdev.conf; then - # install before existing rule - line="-$line" - else - # no rule exists, put it before the catch-all fallback - before="^# fallback" - line="$line\n" - fi - sed -i -Ee "s|($before.*)|$line\n\1|" /etc/mdev.conf + if grep -q "$before" /etc/mdev.conf; then + # install before existing rule + line="-$line" + else + # no rule exists, put it before the catch-all fallback + before="^# fallback" + line="$line\n" + fi + sed -i -Ee "s|($before.*)|$line\n\1|" /etc/mdev.conf } # hotpluggable VNICs (multi-cloud) mod__vnic_eth_hotplug() { - [ -f /lib/mdev/vnic-eth-hotplug ] || return 1 + [ -f /lib/mdev/vnic-eth-hotplug ] || return 1 - install_before "^eth" \ - "eth[0-9] root:root 0644 */lib/mdev/vnic-eth-hotplug" + install_before "^eth" \ + "eth[0-9] root:root 0644 */lib/mdev/vnic-eth-hotplug" - # NICs attached at launch don't get added with mdev -s - assemble-interfaces + # NICs attached at launch don't get added with mdev -s + assemble-interfaces } # load cloud-specific functions diff --git a/lib/tiny-cloud/user-data/alpine-config b/lib/tiny-cloud/user-data/alpine-config index 3dcd64c..b4e0bd5 100644 --- a/lib/tiny-cloud/user-data/alpine-config +++ b/lib/tiny-cloud/user-data/alpine-config @@ -1,117 +1,117 @@ # Script UserData Functions -# vim:set ts=4 et ft=sh: +# vim:set ft=sh: # shellcheck shell=sh INIT_ACTIONS_MAIN="$(insert_after set_hostname \ - "userdata_bootcmd userdata_write_files userdata_ntp userdata_apk_cache userdata_apk_repositories userdata_packages" \ - $INIT_ACTIONS_MAIN)" + "userdata_bootcmd userdata_write_files userdata_ntp userdata_apk_cache userdata_apk_repositories userdata_packages" \ + $INIT_ACTIONS_MAIN)" INIT_ACTIONS_FINAL="$INIT_ACTIONS_FINAL userdata_runcmd" get_userdata() { - IFS="/" - yx -f "$TINY_CLOUD_VAR/user-data" $1 2>/dev/null - unset IFS + IFS="/" + yx -f "$TINY_CLOUD_VAR/user-data" $1 2>/dev/null + unset IFS } init__userdata_bootcmd() { - # run bootcmd - local bootcmds="$(get_userdata bootcmd)" - for i in $bootcmds; do - local cmd="$(get_userdata bootcmd/"$i")" - sh -c "$cmd" - done + # run bootcmd + local bootcmds="$(get_userdata bootcmd)" + for i in $bootcmds; do + local cmd="$(get_userdata bootcmd/"$i")" + sh -c "$cmd" + done } init__userdata_ntp() { - local ntp_enabled="$(get_userdata ntp/enabled)" - if [ "$ntp_enabled" != "yes" ] && [ "$ntp_enabled" != "true" ]; then - return - fi - local ntp_client="$(get_userdata ntp/ntp_client)" - local svc= pkg= - case "$ntp_client" in - busybox) - svc=ntpd - ;; - chrony|"") - pkg=chrony - svc=chronyd - ;; - openntpd) - pkg=openntpd - svc=openntpd - ;; - esac - if [ -n "$pkg" ]; then - $MOCK apk add "$pkg" - fi - if [ -n "$svc" ]; then - $MOCK rc-update add "$svc" default - $MOCK rc-service "$svc" start - fi + local ntp_enabled="$(get_userdata ntp/enabled)" + if [ "$ntp_enabled" != "yes" ] && [ "$ntp_enabled" != "true" ]; then + return + fi + local ntp_client="$(get_userdata ntp/ntp_client)" + local svc= pkg= + case "$ntp_client" in + busybox) + svc=ntpd + ;; + chrony|"") + pkg=chrony + svc=chronyd + ;; + openntpd) + pkg=openntpd + svc=openntpd + ;; + esac + if [ -n "$pkg" ]; then + $MOCK apk add "$pkg" + fi + if [ -n "$svc" ]; then + $MOCK rc-update add "$svc" default + $MOCK rc-service "$svc" start + fi } init__userdata_apk_cache() { - local cache="$(get_userdata apk/cache)" - if [ -z "$cache" ]; then - return - fi - mkdir -p "$ROOT/$cache" - # make link relative - case "$cache" in - /*) cache="../..$cache";; - esac - mkdir -p "$ROOT"/etc/apk - ln -sf "$cache" "$ROOT"/etc/apk/cache + local cache="$(get_userdata apk/cache)" + if [ -z "$cache" ]; then + return + fi + mkdir -p "$ROOT/$cache" + # make link relative + case "$cache" in + /*) cache="../..$cache";; + esac + mkdir -p "$ROOT"/etc/apk + ln -sf "$cache" "$ROOT"/etc/apk/cache } init__userdata_apk_cache() { - local cache="$(get_userdata apk/cache)" - if [ -z "$cache" ]; then - return - fi - mkdir -p "$ROOT/$cache" - # make link relative - case "$cache" in - /*) cache="../..$cache";; - esac - mkdir -p "$ROOT"/etc/apk - ln -sf "$cache" "$ROOT"/etc/apk/cache + local cache="$(get_userdata apk/cache)" + if [ -z "$cache" ]; then + return + fi + mkdir -p "$ROOT/$cache" + # make link relative + case "$cache" in + /*) cache="../..$cache";; + esac + mkdir -p "$ROOT"/etc/apk + ln -sf "$cache" "$ROOT"/etc/apk/cache } init__userdata_apk_repositories() { - local repositories="$(get_userdata apk/repositories)" - mkdir -p "$ROOT"/etc/apk - for r in $repositories; do - local baseurl="$(get_userdata apk/repositories/$r/base_url)" - local repos="$(get_userdata apk/repositories/$r/repos)" - local version="$(get_userdata apk/repositories/$r/version)" - if [ -z "$version" ]; then - local version_id=$( . "$ROOT"/etc/os-release 2>/dev/null && echo "$VERSION_ID") - case "$version_id" in - edge*|*_alpha*) version="edge";; - [0-9]*.[0-9]*.[0-9]*) version="v${version_id%.*}";; - esac - fi - if [ -n "$version" ] && [ "$version" != "." ] && [ "$version" != "/" ]; then - baseurl="${baseurl%/}/$version" - fi - for repo in $repos; do - local uri="${baseurl%/}/$(get_userdata apk/repositories/$r/repos/$repo)" - add_once "$ROOT"/etc/apk/repositories "$uri" - done - done + local repositories="$(get_userdata apk/repositories)" + mkdir -p "$ROOT"/etc/apk + for r in $repositories; do + local baseurl="$(get_userdata apk/repositories/$r/base_url)" + local repos="$(get_userdata apk/repositories/$r/repos)" + local version="$(get_userdata apk/repositories/$r/version)" + if [ -z "$version" ]; then + local version_id=$( . "$ROOT"/etc/os-release 2>/dev/null && echo "$VERSION_ID") + case "$version_id" in + edge*|*_alpha*) version="edge";; + [0-9]*.[0-9]*.[0-9]*) version="v${version_id%.*}";; + esac + fi + if [ -n "$version" ] && [ "$version" != "." ] && [ "$version" != "/" ]; then + baseurl="${baseurl%/}/$version" + fi + for repo in $repos; do + local uri="${baseurl%/}/$(get_userdata apk/repositories/$r/repos/$repo)" + add_once "$ROOT"/etc/apk/repositories "$uri" + done + done } init__userdata_packages() { - local packages="$(get_userdata packages)" - local pkgs= - for i in $packages; do - pkgs="$pkgs $(get_userdata packages/$i)" - done - if [ -n "$pkgs" ]; then - $MOCK apk add $pkgs - fi + local packages="$(get_userdata packages)" + local pkgs= + for i in $packages; do + pkgs="$pkgs $(get_userdata packages/$i)" + done + if [ -n "$pkgs" ]; then + $MOCK apk add $pkgs + fi } init__userdata_runcmd() { @@ -124,60 +124,60 @@ init__userdata_runcmd() { # write_file write_file() { - # Defaults used are the same as for full cloud-init "spec": - # https://cloudinit.readthedocs.io/en/latest/reference/modules.html#write-files - local path="$1" - local mode="${2:-0644}" - local owner="${3:-root:root}" - local encoding="${4:-text/plain}" - local append="${5:-false}" + # Defaults used are the same as for full cloud-init "spec": + # https://cloudinit.readthedocs.io/en/latest/reference/modules.html#write-files + local path="$1" + local mode="${2:-0644}" + local owner="${3:-root:root}" + local encoding="${4:-text/plain}" + local append="${5:-false}" - if [ "$append" != "true" ] && [ "$append" != "false" ]; then - log err "append must be true or false" - return - fi + if [ "$append" != "true" ] && [ "$append" != "false" ]; then + log err "append must be true or false" + return + fi - local tmpfile="$(mktemp $TINY_CLOUD_VAR/user-data.write_files.XXXXXX)" + local tmpfile="$(mktemp $TINY_CLOUD_VAR/user-data.write_files.XXXXXX)" - case "$encoding" in - gzip|gz|gz+base64|gzip+base64|gz+b64|gzip+b64) - base64 -d | gzip -d > "$tmpfile" - ;; - base64|b64) - base64 -d > "$tmpfile" - ;; - text/plain) - cat > "$tmpfile" - ;; - esac + case "$encoding" in + gzip|gz|gz+base64|gzip+base64|gz+b64|gzip+b64) + base64 -d | gzip -d > "$tmpfile" + ;; + base64|b64) + base64 -d > "$tmpfile" + ;; + text/plain) + cat > "$tmpfile" + ;; + esac - if [ "$append" = "true" ]; then - cat "$tmpfile" >> "$path" - else - cat "$tmpfile" > "$path" - fi - rm -f "$tmpfile" + if [ "$append" = "true" ]; then + cat "$tmpfile" >> "$path" + else + cat "$tmpfile" > "$path" + fi + rm -f "$tmpfile" - chmod "$mode" "$path" - # mocked as we do not know which users we could use in testing - # this way we can check the proper invocation at least - $MOCK chown "$owner" "$path" + chmod "$mode" "$path" + # mocked as we do not know which users we could use in testing + # this way we can check the proper invocation at least + $MOCK chown "$owner" "$path" } init__userdata_write_files() { - local files="$(get_userdata write_files)" + local files="$(get_userdata write_files)" - for i in $files; do - local path="$(get_userdata write_files/$i/path)" - if [ -z "$path" ]; then - continue - fi + for i in $files; do + local path="$(get_userdata write_files/$i/path)" + if [ -z "$path" ]; then + continue + fi - mkdir -p "$(dirname "$ROOT/$path")" - get_userdata write_files/$i/content | write_file "$ROOT/$path" \ - "$(get_userdata write_files/$i/permissions)" \ - "$(get_userdata write_files/$i/owner)" \ - "$(get_userdata write_files/$i/encoding)" \ - "$(get_userdata write_files/$i/append)" - done + mkdir -p "$(dirname "$ROOT/$path")" + get_userdata write_files/$i/content | write_file "$ROOT/$path" \ + "$(get_userdata write_files/$i/permissions)" \ + "$(get_userdata write_files/$i/owner)" \ + "$(get_userdata write_files/$i/encoding)" \ + "$(get_userdata write_files/$i/append)" + done } diff --git a/lib/tiny-cloud/user-data/cloud-config b/lib/tiny-cloud/user-data/cloud-config index 67afcaf..78bd42b 100644 --- a/lib/tiny-cloud/user-data/cloud-config +++ b/lib/tiny-cloud/user-data/cloud-config @@ -1,5 +1,5 @@ # CloudConfig UserData Functions -# vim:set ts=4 et ft=sh: +# vim:set ft=sh: # shellcheck shell=sh # TODO diff --git a/lib/tiny-cloud/user-data/missing b/lib/tiny-cloud/user-data/missing index 6eb4ab7..80f0ac2 100644 --- a/lib/tiny-cloud/user-data/missing +++ b/lib/tiny-cloud/user-data/missing @@ -1,9 +1,9 @@ # Missing UserData Functions -# vim:set ts=4 et ft=sh: +# vim:set ft=sh: # shellcheck shell=sh init__missing_userdata() { - log -i -t "$phase" notice "$ACTION: no user-data found" + log -i -t "$phase" notice "$ACTION: no user-data found" } INIT_ACTIONS_MAIN="missing_userdata ${INIT_ACTIONS_MAIN}" diff --git a/lib/tiny-cloud/user-data/script b/lib/tiny-cloud/user-data/script index b967582..7c94cf6 100644 --- a/lib/tiny-cloud/user-data/script +++ b/lib/tiny-cloud/user-data/script @@ -1,16 +1,16 @@ # Script UserData Functions -# vim:set ts=4 et ft=sh: +# vim:set ft=sh: # shellcheck shell=sh init__run_userdata() { - local log="$TINY_CLOUD_LOGS/user-data.log" - local exit="$TINY_CLOUD_LOGS/user-data.exit" - local userdata="$TINY_CLOUD_VAR/user-data" + local log="$TINY_CLOUD_LOGS/user-data.log" + local exit="$TINY_CLOUD_LOGS/user-data.exit" + local userdata="$TINY_CLOUD_VAR/user-data" - chmod u+x "$userdata" - { "$userdata" 2>& 1; echo $? > "$exit"; } | tee "$log" + chmod u+x "$userdata" + { "$userdata" 2>& 1; echo $? > "$exit"; } | tee "$log" - return $(cat "$exit") + return $(cat "$exit") } # add init actions diff --git a/lib/tiny-cloud/user-data/unknown b/lib/tiny-cloud/user-data/unknown index 3bf4c9b..6cfe4b7 100644 --- a/lib/tiny-cloud/user-data/unknown +++ b/lib/tiny-cloud/user-data/unknown @@ -1,10 +1,10 @@ # Unknown UserData Functions -# vim:set ts=4 et ft=sh: +# vim:set ft=sh: # shellcheck shell=sh init__unknown_userdata() { - local type="$(userdata_type)" - log -i -t "$phase" warn "$ACTION: unable to process '$type' user-data" + local type="$(userdata_type)" + log -i -t "$phase" warn "$ACTION: unable to process '$type' user-data" } INIT_ACTIONS_MAIN="unknown_userdata ${INIT_ACTIONS_MAIN}" diff --git a/sbin/assemble-interfaces b/sbin/assemble-interfaces index 6e43e7b..15b4cdc 100755 --- a/sbin/assemble-interfaces +++ b/sbin/assemble-interfaces @@ -1,5 +1,5 @@ #!/bin/sh -# vim:set ts=4 et: +# vim:set ft=sh: set -e @@ -10,33 +10,33 @@ cd "$IFACE_DIR" cat > "$IFACE_CFG.new" < "$IFACE" - printf "%s\n\n" "$(cat "$IFACE")" >> "$IFACE_CFG.new" - ;; - *) continue ;; - esac + IFACE="$(basename "$i")" + case $IFACE in + lo|eth*) + [ ! -f "$IFACE" ] && sed -e "s/%%/$IFACE/g" DEFAULT > "$IFACE" + printf "%s\n\n" "$(cat "$IFACE")" >> "$IFACE_CFG.new" + ;; + *) continue ;; + esac done # all the rest for i in "$IFACE_DIR"/*; do - IFACE="$(basename "$i")" - case $IFACE in - DEFAULT|lo|eth*) - continue - ;; - *) - printf "%s\n\n" "$(cat "$IFACE")" >> "$IFACE_CFG.new" - ;; - esac + IFACE="$(basename "$i")" + case $IFACE in + DEFAULT|lo|eth*) + continue + ;; + *) + printf "%s\n\n" "$(cat "$IFACE")" >> "$IFACE_CFG.new" + ;; + esac done # install new interfaces config diff --git a/sbin/imds-net-sync b/sbin/imds-net-sync index ddc14aa..af373fc 100755 --- a/sbin/imds-net-sync +++ b/sbin/imds-net-sync @@ -1,5 +1,5 @@ #!/bin/sh -# vim: ts=4 et ft=sh: +# vim:set ft=sh: # Sync interface's network configuration with IMDS @@ -21,129 +21,129 @@ let RTABLE+=10000 # ip [+F] [-4|-6] [] ip() { - local fail_ok v=-4 cmd level - [ "$1" = '+F' ] && fail_ok=1 && shift - if [ "$1" = '-4' ] || [ "$1" = '-6' ]; then - v="$1" - shift - fi - cmd="$2" - [ "$cmd" = show ] && level=debug || level=info - if /sbin/ip "$v" "$@" || [ -n "$fail_ok" ]; then - log -s "$level" "OK: ip $v $*" - else - log -s err "FAIL: ip $v $*" - fi + local fail_ok v=-4 cmd level + [ "$1" = '+F' ] && fail_ok=1 && shift + if [ "$1" = '-4' ] || [ "$1" = '-6' ]; then + v="$1" + shift + fi + cmd="$2" + [ "$cmd" = show ] && level=debug || level=info + if /sbin/ip "$v" "$@" || [ -n "$fail_ok" ]; then + log -s "$level" "OK: ip $v $*" + else + log -s err "FAIL: ip $v $*" + fi } # get secondary IPv4s currently on the interface iface_ip4s() { - ip -4 addr show "$IFACE" secondary | - sed -E -e '/inet /!d' -e 's/.*inet ([0-9.]+).*/\1/' + ip -4 addr show "$IFACE" secondary | + sed -E -e '/inet /!d' -e 's/.*inet ([0-9.]+).*/\1/' } # get IPv6s currently on the interface iface_ip6s() { - ip -6 addr show "$IFACE" scope global | - sed -E -e '/inet6/!d' -e 's/.*inet6 ([0-9a-f:]+).*/\1/' + ip -6 addr show "$IFACE" scope global | + sed -E -e '/inet6/!d' -e 's/.*inet6 ([0-9a-f:]+).*/\1/' } imds_ip4s() { - local ip4=$(imds "@nic:$IFACE,@ipv4") - local ip4s=$(echo "$ip4" | tail +2) # secondary IPv4s - local ip4p ip4_cidr ip4_gw + local ip4=$(imds "@nic:$IFACE,@ipv4") + local ip4s=$(echo "$ip4" | tail +2) # secondary IPv4s + local ip4p ip4_cidr ip4_gw - # non-eth0 interfaces need custom route tables - # - if [ "$IFACE" != eth0 ] && [ -n "$ip4s" ] && - [ -z $(ip +F -4 route show table "$RTABLE" 2>/dev/null) ]; then - ip4p=$(echo "$ip4" | head -1) # primary IPv4 - ip4_cidr=$(imds "@nic:$IFACE,@ipv4-net") # TODO: get from iface instead? - # TODO: this may not hold true for non-AWS clouds - ip4_gw=$(echo "$ip4_cidr" | cut -d/ -f1 | - awk -F. '{ print $1"."$2"."$3"."$4+1 }') - ip -4 route add default via "$ip4_gw" dev "$IFACE" table "$RTABLE" - ip -4 route add "$ip4_cidr" dev "$IFACE" proto kernel scope link \ - src "$ip4p" table "$RTABLE" - fi - echo "$ip4s" + # non-eth0 interfaces need custom route tables + # + if [ "$IFACE" != eth0 ] && [ -n "$ip4s" ] && + [ -z $(ip +F -4 route show table "$RTABLE" 2>/dev/null) ]; then + ip4p=$(echo "$ip4" | head -1) # primary IPv4 + ip4_cidr=$(imds "@nic:$IFACE,@ipv4-net") # TODO: get from iface instead? + # TODO: this may not hold true for non-AWS clouds + ip4_gw=$(echo "$ip4_cidr" | cut -d/ -f1 | + awk -F. '{ print $1"."$2"."$3"."$4+1 }') + ip -4 route add default via "$ip4_gw" dev "$IFACE" table "$RTABLE" + ip -4 route add "$ip4_cidr" dev "$IFACE" proto kernel scope link \ + src "$ip4p" table "$RTABLE" + fi + echo "$ip4s" } # TODO: 3.18+ when we use dhcpcd for ipv4 & ipv6, we only need to do secondary IPv6s # circle back and see how amazon-ec2-net-utils is handling everything these days imds_ip6s() { - local ip6s gw tries=20 - ip6s=$(imds "@nic:$IFACE,@ipv6") + local ip6s gw tries=20 + ip6s=$(imds "@nic:$IFACE,@ipv6") - # non-eth0 interfaces need custom route tables - # - # NOTE: busybox iproute2 doesn't do 'route show table' properly for IPv6, - # so iproute2-minimal package is required! - # - if [ "$IFACE" != eth0 ] && [ -n "$ip6s" ] && - [ -z $(ip +F -6 route show table "$RTABLE" 2>/dev/null) ]; then - while true; do - gw=$(ip -6 route show dev "$IFACE" default | awk '{ print $3 }') - [ -n "$gw" ] && break - let tries-- - if [ "$tries" -eq 0 ]; then - log -s warn "Unable to get IPv6 gateway RA after 10s" - break - fi - sleep 0.5 - done - ip -6 route add default via "$gw" dev "$IFACE" table "$RTABLE" - # TODO? match imds_ip4s() with ip -6 route add "ip6_cidr" dev "$IFACE" ... - fi - echo "$ip6s" + # non-eth0 interfaces need custom route tables + # + # NOTE: busybox iproute2 doesn't do 'route show table' properly for IPv6, + # so iproute2-minimal package is required! + # + if [ "$IFACE" != eth0 ] && [ -n "$ip6s" ] && + [ -z $(ip +F -6 route show table "$RTABLE" 2>/dev/null) ]; then + while true; do + gw=$(ip -6 route show dev "$IFACE" default | awk '{ print $3 }') + [ -n "$gw" ] && break + let tries-- + if [ "$tries" -eq 0 ]; then + log -s warn "Unable to get IPv6 gateway RA after 10s" + break + fi + sleep 0.5 + done + ip -6 route add default via "$gw" dev "$IFACE" table "$RTABLE" + # TODO? match imds_ip4s() with ip -6 route add "ip6_cidr" dev "$IFACE" ... + fi + echo "$ip6s" } in_list() { - echo "$2" | grep -q "^$1$" + echo "$2" | grep -q "^$1$" } # ip_addr {4|6} {add|del} ip_addr() { - local mask=32 # IPv4 always /32 - [ "$1" -eq 6 ] && mask=128 # IPv6 always /128 - ip -"$1" addr "$2" "$3/$mask" dev "$IFACE" + local mask=32 # IPv4 always /32 + [ "$1" -eq 6 ] && mask=128 # IPv6 always /128 + ip -"$1" addr "$2" "$3/$mask" dev "$IFACE" - # TODO? delegated ipv[46] prefixes? + # TODO? delegated ipv[46] prefixes? - # non-eth0 interfaces get rules associating IPs with route tables - [ "$IFACE" = eth0 ] && return - ip -"$1" rule "$2" from "$3" lookup "$RTABLE" - ip -"$1" rule "$2" to "$3" lookup "$RTABLE" + # non-eth0 interfaces get rules associating IPs with route tables + [ "$IFACE" = eth0 ] && return + ip -"$1" rule "$2" from "$3" lookup "$RTABLE" + ip -"$1" rule "$2" to "$3" lookup "$RTABLE" } # sync_ips {4|6} "" "" sync_ips() { - local i - # remove extra IPs - for i in $3; do - in_list "$i" "$2" || ip_addr "$1" del "$i" - done - # add missing IPs - # NOTE: this adds an extra /32 for the primary IP - for i in $2; do - in_list "$i" "$3" || ip_addr "$1" add "$i" - done + local i + # remove extra IPs + for i in $3; do + in_list "$i" "$2" || ip_addr "$1" del "$i" + done + # add missing IPs + # NOTE: this adds an extra /32 for the primary IP + for i in $2; do + in_list "$i" "$3" || ip_addr "$1" add "$i" + done } imds_iface_sync() { - log -s info "SYNCING: $IFACE" - sync_ips 4 "$(imds_ip4s)" "$(iface_ip4s)" - sync_ips 6 "$(imds_ip6s)" "$(iface_ip6s)" - log -s info "FINISHED: $IFACE" + log -s info "SYNCING: $IFACE" + sync_ips 4 "$(imds_ip4s)" "$(iface_ip4s)" + sync_ips 6 "$(imds_ip6s)" "$(iface_ip6s)" + log -s info "FINISHED: $IFACE" } case "$PHASE" in - post-up) - # TODO: daemonize this - imds_iface_sync - ;; - pre-down) - # TODO: kill daemon, maybe some cleanup - ;; - *) + post-up) + # TODO: daemonize this + imds_iface_sync + ;; + pre-down) + # TODO: kill daemon, maybe some cleanup + ;; + *) esac diff --git a/sbin/tiny-cloud b/sbin/tiny-cloud index 3b5c7df..a95f787 100755 --- a/sbin/tiny-cloud +++ b/sbin/tiny-cloud @@ -1,5 +1,5 @@ #!/bin/sh -# vim:set ts=4 et ft=sh: +# vim:set ft=sh: # Tiny Cloud @@ -9,69 +9,69 @@ set -e . "$LIBDIR/tiny-cloud/common" usage() { - cat <&2; exit 1; } if [ $# -eq 0 ]; then - usage >&2 - exit 1 + usage >&2 + exit 1 fi eval set -- "$args" while true; do - case "$1" in - -h|--help) usage; exit 0;; - -b|--bootstrap) shift - case "$1" in - complete) # indicate bootstrap is done - bootstrap_complete - log -i notice 'bootstrap marked complete';; - incomplete) # indicate bootstrap isn't done - bootstrap_incomplete - log -i warn 'bootstrap marked incomplete';; - status) is_bootstrap_complete && echo 'complete' || echo 'incomplete' ;; - *) usage >&2; exit 1;; - esac - exit 0;; - -s|--setup) # just openrc for now - for phase in -early -net '' -final; do - rc-update -a del "tiny-cloud$phase" || true - done - rc-update add tiny-cloud-early boot - rc-update add tiny-cloud-net default - rc-update add tiny-cloud default - rc-update add tiny-cloud-final default - exit 0;; - --) shift; break;; - *) usage >&2; exit 1;; - esac - shift + case "$1" in + -h|--help) usage; exit 0;; + -b|--bootstrap) shift + case "$1" in + complete) # indicate bootstrap is done + bootstrap_complete + log -i notice 'bootstrap marked complete';; + incomplete) # indicate bootstrap isn't done + bootstrap_incomplete + log -i warn 'bootstrap marked incomplete';; + status) is_bootstrap_complete && echo 'complete' || echo 'incomplete' ;; + *) usage >&2; exit 1;; + esac + exit 0;; + -s|--setup) # just openrc for now + for phase in -early -net '' -final; do + rc-update -a del "tiny-cloud$phase" || true + done + rc-update add tiny-cloud-early boot + rc-update add tiny-cloud-net default + rc-update add tiny-cloud default + rc-update add tiny-cloud-final default + exit 0;; + --) shift; break;; + *) usage >&2; exit 1;; + esac + shift done phase="$1" shift case "$phase" in - early|net|main|final) ;; - *) usage >&2; exit 1;; + early|net|main|final) ;; + *) usage >&2; exit 1;; esac # is initial bootstrap already done? if is_bootstrap_complete; then - log -i -t "$phase" info "already bootstrapped" - exit 0; + log -i -t "$phase" info "already bootstrapped" + exit 0; fi # load init functions @@ -81,48 +81,48 @@ fi # should we skip this action? skip_action() { - local action="$1" - for i in $SKIP_INIT_ACTIONS; do - [ "$i" = "$action" ] && return 0 - done - return 1 + local action="$1" + for i in $SKIP_INIT_ACTIONS; do + [ "$i" = "$action" ] && return 0 + done + return 1 } # mandatory final action... init__bootstrap_complete() { - bootstrap_complete + bootstrap_complete } INIT_ACTIONS_FINAL="${INIT_ACTIONS_FINAL} bootstrap_complete" ### let's do stuff! case "$phase" in - early) INIT_ACTIONS="$INIT_ACTIONS_EARLY";; - net) INIT_ACTIONS="$INIT_ACTIONS_NET";; - main) INIT_ACTIONS="$INIT_ACTIONS_MAIN";; - final) INIT_ACTIONS="$INIT_ACTIONS_FINAL";; - *) usage >&2; exit 1 + early) INIT_ACTIONS="$INIT_ACTIONS_EARLY";; + net) INIT_ACTIONS="$INIT_ACTIONS_NET";; + main) INIT_ACTIONS="$INIT_ACTIONS_MAIN";; + final) INIT_ACTIONS="$INIT_ACTIONS_FINAL";; + *) usage >&2; exit 1 esac printf '\n' >&2 for ACTION in $INIT_ACTIONS; do - if skip_action "$ACTION"; then - printf ' -- ' >&2 - log -i -t "$phase" notice "$ACTION: skipped" - continue - fi - printf ' ++ ' >&2 - log -i -t "$phase" info "$ACTION: starting" - RESULT="unknown" - LEVEL="err" - if type "init__$ACTION" | grep -q -w "function"; then - if "init__$ACTION" "$@"; then - RESULT="done" - LEVEL="info" - else - RESULT="failed" - fi - fi - printf ' ++ ' >&2 - log -i -t "$phase" "$LEVEL" "$ACTION: $RESULT" + if skip_action "$ACTION"; then + printf ' -- ' >&2 + log -i -t "$phase" notice "$ACTION: skipped" + continue + fi + printf ' ++ ' >&2 + log -i -t "$phase" info "$ACTION: starting" + RESULT="unknown" + LEVEL="err" + if type "init__$ACTION" | grep -q -w "function"; then + if "init__$ACTION" "$@"; then + RESULT="done" + LEVEL="info" + else + RESULT="failed" + fi + fi + printf ' ++ ' >&2 + log -i -t "$phase" "$LEVEL" "$ACTION: $RESULT" done diff --git a/tests/assemble-interfaces.test b/tests/assemble-interfaces.test index e916374..64343eb 100755 --- a/tests/assemble-interfaces.test +++ b/tests/assemble-interfaces.test @@ -1,4 +1,5 @@ #!/usr/bin/env atf-sh +# vim:set ft=sh # shellcheck shell=sh . $(atf_get_srcdir)/test_env.sh diff --git a/tests/bin/wget b/tests/bin/wget index dafac90..9961d0a 100755 --- a/tests/bin/wget +++ b/tests/bin/wget @@ -2,27 +2,27 @@ prog=${0##*/} usage() { - cat <