cli: add 'nmcli connection import' (rh #1034105)
Synopsis: nmcli connection import [--temporary] type <type> file <file to import> Only VPN configurations can be imported at the moment. https://bugzilla.redhat.com/show_bug.cgi?id=1034105
This commit is contained in:
@@ -40,6 +40,8 @@ nmcli_SOURCES = \
|
|||||||
\
|
\
|
||||||
$(srcdir)/../common/nm-secret-agent-simple.c \
|
$(srcdir)/../common/nm-secret-agent-simple.c \
|
||||||
$(srcdir)/../common/nm-secret-agent-simple.h \
|
$(srcdir)/../common/nm-secret-agent-simple.h \
|
||||||
|
$(srcdir)/../common/nm-vpn-helpers.c \
|
||||||
|
$(srcdir)/../common/nm-vpn-helpers.h \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
nmcli_LDADD = \
|
nmcli_LDADD = \
|
||||||
|
@@ -36,6 +36,7 @@
|
|||||||
#include "connections.h"
|
#include "connections.h"
|
||||||
#include "nm-secret-agent-simple.h"
|
#include "nm-secret-agent-simple.h"
|
||||||
#include "polkit-agent.h"
|
#include "polkit-agent.h"
|
||||||
|
#include "nm-vpn-helpers.h"
|
||||||
|
|
||||||
/* define some prompts for connection editor */
|
/* define some prompts for connection editor */
|
||||||
#define EDITOR_PROMPT_SETTING _("Setting name? ")
|
#define EDITOR_PROMPT_SETTING _("Setting name? ")
|
||||||
@@ -274,7 +275,8 @@ usage (void)
|
|||||||
" delete [id | uuid | path] <ID>\n\n"
|
" delete [id | uuid | path] <ID>\n\n"
|
||||||
" monitor [id | uuid | path] <ID> ...\n\n"
|
" monitor [id | uuid | path] <ID> ...\n\n"
|
||||||
" reload\n\n"
|
" reload\n\n"
|
||||||
" load <filename> [ <filename>... ]\n\n"));
|
" load <filename> [ <filename>... ]\n\n"
|
||||||
|
" import [--temporary] type <type> file <file to import>\n\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -522,6 +524,19 @@ usage_connection_load (void)
|
|||||||
"state.\n\n"));
|
"state.\n\n"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
usage_connection_import (void)
|
||||||
|
{
|
||||||
|
g_printerr (_("Usage: nmcli connection import { ARGUMENTS | help }\n"
|
||||||
|
"\n"
|
||||||
|
"ARGUMENTS := [--temporary] type <type> file <file to import>\n"
|
||||||
|
"\n"
|
||||||
|
"Import an external/foreign configuration as a NetworkManager connection profile.\n"
|
||||||
|
"The type of the input file is specified by type option.\n"
|
||||||
|
"Only VPN configurations are supported at the moment. The configuration\n"
|
||||||
|
"is imported by NetworkManager VPN plugins.\n\n"));
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
usage_connection_second_level (const char *cmd)
|
usage_connection_second_level (const char *cmd)
|
||||||
{
|
{
|
||||||
@@ -549,6 +564,8 @@ usage_connection_second_level (const char *cmd)
|
|||||||
usage_connection_reload ();
|
usage_connection_reload ();
|
||||||
else if (matches (cmd, "load") == 0)
|
else if (matches (cmd, "load") == 0)
|
||||||
usage_connection_load ();
|
usage_connection_load ();
|
||||||
|
else if (matches (cmd, "import") == 0)
|
||||||
|
usage_connection_import ();
|
||||||
else
|
else
|
||||||
ret = FALSE;
|
ret = FALSE;
|
||||||
return ret;
|
return ret;
|
||||||
@@ -9967,6 +9984,114 @@ do_connection_load (NmCli *nmc, int argc, char **argv)
|
|||||||
return nmc->return_value;
|
return nmc->return_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FIXME: change the text when non-VPN connection types are supported
|
||||||
|
#define PROMPT_IMPORT_TYPE PROMPT_VPN_TYPE
|
||||||
|
#define PROMPT_IMPORT_FILE _("File to import: ")
|
||||||
|
|
||||||
|
static NMCResultCode
|
||||||
|
do_connection_import (NmCli *nmc, gboolean temporary, int argc, char **argv)
|
||||||
|
{
|
||||||
|
GError *error = NULL;
|
||||||
|
const char *type = NULL, *filename = NULL;
|
||||||
|
char *type_ask = NULL, *filename_ask = NULL;
|
||||||
|
AddConnectionInfo *info;
|
||||||
|
NMConnection *connection = NULL;
|
||||||
|
NMVpnEditorPlugin *plugin;
|
||||||
|
|
||||||
|
if (argc == 0) {
|
||||||
|
if (nmc->ask) {
|
||||||
|
type_ask = nmc_readline (PROMPT_IMPORT_TYPE);
|
||||||
|
filename_ask = nmc_readline (PROMPT_IMPORT_FILE);
|
||||||
|
type = type_ask = type_ask ? g_strstrip (type_ask) : NULL;
|
||||||
|
filename = filename_ask = filename_ask ? g_strstrip (filename_ask) : NULL;
|
||||||
|
} else {
|
||||||
|
g_string_printf (nmc->return_text, _("Error: No arguments provided."));
|
||||||
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
while (argc > 0) {
|
||||||
|
if (strcmp (*argv, "type") == 0) {
|
||||||
|
if (next_arg (&argc, &argv) != 0) {
|
||||||
|
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
|
||||||
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
if (!type)
|
||||||
|
type = *argv;
|
||||||
|
else
|
||||||
|
g_printerr (_("Warning: 'type' already specified, ignoring extra one.\n"));
|
||||||
|
|
||||||
|
} else if (strcmp (*argv, "file") == 0) {
|
||||||
|
if (next_arg (&argc, &argv) != 0) {
|
||||||
|
g_string_printf (nmc->return_text, _("Error: %s argument is missing."), *(argv-1));
|
||||||
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
if (!filename)
|
||||||
|
filename = *argv;
|
||||||
|
else
|
||||||
|
g_printerr (_("Warning: 'file' already specified, ignoring extra one.\n"));
|
||||||
|
} else {
|
||||||
|
g_string_printf (nmc->return_text, _("Unknown parameter: %s\n"), *argv);
|
||||||
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!type) {
|
||||||
|
g_string_printf (nmc->return_text, _("Error: 'type' argument is required."));
|
||||||
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
if (!filename) {
|
||||||
|
g_string_printf (nmc->return_text, _("Error: 'file' argument is required."));
|
||||||
|
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Import VPN configuration */
|
||||||
|
plugin = nm_vpn_get_plugin_by_service (type, &error);
|
||||||
|
if (!plugin) {
|
||||||
|
g_string_printf (nmc->return_text, _("Error: failed to load VPN plugin: %s."),
|
||||||
|
error->message);
|
||||||
|
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
connection = nm_vpn_editor_plugin_import (plugin, filename, &error);
|
||||||
|
if (!connection) {
|
||||||
|
g_string_printf (nmc->return_text, _("Error: failed to import '%s': %s."),
|
||||||
|
filename, error->message);
|
||||||
|
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
|
||||||
|
goto finish;
|
||||||
|
}
|
||||||
|
|
||||||
|
info = g_malloc0 (sizeof (AddConnectionInfo));
|
||||||
|
info->nmc = nmc;
|
||||||
|
info->con_name = g_strdup (nm_connection_get_id (connection));
|
||||||
|
|
||||||
|
/* Add the new imported connection to NetworkManager */
|
||||||
|
add_new_connection (!temporary,
|
||||||
|
nmc->client,
|
||||||
|
connection,
|
||||||
|
add_connection_cb,
|
||||||
|
info);
|
||||||
|
|
||||||
|
nmc->should_wait = TRUE;
|
||||||
|
finish:
|
||||||
|
if (connection)
|
||||||
|
g_object_unref (connection);
|
||||||
|
g_clear_error (&error);
|
||||||
|
g_free (type_ask);
|
||||||
|
g_free (filename_ask);
|
||||||
|
return nmc->return_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
NmCli *nmc;
|
NmCli *nmc;
|
||||||
@@ -10067,6 +10192,11 @@ nmcli_con_tab_completion (const char *text, int start, int end)
|
|||||||
generator_func = gen_func_connection_names;
|
generator_func = gen_func_connection_names;
|
||||||
} else if (g_strcmp0 (rl_prompt, PROMPT_ACTIVE_CONNECTIONS) == 0) {
|
} else if (g_strcmp0 (rl_prompt, PROMPT_ACTIVE_CONNECTIONS) == 0) {
|
||||||
generator_func = gen_func_active_connection_names;
|
generator_func = gen_func_active_connection_names;
|
||||||
|
} else if (g_strcmp0 (rl_prompt, PROMPT_IMPORT_TYPE) == 0) {
|
||||||
|
generator_func = gen_func_vpn_types;
|
||||||
|
} else if (g_strcmp0 (rl_prompt, PROMPT_IMPORT_FILE) == 0) {
|
||||||
|
rl_attempted_completion_over = 0;
|
||||||
|
rl_complete_with_tilde_expansion = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (generator_func)
|
if (generator_func)
|
||||||
@@ -10250,6 +10380,15 @@ do_connections (NmCli *nmc, int argc, char **argv)
|
|||||||
next_arg (&argc, &argv);
|
next_arg (&argc, &argv);
|
||||||
}
|
}
|
||||||
nmc->return_value = do_connection_clone (nmc, temporary, argc, argv);
|
nmc->return_value = do_connection_clone (nmc, temporary, argc, argv);
|
||||||
|
} else if (matches(*argv, "import") == 0) {
|
||||||
|
gboolean temporary = FALSE;
|
||||||
|
|
||||||
|
next_arg (&argc, &argv);
|
||||||
|
if (nmc_arg_is_option (*argv, "temporary")) {
|
||||||
|
temporary = TRUE;
|
||||||
|
next_arg (&argc, &argv);
|
||||||
|
}
|
||||||
|
nmc->return_value = do_connection_import (nmc, temporary, argc, argv);
|
||||||
} else {
|
} else {
|
||||||
usage ();
|
usage ();
|
||||||
g_string_printf (nmc->return_text, _("Error: '%s' is not valid 'connection' command."), *argv);
|
g_string_printf (nmc->return_text, _("Error: '%s' is not valid 'connection' command."), *argv);
|
||||||
|
@@ -282,6 +282,7 @@ _nmcli_compl_OPTIONS()
|
|||||||
# expects several options with parameters. This function can parse them and remove them from the words array.
|
# expects several options with parameters. This function can parse them and remove them from the words array.
|
||||||
_nmcli_compl_ARGS()
|
_nmcli_compl_ARGS()
|
||||||
{
|
{
|
||||||
|
local aliases=${@}
|
||||||
local OPTIONS_ALL N_REMOVE_WORDS REMOVE_OPTIONS OPTIONS_HAS_MANDATORY i
|
local OPTIONS_ALL N_REMOVE_WORDS REMOVE_OPTIONS OPTIONS_HAS_MANDATORY i
|
||||||
OPTIONS_ALL=("${OPTIONS[@]}")
|
OPTIONS_ALL=("${OPTIONS[@]}")
|
||||||
OPTIONS_UNKNOWN_OPTION=
|
OPTIONS_UNKNOWN_OPTION=
|
||||||
@@ -317,7 +318,17 @@ _nmcli_compl_ARGS()
|
|||||||
|
|
||||||
N_REMOVE_WORDS=2
|
N_REMOVE_WORDS=2
|
||||||
REMOVE_OPTIONS=("${words[0]}")
|
REMOVE_OPTIONS=("${words[0]}")
|
||||||
case "${words[0]}" in
|
|
||||||
|
# change option name to alias
|
||||||
|
WORD0="${words[0]}"
|
||||||
|
for alias in "${aliases[@]}" ; do
|
||||||
|
if [[ "${WORD0}" == ${alias%%:*} ]]; then
|
||||||
|
WORD0=${alias#*:}
|
||||||
|
break
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
case "${WORD0}" in
|
||||||
level)
|
level)
|
||||||
if [[ "${#words[@]}" -eq 2 ]]; then
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
||||||
_nmcli_list "OFF ERR WARN INFO DEBUG TRACE"
|
_nmcli_list "OFF ERR WARN INFO DEBUG TRACE"
|
||||||
@@ -560,7 +571,8 @@ _nmcli_compl_ARGS()
|
|||||||
username| \
|
username| \
|
||||||
service| \
|
service| \
|
||||||
password| \
|
password| \
|
||||||
passwd-file)
|
passwd-file| \
|
||||||
|
file)
|
||||||
if [[ "${#words[@]}" -eq 2 ]]; then
|
if [[ "${#words[@]}" -eq 2 ]]; then
|
||||||
return 0
|
return 0
|
||||||
fi
|
fi
|
||||||
@@ -870,7 +882,7 @@ _nmcli()
|
|||||||
;;
|
;;
|
||||||
c|co|con|conn|conne|connec|connect|connecti|connectio|connection)
|
c|co|con|conn|conne|connec|connect|connecti|connectio|connection)
|
||||||
if [[ ${#words[@]} -eq 2 ]]; then
|
if [[ ${#words[@]} -eq 2 ]]; then
|
||||||
_nmcli_compl_COMMAND "$command" show up down add modify clone edit delete monitor reload load
|
_nmcli_compl_COMMAND "$command" show up down add modify clone edit delete monitor reload load import
|
||||||
elif [[ ${#words[@]} -gt 2 ]]; then
|
elif [[ ${#words[@]} -gt 2 ]]; then
|
||||||
case "$command" in
|
case "$command" in
|
||||||
s|sh|sho|show)
|
s|sh|sho|show)
|
||||||
@@ -1315,6 +1327,35 @@ _nmcli()
|
|||||||
COMPREPLY=()
|
COMPREPLY=()
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
|
i|im|imp|impo|impor|import)
|
||||||
|
if [[ ${#words[@]} -eq 3 ]]; then
|
||||||
|
_nmcli_compl_COMMAND "${words[2]}" type file --temporary
|
||||||
|
elif [[ ${#words[@]} -gt 3 ]]; then
|
||||||
|
_nmcli_array_delete_at words 0 1
|
||||||
|
|
||||||
|
LONG_OPTIONS=(help temporary)
|
||||||
|
HELP_ONLY_AS_FIRST=1
|
||||||
|
_nmcli_compl_OPTIONS
|
||||||
|
case $? in
|
||||||
|
0)
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
1)
|
||||||
|
if [[ "$HELP_ONLY_AS_FIRST" == 1 ]]; then
|
||||||
|
_nmcli_compl_COMMAND "${words[2]}" type file
|
||||||
|
fi
|
||||||
|
return 0
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
|
||||||
|
OPTIONS=(type file)
|
||||||
|
OPTIONS_MANDATORY=(type file)
|
||||||
|
ALIASES=("type:vpn-type")
|
||||||
|
_nmcli_compl_ARGS ${ALIASES[@]}
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
|
||||||
esac
|
esac
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
|
@@ -816,6 +816,21 @@ then \fINetworkManager\fP will reload connection files any time they change
|
|||||||
Load/reload one or more connection files from disk. Use this after manually
|
Load/reload one or more connection files from disk. Use this after manually
|
||||||
editing a connection file to ensure that \fBNetworkManager\fP is aware
|
editing a connection file to ensure that \fBNetworkManager\fP is aware
|
||||||
of its latest state.
|
of its latest state.
|
||||||
|
.TP
|
||||||
|
.B import [--temporary] type <type> file <file to import>
|
||||||
|
.br
|
||||||
|
Import an external/foreign configuration as a NetworkManager connection profile.
|
||||||
|
The type of the input file is specified by \fItype\fP option.
|
||||||
|
.br
|
||||||
|
Only VPN configurations are supported at the moment. The configuration
|
||||||
|
is imported by NetworkManager VPN plugins. \fItype\fP values are the same as for
|
||||||
|
\fIvpn-type\fP option in \fBnmcli connection add\fP. VPN configurations are
|
||||||
|
imported by VPN plugins. Therefore the proper VPN plugin has to be installed
|
||||||
|
so that nmcli could import the data.
|
||||||
|
.br
|
||||||
|
The imported connection profile will be saved as persistent unless \fI--temporary\fP
|
||||||
|
option is specified, in which case the new profile won't exist after NetworkManager
|
||||||
|
restart.
|
||||||
.RE
|
.RE
|
||||||
|
|
||||||
.TP
|
.TP
|
||||||
@@ -1187,6 +1202,10 @@ appends a Google public DNS server to DNS servers in ABC profile.
|
|||||||
.IP
|
.IP
|
||||||
removes the specified IP address from (static) profile ABC.
|
removes the specified IP address from (static) profile ABC.
|
||||||
|
|
||||||
|
.IP "\fB\f(CWnmcli con import type openvpn file ~/Downloads/frootvpn.ovpn\fP\fP"
|
||||||
|
.IP
|
||||||
|
imports an OpenVPN configuration to NetworkManager.
|
||||||
|
|
||||||
.SH NOTES
|
.SH NOTES
|
||||||
\fInmcli\fP accepts abbreviations, as long as they are a unique prefix in the set
|
\fInmcli\fP accepts abbreviations, as long as they are a unique prefix in the set
|
||||||
of possible options. As new options get added, these abbreviations are not guaranteed
|
of possible options. As new options get added, these abbreviations are not guaranteed
|
||||||
|
Reference in New Issue
Block a user