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

Add kyua testsuite and make code more portable

This commit is contained in:
Natanael Copa 2023-03-08 03:39:39 +00:00 committed by Jake Buchholz Göktürk
parent 39670c091c
commit c335944911
21 changed files with 243 additions and 59 deletions

1
.gitignore vendored
View File

@ -2,3 +2,4 @@
*.bak *.bak
*.swp *.swp
.vscode/ .vscode/
Kyuafile

33
.gitlab-ci.yml Normal file
View File

@ -0,0 +1,33 @@
test-default:
image: alpine:latest
stage: test
script:
- apk add make kyua yx
- make -j $(nproc) check
tags:
- docker-alpine
- x86_64
test-dash:
extends: test-default
before_script:
- apk add dash
- ln -sf /usr/bin/dash /bin/sh
test-oksh:
extends: test-default
before_script:
- apk add oksh
- ln -sf /bin/oksh /bin/sh
test-yash:
extends: test-default
before_script:
- apk add yash
- ln -sf /usr/bin/yash /bin/sh
test-zsh:
extends: test-default
before_script:
- apk add zsh
- ln -sf /bin/zsh /bin/sh

View File

@ -2,7 +2,7 @@ PREFIX?=/
SUBPACKAGES = core network openrc aws azure gcp oci nocloud SUBPACKAGES = core network openrc aws azure gcp oci nocloud
.PHONY: install $(SUBPACKAGES) .PHONY: check install $(SUBPACKAGES)
install: $(SUBPACKAGES) install: $(SUBPACKAGES)
@ -52,3 +52,21 @@ oci:
nocloud: nocloud:
install -Dm644 -t $(PREFIX)/lib/tiny-cloud/nocloud \ install -Dm644 -t $(PREFIX)/lib/tiny-cloud/nocloud \
lib/tiny-cloud/nocloud/* lib/tiny-cloud/nocloud/*
check: tests/Kyuafile Kyuafile
kyua test || (kyua report --verbose && exit 1)
tests/Kyuafile: $(wildcard tests/*.test)
echo "syntax(2)" > $@.tmp
echo "test_suite('tiny-cloud')" >> $@.tmp
for i in $(notdir $(wildcard tests/*.test)); do \
echo "atf_test_program{name='$$i',timeout=5}" >> $@.tmp ; \
done
mv $@.tmp $@
Kyuafile:
echo "syntax(2)" > $@.tmp
echo "test_suite('tiny-cloud')" >> $@.tmp
echo "include('tests/Kyuafile')" >> $@.tmp
mv $@.tmp $@

View File

@ -5,7 +5,34 @@
### configuration, common functions ### configuration, common functions
source /lib/tiny-cloud/common : "${LIBDIR:=$PREFIX/lib}"
. "$LIBDIR"/tiny-cloud/common
if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
cat <<EOT
Usage: imds [-h] { -e | +e | +n | +s | +t | @<alias> | <imds-path> } ...
-h : help
-e / +e : ignore / catch errors
+n / +s / +t : insert newline / space / tab
<alias> :-
hostname : instance hostname
ssh-keys : instance SSH keys
userdata : instance user data
nics : instance NICs
nic:<iface>[,<nic-key> ...] : specific NIC interface
<iface> : network interface (i.e. eth1)
<nic-key> :- { -e | +e | +n | +s | +t | @<nic-alias> | <nic-path> }
<nic-alias> :-
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 ### cloud-specific variables/functions
@ -57,20 +84,15 @@ _imds_nic_index() { cat "/sys/class/net/$1/address"; }
### load cloud-specific variables and functions ### load cloud-specific variables and functions
if [ ! -d /lib/tiny-cloud/"$CLOUD" ]; then if [ ! -d "$LIBDIR"/tiny-cloud/"$CLOUD" ]; then
echo "ERROR: Unknown Cloud '$CLOUD'" >&2 echo "ERROR: Unknown Cloud '$CLOUD'" >&2
exit 1
fi fi
source /lib/tiny-cloud/"$CLOUD"/imds . "$LIBDIR"/tiny-cloud/"$CLOUD"/imds
### non-overrideable functions ### non-overrideable functions
imds() { imds() {
local cmd args key rv err=1 local cmd args key rv err=1
if [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
_imds_help
return
fi
while [ -n "$1" ]; do while [ -n "$1" ]; do
cmd=_imds cmd=_imds
args= args=
@ -129,30 +151,4 @@ _imds_nic_args() {
done done
} }
_imds_help() {
cat <<EOT
Usage: imds [-h] { -e | +e | +n | +s | +t | @<alias> | <imds-path> } ...
-h : help
-e / +e : ignore / catch errors
+n / +s / +t : insert newline / space / tab
<alias> :-
hostname : instance hostname
ssh-keys : instance SSH keys
userdata : instance user data
nics : instance NICs
nic:<iface>[,<nic-key> ...] : specific NIC interface
<iface> : network interface (i.e. eth1)
<nic-key> :- { -e | +e | +n | +s | +t | @<nic-alias> | <nic-path> }
<nic-alias> :-
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
}
imds "$@" imds "$@"

View File

@ -4,7 +4,8 @@
description="Tiny Cloud Bootstrap - main phase" description="Tiny Cloud Bootstrap - main phase"
extra_commands="complete incomplete" extra_commands="complete incomplete"
source /lib/tiny-cloud/init-main : "${LIBDIR:=$PREFIX/lib}"
. "$LIBDIR"/tiny-cloud/init-main
depend() { depend() {
need net need net

View File

@ -3,12 +3,14 @@
description="Tiny Cloud Bootstrap - early phase" description="Tiny Cloud Bootstrap - early phase"
: "${LIBDIR:=$PREFIX/lib}"
depend() { depend() {
before mdev before mdev
} }
start() { start() {
source /lib/tiny-cloud/init-early . "$LIBDIR"/tiny-cloud/init-early
is_bootstrapped && return 0 is_bootstrapped && return 0

View File

@ -3,13 +3,15 @@
description="Tiny Cloud Bootstrap - final phase" description="Tiny Cloud Bootstrap - final phase"
: "${LIBDIR:=$PREFIX/lib}"
depend() { depend() {
after * after *
provide cloud-final provide cloud-final
} }
start() { start() {
source /lib/tiny-cloud/init-final . "$LIBDIR"/tiny-cloud/init-final
is_bootstrapped && return 0 is_bootstrapped && return 0

View File

@ -1,7 +1,8 @@
#!/bin/sh #!/bin/sh
# vim:set ts=2 et: # vim:set ts=2 et:
source /lib/tiny-cloud/common : "${LIBDIR:=$PREFIX/lib}"
. "$LIBDIR"/tiny-cloud/common
# nvme tool not installed? # nvme tool not installed?
[ -x /usr/sbin/nvme ] || log crit "nvme cli not installed" [ -x /usr/sbin/nvme ] || log crit "nvme cli not installed"

View File

@ -3,7 +3,8 @@
set -e set -e
source /lib/tiny-cloud/common : "${LIBDIR:=$PREFIX/lib}"
. "$LIBDIR"/tiny-cloud/common
if [ -z "$MDEV" ] || [ -z "$ACTION" ]; then if [ -z "$MDEV" ] || [ -z "$ACTION" ]; then
log crit "MDEV or ACTION undefined, aborting" log crit "MDEV or ACTION undefined, aborting"

View File

@ -2,17 +2,17 @@
# vim: ts=4 et ft=sh: # vim: ts=4 et ft=sh:
# set defaults # set defaults
[ -f /etc/conf.d/tiny-cloud ] && source /etc/conf.d/tiny-cloud [ -f "$ROOT"/etc/conf.d/tiny-cloud ] && . "$ROOT"/etc/conf.d/tiny-cloud
: "${CLOUD:=unknown}" : "${CLOUD:=unknown}"
: "${CLOUD_USER:=alpine}" : "${CLOUD_USER:=alpine}"
: "${TINY_CLOUD_LOGS:=/var/log}" : "${TINY_CLOUD_LOGS:=$ROOT/var/log}"
: "${TINY_CLOUD_VAR:=/var/lib/cloud}" : "${TINY_CLOUD_VAR:=$ROOT/var/lib/cloud}"
log() { log() {
local facility="kern" local facility="kern"
local stderr local stderr
local tag=$(basename "$0") local tag=$(basename "$0")
while [ "${1:0:1}" = '-' ]; do while [ "${1#-}" != "$1" ]; do
case "$1" in case "$1" in
-f) facility="$2"; shift ;; -f) facility="$2"; shift ;;
-s) stderr=-s ;; -s) stderr=-s ;;

View File

@ -2,7 +2,9 @@
# vim:set ts=4 et ft=sh: # vim:set ts=4 et ft=sh:
# set defaults # set defaults
source /lib/tiny-cloud/common : "${LIBDIR:=$PREFIX/lib}"
. "$LIBDIR"/tiny-cloud/common
: "${SKIP_INIT_ACTIONS:=}" : "${SKIP_INIT_ACTIONS:=}"
# is initial bootstrap already done? # is initial bootstrap already done?

View File

@ -1,7 +1,8 @@
# Tiny Cloud - Early Phase Functions # Tiny Cloud - Early Phase Functions
# vim:set ts=4 et ft=sh: # vim:set ts=4 et ft=sh:
source /lib/tiny-cloud/init-common : "${LIBDIR:=$PREFIX/lib}"
. "$LIBDIR"/tiny-cloud/init-common
expand_root() { expand_root() {
skip_action expand_root && return skip_action expand_root && return
@ -41,4 +42,7 @@ install_hotplugs() {
done done
} }
[ -f /lib/tiny-cloud/"${HOTPLUG_TYPE:=mdev}" ] && source /lib/tiny-cloud/"$HOTPLUG_TYPE" : "${HOTPLUG_TYPE:=mdev}"
if [ -f "$LIBDIR"/tiny-cloud/"$HOTPLUG_TYPE" ]; then
. "$LIBDIR"/tiny-cloud/"$HOTPLUG_TYPE"
fi

View File

@ -1,7 +1,8 @@
# Tiny Cloud - Final Phase Functions # Tiny Cloud - Final Phase Functions
# vim:set ts=4 et ft=sh: # vim:set ts=4 et ft=sh:
source /lib/tiny-cloud/init-common : "${LIBDIR:=$PREFIX/lib}"
. "$LIBDIR"/tiny-cloud/init-common
is_userdata_script() { is_userdata_script() {
head -n1 "$TINY_CLOUD_VAR/user-data" | grep -q "#!/" head -n1 "$TINY_CLOUD_VAR/user-data" | grep -q "#!/"

View File

@ -1,7 +1,8 @@
# Tiny Cloud - Main Phase Functions # Tiny Cloud - Main Phase Functions
# vim:set ts=4 et ft=sh: # vim:set ts=4 et ft=sh:
source /lib/tiny-cloud/init-common : "${LIBDIR:=$PREFIX/lib}"
. "$LIBDIR"/tiny-cloud/init-common
# ensure existence of output directories # ensure existence of output directories
[ ! -d "$TINY_CLOUD_LOGS" ] && mkdir -p "$TINY_CLOUD_LOGS" [ ! -d "$TINY_CLOUD_LOGS" ] && mkdir -p "$TINY_CLOUD_LOGS"

View File

@ -33,5 +33,7 @@ mod__vnic_eth_hotplug() {
} }
# load cloud-specific functions # load cloud-specific functions
: "${LIBDIR:=$PREFIX/lib}"
[ -f /lib/tiny-cloud/"$CLOUD"/mdev ] && source /lib/tiny-cloud/"$CLOUD"/mdev if [ -f "$LIBDIR"/lib/tiny-cloud/"$CLOUD"/mdev ]; then
"$LIBDIR"/tiny-cloud/"$CLOUD"/mdev
fi

View File

@ -8,17 +8,17 @@ is_nocloud_loaded() { [ -f "$TINY_CLOUD_VAR/.nocloud_loaded" ]; }
_load_nocloud_cmdline() { _load_nocloud_cmdline() {
local kopt kv k v data local kopt kv k v data
for kopt in $(cat /proc/cmdline); do for kopt in $(cat "$ROOT"/proc/cmdline 2>/dev/null); do
echo "$kopt" | grep -qE '(^|=)ds=nocloud(-net)?;' || continue echo "$kopt" | grep -qE '(^|=)ds=nocloud(-net)?;' || continue
for kv in $(echo "${kopt#*;}" | tr \; ' '); do for kv in $(echo "${kopt#*;}" | tr \; ' '); do
k=$(echo "$kv" | cut -d= -f1) k=$(echo "$kv" | cut -d= -f1)
v=$(echo "$kv" | cut -d= -f2-) v=$(echo "$kv" | cut -d= -f2-)
case "$k" in case "$k" in
h|hostname) h|hostname)
echo -e "\nhostname: $v" >> "$TINY_CLOUD_VAR/meta-data" printf "\nhostname: %s" "$v" >> "$TINY_CLOUD_VAR/meta-data"
;; ;;
i|instance-id) i|instance-id)
echo -e "\ninstance-id: $v" >> "$TINY_CLOUD_VAR/meta-data" printf "\ninstance-id: %s" "$v" >> "$TINY_CLOUD_VAR/meta-data"
;; ;;
s|seedfrom) s|seedfrom)
for data in $NOCLOUD_FILES; do for data in $NOCLOUD_FILES; do
@ -46,7 +46,7 @@ _load_nocloud_cmdline() {
} }
_load_nocloud_volume() { _load_nocloud_volume() {
local mntdir=$(mktemp -d /mnt/cidata-XXXXXX) local mntdir=$(mktemp -d "$ROOT"/mnt/cidata-XXXXXX)
local data mounted local data mounted
mkdir -p "$mntdir" mkdir -p "$mntdir"
@ -60,7 +60,7 @@ _load_nocloud_volume() {
if [ -n "$mounted" ]; then if [ -n "$mounted" ]; then
for data in $NOCLOUD_FILES; do for data in $NOCLOUD_FILES; do
# lack of source results in empty target # lack of source results in empty target
cat "$mntdir/$data" > "$TINY_CLOUD_VAR/$data" cat "$mntdir/$data" > "$TINY_CLOUD_VAR/$data" 2>/dev/null
done done
umount "$mntdir" umount "$mntdir"
else else
@ -86,6 +86,7 @@ load_nocloud() {
} }
_imds() { _imds() {
mkdir -p "$TINY_CLOUD_VAR"
local file="$TINY_CLOUD_VAR"/$(echo "$1" | cut -d/ -f1) local file="$TINY_CLOUD_VAR"/$(echo "$1" | cut -d/ -f1)
local keypath=$(echo "$1" | cut -d/ -f2- | tr / ' ') local keypath=$(echo "$1" | cut -d/ -f2- | tr / ' ')

View File

@ -3,7 +3,7 @@
set -e set -e
IFACE_CFG=/etc/network/interfaces IFACE_CFG="$ROOT"/etc/network/interfaces
IFACE_DIR="${IFACE_CFG}.d" IFACE_DIR="${IFACE_CFG}.d"
cd "$IFACE_DIR" cd "$IFACE_DIR"
@ -15,7 +15,7 @@ cat > "$IFACE_CFG.new" <<EOT
EOT EOT
# existing loopback and eths # existing loopback and eths
for i in /sys/class/net/*; do for i in $ROOT/sys/class/net/*; do
IFACE="$(basename "$i")" IFACE="$(basename "$i")"
case $IFACE in case $IFACE in
lo|eth*) lo|eth*)

View File

@ -5,7 +5,8 @@
[ -z "$VERBOSE" ] || set -x [ -z "$VERBOSE" ] || set -x
source /lib/tiny-cloud/common : "${LIBDIR:=$PREFIX/lib}"
"$LIBDIR"/tiny-cloud/common
[ -z "${IFACE}" ] && log -s crit "IFACE not set, aborting" [ -z "${IFACE}" ] && log -s crit "IFACE not set, aborting"

35
tests/assemble-interfaces.test Executable file
View File

@ -0,0 +1,35 @@
#!/usr/bin/env atf-sh
. $(atf_get_srcdir)/test_env.sh
init_tests \
assemble_eth0 \
assemble_missing_interfaces_d
assemble_eth0_body() {
mkdir -p etc/network/interfaces.d \
sys/class/net/eth0
cat > etc/network/interfaces.d/DEFAULT <<-EOF
auto %%
iface %% inet dhcp
EOF
atf_check assemble-interfaces
atf_check \
-o match:"# NOTE:" \
-o match:"auto eth0" \
-o match:"iface eth0 inet dhcp" \
cat etc/network/interfaces
}
# test what happens if etc/network/interfaces.d is missing
assemble_missing_interfaces_d_body() {
atf_check -s not-exit:0 \
-e match:"([Nn]o such file or directory|can't cd to)" \
assemble-interfaces
if [ -f etc/network/interfaces ]; then
atf_fail "should not create etc/network/interfaces"
fi
}

52
tests/imds.test Executable file
View File

@ -0,0 +1,52 @@
#!/usr/bin/env atf-sh
. $(atf_get_srcdir)/test_env.sh
export PREFIX="$srcdir"
init_tests \
imds_help \
imds_nocloud_cmdline_hostname \
imds_nocloud_cidata_hostname
imds_help_body() {
atf_check -o match:"Usage: imds" imds -h
}
imds_nocloud_cmdline_hostname_body() {
atf_require_prog yx
mkdir proc
for key in h hostname; do
echo "BOOT_IMAGE=/boot/vmlinuz-lts ro ds=nocloud;$key=myhostname" > proc/cmdline
CLOUD=nocloud atf_check \
-o match:'^myhostname$' \
imds @hostname
done
}
imds_nocloud_cidata_hostname_body() {
atf_require_prog yx
fake_bin mount <<-EOF
#!/bin/sh
# find last arg which is the mount dir
while ! [ -d "\$1" ]; do
shift
done
printf "#cloud-config\nhostname: myhostname\n" \
> "\$1"/meta-data
EOF
fake_bin umount <<-EOF
#!/bin/sh
while ! [ -d "\$1" ]; do
shift
done
rm -f "\$1"/meta-data
EOF
mkdir -p mnt
CLOUD=nocloud atf_check \
-o match:'^myhostname$' \
imds @hostname
}

30
tests/test_env.sh Normal file
View File

@ -0,0 +1,30 @@
# shellcheck shell=sh
srcdir="$(atf_get_srcdir)/.."
PATH="$srcdir/bin:$srcdir/sbin:$PATH"
export TINY_CLOUD_BASEDIR="$srcdir"
export ROOT="$PWD"
init_tests() {
TESTS=
for t; do
TESTS="$TESTS $t"
atf_test_case "$t"
done
export TESTS
}
atf_init_test_cases() {
for t in $TESTS; do
atf_add_test_case "$t"
done
}
fake_bin() {
mkdir -p bin
cat > bin/"$1"
chmod +x bin/"$1"
PATH="$PWD/bin:$PATH"
}