nmcli: improve setting connection.secondaries property

- check if the values being set are existing connections
- also allow specifying connections by names, translating them transparently
   to UUIDs.
- nmcli-specific section for 'describe' command added

(We use a global nm_cli variable in nmc_property_connection_set_secondaries())
This commit is contained in:
Jiří Klimeš 2014-04-16 18:23:50 +02:00
parent ab0c37d042
commit 645f0204f9
5 changed files with 130 additions and 69 deletions

View file

@ -951,3 +951,69 @@ nmc_team_check_config (const char *config, char **out_config, GError **error)
return TRUE;
}
/*
* nmc_find_connection:
* @list: list of NMConnections to search in
* @filter_type: "id", "uuid", "path" or %NULL
* @filter_val: connection to find (connection name, UUID or path)
* @start: where to start in @list. The location is updated so that the function
* can be called multiple times (for connections with the same name).
*
* Find a connection in @list according to @filter_val. @filter_type determines
* what property is used for comparison. When @filter_type is NULL, compare
* @filter_val against all types. Otherwise, only compare against the specified
* type. If 'path' filter type is specified, comparison against numeric index
* (in addition to the whole path) is allowed.
*
* Returns: found connection, or %NULL
*/
NMConnection *
nmc_find_connection (GSList *list,
const char *filter_type,
const char *filter_val,
GSList **start)
{
NMConnection *connection;
NMConnection *found = NULL;
GSList *iterator;
const char *id;
const char *uuid;
const char *path, *path_num;
iterator = (start && *start) ? *start : list;
while (iterator) {
connection = NM_CONNECTION (iterator->data);
id = nm_connection_get_id (connection);
uuid = nm_connection_get_uuid (connection);
path = nm_connection_get_path (connection);
path_num = path ? strrchr (path, '/') + 1 : NULL;
/* When filter_type is NULL, compare connection ID (filter_val)
* against all types. Otherwise, only compare against the specific
* type. If 'path' filter type is specified, comparison against
* numeric index (in addition to the whole path) is allowed.
*/
if ( ( (!filter_type || strcmp (filter_type, "id") == 0)
&& strcmp (filter_val, id) == 0)
|| ( (!filter_type || strcmp (filter_type, "uuid") == 0)
&& strcmp (filter_val, uuid) == 0)
|| ( (!filter_type || strcmp (filter_type, "path") == 0)
&& (g_strcmp0 (filter_val, path) == 0 || (filter_type && g_strcmp0 (filter_val, path_num) == 0)))) {
if (!start)
return connection;
if (found) {
*start = iterator;
return found;
}
found = connection;
}
iterator = g_slist_next (iterator);
}
if (start)
*start = NULL;
return found;
}

View file

@ -16,7 +16,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* (C) Copyright 2012 - 2013 Red Hat, Inc.
* (C) Copyright 2012 - 2014 Red Hat, Inc.
*/
#ifndef NMC_COMMON_H
@ -54,4 +54,9 @@ nmc_vlan_parse_priority_maps (const char *priority_map,
const char *nmc_bond_validate_mode (const char *mode, GError **error);
gboolean nmc_team_check_config (const char *config, char **out_config, GError **error);
NMConnection *nmc_find_connection (GSList *list,
const char *filter_type,
const char *filter_val,
GSList **start);
#endif /* NMC_COMMON_H */

View file

@ -702,56 +702,6 @@ nmc_connection_profile_details (NMConnection *connection, NmCli *nmc)
return TRUE;
}
static NMConnection *
find_connection (GSList *list,
const char *filter_type,
const char *filter_val,
GSList **start)
{
NMConnection *connection;
NMConnection *found = NULL;
GSList *iterator;
const char *id;
const char *uuid;
const char *path, *path_num;
iterator = (start && *start) ? *start : list;
while (iterator) {
connection = NM_CONNECTION (iterator->data);
id = nm_connection_get_id (connection);
uuid = nm_connection_get_uuid (connection);
path = nm_connection_get_path (connection);
path_num = path ? strrchr (path, '/') + 1 : NULL;
/* When filter_type is NULL, compare connection ID (filter_val)
* against all types. Otherwise, only compare against the specific
* type. If 'path' filter type is specified, comparison against
* numeric index (in addition to the whole path) is allowed.
*/
if ( ( (!filter_type || strcmp (filter_type, "id") == 0)
&& strcmp (filter_val, id) == 0)
|| ( (!filter_type || strcmp (filter_type, "uuid") == 0)
&& strcmp (filter_val, uuid) == 0)
|| ( (!filter_type || strcmp (filter_type, "path") == 0)
&& (g_strcmp0 (filter_val, path) == 0 || (filter_type && g_strcmp0 (filter_val, path_num) == 0)))) {
if (!start)
return connection;
if (found) {
*start = iterator;
return found;
}
found = connection;
}
iterator = g_slist_next (iterator);
}
if (start)
*start = NULL;
return found;
}
static NMActiveConnection *
find_active_connection (const GPtrArray *active_cons,
const GSList *cons,
@ -1405,7 +1355,7 @@ do_connections_show (NmCli *nmc, gboolean active_only, int argc, char **argv)
}
/* Find connection by id, uuid, path or apath */
con = find_connection (nmc->system_connections, selector, *argv, &pos);
con = nmc_find_connection (nmc->system_connections, selector, *argv, &pos);
if (!con) {
acon = find_active_connection (active_cons, nmc->system_connections, selector, *argv, NULL);
if (acon)
@ -2012,7 +1962,7 @@ do_connection_up (NmCli *nmc, int argc, char **argv)
}
if (name)
connection = find_connection (nmc->system_connections, selector, name, NULL);
connection = nmc_find_connection (nmc->system_connections, selector, name, NULL);
while (argc > 0) {
if (strcmp (*argv, "ifname") == 0) {
@ -7812,7 +7762,7 @@ do_connection_edit (NmCli *nmc, int argc, char **argv)
/* Existing connection */
NMConnection *found_con;
found_con = find_connection (nmc->system_connections, selector, con, NULL);
found_con = nmc_find_connection (nmc->system_connections, selector, con, NULL);
if (!found_con) {
g_string_printf (nmc->return_text, _("Error: Unknown connection '%s'."), con);
nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
@ -8002,7 +7952,7 @@ do_connection_modify (NmCli *nmc,
nmc->return_value = NMC_RESULT_ERROR_USER_INPUT;
goto finish;
}
connection = find_connection (nmc->system_connections, selector, name, NULL);
connection = nmc_find_connection (nmc->system_connections, selector, name, NULL);
if (!connection) {
g_string_printf (nmc->return_text, _("Error: Unknown connection '%s'."), name);
nmc->return_value = NMC_RESULT_ERROR_NOT_FOUND;
@ -8218,7 +8168,7 @@ do_connection_delete (NmCli *nmc, int argc, char **argv)
}
}
connection = find_connection (nmc->system_connections, selector, *arg_ptr, &pos);
connection = nmc_find_connection (nmc->system_connections, selector, *arg_ptr, &pos);
if (!connection) {
if (nmc->print_output != NMC_PRINT_TERSE)
printf (_("Error: unknown connection: %s\n"), *arg_ptr);

View file

@ -16,7 +16,7 @@
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* (C) Copyright 2010 - 2012 Red Hat, Inc.
* (C) Copyright 2010 - 2014 Red Hat, Inc.
*/
/* Generated configuration file */
@ -47,6 +47,10 @@
# define NMCLI_VERSION VERSION
#endif
/* Global NmCli object */
// FIXME: Currently, we pass NmCli over in most APIs, but we might refactor
// that and use the global variable directly instead.
NmCli nm_cli;
typedef struct {
NmCli *nmc;
@ -406,8 +410,7 @@ start (gpointer data)
int
main (int argc, char *argv[])
{
NmCli nmc;
ArgsInfo args_info = { &nmc, argc, argv };
ArgsInfo args_info = { &nm_cli, argc, argv };
/* Set up unix signal handling */
if (!setup_signals ())
@ -425,19 +428,19 @@ main (int argc, char *argv[])
g_type_init ();
nmc_init (&nmc);
nmc_init (&nm_cli);
g_idle_add (start, &args_info);
loop = g_main_loop_new (NULL, FALSE); /* create main loop */
g_main_loop_run (loop); /* run main loop */
/* Print result descripting text */
if (nmc.return_value != NMC_RESULT_SUCCESS) {
fprintf (stderr, "%s\n", nmc.return_text->str);
if (nm_cli.return_value != NMC_RESULT_SUCCESS) {
fprintf (stderr, "%s\n", nm_cli.return_text->str);
}
g_main_loop_unref (loop);
nmc_cleanup (&nmc);
nmc_cleanup (&nm_cli);
return nmc.return_value;
return nm_cli.return_value;
}

View file

@ -1587,6 +1587,13 @@ typedef struct {
NmcPropertyOut2InFunc out2in_func; /* func converting property values from output to input format */
} NmcPropertyFuncs;
/*
* We need NmCli in some _set_property functions, and they aren't passed NmCli.
* So use the global variable.
*/
/* Global variable defined in nmcli.c */
extern NmCli nm_cli;
NMSetting *
nmc_setting_new_for_name (const char *name)
{
@ -2446,15 +2453,34 @@ DEFINE_ALLOWED_VAL_FUNC (nmc_property_con_allowed_slave_type, con_valid_slave_ty
static gboolean
nmc_property_connection_set_secondaries (NMSetting *setting, const char *prop, const char *val, GError **error)
{
char **strv = NULL;
NMConnection *con;
char **strv = NULL, **iter;
guint i = 0;
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
strv = nmc_strsplit_set (val, " \t,", 0);
if (!verify_string_list (strv, prop, nm_utils_is_uuid, error)) {
g_strfreev (strv);
return FALSE;
for (iter = strv; iter && *iter; iter++) {
if (**iter == '\0')
continue;
if (nm_utils_is_uuid (*iter)) {
con = nmc_find_connection (nm_cli.system_connections,
"uuid", *iter, NULL);
if (!con)
printf (_("Warning: %s is not an UUID of any existing connection profile\n"), *iter);
} else {
con = nmc_find_connection (nm_cli.system_connections,
"id", *iter, NULL);
if (!con) {
g_set_error (error, 1, 0, _("'%s' is not a name of any exiting profile"), *iter);
g_strfreev (strv);
return FALSE;
}
/* translate id to uuid */
g_free (*iter);
*iter = g_strdup (nm_connection_get_uuid (con));
}
}
while (strv && strv[i])
@ -2489,6 +2515,17 @@ DEFINE_REMOVER_INDEX_OR_VALUE (nmc_property_connection_remove_secondaries,
nm_setting_connection_remove_secondary,
_validate_and_remove_connection_secondary)
static const char *
nmc_property_connection_describe_secondaries (NMSetting *setting, const char *prop)
{
return _("Enter secondary connections that should be activated when this connection is\n"
"activated. Connections can be specified either by UUID or ID (name). nmcli\n"
"transparently translates names to UUIDs. Note that NetworkManager only supports\n"
"VPNs as secondary connections at the moment.\n"
"The items can be separated by commas or spaces.\n\n"
"Example: private-openvpn, fe6ba5d8-c2fc-4aae-b2e3-97efddd8d9a7\n");
}
/* --- NM_SETTING_802_1X_SETTING_NAME property setter functions --- */
#define DEFINE_SETTER_STR_LIST(def_func, set_func) \
static gboolean \
@ -5051,7 +5088,7 @@ nmc_properties_init (void)
nmc_property_connection_get_secondaries,
nmc_property_connection_set_secondaries,
nmc_property_connection_remove_secondaries,
NULL,
nmc_property_connection_describe_secondaries,
NULL,
NULL);
nmc_add_prop_funcs (GLUE (CONNECTION, GATEWAY_PING_TIMEOUT),