caught up with latest gitlab commits, added a new tests directory leveraging pytest based tests for testing core functionality

This commit is contained in:
Blake J. Harnden 2017-04-27 13:34:23 -07:00
parent 2fc6345138
commit 14cb7dc251
14 changed files with 570 additions and 96 deletions

View file

@ -38,6 +38,7 @@ from core.phys.pnodes import PhysicalNode
logger = log.get_logger(__name__)
# TODO: name conflict with main core server, probably should rename
class CoreServer(object):
def __init__(self, name, host, port):
self.name = name
@ -93,7 +94,6 @@ class CoreBroker(ConfigurableManager):
self.nodemap_lock = threading.Lock()
# reference counts of nodes on servers
self.nodecounts = {}
self.bootcount = 0
# set of node numbers that are link-layer nodes (networks)
self.network_nodes = set()
# set of node numbers that are PhysicalNode nodes
@ -224,11 +224,6 @@ class CoreBroker(ConfigurableManager):
nodenum = msg.get_tlv(NodeTlvs.NUMBER.value)
if nodenum is not None:
count = self.delnodemap(server, nodenum)
# snoop node add response to increment booted node count
# (only CoreNodes send these response messages)
elif msgflags & (MessageFlags.ADD.value | MessageFlags.LOCAL.value):
self.incrbootcount()
self.session.check_runtime()
elif msgtype == MessageTypes.LINK.value:
# this allows green link lines for remote WLANs
msg = coreapi.CoreLinkMessage(msgflags, msghdr, msgdata)
@ -485,19 +480,6 @@ class CoreBroker(ConfigurableManager):
self.nodecounts[server] = count
return count
def incrbootcount(self):
"""
Count a node that has booted.
"""
self.bootcount += 1
return self.bootcount
def getbootcount(self):
"""
Return the number of booted nodes.
"""
return self.bootcount
def getserversbynode(self, nodenum):
"""
Retrieve a set of emulation servers given a node number.
@ -588,13 +570,14 @@ class CoreBroker(ConfigurableManager):
:rtype: bool
"""
servers = set()
handle_locally = False
# Do not forward messages when in definition state
# (for e.g. configuring services)
if self.session.state == EventTypes.DEFINITION_STATE.value:
return False
# Decide whether message should be handled locally or forwarded, or both
if message.message_type == MessageTypes.NODE.value:
servers = self.handlenodemsg(message)
handle_locally, servers = self.handlenodemsg(message)
elif message.message_type == MessageTypes.EVENT.value:
# broadcast events everywhere
servers = self.getservers()
@ -611,7 +594,7 @@ class CoreBroker(ConfigurableManager):
servers = self.getservers()
if message.message_type == MessageTypes.LINK.value:
# prepare a server list from two node numbers in link message
servers, message = self.handlelinkmsg(message)
handle_locally, servers, message = self.handlelinkmsg(message)
elif len(servers) == 0:
# check for servers based on node numbers in all messages but link
nn = message.node_numbers()
@ -626,7 +609,7 @@ class CoreBroker(ConfigurableManager):
handler(message)
# Perform any message forwarding
handle_locally = self.forwardmsg(message, servers)
handle_locally |= self.forwardmsg(message, servers)
return not handle_locally
def setupserver(self, servername):
@ -694,6 +677,7 @@ class CoreBroker(ConfigurableManager):
:return:
"""
servers = set()
handle_locally = False
serverfiletxt = None
# snoop Node Message for emulation server TLV and record mapping
n = message.tlv_data[NodeTlvs.NUMBER.value]
@ -704,25 +688,21 @@ class CoreBroker(ConfigurableManager):
nodecls = nodeutils.get_node_class(NodeTypes(nodetype))
except KeyError:
logger.warn("broker invalid node type %s" % nodetype)
return servers
return handle_locally, servers
if nodecls is None:
logger.warn("broker unimplemented node type %s" % nodetype)
return servers
return handle_locally, servers
if issubclass(nodecls, PyCoreNet) and nodetype != NodeTypes.WIRELESS_LAN.value:
# network node replicated on all servers; could be optimized
# don"t replicate WLANs, because ebtables rules won"t work
servers = self.getservers()
handle_locally = True
self.addnet(n)
for server in servers:
self.addnodemap(server, n)
# do not record server name for networks since network
# nodes are replicated across all server
return servers
if issubclass(nodecls, PyCoreNet) and nodetype == NodeTypes.WIRELESS_LAN.value:
# special case where remote WLANs not in session._objs, and no
# node response message received, so they are counted here
if message.get_tlv(NodeTlvs.EMULATION_SERVER.value) is not None:
self.incrbootcount()
return handle_locally, servers
elif issubclass(nodecls, PyCoreNode):
name = message.get_tlv(NodeTlvs.NAME.value)
if name:
@ -743,7 +723,7 @@ class CoreBroker(ConfigurableManager):
# hook to update coordinates of physical nodes
if n in self.physical_nodes:
self.session.mobility.physnodeupdateposition(message)
return servers
return handle_locally, servers
def handlelinkmsg(self, message):
"""
@ -804,10 +784,11 @@ class CoreBroker(ConfigurableManager):
self.addtunnel(host, nn[0], nn[1], localn)
elif message.flags & MessageFlags.DELETE.value:
self.deltunnel(nn[0], nn[1])
handle_locally = False
else:
servers = servers1.union(servers2)
return servers, message
return handle_locally, servers, message
def addlinkendpoints(self, message, servers1, servers2):
"""
@ -946,7 +927,7 @@ class CoreBroker(ConfigurableManager):
if server is not None:
server.instantiation_complete = True
if self.session.is_connected():
if self.session_handler:
tlvdata = ""
tlvdata += coreapi.CoreEventTlv.pack(EventTlvs.TYPE.value, EventTypes.INSTANTIATION_COMPLETE.value)
msg = coreapi.CoreEventMessage.pack(0, tlvdata)

View file

@ -71,6 +71,7 @@ class CoreRequestHandler(SocketServer.BaseRequestHandler):
}
self.message_queue = Queue.Queue()
self.node_status_request = {}
self._shutdown_lock = threading.Lock()
self.handler_threads = []
num_threads = int(server.config["numthreads"])
@ -602,22 +603,16 @@ class CoreRequestHandler(SocketServer.BaseRequestHandler):
self.node_status_request[node_id] = True
elif message.flags & MessageFlags.DELETE.value:
# TODO: logic below seems pointless, when the deletion is attempted regardless
node = None
try:
node = self.session.get_object(node_id)
except KeyError:
logger.exception("error retrieving object: %s", node_id)
with self._shutdown_lock:
self.session.delete_object(node_id)
self.session.delete_object(node_id)
if message.flags & MessageFlags.STRING.value:
tlvdata = ""
tlvdata += coreapi.CoreNodeTlv.pack(NodeTlvs.NUMBER.value, node_id)
flags = MessageFlags.DELETE.value | MessageFlags.LOCAL.value
replies.append(coreapi.CoreNodeMessage.pack(flags, tlvdata))
if message.flags & MessageFlags.STRING.value:
tlv_data = ""
tlv_data += coreapi.CoreNodeTlv.pack(NodeTlvs.NUMBER.value, node_id)
flags = MessageFlags.DELETE.value | MessageFlags.LOCAL.value
replies.append(coreapi.CoreNodeMessage.pack(flags, tlv_data))
self.session.check_shutdown()
self.session.check_shutdown()
# Node modify message (no add/del flag)
else:
try:

View file

@ -457,6 +457,7 @@ class EmaneManager(ConfigurableManager):
servers.append(s)
self._objslock.release()
servers.sort(key=lambda x: x.name)
for server in servers:
if server.name == "localhost":
continue
@ -1139,6 +1140,24 @@ class EmaneManager(ConfigurableManager):
return True
def emanerunning(self, node):
"""
Return True if an EMANE process associated with the given node
is running, False otherwise.
"""
status = -1
cmd = ['pkill', '-0', '-x', 'emane']
try:
if self.version < emane.EMANE092:
status = subprocess.call(cmd)
else:
status = node.cmd(cmd, wait=True)
except IOError:
logger.exception("error checking if emane is running")
return status == 0
class EmaneGlobalModel(EmaneModel):
"""

View file

@ -422,33 +422,34 @@ class BasicRangeModel(WirelessModel):
"""
if netif == netif2:
return
try:
(x, y, z) = self._netifs[netif]
(x2, y2, z2) = self._netifs[netif2]
except KeyError:
return
if x2 is None or y2 is None:
return
d = self.calcdistance((x, y, z), (x2, y2, z2))
# ordering is important, to keep the wlan._linked dict organized
a = min(netif, netif2)
b = max(netif, netif2)
try:
self.wlan._linked_lock.acquire()
linked = self.wlan.linked(a, b)
x, y, z = self._netifs[netif]
x2, y2, z2 = self._netifs[netif2]
if x2 is None or y2 is None:
return
d = self.calcdistance((x, y, z), (x2, y2, z2))
# ordering is important, to keep the wlan._linked dict organized
a = min(netif, netif2)
b = max(netif, netif2)
with self.wlan._linked_lock:
linked = self.wlan.linked(a, b)
logger.info("checking if link distance is out of range: %s > %s", d, self.range)
if d > self.range:
if linked:
self.wlan.unlink(a, b)
self.sendlinkmsg(a, b, unlink=True)
else:
if not linked:
self.wlan.link(a, b)
self.sendlinkmsg(a, b)
except KeyError:
return
finally:
self.wlan._linked_lock.release()
if d > self.range:
if linked:
self.wlan.unlink(a, b)
self.sendlinkmsg(a, b, unlink=True)
else:
if not linked:
self.wlan.link(a, b)
self.sendlinkmsg(a, b)
logger.exception("error getting interfaces during calclinkS")
@staticmethod
def calcdistance(p1, p2):

View file

@ -312,7 +312,7 @@ class WlanNode(LxBrNet):
for netif in self.netifs():
netif.poshook = self.model.position_callback
if netif.node is not None:
(x, y, z) = netif.node.position.get()
x, y, z = netif.node.position.get()
netif.poshook(netif, x, y, z)
self.model.setlinkparams()
elif model.config_type == RegisterTlvs.MOBILITY.value:

View file

@ -8,7 +8,9 @@ import time
from core import constants
from core.coreobj import PyCoreNetIf
from core.enumerations import NodeTypes
from core.misc import log
from core.misc import nodeutils
from core.misc import utils
logger = log.get_logger(__name__)
@ -116,7 +118,20 @@ class TunTap(PyCoreNetIf):
cmd = (constants.IP_BIN, 'link', 'show', self.name)
return self.node.cmd(cmd)
self.waitfor(nodedevexists)
count = 0
while True:
try:
self.waitfor(nodedevexists)
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):
count += 1
else:
raise e
def install(self):
"""

View file

@ -40,8 +40,7 @@ class Sdt(object):
DEFAULT_SDT_URL = "tcp://127.0.0.1:50000/"
# default altitude (in meters) for flyto view
DEFAULT_ALT = 2500
# TODO: read in user's nodes.conf here; below are default node types
# from the GUI
# TODO: read in user's nodes.conf here; below are default node types from the GUI
DEFAULT_SPRITES = [
('router', 'router.gif'), ('host', 'host.gif'),
('PC', 'pc.gif'), ('mdr', 'mdr.gif'),

View file

@ -636,12 +636,9 @@ class Session(object):
with self._objects_lock:
try:
obj = self.objects.pop(object_id)
obj.shutdown()
except KeyError:
logger.error("failed to remove object, object with id was not found: %s", object_id)
obj = None
if obj:
obj.shutdown()
def delete_objects(self):
"""
@ -840,23 +837,6 @@ class Session(object):
logger.info("valid runtime state found, returning")
return
# session_node_count = self.get_node_count()
#
# node_count = self.get_node_count()
# count booted nodes not emulated on this server
# TODO: let slave server determine RUNTIME and wait for Event Message
# broker.getbootocunt() counts all CoreNodes from status reponse
# messages, plus any remote WLANs; remote EMANE, hub, switch, etc.
# are already counted in self._objs
# node_count += self.broker.getbootcount()
# logger.info("Checking for runtime with %d of %d session nodes",
# node_count, session_node_count)
# if node_count < session_node_count:
# return # do not have information on all nodes yet
# information on all nodes has been received and they have been started enter the runtime state
# check to verify that all nodes and networks are running
if not self.broker.instantiation_complete():
return