Lubomir Rintel 2022-03-28 15:00:45 +02:00
commit 8dbe6fa0d5
13 changed files with 347 additions and 19 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

@ -67,7 +67,7 @@
AddConnection2: AddConnection2:
@settings: New connection settings, properties, and (optionally) secrets. @settings: New connection settings, properties, and (optionally) secrets.
@flags: Flags. Unknown flags cause the call to fail. @flags: 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.
@path: Object path of the new connection that was just added. @path: Object path of the new connection that was just added.
@result: Output argument, currently no additional results are returned. @result: Output argument, currently no additional results are returned.
@since: 1.20 @since: 1.20
@ -100,6 +100,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 newly added connection will
use, such as "keyfile" or "ifcfg-rh".</para>
<para role="since">Since 1.38</para></listitem>
</varlistentry>
</variablelist>
Either the flags 0x1 (to-disk) or 0x2 (in-memory) must be specified. Either the flags 0x1 (to-disk) or 0x2 (in-memory) must be specified.
The effect is whether to behave like The effect is whether to behave like
<link linkend="gdbus-method-org-freedesktop-NetworkManager-Settings.AddConnection">AddConnection</link> or <link linkend="gdbus-method-org-freedesktop-NetworkManager-Settings.AddConnection">AddConnection</link> or

View file

@ -659,6 +659,7 @@
<arg choice='plain'><command>load</command></arg> <arg choice='plain'><command>load</command></arg>
<arg choice='plain'><command>import</command></arg> <arg choice='plain'><command>import</command></arg>
<arg choice='plain'><command>export</command></arg> <arg choice='plain'><command>export</command></arg>
<arg choice='plain'><command>migrate</command></arg>
</group> </group>
<arg rep='repeat'><replaceable>ARGUMENTS</replaceable></arg> <arg rep='repeat'><replaceable>ARGUMENTS</replaceable></arg>
</cmdsynopsis> </cmdsynopsis>
@ -1312,6 +1313,40 @@
data will be printed to standard output.</para> data will be printed to standard output.</para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>
<command>migrate</command>
<arg>
<option>--plugin</option>
<arg choice='plain' rep='repeat'><replaceable>plugin</replaceable></arg>
</arg>
<group>
<arg choice='plain'><option>id</option></arg>
<arg choice='plain'><option>uuid</option></arg>
<arg choice='plain'><option>path</option></arg>
</group>
<arg rep='repeat'><replaceable>ID</replaceable></arg>
</term>
<listitem>
<para>Migrate connection profiles to a different settings plugin, such
as <literal>keyfile</literal> (default) or <literal>ifcfg-rh</literal>.</para>
<para>The connection to be migrated is identified by its name, UUID or D-Bus path.
If <replaceable>ID</replaceable> is ambiguous, a keyword <option>id</option>,
<option>uuid</option> or <option>path</option> can be used. See <command>connection
show</command> above for the description of the
<replaceable>ID</replaceable>-specifying keywords.</para>
<para>If no connections are specified, the command acts on all available
connections. Therefore, with no arguments, the command migrates all connection
profiles to the <literal>keyfile</literal> plugin.</para>
<para>If <option>--wait</option> option is not specified, the default timeout will be 10
seconds.</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</refsect1> </refsect1>

View file

@ -1352,6 +1352,7 @@ _conn_create_panu_connection(NMBluezManager *self, BzDBusObj *bzobj)
bzobj->d_device.address); bzobj->d_device.address);
nm_settings_add_connection(priv->settings, nm_settings_add_connection(priv->settings,
NULL,
connection, connection,
NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY, NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY,
NM_SETTINGS_CONNECTION_ADD_REASON_NONE, NM_SETTINGS_CONNECTION_ADD_REASON_NONE,

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

@ -948,6 +948,7 @@ mirror_connection(NMIwdManager *self,
if (!nm_settings_add_connection( if (!nm_settings_add_connection(
priv->settings, priv->settings,
NULL,
connection, connection,
NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY, NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY,
NM_SETTINGS_CONNECTION_ADD_REASON_NONE, NM_SETTINGS_CONNECTION_ADD_REASON_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,
@ -247,6 +248,7 @@ restore_and_activate_connection(NMCheckpoint *self, DeviceCheckpoint *dev_checkp
persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_TO_DISK; persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_TO_DISK;
if (!nm_settings_add_connection(NM_SETTINGS_GET, if (!nm_settings_add_connection(NM_SETTINGS_GET,
NULL,
dev_checkpoint->settings_connection, dev_checkpoint->settings_connection,
persist_mode, persist_mode,
NM_SETTINGS_CONNECTION_ADD_REASON_NONE, NM_SETTINGS_CONNECTION_ADD_REASON_NONE,

View file

@ -2939,6 +2939,7 @@ get_existing_connection(NMManager *self, NMDevice *device, gboolean *out_generat
nm_device_assume_state_reset(device); nm_device_assume_state_reset(device);
if (!nm_settings_add_connection(priv->settings, if (!nm_settings_add_connection(priv->settings,
NULL,
connection, connection,
NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY, NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY,
NM_SETTINGS_CONNECTION_ADD_REASON_NONE, NM_SETTINGS_CONNECTION_ADD_REASON_NONE,
@ -3059,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,
@ -5915,6 +5917,7 @@ _add_and_activate_auth_done(NMManager *self,
* shutdown. */ * shutdown. */
nm_settings_add_connection_dbus( nm_settings_add_connection_dbus(
priv->settings, priv->settings,
NULL,
connection, connection,
persist_mode, persist_mode,
NM_SETTINGS_CONNECTION_ADD_REASON_NONE, NM_SETTINGS_CONNECTION_ADD_REASON_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
@ -1463,6 +1473,7 @@ _plugin_connections_reload(NMSettings *self)
static gboolean static gboolean
_add_connection_to_first_plugin(NMSettings *self, _add_connection_to_first_plugin(NMSettings *self,
const char *plugin_name,
SettConnEntry *sett_conn_entry, SettConnEntry *sett_conn_entry,
NMConnection *new_connection, NMConnection *new_connection,
gboolean in_memory, gboolean in_memory,
@ -1471,12 +1482,14 @@ _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);
gs_free_error GError *first_error = NULL; gs_free_error GError *first_error = NULL;
GSList *iter; GSList *iter;
const char *uuid; const char *uuid;
gboolean no_plugin = TRUE;
uuid = nm_connection_get_uuid(new_connection); uuid = nm_connection_get_uuid(new_connection);
@ -1493,12 +1506,18 @@ _add_connection_to_first_plugin(NMSettings *self,
gboolean success; gboolean success;
const char *filename; const char *filename;
if (plugin_name && strcmp(plugin_name, nm_settings_plugin_get_plugin_name(plugin))) {
/* Not the plugin we're confined to. Ignore. */
continue;
}
if (!in_memory) { if (!in_memory) {
NMSettingsStorage *conflicting_storage; NMSettingsStorage *conflicting_storage;
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
@ -1545,6 +1564,8 @@ _add_connection_to_first_plugin(NMSettings *self,
&add_error); &add_error);
} }
no_plugin = FALSE;
if (!success) { if (!success) {
_LOGT("add-connection: failed to add %s/'%s': %s", _LOGT("add-connection: failed to add %s/'%s': %s",
nm_connection_get_uuid(new_connection), nm_connection_get_uuid(new_connection),
@ -1588,8 +1609,18 @@ _add_connection_to_first_plugin(NMSettings *self,
return TRUE; return TRUE;
} }
nm_assert(first_error); if (no_plugin) {
g_propagate_error(error, g_steal_pointer(&first_error)); nm_assert(plugin_name);
nm_assert(!first_error);
g_set_error(error,
NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_INVALID_ARGUMENTS,
"a plugin by the name of '%s' is not available",
plugin_name);
} else {
nm_assert(first_error);
g_propagate_error(error, g_steal_pointer(&first_error));
}
return FALSE; return FALSE;
} }
@ -1704,6 +1735,7 @@ _set_nmmeta_tombstone(NMSettings *self,
*/ */
gboolean gboolean
nm_settings_add_connection(NMSettings *self, nm_settings_add_connection(NMSettings *self,
const char *plugin,
NMConnection *connection, NMConnection *connection,
NMSettingsConnectionPersistMode persist_mode, NMSettingsConnectionPersistMode persist_mode,
NMSettingsConnectionAddReason add_reason, NMSettingsConnectionAddReason add_reason,
@ -1800,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
@ -1824,6 +1857,7 @@ again_add_connection:
if (!update_storage) { if (!update_storage) {
success = _add_connection_to_first_plugin(self, success = _add_connection_to_first_plugin(self,
plugin,
sett_conn_entry, sett_conn_entry,
connection, connection,
new_in_memory, new_in_memory,
@ -1832,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,
@ -1948,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,
@ -2154,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) {
@ -2174,8 +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,
plugin_name,
sett_conn_entry, sett_conn_entry,
connection, connection,
new_in_memory, new_in_memory,
@ -2184,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,
@ -2462,6 +2514,7 @@ pk_add_cb(NMAuthChain *chain, GDBusMethodInvocation *context, gpointer user_data
nm_assert(NM_IS_CONNECTION(connection)); nm_assert(NM_IS_CONNECTION(connection));
nm_settings_add_connection(self, nm_settings_add_connection(self,
nm_auth_chain_get_data(chain, "plugin"),
connection, connection,
GPOINTER_TO_UINT(nm_auth_chain_get_data(chain, "persist-mode")), GPOINTER_TO_UINT(nm_auth_chain_get_data(chain, "persist-mode")),
GPOINTER_TO_UINT(nm_auth_chain_get_data(chain, "add-reason")), GPOINTER_TO_UINT(nm_auth_chain_get_data(chain, "add-reason")),
@ -2489,6 +2542,7 @@ pk_add_cb(NMAuthChain *chain, GDBusMethodInvocation *context, gpointer user_data
void void
nm_settings_add_connection_dbus(NMSettings *self, nm_settings_add_connection_dbus(NMSettings *self,
const char *plugin,
NMConnection *connection, NMConnection *connection,
NMSettingsConnectionPersistMode persist_mode, NMSettingsConnectionPersistMode persist_mode,
NMSettingsConnectionAddReason add_reason, NMSettingsConnectionAddReason add_reason,
@ -2549,6 +2603,7 @@ nm_settings_add_connection_dbus(NMSettings *self,
nm_auth_chain_set_data(chain, "persist-mode", GUINT_TO_POINTER(persist_mode), NULL); nm_auth_chain_set_data(chain, "persist-mode", GUINT_TO_POINTER(persist_mode), NULL);
nm_auth_chain_set_data(chain, "add-reason", GUINT_TO_POINTER(add_reason), NULL); nm_auth_chain_set_data(chain, "add-reason", GUINT_TO_POINTER(add_reason), NULL);
nm_auth_chain_set_data(chain, "sett-flags", GUINT_TO_POINTER(sett_flags), NULL); nm_auth_chain_set_data(chain, "sett-flags", GUINT_TO_POINTER(sett_flags), NULL);
nm_auth_chain_set_data(chain, "plugin", g_strdup(plugin), g_free);
nm_auth_chain_add_call_unsafe(chain, perm, TRUE); nm_auth_chain_add_call_unsafe(chain, perm, TRUE);
return; return;
@ -2601,6 +2656,7 @@ settings_add_connection_helper(NMSettings *self,
GDBusMethodInvocation *context, GDBusMethodInvocation *context,
gboolean is_add_connection_2, gboolean is_add_connection_2,
GVariant *settings, GVariant *settings,
const char *plugin,
NMSettingsAddConnection2Flags flags) NMSettingsAddConnection2Flags flags)
{ {
gs_unref_object NMConnection *connection = NULL; gs_unref_object NMConnection *connection = NULL;
@ -2636,6 +2692,7 @@ settings_add_connection_helper(NMSettings *self,
nm_settings_add_connection_dbus( nm_settings_add_connection_dbus(
self, self,
plugin,
connection, connection,
persist_mode, persist_mode,
NM_FLAGS_HAS(flags, NM_SETTINGS_ADD_CONNECTION2_FLAG_BLOCK_AUTOCONNECT) NM_FLAGS_HAS(flags, NM_SETTINGS_ADD_CONNECTION2_FLAG_BLOCK_AUTOCONNECT)
@ -2665,6 +2722,7 @@ impl_settings_add_connection(NMDBusObject *obj,
invocation, invocation,
FALSE, FALSE,
settings, settings,
NULL,
NM_SETTINGS_ADD_CONNECTION2_FLAG_TO_DISK); NM_SETTINGS_ADD_CONNECTION2_FLAG_TO_DISK);
} }
@ -2685,6 +2743,7 @@ impl_settings_add_connection_unsaved(NMDBusObject *obj,
invocation, invocation,
FALSE, FALSE,
settings, settings,
NULL,
NM_SETTINGS_ADD_CONNECTION2_FLAG_IN_MEMORY); NM_SETTINGS_ADD_CONNECTION2_FLAG_IN_MEMORY);
} }
@ -2700,8 +2759,10 @@ impl_settings_add_connection2(NMDBusObject *obj,
NMSettings *self = NM_SETTINGS(obj); NMSettings *self = NM_SETTINGS(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 = NULL;
NMSettingsAddConnection2Flags flags; NMSettingsAddConnection2Flags flags;
const char *args_name; const char *args_name;
GVariant *args_value;
GVariantIter iter; GVariantIter iter;
guint32 flags_u; guint32 flags_u;
@ -2745,7 +2806,13 @@ impl_settings_add_connection2(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 == NULL && nm_streq(args_name, "plugin")
&& g_variant_is_of_type(args_value, G_VARIANT_TYPE_STRING)) {
plugin = g_variant_dup_string(args_value, NULL);
continue;
}
g_dbus_method_invocation_take_error(invocation, g_dbus_method_invocation_take_error(invocation,
g_error_new(NM_SETTINGS_ERROR, g_error_new(NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_INVALID_ARGUMENTS, NM_SETTINGS_ERROR_INVALID_ARGUMENTS,
@ -2754,7 +2821,7 @@ impl_settings_add_connection2(NMDBusObject *obj,
return; return;
} }
settings_add_connection_helper(self, invocation, TRUE, settings, flags); settings_add_connection_helper(self, invocation, TRUE, settings, plugin, flags);
} }
/*****************************************************************************/ /*****************************************************************************/
@ -3606,6 +3673,7 @@ device_realized(NMDevice *device, GParamSpec *pspec, NMSettings *self)
nm_device_get_iface(device)); nm_device_get_iface(device));
nm_settings_add_connection(self, nm_settings_add_connection(self,
NULL,
connection, connection,
NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY, NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY,
NM_SETTINGS_CONNECTION_ADD_REASON_NONE, NM_SETTINGS_CONNECTION_ADD_REASON_NONE,

View file

@ -68,6 +68,7 @@ typedef void (*NMSettingsAddCallback)(NMSettings *settings,
gpointer user_data); gpointer user_data);
void nm_settings_add_connection_dbus(NMSettings *self, void nm_settings_add_connection_dbus(NMSettings *self,
const char *plugin,
NMConnection *connection, NMConnection *connection,
NMSettingsConnectionPersistMode persist_mode, NMSettingsConnectionPersistMode persist_mode,
NMSettingsConnectionAddReason add_reason, NMSettingsConnectionAddReason add_reason,
@ -90,6 +91,7 @@ NMSettingsConnection **nm_settings_get_connections_clone(NMSettings
gpointer sort_data); gpointer sort_data);
gboolean nm_settings_add_connection(NMSettings *settings, gboolean nm_settings_add_connection(NMSettings *settings,
const char *plugin,
NMConnection *connection, NMConnection *connection,
NMSettingsConnectionPersistMode persist_mode, NMSettingsConnectionPersistMode persist_mode,
NMSettingsConnectionAddReason add_reason, NMSettingsConnectionAddReason add_reason,
@ -99,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,

View file

@ -1231,10 +1231,10 @@ usage_connection_delete(void)
{ {
g_printerr(_("Usage: nmcli connection delete { ARGUMENTS | help }\n" g_printerr(_("Usage: nmcli connection delete { ARGUMENTS | help }\n"
"\n" "\n"
"ARGUMENTS := [id | uuid | path] <ID>\n" "ARGUMENTS := [id | uuid | path] <ID>, ...\n"
"\n" "\n"
"Delete a connection profile.\n" "Delete connection profiles.\n"
"The profile is identified by its name, UUID or D-Bus path.\n\n")); "The profiles are identified by their name, UUID or D-Bus path.\n\n"));
} }
static void static void
@ -1294,6 +1294,17 @@ usage_connection_export(void)
"The data are directed to standard output or to a file if a name is given.\n\n")); "The data are directed to standard output or to a file if a name is given.\n\n"));
} }
static void
usage_connection_migrate(void)
{
g_printerr(_("Usage: nmcli connection migrate { ARGUMENTS | help }\n"
"\n"
"ARGUMENTS := [--plugin <plugin>] [id | uuid | path] <ID>, ...\n"
"\n"
"Migrate connection profiles to a different settings plugin,\n"
"such as \"keyfile\" (default) or \"ifcfg-rh\".\n\n"));
}
static void static void
quit(void) quit(void)
{ {
@ -9138,8 +9149,11 @@ do_connection_delete(const NMCCommand *cmd, NmCli *nmc, int argc, const char *co
nmc->return_value = error->code; nmc->return_value = error->code;
g_clear_error(&error); g_clear_error(&error);
if (nmc->return_value != NMC_RESULT_ERROR_NOT_FOUND) if (nmc->return_value != NMC_RESULT_ERROR_NOT_FOUND) {
g_string_free(invalid_cons, TRUE);
invalid_cons = NULL;
goto finish; goto finish;
}
if (!invalid_cons) if (!invalid_cons)
invalid_cons = g_string_new(NULL); invalid_cons = g_string_new(NULL);
@ -9192,7 +9206,6 @@ finish:
g_string_printf(nmc->return_text, g_string_printf(nmc->return_text,
_("Error: cannot delete unknown connection(s): %s."), _("Error: cannot delete unknown connection(s): %s."),
invalid_cons->str); invalid_cons->str);
nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
} }
} }
@ -9645,6 +9658,154 @@ finish:
unlink(path); unlink(path);
} }
static void
migrate_cb(GObject *obj, GAsyncResult *result, gpointer user_data)
{
ConnectionCbInfo *info = (ConnectionCbInfo *) user_data;
NMConnection *connection = NM_CONNECTION(obj);
gs_unref_variant GVariant *res = NULL;
GError *error = NULL;
res = nm_remote_connection_update2_finish(NM_REMOTE_CONNECTION(obj), result, &error);
if (!res) {
g_string_printf(info->nmc->return_text, _("Error: not all connections migrated."));
g_printerr(_("Error: Connection migration failed: %s\n"), error->message);
g_error_free(error);
info->nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
} else {
g_print(_("Connection '%s' (%s) successfully migrated.\n"),
nm_connection_get_id(connection),
nm_connection_get_uuid(connection));
}
connection_cb_info_finish(info, obj);
}
static void
do_connection_migrate(const NMCCommand *cmd, NmCli *nmc, int argc, const char *const *argv)
{
NMConnection *connection;
ConnectionCbInfo *info = NULL;
gs_strfreev char **arg_arr = NULL;
const char *const *arg_ptr;
guint i;
int arg_num;
nm_auto_free_gstring GString *invalid_cons = NULL;
gs_unref_ptrarray GPtrArray *found_cons = NULL;
GError *error = NULL;
const char *plugin = "keyfile";
const GPtrArray *connections = NULL;
int option;
if (nmc->timeout == -1)
nmc->timeout = 10;
while ((option = next_arg(nmc, &argc, &argv, "--plugin", NULL)) > 0) {
switch (option) {
case 1: /* --plugin */
argc--;
argv++;
if (!argc) {
g_set_error_literal(&error, NMCLI_ERROR, 0, _("'--plugin' argument is missing"));
goto finish;
}
plugin = *argv;
break;
default:
g_return_if_reached();
break;
}
}
arg_ptr = argv;
arg_num = argc;
if (argc == 0) {
if (nmc->ask) {
gs_free char *line = NULL;
/* nmc_do_cmd() should not call this with argc=0. */
g_assert(!nmc->complete);
line = nmc_readline(&nmc->nmc_config, PROMPT_CONNECTIONS);
nmc_string_to_arg_array(line, NULL, TRUE, &arg_arr, &arg_num);
arg_ptr = (const char *const *) arg_arr;
}
}
while (arg_num > 0) {
const char *cur_selector, *cur_value;
connection =
get_connection(nmc, &arg_num, &arg_ptr, &cur_selector, &cur_value, &found_cons, &error);
if (!connection) {
if (!nmc->complete)
g_printerr(_("Error: %s.\n"), error->message);
g_string_printf(nmc->return_text, _("Error: not all connections found."));
nmc->return_value = error->code;
g_clear_error(&error);
if (nmc->return_value != NMC_RESULT_ERROR_NOT_FOUND) {
g_string_free(invalid_cons, TRUE);
invalid_cons = NULL;
goto finish;
}
if (!invalid_cons)
invalid_cons = g_string_new(NULL);
if (cur_selector)
g_string_append_printf(invalid_cons, "%s '%s', ", cur_selector, cur_value);
else
g_string_append_printf(invalid_cons, "'%s', ", cur_value);
}
}
if (nmc->complete)
goto finish;
if (invalid_cons)
goto finish;
if (!found_cons) {
/* No connections specified explicitly? Fine, add all. */
found_cons = g_ptr_array_new();
connections = nm_client_get_connections(nmc->client);
for (i = 0; i < connections->len; i++) {
connection = connections->pdata[i];
g_ptr_array_add(found_cons, connection);
}
}
info = g_slice_new0(ConnectionCbInfo);
info->nmc = nmc;
info->obj_list = g_ptr_array_sized_new(found_cons->len);
for (i = 0; i < found_cons->len; i++) {
connection = found_cons->pdata[i];
g_ptr_array_add(info->obj_list, g_object_ref(connection));
}
info->timeout_id = g_timeout_add_seconds(nmc->timeout, connection_op_timeout_cb, info);
info->cancellable = g_cancellable_new();
nmc->nowait_flag = (nmc->timeout == 0);
nmc->should_wait++;
for (i = 0; i < found_cons->len; i++) {
nm_remote_connection_update2(NM_REMOTE_CONNECTION(found_cons->pdata[i]),
NULL,
0,
g_variant_new_parsed("{'plugin': <%s>}", plugin),
info->cancellable,
migrate_cb,
info);
}
finish:
if (invalid_cons) {
g_string_truncate(invalid_cons, invalid_cons->len - 2); /* truncate trailing ", " */
g_string_printf(nmc->return_text,
_("Error: cannot migrate unknown connection(s): %s."),
invalid_cons->str);
}
}
static char * static char *
gen_func_connection_names(const char *text, int state) gen_func_connection_names(const char *text, int state)
{ {
@ -9752,6 +9913,7 @@ nmc_command_func_connection(const NMCCommand *cmd, NmCli *nmc, int argc, const c
{"clone", do_connection_clone, usage_connection_clone, TRUE, TRUE}, {"clone", do_connection_clone, usage_connection_clone, TRUE, TRUE},
{"import", do_connection_import, usage_connection_import, TRUE, TRUE}, {"import", do_connection_import, usage_connection_import, TRUE, TRUE},
{"export", do_connection_export, usage_connection_export, TRUE, TRUE}, {"export", do_connection_export, usage_connection_export, TRUE, TRUE},
{"migrate", do_connection_migrate, usage_connection_migrate, TRUE, TRUE},
{"monitor", do_connection_monitor, usage_connection_monitor, TRUE, TRUE}, {"monitor", do_connection_monitor, usage_connection_monitor, TRUE, TRUE},
{NULL, do_connections_show, usage, TRUE, TRUE}, {NULL, do_connections_show, usage, TRUE, TRUE},
}; };