1
0
mirror of https://gitlab.alpinelinux.org/alpine/cloud/tiny-cloud.git synced 2025-12-14 19:02:45 +03:00

Add support for write_files instructions

This commit is contained in:
Jussi Nummelin 2023-05-18 13:31:11 +00:00 committed by Jake Buchholz Göktürk
parent b63ffb71d0
commit 7d9a280a67
2 changed files with 148 additions and 16 deletions

View File

@ -3,25 +3,31 @@
# shellcheck shell=sh # shellcheck shell=sh
INIT_ACTIONS_MAIN="$(insert_after set_hostname \ INIT_ACTIONS_MAIN="$(insert_after set_hostname \
"userdata_bootcmd userdata_ntp userdata_apk_cache userdata_apk_repositories userdata_packages" \ "userdata_bootcmd userdata_write_files userdata_ntp userdata_apk_cache userdata_apk_repositories userdata_packages" \
$INIT_ACTIONS_MAIN)" $INIT_ACTIONS_MAIN)"
INIT_ACTIONS_FINAL="$INIT_ACTIONS_FINAL userdata_runcmd" INIT_ACTIONS_FINAL="$INIT_ACTIONS_FINAL userdata_runcmd"
get_userdata() {
IFS="/"
yx -f "$TINY_CLOUD_VAR/user-data" $1 2>/dev/null
unset IFS
}
init__userdata_bootcmd() { init__userdata_bootcmd() {
# run bootcmd # run bootcmd
local bootcmds="$(imds user-data/bootcmd)" local bootcmds="$(get_userdata bootcmd)"
for i in $bootcmds; do for i in $bootcmds; do
local cmd="$(imds user-data/bootcmd/"$i")" local cmd="$(get_userdata bootcmd/"$i")"
sh -c "$cmd" sh -c "$cmd"
done done
} }
init__userdata_ntp() { init__userdata_ntp() {
local ntp_enabled="$(imds user-data/ntp/enabled)" local ntp_enabled="$(get_userdata ntp/enabled)"
if [ "$ntp_enabled" != "yes" ] && [ "$ntp_enabled" != "true" ]; then if [ "$ntp_enabled" != "yes" ] && [ "$ntp_enabled" != "true" ]; then
return return
fi fi
local ntp_client="$(imds user-data/ntp/ntp_client)" local ntp_client="$(get_userdata ntp/ntp_client)"
local svc= pkg= local svc= pkg=
case "$ntp_client" in case "$ntp_client" in
busybox) busybox)
@ -46,7 +52,7 @@ init__userdata_ntp() {
} }
init__userdata_apk_cache() { init__userdata_apk_cache() {
local cache="$(imds user-data/apk/cache)" local cache="$(get_userdata apk/cache)"
if [ -z "$cache" ]; then if [ -z "$cache" ]; then
return return
fi fi
@ -60,7 +66,7 @@ init__userdata_apk_cache() {
} }
init__userdata_apk_cache() { init__userdata_apk_cache() {
local cache="$(imds user-data/apk/cache)" local cache="$(get_userdata apk/cache)"
if [ -z "$cache" ]; then if [ -z "$cache" ]; then
return return
fi fi
@ -74,12 +80,12 @@ init__userdata_apk_cache() {
} }
init__userdata_apk_repositories() { init__userdata_apk_repositories() {
local repositories="$(imds user-data/apk/repositories)" local repositories="$(get_userdata apk/repositories)"
mkdir -p "$ROOT"/etc/apk mkdir -p "$ROOT"/etc/apk
for r in $repositories; do for r in $repositories; do
local baseurl="$(imds user-data/apk/repositories/$r/base_url)" local baseurl="$(get_userdata apk/repositories/$r/base_url)"
local repos="$(imds user-data/apk/repositories/$r/repos)" local repos="$(get_userdata apk/repositories/$r/repos)"
local version="$(imds user-data/apk/repositories/$r/version)" local version="$(get_userdata apk/repositories/$r/version)"
if [ -z "$version" ]; then if [ -z "$version" ]; then
local version_id=$( . "$ROOT"/etc/os-release 2>/dev/null && echo "$VERSION_ID") local version_id=$( . "$ROOT"/etc/os-release 2>/dev/null && echo "$VERSION_ID")
case "$version_id" in case "$version_id" in
@ -91,17 +97,17 @@ init__userdata_apk_repositories() {
baseurl="${baseurl%/}/$version" baseurl="${baseurl%/}/$version"
fi fi
for repo in $repos; do for repo in $repos; do
local uri="${baseurl%/}/$(imds user-data/apk/repositories/$r/repos/$repo)" local uri="${baseurl%/}/$(get_userdata apk/repositories/$r/repos/$repo)"
add_once "$ROOT"/etc/apk/repositories "$uri" add_once "$ROOT"/etc/apk/repositories "$uri"
done done
done done
} }
init__userdata_packages() { init__userdata_packages() {
local packages="$(imds user-data/packages)" local packages="$(get_userdata packages)"
local pkgs= local pkgs=
for i in $packages; do for i in $packages; do
pkgs="$pkgs $(imds user-data/packages/$i)" pkgs="$pkgs $(get_userdata packages/$i)"
done done
if [ -n "$pkgs" ]; then if [ -n "$pkgs" ]; then
$MOCK apk add $pkgs $MOCK apk add $pkgs
@ -109,9 +115,69 @@ init__userdata_packages() {
} }
init__userdata_runcmd() { init__userdata_runcmd() {
local runcmds="$(imds user-data/runcmd)" local runcmds="$(get_userdata runcmd)"
for i in $runcmds; do for i in $runcmds; do
local cmd="$(imds user-data/runcmd/$i)" local cmd="$(get_userdata runcmd/$i)"
sh -c "$cmd" sh -c "$cmd"
done done
} }
# write_file <path> <mode> <owner> <encoding> <append>
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}"
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)"
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"
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)"
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
}

View File

@ -12,6 +12,7 @@ init_tests \
set_network_config_network_interfaces \ set_network_config_network_interfaces \
set_network_config_auto \ set_network_config_auto \
userdata_bootcmd \ userdata_bootcmd \
userdata_write_files \
userdata_ntp \ userdata_ntp \
userdata_ntp_busybox \ userdata_ntp_busybox \
userdata_ntp_openntpd \ userdata_ntp_openntpd \
@ -240,3 +241,68 @@ userdata_runcmd_body() {
-o match:"^foo$" -o match:"^bar$" \ -o match:"^foo$" -o match:"^bar$" \
tiny-cloud final tiny-cloud final
} }
userdata_write_files_body() {
fake_userdata_nocloud <<-EOF
#alpine-config
write_files:
- path: /etc/motd
content: |
Hello world
- path: /etc/foo
encoding: text/plain
permissions: '0755'
content: |
Hello world
- path: /etc/bar
owner: foo:bar
content: |
Hello world
- path: /etc/gzipped
encoding: gzip
content: !!binary |
H4sIAAAAAAAAA/NIzcnJVyjPL8pJ4QIA1eA5twwAAAA=
- path: /foo/bar/hello
content: |
Hello world
- path: /foo/bar/appended
content: |
Hello
- path: /foo/bar/appended
append: true
content: |
world
EOF
# fetch user-data
atf_check -e ignore -o ignore tiny-cloud net
atf_check \
-e match:"userdata_write_files: done" \
-o match:"chown foo:bar.*etc/bar" \
-o match:"chown root:root.*etc/motd" \
tiny-cloud main
if [ "$(cat etc/motd)" != "Hello world" ]; then
atf_fail "content of etc/motd was not 'Hello world'"
fi
# check that etc/motd permissions are the defaults
atf_check -o match:"644" stat -c %a etc/motd
if [ "$(cat etc/foo)" != "Hello world" ]; then
atf_fail "content of etc/foo was not 'Hello world'"
fi
atf_check -o match:"755" stat -c %a etc/foo
if [ "$(cat etc/gzipped)" != "Hello world" ]; then
atf_fail "content of etc/foo was not 'Hello world'"
fi
if [ "$(cat foo/bar/hello)" != "Hello world" ]; then
atf_fail "content of foo/bar/hello was not 'Hello world'"
fi
atf_check diff -u foo/bar/appended - <<-EOF
Hello
world
EOF
}