diff --git a/Makefile-tests.am b/Makefile-tests.am index 89675288..6aae5f05 100644 --- a/Makefile-tests.am +++ b/Makefile-tests.am @@ -82,6 +82,7 @@ _installed_or_uninstalled_test_scripts = \ tests/test-local-pull-depth.sh \ tests/test-gpg-signed-commit.sh \ tests/test-admin-upgrade-unconfigured.sh \ + tests/test-admin-upgrade-endoflife.sh \ tests/test-admin-deploy-syslinux.sh \ tests/test-admin-deploy-2.sh \ tests/test-admin-deploy-karg.sh \ diff --git a/src/libostree/ostree-sysroot-upgrader.c b/src/libostree/ostree-sysroot-upgrader.c index 9816b3d6..45ef90e6 100644 --- a/src/libostree/ostree-sysroot-upgrader.c +++ b/src/libostree/ostree-sysroot-upgrader.c @@ -512,6 +512,10 @@ ostree_sysroot_upgrader_pull_one_dir (OstreeSysrootUpgrader *self, char *refs_to_fetch[] = { NULL, NULL }; const char *from_revision = NULL; g_autofree char *origin_refspec = NULL; + g_autofree char *new_revision = NULL; + g_autoptr(GVariant) new_variant = NULL; + g_autoptr(GVariant) new_metadata = NULL; + g_autoptr(GVariant) rebase = NULL; if (self->override_csum != NULL) refs_to_fetch[0] = self->override_csum; @@ -541,6 +545,48 @@ ostree_sysroot_upgrader_pull_one_dir (OstreeSysrootUpgrader *self, ostree_async_progress_finish (progress); } + /* Check to see if the commit marks the ref as EOL, redirecting to + * another. */ + if (!ostree_repo_resolve_rev (repo, origin_refspec, FALSE, + &new_revision, error)) + return FALSE; + + if (!ostree_repo_load_variant (repo, + OSTREE_OBJECT_TYPE_COMMIT, + new_revision, + &new_variant, + error)) + return FALSE; + + g_variant_get_child (new_variant, 0, "@a{sv}", &new_metadata); + rebase = g_variant_lookup_value (new_metadata, "ostree.endoflife-rebase", G_VARIANT_TYPE_STRING); + if (rebase) + { + const char *new_ref = g_variant_get_string (rebase, 0); + + /* Pull the new ref */ + if (self->origin_remote && + (upgrader_flags & OSTREE_SYSROOT_UPGRADER_PULL_FLAGS_SYNTHETIC) == 0) + { + refs_to_fetch[0] = (char *) new_ref; + if (!ostree_repo_pull_one_dir (repo, self->origin_remote, dir_to_pull, refs_to_fetch, + flags, progress, cancellable, error)) + return FALSE; + } + + /* Use the new ref for the rest of the update process */ + g_free (self->origin_ref); + self->origin_ref = g_strdup(new_ref); + g_free (origin_refspec); + + if (self->origin_remote) + origin_refspec = g_strconcat (self->origin_remote, ":", new_ref, NULL); + else + origin_refspec = g_strdup (new_ref); + + g_key_file_set_string (self->origin, "origin", "refspec", origin_refspec); + } + if (self->override_csum != NULL) { if (!ostree_repo_set_ref_immediate (repo, diff --git a/tests/test-admin-upgrade-endoflife.sh b/tests/test-admin-upgrade-endoflife.sh new file mode 100755 index 00000000..a58c64ce --- /dev/null +++ b/tests/test-admin-upgrade-endoflife.sh @@ -0,0 +1,72 @@ +#!/bin/bash +# +# Copyright (C) 2014 Colin Walters +# +# 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. + +set -euo pipefail + +. $(dirname $0)/libtest.sh + +# Exports OSTREE_SYSROOT so --sysroot not needed. +setup_os_repository "archive-z2" "syslinux" +# This does: +# - init ostree repo in testos-repo +# - create system files in osdata and commit twice those contents into testos-repo +# - copy osdata to osdata-devel and make another change then commit +# - create sysroot with init-fs and os-init and syslinux +# sysroot has /ostree basics (but no contents), syslinux cfg and empty root dirs + +echo "1..3" + +cd ${test_tmpdir} +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos $(cat httpd-address)/ostree/testos-repo +${CMD_PREFIX} ostree --repo=sysroot/ostree/repo pull testos testos/buildmaster/x86_64-runtime +rev=$(${CMD_PREFIX} ostree --repo=sysroot/ostree/repo rev-parse testos/buildmaster/x86_64-runtime) +echo "rev=${rev}" + +# Now sysroot/ostree has the objects from the testos-repo (obtained over http +# and kept in remote "testos"), but there is no deployment + +# This initial deployment gets kicked off with some kernel arguments +${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime +assert_has_dir sysroot/boot/ostree/testos-${bootcsum} + +echo "ok deploy" + +# Create a new branch which we want to migrate to +os_repository_new_commit 1 1 testos/buildmaster/newbranch +# bootcsum now refers to this new commit + +# Create a new commit with an empty tree, which marks the original branch as +# EOL, redirecting to the new one. +mkdir empty +${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo commit --tree=dir=$(pwd)/empty --add-metadata-string "ostree.endoflife=Product discontinued" --add-metadata-string "ostree.endoflife-rebase=testos/buildmaster/newbranch" -b testos/buildmaster/x86_64-runtime -s "EOL redirect to new branch" + +echo "ok new branch" + +# Upgrade existing checkout +${CMD_PREFIX} ostree admin upgrade --os=testos --pull-only +${CMD_PREFIX} ostree admin upgrade --os=testos --deploy-only + +# Check we got redirected to the new branch +assert_file_has_content sysroot/boot/loader/entries/ostree-testos-0.conf "${bootcsum}" +rev=$(${CMD_PREFIX} ostree --repo=${test_tmpdir}/testos-repo rev-parse testos/buildmaster/newbranch) +assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0/usr/bin/content-iteration "1" + +assert_file_has_content sysroot/ostree/deploy/testos/deploy/${rev}.0.origin "newbranch" + +echo "ok update and redirect"