rpm-ostree/tests/common/libvm.sh
Colin Walters 30bed29230 daemon/upgrader: Rework layer tracking
Working on initramfs, I hit a subtle issue with the fact that
I was trying to "redeploy", but with the origin file changed
during the process.

Previously, it was a bit unclear which parts of the upgrader logic are operating
on the *new* origin versus the "original origin".

The package layering code in the upgrader explicitly carries a delta on top in
the "add/remove" hash sets, which means it isn't visible to
`rpmostree_origin_is_locally_assembled()`.

Whereas for initramfs, I set a new origin. This broke things since we were
expecting to find a parent commit, but the original origin wasn't locally
assembled.

When looking more at this, I realized there's a far simpler model -
rather than keeping track of commit + origin, and using the origin
to try to determine whether or not the commit is layered, we can
keep track of `base_revision` and `final_revision`, and the latter
is only set if we're doing layering.

The diff speaks for itself here - a lot of fragile logic looking at the origin
drops away.

The next step here is probably to drop away the package layering hash sets, but
I'm trying to not change everything at once.

Closes: #579
Approved by: jlebon
2017-01-18 20:05:19 +00:00

210 lines
5.2 KiB
Bash

# Source library for installed virtualized shell script tests
#
# Copyright (C) 2016 Jonathan Lebon <jlebon@redhat.com>
#
# 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, write to the
# Free Software Foundation, Inc., 59 Temple Place - Suite 330,
# Boston, MA 02111-1307, USA.
# prepares the VM and library for action
vm_setup() {
# We assume that there's already a configured ssh-config
# file available to tell us how to connect to the VM.
if [ ! -f "${topsrcdir}/ssh-config" ]; then
echo "ERROR: No ssh-config found."
exit 1
fi
local sshopts="-F ${topsrcdir}/ssh-config \
-o User=root \
-o ControlMaster=auto \
-o ControlPath=${topsrcdir}/ssh.sock \
-o ControlPersist=yes"
export SSH="ssh $sshopts vmcheck"
export SCP="scp $sshopts"
}
vm_rsync() {
if ! test -f .vagrant/using_sshfs; then
pushd ${topsrcdir}
rsync -az --no-owner --no-group -e "ssh -o User=root -F ssh-config" \
--exclude .git/ . vmcheck:/var/roothome/sync
popd
fi
}
# run command in vm
# - $@ command to run
vm_cmd() {
$SSH "$@"
}
# run rpm-ostree in vm
# - $@ args
vm_rpmostree() {
$SSH env ASAN_OPTIONS=detect_leaks=false rpm-ostree "$@"
}
# copy files to a directory in the vm
# - $1 target directory
# - $2.. files & dirs to copy
vm_send() {
dir=$1; shift
vm_cmd mkdir -p $dir
$SCP -r "$@" vmcheck:$dir
}
# copy the test repo to the vm
vm_send_test_repo() {
vm_cmd rm -rf /tmp/vmcheck
vm_send /tmp/vmcheck ${commondir}/compose/yum/repo
cat > vmcheck.repo << EOF
[test-repo]
name=test-repo
baseurl=file:///tmp/vmcheck/repo
EOF
vm_send /etc/yum.repos.d vmcheck.repo
}
# wait until ssh is available on the vm
# - $1 timeout in second (optional)
# - $2 previous bootid (optional)
vm_ssh_wait() {
timeout=${1:-0}; shift
old_bootid=${1:-}; shift
if ! vm_cmd true; then
echo "Failed to log into VM, retrying with debug:"
$SSH -o LogLevel=debug true || true
fi
while [ $timeout -gt 0 ]; do
if bootid=$(vm_get_boot_id 2>/dev/null); then
if [[ $bootid != $old_bootid ]]; then
return 0
fi
fi
if test $(($timeout % 5)) == 0; then
echo "Still failed to log into VM, retrying for $timeout seconds"
fi
timeout=$((timeout - 1))
sleep 1
done
false "Timed out while waiting for SSH."
}
vm_get_boot_id() {
vm_cmd cat /proc/sys/kernel/random/boot_id
}
# reboot the vm
vm_reboot() {
vm_cmd sync
bootid=$(vm_get_boot_id 2>/dev/null)
vm_cmd systemctl reboot || :
vm_ssh_wait 120 $bootid
}
# check that the given files/dirs exist on the VM
# - $@ files/dirs to check for
vm_has_files() {
for file in "$@"; do
if ! vm_cmd test -e $file; then
return 1
fi
done
}
# check that the packages are installed
# - $@ packages to check for
vm_has_packages() {
for pkg in "$@"; do
if ! vm_cmd rpm -q $pkg; then
return 1
fi
done
}
# retrieve info from the booted deployment
# - $1 key to retrieve
vm_get_booted_deployment_info() {
key=$1
vm_rpmostree status --json | \
python -c "
import sys, json
deployments = json.load(sys.stdin)[\"deployments\"]
booted = None
for deployment in deployments:
if deployment[\"booted\"]:
booted = deployment
break
if not booted:
print \"Failed to determine currently booted deployment\"
exit(1)
if \"$key\" in booted:
data = booted[\"$key\"]
if type(data) is list:
print \" \".join(data)
else:
print data
"
}
# print the layered packages
vm_get_layered_packages() {
vm_get_booted_deployment_info packages
}
# check that the packages are currently layered
# - $@ packages to check for
vm_has_layered_packages() {
pkgs=$(vm_get_layered_packages)
for pkg in "$@"; do
if [[ " $pkgs " != *$pkg* ]]; then
return 1
fi
done
}
# retrieve the checksum of the currently booted deployment
vm_get_booted_csum() {
vm_get_booted_deployment_info checksum
}
# make multiple consistency checks on a test pkg
# - $1 package to check for
# - $2 either "present" or "absent"
vm_assert_layered_pkg() {
pkg=$1; shift
policy=$1; shift
set +e
vm_has_packages $pkg; pkg_in_rpmdb=$?
vm_has_layered_packages $pkg; pkg_is_layered=$?
[ $pkg_in_rpmdb == 0 ] && [ $pkg_is_layered == 0 ]; pkg_present=$?
[ $pkg_in_rpmdb != 0 ] && [ $pkg_is_layered != 0 ]; pkg_absent=$?
set -e
if [ $policy == present ] && [ $pkg_present != 0 ]; then
vm_cmd rpm-ostree status
assert_not_reached "pkg $pkg is not present"
fi
if [ $policy == absent ] && [ $pkg_absent != 0 ]; then
vm_cmd rpm-ostree status
assert_not_reached "pkg $pkg is not absent"
fi
}