From: Jiri Pirko jiri@mellanox.com
if_id is for interface id, iface is for InterfaceAPI objects, interface is for Interface object
Signed-off-by: Jiri Pirko jiri@mellanox.com --- lnst/Controller/Task.py | 54 ++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 27 deletions(-)
diff --git a/lnst/Controller/Task.py b/lnst/Controller/Task.py index 673048d..242d046 100644 --- a/lnst/Controller/Task.py +++ b/lnst/Controller/Task.py @@ -171,11 +171,11 @@ class HostAPI(object): self._id = host_id self._m = host
- self._interfaces = {} - for i in self._m.get_interfaces(): - if i.get_id() is None: + self._ifaces = {} + for interface in self._m.get_interfaces(): + if interface.get_id() is None: continue - self._interfaces[i.get_id()] = InterfaceAPI(i, self) + self._ifaces[interface.get_id()] = InterfaceAPI(interface, self)
self._bg_id_seq = 0
@@ -274,72 +274,72 @@ class HostAPI(object): return ProcessAPI(self._ctl, self._id, cmd_res, bg_id, cmd["netns"])
def get_interfaces(self): - return self._interfaces + return self._ifaces
- def get_interface(self, interface_id): - return self._interfaces[interface_id] + def get_interface(self, if_id): + return self._ifaces[if_id]
@deprecated - def get_devname(self, interface_id): + def get_devname(self, if_id): """ Returns devname of the interface.
- :param interface_id: which interface - :type interface_id: string + :param if_id: which interface + :type if_id: string
:return: Device name (e.g., eth0). :rtype: str """ - iface = self._interfaces[interface_id] + iface = self._ifaces[if_id] return iface.get_devname()
@deprecated - def get_hwaddr(self, interface_id): + def get_hwaddr(self, if_id): """ Returns hwaddr of the interface.
- :param interface_id: which interface - :type interface_id: string + :param if_id: which interface + :type if_id: string
:return: HW address (e.g., 00:11:22:33:44:55:FF). :rtype: str """ - iface = self._interfaces[interface_id] + iface = self._ifaces[if_id] return iface.get_hwaddr()
@deprecated - def get_ip(self, interface_id, addr_number=0): + def get_ip(self, if_id, addr_number=0): """ Returns an IP address of the interface.
- :param interface_id: which interface - :type interface_id: string + :param if_id: which interface + :type if_id: string
- :param interface_id: which address - :type interface_id: int + :param addr_number: which address + :type addr_number: int
:return: IP address (e.g., 192.168.1.10). :rtype: str """ - iface = self._interfaces[interface_id] + iface = self._ifaces[if_id] return iface.get_ip_addr(addr_number)
@deprecated - def get_prefix(self, interface_id, addr_number=0): + def get_prefix(self, if_id, addr_number=0): """ Returns an IP address prefix (netmask) of the interface.
- :param interface_id: which interface - :type interface_id: string + :param if_id: which interface + :type if_id: string
- :param interface_id: which address - :type interface_id: int + :param addr_number: which address + :type addr_number: int
:return: netmask (e.g., 24). :rtype: str """ - iface = self._interfaces[interface_id] + iface = self._ifaces[if_id] return iface.get_ip_prefix(addr_number)
def sync_resources(self, modules=[], tools=[]):
From: Jiri Pirko jiri@mellanox.com
In prepare_json_str, just return valid empty JSON string then no config is set.
Signed-off-by: Jiri Pirko jiri@mellanox.com --- lnst/Slave/NetConfigDevice.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/lnst/Slave/NetConfigDevice.py b/lnst/Slave/NetConfigDevice.py index 85eef7f..809c0c5 100644 --- a/lnst/Slave/NetConfigDevice.py +++ b/lnst/Slave/NetConfigDevice.py @@ -283,7 +283,7 @@ class NetConfigDeviceVlan(NetConfigDeviceGeneric):
def prepare_json_str(json_str): if not json_str: - return "" + return "{}" json_str = json_str.replace('"', '\"') json_str = re.sub('\s+', ' ', json_str) return json_str
From: Jiri Pirko jiri@mellanox.com
If caller wants to create an Interface instance and does not care about id, generate some.
Signed-off-by: Jiri Pirko jiri@mellanox.com --- lnst/Controller/Machine.py | 26 +++++++++++++++++++++----- 1 file changed, 21 insertions(+), 5 deletions(-)
diff --git a/lnst/Controller/Machine.py b/lnst/Controller/Machine.py index 2ed6363..a6256e6 100644 --- a/lnst/Controller/Machine.py +++ b/lnst/Controller/Machine.py @@ -81,13 +81,29 @@ class Machine(object): configuration["interface_"+i.get_id()] = i.get_config() return configuration
+ def _if_id_exists(self, if_id): + for iface in self._interfaces: + if if_id == iface.get_id(): + return True + return False + + def _generate_if_id(self, if_type): + i = 0 + while True: + if_id = "gen_%s_%d" % (if_type, i) + if not self._if_id_exists(if_id): + break + i += 1 + return if_id + def _add_interface(self, if_id, if_type, cls): if if_id != None: - for iface in self._interfaces: - if if_id == iface.get_id(): - msg = "Interface '%s' already exists on machine '%s'" \ - % (if_id, self._id) - raise MachineError(msg) + if self._if_id_exists(if_id): + msg = "Interface '%s' already exists on machine '%s'" \ + % (if_id, self._id) + raise MachineError(msg) + else: + if_id = self._generate_if_id(if_type)
iface = cls(self, if_id, if_type) self._interfaces.append(iface)
From: Jiri Pirko jiri@mellanox.com
Signed-off-by: Jiri Pirko jiri@mellanox.com --- lnst/Controller/Machine.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/lnst/Controller/Machine.py b/lnst/Controller/Machine.py index a6256e6..dbf71c3 100644 --- a/lnst/Controller/Machine.py +++ b/lnst/Controller/Machine.py @@ -627,7 +627,11 @@ class Interface(object): self._slave_options[slave_id].append((name, value))
def add_address(self, addr): - self._addresses.append(addr) + if (type(addr) == type([])): + for one_addr in addr: + self._addresses.append(one_addr) + else: + self._addresses.append(addr)
def get_address(self, num): return self._addresses[num].split('/')[0]
From: Jiri Pirko jiri@mellanox.com
This patch allows LNST tasks to create on-fly soft-devices. So far, bridge, bonds, teams and vlans are supported. It is easy to extend this to all devices supported by LNST.
This allows user to define machine network config in Task like in following example:
------------------------------------------------------------------------------- from lnst.Controller.Task import ctl
m1 = ctl.get_host("machine1") if1 = m1.get_interface("if1") if2 = m1.get_interface("if2") if3 = m1.get_interface("if3") if4 = m1.get_interface("if4")
team_config = '{"runner" : {"name" : "lacp"}}' team_if1_config = '{"prio": 11}' team = m1.create_team(slaves=[(if1, team_if1_config), if2], config=team_config)
br = m1.create_bridge(slaves=[if3, team], options={"stp_state": 0}) vlan = m1.create_vlan(br, 100, ip="192.168.1.1/24")
if4.reset(ip="192.168.2.1/24") -------------------------------------------------------------------------------
As you can see, it is quite easy and intuitive.
Next step is to allow device destruction in Tasks. Should be quite easy to implement as well. That would allow on-fly change of network configuration for running tasks.
This allows to reduce LNST xml recipes to just plain definition of physical devices used for match. Next step is to allow to do this definition of physical devices in so-called python-recipe. That would allow user to use pure-python LNST recipes and tasks. Cool, isn't it?
Signed-off-by: Jiri Pirko jiri@mellanox.com --- lnst/Controller/Task.py | 74 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 74 insertions(+)
diff --git a/lnst/Controller/Task.py b/lnst/Controller/Task.py index 242d046..8670150 100644 --- a/lnst/Controller/Task.py +++ b/lnst/Controller/Task.py @@ -363,6 +363,67 @@ class HostAPI(object):
self._m.sync_resources(sync_table)
+ def _add_iface(self, if_type, if_id, netns, ip, options, slaves): + interface = self._m.new_soft_interface(if_id, if_type) + iface = InterfaceAPI(interface, self) + self._ifaces[if_id] = iface + + if slaves: + for slave in slaves: + if type(slave) == type(()): + slave_iface = slave[0] + slave_options = slave[1] + for key in slave_options: + interface.set_slave_option(slave_iface.get_id(), + key, slave_options[key]) + else: + slave_iface = slave + interface.add_slave(slave_iface._if) + + if ip: + interface.add_address(ip) + + if options: + for key in options: + interface.set_option(key, options[key]) + + if netns: + interface.set_netns(netns) + + interface.configure() + interface.up() + return iface + + def create_bond(self, if_id=None, netns=None, ip=None, + options=None, slaves=None): + return self._add_iface("bond", if_id, netns, ip, options, slaves) + + def create_bridge(self, if_id=None, netns=None, ip=None, + options=None, slaves=None): + return self._add_iface("bridge", if_id, netns, ip, options, slaves) + + def create_team(self, config=None, if_id=None, netns=None, ip=None, + slaves=None): + out_slaves = [] + for slave in slaves: + if type(slave) == type(()): + slave_iface = slave[0] + slave_config = slave[1] + out_slaves.append((slave_iface, + {"teamd_port_config": slave_config})) + else: + out_slaves.append(slave) + + options = {} + if config: + options["teamd_config"] = config + + return self._add_iface("team", if_id, netns, ip, options, out_slaves) + + def create_vlan(self, realdev_iface, vlan_tci, if_id=None, netns=None, ip=None): + return self._add_iface("vlan", if_id, netns, ip, {"vlan_tci": vlan_tci}, + [realdev_iface]) + class InterfaceAPI(object): def __init__(self, interface, host): self._if = interface @@ -422,6 +483,19 @@ class InterfaceAPI(object): def get_host(self): return self._host
+ def reset(self, ip=None, netns=None): + self._if.down() + self._if.deconfigure() + + if ip: + self._if.add_address(ip) + + if netns: + self._if.set_netns(netns) + + self._if.configure() + self._if.up() + class ModuleAPI(object): """ An API class representing a module. """
lnst-developers@lists.fedorahosted.org