mirror of
https://github.com/ostreedev/ostree.git
synced 2024-12-23 21:35:26 +03:00
3b2fd6e9ff
For ostree_repo_export_tree_to_archive(), and 'ostree export', when the exported tree contains multiple files with the same checksum, write an archive with hard links. Without this, importing a tree, then exporting it again breaks hardlinks. As an example of savings: this reduces the (compressed) size of the Fedora Flatpak Runtime image from 1345MiB to 712MiB. Resolves: #2925
856 lines
26 KiB
Bash
Executable File
856 lines
26 KiB
Bash
Executable File
# Source library for shell script tests
|
|
#
|
|
# Copyright (C) 2011 Colin Walters <walters@verbum.org>
|
|
#
|
|
# SPDX-License-Identifier: LGPL-2.0+
|
|
#
|
|
# This library is free software; you can redistribute it and/or
|
|
# modify it under the terms of the GNU Lesser General Public
|
|
# License as published by the Free Software Foundation; either
|
|
# version 2 of the License, or (at your option) any later version.
|
|
#
|
|
# This library is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
# Lesser General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU Lesser General Public
|
|
# License along with this library. If not, see <https://www.gnu.org/licenses/>.
|
|
|
|
dn=$(dirname $0)
|
|
|
|
if [ -n "${G_TEST_SRCDIR:-}" ]; then
|
|
test_srcdir="${G_TEST_SRCDIR}/tests"
|
|
else
|
|
test_srcdir=$(dirname $0)
|
|
fi
|
|
|
|
top_builddir="${G_TEST_BUILDDIR:-}"
|
|
if test -z "${top_builddir}"; then
|
|
top_builddir=$(cd $(dirname $0)/.. && pwd)
|
|
fi
|
|
|
|
test_builddir="${top_builddir}/tests"
|
|
. ${test_srcdir}/libtest-core.sh
|
|
|
|
# Make sure /sbin/capsh etc. are in our PATH even if non-root
|
|
PATH="$PATH:/usr/sbin:/sbin"
|
|
|
|
# Array of expressions to execute when exiting. Each expression should
|
|
# be a single string (quoting if necessary) that will be eval'd. To add
|
|
# a command to run on exit, append to the libtest_exit_cmds array like
|
|
# libtest_exit_cmds+=(expr).
|
|
libtest_exit_cmds=()
|
|
run_exit_cmds() {
|
|
for expr in "${libtest_exit_cmds[@]}"; do
|
|
eval "${expr}" || true
|
|
done
|
|
}
|
|
trap run_exit_cmds EXIT
|
|
|
|
save_core() {
|
|
if [ -e core ]; then
|
|
cp core "$test_srcdir/core"
|
|
fi
|
|
}
|
|
libtest_exit_cmds+=(save_core)
|
|
|
|
test_tmpdir=$(pwd)
|
|
|
|
# Sanity check that we're in a tmpdir that has
|
|
# just .testtmp (created by tap-driver for `make check`,
|
|
# or nothing at all (as ginstest-runner does)
|
|
if ! test -f .testtmp; then
|
|
files=$(ls)
|
|
if test -n "${files}"; then
|
|
ls -l
|
|
assert_not_reached "test tmpdir=${test_tmpdir} is not empty; run this test via \`make check TESTS=\`, not directly"
|
|
fi
|
|
# Remember that this is an acceptable test $(pwd), for the benefit of
|
|
# C and JS tests which may source this file again
|
|
touch .testtmp
|
|
fi
|
|
|
|
# Some distribution builds set this, but some of our build-time tests
|
|
# assume this won't be used when committing
|
|
unset SOURCE_DATE_EPOCH
|
|
|
|
# Also, unbreak `tar` inside `make check`...Automake will inject
|
|
# TAR_OPTIONS: --owner=0 --group=0 --numeric-owner presumably so that
|
|
# tarballs are predictable, except we don't want this in our tests.
|
|
unset TAR_OPTIONS
|
|
|
|
# Don't flag deployments as immutable so that test harnesses can
|
|
# easily clean up.
|
|
export OSTREE_SYSROOT_DEBUG=mutable-deployments
|
|
|
|
# By default, don't use a cache directory since it makes the tests racy.
|
|
# Tests that are explicitly testing the cache operation should unset
|
|
# this.
|
|
export OSTREE_SKIP_CACHE=1
|
|
|
|
export TEST_GPG_KEYID_1="7FCA23D8472CDAFA"
|
|
export TEST_GPG_KEYFPR_1="5E65DE75AB1C501862D476347FCA23D8472CDAFA"
|
|
export TEST_GPG_KEYID_2="D8228CFECA950D41"
|
|
export TEST_GPG_KEYFPR_2="7B3B1020D74479687FDB2273D8228CFECA950D41"
|
|
export TEST_GPG_KEYID_3="0D15FAE7DF444D67"
|
|
export TEST_GPG_KEYFPR_3="7D29CF060B8269CDF63BFBDD0D15FAE7DF444D67"
|
|
|
|
# GPG when creating signatures demands a private writable
|
|
# homedir in order to create lockfiles. Work around
|
|
# this by copying locally.
|
|
echo "Copying gpghome to ${test_tmpdir}"
|
|
cp -a "${test_srcdir}/gpghome" ${test_tmpdir}
|
|
chmod -R u+w "${test_tmpdir}"
|
|
chmod 700 "${test_tmpdir}/gpghome"
|
|
export TEST_GPG_KEYHOME=${test_tmpdir}/gpghome
|
|
export OSTREE_GPG_HOME=${test_tmpdir}/gpghome/trusted
|
|
|
|
assert_has_setfattr() {
|
|
if ! which setfattr 2>/dev/null; then
|
|
fatal "no setfattr available to determine xattr support"
|
|
fi
|
|
}
|
|
|
|
_have_selinux_relabel=''
|
|
have_selinux_relabel() {
|
|
assert_has_setfattr
|
|
if test "${_have_selinux_relabel}" = ''; then
|
|
pushd ${test_tmpdir}
|
|
echo testlabel > testlabel.txt
|
|
selinux_xattr=security.selinux
|
|
if getfattr --encoding=base64 -n ${selinux_xattr} testlabel.txt >label.txt 2>err.txt; then
|
|
label=$(grep -E -e "^${selinux_xattr}=" < label.txt |sed -e "s,${selinux_xattr}=,,")
|
|
if setfattr -n ${selinux_xattr} -v ${label} testlabel.txt 2>err.txt; then
|
|
echo "SELinux enabled in $(pwd), and have privileges to relabel"
|
|
_have_selinux_relabel=yes
|
|
else
|
|
sed -e 's/^/# /' < err.txt >&2
|
|
echo "Found SELinux label, but unable to set (Unprivileged Docker?)"
|
|
_have_selinux_relabel=no
|
|
fi
|
|
else
|
|
sed -e 's/^/# /' < err.txt >&2
|
|
echo "Unable to retrieve SELinux label, assuming disabled"
|
|
_have_selinux_relabel=no
|
|
fi
|
|
popd
|
|
fi
|
|
test ${_have_selinux_relabel} = yes
|
|
}
|
|
|
|
# just globally turn off xattrs if we can't manipulate security xattrs; this is
|
|
# the case for overlayfs -- really, we should only enforce this for tests that
|
|
# use bare repos; separate from other tests that should check for user xattrs
|
|
# support
|
|
# see https://github.com/ostreedev/ostree/issues/758
|
|
# and https://github.com/ostreedev/ostree/pull/1217
|
|
echo -n checking for xattrs...
|
|
if ! have_selinux_relabel; then
|
|
export OSTREE_SYSROOT_DEBUG="${OSTREE_SYSROOT_DEBUG},no-xattrs"
|
|
export OSTREE_NO_XATTRS=1
|
|
fi
|
|
echo done
|
|
|
|
# whiteout char 0:0 devices can be created as regular users, but
|
|
# cannot be created inside containers mounted via overlayfs
|
|
can_create_whiteout_devices() {
|
|
mknod -m 000 ${test_tmpdir}/.test-whiteout c 0 0 || return 1
|
|
rm -f ${test_tmpdir}/.test-whiteout
|
|
return 0
|
|
}
|
|
|
|
echo -n checking for overlayfs whiteouts...
|
|
if ! can_create_whiteout_devices; then
|
|
export OSTREE_NO_WHITEOUTS=1
|
|
fi
|
|
echo done
|
|
|
|
if test -n "${OT_TESTS_DEBUG:-}"; then
|
|
set -x
|
|
fi
|
|
|
|
# This is substituted by the build for installed tests
|
|
BUILT_WITH_ASAN=""
|
|
if test -n "${ASAN_OPTIONS:-}"; then
|
|
BUILT_WITH_ASAN=1
|
|
fi
|
|
|
|
CMD_PREFIX=""
|
|
if test -n "${OT_TESTS_VALGRIND:-}"; then
|
|
CMD_PREFIX="env G_SLICE=always-malloc OSTREE_SUPPRESS_SYNCFS=1 valgrind -q --error-exitcode=1 --leak-check=full --num-callers=30 --suppressions=${test_srcdir}/glib.supp --suppressions=${test_srcdir}/ostree.supp"
|
|
fi
|
|
|
|
if test -z "${OSTREE_HTTPD:-}"; then
|
|
OSTREE_HTTPD="${top_builddir}/ostree-trivial-httpd"
|
|
if ! [ -x "${OSTREE_HTTPD}" ]; then
|
|
OSTREE_HTTPD=
|
|
fi
|
|
fi
|
|
|
|
files_are_hardlinked() {
|
|
inode1=$(stat -c %i $1)
|
|
inode2=$(stat -c %i $2)
|
|
test -n "${inode1}" && test -n "${inode2}"
|
|
[ "${inode1}" == "${inode2}" ]
|
|
}
|
|
|
|
assert_files_hardlinked() {
|
|
if ! files_are_hardlinked "$1" "$2"; then
|
|
fatal "Files '$1' and '$2' are not hardlinked"
|
|
fi
|
|
}
|
|
|
|
setup_test_repository () {
|
|
mode=$1
|
|
shift
|
|
|
|
oldpwd=`pwd`
|
|
|
|
COMMIT_ARGS=""
|
|
if [ $mode == "bare-user-only" ] ; then
|
|
COMMIT_ARGS="--owner-uid=0 --owner-gid=0 --no-xattrs --canonical-permissions"
|
|
fi
|
|
|
|
cd ${test_tmpdir}
|
|
rm -rf repo
|
|
if test -n "${mode}"; then
|
|
ostree_repo_init repo --mode=${mode}
|
|
else
|
|
ostree_repo_init repo
|
|
fi
|
|
ot_repo="--repo=$(pwd)/repo"
|
|
export OSTREE="${CMD_PREFIX} ostree ${ot_repo}"
|
|
|
|
cd ${test_tmpdir}
|
|
local oldumask="$(umask)"
|
|
umask 022
|
|
rm -rf files
|
|
mkdir files
|
|
cd files
|
|
ot_files=`pwd`
|
|
export ht_files
|
|
ln -s nosuchfile somelink
|
|
echo first > firstfile
|
|
|
|
cd ${test_tmpdir}/files
|
|
$OSTREE commit ${COMMIT_ARGS} -b test2 -s "Test Commit 1" -m "Commit body first"
|
|
|
|
mkdir baz
|
|
echo moo > baz/cow
|
|
echo mooro > baz/cowro
|
|
chmod 600 baz/cowro
|
|
echo alien > baz/saucer
|
|
mkdir baz/deeper
|
|
echo hi > baz/deeper/ohyeah
|
|
echo hix > baz/deeper/ohyeahx
|
|
chmod 755 baz/deeper/ohyeahx
|
|
ln -s nonexistent baz/alink
|
|
mkdir baz/another/
|
|
echo x > baz/another/y
|
|
|
|
mkdir baz/sub1
|
|
echo SAME_CONTENT > baz/sub1/duplicate_a
|
|
echo SAME_CONTENT > baz/sub1/duplicate_b
|
|
|
|
mkdir baz/sub2
|
|
echo SAME_CONTENT > baz/sub2/duplicate_c
|
|
|
|
# if we are running inside a container we cannot test
|
|
# the overlayfs whiteout marker passthrough
|
|
if ! test -n "${OSTREE_NO_WHITEOUTS:-}"; then
|
|
mkdir whiteouts
|
|
touch whiteouts/.ostree-wh.whiteout
|
|
touch whiteouts/.ostree-wh.whiteout2
|
|
chmod 755 whiteouts/.ostree-wh.whiteout2
|
|
fi
|
|
umask "${oldumask}"
|
|
|
|
cd ${test_tmpdir}/files
|
|
$OSTREE commit ${COMMIT_ARGS} -b test2 -s "Test Commit 2" -m "Commit body second"
|
|
$OSTREE fsck -q
|
|
|
|
cd $oldpwd
|
|
}
|
|
|
|
# A wrapper which also possibly disables xattrs for CI testing
|
|
ostree_repo_init() {
|
|
repo=$1
|
|
shift
|
|
${CMD_PREFIX} ostree --repo=${repo} init "$@"
|
|
if test -n "${OSTREE_NO_XATTRS:-}"; then
|
|
echo -e 'disable-xattrs=true\n' >> ${repo}/config
|
|
fi
|
|
}
|
|
|
|
# The original one; use setup_fake_remote_repo2 for newer code,
|
|
# down the line we'll try to port tests.
|
|
setup_fake_remote_repo1() {
|
|
mode=$1; shift
|
|
commit_opts=${1:-}
|
|
[ $# -eq 0 ] || shift
|
|
oldpwd=`pwd`
|
|
mkdir ostree-srv
|
|
cd ostree-srv
|
|
mkdir gnomerepo
|
|
ostree_repo_init gnomerepo --mode=$mode
|
|
mkdir gnomerepo-files
|
|
cd gnomerepo-files
|
|
echo first > firstfile
|
|
mkdir baz
|
|
echo moo > baz/cow
|
|
echo alien > baz/saucer
|
|
${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit $commit_opts --add-metadata-string version=3.0 -b main -s "A remote commit" -m "Some Commit body"
|
|
mkdir baz/deeper
|
|
${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit $commit_opts --add-metadata-string version=3.1 -b main -s "Add deeper"
|
|
echo hi > baz/deeper/ohyeah
|
|
mkdir baz/another/
|
|
echo x > baz/another/y
|
|
${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/gnomerepo commit $commit_opts --add-metadata-string version=3.2 -b main -s "The rest"
|
|
cd ..
|
|
rm -rf gnomerepo-files
|
|
|
|
cd ${test_tmpdir}
|
|
mkdir ${test_tmpdir}/httpd
|
|
cd httpd
|
|
ln -s ${test_tmpdir}/ostree-srv ostree
|
|
${OSTREE_HTTPD} --autoexit --log-file $(pwd)/httpd.log --daemonize -p ${test_tmpdir}/httpd-port "$@"
|
|
port=$(cat ${test_tmpdir}/httpd-port)
|
|
echo "http://127.0.0.1:${port}" > ${test_tmpdir}/httpd-address
|
|
cd ${oldpwd}
|
|
|
|
export OSTREE="${CMD_PREFIX} ostree --repo=repo"
|
|
}
|
|
|
|
# Newer version of the above with more "real" data
|
|
setup_fake_remote_repo2() {
|
|
mode=$1
|
|
commit_opts=${2:-}
|
|
args=${3:-}
|
|
shift
|
|
oldpwd=`pwd`
|
|
mkdir ostree-srv
|
|
cd ostree-srv
|
|
mkdir repo
|
|
ostree_repo_init repo --mode=$mode
|
|
# Backcompat
|
|
ln -sr repo gnomerepo
|
|
# Initialize content
|
|
mkdir files
|
|
cd files
|
|
mkdir -p usr/{etc,bin,lib,share}
|
|
ln -sr usr/bin bin
|
|
ln -sr usr/lib lib
|
|
tar xf ${test_srcdir}/fah-deltadata-old.tar.xz
|
|
remote_ref=exampleos/42/x86_64/main
|
|
cd ..
|
|
${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/repo commit \
|
|
--consume $commit_opts --add-metadata-string version=42.0 -b ${remote_ref} \
|
|
--tree=dir=files
|
|
test '!' -d files
|
|
${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/repo checkout -U ${remote_ref} files
|
|
(cd files && tar xf ${test_srcdir}/fah-deltadata-new.tar.xz)
|
|
${CMD_PREFIX} ostree --repo=${test_tmpdir}/ostree-srv/repo commit \
|
|
--consume $commit_opts --add-metadata-string version=42.1 -b ${remote_ref} \
|
|
--tree=dir=files
|
|
|
|
# And serve via HTTP
|
|
cd ${test_tmpdir}
|
|
mkdir ${test_tmpdir}/httpd
|
|
cd httpd
|
|
ln -s ${test_tmpdir}/ostree-srv ostree
|
|
${OSTREE_HTTPD} --autoexit --log-file $(pwd)/httpd.log --daemonize -p ${test_tmpdir}/httpd-port $args
|
|
port=$(cat ${test_tmpdir}/httpd-port)
|
|
echo "http://127.0.0.1:${port}" > ${test_tmpdir}/httpd-address
|
|
cd ${oldpwd}
|
|
export OSTREE="${CMD_PREFIX} ostree --repo=repo"
|
|
}
|
|
|
|
setup_os_boot_syslinux() {
|
|
# Stub syslinux configuration
|
|
mkdir -p sysroot/boot/loader.0
|
|
ln -s loader.0 sysroot/boot/loader
|
|
touch sysroot/boot/loader/syslinux.cfg
|
|
# And a compatibility symlink
|
|
mkdir -p sysroot/boot/syslinux
|
|
ln -s ../loader/syslinux.cfg sysroot/boot/syslinux/syslinux.cfg
|
|
}
|
|
|
|
setup_os_boot_uboot() {
|
|
# Stub U-Boot configuration
|
|
mkdir -p sysroot/boot/loader.0
|
|
ln -s loader.0 sysroot/boot/loader
|
|
touch sysroot/boot/loader/uEnv.txt
|
|
# And a compatibility symlink
|
|
ln -s loader/uEnv.txt sysroot/boot/uEnv.txt
|
|
}
|
|
|
|
setup_os_boot_grub2() {
|
|
grub2_options=$1
|
|
mkdir -p sysroot/boot/grub2/
|
|
ln -s ../loader/grub.cfg sysroot/boot/grub2/grub.cfg
|
|
export OSTREE_BOOT_PARTITION="/boot"
|
|
case "$grub2_options" in
|
|
*ostree-grub-generator*)
|
|
cp ${test_srcdir}/ostree-grub-generator ${test_tmpdir}
|
|
chmod +x ${test_tmpdir}/ostree-grub-generator
|
|
export OSTREE_GRUB2_EXEC=${test_tmpdir}/ostree-grub-generator
|
|
;;
|
|
esac
|
|
}
|
|
|
|
setup_os_boot_configured_bootloader() {
|
|
bootloader_keyval=$1
|
|
${CMD_PREFIX} ostree --repo=sysroot/ostree/repo config set ${bootloader_keyval}
|
|
}
|
|
|
|
setup_os_repository () {
|
|
mode=$1
|
|
shift
|
|
bootmode=$1
|
|
shift
|
|
bootdir=${1:-usr/lib/modules/3.6.0}
|
|
|
|
oldpwd=`pwd`
|
|
|
|
cd ${test_tmpdir}
|
|
mkdir testos-repo
|
|
if test -n "$mode"; then
|
|
ostree_repo_init testos-repo --mode=${mode}
|
|
else
|
|
ostree_repo_init testos-repo
|
|
fi
|
|
|
|
cd ${test_tmpdir}
|
|
mkdir osdata
|
|
cd osdata
|
|
kver=3.6.0
|
|
mkdir -p usr/bin ${bootdir} usr/lib/modules/${kver} usr/share usr/etc usr/container/layers/abcd
|
|
kernel_path=${bootdir}/vmlinuz
|
|
initramfs_path=${bootdir}/initramfs.img
|
|
# the HMAC file is only in /usr/lib/modules
|
|
hmac_path=usr/lib/modules/${kver}/.vmlinuz.hmac
|
|
# /usr/lib/modules just uses "vmlinuz", since the version is in the module
|
|
# directory name.
|
|
if [[ $bootdir != usr/lib/modules/* ]]; then
|
|
kernel_path=${kernel_path}-${kver}
|
|
initramfs_path=${bootdir}/initramfs-${kver}.img
|
|
fi
|
|
echo "a kernel" > ${kernel_path}
|
|
echo "an initramfs" > ${initramfs_path}
|
|
echo "an hmac file" > ${hmac_path}
|
|
bootcsum=$(cat ${kernel_path} ${initramfs_path} | sha256sum | cut -f 1 -d ' ')
|
|
export bootcsum
|
|
bootable_flag=""
|
|
# Add the checksum for legacy dirs (/boot, /usr/lib/ostree-boot), but not
|
|
# /usr/lib/modules.
|
|
if [[ $bootdir != usr/lib/modules/* ]]; then
|
|
mv ${kernel_path}{,-${bootcsum}}
|
|
mv ${initramfs_path}{,-${bootcsum}}
|
|
else
|
|
bootable_flag="--bootable"
|
|
fi
|
|
|
|
echo "an executable" > usr/bin/sh
|
|
echo "some shared data" > usr/share/langs.txt
|
|
echo "a library" > usr/lib/libfoo.so.0
|
|
ln -s usr/bin bin
|
|
cat > usr/etc/os-release <<EOF
|
|
NAME=TestOS
|
|
VERSION=42
|
|
ID=testos
|
|
VERSION_ID=42
|
|
PRETTY_NAME="TestOS 42"
|
|
EOF
|
|
echo "a config file" > usr/etc/aconfigfile
|
|
mkdir -p usr/etc/NetworkManager
|
|
echo "a default daemon file" > usr/etc/NetworkManager/nm.conf
|
|
mkdir -p usr/etc/testdirectory
|
|
echo "a default daemon file" > usr/etc/testdirectory/test
|
|
|
|
# if we are running inside a container we cannot test
|
|
# the overlayfs whiteout marker passthrough
|
|
if ! test -n "${OSTREE_NO_WHITEOUTS:-}"; then
|
|
# overlayfs whiteout passhthrough marker files
|
|
touch usr/container/layers/abcd/.ostree-wh.whiteout
|
|
chmod 400 usr/container/layers/abcd/.ostree-wh.whiteout
|
|
|
|
touch usr/container/layers/abcd/.ostree-wh.whiteout2
|
|
chmod 777 usr/container/layers/abcd/.ostree-wh.whiteout2
|
|
fi
|
|
|
|
${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit ${bootable_flag} --add-metadata-string version=1.0.9 -b testos/buildmain/x86_64-runtime -s "Build"
|
|
|
|
# Ensure these commits have distinct second timestamps
|
|
sleep 2
|
|
echo "a new executable" > usr/bin/sh
|
|
${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit ${bootable_flag} --add-metadata-string version=1.0.10 -b testos/buildmain/x86_64-runtime -s "Build"
|
|
|
|
cd ${test_tmpdir}
|
|
rm -rf osdata-devel
|
|
mkdir osdata-devel
|
|
tar -C osdata -cf - . | tar -C osdata-devel -xf -
|
|
cd osdata-devel
|
|
mkdir -p usr/include
|
|
echo "a development header" > usr/include/foo.h
|
|
${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit ${bootable_flag} --add-metadata-string version=1.0.9 -b testos/buildmain/x86_64-devel -s "Build"
|
|
|
|
${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo fsck -q
|
|
|
|
cd ${test_tmpdir}
|
|
mkdir sysroot
|
|
export OSTREE_SYSROOT=sysroot
|
|
${CMD_PREFIX} ostree admin init-fs sysroot
|
|
if test -n "${OSTREE_NO_XATTRS:-}"; then
|
|
echo -e 'disable-xattrs=true\n' >> sysroot/ostree/repo/config
|
|
fi
|
|
${CMD_PREFIX} ostree admin stateroot-init testos
|
|
|
|
case $bootmode in
|
|
"syslinux")
|
|
setup_os_boot_syslinux
|
|
;;
|
|
"uboot")
|
|
setup_os_boot_uboot
|
|
;;
|
|
*grub2*)
|
|
setup_os_boot_grub2 "${bootmode}"
|
|
;;
|
|
sysroot\.bootloader*)
|
|
setup_os_boot_configured_bootloader "${bootmode}"
|
|
;;
|
|
esac
|
|
|
|
cd ${test_tmpdir}
|
|
mkdir ${test_tmpdir}/httpd
|
|
cd httpd
|
|
ln -s ${test_tmpdir} ostree
|
|
${OSTREE_HTTPD} --autoexit --daemonize -p ${test_tmpdir}/httpd-port
|
|
port=$(cat ${test_tmpdir}/httpd-port)
|
|
echo "http://127.0.0.1:${port}" > ${test_tmpdir}/httpd-address
|
|
cd ${oldpwd}
|
|
}
|
|
|
|
timestamp_of_commit()
|
|
{
|
|
date --date="$(ostree --repo=$1 show $2 | grep -Ee '^Date: ' | sed -e 's,^Date: *,,')" '+%s'
|
|
}
|
|
|
|
os_repository_new_commit ()
|
|
{
|
|
boot_checksum_iteration=${1:-0}
|
|
content_iteration=${2:-0}
|
|
branch=${3:-testos/buildmain/x86_64-runtime}
|
|
export version=${4:-$(date "+%Y%m%d.${content_iteration}")}
|
|
echo "BOOT ITERATION: $boot_checksum_iteration"
|
|
cd ${test_tmpdir}/osdata
|
|
kver=3.6.0
|
|
if test -f usr/lib/modules/${kver}/vmlinuz; then
|
|
bootdir=usr/lib/modules/${kver}
|
|
else
|
|
if test -d usr/lib/ostree-boot; then
|
|
bootdir=usr/lib/ostree-boot
|
|
else
|
|
bootdir=boot
|
|
fi
|
|
fi
|
|
rm ${bootdir}/*
|
|
kernel_path=${bootdir}/vmlinuz
|
|
initramfs_path=${bootdir}/initramfs.img
|
|
if [[ $bootdir != usr/lib/modules/* ]]; then
|
|
kernel_path=${kernel_path}-${kver}
|
|
initramfs_path=${bootdir}/initramfs-${kver}.img
|
|
fi
|
|
echo "new: a kernel ${boot_checksum_iteration}" > ${kernel_path}
|
|
echo "new: an initramfs ${boot_checksum_iteration}" > ${initramfs_path}
|
|
bootcsum=$(cat ${kernel_path} ${initramfs_path} | sha256sum | cut -f 1 -d ' ')
|
|
export bootcsum
|
|
if [[ $bootdir != usr/lib/modules/* ]]; then
|
|
mv ${kernel_path}{,-${bootcsum}}
|
|
mv ${initramfs_path}{,-${bootcsum}}
|
|
fi
|
|
|
|
echo "a new default config file" > usr/etc/a-new-default-config-file
|
|
mkdir -p usr/etc/new-default-dir
|
|
echo "a new default dir and file" > usr/etc/new-default-dir/moo
|
|
|
|
echo "content iteration ${content_iteration}" > usr/bin/content-iteration
|
|
|
|
${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --add-metadata-string "version=${version}" -b $branch -s "Build"
|
|
if ${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo rev-parse ${branch} 2>/dev/null; then
|
|
prevdate=$(timestamp_of_commit ${test_tmpdir}/testos-repo "${branch}"^)
|
|
newdate=$(timestamp_of_commit ${test_tmpdir}/testos-repo "${branch}")
|
|
if [ $((${prevdate} > ${newdate})) = 1 ]; then
|
|
fatal "clock skew detected writing commits: prev=${prevdate} new=${newdate}"
|
|
fi
|
|
fi
|
|
cd ${test_tmpdir}
|
|
}
|
|
|
|
_have_user_xattrs=''
|
|
have_user_xattrs() {
|
|
assert_has_setfattr
|
|
if test "${_have_user_xattrs}" = ''; then
|
|
touch test-xattrs
|
|
if setfattr -n user.testvalue -v somevalue test-xattrs 2>/dev/null; then
|
|
_have_user_xattrs=yes
|
|
else
|
|
_have_user_xattrs=no
|
|
fi
|
|
rm -f test-xattrs
|
|
fi
|
|
test ${_have_user_xattrs} = yes
|
|
}
|
|
|
|
# Usage: if ! skip_one_without_user_xattrs; then ... more tests ...; fi
|
|
skip_one_without_user_xattrs () {
|
|
if ! have_user_xattrs; then
|
|
echo "ok # SKIP - this test requires xattr support"
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
skip_without_user_xattrs () {
|
|
if ! have_user_xattrs; then
|
|
skip "this test requires xattr support"
|
|
fi
|
|
}
|
|
|
|
skip_without_sudo () {
|
|
if test -z "${OSTREE_TEST_SUDO:-}"; then
|
|
skip "this test needs sudo, skipping without OSTREE_TEST_SUDO being set"
|
|
fi
|
|
}
|
|
|
|
# Usage: if ! skip_one_without_whiteouts_devices; then ... more tests ...; fi
|
|
skip_one_without_whiteouts_devices() {
|
|
if ! can_create_whiteout_devices; then
|
|
echo "ok # SKIP - this test requires whiteout device support (test outside containers)"
|
|
return 0
|
|
else
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
skip_without_whiteouts_devices () {
|
|
if ! can_create_whiteout_devices; then
|
|
skip "this test requires whiteout device support (test outside containers)"
|
|
fi
|
|
}
|
|
|
|
_have_systemd_and_libmount=''
|
|
have_systemd_and_libmount() {
|
|
if test "${_have_systemd_and_libmount}" = ''; then
|
|
if [ $(ostree --version | grep -c -e '- systemd' -e '- libmount') -eq 2 ]; then
|
|
_have_systemd_and_libmount=yes
|
|
else
|
|
_have_systemd_and_libmount=no
|
|
fi
|
|
fi
|
|
test ${_have_systemd_and_libmount} = yes
|
|
}
|
|
|
|
# Skip unless SELinux is disabled, or we can relabel.
|
|
# Default Docker has security.selinux xattrs, but returns
|
|
# EOPNOTSUPP when trying to set them, even to the existing value.
|
|
# https://github.com/ostreedev/ostree/pull/759
|
|
# https://github.com/ostreedev/ostree/pull/1217
|
|
skip_without_no_selinux_or_relabel () {
|
|
if ! have_selinux_relabel; then
|
|
skip "this test requires SELinux relabeling support"
|
|
fi
|
|
}
|
|
|
|
# https://brokenpi.pe/tools/strace-fault-injection
|
|
_have_strace_fault_injection=''
|
|
have_strace_fault_injection() {
|
|
if test "${_have_strace_fault_injection}" = ''; then
|
|
if strace -P ${test_srcdir}/libtest-core.sh -e inject=read:retval=0 cat ${test_srcdir}/libtest-core.sh >out.txt &&
|
|
test '!' -s out.txt; then
|
|
_have_strace_fault_injection=yes
|
|
else
|
|
_have_strace_fault_injection=no
|
|
fi
|
|
rm -f out.txt
|
|
fi
|
|
test ${_have_strace_fault_injection} = yes
|
|
}
|
|
|
|
skip_one_without_strace_fault_injection() {
|
|
if ! have_strace_fault_injection; then
|
|
echo "ok # SKIP this test requires strace fault injection"
|
|
return 0
|
|
fi
|
|
return 1
|
|
}
|
|
|
|
skip_without_fuse () {
|
|
fusermount --version >/dev/null 2>&1 || skip "no fusermount"
|
|
|
|
capsh --print | grep -q 'Bounding set.*[^a-z]cap_sys_admin' || \
|
|
skip "No cap_sys_admin in bounding set, can't use FUSE"
|
|
|
|
[ -w /dev/fuse ] || skip "no write access to /dev/fuse"
|
|
[ -e /etc/mtab ] || skip "no /etc/mtab"
|
|
}
|
|
|
|
has_gpgme () {
|
|
local ret
|
|
${CMD_PREFIX} ostree --version > version.txt
|
|
grep -q -e '- gpgme' version.txt
|
|
ret=$?
|
|
rm -f version.txt
|
|
return ${ret}
|
|
}
|
|
|
|
skip_without_gpgme() {
|
|
if ! has_gpgme; then
|
|
skip "no gpg support compiled in"
|
|
fi
|
|
}
|
|
|
|
# Find an appropriate gpg program to use. We want one that has the
|
|
# --generate-key, --quick-set-expire and --quick-add-key options. The
|
|
# gpg program to use is returend.
|
|
which_gpg () {
|
|
local gpg
|
|
local gpg_options
|
|
local needed_options=(
|
|
--generate-key
|
|
--quick-set-expire
|
|
--quick-add-key
|
|
)
|
|
local opt
|
|
|
|
# Prefer gpg2 in case gpg refers to gpg1
|
|
if which gpg2 &>/dev/null; then
|
|
gpg=gpg2
|
|
elif which gpg &>/dev/null; then
|
|
gpg=gpg
|
|
else
|
|
# Succeed but don't return anything.
|
|
return 0
|
|
fi
|
|
|
|
# Make sure all the needed options are available
|
|
gpg_options=$(${gpg} --dump-options) || return 0
|
|
for opt in ${needed_options[*]}; do
|
|
grep -q -x -e "${opt}" <<< "${gpg_options}" || return 0
|
|
done
|
|
|
|
# Found an appropriate gpg
|
|
echo ${gpg}
|
|
}
|
|
|
|
libtest_cleanup_gpg () {
|
|
local gpg_homedir=${1:-${test_tmpdir}/gpghome}
|
|
gpg-connect-agent --homedir "${gpg_homedir}" killagent /bye || true
|
|
}
|
|
libtest_exit_cmds+=(libtest_cleanup_gpg)
|
|
|
|
has_sign_ed25519 () {
|
|
local ret
|
|
${CMD_PREFIX} ostree --version > version.txt
|
|
grep -q -e '- sign-ed25519' version.txt
|
|
ret=$?
|
|
rm -f version.txt
|
|
return ${ret}
|
|
}
|
|
|
|
skip_without_sign_ed25519() {
|
|
if ! has_sign_ed25519; then
|
|
skip "no ed25519 support compiled in"
|
|
fi
|
|
}
|
|
|
|
# Keys for ed25519 signing tests
|
|
ED25519PUBLIC=
|
|
ED25519SEED=
|
|
ED25519SECRET=
|
|
|
|
gen_ed25519_keys ()
|
|
{
|
|
# Generate private key in PEM format
|
|
pemfile="$(mktemp -p ${test_tmpdir} ed25519_XXXXXX.pem)"
|
|
openssl genpkey -algorithm ed25519 -outform PEM -out "${pemfile}"
|
|
|
|
# Based on: http://openssl.6102.n7.nabble.com/ed25519-key-generation-td73907.html
|
|
# Extract the private and public parts from generated key.
|
|
ED25519PUBLIC="$(openssl pkey -outform DER -pubout -in ${pemfile} | tail -c 32 | base64)"
|
|
ED25519SEED="$(openssl pkey -outform DER -in ${pemfile} | tail -c 32 | base64)"
|
|
# Secret key is concantination of SEED and PUBLIC
|
|
ED25519SECRET="$(echo ${ED25519SEED}${ED25519PUBLIC} | base64 -d | base64 -w 0)"
|
|
|
|
echo "Generated ed25519 keys:"
|
|
echo "public: ${ED25519PUBLIC}"
|
|
echo " seed: ${ED25519SEED}"
|
|
}
|
|
|
|
gen_ed25519_random_public()
|
|
{
|
|
openssl genpkey -algorithm ED25519 | openssl pkey -outform DER | tail -c 32 | base64
|
|
}
|
|
|
|
is_bare_user_only_repo () {
|
|
grep -q 'mode=bare-user-only' $1/config
|
|
}
|
|
|
|
# Given a path to a file in a repo for a ref, print its checksum
|
|
ostree_file_path_to_checksum() {
|
|
repo=$1
|
|
ref=$2
|
|
path=$3
|
|
$CMD_PREFIX ostree --repo=$repo ls -C $ref $path | awk '{ print $5 }'
|
|
}
|
|
|
|
# Given an object checksum, print its relative file path
|
|
ostree_checksum_to_relative_object_path() {
|
|
repo=$1
|
|
checksum=$2
|
|
if grep -Eq -e '^mode=archive' ${repo}/config; then suffix=z; else suffix=''; fi
|
|
echo objects/${checksum:0:2}/${checksum:2}.file${suffix}
|
|
}
|
|
|
|
# Given a path to a file in a repo for a ref, print the (relative) path to its
|
|
# object
|
|
ostree_file_path_to_relative_object_path() {
|
|
repo=$1
|
|
ref=$2
|
|
path=$3
|
|
checksum=$(ostree_file_path_to_checksum $repo $ref $path)
|
|
test -n "${checksum}"
|
|
ostree_checksum_to_relative_object_path ${repo} ${checksum}
|
|
}
|
|
|
|
# Given a path to a file in a repo for a ref, print the path to its object
|
|
ostree_file_path_to_object_path() {
|
|
repo=$1
|
|
ref=$2
|
|
path=$3
|
|
relpath=$(ostree_file_path_to_relative_object_path $repo $ref $path)
|
|
echo ${repo}/${relpath}
|
|
}
|
|
|
|
# Assert ref $2 in repo $1 has checksum $3.
|
|
assert_ref () {
|
|
assert_streq $(${CMD_PREFIX} ostree rev-parse --repo=$1 $2) $3
|
|
}
|
|
|
|
# Assert no ref named $2 is present in repo $1.
|
|
assert_not_ref () {
|
|
if ${CMD_PREFIX} ostree rev-parse --repo=$1 $2 2>/dev/null; then
|
|
fatal "rev-parse $2 unexpectedly succeeded!"
|
|
fi
|
|
}
|
|
|
|
assert_fail () {
|
|
set +e
|
|
$@
|
|
if [ $? = 0 ] ; then
|
|
echo 1>&2 "$@ did not fail"; exit 1
|
|
fi
|
|
set -euo pipefail
|
|
}
|