Mini Shell
"""
Module for gathering and managing bridging information
"""
import re
import sys
import salt.utils.path
__func_alias__ = {"list_": "list"}
# Other BSD-like derivatives that use ifconfig may work too
SUPPORTED_BSD_LIKE = ["FreeBSD", "NetBSD", "OpenBSD"]
def __virtual__():
"""
Confirm this module is supported by the OS and the system has
required tools
"""
supported_os_tool = {
"FreeBSD": "ifconfig",
"Linux": "brctl",
"NetBSD": "brconfig",
"OpenBSD": "ifconfig",
}
cur_os = __grains__["kernel"]
for _os in supported_os_tool:
if cur_os == _os and salt.utils.path.which(supported_os_tool[cur_os]):
return True
return (
False,
"The bridge execution module failed to load: requires one of the following"
" tool/os combinations: ifconfig on FreeBSD/OpenBSD, brctl on Linux or brconfig"
" on NetBSD.",
)
def _tool_path(ostool):
"""
Internal, returns tools path
"""
return salt.utils.path.which(ostool)
def _linux_brshow(br=None):
"""
Internal, returns bridges and enslaved interfaces (GNU/Linux - brctl)
"""
brctl = _tool_path("brctl")
if br:
cmd = f"{brctl} show {br}"
else:
cmd = f"{brctl} show"
brs = {}
for line in __salt__["cmd.run"](cmd, python_shell=False).splitlines():
# get rid of first line
if line.startswith("bridge name"):
continue
# get rid of ^\n's
vals = line.split()
if not vals:
continue
# bridge name bridge id STP enabled interfaces
# br0 8000.e4115bac8ddc no eth0
# foo0
# br1 8000.e4115bac8ddc no eth1
if len(vals) > 1:
brname = vals[0]
brs[brname] = {
"id": vals[1],
"stp": vals[2],
}
if len(vals) > 3:
brs[brname]["interfaces"] = [vals[3]]
if len(vals) == 1 and brname:
brs[brname]["interfaces"].append(vals[0])
if br:
try:
return brs[br]
except KeyError:
return None
return brs
def _linux_bradd(br):
"""
Internal, creates the bridge
"""
brctl = _tool_path("brctl")
return __salt__["cmd.run"](f"{brctl} addbr {br}", python_shell=False)
def _linux_brdel(br):
"""
Internal, deletes the bridge
"""
brctl = _tool_path("brctl")
return __salt__["cmd.run"](f"{brctl} delbr {br}", python_shell=False)
def _linux_addif(br, iface):
"""
Internal, adds an interface to a bridge
"""
brctl = _tool_path("brctl")
return __salt__["cmd.run"](f"{brctl} addif {br} {iface}", python_shell=False)
def _linux_delif(br, iface):
"""
Internal, removes an interface from a bridge
"""
brctl = _tool_path("brctl")
return __salt__["cmd.run"](f"{brctl} delif {br} {iface}", python_shell=False)
def _linux_stp(br, state):
"""
Internal, sets STP state
"""
brctl = _tool_path("brctl")
return __salt__["cmd.run"](f"{brctl} stp {br} {state}", python_shell=False)
def _bsd_brshow(br=None):
"""
Internal, returns bridges and member interfaces (BSD-like: ifconfig)
"""
if __grains__["kernel"] == "NetBSD":
return _netbsd_brshow(br)
ifconfig = _tool_path("ifconfig")
ifaces = {}
if br:
ifaces[br] = br
else:
cmd = f"{ifconfig} -g bridge"
for line in __salt__["cmd.run"](cmd, python_shell=False).splitlines():
ifaces[line] = line
brs = {}
for iface in ifaces:
cmd = f"{ifconfig} {iface}"
for line in __salt__["cmd.run"](cmd, python_shell=False).splitlines():
brs[iface] = {"interfaces": [], "stp": "no"}
line = line.lstrip()
if line.startswith("member:"):
brs[iface]["interfaces"].append(line.split(" ")[1])
if "STP" in line:
brs[iface]["stp"] = "yes"
if br:
return brs[br]
return brs
def _netbsd_brshow(br=None):
"""
Internal, returns bridges and enslaved interfaces (NetBSD - brconfig)
"""
brconfig = _tool_path("brconfig")
if br:
cmd = f"{brconfig} {br}"
else:
cmd = f"{brconfig} -a"
brs = {}
start_int = False
for line in __salt__["cmd.run"](cmd, python_shell=False).splitlines():
if line.startswith("bridge"):
start_int = False
brname = line.split(":")[0] # on NetBSD, always ^bridge([0-9]+):
brs[brname] = {"interfaces": [], "stp": "no"}
if "Interfaces:" in line:
start_int = True
continue
if start_int and brname:
m = re.match(r"\s*([a-z0-9]+)\s.*<.*>", line)
if m:
brs[brname]["interfaces"].append(m.group(1))
if "STP" in line:
brs[brname]["stp"] = "yes"
if br:
try:
return brs[br]
except KeyError:
return None
return brs
def _bsd_bradd(br):
"""
Internal, creates the bridge
"""
kernel = __grains__["kernel"]
ifconfig = _tool_path("ifconfig")
if not br:
return False
if __salt__["cmd.retcode"](f"{ifconfig} {br} create up", python_shell=False) != 0:
return False
# NetBSD is two cmds
if kernel == "NetBSD":
brconfig = _tool_path("brconfig")
if __salt__["cmd.retcode"](f"{brconfig} {br} up", python_shell=False) != 0:
return False
return True
def _bsd_brdel(br):
"""
Internal, deletes the bridge
"""
ifconfig = _tool_path("ifconfig")
if not br:
return False
return __salt__["cmd.run"](f"{ifconfig} {br} destroy", python_shell=False)
def _bsd_addif(br, iface):
"""
Internal, adds an interface to a bridge
"""
kernel = __grains__["kernel"]
if kernel == "NetBSD":
cmd = _tool_path("brconfig")
brcmd = "add"
else:
cmd = _tool_path("ifconfig")
brcmd = "addem"
if not br or not iface:
return False
return __salt__["cmd.run"](f"{cmd} {br} {brcmd} {iface}", python_shell=False)
def _bsd_delif(br, iface):
"""
Internal, removes an interface from a bridge
"""
kernel = __grains__["kernel"]
if kernel == "NetBSD":
cmd = _tool_path("brconfig")
brcmd = "delete"
else:
cmd = _tool_path("ifconfig")
brcmd = "deletem"
if not br or not iface:
return False
return __salt__["cmd.run"](f"{cmd} {br} {brcmd} {iface}", python_shell=False)
def _bsd_stp(br, state, iface):
"""
Internal, sets STP state. On BSD-like, it is required to specify the
STP physical interface
"""
kernel = __grains__["kernel"]
if kernel == "NetBSD":
cmd = _tool_path("brconfig")
else:
cmd = _tool_path("ifconfig")
if not br or not iface:
return False
return __salt__["cmd.run"](f"{cmd} {br} {state} {iface}", python_shell=False)
def _os_dispatch(func, *args, **kwargs):
"""
Internal, dispatches functions by operating system
"""
if __grains__["kernel"] in SUPPORTED_BSD_LIKE:
kernel = "bsd"
else:
kernel = __grains__["kernel"].lower()
_os_func = getattr(sys.modules[__name__], f"_{kernel}_{func}")
if callable(_os_func):
return _os_func(*args, **kwargs)
# End of internal functions
def show(br=None):
"""
Returns bridges interfaces along with enslaved physical interfaces. If
no interface is given, all bridges are shown, else only the specified
bridge values are returned.
CLI Example:
.. code-block:: bash
salt '*' bridge.show
salt '*' bridge.show br0
"""
return _os_dispatch("brshow", br)
def list_():
"""
Returns the machine's bridges list
CLI Example:
.. code-block:: bash
salt '*' bridge.list
"""
brs = _os_dispatch("brshow")
if not brs:
return None
brlist = []
for br in brs:
brlist.append(br)
return brlist
def interfaces(br=None):
"""
Returns interfaces attached to a bridge
CLI Example:
.. code-block:: bash
salt '*' bridge.interfaces br0
"""
if not br:
return None
br_ret = _os_dispatch("brshow", br)
if br_ret:
return br_ret["interfaces"]
def find_interfaces(*args):
"""
Returns the bridge to which the interfaces are bond to
CLI Example:
.. code-block:: bash
salt '*' bridge.find_interfaces eth0 [eth1...]
"""
brs = _os_dispatch("brshow")
if not brs:
return None
iflist = {}
for iface in args:
for br in brs:
try: # a bridge may not contain interfaces
if iface in brs[br]["interfaces"]:
iflist[iface] = br
except Exception: # pylint: disable=broad-except
pass
return iflist
def add(br=None):
"""
Creates a bridge
CLI Example:
.. code-block:: bash
salt '*' bridge.add br0
"""
return _os_dispatch("bradd", br)
def delete(br=None):
"""
Deletes a bridge
CLI Example:
.. code-block:: bash
salt '*' bridge.delete br0
"""
return _os_dispatch("brdel", br)
def addif(br=None, iface=None):
"""
Adds an interface to a bridge
CLI Example:
.. code-block:: bash
salt '*' bridge.addif br0 eth0
"""
return _os_dispatch("addif", br, iface)
def delif(br=None, iface=None):
"""
Removes an interface from a bridge
CLI Example:
.. code-block:: bash
salt '*' bridge.delif br0 eth0
"""
return _os_dispatch("delif", br, iface)
def stp(br=None, state="disable", iface=None):
"""
Sets Spanning Tree Protocol state for a bridge
CLI Example:
.. code-block:: bash
salt '*' bridge.stp br0 enable
salt '*' bridge.stp br0 disable
For BSD-like operating systems, it is required to add the interface on
which to enable the STP.
CLI Example:
.. code-block:: bash
salt '*' bridge.stp bridge0 enable fxp0
salt '*' bridge.stp bridge0 disable fxp0
"""
kernel = __grains__["kernel"]
if kernel == "Linux":
states = {"enable": "on", "disable": "off"}
return _os_dispatch("stp", br, states[state])
elif kernel in SUPPORTED_BSD_LIKE:
states = {"enable": "stp", "disable": "-stp"}
return _os_dispatch("stp", br, states[state], iface)
else:
return False
Zerion Mini Shell 1.0