initial effort to remove swallowing exceptions within internal code

This commit is contained in:
Blake J. Harnden 2018-03-02 13:39:44 -08:00
parent a3356127d2
commit 43554cbb62
10 changed files with 423 additions and 399 deletions

View file

@ -37,9 +37,9 @@ class Position(object):
"""
Returns True if the position has actually changed.
:param x: x position
:param y: y position
:param z: z position
:param float x: x position
:param float y: y position
:param float z: z position
:return: True if position changed, False otherwise
:rtype: bool
"""
@ -113,9 +113,9 @@ class PyCoreObj(object):
"""
Set the (x,y,z) position of the object.
:param x: x position
:param y: y position
:param z: z position
:param float x: x position
:param float y: y position
:param float z: z position
:return: True if position changed, False otherwise
:rtype: bool
"""
@ -460,6 +460,22 @@ class PyCoreNet(PyCoreObj):
"""
linktype = LinkTypes.WIRED.value
def startup(self):
"""
Each object implements its own startup method.
:return: nothing
"""
raise NotImplementedError
def shutdown(self):
"""
Each object implements its own shutdown method.
:return: nothing
"""
raise NotImplementedError
def __init__(self, session, objid, name, start=True):
"""
Create a PyCoreNet instance.
@ -597,7 +613,7 @@ class PyCoreNetIf(object):
"""
Creates a PyCoreNetIf instance.
:param core.netns.vnode.SimpleLxcNode node: node for interface
:param core.coreobj.PyCoreNode node: node for interface
:param str name: interface name
:param mtu: mtu value
"""

View file

@ -21,31 +21,30 @@ def emane_version():
"""
global VERSION
global VERSIONSTR
args = ("emane", "--version")
try:
status, result = utils.check_cmd(args)
except subprocess.CalledProcessError:
logger.exception("error checking emane version")
status = -1
result = ""
args = ["emane", "--version"]
VERSION = EMANEUNK
if status == 0:
if result.startswith("0.7.4"):
VERSION = EMANE074
elif result.startswith("0.8.1"):
VERSION = EMANE081
elif result.startswith("0.9.1"):
VERSION = EMANE091
elif result.startswith("0.9.2"):
VERSION = EMANE092
elif result.startswith("0.9.3"):
VERSION = EMANE093
elif result.startswith("1.0.1"):
VERSION = EMANE101
VERSIONSTR = result.strip()
try:
status, output = utils.check_cmd(args)
if status == 0:
if output.startswith("0.7.4"):
VERSION = EMANE074
elif output.startswith("0.8.1"):
VERSION = EMANE081
elif output.startswith("0.9.1"):
VERSION = EMANE091
elif output.startswith("0.9.2"):
VERSION = EMANE092
elif output.startswith("0.9.3"):
VERSION = EMANE093
elif output.startswith("1.0.1"):
VERSION = EMANE101
except subprocess.CalledProcessError:
logger.exception("error checking emane version")
output = ""
VERSIONSTR = output.strip()
# set version variables for the Emane class

View file

@ -925,7 +925,8 @@ class EmaneManager(ConfigurableManager):
logger.exception("error adding route for event data")
try:
args = emanecmd + ["-f", os.path.join(path, "emane%d.log" % n), os.path.join(path, "platform%d.xml" % n)]
args = emanecmd + ["-f", os.path.join(path, "emane%d.log" % n),
os.path.join(path, "platform%d.xml" % n)]
logger.info("Emane.startdaemons2() running %s" % str(args))
status, output = node.check_cmd(args)
logger.info("Emane.startdaemons2() return code %d" % status)
@ -1163,14 +1164,15 @@ class EmaneManager(ConfigurableManager):
Return True if an EMANE process associated with the given node
is running, False otherwise.
"""
status = -1
args = ["pkill", "-0", "-x", "emane"]
status = -1
try:
if emane.VERSION < emane.EMANE092:
status = utils.check_cmd(args)
utils.check_cmd(args)
else:
status, _ = node.check_cmd(args)
node.check_cmd(args)
status = 0
except subprocess.CalledProcessError:
logger.exception("error checking if emane is running")

View file

@ -199,7 +199,7 @@ def cmd_output(args):
p = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
stdout, _ = p.communicate()
status = p.wait()
return status, stdout
return status, stdout.strip()
except OSError:
raise subprocess.CalledProcessError(-1, args)
@ -222,9 +222,9 @@ def check_cmd(args, **kwargs):
p = subprocess.Popen(args, **kwargs)
stdout, _ = p.communicate()
status = p.wait()
if status:
if status != 0:
raise subprocess.CalledProcessError(status, args, stdout)
return status, stdout
return status, stdout.strip()
except OSError:
raise subprocess.CalledProcessError(-1, args)

View file

@ -68,6 +68,7 @@ class CtrlNet(LxBrNet):
Startup functionality for the control network.
:return: nothing
:raises subprocess.CalledProcessError: when there is a command exception
"""
if self.detectoldbridge():
return
@ -79,26 +80,23 @@ class CtrlNet(LxBrNet):
else:
addr = self.prefix.max_addr()
msg = "Added control network bridge: %s %s" % (self.brname, self.prefix)
addrlist = ["%s/%s" % (addr, self.prefix.prefixlen)]
logger.info("added control network bridge: %s %s", self.brname, self.prefix)
if self.assign_address:
addrlist = ["%s/%s" % (addr, self.prefix.prefixlen)]
self.addrconfig(addrlist=addrlist)
msg += " address %s" % addr
logger.info(msg)
logger.info("address %s", addr)
if self.updown_script is not None:
logger.info("interface %s updown script (%s startup) called",
self.brname, self.updown_script)
if self.updown_script:
logger.info("interface %s updown script (%s startup) called", self.brname, self.updown_script)
utils.check_cmd([self.updown_script, self.brname, "startup"])
if self.serverintf is not None:
try:
if self.serverintf:
# sets the interface as a port of the bridge
utils.check_cmd([constants.BRCTL_BIN, "addif", self.brname, self.serverintf])
# bring interface up
utils.check_cmd([constants.IP_BIN, "link", "set", self.serverintf, "up"])
except subprocess.CalledProcessError:
logger.exception("error joining server interface %s to controlnet bridge %s",
self.serverintf, self.brname)
def detectoldbridge(self):
"""
@ -120,10 +118,9 @@ class CtrlNet(LxBrNet):
if len(flds) == 3:
if flds[0] == "b" and flds[1] == self.objid:
logger.error(
"Error: An active control net bridge (%s) found. "
"error: An active control net bridge (%s) found. "
"An older session might still be running. "
"Stop all sessions and, if needed, delete %s to continue." %
(oldbr, oldbr)
"Stop all sessions and, if needed, delete %s to continue.", oldbr, oldbr
)
return True
return False
@ -137,20 +134,26 @@ class CtrlNet(LxBrNet):
if self.serverintf is not None:
try:
utils.check_cmd([constants.BRCTL_BIN, "delif", self.brname, self.serverintf])
except subprocess.CalledProcessError:
logger.exception("error deleting server interface %s to controlnet bridge %s",
self.serverintf, self.brname)
except subprocess.CalledProcessError as e:
logger.exception("error deleting server interface %s from bridge %s: %s",
self.serverintf, self.brname, e.output)
if self.updown_script is not None:
logger.info("interface %s updown script (%s shutdown) called" % (self.brname, self.updown_script))
try:
logger.info("interface %s updown script (%s shutdown) called", self.brname, self.updown_script)
utils.check_cmd([self.updown_script, self.brname, "shutdown"])
except subprocess.CalledProcessError as e:
logger.exception("error issuing shutdown script shutdown: %s", e.output)
LxBrNet.shutdown(self)
def all_link_data(self, flags):
"""
Do not include CtrlNet in link messages describing this session.
:return: nothing
:param flags: message flags
:return: list of link data
:rtype: list[core.data.LinkData]
"""
return []
@ -172,29 +175,36 @@ class PtpNet(LxBrNet):
"""
Attach a network interface, but limit attachment to two interfaces.
:param core.coreobj.PyCoreNetIf netif: network interface
:param core.netns.vif.VEth netif: network interface
:return: nothing
"""
if len(self._netif) >= 2:
raise ValueError("Point-to-point links support at most 2 network interfaces")
LxBrNet.attach(self, netif)
def data(self, message_type):
def data(self, message_type, lat=None, lon=None, alt=None):
"""
Do not generate a Node Message for point-to-point links. They are
built using a link message instead.
:return: nothing
:param message_type: purpose for the data object we are creating
:param float lat: latitude
:param float lon: longitude
:param float alt: altitude
:return: node data object
:rtype: core.data.NodeData
"""
pass
return None
def all_link_data(self, flags):
"""
Build CORE API TLVs for a point-to-point link. One Link message
describes this network.
:return: all link data
:rtype: list[LinkData]
:param flags: message flags
:return: list of link data
:rtype: list[core.data.LinkData]
"""
all_links = []
@ -318,8 +328,11 @@ class HubNode(LxBrNet):
:param int objid: node id
:param str name: node namee
:param bool start: start flag
:raises subprocess.CalledProcessError: when there is a command exception
"""
LxBrNet.__init__(self, session, objid, name, start)
# TODO: move to startup method
if start:
utils.check_cmd([constants.BRCTL_BIN, "setageing", self.brname, "0"])
@ -353,7 +366,7 @@ class WlanNode(LxBrNet):
"""
Attach a network interface.
:param core.coreobj.PyCoreNetIf netif: network interface
:param core.netns.vif.VEth netif: network interface
:return: nothing
"""
LxBrNet.attach(self, netif)
@ -364,7 +377,6 @@ class WlanNode(LxBrNet):
x, y, z = netif.node.position.get()
# invokes any netif.poshook
netif.setposition(x, y, z)
# self.model.setlinkparams()
def setmodel(self, model, config):
"""
@ -398,25 +410,28 @@ class WlanNode(LxBrNet):
logger.info("updating model %s" % model_name)
if self.model is None or self.model.name != model_name:
return
model = self.model
if model.config_type == RegisterTlvs.WIRELESS.value:
if not model.updateconfig(values):
return
if self.model.position_callback:
for netif in self.netifs():
netif.poshook = self.model.position_callback
if netif.node is not None:
(x, y, z) = netif.node.position.get()
netif.poshook(netif, x, y, z)
self.model.setlinkparams()
def all_link_data(self, flags):
"""
Retrieve all link data.
:param flags: link flags
:return: all link data
:rtype: list[LinkData]
:param flags: message flags
:return: list of link data
:rtype: list[core.data.LinkData]
"""
all_links = LxBrNet.all_link_data(self, flags)
@ -446,7 +461,6 @@ class RJ45Node(PyCoreNode, PyCoreNetIf):
:return:
"""
PyCoreNode.__init__(self, session, objid, name, start=start)
# this initializes net, params, poshook
PyCoreNetIf.__init__(self, node=self, name=name, mtu=mtu)
self.up = False
self.lock = threading.RLock()
@ -456,6 +470,7 @@ class RJ45Node(PyCoreNode, PyCoreNetIf):
self.localname = name
self.old_up = False
self.old_addrs = []
if start:
self.startup()
@ -464,15 +479,12 @@ class RJ45Node(PyCoreNode, PyCoreNetIf):
Set the interface in the up state.
:return: nothing
:raises subprocess.CalledProcessError: when there is a command exception
"""
# interface will also be marked up during net.attach()
self.savestate()
try:
utils.check_cmd([constants.IP_BIN, "link", "set", self.localname, "up"])
self.up = True
except subprocess.CalledProcessError:
logger.exception("failed to run command: %s link set %s up", constants.IP_BIN, self.localname)
def shutdown(self):
"""
@ -504,6 +516,7 @@ class RJ45Node(PyCoreNode, PyCoreNetIf):
"""
PyCoreNetIf.attachnet(self, net)
# TODO: issue in that both classes inherited from provide the same method with different signatures
def detachnet(self):
"""
Detach a network.
@ -523,7 +536,9 @@ class RJ45Node(PyCoreNode, PyCoreNetIf):
:param str hwaddr: hardware address
:param int ifindex: interface index
:param str ifname: interface name
:return:
:return: interface index
:rtype: int
:raises ValueError: when an interface has already been created, one max
"""
with self.lock:
if ifindex is None:
@ -556,14 +571,12 @@ class RJ45Node(PyCoreNode, PyCoreNetIf):
if ifindex is None:
ifindex = 0
if ifindex not in self._netif:
raise ValueError, "ifindex %s does not exist" % ifindex
self._netif.pop(ifindex)
if ifindex == self.ifindex:
self.shutdown()
else:
raise ValueError, "ifindex %s does not exist" % ifindex
raise ValueError("ifindex %s does not exist" % ifindex)
def netif(self, ifindex, net=None):
"""
@ -606,9 +619,11 @@ class RJ45Node(PyCoreNode, PyCoreNetIf):
:param str addr: address to add
:return: nothing
:raises subprocess.CalledProcessError: when there is a command exception
"""
if self.up:
utils.check_cmd([constants.IP_BIN, "addr", "add", str(addr), "dev", self.name])
PyCoreNetIf.addaddr(self, addr)
def deladdr(self, addr):
@ -617,9 +632,11 @@ class RJ45Node(PyCoreNode, PyCoreNetIf):
:param str addr: address to delete
:return: nothing
:raises subprocess.CalledProcessError: when there is a command exception
"""
if self.up:
utils.check_cmd([constants.IP_BIN, "addr", "del", str(addr), "dev", self.name])
PyCoreNetIf.deladdr(self, addr)
def savestate(self):
@ -628,11 +645,11 @@ class RJ45Node(PyCoreNode, PyCoreNetIf):
interface for emulation purposes. TODO: save/restore the PROMISC flag
:return: nothing
:raises subprocess.CalledProcessError: when there is a command exception
"""
self.old_up = False
self.old_addrs = []
args = [constants.IP_BIN, "addr", "show", "dev", self.localname]
try:
_, output = utils.check_cmd(args)
for line in output.split("\n"):
items = line.split()
@ -649,14 +666,13 @@ class RJ45Node(PyCoreNode, PyCoreNetIf):
if items[1][:4] == "fe80":
continue
self.old_addrs.append((items[1], None))
except subprocess.CalledProcessError:
logger.exception("error during save state")
def restorestate(self):
"""
Restore the addresses and other interface state after using it.
:return: nothing
:raises subprocess.CalledProcessError: when there is a command exception
"""
for addr in self.old_addrs:
if addr[1] is None:
@ -669,13 +685,58 @@ class RJ45Node(PyCoreNode, PyCoreNetIf):
def setposition(self, x=None, y=None, z=None):
"""
Use setposition() from both parent classes.
Uses setposition from both parent classes.
:return: nothing
:param float x: x position
:param float y: y position
:param float z: z position
:return: True if position changed, False otherwise
:rtype: bool
"""
PyCoreObj.setposition(self, x, y, z)
# invoke any poshook
result = PyCoreObj.setposition(self, x, y, z)
PyCoreNetIf.setposition(self, x, y, z)
return result
def check_cmd(self, args):
"""
Runs shell command on node.
:param list[str]|str args: command to run
:return: exist status and combined stdout and stderr
:rtype: tuple[int, str]
:raises subprocess.CalledProcessError: when a non-zero exit status occurs
"""
raise NotImplementedError
def cmd(self, args, wait=True):
"""
Runs shell command on node, with option to not wait for a result.
:param list[str]|str args: command to run
:param bool wait: wait for command to exit, defaults to True
:return: exit status for command
:rtype: int
"""
raise NotImplementedError
def cmd_output(self, args):
"""
Runs shell command on node and get exit status and output.
:param list[str]|str args: command to run
:return: exit status and combined stdout and stderr
:rtype: tuple[int, str]
"""
raise NotImplementedError
def termcmdstring(self, sh):
"""
Create a terminal command string.
:param str sh: shell to execute command in
:return: str
"""
raise NotImplementedError
class TunnelNode(GreTapBridge):

View file

@ -78,12 +78,13 @@ class OvsNet(PyCoreNet):
ebtables_queue.startupdateloop(self)
def startup(self):
try:
utils.check_cmd([constants.OVS_BIN, "add-br", self.bridge_name])
except subprocess.CalledProcessError:
logger.exception("error adding bridge")
"""
:return:
:raises subprocess.CalledProcessError: when there is a command exception
"""
utils.check_cmd([constants.OVS_BIN, "add-br", self.bridge_name])
try:
# turn off spanning tree protocol and forwarding delay
# TODO: appears stp and rstp are off by default, make sure this always holds true
# TODO: apears ovs only supports rstp forward delay and again it's off by default
@ -94,8 +95,6 @@ class OvsNet(PyCoreNet):
[constants.EBTABLES_BIN, "-N", self.bridge_name, "-P", self.policy],
[constants.EBTABLES_BIN, "-A", "FORWARD", "--logical-in", self.bridge_name, "-j", self.bridge_name]
])
except subprocess.CalledProcessError:
logger.exception("Error setting bridge parameters")
self.up = True
@ -127,22 +126,14 @@ class OvsNet(PyCoreNet):
def attach(self, interface):
if self.up:
try:
utils.check_cmd([constants.OVS_BIN, "add-port", self.bridge_name, interface.localname])
utils.check_cmd([constants.IP_BIN, "link", "set", interface.localname, "up"])
except subprocess.CalledProcessError:
logger.exception("error joining interface %s to bridge %s", interface.localname, self.bridge_name)
return
PyCoreNet.attach(self, interface)
def detach(self, interface):
if self.up:
try:
utils.check_cmd([constants.OVS_BIN, "del-port", self.bridge_name, interface.localname])
except subprocess.CalledProcessError:
logger.exception("error removing interface %s from bridge %s", interface.localname, self.bridge_name)
return
PyCoreNet.detach(self, interface)
@ -345,10 +336,7 @@ class OvsNet(PyCoreNet):
return
for address in addresses:
try:
utils.check_cmd([constants.IP_BIN, "addr", "add", str(address), "dev", self.bridge_name])
except subprocess.CalledProcessError:
logger.exception("error adding IP address")
class OvsCtrlNet(OvsNet):
@ -392,20 +380,16 @@ class OvsCtrlNet(OvsNet):
utils.check_cmd([self.updown_script, self.bridge_name, "startup"])
if self.serverintf:
try:
utils.check_cmd([constants.OVS_BIN, "add-port", self.bridge_name, self.serverintf])
utils.check_cmd([constants.IP_BIN, "link", "set", self.serverintf, "up"])
except subprocess.CalledProcessError:
logger.exception("error joining server interface %s to controlnet bridge %s",
self.serverintf, self.bridge_name)
def detectoldbridge(self):
"""
Occassionally, control net bridges from previously closed sessions are not cleaned up.
Occasionally, control net bridges from previously closed sessions are not cleaned up.
Check if there are old control net bridges and delete them
"""
status, output = utils.cmd_output([constants.OVS_BIN, "list-br"])
_, output = utils.check_cmd([constants.OVS_BIN, "list-br"])
output = output.strip()
if output:
for line in output.split("\n"):
@ -420,13 +404,16 @@ class OvsCtrlNet(OvsNet):
if self.serverintf:
try:
utils.check_cmd([constants.OVS_BIN, "del-port", self.bridge_name, self.serverintf])
except subprocess.CalledProcessError:
logger.exception("Error deleting server interface %s to controlnet bridge %s",
self.serverintf, self.bridge_name)
except subprocess.CalledProcessError as e:
logger.exception("error deleting server interface %s to controlnet bridge %s: %s",
self.serverintf, self.bridge_name, e.output)
if self.updown_script:
try:
logger.info("interface %s updown script (%s shutdown) called", self.bridge_name, self.updown_script)
utils.check_cmd([self.updown_script, self.bridge_name, "shutdown"])
except subprocess.CalledProcessError as e:
logger.exception("error during updown script shutdown: %s", e.output)
OvsNet.shutdown(self)
@ -445,12 +432,12 @@ class OvsPtpNet(OvsNet):
raise ValueError("point-to-point links support at most 2 network interfaces")
OvsNet.attach(self, interface)
def data(self, message_type):
def data(self, message_type, lat=None, lon=None, alt=None):
"""
Do not generate a Node Message for point-to-point links. They are
built using a link message instead.
"""
pass
return None
def all_link_data(self, flags):
"""
@ -685,8 +672,8 @@ class OvsGreTapBridge(OvsNet):
if remoteip is None:
self.gretap = None
else:
self.gretap = GreTap(node=self, name=None, session=session, remoteip=remoteip,
objid=None, localip=localip, ttl=ttl, key=self.grekey)
self.gretap = GreTap(node=self, session=session, remoteip=remoteip,
localip=localip, ttl=ttl, key=self.grekey)
if start:
self.startup()
@ -726,7 +713,7 @@ class OvsGreTapBridge(OvsNet):
if len(addresses) > 1:
localip = addresses[1].split("/")[0]
self.gretap = GreTap(session=self.session, remoteip=remoteip, objid=None, name=None,
self.gretap = GreTap(session=self.session, remoteip=remoteip,
localip=localip, ttl=self.ttl, key=self.grekey)
self.attach(self.gretap)

View file

@ -31,7 +31,7 @@ class VEth(PyCoreNetIf):
:param mtu: interface mtu
:param net: network
:param bool start: start flag
:return:
:raises subprocess.CalledProcessError: when there is a command exception
"""
# note that net arg is ignored
PyCoreNetIf.__init__(self, node=node, name=name, mtu=mtu)
@ -45,6 +45,7 @@ class VEth(PyCoreNetIf):
Interface startup logic.
:return: nothing
:raises subprocess.CalledProcessError: when there is a command exception
"""
utils.check_cmd([constants.IP_BIN, "link", "add", "name", self.localname,
"type", "veth", "peer", "name", self.name])
@ -63,11 +64,14 @@ class VEth(PyCoreNetIf):
if self.node:
try:
self.node.check_cmd([constants.IP_BIN, "-6", "addr", "flush", "dev", self.name])
except subprocess.CalledProcessError:
logger.exception("error shutting down interface")
except subprocess.CalledProcessError as e:
logger.exception("error shutting down interface: %s", e.output)
if self.localname:
utils.mute_detach([constants.IP_BIN, "link", "delete", self.localname])
try:
utils.check_cmd([constants.IP_BIN, "link", "delete", self.localname])
except subprocess.CalledProcessError as e:
logger.exception("error deleting link: %s", e.output)
self.up = False
@ -121,8 +125,8 @@ class TunTap(PyCoreNetIf):
try:
self.node.check_cmd([constants.IP_BIN, "-6", "addr", "flush", "dev", self.name])
except subprocess.CalledProcessError:
logger.exception("error shutting down tunnel tap")
except subprocess.CalledProcessError as e:
logger.exception("error shutting down tunnel tap: %s", e.output)
self.up = False
@ -133,13 +137,16 @@ class TunTap(PyCoreNetIf):
:param func: function to wait for a result of zero
:param int attempts: number of attempts to wait for a zero result
:param float maxretrydelay: maximum retry delay
:return: nothing
:return: True if wait succeeded, False otherwise
:rtype: bool
"""
delay = 0.01
result = False
for i in xrange(1, attempts + 1):
r = func()
if r == 0:
return
result = True
break
msg = "attempt %s failed with nonzero exit status %s" % (i, r)
if i < attempts + 1:
msg += ", retrying..."
@ -152,7 +159,7 @@ class TunTap(PyCoreNetIf):
msg += ", giving up"
logger.info(msg)
raise RuntimeError("command failed after %s attempts" % attempts)
return result
def waitfordevicelocal(self):
"""
@ -182,18 +189,20 @@ class TunTap(PyCoreNetIf):
count = 0
while True:
try:
self.waitfor(nodedevexists)
result = self.waitfor(nodedevexists)
if result:
break
except RuntimeError as e:
# check if this is an EMANE interface; if so, continue
# waiting if EMANE is still running
# TODO: remove emane code
if count < 5 and nodeutils.is_node(self.net, NodeTypes.EMANE) and self.node.session.emane.emanerunning(
self.node):
should_retry = count < 5
is_emane_node = nodeutils.is_node(self.net, NodeTypes.EMANE)
is_emane_running = self.node.session.emane.emanerunning(self.node)
if all([should_retry, is_emane_node, is_emane_running]):
count += 1
else:
raise e
raise RuntimeError("node device failed to exist")
def install(self):
"""
@ -203,16 +212,13 @@ class TunTap(PyCoreNetIf):
end of the TAP.
:return: nothing
:raises subprocess.CalledProcessError: when there is a command exception
"""
self.waitfordevicelocal()
netns = str(self.node.pid)
try:
utils.check_cmd([constants.IP_BIN, "link", "set", self.localname, "netns", netns])
self.node.check_cmd([constants.IP_BIN, "link", "set", self.localname, "name", self.name])
self.node.check_cmd([constants.IP_BIN, "link", "set", self.name, "up"])
except subprocess.CalledProcessError:
logger.exception("error installing TAP interface")
def setaddrs(self):
"""
@ -222,10 +228,7 @@ class TunTap(PyCoreNetIf):
"""
self.waitfordevicenode()
for addr in self.addrlist:
try:
self.node.check_cmd([constants.IP_BIN, "addr", "add", str(addr), "dev", self.name])
except subprocess.CalledProcessError:
logger.exception("failure setting interface address")
class GreTap(PyCoreNetIf):
@ -251,6 +254,7 @@ class GreTap(PyCoreNetIf):
:param ttl: ttl value
:param key: gre tap key
:param bool start: start flag
:raises subprocess.CalledProcessError: when there is a command exception
"""
PyCoreNetIf.__init__(self, node=node, name=name, mtu=mtu)
self.session = session
@ -268,16 +272,16 @@ class GreTap(PyCoreNetIf):
if remoteip is None:
raise ValueError, "missing remote IP required for GRE TAP device"
args = ("ip", "link", "add", self.localname, "type", "gretap",
"remote", str(remoteip))
args = ["ip", "link", "add", self.localname, "type", "gretap",
"remote", str(remoteip)]
if localip:
args += ("local", str(localip))
args += ["local", str(localip)]
if ttl:
args += ("ttl", str(ttl))
args += ["ttl", str(ttl)]
if key:
args += ("key", str(key))
args += ["key", str(key)]
utils.check_cmd(args)
args = ("ip", "link", "set", self.localname, "up")
args = ["ip", "link", "set", self.localname, "up"]
utils.check_cmd(args)
self.up = True
@ -288,10 +292,14 @@ class GreTap(PyCoreNetIf):
:return: nothing
"""
if self.localname:
args = ("ip", "link", "set", self.localname, "down")
try:
args = ["ip", "link", "set", self.localname, "down"]
utils.check_cmd(args)
args = ("ip", "link", "del", self.localname)
args = ["ip", "link", "del", self.localname]
utils.check_cmd(args)
except subprocess.CalledProcessError as e:
logger.exception("error during shutdown: %s", e.output)
self.localname = None
def data(self, message_type):

View file

@ -59,11 +59,12 @@ class EbtablesQueue(object):
:return: nothing
"""
self.updatelock.acquire()
with self.updatelock:
self.last_update_time[wlan] = time.time()
self.updatelock.release()
if self.doupdateloop:
return
self.doupdateloop = True
self.updatethread = threading.Thread(target=self.updateloop)
self.updatethread.daemon = True
@ -75,15 +76,15 @@ class EbtablesQueue(object):
:return: nothing
"""
self.updatelock.acquire()
with self.updatelock:
try:
del self.last_update_time[wlan]
except KeyError:
logger.exception("error deleting last update time for wlan, ignored before: %s", wlan)
self.updatelock.release()
if len(self.last_update_time) > 0:
return
self.doupdateloop = False
if self.updatethread:
self.updatethread.join()
@ -137,25 +138,26 @@ class EbtablesQueue(object):
:return: nothing
"""
while self.doupdateloop:
self.updatelock.acquire()
with self.updatelock:
for wlan in self.updates:
"""
Check if wlan is from a previously closed session. Because of the
rate limiting scheme employed here, this may happen if a new session
is started soon after closing a previous session.
"""
# TODO: if these are WlanNodes, this will never throw an exception
try:
wlan.session
except:
# Just mark as updated to remove from self.updates.
self.updated(wlan)
continue
if self.lastupdate(wlan) > self.rate:
self.buildcmds(wlan)
# print "ebtables commit %d rules" % len(self.cmds)
self.ebcommit(wlan)
self.updated(wlan)
self.updatelock.release()
time.sleep(self.rate)
def ebcommit(self, wlan):
@ -166,29 +168,22 @@ class EbtablesQueue(object):
"""
# save kernel ebtables snapshot to a file
args = self.ebatomiccmd(["--atomic-save", ])
try:
utils.check_cmd(args)
except subprocess.CalledProcessError:
logger.exception("atomic-save (%s)", args)
# no atomic file, exit
return
# modify the table file using queued ebtables commands
for c in self.cmds:
args = self.ebatomiccmd(c)
try:
utils.check_cmd(args)
except subprocess.CalledProcessError:
logger.exception("cmd=%s", args)
self.cmds = []
# commit the table file to the kernel
args = self.ebatomiccmd(["--atomic-commit", ])
utils.check_cmd(args)
try:
utils.check_cmd(args)
os.unlink(self.atomic_file)
except OSError:
logger.exception("atomic-commit (%s)", args)
logger.exception("error removing atomic file: %s", self.atomic_file)
def ebchange(self, wlan):
"""
@ -197,10 +192,9 @@ class EbtablesQueue(object):
:return: nothing
"""
self.updatelock.acquire()
with self.updatelock:
if wlan not in self.updates:
self.updates.append(wlan)
self.updatelock.release()
def buildcmds(self, wlan):
"""
@ -208,7 +202,7 @@ class EbtablesQueue(object):
:return: nothing
"""
wlan._linked_lock.acquire()
with wlan._linked_lock:
# flush the chain
self.cmds.extend([["-F", wlan.brname], ])
# rebuild the chain
@ -224,7 +218,6 @@ class EbtablesQueue(object):
"-o", netif2.localname, "-j", "DROP"],
["-A", wlan.brname, "-o", netif1.localname,
"-i", netif2.localname, "-j", "DROP"]])
wlan._linked_lock.release()
# a global object because all WLANs share the same queue
@ -279,13 +272,10 @@ class LxBrNet(PyCoreNet):
Linux bridge starup logic.
:return: nothing
:raises subprocess.CalledProcessError: when there is a command exception
"""
try:
utils.check_cmd([constants.BRCTL_BIN, "addbr", self.brname])
except subprocess.CalledProcessError:
logger.exception("Error adding bridge")
try:
# turn off spanning tree protocol and forwarding delay
utils.check_cmd([constants.BRCTL_BIN, "stp", self.brname, "off"])
utils.check_cmd([constants.BRCTL_BIN, "setfd", self.brname, "0"])
@ -298,9 +288,8 @@ class LxBrNet(PyCoreNet):
# turn off multicast snooping so mcast forwarding occurs w/o IGMP joins
snoop = "/sys/devices/virtual/net/%s/bridge/multicast_snooping" % self.brname
if os.path.exists(snoop):
open(snoop, "w").write("0")
except subprocess.CalledProcessError:
logger.exception("Error setting bridge parameters")
with open(snoop, "w") as snoop_file:
snoop_file.write("0")
self.up = True
@ -312,6 +301,7 @@ class LxBrNet(PyCoreNet):
"""
if not self.up:
return
ebq.stopupdateloop(self)
try:
@ -333,20 +323,18 @@ class LxBrNet(PyCoreNet):
del self.session
self.up = False
# TODO: this depends on a subtype with localname defined, seems like the wrong place for this to live
def attach(self, netif):
"""
Attach a network interface.
:param core.netns.vif.VEth netif: network interface to attach
:param core.netns.vnode.VEth netif: network interface to attach
:return: nothing
"""
if self.up:
try:
utils.check_cmd([constants.BRCTL_BIN, "addif", self.brname, netif.localname])
utils.check_cmd([constants.IP_BIN, "link", "set", netif.localname, "up"])
except subprocess.CalledProcessError:
logger.exception("Error joining interface %s to bridge %s", netif.localname, self.brname)
return
PyCoreNet.attach(self, netif)
def detach(self, netif):
@ -357,11 +345,8 @@ class LxBrNet(PyCoreNet):
:return: nothing
"""
if self.up:
try:
utils.check_cmd([constants.BRCTL_BIN, "delif", self.brname, netif.localname])
except subprocess.CalledProcessError:
logger.exception("Error removing interface %s from bridge %s", netif.localname, self.brname)
return
PyCoreNet.detach(self, netif)
def linked(self, netif1, netif2):
@ -402,12 +387,11 @@ class LxBrNet(PyCoreNet):
:param core.netns.vif.Veth netif2: interface two
:return: nothing
"""
self._linked_lock.acquire()
with self._linked_lock:
if not self.linked(netif1, netif2):
self._linked_lock.release()
return
self._linked[netif1][netif2] = False
self._linked_lock.release()
ebq.ebchange(self)
def link(self, netif1, netif2):
@ -419,12 +403,11 @@ class LxBrNet(PyCoreNet):
:param core.netns.vif.Veth netif2: interface two
:return: nothing
"""
self._linked_lock.acquire()
with self._linked_lock:
if self.linked(netif1, netif2):
self._linked_lock.release()
return
self._linked[netif1][netif2] = True
self._linked_lock.release()
ebq.ebchange(self)
def linkconfig(self, netif, bw=None, delay=None, loss=None, duplicate=None,
@ -525,18 +508,21 @@ class LxBrNet(PyCoreNet):
self_objid = "%x" % self.objid
except TypeError:
self_objid = "%s" % self.objid
try:
net_objid = "%x" % net.objid
except TypeError:
net_objid = "%s" % net.objid
localname = "veth%s.%s.%s" % (self_objid, net_objid, sessionid)
if len(localname) >= 16:
raise ValueError("interface local name %s too long" % localname)
name = "veth%s.%s.%s" % (net_objid, self_objid, sessionid)
if len(name) >= 16:
raise ValueError("interface name %s too long" % name)
netif = VEth(node=None, name=name, localname=localname,
mtu=1500, net=self, start=self.up)
netif = VEth(node=None, name=name, localname=localname, mtu=1500, net=self, start=self.up)
self.attach(netif)
if net.up:
# this is similar to net.attach() but uses netif.name instead
@ -563,6 +549,7 @@ class LxBrNet(PyCoreNet):
for netif in self.netifs():
if hasattr(netif, "othernet") and netif.othernet == net:
return netif
return None
def addrconfig(self, addrlist):
@ -574,11 +561,9 @@ class LxBrNet(PyCoreNet):
"""
if not self.up:
return
for addr in addrlist:
try:
utils.check_cmd([constants.IP_BIN, "addr", "add", str(addr), "dev", self.brname])
except subprocess.CalledProcessError:
logger.exception("Error adding IP address")
class GreTapBridge(LxBrNet):
@ -615,8 +600,8 @@ class GreTapBridge(LxBrNet):
if remoteip is None:
self.gretap = None
else:
self.gretap = GreTap(node=self, name=None, session=session, remoteip=remoteip,
objid=None, localip=localip, ttl=ttl, key=self.grekey)
self.gretap = GreTap(node=self, session=session, remoteip=remoteip,
localip=localip, ttl=ttl, key=self.grekey)
if start:
self.startup()
@ -658,7 +643,7 @@ class GreTapBridge(LxBrNet):
localip = None
if len(addrlist) > 1:
localip = addrlist[1].split("/")[0]
self.gretap = GreTap(session=self.session, remoteip=remoteip, objid=None, name=None,
self.gretap = GreTap(session=self.session, remoteip=remoteip,
localip=localip, ttl=self.ttl, key=self.grekey)
self.attach(self.gretap)

View file

@ -98,16 +98,12 @@ class SimpleLxcNode(PyCoreNode):
env["NODE_NUMBER"] = str(self.objid)
env["NODE_NAME"] = str(self.name)
try:
_, output = utils.check_cmd(vnoded, env=env)
self.pid = int(output)
except subprocess.CalledProcessError:
logger.exception("vnoded failed to create a namespace; check kernel support and user privileges")
# create vnode client
self.client = vnodeclient.VnodeClient(self.name, self.ctrlchnlname)
try:
# bring up the loopback interface
logger.info("bringing up loopback interface")
self.check_cmd([constants.IP_BIN, "link", "set", "lo", "up"])
@ -115,8 +111,6 @@ class SimpleLxcNode(PyCoreNode):
# set hostname for node
logger.info("setting hostname: %s" % self.name)
self.check_cmd(["hostname", self.name])
except subprocess.CalledProcessError:
logger.exception("error setting up loopback and hostname: %s")
# mark node as up
self.up = True
@ -165,7 +159,7 @@ class SimpleLxcNode(PyCoreNode):
:return: nothing
"""
pass
return None
def cmd(self, args, wait=True):
"""
@ -208,7 +202,6 @@ class SimpleLxcNode(PyCoreNode):
"""
return self.client.termcmdstring(sh)
# TODO: should change how this exception is just swallowed up
def mount(self, source, target):
"""
Create and mount a directory.
@ -216,17 +209,15 @@ class SimpleLxcNode(PyCoreNode):
:param str source: source directory to mount
:param str target: target directory to create
:return: nothing
:raises subprocess.CalledProcessError: when a non-zero exit status occurs
"""
source = os.path.abspath(source)
logger.info("mounting %s at %s" % (source, target))
try:
cmd = 'mkdir -p "%s" && %s -n --bind "%s" "%s"' % (target, constants.MOUNT_BIN, source, target)
status, output = self.client.shcmd_result(cmd)
if status:
raise IOError("error during mount: %s" % output)
raise subprocess.CalledProcessError(status, cmd, output)
self._mounts.append((source, target))
except IOError:
logger.exception("mounting failed for %s at %s", source, target)
def umount(self, target):
"""
@ -238,8 +229,8 @@ class SimpleLxcNode(PyCoreNode):
logger.info("unmounting: %s", target)
try:
self.check_cmd([constants.UMOUNT_BIN, "-n", "-l", target])
except subprocess.CalledProcessError:
logger.exception("error during unmount")
except subprocess.CalledProcessError as e:
logger.exception("error during unmount: %s", e.output)
def newifindex(self):
"""
@ -277,24 +268,22 @@ class SimpleLxcNode(PyCoreNode):
localname = "veth" + suffix
if len(localname) >= 16:
raise ValueError("interface local name (%s) too long" % localname)
name = localname + "p"
if len(name) >= 16:
raise ValueError("interface name (%s) too long" % name)
veth = VEth(node=self, name=name, localname=localname, net=net, start=self.up)
if self.up:
try:
utils.check_cmd([constants.IP_BIN, "link", "set", veth.name, "netns", str(self.pid)])
self.check_cmd([constants.IP_BIN, "link", "set", veth.name, "name", ifname])
except subprocess.CalledProcessError:
logger.exception("failure setting eth name")
veth.name = ifname
if self.up:
# TODO: potentially find better way to query interface ID
# retrieve interface information
try:
_, output = self.check_cmd(["ip", "link", "show", veth.name])
logger.info("interface command output: %s", output)
output = output.split("\n")
@ -302,8 +291,6 @@ class SimpleLxcNode(PyCoreNode):
logger.info("interface flow index: %s - %s", veth.name, veth.flow_id)
veth.hwaddr = output[1].strip().split()[1]
logger.info("interface mac: %s - %s", veth.name, veth.hwaddr)
except subprocess.CalledProcessError:
logger.exception("failure getting flow id and mac address")
try:
self.addnetif(veth, ifindex)
@ -351,15 +338,13 @@ class SimpleLxcNode(PyCoreNode):
:param int ifindex: index of interface to set hardware address for
:param core.misc.ipaddress.MacAddress addr: hardware address to set
:return: mothing
:return: nothing
:raises subprocess.CalledProcessError: when a non-zero exit status occurs
"""
self._netif[ifindex].sethwaddr(addr)
if self.up:
args = [constants.IP_BIN, "link", "set", "dev", self.ifname(ifindex), "address", str(addr)]
try:
self.check_cmd(args)
except subprocess.CalledProcessError:
logger.exception("error setting MAC address %s: %s", addr)
def addaddr(self, ifindex, addr):
"""
@ -370,7 +355,6 @@ class SimpleLxcNode(PyCoreNode):
:return: nothing
"""
if self.up:
try:
# check if addr is ipv6
if ":" in str(addr):
args = [constants.IP_BIN, "addr", "add", str(addr), "dev", self.ifname(ifindex)]
@ -378,8 +362,6 @@ class SimpleLxcNode(PyCoreNode):
else:
args = [constants.IP_BIN, "addr", "add", str(addr), "broadcast", "+", "dev", self.ifname(ifindex)]
self.check_cmd(args)
except subprocess.CalledProcessError:
logger.exception("failure adding interface address")
self._netif[ifindex].addaddr(addr)
@ -390,6 +372,7 @@ class SimpleLxcNode(PyCoreNode):
:param int ifindex: index of interface to delete address from
:param str addr: address to delete from interface
:return: nothing
:raises subprocess.CalledProcessError: when a non-zero exit status occurs
"""
try:
self._netif[ifindex].deladdr(addr)
@ -397,10 +380,7 @@ class SimpleLxcNode(PyCoreNode):
logger.exception("trying to delete unknown address: %s" % addr)
if self.up:
try:
self.check_cmd([constants.IP_BIN, "addr", "del", str(addr), "dev", self.ifname(ifindex)])
except subprocess.CalledProcessError:
logger.exception("failure deleting address")
def delalladdr(self, ifindex, address_types=valid_address_types):
"""
@ -409,6 +389,7 @@ class SimpleLxcNode(PyCoreNode):
:param int ifindex: index of interface to delete address types from
:param tuple[str] address_types: address types to delete
:return: nothing
:raises subprocess.CalledProcessError: when a non-zero exit status occurs
"""
interface_name = self.ifname(ifindex)
addresses = self.client.getaddr(interface_name, rescan=True)
@ -430,10 +411,7 @@ class SimpleLxcNode(PyCoreNode):
:return: nothing
"""
if self.up:
try:
self.check_cmd([constants.IP_BIN, "link", "set", self.ifname(ifindex), "up"])
except subprocess.CalledProcessError:
logger.exception("failure bringing interface up")
def newnetif(self, net=None, addrlist=None, hwaddr=None, ifindex=None, ifname=None):
"""
@ -510,17 +488,15 @@ class SimpleLxcNode(PyCoreNode):
:param str srcname: source file name
:param str filename: file name to add
:return: nothing
:raises subprocess.CalledProcessError: when a non-zero exit status occurs
"""
logger.info("adding file from %s to %s", srcname, filename)
directory = os.path.dirname(filename)
try:
cmd = 'mkdir -p "%s" && mv "%s" "%s" && sync' % (directory, srcname, filename)
status, output = self.client.shcmd_result(cmd)
if status:
raise IOError("error adding file: %s" % output)
except IOError:
logger.exception("error during addfile")
raise subprocess.CalledProcessError(status, cmd, output)
class LxcNode(SimpleLxcNode):
@ -567,13 +543,10 @@ class LxcNode(SimpleLxcNode):
:return: nothing
"""
with self.lock:
try:
self.makenodedir()
super(LxcNode, self).startup()
self.privatedir("/var/run")
self.privatedir("/var/log")
except OSError:
logger.exception("error during startup")
def shutdown(self):
"""
@ -585,8 +558,6 @@ class LxcNode(SimpleLxcNode):
return
with self.lock:
# services are instead stopped when session enters datacollect state
# self.session.services.stopnodeservices(self)
try:
super(LxcNode, self).shutdown()
except OSError:
@ -605,12 +576,7 @@ class LxcNode(SimpleLxcNode):
if path[0] != "/":
raise ValueError("path not fully qualified: %s" % path)
hostpath = os.path.join(self.nodedir, os.path.normpath(path).strip("/").replace("/", "."))
try:
os.mkdir(hostpath)
except OSError:
logger.exception("error creating directory: %s", hostpath)
self.mount(hostpath, path)
def hostfilename(self, filename):
@ -622,7 +588,7 @@ class LxcNode(SimpleLxcNode):
"""
dirname, basename = os.path.split(filename)
if not basename:
raise ValueError("no basename for filename: " + filename)
raise ValueError("no basename for filename: %s" % filename)
if dirname and dirname[0] == "/":
dirname = dirname[1:]
dirname = dirname.replace("/", ".")

View file

@ -109,7 +109,7 @@ class VnodeClient(object):
:raises subprocess.CalledProcessError: when there is a non-zero exit status
"""
status, output = self.cmd_output(args)
if status:
if status != 0:
raise subprocess.CalledProcessError(status, args, output)
return status, output.strip()