team: Fix failure of creating team interface with slaves
Got failure when creating team interface with slaves caused by: * When create setting, the `create_setting()` of `nm/team.py` altered the data layout which trigger failure in `merge_interfaces` at the verification stage. * The slave interface does not set `connection.master` and `connection.slave-type`. Fixed and also added integration test to assert on the run time status of team interface. Signed-off-by: Gris Ge <fge@redhat.com>
This commit is contained in:
parent
57c980aca5
commit
4ff6ffedf1
27
libnmstate/appliers/team.py
Normal file
27
libnmstate/appliers/team.py
Normal file
@ -0,0 +1,27 @@
|
||||
#
|
||||
# Copyright (c) 2020 Red Hat, Inc.
|
||||
#
|
||||
# This file is part of nmstate
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published by
|
||||
# the Free Software Foundation, either version 2.1 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
from libnmstate.schema import Team
|
||||
|
||||
|
||||
def get_slaves_from_state(state, default=()):
|
||||
ports = state.get(Team.CONFIG_SUBTREE, {}).get(Team.PORT_SUBTREE)
|
||||
if ports is None:
|
||||
return default
|
||||
return [p[Team.Port.NAME] for p in ports]
|
@ -21,6 +21,7 @@ from libnmstate import iplib
|
||||
from libnmstate.appliers import linux_bridge
|
||||
from libnmstate.appliers import ovs_bridge
|
||||
from libnmstate.appliers import bond
|
||||
from libnmstate.appliers import team
|
||||
from libnmstate.error import NmstateValueError
|
||||
from libnmstate import nm
|
||||
from libnmstate.schema import DNS
|
||||
@ -73,6 +74,13 @@ def generate_ifaces_metadata(desired_state, current_state):
|
||||
get_slaves_func=linux_bridge.get_slaves_from_state,
|
||||
set_metadata_func=linux_bridge.set_bridge_ports_metadata,
|
||||
)
|
||||
_generate_link_master_metadata(
|
||||
desired_state.interfaces,
|
||||
current_state.interfaces,
|
||||
master_type=InterfaceType.TEAM,
|
||||
get_slaves_func=team.get_slaves_from_state,
|
||||
set_metadata_func=lambda *args: None,
|
||||
)
|
||||
_generate_dns_metadata(desired_state, current_state)
|
||||
_generate_route_metadata(desired_state, current_state)
|
||||
_generate_route_rule_metadata(desired_state)
|
||||
|
@ -17,6 +17,7 @@
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
|
||||
import copy
|
||||
import json
|
||||
|
||||
from libnmstate.nm import connection as nm_connection
|
||||
@ -59,6 +60,7 @@ def create_setting(iface_state, base_con_profile):
|
||||
|
||||
|
||||
def _convert_team_config_to_teamd_format(team_config, ifname):
|
||||
team_config = copy.deepcopy(team_config)
|
||||
team_config[TEAMD_JSON_DEVICE] = ifname
|
||||
|
||||
team_ports = team_config.get(Team.PORT_SUBTREE, ())
|
||||
|
@ -18,22 +18,28 @@
|
||||
#
|
||||
|
||||
from contextlib import contextmanager
|
||||
import json
|
||||
import os
|
||||
|
||||
import pytest
|
||||
|
||||
import libnmstate
|
||||
from libnmstate.error import NmstateDependencyError
|
||||
from libnmstate.error import NmstateLibnmError
|
||||
from libnmstate.schema import Interface
|
||||
from libnmstate.schema import InterfaceState
|
||||
from libnmstate.schema import InterfaceType
|
||||
from libnmstate.schema import Team
|
||||
|
||||
from .testlib import assertlib
|
||||
from .testlib.cmdlib import exec_cmd
|
||||
from .testlib.cmdlib import RC_SUCCESS
|
||||
from .testlib.nmplugin import disable_nm_plugin
|
||||
|
||||
|
||||
TEAM0 = "team0"
|
||||
PORT1 = "eth1"
|
||||
PORT2 = "eth2"
|
||||
|
||||
|
||||
pytestmark = pytest.mark.skipif(
|
||||
@ -42,13 +48,27 @@ pytestmark = pytest.mark.skipif(
|
||||
)
|
||||
|
||||
|
||||
@pytest.mark.xfail(reason="https://bugzilla.redhat.com/1798947")
|
||||
def test_create_team_iface():
|
||||
@pytest.mark.xfail(
|
||||
raises=NmstateLibnmError, reason="https://bugzilla.redhat.com/1798947"
|
||||
)
|
||||
def test_create_team_iface_without_slaves():
|
||||
with team_interface(TEAM0) as team_state:
|
||||
assertlib.assert_state(team_state)
|
||||
|
||||
|
||||
@pytest.mark.xfail(reason="https://bugzilla.redhat.com/1798947")
|
||||
@pytest.mark.xfail(
|
||||
raises=NmstateLibnmError, reason="https://bugzilla.redhat.com/1798947"
|
||||
)
|
||||
def test_create_team_iface_with_slaves():
|
||||
with team_interface(TEAM0, [PORT1, PORT2]) as team_state:
|
||||
assertlib.assert_state(team_state)
|
||||
assert [PORT1, PORT2] == _get_runtime_team_slaves(TEAM0)
|
||||
assertlib.assert_absent(TEAM0)
|
||||
|
||||
|
||||
@pytest.mark.xfail(
|
||||
raises=NmstateLibnmError, reason="https://bugzilla.redhat.com/1798947"
|
||||
)
|
||||
def test_edit_team_iface():
|
||||
with team_interface(TEAM0) as team_state:
|
||||
team_state[Interface.KEY][0][Team.CONFIG_SUBTREE] = {
|
||||
@ -78,7 +98,7 @@ def test_nm_team_plugin_missing():
|
||||
|
||||
|
||||
@contextmanager
|
||||
def team_interface(ifname):
|
||||
def team_interface(ifname, slaves=None):
|
||||
desired_state = {
|
||||
Interface.KEY: [
|
||||
{
|
||||
@ -88,6 +108,11 @@ def team_interface(ifname):
|
||||
}
|
||||
]
|
||||
}
|
||||
if slaves:
|
||||
team_state = {Team.PORT_SUBTREE: []}
|
||||
desired_state[Interface.KEY][0][Team.CONFIG_SUBTREE] = team_state
|
||||
for slave in slaves:
|
||||
team_state[Team.PORT_SUBTREE].append({Team.Port.NAME: slave})
|
||||
libnmstate.apply(desired_state)
|
||||
try:
|
||||
yield desired_state
|
||||
@ -102,3 +127,13 @@ def team_interface(ifname):
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
def _get_runtime_team_slaves(team_iface_name):
|
||||
"""
|
||||
Use `teamdctl team0 state dump` to check team runtime status
|
||||
"""
|
||||
rc, output, _ = exec_cmd(f"teamdctl {team_iface_name} state dump".split())
|
||||
assert rc == RC_SUCCESS
|
||||
teamd_state = json.loads(output)
|
||||
return sorted(teamd_state.get("ports", {}).keys())
|
||||
|
Loading…
x
Reference in New Issue
Block a user