not sure why that from line is still showing up, its not in the patch file that i am sending. still looking into that. 

On Mon, Apr 20, 2020 at 2:25 PM <pgagne@redhat.com> wrote:
From: Perry Gagne <pgagne@redhat.com>

Team devices now are created with a config dict that gets converted to json when configuring them on the host.

Signed-off-by: Perry Gagne <pgagne@redhat.com>
---
 lnst/Devices/TeamDevice.py      | 54 ++++++++++++++++++---------------
 lnst/Recipes/ENRT/TeamRecipe.py |  7 ++---
 2 files changed, 32 insertions(+), 29 deletions(-)

diff --git a/lnst/Devices/TeamDevice.py b/lnst/Devices/TeamDevice.py
index 4f6eee5..fc05de4 100644
--- a/lnst/Devices/TeamDevice.py
+++ b/lnst/Devices/TeamDevice.py
@@ -9,44 +9,46 @@ published by the Free Software Foundation; see COPYING for details.
 __author__ = """
 olichtne@redhat.com (Ondrej Lichtner)
 """
-
-import re
+import json
 from lnst.Common.ExecCmd import exec_cmd
-from lnst.Common.Utils import bool_it
+from lnst.Common.DeviceError import DeviceError, DeviceConfigError
 from lnst.Devices.MasterDevice import MasterDevice

-def prepare_json_str(json_str):
-    if not json_str:
-        return "{}"
-    json_str = json_str.replace('"', '\\"')
-    json_str = re.sub('\s+', ' ', json_str)
-    return json_str

-#TODO rework with pyroute2? don't know how json and teamd works with that...
+# TODO Rework with pyroute2 if thats possible.
+# See https://github.com/svinota/pyroute2/issues/699#issuecomment-615367686
 class TeamDevice(MasterDevice):
     _name_template = "t_team"

     def __init__(self, ifmanager, *args, **kwargs):
+        self._config = {}
+        self._dbus = False
         super(TeamDevice, self).__init__(ifmanager, *args, **kwargs)

-        self._config = kwargs.get("config", None)
-        self._dbus = not bool_it(kwargs.get("disable_dbus", False))
-
     @property
     def config(self):
         return self._config

+    @config.setter
+    def config(self, v: dict):
+        if not isinstance(v, dict):
+            raise DeviceConfigError("team device config must be dict")
+        self._config = v
+
     @property
     def dbus(self):
         return self._dbus

-    def _create(self):
-        teamd_config = prepare_json_str(self.config)
+    @dbus.setter
+    def dbus(self, v: bool):
+        if not isinstance(v, bool):
+            raise DeviceConfigError("team dbus setting must be bool")
+        self._dbus = v

-        exec_cmd("teamd -r -d -c \"%s\" -t %s %s" %\
-                    (teamd_config,
-                     self.name,
-                     " -D" if self.dbus else ""))
+    def _create(self):
+        teamd_json = json.dumps(self.config)
+        exec_cmd(f"teamd -r -d -c '{teamd_json}' -t {self.name}"
+                 " -D" if self.dbus else "")

         retry = 0
         while self._nl_msg is None and retry < 5:
@@ -56,11 +58,13 @@ class TeamDevice(MasterDevice):
     def destroy(self):
         exec_cmd("teamd -k -t %s" % self.name)

-    def slave_add(self, dev, port_config=None):
-        exec_cmd("teamdctl %s %s port config update %s \"%s\"" %\
-                    (" -D" if self.dbus else "",
-                     self.name,
-                     dev.name,
-                     prepare_json_str(port_config)))
+    def slave_add(self, dev, port_config={}):
+        if not isinstance(port_config, dict):
+            raise DeviceConfigError(f"team link {dev.name} port config must be dict")
+
+        port_json = json.dumps(port_config)
+        opts = "-D" if self.dbus else ""
+        exec_cmd(f"teamdctl {opts} {self.name} port config "
+                 f"update {dev.name} '{port_json}'")

         dev.master = self
diff --git a/lnst/Recipes/ENRT/TeamRecipe.py b/lnst/Recipes/ENRT/TeamRecipe.py
index e083b90..e97a10b 100644
--- a/lnst/Recipes/ENRT/TeamRecipe.py
+++ b/lnst/Recipes/ENRT/TeamRecipe.py
@@ -9,6 +9,7 @@ from lnst.Recipes.ENRT.ConfigMixins.CommonHWSubConfigMixin import (
 from lnst.RecipeCommon.Ping.PingEndpoints import PingEndpoints
 from lnst.Devices import TeamDevice

+
 class TeamRecipe(CommonHWSubConfigMixin, OffloadSubConfigMixin,
     BaseEnrtRecipe):
     host1 = HostReq()
@@ -30,10 +31,8 @@ class TeamRecipe(CommonHWSubConfigMixin, OffloadSubConfigMixin,
     def test_wide_configuration(self):
         host1, host2 = self.matched.host1, self.matched.host2

-        #The config argument needs to be used with a team device normally
-        #(e.g  to specify the runner mode), but it is not used here due to
-        #a bug in the TeamDevice module
-        host1.team0 = TeamDevice()
+        teamd_config = {'runner': {'name': self.params.runner_name}}
+        host1.team0 = TeamDevice(config=teamd_config)

         configuration = super().test_wide_configuration()
         configuration.test_wide_devices = [host1.team0, host2.eth0]
--
2.21.1