Merge pull request #2544 from dbnicholson/finalize-block
finalize-staged: Ensure /boot and /sysroot automounts don't expire
This commit is contained in:
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
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in new issue
Block a user