From 64ab8334b7653562a9cd05ff4606efdf6b8331ac Mon Sep 17 00:00:00 2001 From: Anton Gerasimov Date: Thu, 1 Jun 2017 12:43:50 +0200 Subject: [PATCH] lib/sysroot: Add API to get pending/rollback for given stateroot This imports a function that is used in rpm-ostree, and it's also intended for use by https://github.com/advancedtelematic/aktualizr to display what deployment we're going to boot next after the reboot. Updated-by: Colin Walters Closes: #897 Approved by: OYTIS --- apidoc/ostree-sections.txt | 1 + src/libostree/libostree.sym | 1 + src/libostree/ostree-sysroot.c | 73 +++++++++++++++++++++++----- src/libostree/ostree-sysroot.h | 6 +++ src/ostree/ot-admin-builtin-status.c | 16 +++++- tests/admin-test.sh | 2 + 6 files changed, 84 insertions(+), 15 deletions(-) diff --git a/apidoc/ostree-sections.txt b/apidoc/ostree-sections.txt index 5e111a96..116c50e8 100644 --- a/apidoc/ostree-sections.txt +++ b/apidoc/ostree-sections.txt @@ -496,6 +496,7 @@ ostree_sysroot_write_deployments_with_options ostree_sysroot_write_origin_file ostree_sysroot_deploy_tree ostree_sysroot_get_merge_deployment +ostree_sysroot_query_deployments_for ostree_sysroot_origin_new_from_refspec OstreeSysrootSimpleWriteDeploymentFlags ostree_sysroot_simple_write_deployment diff --git a/src/libostree/libostree.sym b/src/libostree/libostree.sym index 612eb8ac..b307548d 100644 --- a/src/libostree/libostree.sym +++ b/src/libostree/libostree.sym @@ -405,6 +405,7 @@ global: LIBOSTREE_2017.7 { global: ostree_sysroot_repo; + ostree_sysroot_query_deployments_for; } LIBOSTREE_2017.6; /* Stub section for the stable release *after* this development one; don't diff --git a/src/libostree/ostree-sysroot.c b/src/libostree/ostree-sysroot.c index a3e9e75d..90868aae 100644 --- a/src/libostree/ostree-sysroot.c +++ b/src/libostree/ostree-sysroot.c @@ -1107,6 +1107,63 @@ find_booted_deployment (OstreeSysroot *self, return TRUE; } +/** + * ostree_sysroot_query_deployments_for: + * @self: Sysroot + * @osname: (allow-none): "stateroot" name + * @out_pending: (out) (allow-none) (transfer full): The pending deployment + * @out_rollback: (out) (allow-none) (transfer full): The rollback deployment + * + * Find the pending and rollback deployments for @osname. Pass %NULL for @osname + * to use the booted deployment's osname. By default, pending deployment is the + * first deployment in the order that matches @osname, and @rollback will be the + * next one after the booted deployment, or the deployment after the pending if + * we're not looking at the booted deployment. + * + * Since: 2017.7 + */ +void +ostree_sysroot_query_deployments_for (OstreeSysroot *self, + const char *osname, + OstreeDeployment **out_pending, + OstreeDeployment **out_rollback) +{ + g_return_if_fail (osname != NULL || self->booted_deployment != NULL); + g_autoptr(OstreeDeployment) ret_pending = NULL; + g_autoptr(OstreeDeployment) ret_rollback = NULL; + + if (osname == NULL) + osname = ostree_deployment_get_osname (self->booted_deployment); + + gboolean found_booted = FALSE; + for (guint i = 0; i < self->deployments->len; i++) + { + OstreeDeployment *deployment = self->deployments->pdata[i]; + + /* Is this deployment booted? If so, note we're past the booted */ + if (self->booted_deployment != NULL && + ostree_deployment_equal (deployment, self->booted_deployment)) + { + found_booted = TRUE; + continue; + } + + /* Ignore deployments not for this osname */ + if (strcmp (ostree_deployment_get_osname (deployment), osname) != 0) + continue; + + if (!found_booted && !ret_pending) + ret_pending = g_object_ref (deployment); + else if (found_booted && !ret_rollback) + ret_rollback = g_object_ref (deployment); + } + if (out_pending) + *out_pending = g_steal_pointer (&ret_pending); + if (out_rollback) + *out_rollback = g_steal_pointer (&ret_rollback); +} + + /** * ostree_sysroot_get_merge_deployment: * @self: Sysroot @@ -1132,23 +1189,13 @@ ostree_sysroot_get_merge_deployment (OstreeSysroot *self, */ if (self->booted_deployment && g_strcmp0 (ostree_deployment_get_osname (self->booted_deployment), osname) == 0) - { return g_object_ref (self->booted_deployment); - } else { - guint i; - for (i = 0; i < self->deployments->len; i++) - { - OstreeDeployment *deployment = self->deployments->pdata[i]; - - if (strcmp (ostree_deployment_get_osname (deployment), osname) != 0) - continue; - - return g_object_ref (deployment); - } + g_autoptr(OstreeDeployment) pending = NULL; + ostree_sysroot_query_deployments_for (self, osname, &pending, NULL); + return g_steal_pointer (&pending); } - return NULL; } /** diff --git a/src/libostree/ostree-sysroot.h b/src/libostree/ostree-sysroot.h index e5969e9e..3d2446f9 100644 --- a/src/libostree/ostree-sysroot.h +++ b/src/libostree/ostree-sysroot.h @@ -187,6 +187,12 @@ gboolean ostree_sysroot_deployment_unlock (OstreeSysroot *self, GCancellable *cancellable, GError **error); +_OSTREE_PUBLIC +void ostree_sysroot_query_deployments_for (OstreeSysroot *self, + const char *osname, + OstreeDeployment **out_pending, + OstreeDeployment **out_rollback); + _OSTREE_PUBLIC OstreeDeployment *ostree_sysroot_get_merge_deployment (OstreeSysroot *self, const char *osname); diff --git a/src/ostree/ot-admin-builtin-status.c b/src/ostree/ot-admin-builtin-status.c index 79621a1d..a437e7cf 100644 --- a/src/ostree/ot-admin-builtin-status.c +++ b/src/ostree/ot-admin-builtin-status.c @@ -88,6 +88,8 @@ ot_admin_builtin_status (int argc, char **argv, GCancellable *cancellable, GErro gboolean ret = FALSE; glnx_unref_object OstreeRepo *repo = NULL; OstreeDeployment *booted_deployment = NULL; + g_autoptr(OstreeDeployment) pending_deployment = NULL; + g_autoptr(OstreeDeployment) rollback_deployment = NULL; g_autoptr(GPtrArray) deployments = NULL; const int is_tty = isatty (1); const char *red_bold_prefix = is_tty ? "\x1b[31m\x1b[1m" : ""; @@ -110,6 +112,10 @@ ot_admin_builtin_status (int argc, char **argv, GCancellable *cancellable, GErro deployments = ostree_sysroot_get_deployments (sysroot); booted_deployment = ostree_sysroot_get_booted_deployment (sysroot); + if (booted_deployment) + ostree_sysroot_query_deployments_for (sysroot, NULL, &pending_deployment, + &rollback_deployment); + if (deployments->len == 0) { g_print ("No deployments.\n"); @@ -129,11 +135,17 @@ ot_admin_builtin_status (int argc, char **argv, GCancellable *cancellable, GErro origin = ostree_deployment_get_origin (deployment); - g_print ("%c %s %s.%d\n", + const char *deployment_status = ""; + if (deployment == pending_deployment) + deployment_status = " (pending)"; + else if (deployment == rollback_deployment) + deployment_status = " (rollback)"; + g_print ("%c %s %s.%d%s\n", deployment == booted_deployment ? '*' : ' ', ostree_deployment_get_osname (deployment), ostree_deployment_get_csum (deployment), - ostree_deployment_get_deployserial (deployment)); + ostree_deployment_get_deployserial (deployment), + deployment_status); if (version) g_print (" Version: %s\n", version); switch (unlocked) diff --git a/tests/admin-test.sh b/tests/admin-test.sh index cc06fe6f..671fd905 100644 --- a/tests/admin-test.sh +++ b/tests/admin-test.sh @@ -42,6 +42,8 @@ ${CMD_PREFIX} ostree admin deploy --karg=root=LABEL=MOO --karg=quiet --os=testos new_mtime=$(stat -c '%.Y' sysroot/ostree/deploy) assert_not_streq "${orig_mtime}" "${new_mtime}" ${CMD_PREFIX} ostree admin status | tee status.txt +assert_not_file_has_content status.txt "pending" +assert_not_file_has_content status.txt "rollback" validate_bootloader echo "ok deploy command"