summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLubomir Rintel <lkundrak@v3.sk>2022-03-14 13:42:09 +0100
committerLubomir Rintel <lkundrak@v3.sk>2022-03-28 14:59:30 +0200
commit1aa9c80b9bfdb2131e30477db6de18a05699b1bf (patch)
tree2673b1d6c00eeedc3b8a490a53a508db4af2ea1e
parentc7ab380a5cbcf22d943df2ea866649dba97c2806 (diff)
downloadNetworkManager-lr/conn-migrate.tar.gz
cli: add "connection migrate" subcommandlr/conn-migrate
This is used to move a connection to a different settings plugin.
-rw-r--r--man/nmcli.xml35
-rw-r--r--src/nmcli/connections.c160
2 files changed, 195 insertions, 0 deletions
diff --git a/man/nmcli.xml b/man/nmcli.xml
index fabb590f24..d4f27b0b37 100644
--- a/man/nmcli.xml
+++ b/man/nmcli.xml
@@ -659,6 +659,7 @@
<arg choice='plain'><command>load</command></arg>
<arg choice='plain'><command>import</command></arg>
<arg choice='plain'><command>export</command></arg>
+ <arg choice='plain'><command>migrate</command></arg>
</group>
<arg rep='repeat'><replaceable>ARGUMENTS</replaceable></arg>
</cmdsynopsis>
@@ -1312,6 +1313,40 @@
data will be printed to standard output.</para>
</listitem>
</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>
</refsect1>
diff --git a/src/nmcli/connections.c b/src/nmcli/connections.c
index 9f09fee0c6..862c1dd61e 100644
--- a/src/nmcli/connections.c
+++ b/src/nmcli/connections.c
@@ -1295,6 +1295,17 @@ usage_connection_export(void)
}
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
quit(void)
{
if (nm_clear_g_source(&progress_id))
@@ -9641,6 +9652,154 @@ finish:
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 *
gen_func_connection_names(const char *text, int state)
{
@@ -9748,6 +9907,7 @@ nmc_command_func_connection(const NMCCommand *cmd, NmCli *nmc, int argc, const c
{"clone", do_connection_clone, usage_connection_clone, TRUE, TRUE},
{"import", do_connection_import, usage_connection_import, 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},
{NULL, do_connections_show, usage, TRUE, TRUE},
};