attempt to fix missing updates for sdt, moved broker specific code to broker
This commit is contained in:
parent
8612c73d49
commit
73eea80f51
11 changed files with 146 additions and 139 deletions
|
@ -34,11 +34,11 @@ from core.netns.vnet import GreTapBridge
|
||||||
from core.phys.pnodes import PhysicalNode
|
from core.phys.pnodes import PhysicalNode
|
||||||
|
|
||||||
|
|
||||||
# TODO: name conflict with main core server, probably should rename
|
class CoreDistributedServer(object):
|
||||||
class CoreServer(object):
|
|
||||||
"""
|
"""
|
||||||
Represents CORE daemon servers for communication.
|
Represents CORE daemon servers for communication.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, name, host, port):
|
def __init__(self, name, host, port):
|
||||||
"""
|
"""
|
||||||
Creates a CoreServer instance.
|
Creates a CoreServer instance.
|
||||||
|
@ -121,6 +121,7 @@ class CoreBroker(ConfigurableManager):
|
||||||
self.physical_nodes = set()
|
self.physical_nodes = set()
|
||||||
# allows for other message handlers to process API messages (e.g. EMANE)
|
# allows for other message handlers to process API messages (e.g. EMANE)
|
||||||
self.handlers = set()
|
self.handlers = set()
|
||||||
|
self.handlers.add(self.handle_distributed)
|
||||||
# dict with tunnel key to tunnel device mapping
|
# dict with tunnel key to tunnel device mapping
|
||||||
self.tunnels = {}
|
self.tunnels = {}
|
||||||
self.dorecvloop = False
|
self.dorecvloop = False
|
||||||
|
@ -223,7 +224,7 @@ class CoreBroker(ConfigurableManager):
|
||||||
and forwarded. Return value of zero indicates the socket has closed
|
and forwarded. Return value of zero indicates the socket has closed
|
||||||
and should be removed from the self.servers dict.
|
and should be removed from the self.servers dict.
|
||||||
|
|
||||||
:param CoreServer server: server to receive from
|
:param CoreDistributedServer server: server to receive from
|
||||||
:return: message length
|
:return: message length
|
||||||
:rtype: int
|
:rtype: int
|
||||||
"""
|
"""
|
||||||
|
@ -302,7 +303,7 @@ class CoreBroker(ConfigurableManager):
|
||||||
del self.servers[name]
|
del self.servers[name]
|
||||||
|
|
||||||
logger.info("adding server: %s @ %s:%s" % (name, host, port))
|
logger.info("adding server: %s @ %s:%s" % (name, host, port))
|
||||||
server = CoreServer(name, host, port)
|
server = CoreDistributedServer(name, host, port)
|
||||||
if host is not None and port is not None:
|
if host is not None and port is not None:
|
||||||
try:
|
try:
|
||||||
server.connect()
|
server.connect()
|
||||||
|
@ -316,7 +317,7 @@ class CoreBroker(ConfigurableManager):
|
||||||
"""
|
"""
|
||||||
Remove a server and hang up any connection.
|
Remove a server and hang up any connection.
|
||||||
|
|
||||||
:param CoreServer server: server to delete
|
:param CoreDistributedServer server: server to delete
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
with self.servers_lock:
|
with self.servers_lock:
|
||||||
|
@ -336,7 +337,7 @@ class CoreBroker(ConfigurableManager):
|
||||||
|
|
||||||
:param str name: name of server to retrieve
|
:param str name: name of server to retrieve
|
||||||
:return: server for given name
|
:return: server for given name
|
||||||
:rtype: CoreServer
|
:rtype: CoreDistributedServer
|
||||||
"""
|
"""
|
||||||
with self.servers_lock:
|
with self.servers_lock:
|
||||||
return self.servers.get(name)
|
return self.servers.get(name)
|
||||||
|
@ -347,7 +348,7 @@ class CoreBroker(ConfigurableManager):
|
||||||
|
|
||||||
:param sock: socket associated with a server
|
:param sock: socket associated with a server
|
||||||
:return: core server associated wit the socket
|
:return: core server associated wit the socket
|
||||||
:rtype: CoreServer
|
:rtype: CoreDistributedServer
|
||||||
"""
|
"""
|
||||||
with self.servers_lock:
|
with self.servers_lock:
|
||||||
for server in self.servers.itervalues():
|
for server in self.servers.itervalues():
|
||||||
|
@ -540,7 +541,7 @@ class CoreBroker(ConfigurableManager):
|
||||||
"""
|
"""
|
||||||
Record a node number to emulation server mapping.
|
Record a node number to emulation server mapping.
|
||||||
|
|
||||||
:param CoreServer server: core server to associate node with
|
:param CoreDistributedServer server: core server to associate node with
|
||||||
:param int nodenum: node id
|
:param int nodenum: node id
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
|
@ -562,7 +563,7 @@ class CoreBroker(ConfigurableManager):
|
||||||
Remove a node number to emulation server mapping.
|
Remove a node number to emulation server mapping.
|
||||||
Return the number of nodes left on this server.
|
Return the number of nodes left on this server.
|
||||||
|
|
||||||
:param CoreServer server: server to remove from node map
|
:param CoreDistributedServer server: server to remove from node map
|
||||||
:param int nodenum: node id
|
:param int nodenum: node id
|
||||||
:return: number of nodes left on server
|
:return: number of nodes left on server
|
||||||
:rtype: int
|
:rtype: int
|
||||||
|
@ -1056,7 +1057,7 @@ class CoreBroker(ConfigurableManager):
|
||||||
VnodeClient class.
|
VnodeClient class.
|
||||||
|
|
||||||
:param str nodestr: node string
|
:param str nodestr: node string
|
||||||
:param CoreServer server: core server
|
:param CoreDistributedServer server: core server
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
serverstr = "%s %s %s" % (server.name, server.host, server.port)
|
serverstr = "%s %s %s" % (server.name, server.host, server.port)
|
||||||
|
@ -1107,3 +1108,62 @@ class CoreBroker(ConfigurableManager):
|
||||||
if not server.instantiation_complete:
|
if not server.instantiation_complete:
|
||||||
return False
|
return False
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
def handle_distributed(self, message):
|
||||||
|
"""
|
||||||
|
Handle the session options config message as it has reached the
|
||||||
|
broker. Options requiring modification for distributed operation should
|
||||||
|
be handled here.
|
||||||
|
|
||||||
|
:param message: message to handle
|
||||||
|
:return: nothing
|
||||||
|
"""
|
||||||
|
if not self.session.master:
|
||||||
|
return
|
||||||
|
|
||||||
|
if message.message_type != MessageTypes.CONFIG.value or message.get_tlv(ConfigTlvs.OBJECT.value) != "session":
|
||||||
|
return
|
||||||
|
|
||||||
|
values_str = message.get_tlv(ConfigTlvs.VALUES.value)
|
||||||
|
if values_str is None:
|
||||||
|
return
|
||||||
|
|
||||||
|
value_strings = values_str.split('|')
|
||||||
|
for value_string in value_strings:
|
||||||
|
key, value = value_string.split('=', 1)
|
||||||
|
if key == "controlnet":
|
||||||
|
self.handle_distributed_control_net(message, value_strings, value_strings.index(value_string))
|
||||||
|
|
||||||
|
def handle_distributed_control_net(self, message, values, index):
|
||||||
|
"""
|
||||||
|
Modify Config Message if multiple control network prefixes are
|
||||||
|
defined. Map server names to prefixes and repack the message before
|
||||||
|
it is forwarded to slave servers.
|
||||||
|
|
||||||
|
:param message: message to handle
|
||||||
|
:param list values: values to handle
|
||||||
|
:param int index: index ti get key value from
|
||||||
|
:return: nothing
|
||||||
|
"""
|
||||||
|
key_value = values[index]
|
||||||
|
key, value = key_value.split('=', 1)
|
||||||
|
control_nets = value.split()
|
||||||
|
|
||||||
|
if len(control_nets) < 2:
|
||||||
|
logger.warn("multiple controlnet prefixes do not exist")
|
||||||
|
return
|
||||||
|
|
||||||
|
servers = self.session.broker.getservernames()
|
||||||
|
if len(servers) < 2:
|
||||||
|
logger.warn("not distributed")
|
||||||
|
return
|
||||||
|
|
||||||
|
servers.remove("localhost")
|
||||||
|
# master always gets first prefix
|
||||||
|
servers.insert(0, "localhost")
|
||||||
|
# create list of "server1:ctrlnet1 server2:ctrlnet2 ..."
|
||||||
|
control_nets = map(lambda x: "%s:%s" % (x[0], x[1]), zip(servers, control_nets))
|
||||||
|
values[index] = "controlnet=%s" % (" ".join(control_nets))
|
||||||
|
values_str = "|".join(values)
|
||||||
|
message.tlvdata[ConfigTlvs.VALUES.value] = values_str
|
||||||
|
message.repack()
|
||||||
|
|
|
@ -301,7 +301,6 @@ class Configurable(object):
|
||||||
:return: tuple of default values
|
:return: tuple of default values
|
||||||
:rtype: tuple
|
:rtype: tuple
|
||||||
"""
|
"""
|
||||||
# TODO: why the need for a tuple?
|
|
||||||
return tuple(map(lambda x: x[2], cls.config_matrix))
|
return tuple(map(lambda x: x[2], cls.config_matrix))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
@ -312,7 +311,6 @@ class Configurable(object):
|
||||||
:return: tuple of name values
|
:return: tuple of name values
|
||||||
:rtype: tuple
|
:rtype: tuple
|
||||||
"""
|
"""
|
||||||
# TODO: why the need for a tuple?
|
|
||||||
return tuple(map(lambda x: x[0], cls.config_matrix))
|
return tuple(map(lambda x: x[0], cls.config_matrix))
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
|
@ -945,8 +945,7 @@ class CoreRequestHandler(SocketServer.BaseRequestHandler):
|
||||||
Remove a link.
|
Remove a link.
|
||||||
"""
|
"""
|
||||||
if node1 and node2:
|
if node1 and node2:
|
||||||
# TODO: fix this for the case where ifindex[1,2] are
|
# TODO: fix this for the case where ifindex[1,2] are not specified
|
||||||
# not specified
|
|
||||||
# a wired unlink event, delete the connecting bridge
|
# a wired unlink event, delete the connecting bridge
|
||||||
netif1 = node1.netif(interface_index1)
|
netif1 = node1.netif(interface_index1)
|
||||||
netif2 = node2.netif(interface_index2)
|
netif2 = node2.netif(interface_index2)
|
||||||
|
@ -1211,7 +1210,7 @@ class CoreRequestHandler(SocketServer.BaseRequestHandler):
|
||||||
# find the session containing this client and set the session to master
|
# find the session containing this client and set the session to master
|
||||||
for session in self.server.sessions.itervalues():
|
for session in self.server.sessions.itervalues():
|
||||||
if self in session.broker.session_clients:
|
if self in session.broker.session_clients:
|
||||||
logger.info("SESSION SET TO MASTER!: %s", session.session_id)
|
logger.info("setting session to master: %s", session.session_id)
|
||||||
session.master = True
|
session.master = True
|
||||||
break
|
break
|
||||||
|
|
||||||
|
@ -1746,8 +1745,6 @@ class BaseAuxRequestHandler(CoreRequestHandler):
|
||||||
messages = self.receive_message()
|
messages = self.receive_message()
|
||||||
if messages:
|
if messages:
|
||||||
for message in messages:
|
for message in messages:
|
||||||
# TODO: do we really want to broadcast node and link messages from a client to other clients?
|
|
||||||
# self.session.broadcast(self, message)
|
|
||||||
self.handle_message(message)
|
self.handle_message(message)
|
||||||
except EOFError:
|
except EOFError:
|
||||||
break
|
break
|
||||||
|
|
|
@ -190,18 +190,21 @@ class PyCoreObj(object):
|
||||||
self.ifindex += 1
|
self.ifindex += 1
|
||||||
return ifindex
|
return ifindex
|
||||||
|
|
||||||
def data(self, message_type):
|
def data(self, message_type, lat=None, lon=None, alt=None):
|
||||||
"""
|
"""
|
||||||
Build a data object for this node.
|
Build a data object for this node.
|
||||||
|
|
||||||
:param message_type: purpose for the data object we are creating
|
: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
|
:return: node data object
|
||||||
:rtype: core.data.NodeData
|
:rtype: core.data.NodeData
|
||||||
"""
|
"""
|
||||||
if self.apitype is None:
|
if self.apitype is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
x, y, z = self.getposition()
|
x, y, _ = self.getposition()
|
||||||
|
|
||||||
model = None
|
model = None
|
||||||
if hasattr(self, "type"):
|
if hasattr(self, "type"):
|
||||||
|
@ -229,6 +232,9 @@ class PyCoreObj(object):
|
||||||
opaque=self.opaque,
|
opaque=self.opaque,
|
||||||
x_position=x,
|
x_position=x,
|
||||||
y_position=y,
|
y_position=y,
|
||||||
|
latitude=lat,
|
||||||
|
longitude=lon,
|
||||||
|
altitude=alt,
|
||||||
model=model,
|
model=model,
|
||||||
emulation_server=emulation_server,
|
emulation_server=emulation_server,
|
||||||
services=services
|
services=services
|
||||||
|
@ -254,7 +260,6 @@ class PyCoreNode(PyCoreObj):
|
||||||
Base class for CORE nodes.
|
Base class for CORE nodes.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# TODO: start seems like it should go away
|
|
||||||
def __init__(self, session, objid=None, name=None, start=True):
|
def __init__(self, session, objid=None, name=None, start=True):
|
||||||
"""
|
"""
|
||||||
Create a PyCoreNode instance.
|
Create a PyCoreNode instance.
|
||||||
|
@ -414,7 +419,6 @@ class PyCoreNet(PyCoreObj):
|
||||||
"""
|
"""
|
||||||
linktype = LinkTypes.WIRED.value
|
linktype = LinkTypes.WIRED.value
|
||||||
|
|
||||||
# TODO: remove start if appropriate
|
|
||||||
def __init__(self, session, objid, name, start=True):
|
def __init__(self, session, objid, name, start=True):
|
||||||
"""
|
"""
|
||||||
Create a PyCoreNet instance.
|
Create a PyCoreNet instance.
|
||||||
|
@ -502,8 +506,6 @@ class PyCoreNet(PyCoreObj):
|
||||||
interface2_ip6 = ipaddress.IpAddress(af=family, address=ipl)
|
interface2_ip6 = ipaddress.IpAddress(af=family, address=ipl)
|
||||||
interface2_ip6_mask = mask
|
interface2_ip6_mask = mask
|
||||||
|
|
||||||
# TODO: not currently used
|
|
||||||
# loss = netif.getparam('loss')
|
|
||||||
link_data = LinkData(
|
link_data = LinkData(
|
||||||
message_type=flags,
|
message_type=flags,
|
||||||
node1_id=self.objid,
|
node1_id=self.objid,
|
||||||
|
|
|
@ -1094,25 +1094,25 @@ class EmaneManager(ConfigurableManager):
|
||||||
alt = attrs["altitude"]
|
alt = attrs["altitude"]
|
||||||
self.handlelocationeventtoxyz(txnemid, lat, long, alt)
|
self.handlelocationeventtoxyz(txnemid, lat, long, alt)
|
||||||
|
|
||||||
def handlelocationeventtoxyz(self, nemid, lat, long, alt):
|
def handlelocationeventtoxyz(self, nemid, lat, lon, alt):
|
||||||
"""
|
"""
|
||||||
Convert the (NEM ID, lat, long, alt) from a received location event
|
Convert the (NEM ID, lat, long, alt) from a received location event
|
||||||
into a node and x,y,z coordinate values, sending a Node Message.
|
into a node and x,y,z coordinate values, sending a Node Message.
|
||||||
Returns True if successfully parsed and a Node Message was sent.
|
Returns True if successfully parsed and a Node Message was sent.
|
||||||
"""
|
"""
|
||||||
# convert nemid to node number
|
# convert nemid to node number
|
||||||
(emanenode, netif) = self.nemlookup(nemid)
|
emanenode, netif = self.nemlookup(nemid)
|
||||||
if netif is None:
|
if netif is None:
|
||||||
logger.info("location event for unknown NEM %s" % nemid)
|
logger.info("location event for unknown NEM %s", nemid)
|
||||||
return False
|
return False
|
||||||
n = netif.node.objid
|
n = netif.node.objid
|
||||||
# convert from lat/long/alt to x,y,z coordinates
|
# convert from lat/long/alt to x,y,z coordinates
|
||||||
x, y, z = self.session.location.getxyz(lat, long, alt)
|
x, y, z = self.session.location.getxyz(lat, lon, alt)
|
||||||
x = int(x)
|
x = int(x)
|
||||||
y = int(y)
|
y = int(y)
|
||||||
z = int(z)
|
z = int(z)
|
||||||
logger.info("location event NEM %s (%s, %s, %s) -> (%s, %s, %s)",
|
logger.info("location event NEM %s (%s, %s, %s) -> (%s, %s, %s)",
|
||||||
nemid, lat, long, alt, x, y, z)
|
nemid, lat, lon, alt, x, y, z)
|
||||||
try:
|
try:
|
||||||
if (x.bit_length() > 16) or (y.bit_length() > 16) or \
|
if (x.bit_length() > 16) or (y.bit_length() > 16) or \
|
||||||
(z.bit_length() > 16) or (x < 0) or (y < 0) or (z < 0):
|
(z.bit_length() > 16) or (x < 0) or (y < 0) or (z < 0):
|
||||||
|
@ -1123,7 +1123,7 @@ class EmaneManager(ConfigurableManager):
|
||||||
return False
|
return False
|
||||||
except AttributeError:
|
except AttributeError:
|
||||||
# int.bit_length() not present on Python 2.6
|
# int.bit_length() not present on Python 2.6
|
||||||
logger.exception("error wusing bit_length")
|
logger.exception("error using bit_length")
|
||||||
|
|
||||||
# generate a node message for this location update
|
# generate a node message for this location update
|
||||||
try:
|
try:
|
||||||
|
@ -1134,12 +1134,9 @@ class EmaneManager(ConfigurableManager):
|
||||||
# don"t use node.setposition(x,y,z) which generates an event
|
# don"t use node.setposition(x,y,z) which generates an event
|
||||||
node.position.set(x, y, z)
|
node.position.set(x, y, z)
|
||||||
|
|
||||||
node_data = node.data(message_type=0)
|
node_data = node.data(message_type=0, lat=lat, lon=lon, alt=alt)
|
||||||
self.session.broadcast_node(node_data)
|
self.session.broadcast_node(node_data)
|
||||||
|
|
||||||
# TODO: determinehow to add SDT handlers
|
|
||||||
# self.session.sdt.updatenodegeo(node.objid, lat, long, alt)
|
|
||||||
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def emanerunning(self, node):
|
def emanerunning(self, node):
|
||||||
|
|
|
@ -607,9 +607,6 @@ class BasicRangeModel(WirelessModel):
|
||||||
link_data = self.create_link_data(netif, netif2, message_type)
|
link_data = self.create_link_data(netif, netif2, message_type)
|
||||||
self.session.broadcast_link(link_data)
|
self.session.broadcast_link(link_data)
|
||||||
|
|
||||||
# TODO: account for SDT wanting to listen as well
|
|
||||||
# self.session.sdt.updatelink(netif.node.objid, netif2.node.objid, flags, wireless=True)
|
|
||||||
|
|
||||||
def all_link_data(self, flags):
|
def all_link_data(self, flags):
|
||||||
"""
|
"""
|
||||||
Return a list of wireless link messages for when the GUI reconnects.
|
Return a list of wireless link messages for when the GUI reconnects.
|
||||||
|
@ -913,9 +910,6 @@ class WayPointMobility(WirelessModel):
|
||||||
node_data = node.data(message_type=0)
|
node_data = node.data(message_type=0)
|
||||||
self.session.broadcast_node(node_data)
|
self.session.broadcast_node(node_data)
|
||||||
|
|
||||||
# TODO: determine how to add handler for SDT
|
|
||||||
# self.session.sdt.updatenode(node.objid, flags=0, x=x, y=y, z=z)
|
|
||||||
|
|
||||||
def setendtime(self):
|
def setendtime(self):
|
||||||
"""
|
"""
|
||||||
Set self.endtime to the time of the last waypoint in the queue of
|
Set self.endtime to the time of the last waypoint in the queue of
|
||||||
|
|
|
@ -249,8 +249,6 @@ class PtpNet(LxBrNet):
|
||||||
interface2_ip6 = ipaddress.IpAddress(af=family, address=ipl)
|
interface2_ip6 = ipaddress.IpAddress(af=family, address=ipl)
|
||||||
interface2_ip6_mask = mask
|
interface2_ip6_mask = mask
|
||||||
|
|
||||||
# TODO: not currently used
|
|
||||||
# loss=netif.getparam("loss")
|
|
||||||
link_data = LinkData(
|
link_data = LinkData(
|
||||||
message_type=flags,
|
message_type=flags,
|
||||||
node1_id=if1.node.objid,
|
node1_id=if1.node.objid,
|
||||||
|
@ -510,7 +508,6 @@ class RJ45Node(PyCoreNode, PyCoreNetIf):
|
||||||
"""
|
"""
|
||||||
PyCoreNetIf.detachnet(self)
|
PyCoreNetIf.detachnet(self)
|
||||||
|
|
||||||
# TODO: parameters are not used
|
|
||||||
def newnetif(self, net=None, addrlist=None, hwaddr=None, ifindex=None, ifname=None):
|
def newnetif(self, net=None, addrlist=None, hwaddr=None, ifindex=None, ifname=None):
|
||||||
"""
|
"""
|
||||||
This is called when linking with another node. Since this node
|
This is called when linking with another node. Since this node
|
||||||
|
|
|
@ -71,6 +71,42 @@ class Sdt(object):
|
||||||
self.remotes = {}
|
self.remotes = {}
|
||||||
session.broker.handlers.add(self.handle_distributed)
|
session.broker.handlers.add(self.handle_distributed)
|
||||||
|
|
||||||
|
# add handler for node updates
|
||||||
|
self.session.node_handlers.append(self.handle_node_update)
|
||||||
|
|
||||||
|
# add handler for link updates
|
||||||
|
self.session.link_handlers.append(self.handle_link_update)
|
||||||
|
|
||||||
|
def handle_node_update(self, node_data):
|
||||||
|
"""
|
||||||
|
Handler for node updates, specifically for updating their location.
|
||||||
|
|
||||||
|
:param core.data.NodeData node_data: node data being updated
|
||||||
|
:return: nothing
|
||||||
|
"""
|
||||||
|
x = node_data.x_position
|
||||||
|
y = node_data.y_position
|
||||||
|
lat = node_data.latitude
|
||||||
|
lon = node_data.longitude
|
||||||
|
alt = node_data.altitude
|
||||||
|
|
||||||
|
if all([lat, lon, alt]):
|
||||||
|
self.updatenodegeo(node_data.id, node_data.latitude, node_data.longitude, node_data.altitude)
|
||||||
|
|
||||||
|
if node_data.message_type == 0:
|
||||||
|
# TODO: z is not currently supported by node messages
|
||||||
|
self.updatenode(node_data.id, 0, x, y, 0)
|
||||||
|
|
||||||
|
def handle_link_update(self, link_data):
|
||||||
|
"""
|
||||||
|
Handler for link updates, checking for wireless link/unlink messages.
|
||||||
|
|
||||||
|
:param core.data.LinkData link_data: link data being updated
|
||||||
|
:return: nothing
|
||||||
|
"""
|
||||||
|
if link_data.link_type == LinkTypes.WIRELESS.value:
|
||||||
|
self.updatelink(link_data.node1_id, link_data.node2_id, link_data.message_type, wireless=True)
|
||||||
|
|
||||||
def is_enabled(self):
|
def is_enabled(self):
|
||||||
"""
|
"""
|
||||||
Check for "enablesdt" session option. Return False by default if
|
Check for "enablesdt" session option. Return False by default if
|
||||||
|
@ -180,6 +216,7 @@ class Sdt(object):
|
||||||
|
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
|
logger.info("SDT shutdown!")
|
||||||
self.cmd("clear all")
|
self.cmd("clear all")
|
||||||
self.disconnect()
|
self.disconnect()
|
||||||
self.showerror = True
|
self.showerror = True
|
||||||
|
@ -227,8 +264,8 @@ class Sdt(object):
|
||||||
return
|
return
|
||||||
if x is None or y is None:
|
if x is None or y is None:
|
||||||
return
|
return
|
||||||
lat, long, alt = self.session.location.getgeo(x, y, z)
|
lat, lon, alt = self.session.location.getgeo(x, y, z)
|
||||||
pos = "pos %.6f,%.6f,%.6f" % (long, lat, alt)
|
pos = "pos %.6f,%.6f,%.6f" % (lon, lat, alt)
|
||||||
if flags & MessageFlags.ADD.value:
|
if flags & MessageFlags.ADD.value:
|
||||||
if icon is not None:
|
if icon is not None:
|
||||||
type = name
|
type = name
|
||||||
|
@ -327,7 +364,6 @@ class Sdt(object):
|
||||||
for n2num, wl in r.links:
|
for n2num, wl in r.links:
|
||||||
self.updatelink(n1num, n2num, MessageFlags.ADD.value, wl)
|
self.updatelink(n1num, n2num, MessageFlags.ADD.value, wl)
|
||||||
|
|
||||||
# TODO: remove the need for this
|
|
||||||
def handle_distributed(self, message):
|
def handle_distributed(self, message):
|
||||||
"""
|
"""
|
||||||
Broker handler for processing CORE API messages as they are
|
Broker handler for processing CORE API messages as they are
|
||||||
|
@ -342,7 +378,6 @@ class Sdt(object):
|
||||||
elif message.message_type == MessageTypes.NODE.value:
|
elif message.message_type == MessageTypes.NODE.value:
|
||||||
return self.handlenodemsg(message)
|
return self.handlenodemsg(message)
|
||||||
|
|
||||||
# TODO: remove the need for this
|
|
||||||
def handlenodemsg(self, msg):
|
def handlenodemsg(self, msg):
|
||||||
"""
|
"""
|
||||||
Process a Node Message to add/delete or move a node on
|
Process a Node Message to add/delete or move a node on
|
||||||
|
@ -403,7 +438,6 @@ class Sdt(object):
|
||||||
remote.pos = (x, y, z)
|
remote.pos = (x, y, z)
|
||||||
self.updatenode(nodenum, msg.flags, x, y, z, name, type, icon)
|
self.updatenode(nodenum, msg.flags, x, y, z, name, type, icon)
|
||||||
|
|
||||||
# TODO: remove the need for this
|
|
||||||
def handlelinkmsg(self, msg):
|
def handlelinkmsg(self, msg):
|
||||||
"""
|
"""
|
||||||
Process a Link Message to add/remove links on the SDT display.
|
Process a Link Message to add/remove links on the SDT display.
|
||||||
|
|
|
@ -867,7 +867,8 @@ class CoreServices(ConfigurableManager):
|
||||||
if len(cfgfiles) > 0:
|
if len(cfgfiles) > 0:
|
||||||
for filename in cfgfiles:
|
for filename in cfgfiles:
|
||||||
if filename[:7] == "file:///":
|
if filename[:7] == "file:///":
|
||||||
raise NotImplementedError # TODO
|
# TODO: implement this
|
||||||
|
raise NotImplementedError
|
||||||
cfg = self.getservicefiledata(s, filename)
|
cfg = self.getservicefiledata(s, filename)
|
||||||
if cfg is None:
|
if cfg is None:
|
||||||
cfg = s.generateconfig(node, filename, services)
|
cfg = s.generateconfig(node, filename, services)
|
||||||
|
|
|
@ -27,13 +27,11 @@ from core.data import EventData
|
||||||
from core.data import ExceptionData
|
from core.data import ExceptionData
|
||||||
from core.data import FileData
|
from core.data import FileData
|
||||||
from core.emane.emanemanager import EmaneManager
|
from core.emane.emanemanager import EmaneManager
|
||||||
from core.enumerations import ConfigDataTypes, EventTlvs
|
from core.enumerations import ConfigDataTypes
|
||||||
from core.enumerations import ConfigFlags
|
from core.enumerations import ConfigFlags
|
||||||
from core.enumerations import ConfigTlvs
|
|
||||||
from core.enumerations import EventTypes
|
from core.enumerations import EventTypes
|
||||||
from core.enumerations import ExceptionLevels
|
from core.enumerations import ExceptionLevels
|
||||||
from core.enumerations import MessageFlags
|
from core.enumerations import MessageFlags
|
||||||
from core.enumerations import MessageTypes
|
|
||||||
from core.enumerations import NodeTypes
|
from core.enumerations import NodeTypes
|
||||||
from core.enumerations import RegisterTlvs
|
from core.enumerations import RegisterTlvs
|
||||||
from core.location import CoreLocation
|
from core.location import CoreLocation
|
||||||
|
@ -156,6 +154,15 @@ class Session(object):
|
||||||
|
|
||||||
self.master = False
|
self.master = False
|
||||||
|
|
||||||
|
# handlers for broadcasting information
|
||||||
|
self.event_handlers = []
|
||||||
|
self.exception_handlers = []
|
||||||
|
self.node_handlers = []
|
||||||
|
self.link_handlers = []
|
||||||
|
self.file_handlers = []
|
||||||
|
self.config_handlers = []
|
||||||
|
self.shutdown_handlers = []
|
||||||
|
|
||||||
# setup broker
|
# setup broker
|
||||||
self.broker = CoreBroker(session=self)
|
self.broker = CoreBroker(session=self)
|
||||||
self.add_config_object(CoreBroker.name, CoreBroker.config_type, self.broker.configure)
|
self.add_config_object(CoreBroker.name, CoreBroker.config_type, self.broker.configure)
|
||||||
|
@ -192,15 +199,6 @@ class Session(object):
|
||||||
self.metadata = SessionMetaData()
|
self.metadata = SessionMetaData()
|
||||||
self.add_config_object(SessionMetaData.name, SessionMetaData.config_type, self.metadata.configure)
|
self.add_config_object(SessionMetaData.name, SessionMetaData.config_type, self.metadata.configure)
|
||||||
|
|
||||||
# handlers for broadcasting information
|
|
||||||
self.event_handlers = []
|
|
||||||
self.exception_handlers = []
|
|
||||||
self.node_handlers = []
|
|
||||||
self.link_handlers = []
|
|
||||||
self.file_handlers = []
|
|
||||||
self.config_handlers = []
|
|
||||||
self.shutdown_handlers = []
|
|
||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
"""
|
"""
|
||||||
Shutdown all emulation objects and remove the session directory.
|
Shutdown all emulation objects and remove the session directory.
|
||||||
|
@ -326,10 +324,6 @@ class Session(object):
|
||||||
event_data = EventData(event_type=state, time="%s" % time.time())
|
event_data = EventData(event_type=state, time="%s" % time.time())
|
||||||
self.broadcast_event(event_data)
|
self.broadcast_event(event_data)
|
||||||
|
|
||||||
# also inform slave servers
|
|
||||||
# TODO: deal with broker, potentially broker should really live within the core server/handlers
|
|
||||||
# self.broker.handlerawmsg(message)
|
|
||||||
|
|
||||||
def write_state(self, state):
|
def write_state(self, state):
|
||||||
"""
|
"""
|
||||||
Write the current state to a state file in the session dir.
|
Write the current state to a state file in the session dir.
|
||||||
|
@ -915,8 +909,7 @@ class Session(object):
|
||||||
if node_count == 0:
|
if node_count == 0:
|
||||||
shutdown = True
|
shutdown = True
|
||||||
self.set_state(state=EventTypes.SHUTDOWN_STATE.value)
|
self.set_state(state=EventTypes.SHUTDOWN_STATE.value)
|
||||||
# TODO: this seems redundant as it occurs during shutdown as well
|
|
||||||
self.sdt.shutdown()
|
|
||||||
return shutdown
|
return shutdown
|
||||||
|
|
||||||
def short_session_id(self):
|
def short_session_id(self):
|
||||||
|
@ -935,16 +928,13 @@ class Session(object):
|
||||||
"""
|
"""
|
||||||
with self._objects_lock:
|
with self._objects_lock:
|
||||||
for obj in self.objects.itervalues():
|
for obj in self.objects.itervalues():
|
||||||
# TODO: determine instance type we need to check, due to method issue below
|
# TODO: PyCoreNode is not the type to check, but there are two types, due to bsd and netns
|
||||||
if isinstance(obj, nodes.PyCoreNode) and not nodeutils.is_node(obj, NodeTypes.RJ45):
|
if isinstance(obj, nodes.PyCoreNode) and not nodeutils.is_node(obj, NodeTypes.RJ45):
|
||||||
# add a control interface if configured
|
# add a control interface if configured
|
||||||
logger.info("booting node: %s - %s", obj.objid, obj.name)
|
logger.info("booting node: %s - %s", obj.objid, obj.name)
|
||||||
self.add_remove_control_interface(node=obj, remove=False)
|
self.add_remove_control_interface(node=obj, remove=False)
|
||||||
obj.boot()
|
obj.boot()
|
||||||
|
|
||||||
# TODO(blake): send node emu ids back
|
|
||||||
# self.sendnodeemuid(obj.objid)
|
|
||||||
|
|
||||||
self.update_control_interface_hosts()
|
self.update_control_interface_hosts()
|
||||||
|
|
||||||
def validate_nodes(self):
|
def validate_nodes(self):
|
||||||
|
@ -955,7 +945,7 @@ class Session(object):
|
||||||
"""
|
"""
|
||||||
with self._objects_lock:
|
with self._objects_lock:
|
||||||
for obj in self.objects.itervalues():
|
for obj in self.objects.itervalues():
|
||||||
# TODO: this can be extended to validate everything, bad node check here as well
|
# TODO: issues with checking PyCoreNode alone, validate is not a method
|
||||||
# such as vnoded process, bridges, etc.
|
# such as vnoded process, bridges, etc.
|
||||||
if not isinstance(obj, nodes.PyCoreNode):
|
if not isinstance(obj, nodes.PyCoreNode):
|
||||||
continue
|
continue
|
||||||
|
@ -1015,7 +1005,7 @@ class Session(object):
|
||||||
return -1
|
return -1
|
||||||
|
|
||||||
def get_control_net_object(self, net_index):
|
def get_control_net_object(self, net_index):
|
||||||
# TODO: all nodes use an integer id and now this wants to use a string =(
|
# TODO: all nodes use an integer id and now this wants to use a string
|
||||||
object_id = "ctrl%dnet" % net_index
|
object_id = "ctrl%dnet" % net_index
|
||||||
return self.get_object(object_id)
|
return self.get_object(object_id)
|
||||||
|
|
||||||
|
@ -1123,7 +1113,8 @@ class Session(object):
|
||||||
updown_script=updown_script, serverintf=server_interface)
|
updown_script=updown_script, serverintf=server_interface)
|
||||||
|
|
||||||
# tunnels between controlnets will be built with Broker.addnettunnels()
|
# tunnels between controlnets will be built with Broker.addnettunnels()
|
||||||
# TODO: potentialy remove documentation saying object ids are ints
|
# TODO: potentially remove documentation saying object ids are ints
|
||||||
|
# TODO: need to move broker code out of the session object
|
||||||
self.broker.addnet(object_id)
|
self.broker.addnet(object_id)
|
||||||
for server in self.broker.getservers():
|
for server in self.broker.getservers():
|
||||||
self.broker.addnodemap(server, object_id)
|
self.broker.addnodemap(server, object_id)
|
||||||
|
@ -1377,7 +1368,6 @@ class SessionConfig(ConfigurableManager, Configurable):
|
||||||
"""
|
"""
|
||||||
ConfigurableManager.__init__(self)
|
ConfigurableManager.__init__(self)
|
||||||
self.session = session
|
self.session = session
|
||||||
self.session.broker.handlers.add(self.handle_distributed)
|
|
||||||
self.reset()
|
self.reset()
|
||||||
|
|
||||||
def reset(self):
|
def reset(self):
|
||||||
|
@ -1423,70 +1413,6 @@ class SessionConfig(ConfigurableManager, Configurable):
|
||||||
|
|
||||||
return self.config_data(0, node_id, type_flags, values)
|
return self.config_data(0, node_id, type_flags, values)
|
||||||
|
|
||||||
# TODO: update logic to not be tied to old style messages
|
|
||||||
def handle_distributed(self, message):
|
|
||||||
"""
|
|
||||||
Handle the session options config message as it has reached the
|
|
||||||
broker. Options requiring modification for distributed operation should
|
|
||||||
be handled here.
|
|
||||||
|
|
||||||
:param message: message to handle
|
|
||||||
:return: nothing
|
|
||||||
"""
|
|
||||||
if not self.session.master:
|
|
||||||
return
|
|
||||||
|
|
||||||
if message.message_type != MessageTypes.CONFIG.value or message.get_tlv(ConfigTlvs.OBJECT.value) != "session":
|
|
||||||
return
|
|
||||||
|
|
||||||
values_str = message.get_tlv(ConfigTlvs.VALUES.value)
|
|
||||||
if values_str is None:
|
|
||||||
return
|
|
||||||
|
|
||||||
value_strings = values_str.split('|')
|
|
||||||
if not self.haskeyvalues(value_strings):
|
|
||||||
return
|
|
||||||
|
|
||||||
for value_string in value_strings:
|
|
||||||
key, value = value_string.split('=', 1)
|
|
||||||
if key == "controlnet":
|
|
||||||
self.handle_distributed_control_net(message, value_strings, value_strings.index(value_string))
|
|
||||||
|
|
||||||
# TODO: update logic to not be tied to old style messages
|
|
||||||
def handle_distributed_control_net(self, message, values, index):
|
|
||||||
"""
|
|
||||||
Modify Config Message if multiple control network prefixes are
|
|
||||||
defined. Map server names to prefixes and repack the message before
|
|
||||||
it is forwarded to slave servers.
|
|
||||||
|
|
||||||
:param message: message to handle
|
|
||||||
:param list values: values to handle
|
|
||||||
:param int index: index ti get key value from
|
|
||||||
:return: nothing
|
|
||||||
"""
|
|
||||||
key_value = values[index]
|
|
||||||
key, value = key_value.split('=', 1)
|
|
||||||
control_nets = value.split()
|
|
||||||
|
|
||||||
if len(control_nets) < 2:
|
|
||||||
logger.warn("multiple controlnet prefixes do not exist")
|
|
||||||
return
|
|
||||||
|
|
||||||
servers = self.session.broker.getservernames()
|
|
||||||
if len(servers) < 2:
|
|
||||||
logger.warn("not distributed")
|
|
||||||
return
|
|
||||||
|
|
||||||
servers.remove("localhost")
|
|
||||||
# master always gets first prefix
|
|
||||||
servers.insert(0, "localhost")
|
|
||||||
# create list of "server1:ctrlnet1 server2:ctrlnet2 ..."
|
|
||||||
control_nets = map(lambda x: "%s:%s" % (x[0], x[1]), zip(servers, control_nets))
|
|
||||||
values[index] = "controlnet=%s" % (" ".join(control_nets))
|
|
||||||
values_str = "|".join(values)
|
|
||||||
message.tlvdata[ConfigTlvs.VALUES.value] = values_str
|
|
||||||
message.repack()
|
|
||||||
|
|
||||||
|
|
||||||
class SessionMetaData(ConfigurableManager):
|
class SessionMetaData(ConfigurableManager):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -296,7 +296,8 @@ def exec_file(cfg):
|
||||||
tlvdata = coreapi.CoreRegisterTlv.pack(RegisterTlvs.EXECUTE_SERVER.value, filename)
|
tlvdata = coreapi.CoreRegisterTlv.pack(RegisterTlvs.EXECUTE_SERVER.value, filename)
|
||||||
msg = coreapi.CoreRegMessage.pack(MessageFlags.ADD.value, tlvdata)
|
msg = coreapi.CoreRegMessage.pack(MessageFlags.ADD.value, tlvdata)
|
||||||
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||||
sock.connect(("localhost", int(cfg["port"]))) # TODO: connect address option
|
# TODO: connect address option
|
||||||
|
sock.connect(("localhost", int(cfg["port"])))
|
||||||
sock.sendall(msg)
|
sock.sendall(msg)
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue