From 48a03c7fe77ce698cfa8f26f628bc423aad3f831 Mon Sep 17 00:00:00 2001 From: Eric Curtin Date: Wed, 24 Jan 2024 16:23:51 +0000 Subject: [PATCH] admin/pin: Add commands to pin booted, pending and rollbacks deployments Add new commands to pin the current, staged and previous deployment for use in automation and scripting. Right now, it's difficult to pin the current deployment without needing to look into the output of some other tooling (like rpm-ostree) to get the index of each deployment. This index also is not consistent - the current deployment could be 0 when you first boot the system then 1 shortly after. This change makes it easy to pin the current or future deployment. Signed-off-by: Eric Curtin --- src/ostree/ot-admin-builtin-pin.c | 98 ++++++++++++++++++++++++------- 1 file changed, 78 insertions(+), 20 deletions(-) diff --git a/src/ostree/ot-admin-builtin-pin.c b/src/ostree/ot-admin-builtin-pin.c index de219d7e43..6140303fef 100644 --- a/src/ostree/ot-admin-builtin-pin.c +++ b/src/ostree/ot-admin-builtin-pin.c @@ -27,9 +27,76 @@ #include "otutil.h" static gboolean opt_unpin; +static gboolean opt_booted; +static gboolean opt_pending; +static gboolean opt_rollback; static GOptionEntry options[] - = { { "unpin", 'u', 0, G_OPTION_ARG_NONE, &opt_unpin, "Unset pin", NULL }, { NULL } }; + = { { "unpin", 'u', 0, G_OPTION_ARG_NONE, &opt_unpin, "Unset pin", NULL }, + { "booted", 'b', 0, G_OPTION_ARG_NONE, &opt_booted, + "Use the index of the booted deployment", NULL }, + { "pending", 'p', 0, G_OPTION_ARG_NONE, &opt_pending, + "Use the index of the pending deployment", NULL }, + { "rollback", 'r', 0, G_OPTION_ARG_NONE, &opt_rollback, + "Use the index of the rollback deployment", NULL }, + { NULL } }; + +static gint +get_deployment_index (const OstreeDeployment *target_deployment, const GPtrArray *deployments) +{ + for (gint i = 0; i < deployments->len; ++i) + if (deployments->pdata[i] == target_deployment) + return i; + + return -1; +} + +static gint64 +get_deployment_index_for_target (OstreeSysroot *sysroot) +{ + g_autoptr (GPtrArray) deployments = ostree_sysroot_get_deployments (sysroot); + const OstreeDeployment *booted_deployment = ostree_sysroot_get_booted_deployment (sysroot); + if (opt_booted) + return get_deployment_index (booted_deployment, deployments); + + g_autoptr (OstreeDeployment) pending_deployment = NULL; + g_autoptr (OstreeDeployment) rollback_deployment = NULL; + if (booted_deployment) + ostree_sysroot_query_deployments_for (sysroot, NULL, &pending_deployment, &rollback_deployment); + + if (opt_pending) + return get_deployment_index (pending_deployment, deployments); + else if (opt_rollback) + return get_deployment_index (rollback_deployment, deployments); + + return -1; +} + +static gboolean +do_pinning (OstreeSysroot *sysroot, const gint64 deploy_index, GError **error) +{ + g_autoptr (OstreeDeployment) target_deployment + = ot_admin_get_indexed_deployment (sysroot, deploy_index, error); + if (!target_deployment) + return FALSE; + + gboolean current_pin = ostree_deployment_is_pinned (target_deployment); + const gboolean desired_pin = !opt_unpin; + if (current_pin == desired_pin) + { + g_print ("Deployment %lld is already %s\n", (long long int)deploy_index, + current_pin ? "pinned" : "unpinned"); + } + else + { + if (!ostree_sysroot_deployment_set_pinned (sysroot, target_deployment, desired_pin, error)) + return FALSE; + g_print ("Deployment %lld is now %s\n", (long long int)deploy_index, + desired_pin ? "pinned" : "unpinned"); + } + + return TRUE; +} gboolean ot_admin_builtin_pin (int argc, char **argv, OstreeCommandInvocation *invocation, @@ -42,6 +109,15 @@ ot_admin_builtin_pin (int argc, char **argv, OstreeCommandInvocation *invocation cancellable, error)) return FALSE; + if (opt_booted || opt_pending || opt_rollback) + { + const gint64 deploy_index = get_deployment_index_for_target (sysroot); + if (deploy_index < 0) + return glnx_throw (error, "Unable to get valid index: %lld", (long long int)deploy_index); + + return do_pinning (sysroot, deploy_index, error); + } + if (argc < 2) { ot_util_usage_error (context, "INDEX must be specified", error); @@ -60,26 +136,8 @@ ot_admin_builtin_pin (int argc, char **argv, OstreeCommandInvocation *invocation if (errno == ERANGE) return glnx_throw (error, "Index too large: %s", deploy_index_str); - g_autoptr (OstreeDeployment) target_deployment - = ot_admin_get_indexed_deployment (sysroot, deploy_index, error); - if (!target_deployment) + if (!do_pinning (sysroot, deploy_index, error)) return FALSE; - - gboolean current_pin = ostree_deployment_is_pinned (target_deployment); - const gboolean desired_pin = !opt_unpin; - if (current_pin == desired_pin) - { - g_print ("Deployment %s is already %s\n", deploy_index_str, - current_pin ? "pinned" : "unpinned"); - } - else - { - if (!ostree_sysroot_deployment_set_pinned (sysroot, target_deployment, desired_pin, - error)) - return FALSE; - g_print ("Deployment %s is now %s\n", deploy_index_str, - desired_pin ? "pinned" : "unpinned"); - } } return TRUE;