diff --git a/README.md b/README.md index b18f1a0..303ccf5 100644 --- a/README.md +++ b/README.md @@ -105,21 +105,20 @@ any necessary `mdev` rules for device hotplug are set up. ### Main Phase The main `tiny-cloud` init script *does* depend on the cloud provider's IMDS -data, and sets up instance's hostname and the cloud user's SSH keys before -`sshd` starts. - -### Final Phase - -`tiny-cloud-final` should be the very last init script to run in the -**default** runlevel. By default, it saves the instance's user data to -`/var/lib/cloud/user-data`; the directory overrideable via the `TINY_CLOUD_VAR` -config setting. +data; it saves the instance's user data to `/var/lib/cloud/user-data`, sets up +instance's hostname, and installs the cloud user's SSH keys before `sshd` +starts. If the user data is compressed, Tiny Cloud will decompress it. Currently supported compression algorithms are `gzip`, `bzip2`, `unxz`, `lzma`, `lzop`, `lz4`, and `zstd`. _(Note that `lz4` and `zstd` are not installed in Alpine by default, and would need to be added to the image.)_ +### Final Phase + +`tiny-cloud-final` should be the very last init script to run in the +**default** runlevel. + If the user data is a script starting with `#!/`, it will be executed; its output (combined STDOUT and STDERR) and exit code are saved to `/var/log/user-data.log` and `/var/log/user-data.exit`, respectively; the @@ -144,10 +143,14 @@ To force the init scripts to re-run on the next boot... ``` rm -f /var/lib/cloud/.bootstrap-complete ``` +or +``` +service tiny-cloud incomplete +``` If you're instantiating an instance in order to create a new cloud image (using [Packer](https://packer.io), or some other means), you will need to -remove this file before creating the image to ensure that instances using the -new image will also run Tiny Cloud init scripts during their first boot. +do this before creating the image to ensure that instances using the new +image will also run Tiny Cloud init scripts during their first boot. ## Cloud Hotplug Modules diff --git a/etc/init.d/tiny-cloud b/etc/init.d/tiny-cloud index 6155f3a..96d5239 100755 --- a/etc/init.d/tiny-cloud +++ b/etc/init.d/tiny-cloud @@ -2,6 +2,9 @@ # vim:set ts=8 noet ft=sh: description="Tiny Cloud Bootstrap - main phase" +extra_commands="complete incomplete" + +source /lib/tiny-cloud/init-main depend() { need net @@ -9,10 +12,13 @@ depend() { } start() { - source /lib/tiny-cloud/init-main is_bootstrapped && return 0 + ebegin "Saving Instance UserData" + save_userdata + eend $? + ebegin "Setting Instance Hostname" set_hostname eend $? @@ -20,4 +26,8 @@ start() { ebegin "Installing SSH Keys for $CLOUD_USER User" set_ssh_keys "$CLOUD_USER" eend $? -} \ No newline at end of file +} + +# allow setting / unsetting of bootstrap state +complete() { bootstrap_complete ; } +incomplete() { bootstrap_incomplete ; } diff --git a/etc/init.d/tiny-cloud-final b/etc/init.d/tiny-cloud-final index 24f1b43..fce3061 100755 --- a/etc/init.d/tiny-cloud-final +++ b/etc/init.d/tiny-cloud-final @@ -13,10 +13,6 @@ start() { is_bootstrapped && return 0 - ebegin "Saving Instance UserData" - save_userdata - eend $? - if is_userdata_script; then ebegin "Executing UserData Script" run_userdata diff --git a/lib/tiny-cloud/aws/imds b/lib/tiny-cloud/aws/imds index 3ade15f..b86de21 100644 --- a/lib/tiny-cloud/aws/imds +++ b/lib/tiny-cloud/aws/imds @@ -3,7 +3,7 @@ IMDS_HEADER="X-aws-ec2-metadata-token" IMDS_TOKEN_TTL_HEADER="X-aws-ec2-metadata-token-ttl-seconds" -IMDS_TOKEN_TTL=${IMDS_TOKEN_TTL:-5} +: "${IMDS_TOKEN_TTL:=5}" IMDS_URI="latest" _imds_token() { diff --git a/lib/tiny-cloud/common b/lib/tiny-cloud/common index 6848209..dcc72aa 100644 --- a/lib/tiny-cloud/common +++ b/lib/tiny-cloud/common @@ -3,17 +3,17 @@ # set defaults [ -f /etc/conf.d/tiny-cloud ] && source /etc/conf.d/tiny-cloud -CLOUD="${CLOUD:-unknown}" -CLOUD_USER=${CLOUD_USER:-alpine} -TINY_CLOUD_LOGS=${TINY_CLOUD_LOGS:-/var/log} -TINY_CLOUD_VAR=${TINY_CLOUD_VAR:-/var/lib/cloud} +: "${CLOUD:=unknown}" +: "${CLOUD_USER:=alpine}" +: "${TINY_CLOUD_LOGS:=/var/log}" +: "${TINY_CLOUD_VAR:=/var/lib/cloud}" log() { local facility="kern" local stderr local tag=$(basename "$0") while [ "${1:0:1}" = '-' ]; do - case "$1" in + case "$1" in -f) facility="$2"; shift ;; -s) stderr=-s ;; -t) tag="$tag/$2"; shift ;; diff --git a/lib/tiny-cloud/init-common b/lib/tiny-cloud/init-common index 90f8af9..d19d27b 100644 --- a/lib/tiny-cloud/init-common +++ b/lib/tiny-cloud/init-common @@ -3,14 +3,17 @@ # set defaults source /lib/tiny-cloud/common -SKIP_INIT_ACTIONS=${SKIP_INIT_ACTIONS:-} +: "${SKIP_INIT_ACTIONS:=}" # is initial bootstrap already done? -is_bootstrapped() { [ -f "$TINY_CLOUD_VAR"/.bootstrap-complete ]; } +is_bootstrapped() { [ -f "$TINY_CLOUD_VAR"/.bootstrap-complete ] ; } # indicate bootstrap is done bootstrap_complete() { touch "$TINY_CLOUD_VAR"/.bootstrap-complete ; } +# indicate bootstrap isn't done +bootstrap_incomplete() { rm -f "$TINY_CLOUD_VAR"/.bootstrap-complete ; } + # should we skip this action? skip_action() { local action="$1" diff --git a/lib/tiny-cloud/init-early b/lib/tiny-cloud/init-early index e490e9e..0728861 100644 --- a/lib/tiny-cloud/init-early +++ b/lib/tiny-cloud/init-early @@ -41,5 +41,4 @@ install_hotplugs() { done } -HOTPLUG_TYPE=${HOTPLUG_TYPE:-mdev} -[ -f /lib/tiny-cloud/"$HOTPLUG_TYPE" ] && source /lib/tiny-cloud/"$HOTPLUG_TYPE" +[ -f /lib/tiny-cloud/"${HOTPLUG_TYPE:=mdev}" ] && source /lib/tiny-cloud/"$HOTPLUG_TYPE" diff --git a/lib/tiny-cloud/init-final b/lib/tiny-cloud/init-final index 5cd2ab8..1b50934 100644 --- a/lib/tiny-cloud/init-final +++ b/lib/tiny-cloud/init-final @@ -8,36 +8,6 @@ match_header() { [ "$bytes" = "$(dd bs=1 count=${#bytes} if="$2" 2>/dev/null)" ] } -save_userdata() { - skip_action save_userdata && return - - local userdata="$TINY_CLOUD_VAR/user-data" - local tmpfile=$(mktemp "$userdata.XXXXXX") - local cmd - - imds -e @userdata > "$tmpfile" - cmd="cat" - if ! skip_action decompress_userdata; then - if match_header '\037\213\010' "$tmpfile"; then - cmd="gzip -dc" - elif match_header 'BZh' "$tmpfile"; then - cmd="bzip2 -dc" - elif match_header '\3757zXZ\000' "$tmpfile"; then - cmd="unxz -c" - elif match_header '\135\0\0\0' "$tmpfile"; then - cmd="lzma -dc" - elif match_header '\211\114\132' "$tmpfile"; then - cmd="lzop -dc" - elif match_header '\002!L\030' "$tmpfile"; then - cmd="lz4 -dc" - elif match_header '(\265/\375' "$tmpfile"; then - cmd="zstd -dc" - fi - fi - $cmd "$tmpfile" > "$userdata" - rm "$tmpfile" -} - is_userdata_script() { head -n1 "$TINY_CLOUD_VAR/user-data" | grep -q "#!/" } diff --git a/lib/tiny-cloud/init-main b/lib/tiny-cloud/init-main index 2f2e44c..26300e4 100644 --- a/lib/tiny-cloud/init-main +++ b/lib/tiny-cloud/init-main @@ -36,4 +36,34 @@ set_ssh_keys() { chmod 600 "$keys_file" chown -R "$user:$group" "$ssh_dir" imds @ssh-keys > "$keys_file" -} \ No newline at end of file +} + +save_userdata() { + skip_action save_userdata && return + + local userdata="$TINY_CLOUD_VAR/user-data" + local tmpfile=$(mktemp "$userdata.XXXXXX") + local cmd + + imds -e @userdata > "$tmpfile" + cmd="cat" + if ! skip_action decompress_userdata; then + if match_header '\037\213\010' "$tmpfile"; then + cmd="gzip -dc" + elif match_header 'BZh' "$tmpfile"; then + cmd="bzip2 -dc" + elif match_header '\3757zXZ\000' "$tmpfile"; then + cmd="unxz -c" + elif match_header '\135\0\0\0' "$tmpfile"; then + cmd="lzma -dc" + elif match_header '\211\114\132' "$tmpfile"; then + cmd="lzop -dc" + elif match_header '\002!L\030' "$tmpfile"; then + cmd="lz4 -dc" + elif match_header '(\265/\375' "$tmpfile"; then + cmd="zstd -dc" + fi + fi + $cmd "$tmpfile" > "$userdata" + rm "$tmpfile" +} diff --git a/sbin/imds-net-sync b/sbin/imds-net-sync index a6db02c..00b220c 100755 --- a/sbin/imds-net-sync +++ b/sbin/imds-net-sync @@ -7,13 +7,12 @@ source /lib/tiny-cloud/common -IFACE=${IFACE:-unknown} -[ "$IFACE" = unknown ] && log -s crit "IFACE not set, aborting" +[ "${IFACE:=unknown}" = unknown ] && log -s crit "IFACE not set, aborting" # kill interface's imds-net-sync daemon -[ "$1" = '-k' ] && PHASE=pre=down && shift +[ "$1" = '-k' ] && PHASE=pre-down && shift -PHASE=${PHASE:-post-up} +: "${PHASE:=post-up}" # route table number RTABLE=${IFACE#eth}