team: normalize invalid configuration during load

Now that we validate the JSON syntax of a team/team-port
configuration, any existing connection with invalid JSON configuration
would fail to load and disappear upon upgrade. Instead, modify the
setting plugins to emit a warning but still load the connection with
empty configuration.
This commit is contained in:
Beniamino Galvani 2016-08-30 15:21:16 +02:00
parent 39ad134b0c
commit d6ec009afd
8 changed files with 118 additions and 3 deletions

View file

@ -326,4 +326,9 @@ gboolean _nm_setting_bond_option_supported (const char *option, NMBondMode mode)
gboolean _nm_utils_inet6_is_token (const struct in6_addr *in6addr); gboolean _nm_utils_inet6_is_token (const struct in6_addr *in6addr);
/***********************************************************/
gboolean _nm_utils_check_valid_json (const char *json, GError **error);
gboolean _nm_utils_team_config_equal (const char *conf1, const char *conf2, gboolean port);
#endif #endif

View file

@ -1167,6 +1167,24 @@ parity_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
g_object_set (setting, key, parity, NULL); g_object_set (setting, key, parity, NULL);
} }
static void
team_config_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
{
const char *setting_name = nm_setting_get_name (setting);
gs_free char *conf = NULL;
gs_free_error GError *error = NULL;
conf = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, key, NULL);
if (conf && conf[0] && !_nm_utils_check_valid_json (conf, &error)) {
handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
_("ignoring invalid team configuration: %s"),
error->message);
g_clear_pointer (&conf, g_free);
}
g_object_set (G_OBJECT (setting), key, conf, NULL);
}
typedef struct { typedef struct {
const char *setting_name; const char *setting_name;
const char *key; const char *key;
@ -1285,6 +1303,14 @@ static KeyParser key_parsers[] = {
NM_SETTING_SERIAL_PARITY, NM_SETTING_SERIAL_PARITY,
TRUE, TRUE,
parity_parser }, parity_parser },
{ NM_SETTING_TEAM_SETTING_NAME,
NM_SETTING_TEAM_CONFIG,
TRUE,
team_config_parser },
{ NM_SETTING_TEAM_PORT_SETTING_NAME,
NM_SETTING_TEAM_CONFIG,
TRUE,
team_config_parser },
{ NULL, NULL, FALSE } { NULL, NULL, FALSE }
}; };

View file

@ -31,9 +31,6 @@
gboolean _nm_utils_string_slist_validate (GSList *list, gboolean _nm_utils_string_slist_validate (GSList *list,
const char **valid_values); const char **valid_values);
gboolean _nm_utils_check_valid_json (const char *json, GError **error);
gboolean _nm_utils_team_config_equal (const char *conf1, const char *conf2, gboolean port);
/* D-Bus transform funcs */ /* D-Bus transform funcs */
GVariant *_nm_utils_hwaddr_cloned_get (NMSetting *setting, GVariant *_nm_utils_hwaddr_cloned_get (NMSetting *setting,

View file

@ -27,6 +27,7 @@
#include "nm-setting-connection.h" #include "nm-setting-connection.h"
#include "nm-setting-wired.h" #include "nm-setting-wired.h"
#include "nm-setting-8021x.h" #include "nm-setting-8021x.h"
#include "nm-setting-team.h"
#include "nm-utils/nm-test-utils.h" #include "nm-utils/nm-test-utils.h"
@ -518,6 +519,52 @@ test_8021x_cert_read (void)
CLEAR (&con, &keyfile); CLEAR (&con, &keyfile);
} }
static void
test_team_conf_read_valid (void)
{
GKeyFile *keyfile = NULL;
gs_unref_object NMConnection *con = NULL;
NMSettingTeam *s_team;
con = nmtst_create_connection_from_keyfile (
"[connection]\n"
"type=team\n"
"interface-name=nm-team1\n"
"[team]\n"
"config={\"foo\":\"bar\"}",
"/test_team_conf_read/valid", NULL);
g_assert (con);
s_team = nm_connection_get_setting_team (con);
g_assert (s_team);
g_assert_cmpstr (nm_setting_team_get_config (s_team), ==, "{\"foo\":\"bar\"}");
CLEAR (&con, &keyfile);
}
static void
test_team_conf_read_invalid (void)
{
GKeyFile *keyfile = NULL;
gs_unref_object NMConnection *con = NULL;
NMSettingTeam *s_team;
con = nmtst_create_connection_from_keyfile (
"[connection]\n"
"type=team\n"
"interface-name=nm-team1\n"
"[team]\n"
"config={foobar}",
"/test_team_conf_read/invalid", NULL);
g_assert (con);
s_team = nm_connection_get_setting_team (con);
g_assert (s_team);
g_assert (nm_setting_team_get_config (s_team) == NULL);
CLEAR (&con, &keyfile);
}
/******************************************************************************/ /******************************************************************************/
NMTST_DEFINE (); NMTST_DEFINE ();
@ -528,6 +575,8 @@ int main (int argc, char **argv)
g_test_add_func ("/core/keyfile/test_8021x_cert", test_8021x_cert); g_test_add_func ("/core/keyfile/test_8021x_cert", test_8021x_cert);
g_test_add_func ("/core/keyfile/test_8021x_cert_read", test_8021x_cert_read); g_test_add_func ("/core/keyfile/test_8021x_cert_read", test_8021x_cert_read);
g_test_add_func ("/core/keyfile/test_team_conf_read/valid", test_team_conf_read_valid);
g_test_add_func ("/core/keyfile/test_team_conf_read/invalid", test_team_conf_read_invalid);
return g_test_run (); return g_test_run ();
} }

View file

@ -4238,6 +4238,7 @@ bond_connection_from_ifcfg (const char *file,
static char * static char *
read_team_config (shvarFile *ifcfg, const char *key, GError **error) read_team_config (shvarFile *ifcfg, const char *key, GError **error)
{ {
gs_free_error GError *local_error = NULL;
char *value; char *value;
size_t l; size_t l;
@ -4258,6 +4259,12 @@ read_team_config (shvarFile *ifcfg, const char *key, GError **error)
return NULL; return NULL;
} }
svUnescape (value); svUnescape (value);
if (value && value[0] && !_nm_utils_check_valid_json (value, &local_error)) {
PARSE_WARNING ("ignoring invalid team configuration: %s", local_error->message);
g_clear_pointer (&value, g_free);
}
return value; return value;
} }

View file

@ -134,6 +134,7 @@ EXTRA_DIST = \
ifcfg-test-fcoe-vn2vn \ ifcfg-test-fcoe-vn2vn \
ifcfg-test-team-master-1 \ ifcfg-test-team-master-1 \
ifcfg-test-team-master-2 \ ifcfg-test-team-master-2 \
ifcfg-test-team-master-invalid \
ifcfg-test-team-port-1 \ ifcfg-test-team-port-1 \
ifcfg-test-team-port-2 \ ifcfg-test-team-port-2 \
ifcfg-test-team-port-empty-config \ ifcfg-test-team-port-empty-config \

View file

@ -0,0 +1,4 @@
DEVICE=team0
ONBOOT=no
BOOTPROTO=dhcp
TEAM_CONFIG="{ foobar }"

View file

@ -8453,6 +8453,31 @@ test_read_team_master (gconstpointer user_data)
g_object_unref (connection); g_object_unref (connection);
} }
static void
test_read_team_master_invalid (gconstpointer user_data)
{
const char *const PATH_NAME = user_data;
NMConnection *connection;
NMSettingConnection *s_con;
NMSettingTeam *s_team;
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE, "*ignoring invalid team configuration*");
connection = _connection_from_file (PATH_NAME, NULL, TYPE_ETHERNET, NULL);
g_test_assert_expected_messages ();
g_assert_cmpstr (nm_connection_get_interface_name (connection), ==, "team0");
s_con = nm_connection_get_setting_connection (connection);
g_assert (s_con);
g_assert_cmpstr (nm_setting_connection_get_connection_type (s_con), ==, NM_SETTING_TEAM_SETTING_NAME);
s_team = nm_connection_get_setting_team (connection);
g_assert (s_team);
g_assert (nm_setting_team_get_config (s_team) == NULL);
g_object_unref (connection);
}
static void static void
test_write_team_master (void) test_write_team_master (void)
{ {
@ -9050,6 +9075,7 @@ int main (int argc, char **argv)
g_test_add_data_func (TPATH "team/read-master-1", TEST_IFCFG_DIR"/network-scripts/ifcfg-test-team-master-1", test_read_team_master); g_test_add_data_func (TPATH "team/read-master-1", TEST_IFCFG_DIR"/network-scripts/ifcfg-test-team-master-1", test_read_team_master);
g_test_add_data_func (TPATH "team/read-master-2", TEST_IFCFG_DIR"/network-scripts/ifcfg-test-team-master-2", test_read_team_master); g_test_add_data_func (TPATH "team/read-master-2", TEST_IFCFG_DIR"/network-scripts/ifcfg-test-team-master-2", test_read_team_master);
g_test_add_data_func (TPATH "team/read-master-invalid", TEST_IFCFG_DIR"/network-scripts/ifcfg-test-team-master-invalid", test_read_team_master_invalid);
g_test_add_func (TPATH "team/write-master", test_write_team_master); g_test_add_func (TPATH "team/write-master", test_write_team_master);
g_test_add_data_func (TPATH "team/read-port-1", TEST_IFCFG_DIR"/network-scripts/ifcfg-test-team-port-1", test_read_team_port); g_test_add_data_func (TPATH "team/read-port-1", TEST_IFCFG_DIR"/network-scripts/ifcfg-test-team-port-1", test_read_team_port);
g_test_add_data_func (TPATH "team/read-port-2", TEST_IFCFG_DIR"/network-scripts/ifcfg-test-team-port-2", test_read_team_port); g_test_add_data_func (TPATH "team/read-port-2", TEST_IFCFG_DIR"/network-scripts/ifcfg-test-team-port-2", test_read_team_port);