From c446bfc0014a983b79e88254d71830357fd10edf Mon Sep 17 00:00:00 2001 From: Kelvin Fan Date: Fri, 15 Jan 2021 14:06:33 -0500 Subject: [PATCH] Add `register-driver` option to UpdateDeployment D-Bus API Record the agent id and agent systemd unit and serialize it into a JSON file at `/run/rpmostree/update-driver.json`. Also add the companion `--register-driver` option to the `deploy` CLI argument. Closes https://github.com/coreos/rpm-ostree/issues/1747. --- src/app/rpmostree-builtin-deploy.cxx | 3 + src/daemon/org.projectatomic.rpmostree1.xml | 2 + src/daemon/rpmostreed-daemon.h | 6 + src/daemon/rpmostreed-transaction-types.cxx | 115 ++++++++++++++++++++ src/daemon/rpmostreed-transaction-types.h | 9 ++ 5 files changed, 135 insertions(+) diff --git a/src/app/rpmostree-builtin-deploy.cxx b/src/app/rpmostree-builtin-deploy.cxx index 3f756c2d7d..33f580b524 100644 --- a/src/app/rpmostree-builtin-deploy.cxx +++ b/src/app/rpmostree-builtin-deploy.cxx @@ -35,6 +35,7 @@ static gboolean opt_download_only; static gboolean opt_lock_finalization; static gboolean opt_disallow_downgrade; static gboolean opt_unchanged_exit_77; +static gboolean opt_register_driver; static GOptionEntry option_entries[] = { { "os", 0, 0, G_OPTION_ARG_STRING, &opt_osname, "Operate on provided OSNAME", "OSNAME" }, @@ -49,6 +50,7 @@ static GOptionEntry option_entries[] = { { "lock-finalization", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &opt_lock_finalization, "Prevent automatic deployment finalization on shutdown", NULL }, { "disallow-downgrade", 0, 0, G_OPTION_ARG_NONE, &opt_disallow_downgrade, "Forbid deployment of chronologically older trees", NULL }, { "unchanged-exit-77", 0, 0, G_OPTION_ARG_NONE, &opt_unchanged_exit_77, "If no new deployment made, exit 77", NULL }, + { "register-driver", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &opt_register_driver, "Register the calling agent as the driver for updates", NULL }, { NULL } }; @@ -125,6 +127,7 @@ rpmostree_builtin_deploy (int argc, g_variant_dict_insert (&dict, "download-only", "b", opt_download_only); g_variant_dict_insert (&dict, "lock-finalization", "b", opt_lock_finalization); g_variant_dict_insert (&dict, "initiating-command-line", "s", invocation->command_line); + g_variant_dict_insert (&dict, "register-driver", "b", opt_register_driver); g_autoptr(GVariant) options = g_variant_ref_sink (g_variant_dict_end (&dict)); /* Use newer D-Bus API only if we have to so we maintain coverage. */ diff --git a/src/daemon/org.projectatomic.rpmostree1.xml b/src/daemon/org.projectatomic.rpmostree1.xml index 9a86741542..9fa0eccf9f 100644 --- a/src/daemon/org.projectatomic.rpmostree1.xml +++ b/src/daemon/org.projectatomic.rpmostree1.xml @@ -321,6 +321,8 @@ Stop short of deploying the new tree. If layering packages, the pkg diff is printed but packages are not downloaded or imported. + "register-driver" (type 'b') + Register the caller as the update driver. "no-layering" (type 'b') Remove all package requests. Requests in "install-packages" are still subsequently processed if specified. diff --git a/src/daemon/rpmostreed-daemon.h b/src/daemon/rpmostreed-daemon.h index 34fa4a9cad..bb13767ef2 100644 --- a/src/daemon/rpmostreed-daemon.h +++ b/src/daemon/rpmostreed-daemon.h @@ -30,6 +30,12 @@ G_BEGIN_DECLS #define DBUS_NAME "org.projectatomic.rpmostree1" #define BASE_DBUS_PATH "/org/projectatomic/rpmostree1" +/* Update driver info */ +#define RPMOSTREE_RUN_DIR "/run/rpm-ostree/" +#define RPMOSTREE_DRIVER_STATE RPMOSTREE_RUN_DIR "update-driver.gv" +#define RPMOSTREE_DRIVER_AGENT_SD_UNIT "agent-sd-unit" +#define RPMOSTREE_DRIVER_AGENT_ID "agent-id" + GType rpmostreed_daemon_get_type (void) G_GNUC_CONST; RpmostreedDaemon * rpmostreed_daemon_get (void); gboolean rpmostreed_get_client_uid (RpmostreedDaemon *self, diff --git a/src/daemon/rpmostreed-transaction-types.cxx b/src/daemon/rpmostreed-transaction-types.cxx index 7fdc4b6a8e..4079fc6a1a 100644 --- a/src/daemon/rpmostreed-transaction-types.cxx +++ b/src/daemon/rpmostreed-transaction-types.cxx @@ -19,6 +19,8 @@ #include "config.h" #include "ostree.h" +#include +#include #include #include @@ -26,6 +28,8 @@ #include "rpmostreed-transaction.h" #include "rpmostreed-deployment-utils.h" #include "rpmostreed-sysroot.h" +#include "rpmostreed-daemon.h" +#include "rpmostreed-errors.h" #include "rpmostree-sysroot-upgrader.h" #include "rpmostree-sysroot-core.h" #include "rpmostree-rpm-util.h" @@ -787,6 +791,110 @@ deploy_has_bool_option (DeployTransaction *self, return vardict_lookup_bool (self->options, option, FALSE); } +/* Write a state file which records information about the agent that is "driving" updates */ +static gboolean +record_driver_info (RpmostreedTransaction *transaction, + GCancellable *cancellable, + GError **error) +{ + g_auto(GVariantBuilder) caller_info_builder; + g_variant_builder_init (&caller_info_builder, G_VARIANT_TYPE ("a{sv}")); + + const char *id = rpmostreed_transaction_get_agent_id (transaction); + const char *sd_unit = rpmostreed_transaction_get_sd_unit (transaction); + if (!id) + { + g_set_error (error, RPM_OSTREED_ERROR, + RPM_OSTREED_ERROR_FAILED, "caller agent id unspecified"); + return FALSE; + } + g_variant_builder_add (&caller_info_builder, "{sv}", RPMOSTREE_DRIVER_AGENT_ID, + g_variant_new_string (id)); + if (!sd_unit) + { + g_set_error (error, RPM_OSTREED_ERROR, + RPM_OSTREED_ERROR_FAILED, "could not find caller systemd unit"); + return FALSE; + } + g_variant_builder_add (&caller_info_builder, "{sv}", RPMOSTREE_DRIVER_AGENT_SD_UNIT, + g_variant_new_string (sd_unit)); + + g_autoptr(GVariant) driver_info = + g_variant_ref_sink (g_variant_builder_end (&caller_info_builder)); + + if (!glnx_shutil_mkdir_p_at (AT_FDCWD, RPMOSTREE_RUN_DIR, 0755, cancellable, error)) + return FALSE; + if (!glnx_file_replace_contents_at (AT_FDCWD, RPMOSTREE_DRIVER_STATE, + static_cast(g_variant_get_data (driver_info)), + g_variant_get_size (driver_info), + static_cast(0), cancellable, error)) + return FALSE; + + return TRUE; +} + +gboolean +get_driver_g_variant (GVariant **driver_g_variant, + GError **error) +{ + glnx_autofd int fd = -1; + g_autoptr(GError) local_error = NULL; + if (!glnx_openat_rdonly (AT_FDCWD, RPMOSTREE_DRIVER_STATE, TRUE, &fd, + &local_error)) + { + if (!g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) + return g_propagate_error (error, util::move_nullify (local_error)), FALSE; + return TRUE; + } + + g_autoptr(GBytes) data = glnx_fd_readall_bytes (fd, NULL, error); + if (!data) + return FALSE; + + *driver_g_variant = + g_variant_ref_sink (g_variant_new_from_bytes (G_VARIANT_TYPE_VARDICT, data, FALSE)); + + return TRUE; +} + +/* Read from state file that records information about the agent that is "driving" updates */ +gboolean +get_driver_info (char **id, + char **sd_unit, + GError **error) +{ + g_autoptr(GVariant) driver_g_variant = NULL; + if (!get_driver_g_variant (&driver_g_variant, error)) + return FALSE; + if (!driver_g_variant) + return TRUE; // driver state file not found, return early. + + g_auto(GVariantDict) driver_info_dict; + g_variant_dict_init (&driver_info_dict, driver_g_variant); + auto v = static_cast(vardict_lookup_ptr (&driver_info_dict, + RPMOSTREE_DRIVER_AGENT_ID, "s")); + if (!v) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "could not find update driver agent id in %s", + RPMOSTREE_DRIVER_STATE); + return FALSE; + } + *id = v; + v = static_cast(vardict_lookup_ptr (&driver_info_dict, + RPMOSTREE_DRIVER_AGENT_SD_UNIT, "s")); + if (!v) + { + g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, + "could not find update driver systemd unit in %s", + RPMOSTREE_DRIVER_STATE); + return FALSE; + } + *sd_unit = v; + + return TRUE; +} + static gboolean deploy_transaction_execute (RpmostreedTransaction *transaction, GCancellable *cancellable, @@ -797,6 +905,7 @@ deploy_transaction_execute (RpmostreedTransaction *transaction, const gboolean dry_run = ((self->flags & RPMOSTREE_TRANSACTION_DEPLOY_FLAG_DRY_RUN) > 0); + const gboolean register_driver = deploy_has_bool_option (self, "register-driver"); const gboolean no_overrides = deploy_has_bool_option (self, "no-overrides"); const gboolean no_layering = deploy_has_bool_option (self, "no-layering"); const gboolean no_initramfs = deploy_has_bool_option (self, "no-initramfs"); @@ -1332,6 +1441,12 @@ deploy_transaction_execute (RpmostreedTransaction *transaction, return FALSE; changed = changed || layering_changed; + if (register_driver) + { + if (!record_driver_info (transaction, cancellable, error)) + return FALSE; + } + if (dry_run) /* Note early return here; we printed the transaction already */ return TRUE; diff --git a/src/daemon/rpmostreed-transaction-types.h b/src/daemon/rpmostreed-transaction-types.h index d84ccae03a..ec096013aa 100644 --- a/src/daemon/rpmostreed-transaction-types.h +++ b/src/daemon/rpmostreed-transaction-types.h @@ -157,3 +157,12 @@ rpmostreed_transaction_new_kernel_arg (GDBusMethodInvocation *invocation, GError **error); G_END_DECLS + +gboolean +get_driver_info (char **id, + char **sd_unit, + GError **error); + +gboolean +get_driver_g_variant (GVariant **driver_g_variant, + GError **error); \ No newline at end of file