caught up with latest gitlab commits, added a new tests directory leveraging pytest based tests for testing core functionality
This commit is contained in:
parent
2fc6345138
commit
14cb7dc251
14 changed files with 570 additions and 96 deletions
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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):
|
||||
"""
|
||||
|
|
|
@ -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'),
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue