attempt to fix missing updates for sdt, moved broker specific code to broker

This commit is contained in:
Blake J. Harnden 2017-08-07 15:37:41 -07:00
parent 8612c73d49
commit 73eea80f51
11 changed files with 146 additions and 139 deletions

View file

@ -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()

View file

@ -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

View file

@ -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

View file

@ -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,

View file

@ -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):

View file

@ -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

View file

@ -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

View file

@ -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.

View file

@ -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)

View file

@ -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):
""" """

View file

@ -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