Skip to content

Commit

Permalink
Add new ex initramfs-etc command
Browse files Browse the repository at this point in the history
This command allows users to cheaply inject configuration files in the
initramfs stage without having to regenerate the whole initramfs (or
even a new OSTree commit). This will be useful for configuring services
involved in bringing up the root block device.

```
$ echo 'hello world' > /etc/foobar
$ rpm-ostree ex initramfs-etc --track /etc/foobar
Staging deployment... done
Run "systemctl reboot" to start a reboot
$ rpm-ostree status
State: idle
Deployments:
  ostree://fedora:fedora/x86_64/coreos/testing-devel
                   Version: 32.20200716.dev.1 (2020-07-16T02:47:29Z)
                    Commit: 9a817d75bef81b955179be6e602d1e6ae350645b6323231a62ba2ee6e5b9644b
              GPGSignature: (unsigned)
              InitramfsEtc: /etc/foobar

● ostree://fedora:fedora/x86_64/coreos/testing-devel
                   Version: 32.20200716.dev.1 (2020-07-16T02:47:29Z)
                    Commit: 9a817d75bef81b955179be6e602d1e6ae350645b6323231a62ba2ee6e5b9644b
              GPGSignature: (unsigned)
$ reboot
(boot into rd.break)
sh-5.0# cat /etc/foobar
hello world
```

See the libostree side of this at:
ostreedev/ostree#2155

Lots more discussions in:
coreos/fedora-coreos-tracker#94
  • Loading branch information
jlebon committed Oct 21, 2020
1 parent e99be88 commit 7ba80d5
Show file tree
Hide file tree
Showing 19 changed files with 828 additions and 19 deletions.
1 change: 1 addition & 0 deletions Makefile-rpm-ostree.am
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ rpm_ostree_SOURCES = src/app/main.c \
src/app/rpmostree-builtin-cliwrap.c \
src/app/rpmostree-builtin-cleanup.c \
src/app/rpmostree-builtin-initramfs.c \
src/app/rpmostree-builtin-initramfs-etc.c \
src/app/rpmostree-builtin-livefs.c \
src/app/rpmostree-builtin-usroverlay.c \
src/app/rpmostree-builtin-override.c \
Expand Down
2 changes: 1 addition & 1 deletion configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -94,7 +94,7 @@ LIBS="$save_LIBS"
# Remember to update AM_CPPFLAGS in Makefile.am when bumping GIO req.
PKG_CHECK_MODULES(PKGDEP_GIO_UNIX, [gio-unix-2.0])
PKG_CHECK_MODULES(PKGDEP_RPMOSTREE, [gio-unix-2.0 >= 2.50.0 json-glib-1.0
ostree-1 >= 2020.1
ostree-1 >= 2020.7
libsystemd
polkit-gobject-1
rpm librepo libsolv
Expand Down
30 changes: 30 additions & 0 deletions man/rpm-ostree.xml
Original file line number Diff line number Diff line change
Expand Up @@ -662,6 +662,36 @@ Boston, MA 02111-1307, USA.
</listitem>
</varlistentry>

<varlistentry>
<term><command>ex initramfs-etc</command></term>

<listitem>
<para>
Experimental feature; subject to change.
</para>

<para>
Add configuration (<literal>/etc</literal>) files into the initramfs without
regenerating the entire initramfs. This is useful to be able to configure
services backing the root block device as well as early-boot services like
systemd and journald.
</para>

<para>
Use <command>--track</command> to start tracking a specific file. Can be
specified multiple times. A new deployment will be generated. Use
<command>--untrack</command> or <command>--untrack-all</command> to stop
tracking files.
</para>

<para>
When there are tracked files, any future created deployment (e.g. when doing an
upgrade) will ensure that they are synced. You can additionally use
<command>--force-sync</command> to simply generate a new deployment with the
latest versions of tracked files without upgrading.
</para>
</listitem>
</varlistentry>
</variablelist>
</refsect1>

Expand Down
2 changes: 1 addition & 1 deletion packaging/rpm-ostree.spec.in
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ BuildRequires: gnome-common
BuildRequires: /usr/bin/g-ir-scanner
# Core requirements
# One way to check this: `objdump -p /path/to/rpm-ostree | grep LIBOSTREE` and pick the highest (though that might miss e.g. new struct members)
BuildRequires: pkgconfig(ostree-1) >= 2019.2
BuildRequires: pkgconfig(ostree-1) >= 2020.7
BuildRequires: pkgconfig(polkit-gobject-1)
BuildRequires: pkgconfig(json-glib-1.0)
BuildRequires: pkgconfig(rpm)
Expand Down
2 changes: 2 additions & 0 deletions src/app/rpmostree-builtin-ex.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ static RpmOstreeCommand ex_subcommands[] = {
"Convert an rpm-ostree rojig into an OSTree commit", rpmostree_ex_builtin_rojig2commit },
{ "history", RPM_OSTREE_BUILTIN_FLAG_LOCAL_CMD,
"Inspect rpm-ostree history of the system", rpmostree_ex_builtin_history },
{ "initramfs-etc", RPM_OSTREE_BUILTIN_FLAG_REQUIRES_ROOT,
"Track initramfs configuration files", rpmostree_ex_builtin_initramfs_etc },
{ NULL, 0, NULL, NULL }
};

Expand Down
156 changes: 156 additions & 0 deletions src/app/rpmostree-builtin-initramfs-etc.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*-
*
* Copyright (C) 2020 Jonathan Lebon <jonathan@jlebon.com>
*
* This program 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 licence 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 <string.h>
#include <glib-unix.h>

#include "rpmostree-ex-builtins.h"
#include "rpmostree-libbuiltin.h"
#include "rpmostree-dbus-helpers.h"

#include <libglnx.h>

static char *opt_osname;
static gboolean opt_force_sync;
static char **opt_track;
static char **opt_untrack;
static gboolean opt_untrack_all;
static gboolean opt_reboot;
static gboolean opt_lock_finalization;
static gboolean opt_unchanged_exit_77;

static GOptionEntry option_entries[] = {
{ "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname, "Operate on provided OSNAME", "OSNAME" },
{ "force-sync", 0, 0, G_OPTION_ARG_NONE, &opt_force_sync, "Deploy a new tree with the latest tracked /etc files", NULL },
{ "track", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_track, "Track root /etc file", "FILE" },
{ "untrack", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_untrack, "Untrack root /etc file", "FILE" },
{ "untrack-all", 0, 0, G_OPTION_ARG_NONE, &opt_untrack_all, "Untrack all root /etc files", NULL },
{ "reboot", 'r', 0, G_OPTION_ARG_NONE, &opt_reboot, "Initiate a reboot after operation is complete", NULL },
{ "lock-finalization", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &opt_lock_finalization, "Prevent automatic deployment finalization on shutdown", NULL },
{ "unchanged-exit-77", 0, 0, G_OPTION_ARG_NONE, &opt_unchanged_exit_77, "If no new deployment made, exit 77", NULL },

{ NULL }
};

gboolean
rpmostree_ex_builtin_initramfs_etc (int argc,
char **argv,
RpmOstreeCommandInvocation *invocation,
GCancellable *cancellable,
GError **error)
{
g_autoptr(GOptionContext) context = g_option_context_new ("");

_cleanup_peer_ GPid peer_pid = 0;
glnx_unref_object RPMOSTreeSysroot *sysroot_proxy = NULL;
if (!rpmostree_option_context_parse (context,
option_entries,
&argc, &argv,
invocation,
cancellable,
NULL, NULL,
&sysroot_proxy,
&peer_pid,
NULL,
error))
return FALSE;

glnx_unref_object RPMOSTreeOS *os_proxy = NULL;
if (!rpmostree_load_os_proxy (sysroot_proxy, opt_osname,
cancellable, &os_proxy, error))
return FALSE;

g_autoptr(GVariant) previous_deployment = rpmostree_os_dup_default_deployment (os_proxy);

if (!(opt_track || opt_untrack || opt_untrack_all || opt_force_sync))
{
if (opt_reboot)
return glnx_throw (error, "Cannot use ---reboot without --track, --untrack, --untrack-all, or --force-sync");

g_autofree char **files = NULL;
g_autoptr(GVariant) deployments = rpmostree_sysroot_dup_deployments (sysroot_proxy);
if (g_variant_n_children (deployments) > 0)
{
g_autoptr(GVariant) pending = g_variant_get_child_value (deployments, 0);
g_auto(GVariantDict) dict;
g_variant_dict_init (&dict, pending);

g_variant_dict_lookup (&dict, "initramfs-etc", "^a&s", &files);
}

if (!files || !*files)
g_print ("No tracked files.\n");
else
{
g_print ("Tracked files:\n");
for (char **it = files; it && *it; it++)
g_print (" %s\n", *it);
}

return TRUE; /* note early return */
}

char *empty_strv[] = {NULL};
if (!opt_track)
opt_track = empty_strv;
if (!opt_untrack)
opt_untrack = empty_strv;

GVariantDict dict;
g_variant_dict_init (&dict, NULL);
g_variant_dict_insert (&dict, "reboot", "b", opt_reboot);
g_variant_dict_insert (&dict, "initiating-command-line", "s", invocation->command_line);
g_variant_dict_insert (&dict, "lock-finalization", "b", opt_lock_finalization);
g_autoptr(GVariant) options = g_variant_ref_sink (g_variant_dict_end (&dict));

g_autofree char *transaction_address = NULL;
if (!rpmostree_os_call_initramfs_etc_sync (os_proxy,
(const char *const*)opt_track,
(const char *const*)opt_untrack,
opt_untrack_all,
opt_force_sync,
options,
&transaction_address,
cancellable,
error))
return FALSE;

if (!rpmostree_transaction_get_response_sync (sysroot_proxy,
transaction_address,
cancellable,
error))
return FALSE;

if (!opt_reboot)
{
if (!rpmostree_has_new_default_deployment (os_proxy, previous_deployment))
{
if (opt_unchanged_exit_77)
invocation->exit_code = RPM_OSTREE_EXIT_UNCHANGED;
return TRUE;
}

g_print ("Run \"systemctl reboot\" to start a reboot\n");
}

return TRUE;
}
2 changes: 1 addition & 1 deletion src/app/rpmostree-builtin-reset.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ static GOptionEntry option_entries[] = {
{ "reboot", 'r', 0, G_OPTION_ARG_NONE, &opt_reboot, "Initiate a reboot after transaction is complete", NULL },
{ "overlays", 'l', 0, G_OPTION_ARG_NONE, &opt_overlays, "Remove all overlayed packages", NULL },
{ "overrides", 'o', 0, G_OPTION_ARG_NONE, &opt_overrides, "Remove all overrides", NULL },
{ "initramfs", 'i', 0, G_OPTION_ARG_NONE, &opt_initramfs, "Stop regenerating initramfs", NULL },
{ "initramfs", 'i', 0, G_OPTION_ARG_NONE, &opt_initramfs, "Stop regenerating initramfs or tracking files", NULL },
{ "lock-finalization", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &opt_lock_finalization, "Prevent automatic deployment finalization on shutdown", NULL },
{ NULL }
};
Expand Down
7 changes: 7 additions & 0 deletions src/app/rpmostree-builtin-status.c
Original file line number Diff line number Diff line change
Expand Up @@ -870,6 +870,13 @@ print_one_deployment (RPMOSTreeSysroot *sysroot_proxy,
g_string_append (buf, "regenerate");
rpmostree_print_kv ("Initramfs", max_key_len, buf->str);
}

g_autofree char **initramfs_etc_files = NULL;
g_variant_dict_lookup (dict, "initramfs-etc", "^a&s", &initramfs_etc_files);
if (initramfs_etc_files && *initramfs_etc_files)
/* XXX: not really packages but it works... should just rename that function */
print_packages ("InitramfsEtc", max_key_len, (const char**)initramfs_etc_files, NULL);

gboolean pinned = FALSE;
g_variant_dict_lookup (dict, "pinned", "b", &pinned);
if (pinned)
Expand Down
1 change: 1 addition & 0 deletions src/app/rpmostree-ex-builtins.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ BUILTINPROTO(livefs);
BUILTINPROTO(commit2rojig);
BUILTINPROTO(rojig2commit);
BUILTINPROTO(history);
BUILTINPROTO(initramfs_etc);

#undef BUILTINPROTO

Expand Down
9 changes: 9 additions & 0 deletions src/daemon/org.projectatomic.rpmostree1.xml
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,15 @@
<arg type="s" name="transaction_address" direction="out"/>
</method>

<method name="InitramfsEtc">
<arg type="as" name="track" direction="in"/>
<arg type="as" name="untrack" direction="in"/>
<arg type="b" name="untrack_all" direction="in"/>
<arg type="b" name="force_sync" direction="in"/>
<arg type="a{sv}" name="options" direction="in"/>
<arg type="s" name="transaction_address" direction="out"/>
</method>

<!-- Available options:
"reboot" (type 'b')
-->
Expand Down
Loading

0 comments on commit 7ba80d5

Please sign in to comment.