mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager
synced 2024-07-09 04:05:56 +00:00
checkpoint: allow resetting the rollback timeout via D-Bus
This allows to adjust the timeout of an existing checkpoint. The main usecase of checkpoints, is to have a fail-safe when configuring the network remotely. By allowing to reset the timeout, the user can perform a series of actions, and keep bumping the timeout. That way, the entire series is still guarded by the same checkpoint, but the user can start with short timeout, and re-adjust the timeout as he goes along. The libnm API only implements the async form (at least for now). Sync methods are fundamentally wrong with D-Bus, and it's probably not needed. Also, follow glib convenction, where the async form doesn't have the _async name suffix. Also, accept a D-Bus path as argument, not a NMCheckpoint instance. The libnm API should not be more restricted than the underlying D-Bus API. It would be cumbersome to require the user to lookup the NMCheckpoint instance first, especially since libnm doesn't provide an efficient or convenient lookup-by-path method. On the other hand, retrieving the path from a NMCheckpoint instance is always possible.
This commit is contained in:
parent
ab8312a18e
commit
f67303221b
|
@ -251,6 +251,27 @@
|
|||
<arg name="result" type="a{su}" direction="out" />
|
||||
</method>
|
||||
|
||||
<!--
|
||||
CheckpointAdjustRollbackTimeout:
|
||||
@add_timeout: number of seconds from ~now~ in which the
|
||||
timeout will expire. Set to 0 to disable the timeout.
|
||||
Note that the added seconds start counting from now,
|
||||
not "Created" timestamp or the previous expiration
|
||||
time. Note that the "Created" property of the checkpoint
|
||||
will stay unchanged by this call. However, the "RollbackTimeout"
|
||||
will be recalculated to give the approximate new expiration time.
|
||||
The new "RollbackTimeout" property will be approximate up to
|
||||
one second precision, which is the accuracy of the property.
|
||||
|
||||
Reset the timeout for rollback for the checkpoint.
|
||||
|
||||
Since: 1.12
|
||||
-->
|
||||
<method name="CheckpointAdjustRollbackTimeout">
|
||||
<arg name="checkpoint" type="o" direction="in"/>
|
||||
<arg name="add_timeout" type="u" direction="in"/>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
Devices:
|
||||
|
||||
|
|
|
@ -1339,6 +1339,8 @@ global:
|
|||
nm_checkpoint_get_devices;
|
||||
nm_checkpoint_get_rollback_timeout;
|
||||
nm_checkpoint_get_type;
|
||||
nm_client_checkpoint_adjust_rollback_timeout;
|
||||
nm_client_checkpoint_adjust_rollback_timeout_finish;
|
||||
nm_client_checkpoint_create_async;
|
||||
nm_client_checkpoint_create_finish;
|
||||
nm_client_checkpoint_destroy_async;
|
||||
|
|
|
@ -2372,6 +2372,88 @@ nm_client_checkpoint_rollback_finish (NMClient *client,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
checkpoint_adjust_rollback_timeout_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
gs_unref_object GSimpleAsyncResult *simple = user_data;
|
||||
GError *error = NULL;
|
||||
|
||||
if (nm_manager_checkpoint_adjust_rollback_timeout_finish (NM_MANAGER (object), result, &error))
|
||||
g_simple_async_result_set_op_res_gboolean (simple, TRUE);
|
||||
else
|
||||
g_simple_async_result_take_error (simple, error);
|
||||
|
||||
g_simple_async_result_complete (simple);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_client_checkpoint_adjust_rollback_timeout:
|
||||
* @client: the %NMClient
|
||||
* @checkpoint_path: a D-Bus path to a checkpoint
|
||||
* @add_timeout: the timeout in seconds counting from now.
|
||||
* Set to zero, to disable the timeout.
|
||||
* @cancellable: a #GCancellable, or %NULL
|
||||
* @callback: (scope async): callback to be called when the add operation completes
|
||||
* @user_data: (closure): caller-specific data passed to @callback
|
||||
*
|
||||
* Resets the timeout for the checkpoint with path @checkpoint_path
|
||||
* to @timeout_add.
|
||||
*
|
||||
* Since: 1.12
|
||||
**/
|
||||
void
|
||||
nm_client_checkpoint_adjust_rollback_timeout (NMClient *client,
|
||||
const char *checkpoint_path,
|
||||
guint32 add_timeout,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GSimpleAsyncResult *simple;
|
||||
GError *error = NULL;
|
||||
|
||||
g_return_if_fail (NM_IS_CLIENT (client));
|
||||
|
||||
if (!_nm_client_check_nm_running (client, &error)) {
|
||||
g_simple_async_report_take_gerror_in_idle (G_OBJECT (client), callback, user_data, error);
|
||||
return;
|
||||
}
|
||||
|
||||
simple = g_simple_async_result_new (G_OBJECT (client), callback, user_data,
|
||||
nm_client_checkpoint_rollback_async);
|
||||
if (cancellable)
|
||||
g_simple_async_result_set_check_cancellable (simple, cancellable);
|
||||
nm_manager_checkpoint_adjust_rollback_timeout (NM_CLIENT_GET_PRIVATE (client)->manager,
|
||||
checkpoint_path, add_timeout,
|
||||
cancellable, checkpoint_adjust_rollback_timeout_cb, simple);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_client_checkpoint_adjust_rollback_timeout_finish:
|
||||
* @client: an #NMClient
|
||||
* @result: the result passed to the #GAsyncReadyCallback
|
||||
* @error: location for a #GError, or %NULL
|
||||
*
|
||||
* Gets the result of a call to nm_client_checkpoint_adjust_rollback_timeout().
|
||||
*
|
||||
* Returns: %TRUE on success or %FALSE on failure.
|
||||
*
|
||||
* Since: 1.12
|
||||
**/
|
||||
gboolean
|
||||
nm_client_checkpoint_adjust_rollback_timeout_finish (NMClient *client,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
|
||||
g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
|
||||
|
||||
return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
|
||||
error);
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
/* Object Initialization */
|
||||
/****************************************************************/
|
||||
|
|
|
@ -442,6 +442,19 @@ GHashTable *nm_client_checkpoint_rollback_finish (NMClient *client,
|
|||
GAsyncResult *result,
|
||||
GError **error);
|
||||
|
||||
NM_AVAILABLE_IN_1_12
|
||||
void nm_client_checkpoint_adjust_rollback_timeout (NMClient *client,
|
||||
const char *checkpoint_path,
|
||||
guint32 add_timeout,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
|
||||
NM_AVAILABLE_IN_1_12
|
||||
gboolean nm_client_checkpoint_adjust_rollback_timeout_finish (NMClient *client,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __NM_CLIENT_H__ */
|
||||
|
|
|
@ -1545,6 +1545,66 @@ nm_manager_checkpoint_rollback_finish (NMManager *manager,
|
|||
return g_simple_async_result_get_op_res_gpointer (simple);
|
||||
}
|
||||
|
||||
static void
|
||||
checkpoint_adjust_rollback_timeout_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
gs_unref_object GSimpleAsyncResult *simple = user_data;
|
||||
GError *error = NULL;
|
||||
|
||||
if (nmdbus_manager_call_checkpoint_adjust_rollback_timeout_finish (NMDBUS_MANAGER (object),
|
||||
result,
|
||||
&error))
|
||||
g_simple_async_result_set_op_res_gboolean (simple, TRUE);
|
||||
else {
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_simple_async_result_take_error (simple, error);
|
||||
}
|
||||
g_simple_async_result_complete (simple);
|
||||
}
|
||||
|
||||
void
|
||||
nm_manager_checkpoint_adjust_rollback_timeout (NMManager *manager,
|
||||
const char *checkpoint_path,
|
||||
guint32 add_timeout,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GSimpleAsyncResult *simple;
|
||||
|
||||
g_return_if_fail (NM_IS_MANAGER (manager));
|
||||
g_return_if_fail (checkpoint_path && checkpoint_path[0] == '/');
|
||||
|
||||
simple = g_simple_async_result_new (G_OBJECT (manager), callback, user_data,
|
||||
nm_manager_checkpoint_adjust_rollback_timeout);
|
||||
if (cancellable)
|
||||
g_simple_async_result_set_check_cancellable (simple, cancellable);
|
||||
|
||||
nmdbus_manager_call_checkpoint_adjust_rollback_timeout (NM_MANAGER_GET_PRIVATE (manager)->proxy,
|
||||
checkpoint_path,
|
||||
add_timeout,
|
||||
cancellable,
|
||||
checkpoint_adjust_rollback_timeout_cb,
|
||||
simple);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_manager_checkpoint_adjust_rollback_timeout_finish (NMManager *manager,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
GSimpleAsyncResult *simple;
|
||||
|
||||
g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (manager),
|
||||
nm_manager_checkpoint_adjust_rollback_timeout),
|
||||
FALSE);
|
||||
|
||||
simple = G_SIMPLE_ASYNC_RESULT (result);
|
||||
return !g_simple_async_result_propagate_error (simple, error);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
|
|
|
@ -210,5 +210,14 @@ void nm_manager_checkpoint_rollback_async (NMManager *manager,
|
|||
GHashTable *nm_manager_checkpoint_rollback_finish (NMManager *manager,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
void nm_manager_checkpoint_adjust_rollback_timeout (NMManager *manager,
|
||||
const char *checkpoint_path,
|
||||
guint32 add_timeout,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean nm_manager_checkpoint_adjust_rollback_timeout_finish (NMManager *manager,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
|
||||
#endif /* __NM_MANAGER_H__ */
|
||||
|
|
|
@ -57,6 +57,7 @@ typedef struct _NMAuditManagerClass NMAuditManagerClass;
|
|||
#define NM_AUDIT_OP_CHECKPOINT_CREATE "checkpoint-create"
|
||||
#define NM_AUDIT_OP_CHECKPOINT_ROLLBACK "checkpoint-rollback"
|
||||
#define NM_AUDIT_OP_CHECKPOINT_DESTROY "checkpoint-destroy"
|
||||
#define NM_AUDIT_OP_CHECKPOINT_ADJUST_ROLLBACK_TIMEOUT "checkpoint-adjust-rollback-timeout"
|
||||
|
||||
GType nm_audit_manager_get_type (void);
|
||||
NMAuditManager *nm_audit_manager_get (void);
|
||||
|
|
|
@ -296,6 +296,26 @@ nm_checkpoint_manager_get_checkpoint_paths (NMCheckpointManager *self, guint *ou
|
|||
return strv;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_checkpoint_manager_adjust_rollback_timeout (NMCheckpointManager *self,
|
||||
const char *path,
|
||||
guint32 add_timeout,
|
||||
GError **error)
|
||||
{
|
||||
NMCheckpoint *checkpoint;
|
||||
|
||||
g_return_val_if_fail (self, FALSE);
|
||||
g_return_val_if_fail (path && path[0] == '/', FALSE);
|
||||
g_return_val_if_fail (!error || !*error, FALSE);
|
||||
|
||||
checkpoint = nm_checkpoint_manager_lookup_by_path (self, path, error);
|
||||
if (!checkpoint)
|
||||
return FALSE;
|
||||
|
||||
nm_checkpoint_adjust_rollback_timeout (checkpoint, add_timeout);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
NMCheckpointManager *
|
||||
|
|
|
@ -51,6 +51,11 @@ gboolean nm_checkpoint_manager_rollback (NMCheckpointManager *self,
|
|||
GVariant **results,
|
||||
GError **error);
|
||||
|
||||
gboolean nm_checkpoint_manager_adjust_rollback_timeout (NMCheckpointManager *self,
|
||||
const char *path,
|
||||
guint32 add_timeout,
|
||||
GError **error);
|
||||
|
||||
const char **nm_checkpoint_manager_get_checkpoint_paths (NMCheckpointManager *self,
|
||||
guint *out_length);
|
||||
|
||||
|
|
|
@ -48,7 +48,7 @@ typedef struct {
|
|||
NMUnmanFlagOp unmanaged_explicit;
|
||||
} DeviceCheckpoint;
|
||||
|
||||
NM_GOBJECT_PROPERTIES_DEFINE_BASE (
|
||||
NM_GOBJECT_PROPERTIES_DEFINE (NMCheckpoint,
|
||||
PROP_DEVICES,
|
||||
PROP_CREATED,
|
||||
PROP_ROLLBACK_TIMEOUT,
|
||||
|
@ -474,6 +474,42 @@ _timeout_cb (gpointer user_data)
|
|||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
void
|
||||
nm_checkpoint_adjust_rollback_timeout (NMCheckpoint *self, guint32 add_timeout)
|
||||
{
|
||||
guint32 rollback_timeout_s;
|
||||
gint64 now_ms, add_timeout_ms, rollback_timeout_ms;
|
||||
|
||||
NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE (self);
|
||||
|
||||
nm_clear_g_source (&priv->timeout_id);
|
||||
|
||||
if (add_timeout == 0)
|
||||
rollback_timeout_s = 0;
|
||||
else {
|
||||
now_ms = nm_utils_get_monotonic_timestamp_ms ();
|
||||
add_timeout_ms = ((gint64) add_timeout) * 1000;
|
||||
rollback_timeout_ms = (now_ms - priv->created_at_ms) + add_timeout_ms;
|
||||
|
||||
/* round to nearest integer second. Since NM_CHECKPOINT_ROLLBACK_TIMEOUT is
|
||||
* in units seconds, it will be able to exactly express the timeout. */
|
||||
rollback_timeout_s = NM_MIN ((rollback_timeout_ms + 500) / 1000, (gint64) G_MAXUINT32);
|
||||
|
||||
/* we expect the timeout to be positive, because add_timeout_ms is positive.
|
||||
* We cannot accept a zero, because it means "infinity". */
|
||||
nm_assert (rollback_timeout_s > 0);
|
||||
|
||||
priv->timeout_id = g_timeout_add (NM_MIN (add_timeout_ms, (gint64) G_MAXUINT32),
|
||||
_timeout_cb,
|
||||
self);
|
||||
}
|
||||
|
||||
if (rollback_timeout_s != priv->rollback_timeout_s) {
|
||||
priv->rollback_timeout_s = rollback_timeout_s;
|
||||
_notify (self, PROP_ROLLBACK_TIMEOUT);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
|
|
|
@ -61,6 +61,8 @@ void nm_checkpoint_set_timeout_callback (NMCheckpoint *self,
|
|||
|
||||
GVariant *nm_checkpoint_rollback (NMCheckpoint *self);
|
||||
|
||||
void nm_checkpoint_adjust_rollback_timeout (NMCheckpoint *self, guint32 add_timeout);
|
||||
|
||||
NMDevice *nm_checkpoint_includes_devices (NMCheckpoint *self, NMDevice *const*devices, guint n_devices);
|
||||
NMDevice *nm_checkpoint_includes_devices_of (NMCheckpoint *self, NMCheckpoint *cp_for_devices);
|
||||
|
||||
|
|
|
@ -5956,13 +5956,15 @@ checkpoint_auth_done_cb (NMAuthChain *chain,
|
|||
GVariant *variant = NULL;
|
||||
GError *error = NULL;
|
||||
const char *arg = NULL;
|
||||
guint32 add_timeout;
|
||||
|
||||
op = nm_auth_chain_get_data (chain, "audit-op");
|
||||
priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
|
||||
result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK);
|
||||
|
||||
if ( nm_streq0 (op, NM_AUDIT_OP_CHECKPOINT_DESTROY)
|
||||
|| nm_streq0 (op, NM_AUDIT_OP_CHECKPOINT_ROLLBACK))
|
||||
if (NM_IN_STRSET (op, NM_AUDIT_OP_CHECKPOINT_DESTROY,
|
||||
NM_AUDIT_OP_CHECKPOINT_ROLLBACK,
|
||||
NM_AUDIT_OP_CHECKPOINT_ADJUST_ROLLBACK_TIMEOUT))
|
||||
arg = checkpoint_path = nm_auth_chain_get_data (chain, "checkpoint_path");
|
||||
|
||||
if (auth_error) {
|
||||
|
@ -5995,6 +5997,10 @@ checkpoint_auth_done_cb (NMAuthChain *chain,
|
|||
} else if (nm_streq0 (op, NM_AUDIT_OP_CHECKPOINT_ROLLBACK)) {
|
||||
nm_checkpoint_manager_rollback (_checkpoint_mgr_get (self, TRUE),
|
||||
checkpoint_path, &variant, &error);
|
||||
} else if (nm_streq0 (op, NM_AUDIT_OP_CHECKPOINT_ADJUST_ROLLBACK_TIMEOUT)) {
|
||||
add_timeout = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "add_timeout"));
|
||||
nm_checkpoint_manager_adjust_rollback_timeout (_checkpoint_mgr_get (self, TRUE),
|
||||
checkpoint_path, add_timeout, &error);
|
||||
} else
|
||||
g_return_if_reached ();
|
||||
}
|
||||
|
@ -6007,7 +6013,6 @@ checkpoint_auth_done_cb (NMAuthChain *chain,
|
|||
else
|
||||
g_dbus_method_invocation_return_value (context, variant);
|
||||
|
||||
|
||||
nm_auth_chain_unref (chain);
|
||||
}
|
||||
|
||||
|
@ -6110,6 +6115,39 @@ impl_manager_checkpoint_rollback (NMDBusObject *obj,
|
|||
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
impl_manager_checkpoint_adjust_rollback_timeout (NMDBusObject *obj,
|
||||
const NMDBusInterfaceInfoExtended *interface_info,
|
||||
const NMDBusMethodInfoExtended *method_info,
|
||||
GDBusConnection *connection,
|
||||
const char *sender,
|
||||
GDBusMethodInvocation *invocation,
|
||||
GVariant *parameters)
|
||||
{
|
||||
NMManager *self = NM_MANAGER (obj);
|
||||
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
|
||||
NMAuthChain *chain;
|
||||
const char *checkpoint_path;
|
||||
guint32 add_timeout;
|
||||
|
||||
chain = nm_auth_chain_new_context (invocation, checkpoint_auth_done_cb, self);
|
||||
if (!chain) {
|
||||
g_dbus_method_invocation_return_error_literal (invocation,
|
||||
NM_MANAGER_ERROR,
|
||||
NM_MANAGER_ERROR_PERMISSION_DENIED,
|
||||
"Unable to authenticate request.");
|
||||
return;
|
||||
}
|
||||
|
||||
g_variant_get (parameters, "(&ou)", &checkpoint_path, &add_timeout);
|
||||
|
||||
priv->auth_chains = g_slist_append (priv->auth_chains, chain);
|
||||
nm_auth_chain_set_data (chain, "audit-op", NM_AUDIT_OP_CHECKPOINT_ADJUST_ROLLBACK_TIMEOUT, NULL);
|
||||
nm_auth_chain_set_data (chain, "checkpoint_path", g_strdup (checkpoint_path), g_free);
|
||||
nm_auth_chain_set_data (chain, "add_timeout", GUINT_TO_POINTER (add_timeout), NULL);
|
||||
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK, TRUE);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
|
@ -6964,6 +7002,16 @@ static const NMDBusInterfaceInfoExtended interface_info_manager = {
|
|||
),
|
||||
.handle = impl_manager_checkpoint_rollback,
|
||||
),
|
||||
NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
|
||||
NM_DEFINE_GDBUS_METHOD_INFO_INIT (
|
||||
"CheckpointAdjustRollbackTimeout",
|
||||
.in_args = NM_DEFINE_GDBUS_ARG_INFOS (
|
||||
NM_DEFINE_GDBUS_ARG_INFO ("checkpoint", "o"),
|
||||
NM_DEFINE_GDBUS_ARG_INFO ("add_timeout", "u"),
|
||||
),
|
||||
),
|
||||
.handle = impl_manager_checkpoint_adjust_rollback_timeout,
|
||||
),
|
||||
),
|
||||
.signals = NM_DEFINE_GDBUS_SIGNAL_INFOS (
|
||||
&nm_signal_info_property_changed_legacy,
|
||||
|
|
Loading…
Reference in New Issue
Block a user