settings-connection: add a "plugin" argument to Update2()

This will allow migrating a connection. If specified, the connection will
be confined to a particular settings plugin when written back. If the
plugin differs from the existing one, it will be removed from the old one.
This commit is contained in:
Lubomir Rintel 2022-03-14 10:20:12 +01:00
parent f4f165f945
commit 82d16789a5
8 changed files with 85 additions and 10 deletions

View file

@ -105,7 +105,7 @@
Update2: Update2:
@settings: New connection settings, properties, and (optionally) secrets. Provide an empty array to use the current settings. @settings: New connection settings, properties, and (optionally) secrets. Provide an empty array to use the current settings.
@flags: Optional flags. Unknown flags cause the call to fail. @flags: Optional flags. Unknown flags cause the call to fail.
@args: Optional arguments dictionary, for extentibility. Currently, no arguments are accepted. Specifying unknown keys causes the call to fail. @args: Optional arguments dictionary, for extentibility. Specifying unknown keys causes the call to fail.
@result: Currently no results are returned. @result: Currently no results are returned.
@since: 1.12 @since: 1.12
@ -156,6 +156,17 @@
</varlistentry> </varlistentry>
</variablelist> </variablelist>
The %args argument accepts the following keys:
<variablelist>
<varlistentry>
<term><literal>plugin</literal>:</term>
<listitem><para>The settings plugin the connection will be migrated to
such as "keyfile" or "ifcfg-rh".</para>
<para role="since">Since 1.38</para></listitem>
</varlistentry>
</variablelist>
Secrets may be part of the update request, and will be either stored in persistent Secrets may be part of the update request, and will be either stored in persistent
storage or sent to a Secret Agent for storage, depending on the flags storage or sent to a Secret Agent for storage, depending on the flags
associated with each secret. associated with each secret.

View file

@ -3859,6 +3859,7 @@ update_external_connection(NMDevice *self)
if (connection_new) { if (connection_new) {
nm_settings_connection_update(settings_connection, nm_settings_connection_update(settings_connection,
NULL,
connection_new, connection_new,
NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY, NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY,
NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, NM_SETTINGS_CONNECTION_INT_FLAGS_NONE,

View file

@ -231,6 +231,7 @@ restore_and_activate_connection(NMCheckpoint *self, DeviceCheckpoint *dev_checkp
persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP; persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP;
nm_settings_connection_update( nm_settings_connection_update(
connection, connection,
NULL,
dev_checkpoint->settings_connection, dev_checkpoint->settings_connection,
persist_mode, persist_mode,
sett_flags, sett_flags,

View file

@ -3060,6 +3060,7 @@ recheck_assume_connection(NMManager *self, NMDevice *device)
nm_settings_connection_update( nm_settings_connection_update(
sett_conn, sett_conn,
NULL,
con2, con2,
NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP, NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP,
NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, NM_SETTINGS_CONNECTION_INT_FLAGS_NONE,

View file

@ -606,6 +606,7 @@ _secrets_update(NMConnection *connection,
gboolean gboolean
nm_settings_connection_update(NMSettingsConnection *self, nm_settings_connection_update(NMSettingsConnection *self,
const char *plugin_name,
NMConnection *new_connection, NMConnection *new_connection,
NMSettingsConnectionPersistMode persist_mode, NMSettingsConnectionPersistMode persist_mode,
NMSettingsConnectionIntFlags sett_flags, NMSettingsConnectionIntFlags sett_flags,
@ -618,6 +619,7 @@ nm_settings_connection_update(NMSettingsConnection *self,
return nm_settings_update_connection(NM_SETTINGS_CONNECTION_GET_PRIVATE(self)->settings, return nm_settings_update_connection(NM_SETTINGS_CONNECTION_GET_PRIVATE(self)->settings,
self, self,
plugin_name,
new_connection, new_connection,
persist_mode, persist_mode,
sett_flags, sett_flags,
@ -835,6 +837,7 @@ nm_settings_connection_new_secrets(NMSettingsConnection *self,
if (!nm_settings_connection_update( if (!nm_settings_connection_update(
self, self,
NULL,
new_connection ?: connection, new_connection ?: connection,
NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP, NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP,
NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, NM_SETTINGS_CONNECTION_INT_FLAGS_NONE,
@ -980,6 +983,7 @@ get_secrets_done_cb(NMAgentManager *manager,
} }
if (!nm_settings_connection_update( if (!nm_settings_connection_update(
self, self,
NULL,
new_connection, new_connection,
agent_had_system ? NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP agent_had_system ? NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP
: NM_SETTINGS_CONNECTION_PERSIST_MODE_NO_PERSIST, : NM_SETTINGS_CONNECTION_PERSIST_MODE_NO_PERSIST,
@ -1409,6 +1413,7 @@ typedef struct {
NMConnection *new_settings; NMConnection *new_settings;
NMSettingsUpdate2Flags flags; NMSettingsUpdate2Flags flags;
char *audit_args; char *audit_args;
char *plugin_name;
bool is_update2 : 1; bool is_update2 : 1;
} UpdateInfo; } UpdateInfo;
@ -1436,6 +1441,7 @@ update_complete(NMSettingsConnection *self, UpdateInfo *info, GError *error)
g_clear_object(&info->agent_mgr); g_clear_object(&info->agent_mgr);
g_clear_object(&info->new_settings); g_clear_object(&info->new_settings);
g_free(info->audit_args); g_free(info->audit_args);
g_free(info->plugin_name);
g_slice_free(UpdateInfo, info); g_slice_free(UpdateInfo, info);
} }
@ -1572,6 +1578,7 @@ update_auth_cb(NMSettingsConnection *self,
nm_settings_connection_update( nm_settings_connection_update(
self, self,
info->plugin_name,
info->new_settings, info->new_settings,
persist_mode, persist_mode,
(NM_FLAGS_HAS(info->flags, NM_SETTINGS_UPDATE2_FLAG_VOLATILE) (NM_FLAGS_HAS(info->flags, NM_SETTINGS_UPDATE2_FLAG_VOLATILE)
@ -1642,6 +1649,7 @@ settings_connection_update(NMSettingsConnection *self,
gboolean is_update2, gboolean is_update2,
GDBusMethodInvocation *context, GDBusMethodInvocation *context,
GVariant *new_settings, GVariant *new_settings,
const char *plugin_name,
NMSettingsUpdate2Flags flags) NMSettingsUpdate2Flags flags)
{ {
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE(self); NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE(self);
@ -1696,6 +1704,7 @@ settings_connection_update(NMSettingsConnection *self,
info->subject = subject; info->subject = subject;
info->flags = flags; info->flags = flags;
info->new_settings = tmp; info->new_settings = tmp;
info->plugin_name = g_strdup(plugin_name);
permission = get_update_modify_permission(nm_settings_connection_get_connection(self), permission = get_update_modify_permission(nm_settings_connection_get_connection(self),
tmp ?: nm_settings_connection_get_connection(self)); tmp ?: nm_settings_connection_get_connection(self));
@ -1724,7 +1733,12 @@ impl_settings_connection_update(NMDBusObject *obj,
gs_unref_variant GVariant *settings = NULL; gs_unref_variant GVariant *settings = NULL;
g_variant_get(parameters, "(@a{sa{sv}})", &settings); g_variant_get(parameters, "(@a{sa{sv}})", &settings);
settings_connection_update(self, FALSE, invocation, settings, NM_SETTINGS_UPDATE2_FLAG_TO_DISK); settings_connection_update(self,
FALSE,
invocation,
settings,
NULL,
NM_SETTINGS_UPDATE2_FLAG_TO_DISK);
} }
static void static void
@ -1744,6 +1758,7 @@ impl_settings_connection_update_unsaved(NMDBusObject *obj,
FALSE, FALSE,
invocation, invocation,
settings, settings,
NULL,
NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY); NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY);
} }
@ -1758,7 +1773,12 @@ impl_settings_connection_save(NMDBusObject *obj,
{ {
NMSettingsConnection *self = NM_SETTINGS_CONNECTION(obj); NMSettingsConnection *self = NM_SETTINGS_CONNECTION(obj);
settings_connection_update(self, FALSE, invocation, NULL, NM_SETTINGS_UPDATE2_FLAG_TO_DISK); settings_connection_update(self,
FALSE,
invocation,
NULL,
NULL,
NM_SETTINGS_UPDATE2_FLAG_TO_DISK);
} }
static void static void
@ -1770,13 +1790,15 @@ impl_settings_connection_update2(NMDBusObject *obj,
GDBusMethodInvocation *invocation, GDBusMethodInvocation *invocation,
GVariant *parameters) GVariant *parameters)
{ {
NMSettingsConnection *self = NM_SETTINGS_CONNECTION(obj); NMSettingsConnection *self = NM_SETTINGS_CONNECTION(obj);
gs_unref_variant GVariant *settings = NULL; gs_unref_variant GVariant *settings = NULL;
gs_unref_variant GVariant *args = NULL; gs_unref_variant GVariant *args = NULL;
gs_free char *plugin_name = NULL;
guint32 flags_u; guint32 flags_u;
GError *error = NULL; GError *error = NULL;
GVariantIter iter; GVariantIter iter;
const char *args_name; const char *args_name;
GVariant *args_value;
NMSettingsUpdate2Flags flags; NMSettingsUpdate2Flags flags;
g_variant_get(parameters, "(@a{sa{sv}}u@a{sv})", &settings, &flags_u, &args); g_variant_get(parameters, "(@a{sa{sv}}u@a{sv})", &settings, &flags_u, &args);
@ -1812,7 +1834,13 @@ impl_settings_connection_update2(NMDBusObject *obj,
nm_assert(g_variant_is_of_type(args, G_VARIANT_TYPE("a{sv}"))); nm_assert(g_variant_is_of_type(args, G_VARIANT_TYPE("a{sv}")));
g_variant_iter_init(&iter, args); g_variant_iter_init(&iter, args);
while (g_variant_iter_next(&iter, "{&sv}", &args_name, NULL)) { while (g_variant_iter_next(&iter, "{&sv}", &args_name, &args_value)) {
if (plugin_name == NULL && nm_streq(args_name, "plugin")
&& g_variant_is_of_type(args_value, G_VARIANT_TYPE_STRING)) {
plugin_name = g_variant_dup_string(args_value, NULL);
continue;
}
error = g_error_new(NM_SETTINGS_ERROR, error = g_error_new(NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_INVALID_ARGUMENTS, NM_SETTINGS_ERROR_INVALID_ARGUMENTS,
"Unsupported argument '%s'", "Unsupported argument '%s'",
@ -1821,7 +1849,7 @@ impl_settings_connection_update2(NMDBusObject *obj,
return; return;
} }
settings_connection_update(self, TRUE, invocation, settings, flags); settings_connection_update(self, TRUE, invocation, settings, plugin_name, flags);
} }
static void static void
@ -2010,6 +2038,7 @@ dbus_clear_secrets_auth_cb(NMSettingsConnection *self,
if (!nm_settings_connection_update( if (!nm_settings_connection_update(
self, self,
NULL,
connection_cloned, connection_cloned,
NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP, NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP,
NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, NM_SETTINGS_CONNECTION_INT_FLAGS_NONE,

View file

@ -240,6 +240,7 @@ nm_settings_connection_has_unmodified_applied_connection(NMSettingsConnection *s
NMSettingCompareFlags compare_flage); NMSettingCompareFlags compare_flage);
gboolean nm_settings_connection_update(NMSettingsConnection *self, gboolean nm_settings_connection_update(NMSettingsConnection *self,
const char *plugin_name,
NMConnection *new_connection, NMConnection *new_connection,
NMSettingsConnectionPersistMode persist_mode, NMSettingsConnectionPersistMode persist_mode,
NMSettingsConnectionIntFlags sett_flags, NMSettingsConnectionIntFlags sett_flags,

View file

@ -236,12 +236,16 @@ _sett_conn_entry_get_conn(SettConnEntry *sett_conn_entry)
* update-connection. If this parameter is omitted, then it's about what happens * update-connection. If this parameter is omitted, then it's about what happens
* when adding a new profile (add-connection). * when adding a new profile (add-connection).
* *
* @storage_check_ignore is optional, and if given then it skips this particular
* storage.
*
* Returns: the conflicting storage or %NULL if there is none. * Returns: the conflicting storage or %NULL if there is none.
*/ */
static NMSettingsStorage * static NMSettingsStorage *
_sett_conn_entry_storage_find_conflicting_storage(SettConnEntry *sett_conn_entry, _sett_conn_entry_storage_find_conflicting_storage(SettConnEntry *sett_conn_entry,
NMSettingsPlugin *target_plugin, NMSettingsPlugin *target_plugin,
NMSettingsStorage *storage_check_including, NMSettingsStorage *storage_check_including,
NMSettingsStorage *storage_check_ignore,
const GSList *plugins) const GSList *plugins)
{ {
StorageData *sd; StorageData *sd;
@ -269,6 +273,12 @@ _sett_conn_entry_storage_find_conflicting_storage(SettConnEntry *sett_conn_e
continue; continue;
} }
if (sd->storage == storage_check_ignore) {
/* We ignore this one, because we're in the process of
* replacing it. */
continue;
}
if (sd->storage == storage_check_including) { if (sd->storage == storage_check_including) {
/* ok, the storage is the one we are about to check. All other /* ok, the storage is the one we are about to check. All other
* storages are lower priority, so there is no storage that hides * storages are lower priority, so there is no storage that hides
@ -1472,6 +1482,7 @@ _add_connection_to_first_plugin(NMSettings *self,
gboolean shadowed_owned, gboolean shadowed_owned,
NMSettingsStorage **out_new_storage, NMSettingsStorage **out_new_storage,
NMConnection **out_new_connection, NMConnection **out_new_connection,
NMSettingsStorage *drop_storage,
GError **error) GError **error)
{ {
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE(self); NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE(self);
@ -1506,6 +1517,7 @@ _add_connection_to_first_plugin(NMSettings *self,
conflicting_storage = _sett_conn_entry_storage_find_conflicting_storage(sett_conn_entry, conflicting_storage = _sett_conn_entry_storage_find_conflicting_storage(sett_conn_entry,
plugin, plugin,
NULL, NULL,
drop_storage,
priv->plugins); priv->plugins);
if (conflicting_storage) { if (conflicting_storage) {
/* we have a connection provided by a plugin with higher priority than the one /* we have a connection provided by a plugin with higher priority than the one
@ -1820,6 +1832,7 @@ nm_settings_add_connection(NMSettings *self,
sett_conn_entry, sett_conn_entry,
nm_settings_storage_get_plugin(shadowed_storage), nm_settings_storage_get_plugin(shadowed_storage),
shadowed_storage, shadowed_storage,
NULL,
priv->plugins); priv->plugins);
if (conflicting_storage) { if (conflicting_storage) {
/* We cannot add the profile as @shadowed_storage, because there is another, existing storage /* We cannot add the profile as @shadowed_storage, because there is another, existing storage
@ -1853,6 +1866,7 @@ again_add_connection:
FALSE, FALSE,
&new_storage, &new_storage,
&new_connection, &new_connection,
NULL,
&local); &local);
} else { } else {
success = _update_connection_to_plugin(self, success = _update_connection_to_plugin(self,
@ -1969,6 +1983,7 @@ again_delete_tombstone:
gboolean gboolean
nm_settings_update_connection(NMSettings *self, nm_settings_update_connection(NMSettings *self,
NMSettingsConnection *sett_conn, NMSettingsConnection *sett_conn,
const char *plugin_name,
NMConnection *connection, NMConnection *connection,
NMSettingsConnectionPersistMode persist_mode, NMSettingsConnectionPersistMode persist_mode,
NMSettingsConnectionIntFlags sett_flags, NMSettingsConnectionIntFlags sett_flags,
@ -2175,8 +2190,9 @@ nm_settings_update_connection(NMSettings *self,
} else if (nm_settings_storage_is_keyfile_lib(cur_storage)) { } else if (nm_settings_storage_is_keyfile_lib(cur_storage)) {
/* the profile is a keyfile in /usr/lib. It cannot be overwritten, we must migrate it /* the profile is a keyfile in /usr/lib. It cannot be overwritten, we must migrate it
* from /usr/lib to /etc. */ * from /usr/lib to /etc. */
} else } else {
update_storage = cur_storage; update_storage = cur_storage;
}
if (new_in_memory) { if (new_in_memory) {
if (persist_mode == NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY) { if (persist_mode == NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY) {
@ -2195,9 +2211,22 @@ nm_settings_update_connection(NMSettings *self,
} }
} }
if (update_storage && plugin_name) {
NMSettingsPlugin *plugin = nm_settings_storage_get_plugin(update_storage);
if (strcmp(plugin_name, nm_settings_plugin_get_plugin_name(plugin))) {
/* We're updating a connection, we're confined to a particular
* plugin, but the connection is currently using a different one.
* We need to migrate. Drop the existing storage and look out for
* a new one. */
drop_storage = update_storage;
update_storage = NULL;
}
}
if (!update_storage) { if (!update_storage) {
success = _add_connection_to_first_plugin(self, success = _add_connection_to_first_plugin(self,
NULL, plugin_name,
sett_conn_entry, sett_conn_entry,
connection, connection,
new_in_memory, new_in_memory,
@ -2206,6 +2235,7 @@ nm_settings_update_connection(NMSettings *self,
new_shadowed_owned, new_shadowed_owned,
&new_storage, &new_storage,
&new_connection, &new_connection,
drop_storage,
&local); &local);
} else { } else {
success = _update_connection_to_plugin(self, success = _update_connection_to_plugin(self,

View file

@ -101,6 +101,7 @@ gboolean nm_settings_add_connection(NMSettings *settings,
gboolean nm_settings_update_connection(NMSettings *self, gboolean nm_settings_update_connection(NMSettings *self,
NMSettingsConnection *sett_conn, NMSettingsConnection *sett_conn,
const char *plugin_name,
NMConnection *new_connection, NMConnection *new_connection,
NMSettingsConnectionPersistMode persist_mode, NMSettingsConnectionPersistMode persist_mode,
NMSettingsConnectionIntFlags sett_flags, NMSettingsConnectionIntFlags sett_flags,