Merge pull request #2544 from dbnicholson/finalize-block

finalize-staged: Ensure /boot and /sysroot automounts don't expire
This commit is contained in:
Colin Walters authored and GitHub committed 2022-08-30 15:12:32 -04:00
commit 6651b72a7a
8 files changed
+248 -41

No files matched your search

@@ -0,0 +1,35 @@
# Copyright (C) 2018 Red Hat, Inc.
# Copyright (C) 2022 Endless OS Foundation LLC
#
# 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/>.
# See https://github.com/ostreedev/ostree/pull/2543 for background.
[Unit]
Description=Hold /boot Open for OSTree Finalize Staged Deployment
Documentation=man:ostree(1)
ConditionPathExists=/run/ostree-booted
DefaultDependencies=no
RequiresMountsFor=/sysroot /boot
After=local-fs.target
Before=basic.target final.target
[Service]
Type=exec
# This is explicitly run in the root namespace to ensure an automounted
# /boot doesn't time out since autofs doesn't handle mount namespaces.
#
# https://bugzilla.redhat.com/show_bug.cgi?id=2056090
ExecStart=+/usr/bin/ostree admin finalize-staged --hold
+5
View File
@@ -29,6 +29,11 @@ Before=basic.target final.target
After=systemd-journal-flush.service
Conflicts=final.target
# Start the hold unit and ensure it stays active throughout this
# service.
Wants=ostree-finalize-staged-hold.service
After=ostree-finalize-staged-hold.service
[Service]
Type=oneshot
RemainAfterExit=yes
+63 -5
View File
@@ -1,5 +1,6 @@
/*
* Copyright (C) 2018 Red Hat, Inc.
* Copyright (C) 2022 Endless OS Foundation LLC
*
* SPDX-License-Identifier: LGPL-2.0+
*
@@ -19,8 +20,9 @@
#include "config.h"
#include "config.h"
#include <glib-unix.h>
#include <sched.h>
#include <signal.h>
#include <stdlib.h>
#include "ot-main.h"
@@ -32,10 +34,23 @@
#include "ostree-cmd-private.h"
#include "ostree.h"
static gboolean opt_hold;
static GOptionEntry options[] = {
{ "hold", 0, 0, G_OPTION_ARG_NONE, &opt_hold, "Hold /boot open during finalization", NULL },
{ NULL }
};
static gboolean
sigterm_cb (gpointer user_data)
{
gboolean *running = user_data;
g_print ("Received SIGTERM, exiting\n");
*running = FALSE;
g_main_context_wakeup (NULL);
return G_SOURCE_REMOVE;
}
/* Called by ostree-finalize-staged.service, and in turn
* invokes a cmdprivate function inside the shared library.
*/
@@ -50,13 +65,56 @@ ot_admin_builtin_finalize_staged (int argc, char **argv, OstreeCommandInvocation
g_autoptr(GOptionContext) context = g_option_context_new ("");
g_autoptr(OstreeSysroot) sysroot = NULL;
/* First parse the args without loading the sysroot to see what options are
* set. */
if (!ostree_admin_option_context_parse (context, options, &argc, &argv,
OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER,
OSTREE_ADMIN_BUILTIN_FLAG_NO_LOAD,
invocation, &sysroot, cancellable, error))
return FALSE;
if (!ostree_cmd__private__()->ostree_finalize_staged (sysroot, cancellable, error))
return FALSE;
if (opt_hold)
{
/* Load the sysroot unlocked so that a separate namespace isn't
* created. */
if (!ostree_admin_sysroot_load (sysroot,
OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER | OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED,
cancellable, error))
return FALSE;
/* In case it's an automount, open /boot so that the automount doesn't
* expire until before this process exits. If it did expire and got
* unmounted, the service would be stopped and the deployment would be
* finalized earlier than expected.
*/
int sysroot_fd = ostree_sysroot_get_fd (sysroot);
glnx_autofd int boot_fd = -1;
g_debug ("Opening /boot directory");
if (!glnx_opendirat (sysroot_fd, "boot", TRUE, &boot_fd, error))
return FALSE;
/* We want to keep /boot open until the deployment is finalized during
* system shutdown, so block on SIGTERM under the assumption that it will
* be received when systemd stops the unit.
*/
gboolean running = TRUE;
g_unix_signal_add (SIGTERM, sigterm_cb, &running);
g_print ("Waiting for SIGTERM\n");
while (running)
g_main_context_iteration (NULL, TRUE);
}
else
{
/* Load the sysroot with the normal flags and actually finalize the
* deployment. */
if (!ostree_admin_sysroot_load (sysroot,
OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER,
cancellable, error))
return FALSE;
if (!ostree_cmd__private__()->ostree_finalize_staged (sysroot, cancellable, error))
return FALSE;
}
return TRUE;
}
+49 -34
View File
@@ -579,41 +579,11 @@ on_sysroot_journal_msg (OstreeSysroot *sysroot,
}
gboolean
ostree_admin_option_context_parse (GOptionContext *context,
const GOptionEntry *main_entries,
int *argc,
char ***argv,
OstreeAdminBuiltinFlags flags,
OstreeCommandInvocation *invocation,
OstreeSysroot **out_sysroot,
GCancellable *cancellable,
GError **error)
ostree_admin_sysroot_load (OstreeSysroot *sysroot,
OstreeAdminBuiltinFlags flags,
GCancellable *cancellable,
GError **error)
{
/* Entries are listed in --help output in the order added. We add the
* main entries ourselves so that we can add the --sysroot entry first. */
g_option_context_add_main_entries (context, global_admin_entries, NULL);
if (!ostree_option_context_parse (context, main_entries, argc, argv,
invocation, NULL, cancellable, error))
return FALSE;
if (!opt_print_current_dir && (flags & OSTREE_ADMIN_BUILTIN_FLAG_NO_SYSROOT))
{
g_assert_null (out_sysroot);
/* Early return if no sysroot is requested */
return TRUE;
}
g_autoptr(GFile) sysroot_path = NULL;
if (opt_sysroot != NULL)
sysroot_path = g_file_new_for_path (opt_sysroot);
g_autoptr(OstreeSysroot) sysroot = ostree_sysroot_new (sysroot_path);
if (!ostree_sysroot_initialize (sysroot, error))
return FALSE;
g_signal_connect (sysroot, "journal-msg", G_CALLBACK (on_sysroot_journal_msg), NULL);
if ((flags & OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED) == 0)
{
/* If we're requested to lock the sysroot, first check if we're operating
@@ -657,6 +627,51 @@ ostree_admin_option_context_parse (GOptionContext *context,
}
}
return TRUE;
}
gboolean
ostree_admin_option_context_parse (GOptionContext *context,
const GOptionEntry *main_entries,
int *argc,
char ***argv,
OstreeAdminBuiltinFlags flags,
OstreeCommandInvocation *invocation,
OstreeSysroot **out_sysroot,
GCancellable *cancellable,
GError **error)
{
/* Entries are listed in --help output in the order added. We add the
* main entries ourselves so that we can add the --sysroot entry first. */
g_option_context_add_main_entries (context, global_admin_entries, NULL);
if (!ostree_option_context_parse (context, main_entries, argc, argv,
invocation, NULL, cancellable, error))
return FALSE;
if (!opt_print_current_dir && (flags & OSTREE_ADMIN_BUILTIN_FLAG_NO_SYSROOT))
{
g_assert_null (out_sysroot);
/* Early return if no sysroot is requested */
return TRUE;
}
g_autoptr(GFile) sysroot_path = NULL;
if (opt_sysroot != NULL)
sysroot_path = g_file_new_for_path (opt_sysroot);
g_autoptr(OstreeSysroot) sysroot = ostree_sysroot_new (sysroot_path);
if (!ostree_sysroot_initialize (sysroot, error))
return FALSE;
g_signal_connect (sysroot, "journal-msg", G_CALLBACK (on_sysroot_journal_msg), NULL);
if (opt_print_current_dir || (flags & OSTREE_ADMIN_BUILTIN_FLAG_NO_LOAD) == 0)
{
if (!ostree_admin_sysroot_load (sysroot, flags, cancellable, error))
return FALSE;
}
if (opt_print_current_dir)
{
g_autoptr(GPtrArray) deployments = NULL;
+6
View File
@@ -36,6 +36,7 @@ typedef enum {
OSTREE_ADMIN_BUILTIN_FLAG_SUPERUSER = (1 << 0),
OSTREE_ADMIN_BUILTIN_FLAG_UNLOCKED = (1 << 1),
OSTREE_ADMIN_BUILTIN_FLAG_NO_SYSROOT = (1 << 2),
OSTREE_ADMIN_BUILTIN_FLAG_NO_LOAD = (1 << 3),
} OstreeAdminBuiltinFlags;
@@ -91,6 +92,11 @@ gboolean ostree_admin_option_context_parse (GOptionContext *context,
OstreeSysroot **out_sysroot,
GCancellable *cancellable, GError **error);
gboolean ostree_admin_sysroot_load (OstreeSysroot *sysroot,
OstreeAdminBuiltinFlags flags,
GCancellable *cancellable,
GError **error);
gboolean ostree_ensure_repo_writable (OstreeRepo *repo, GError **error);
void ostree_print_gpg_verify_result (OstreeGpgVerifyResult *result);