mirror of
https://github.com/ostreedev/ostree.git
synced 2025-03-30 10:50:31 +03:00
admin/switch: New builtin to switch between trees
This is something I want to make easier, as it better showcases the flexibility of OSTree.
This commit is contained in:
parent
4fff43da1b
commit
878a43411e
@ -58,6 +58,7 @@ ostree_SOURCES += \
|
||||
src/ostree/ot-admin-builtin-cleanup.c \
|
||||
src/ostree/ot-admin-builtin-os-init.c \
|
||||
src/ostree/ot-admin-builtin-status.c \
|
||||
src/ostree/ot-admin-builtin-switch.c \
|
||||
src/ostree/ot-admin-builtin-upgrade.c \
|
||||
src/ostree/ot-admin-builtins.h \
|
||||
src/ostree/ot-admin-functions.h \
|
||||
|
@ -35,6 +35,7 @@ testfiles = test-basic \
|
||||
test-admin-deploy-syslinux \
|
||||
test-admin-deploy-2 \
|
||||
test-admin-deploy-karg \
|
||||
test-admin-deploy-switch \
|
||||
test-admin-deploy-etcmerge-cornercases \
|
||||
test-admin-deploy-uboot \
|
||||
test-setuid \
|
||||
|
198
src/ostree/ot-admin-builtin-switch.c
Normal file
198
src/ostree/ot-admin-builtin-switch.c
Normal file
@ -0,0 +1,198 @@
|
||||
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
|
||||
*
|
||||
* Copyright (C) 2012,2014 Colin Walters <walters@verbum.org>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "ot-admin-builtins.h"
|
||||
#include "ot-admin-functions.h"
|
||||
#include "ot-builtins-common.h"
|
||||
#include "ostree.h"
|
||||
#include "otutil.h"
|
||||
#include "libgsystem.h"
|
||||
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <glib/gi18n.h>
|
||||
|
||||
static gboolean opt_reboot;
|
||||
static char *opt_osname;
|
||||
|
||||
static GOptionEntry options[] = {
|
||||
{ "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname, "Specify operating system root to use", NULL },
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
gboolean
|
||||
ot_admin_builtin_switch (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, GError **error)
|
||||
{
|
||||
gboolean ret = FALSE;
|
||||
GOptionContext *context;
|
||||
const char *new_ref = NULL;
|
||||
gs_unref_object OstreeRepo *repo = NULL;
|
||||
gs_free char *origin_refspec = NULL;
|
||||
gs_free char *origin_remote = NULL;
|
||||
gs_free char *origin_ref = NULL;
|
||||
gs_free char *new_revision = NULL;
|
||||
gs_unref_object GFile *deployment_path = NULL;
|
||||
gs_unref_object GFile *deployment_origin_path = NULL;
|
||||
gs_unref_object OstreeDeployment *merge_deployment = NULL;
|
||||
gs_unref_object OstreeDeployment *new_deployment = NULL;
|
||||
GKeyFile *origin;
|
||||
|
||||
context = g_option_context_new ("REF - Construct new tree from current origin and deploy it, if it changed");
|
||||
g_option_context_add_main_entries (context, options, NULL);
|
||||
|
||||
if (!g_option_context_parse (context, &argc, &argv, error))
|
||||
goto out;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
ot_util_usage_error (context, "REF must be specified", error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
new_ref = argv[1];
|
||||
|
||||
if (!ostree_sysroot_load (sysroot, cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (!ot_admin_require_booted_deployment_or_osname (sysroot, opt_osname,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
merge_deployment = ostree_sysroot_get_merge_deployment (sysroot, opt_osname);
|
||||
if (merge_deployment == NULL)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"No previous deployment for OS '%s'", opt_osname);
|
||||
goto out;
|
||||
}
|
||||
|
||||
deployment_path = ostree_sysroot_get_deployment_directory (sysroot, merge_deployment);
|
||||
deployment_origin_path = ostree_sysroot_get_deployment_origin_path (deployment_path);
|
||||
|
||||
if (!ostree_sysroot_get_repo (sysroot, &repo, cancellable, error))
|
||||
goto out;
|
||||
|
||||
origin = ostree_deployment_get_origin (merge_deployment);
|
||||
if (!origin)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"No origin known for current deployment");
|
||||
goto out;
|
||||
}
|
||||
origin_refspec = g_key_file_get_string (origin, "origin", "refspec", NULL);
|
||||
if (!origin_refspec)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"No origin/refspec in current deployment origin; cannot change via ostree");
|
||||
goto out;
|
||||
}
|
||||
if (!ostree_parse_refspec (origin_refspec, &origin_remote, &origin_ref, error))
|
||||
goto out;
|
||||
|
||||
if (strcmp (origin_ref, new_ref) == 0)
|
||||
{
|
||||
g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
|
||||
"Old and new refs are equal: %s", new_ref);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (origin_remote)
|
||||
{
|
||||
OstreeRepoPullFlags pullflags = 0;
|
||||
char *refs_to_fetch[] = { (char*)new_ref, NULL };
|
||||
GSConsole *console;
|
||||
gs_unref_object OstreeAsyncProgress *progress = NULL;
|
||||
|
||||
console = gs_console_get ();
|
||||
if (console)
|
||||
{
|
||||
gs_console_begin_status_line (console, "", NULL, NULL);
|
||||
progress = ostree_async_progress_new_and_connect (ot_common_pull_progress, console);
|
||||
}
|
||||
|
||||
g_print ("Fetching remote %s ref %s\n", origin_remote, new_ref);
|
||||
|
||||
if (!ostree_repo_pull (repo, origin_remote, refs_to_fetch, pullflags, progress,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!ostree_repo_resolve_rev (repo, new_ref, FALSE, &new_revision,
|
||||
error))
|
||||
goto out;
|
||||
|
||||
if (strcmp (ostree_deployment_get_csum (merge_deployment), new_revision) == 0)
|
||||
{
|
||||
g_print ("Refspec %s is unchanged\n", origin_refspec);
|
||||
}
|
||||
else
|
||||
{
|
||||
gs_unref_object GFile *real_sysroot = g_file_new_for_path ("/");
|
||||
|
||||
/* Here we perform cleanup of any leftover data from previous
|
||||
* partial failures. This avoids having to call gs_shutil_rm_rf()
|
||||
* at random points throughout the process.
|
||||
*
|
||||
* TODO: Add /ostree/transaction file, and only do this cleanup if
|
||||
* we find it.
|
||||
*/
|
||||
if (!ostree_sysroot_cleanup (sysroot, cancellable, error))
|
||||
{
|
||||
g_prefix_error (error, "Performing initial cleanup: ");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (!ostree_sysroot_deploy_tree (sysroot,
|
||||
opt_osname, new_revision, origin,
|
||||
merge_deployment,
|
||||
NULL,
|
||||
&new_deployment,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (!ot_admin_complete_deploy_one (sysroot, opt_osname,
|
||||
new_deployment, merge_deployment, FALSE,
|
||||
cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (!ostree_repo_prepare_transaction (repo, NULL, cancellable, error))
|
||||
goto out;
|
||||
|
||||
g_print ("Deleting ref '%s:%s'\n", origin_remote, origin_ref);
|
||||
ostree_repo_transaction_set_ref (repo, origin_remote, origin_ref, NULL);
|
||||
|
||||
if (!ostree_repo_commit_transaction (repo, NULL, cancellable, error))
|
||||
goto out;
|
||||
|
||||
if (opt_reboot && g_file_equal (ostree_sysroot_get_path (sysroot), real_sysroot))
|
||||
{
|
||||
gs_subprocess_simple_run_sync (NULL, GS_SUBPROCESS_STREAM_DISPOSITION_INHERIT,
|
||||
cancellable, error,
|
||||
"systemctl", "reboot", NULL);
|
||||
}
|
||||
}
|
||||
|
||||
ret = TRUE;
|
||||
out:
|
||||
if (context)
|
||||
g_option_context_free (context);
|
||||
return ret;
|
||||
}
|
@ -34,6 +34,7 @@ gboolean ot_admin_builtin_deploy (int argc, char **argv, OstreeSysroot *sysroot,
|
||||
gboolean ot_admin_builtin_cleanup (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, GError **error);
|
||||
gboolean ot_admin_builtin_status (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, GError **error);
|
||||
gboolean ot_admin_builtin_diff (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, GError **error);
|
||||
gboolean ot_admin_builtin_switch (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, GError **error);
|
||||
gboolean ot_admin_builtin_upgrade (int argc, char **argv, OstreeSysroot *sysroot, GCancellable *cancellable, GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
@ -45,6 +45,7 @@ static OstreeAdminCommand admin_subcommands[] = {
|
||||
{ "upgrade", ot_admin_builtin_upgrade },
|
||||
{ "cleanup", ot_admin_builtin_cleanup },
|
||||
{ "status", ot_admin_builtin_status },
|
||||
{ "switch", ot_admin_builtin_switch },
|
||||
{ "config-diff", ot_admin_builtin_diff },
|
||||
{ NULL, NULL }
|
||||
};
|
||||
|
@ -226,6 +226,13 @@ EOF
|
||||
echo "a new executable" > usr/bin/sh
|
||||
ostree --repo=${test_tmpdir}/testos-repo commit -b testos/buildmaster/x86_64-runtime -s "Build"
|
||||
|
||||
cd ${test_tmpdir}
|
||||
cp -a osdata osdata-devel
|
||||
cd osdata-devel
|
||||
mkdir -p usr/include
|
||||
echo "a development header" > usr/include/foo.h
|
||||
ostree --repo=${test_tmpdir}/testos-repo commit -b testos/buildmaster/x86_64-devel -s "Build"
|
||||
|
||||
ostree --repo=${test_tmpdir}/testos-repo fsck -q
|
||||
|
||||
cd ${test_tmpdir}
|
||||
|
44
tests/test-admin-deploy-switch.sh
Normal file
44
tests/test-admin-deploy-switch.sh
Normal file
@ -0,0 +1,44 @@
|
||||
#!/bin/bash
|
||||
#
|
||||
# Copyright (C) 2011,2014 Colin Walters <walters@verbum.org>
|
||||
#
|
||||
# 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 -e
|
||||
|
||||
. $(dirname $0)/libtest.sh
|
||||
|
||||
echo "1..1"
|
||||
|
||||
setup_os_repository "archive-z2" "syslinux"
|
||||
|
||||
echo "ok setup"
|
||||
|
||||
echo "1..2"
|
||||
|
||||
ostree --repo=sysroot/ostree/repo remote add --set=gpg-verify=false testos file://$(pwd)/testos-repo
|
||||
ostree --repo=sysroot/ostree/repo pull testos testos/buildmaster/x86_64-runtime
|
||||
ostree admin --sysroot=sysroot deploy --karg=root=LABEL=MOO --karg=quiet --os=testos testos:testos/buildmaster/x86_64-runtime
|
||||
assert_not_has_file sysroot/ostree/deploy/testos/current/usr/include/foo.h
|
||||
if ostree admin --sysroot=sysroot switch --os=testos testos/buildmaster/x86_64-runtime; then
|
||||
assert_not_reached "Switch to same ref unexpectedly succeeded"
|
||||
fi
|
||||
echo "ok switch expected error"
|
||||
|
||||
ostree admin --sysroot=sysroot switch --os=testos testos/buildmaster/x86_64-devel
|
||||
assert_file_has_content sysroot/ostree/deploy/testos/current/usr/include/foo.h 'header'
|
||||
|
||||
echo "ok switch"
|
Loading…
x
Reference in New Issue
Block a user