Skip to content

Commit

Permalink
deploy: Keep last deployment version during stage
Browse files Browse the repository at this point in the history
Fixes #1905

Signed-off-by: Rafael Fonseca <[email protected]>
  • Loading branch information
r4f4 committed Feb 4, 2020
1 parent 1efa4e9 commit 4bb4d04
Show file tree
Hide file tree
Showing 5 changed files with 118 additions and 15 deletions.
1 change: 1 addition & 0 deletions src/libostree/libostree-devel.sym
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ global:
ostree_sysroot_initialize;
ostree_sysroot_is_booted;
ostree_sysroot_set_mount_namespace_in_use;
ostree_sysroot_stage_tree_with_flags;
} LIBOSTREE_2019.6;

/* Stub section for the stable release *after* this development one; don't
Expand Down
58 changes: 53 additions & 5 deletions src/libostree/ostree-sysroot-deploy.c
Original file line number Diff line number Diff line change
Expand Up @@ -2850,6 +2850,48 @@ ostree_sysroot_stage_tree (OstreeSysroot *self,
OstreeDeployment **out_new_deployment,
GCancellable *cancellable,
GError **error)
{
return ostree_sysroot_stage_tree_with_flags (self,
osname,
revision,
origin,
merge_deployment,
override_kernel_argv,
out_new_deployment,
OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NONE,
cancellable,
error);
}

/**
* ostree_sysroot_stage_tree_with_flags:
* @self: Sysroot
* @osname: (allow-none): osname to use for merge deployment
* @revision: Checksum to add
* @origin: (allow-none): Origin to use for upgrades
* @merge_deployment: (allow-none): Use this deployment for merge path
* @override_kernel_argv: (allow-none) (array zero-terminated=1) (element-type utf8): Use these as kernel arguments; if %NULL, inherit options from provided_merge_deployment
* @out_new_deployment: (out): The new deployment path
* @flags: flags to control how the deployment is written
* @cancellable: Cancellable
* @error: Error
*
* Like ostree_sysroot_deploy_tree(), but "finalization" only occurs at OS
* shutdown time.
*
* Since: 2019.7
*/
gboolean
ostree_sysroot_stage_tree_with_flags (OstreeSysroot *self,
const char *osname,
const char *revision,
GKeyFile *origin,
OstreeDeployment *merge_deployment,
char **override_kernel_argv,
OstreeDeployment **out_new_deployment,
OstreeSysrootSimpleWriteDeploymentFlags flags,
GCancellable *cancellable,
GError **error)
{
if (!_ostree_sysroot_ensure_writable (self, error))
return FALSE;
Expand Down Expand Up @@ -2921,6 +2963,11 @@ ostree_sysroot_stage_tree (OstreeSysroot *self,
g_variant_builder_add (builder, "{sv}", "kargs",
g_variant_new_strv ((const char *const*)override_kernel_argv, -1));

/* Proxy across any flags */
if (flags)
g_variant_builder_add (builder, "{sv}", "write-deployment-flags",
g_variant_new_uint32 ((guint32)flags));

const char *parent = dirname (strdupa (_OSTREE_SYSROOT_RUNSTATE_STAGED));
if (!glnx_shutil_mkdir_p_at (AT_FDCWD, parent, 0755, cancellable, error))
return FALSE;
Expand Down Expand Up @@ -3042,14 +3089,15 @@ _ostree_sysroot_finalize_staged (OstreeSysroot *self,
staged->staged = FALSE;
g_ptr_array_remove_index (self->deployments, 0);

/* TODO: Proxy across flags too?
*
* But note that we always use NO_CLEAN to avoid adding more latency at
OstreeSysrootSimpleWriteDeploymentFlags flags = 0;
g_variant_lookup (self->staged_deployment_data, "write-deployment-flags", "u", &flags);
/*
* Note that we always use NO_CLEAN to avoid adding more latency at
* shutdown, and also because e.g. rpm-ostree wants to own the cleanup
* process.
*/
OstreeSysrootSimpleWriteDeploymentFlags flags =
OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NO_CLEAN;
flags |= OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NO_CLEAN;

if (!ostree_sysroot_simple_write_deployment (self, ostree_deployment_get_osname (staged),
staged, merge_deployment, flags,
cancellable, error))
Expand Down
41 changes: 41 additions & 0 deletions src/libostree/ostree-sysroot.c
Original file line number Diff line number Diff line change
Expand Up @@ -1698,6 +1698,9 @@ ostree_sysroot_init_osname (OstreeSysroot *self,
* specified, then no cleanup will be performed after adding the
* deployment. Make sure to call ostree_sysroot_cleanup() sometime
* later, instead.
*
* If %OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_PREVIOUS_VERSION is
* specified, then the previous version will not be garbage collected.
*/
gboolean
ostree_sysroot_simple_write_deployment (OstreeSysroot *sysroot,
Expand All @@ -1716,6 +1719,8 @@ ostree_sysroot_simple_write_deployment (OstreeSysroot *sysroot,
(flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_PENDING) > 0;
const gboolean retain_rollback =
(flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_ROLLBACK) > 0;
const gboolean retain_previous =
(flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_PREVIOUS_VERSION) > 0;
gboolean retain =
(flags & OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN) > 0;

Expand All @@ -1738,6 +1743,26 @@ ostree_sysroot_simple_write_deployment (OstreeSysroot *sysroot,
if (!booted_deployment && !merge_deployment && (retain_pending || retain_rollback))
retain = TRUE;

/* tracks current versioned deployment */
OstreeRepo *repo = ostree_sysroot_repo (sysroot);
const gchar *new_version =
_ostree_deployment_get_version (new_deployment, repo, error);

gboolean retained_previous_version = FALSE;
if (booted_deployment)
{
const gchar *booted_version =
_ostree_deployment_get_version (booted_deployment, repo, error);
retained_previous_version = (g_strcmp0 (booted_version, new_version) != 0);
}

if (!retained_previous_version && merge_deployment)
{
const gchar *merge_version =
_ostree_deployment_get_version (merge_deployment, repo, error);
retained_previous_version = (g_strcmp0 (merge_version, new_version) != 0);
}

/* tracks when we come across the booted deployment */
gboolean before_booted = TRUE;
gboolean before_merge = TRUE;
Expand All @@ -1758,6 +1783,13 @@ ostree_sysroot_simple_write_deployment (OstreeSysroot *sysroot,
* deployments, fall back on merge deployment */
const gboolean passed_crossover = booted_deployment ? !before_booted : !before_merge;

gboolean is_previous_version = FALSE;
if (passed_crossover && osname_matches && !retained_previous_version)
{
const gchar *version = _ostree_deployment_get_version (deployment, repo, error);
is_previous_version = (g_strcmp0 (version, new_version) != 0);
}

/* Retain deployment if:
* - we're explicitly asked to, or
* - it's pinned
Expand All @@ -1773,6 +1805,15 @@ ostree_sysroot_simple_write_deployment (OstreeSysroot *sysroot,
|| (is_booted || is_merge)
|| (retain_rollback && passed_crossover))
g_ptr_array_add (new_deployments, g_object_ref (deployment));
/*
* - we're keeping the previous version deployment
*/
else if (retain_previous && !retained_previous_version && is_previous_version)
{
g_ptr_array_add (new_deployments, g_object_ref (deployment));
/* Just keep one previous version */
retained_previous_version = TRUE;
}

/* add right after booted/merge deployment */
if (!added_new && passed_crossover)
Expand Down
31 changes: 22 additions & 9 deletions src/libostree/ostree-sysroot.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,16 @@ gboolean ostree_sysroot_deploy_tree (OstreeSysroot *self,
GCancellable *cancellable,
GError **error);

typedef enum {
OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NONE = 0,
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),
OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_RETAIN_PREVIOUS_VERSION = (1 << 5),
} OstreeSysrootSimpleWriteDeploymentFlags;

_OSTREE_PUBLIC
gboolean ostree_sysroot_stage_tree (OstreeSysroot *self,
const char *osname,
Expand All @@ -211,6 +221,18 @@ gboolean ostree_sysroot_stage_tree (OstreeSysroot *self,
GCancellable *cancellable,
GError **error);

_OSTREE_PUBLIC
gboolean ostree_sysroot_stage_tree_with_flags (OstreeSysroot *self,
const char *osname,
const char *revision,
GKeyFile *origin,
OstreeDeployment *merge_deployment,
char **override_kernel_argv,
OstreeDeployment **out_new_deployment,
OstreeSysrootSimpleWriteDeploymentFlags flags,
GCancellable *cancellable,
GError **error);

_OSTREE_PUBLIC
gboolean ostree_sysroot_deployment_set_mutable (OstreeSysroot *self,
OstreeDeployment *deployment,
Expand Down Expand Up @@ -246,15 +268,6 @@ _OSTREE_PUBLIC
GKeyFile *ostree_sysroot_origin_new_from_refspec (OstreeSysroot *self,
const char *refspec);

typedef enum {
OSTREE_SYSROOT_SIMPLE_WRITE_DEPLOYMENT_FLAGS_NONE = 0,
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
gboolean ostree_sysroot_simple_write_deployment (OstreeSysroot *sysroot,
const char *osname,
Expand Down
2 changes: 1 addition & 1 deletion src/ostree/ot-admin-builtin-deploy.c
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ ot_admin_builtin_deploy (int argc, char **argv, OstreeCommandInvocation *invocat
if (opt_not_as_default)
return glnx_throw (error, "--stage cannot currently be combined with --not-as-default");
if (!ostree_sysroot_stage_tree (sysroot, opt_osname, revision, origin, merge_deployment,
kargs_strv, &new_deployment, cancellable, error))
kargs_strv, &new_deployment, 0, cancellable, error))
return FALSE;
g_assert (new_deployment);
}
Expand Down

0 comments on commit 4bb4d04

Please sign in to comment.