ostree-sysroot: make simple_write_deployment smarter

This is a follow-up to https://github.com/ostreedev/ostree/pull/1097.
We make simple_write_deployment smart enough so that it can be used for
rpm-ostree's purposes. This is mostly an upstreaming of logic that
already existed there.

Notably we correctly append NOT_DEFAULT deployments *after* the booted
deployment and we now support RETAIN_PENDING and RETAIN_ROLLBACK flags
to have more granularity on deployment pruning.

Expose these new flags on the CLI using new options (as well as expose
the previously existing NOT_DEFAULT flag as --not-as-default).

I couldn't add tests for --retain-pending because the merge deployment
is always the topmost one. Though I did check that it worked in a VM.

Closes: #1110
Approved by: cgwalters
This commit is contained in:
Jonathan Lebon authored and Atomic Bot committed 2017-08-25 01:02:15 +00:00
1 parent d0f40a6af8
commit 9342be6e34
9 files changed
+143 -41

No files matched your search

+48 -18
View File
@@ -1487,6 +1487,12 @@ ostree_sysroot_init_osname (OstreeSysroot *self,
* If %OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN is
* specified, then all current deployments will be kept.
*
* If %OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_PENDING is
* specified, then pending deployments will be kept.
*
* If %OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_ROLLBACK is
* specified, then rollback deployments will be kept.
*
* If %OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT is
* specified, then instead of prepending, the new deployment will be
* added right after the booted or merge deployment, instead of first.
@@ -1507,10 +1513,14 @@ ostree_sysroot_simple_write_deployment (OstreeSysroot *sysroot,
{
const gboolean postclean =
(flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NO_CLEAN) == 0;
const gboolean retain =
(flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN) > 0;
const gboolean make_default =
!((flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT) > 0);
const gboolean retain_pending =
(flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_PENDING) > 0;
const gboolean retain_rollback =
(flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_ROLLBACK) > 0;
gboolean retain =
(flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN) > 0;
g_autoptr(GPtrArray) deployments = ostree_sysroot_get_deployments (sysroot);
OstreeDeployment *booted_deployment = ostree_sysroot_get_booted_deployment (sysroot);
@@ -1526,34 +1536,54 @@ ostree_sysroot_simple_write_deployment (OstreeSysroot *sysroot,
added_new = TRUE;
}
/* without a booted and a merge deployment, retain_pending/rollback become meaningless;
* let's just retain all deployments in that case */
if (!booted_deployment && !merge_deployment && (retain_pending || retain_rollback))
retain = TRUE;
/* tracks when we come across the booted deployment */
gboolean before_booted = TRUE;
gboolean before_merge = TRUE;
for (guint i = 0; i < deployments->len; i++)
{
OstreeDeployment *deployment = deployments->pdata[i];
const gboolean is_merge_or_booted =
ostree_deployment_equal (deployment, booted_deployment) ||
ostree_deployment_equal (deployment, merge_deployment);
const gboolean osname_matches =
(osname == NULL || g_str_equal (ostree_deployment_get_osname (deployment), osname));
const gboolean is_booted = ostree_deployment_equal (deployment, booted_deployment);
const gboolean is_merge = ostree_deployment_equal (deployment, merge_deployment);
/* Keep deployments with different osnames, as well as the
* booted and merge deployments
if (is_booted)
before_booted = FALSE;
if (is_merge)
before_merge = FALSE;
/* use the booted deployment as the "crossover" point between pending and rollback
* deployments, fall back on merge deployment */
const gboolean passed_crossover = booted_deployment ? !before_booted : !before_merge;
/* Retain deployment if:
* - we're explicitly asked to, or
* - the deployment is for another osname, or
* - we're keeping pending deployments and this is a pending deployment, or
* - this is the merge or boot deployment, or
* - we're keeping rollback deployments and this is a rollback deployment
*/
if (retain ||
(osname != NULL && strcmp (ostree_deployment_get_osname (deployment), osname) != 0) ||
is_merge_or_booted)
{
g_ptr_array_add (new_deployments, g_object_ref (deployment));
}
if (retain
|| !osname_matches
|| (retain_pending && !passed_crossover)
|| (is_booted || is_merge)
|| (retain_rollback && passed_crossover))
g_ptr_array_add (new_deployments, g_object_ref (deployment));
if ((!added_new) && is_merge_or_booted)
/* add right after booted/merge deployment */
if (!added_new && passed_crossover)
{
g_ptr_array_add (new_deployments, g_object_ref (new_deployment));
added_new = TRUE;
}
}
/* In this non-default case , an improvement in the future would be
* to put the new deployment right after the current default in the
* order.
*/
/* add it last if no crossover defined (or it's the first deployment in the sysroot) */
if (!added_new)
{
g_ptr_array_add (new_deployments, g_object_ref (new_deployment));
+2
View File
@@ -207,6 +207,8 @@ typedef enum {
OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN = (1 << 0),
OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT = (1 << 1),
OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NO_CLEAN = (1 << 2),
OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_PENDING = (1 << 3),
OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_ROLLBACK = (1 << 4),
} OstreeSysrootSimpleWriteDeploymentFlags;
_OSTREE_PUBLIC
+27 -15
View File
@@ -33,6 +33,9 @@
#include <glib/gi18n.h>
static gboolean opt_retain;
static gboolean opt_retain_pending;
static gboolean opt_retain_rollback;
static gboolean opt_not_as_default;
static char **opt_kernel_argv;
static char **opt_kernel_argv_append;
static gboolean opt_kernel_proc_cmdline;
@@ -47,7 +50,10 @@ static char *opt_origin_path;
static GOptionEntry options[] = {
{ "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname, "Use a different operating system root than the current one", "OSNAME" },
{ "origin-file", 0, 0, G_OPTION_ARG_FILENAME, &opt_origin_path, "Specify origin file", "FILENAME" },
{ "retain", 0, 0, G_OPTION_ARG_NONE, &opt_retain, "Do not delete previous deployment", NULL },
{ "retain", 0, 0, G_OPTION_ARG_NONE, &opt_retain, "Do not delete previous deployments", NULL },
{ "retain-pending", 0, 0, G_OPTION_ARG_NONE, &opt_retain_pending, "Do not delete pending deployments", NULL },
{ "retain-rollback", 0, 0, G_OPTION_ARG_NONE, &opt_retain_rollback, "Do not delete rollback deployments", NULL },
{ "not-as-default", 0, 0, G_OPTION_ARG_NONE, &opt_not_as_default, "Append rather than prepend new deployment", NULL },
{ "karg-proc-cmdline", 0, 0, G_OPTION_ARG_NONE, &opt_kernel_proc_cmdline, "Import current /proc/cmdline", NULL },
{ "karg", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_kernel_argv, "Set kernel argument, like root=/dev/sda1; this overrides any earlier argument with the same name", "NAME=VALUE" },
{ "karg-append", 0, 0, G_OPTION_ARG_STRING_ARRAY, &opt_kernel_argv_append, "Append kernel argument; useful with e.g. console= that can be used multiple times", "NAME=VALUE" },
@@ -145,22 +151,28 @@ ot_admin_builtin_deploy (int argc, char **argv, GCancellable *cancellable, GErro
_ostree_kernel_args_append_argv (kargs, opt_kernel_argv_append);
}
{
g_auto(GStrv) kargs_strv = _ostree_kernel_args_to_strv (kargs);
g_autoptr(OstreeDeployment) new_deployment = NULL;
if (!ostree_sysroot_deploy_tree (sysroot,
opt_osname, revision, origin,
merge_deployment, kargs_strv,
&new_deployment,
cancellable, error))
return FALSE;
}
g_auto(GStrv) kargs_strv = _ostree_kernel_args_to_strv (kargs);
if (!ostree_sysroot_deploy_tree (sysroot, opt_osname, revision, origin, merge_deployment,
kargs_strv, &new_deployment, cancellable, error))
return FALSE;
if (!ostree_sysroot_simple_write_deployment (sysroot, opt_osname,
new_deployment, merge_deployment,
opt_retain ? OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN : 0,
cancellable, error))
OstreeSysrootSimpleWriteDeploymentFlags flags = 0;
if (opt_retain)
flags |= OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN;
else
{
if (opt_retain_pending)
flags |= OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_PENDING;
if (opt_retain_rollback)
flags |= OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_ROLLBACK;
}
if (opt_not_as_default)
flags |= OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NOT_DEFAULT;
if (!ostree_sysroot_simple_write_deployment (sysroot, opt_osname, new_deployment,
merge_deployment, flags, cancellable, error))
return FALSE;
return TRUE;