moved future core server and handler code to act as the default core-daemon, updated future examples and tests to leverage new api
This commit is contained in:
parent
f431895357
commit
8644e9d61e
24 changed files with 618 additions and 2728 deletions
File diff suppressed because it is too large
Load diff
|
@ -1,263 +0,0 @@
|
|||
"""
|
||||
Defines server classes and request handlers for TCP and UDP.
|
||||
"""
|
||||
|
||||
import SocketServer
|
||||
import threading
|
||||
import time
|
||||
|
||||
from core import logger
|
||||
from core.api import coreapi
|
||||
from core.enumerations import EventTypes
|
||||
from core.enumerations import SessionTlvs
|
||||
from core.session import Session
|
||||
|
||||
|
||||
class CoreServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
|
||||
"""
|
||||
TCP server class, manages sessions and spawns request handlers for
|
||||
incoming connections.
|
||||
"""
|
||||
daemon_threads = True
|
||||
allow_reuse_address = True
|
||||
servers = set()
|
||||
|
||||
def __init__(self, server_address, handler_class, config=None):
|
||||
"""
|
||||
Server class initialization takes configuration data and calls
|
||||
the SocketServer constructor
|
||||
|
||||
:param tuple[str, int] server_address: server host and port to use
|
||||
:param class handler_class: request handler
|
||||
:param dict config: configuration setting
|
||||
:return:
|
||||
"""
|
||||
self.config = config
|
||||
self.sessions = {}
|
||||
self.udpserver = None
|
||||
self.udpthread = None
|
||||
self._sessions_lock = threading.Lock()
|
||||
CoreServer.add_server(self)
|
||||
SocketServer.TCPServer.__init__(self, server_address, handler_class)
|
||||
|
||||
@classmethod
|
||||
def add_server(cls, server):
|
||||
"""
|
||||
Add a core server to the known servers set.
|
||||
|
||||
:param CoreServer server: server to add
|
||||
:return: nothing
|
||||
"""
|
||||
cls.servers.add(server)
|
||||
|
||||
@classmethod
|
||||
def remove_server(cls, server):
|
||||
"""
|
||||
Remove a core server from the known servers set.
|
||||
|
||||
:param CoreServer server: server to remove
|
||||
:return: nothing
|
||||
"""
|
||||
if server in cls.servers:
|
||||
cls.servers.remove(server)
|
||||
|
||||
def shutdown(self):
|
||||
"""
|
||||
Shutdown the server, all known sessions, and remove server from known servers set.
|
||||
|
||||
:return: nothing
|
||||
"""
|
||||
# shutdown all known sessions
|
||||
for session in self.sessions.values():
|
||||
session.shutdown()
|
||||
|
||||
# remove server from server list
|
||||
CoreServer.remove_server(self)
|
||||
|
||||
def add_session(self, session):
|
||||
"""
|
||||
Add a session to our dictionary of sessions, ensuring a unique session number.
|
||||
|
||||
:param core.session.Session session: session to add
|
||||
:return: added session
|
||||
:raise KeyError: when a session with the same id already exists
|
||||
"""
|
||||
with self._sessions_lock:
|
||||
if session.session_id in self.sessions:
|
||||
raise KeyError("non-unique session id %s for %s" % (session.session_id, session))
|
||||
self.sessions[session.session_id] = session
|
||||
|
||||
return session
|
||||
|
||||
def remove_session(self, session):
|
||||
"""
|
||||
Remove a session from our dictionary of sessions.
|
||||
|
||||
:param core.session.Session session: session to remove
|
||||
:return: removed session
|
||||
:rtype: core.session.Session
|
||||
"""
|
||||
with self._sessions_lock:
|
||||
if session.session_id not in self.sessions:
|
||||
logger.info("session id %s not found (sessions=%s)", session.session_id, self.sessions.keys())
|
||||
else:
|
||||
del self.sessions[session.session_id]
|
||||
|
||||
return session
|
||||
|
||||
def get_session_ids(self):
|
||||
"""
|
||||
Return a list of active session numbers.
|
||||
|
||||
:return: known session ids
|
||||
:rtype: list
|
||||
"""
|
||||
with self._sessions_lock:
|
||||
session_ids = self.sessions.keys()
|
||||
|
||||
return session_ids
|
||||
|
||||
def create_session(self, session_id=None):
|
||||
"""
|
||||
Convenience method for creating sessions with the servers config.
|
||||
|
||||
:param int session_id: session id for new session
|
||||
:return: create session
|
||||
:rtype: core.session.Session
|
||||
"""
|
||||
|
||||
# create random id when necessary, seems to be 1 case wanted, based on legacy code
|
||||
# creating a value so high, typical client side generation schemes hopefully wont collide
|
||||
if not session_id:
|
||||
session_id = next(
|
||||
session_id for session_id in xrange(60000, 65000)
|
||||
if session_id not in self.sessions
|
||||
)
|
||||
|
||||
# create and add session to local manager
|
||||
session = Session(session_id, config=self.config)
|
||||
self.add_session(session)
|
||||
|
||||
# add shutdown handler to remove session from manager
|
||||
session.shutdown_handlers.append(self.session_shutdown)
|
||||
|
||||
return session
|
||||
|
||||
def get_session(self, session_id=None):
|
||||
"""
|
||||
Create a new session or retrieve an existing one from our
|
||||
dictionary of sessions. When the session_id=0 and the use_existing
|
||||
flag is set, return on of the existing sessions.
|
||||
|
||||
:param int session_id: session id of session to retrieve, defaults to returning random session
|
||||
:return: session
|
||||
:rtype: core.session.Session
|
||||
"""
|
||||
|
||||
with self._sessions_lock:
|
||||
# return specified session or none
|
||||
if session_id:
|
||||
return self.sessions.get(session_id)
|
||||
|
||||
# retrieving known session
|
||||
session = None
|
||||
|
||||
# find runtime session with highest node count
|
||||
for known_session in filter(lambda x: x.state == EventTypes.RUNTIME_STATE.value,
|
||||
self.sessions.itervalues()):
|
||||
if not session or known_session.get_node_count() > session.get_node_count():
|
||||
session = known_session
|
||||
|
||||
# return first known session otherwise
|
||||
if not session:
|
||||
for known_session in self.sessions.itervalues():
|
||||
session = known_session
|
||||
break
|
||||
|
||||
return session
|
||||
|
||||
def session_shutdown(self, session):
|
||||
"""
|
||||
Handler method to be used as a callback when a session has shutdown.
|
||||
|
||||
:param core.session.Session session: session shutting down
|
||||
:return: nothing
|
||||
"""
|
||||
self.remove_session(session)
|
||||
|
||||
def to_session_message(self, flags=0):
|
||||
"""
|
||||
Build CORE API Sessions message based on current session info.
|
||||
|
||||
:param int flags: message flags
|
||||
:return: session message
|
||||
"""
|
||||
id_list = []
|
||||
name_list = []
|
||||
file_list = []
|
||||
node_count_list = []
|
||||
date_list = []
|
||||
thumb_list = []
|
||||
num_sessions = 0
|
||||
|
||||
with self._sessions_lock:
|
||||
for session_id in self.sessions:
|
||||
session = self.sessions[session_id]
|
||||
# debug: session.dumpsession()
|
||||
num_sessions += 1
|
||||
id_list.append(str(session_id))
|
||||
|
||||
name = session.name
|
||||
if not name:
|
||||
name = ""
|
||||
name_list.append(name)
|
||||
|
||||
file = session.file_name
|
||||
if not file:
|
||||
file = ""
|
||||
file_list.append(file)
|
||||
|
||||
node_count_list.append(str(session.get_node_count()))
|
||||
|
||||
date_list.append(time.ctime(session._state_time))
|
||||
|
||||
thumb = session.thumbnail
|
||||
if not thumb:
|
||||
thumb = ""
|
||||
thumb_list.append(thumb)
|
||||
|
||||
session_ids = "|".join(id_list)
|
||||
names = "|".join(name_list)
|
||||
files = "|".join(file_list)
|
||||
node_counts = "|".join(node_count_list)
|
||||
dates = "|".join(date_list)
|
||||
thumbs = "|".join(thumb_list)
|
||||
|
||||
if num_sessions > 0:
|
||||
tlv_data = ""
|
||||
if len(session_ids) > 0:
|
||||
tlv_data += coreapi.CoreSessionTlv.pack(SessionTlvs.NUMBER.value, session_ids)
|
||||
if len(names) > 0:
|
||||
tlv_data += coreapi.CoreSessionTlv.pack(SessionTlvs.NAME.value, names)
|
||||
if len(files) > 0:
|
||||
tlv_data += coreapi.CoreSessionTlv.pack(SessionTlvs.FILE.value, files)
|
||||
if len(node_counts) > 0:
|
||||
tlv_data += coreapi.CoreSessionTlv.pack(SessionTlvs.NODE_COUNT.value, node_counts)
|
||||
if len(dates) > 0:
|
||||
tlv_data += coreapi.CoreSessionTlv.pack(SessionTlvs.DATE.value, dates)
|
||||
if len(thumbs) > 0:
|
||||
tlv_data += coreapi.CoreSessionTlv.pack(SessionTlvs.THUMB.value, thumbs)
|
||||
message = coreapi.CoreSessionMessage.pack(flags, tlv_data)
|
||||
else:
|
||||
message = None
|
||||
|
||||
return message
|
||||
|
||||
def dump_sessions(self):
|
||||
"""
|
||||
Log currently known session information.
|
||||
"""
|
||||
logger.info("sessions:")
|
||||
with self._sessions_lock:
|
||||
for session_id in self.sessions:
|
||||
logger.info(session_id)
|
|
@ -195,6 +195,9 @@ class FutureSession(Session):
|
|||
raise ValueError("wireless link failure: %s", objects)
|
||||
logger.info("handling wireless linking objects(%) connect(%s)", objects, connect)
|
||||
common_networks = objects[0].commonnets(objects[1])
|
||||
if not common_networks:
|
||||
raise ValueError("no common network found for wireless link/unlink")
|
||||
|
||||
for common_network, interface_one, interface_two in common_networks:
|
||||
if not nodeutils.is_node(common_network, [NodeTypes.WIRELESS_LAN, NodeTypes.EMANE]):
|
||||
logger.info("skipping common network that is not wireless/emane: %s", common_network)
|
||||
|
@ -205,8 +208,6 @@ class FutureSession(Session):
|
|||
common_network.link(interface_one, interface_two)
|
||||
else:
|
||||
common_network.unlink(interface_one, interface_two)
|
||||
else:
|
||||
raise ValueError("no common network found for wireless link/unlink")
|
||||
|
||||
def add_link(self, node_one_id, node_two_id, interface_one=None, interface_two=None, link_options=LinkOptions()):
|
||||
"""
|
||||
|
@ -429,15 +430,17 @@ class FutureSession(Session):
|
|||
link_config(net_one, interface, link_options)
|
||||
else:
|
||||
common_networks = node_one.commonnets(node_two)
|
||||
if not common_networks:
|
||||
raise ValueError("no common network found")
|
||||
|
||||
for net_one, interface_one, interface_two in common_networks:
|
||||
if interface_one_id and interface_one_id != node_one.getifindex(interface_one):
|
||||
if interface_one_id is not None and interface_one_id != node_one.getifindex(interface_one):
|
||||
continue
|
||||
|
||||
link_config(net_one, interface_one, link_options, interface_two=interface_two)
|
||||
if not link_options.unidirectional:
|
||||
link_config(net_one, interface_two, link_options, interface_two=interface_one)
|
||||
else:
|
||||
raise ValueError("no common network found")
|
||||
|
||||
finally:
|
||||
if node_one:
|
||||
node_one.lock.release()
|
||||
|
@ -610,8 +613,8 @@ class FutureSession(Session):
|
|||
|
||||
:return: nothing
|
||||
"""
|
||||
self.set_state(state=EventTypes.DATACOLLECT_STATE.value, send_event=True)
|
||||
self.set_state(state=EventTypes.SHUTDOWN_STATE.value, send_event=True)
|
||||
self.set_state(EventTypes.DATACOLLECT_STATE, send_event=True)
|
||||
self.set_state(EventTypes.SHUTDOWN_STATE, send_event=True)
|
||||
super(FutureSession, self).shutdown()
|
||||
|
||||
def custom_delete_object(self, object_id):
|
||||
|
@ -753,9 +756,9 @@ class FutureSession(Session):
|
|||
"""
|
||||
self.mobility.handleevent(event_data)
|
||||
|
||||
def create_emane_node(self, _id=None, node_options=NodeOptions()):
|
||||
def create_wireless_node(self, _id=None, node_options=NodeOptions()):
|
||||
"""
|
||||
Create an EMANE node for use within an EMANE network.
|
||||
Create a wireless node for use within an wireless/EMANE networks.
|
||||
|
||||
:param int _id: int for node, defaults to None and will be generated
|
||||
:param core.future.futuredata.NodeOptions node_options: options for emane node, model will always be "mdr"
|
||||
|
@ -796,6 +799,29 @@ class FutureSession(Session):
|
|||
values = list(emane_model.getdefaultvalues())
|
||||
self.emane.setconfig(emane_node.objid, emane_model.name, values)
|
||||
|
||||
def set_wireless_model(self, node, model):
|
||||
"""
|
||||
Convenience method for setting a wireless model.
|
||||
|
||||
:param node: node to set wireless model for
|
||||
:param core.mobility.WirelessModel model: wireless model to set node to
|
||||
:return: nothing
|
||||
"""
|
||||
values = list(model.getdefaultvalues())
|
||||
node.setmodel(model, values)
|
||||
|
||||
def wireless_link_all(self, network, nodes):
|
||||
"""
|
||||
Link all nodes to the provided wireless network.
|
||||
|
||||
:param network: wireless network to link nodes to
|
||||
:param nodes: nodes to link to wireless network
|
||||
:return: nothing
|
||||
"""
|
||||
for node in nodes:
|
||||
for common_network, interface_one, interface_two in node.commonnets(network):
|
||||
common_network.link(interface_one, interface_two)
|
||||
|
||||
|
||||
class CoreEmu(object):
|
||||
"""
|
||||
|
@ -876,26 +902,3 @@ class CoreEmu(object):
|
|||
logger.error("session to delete did not exist: %s", _id)
|
||||
|
||||
return result
|
||||
|
||||
def set_wireless_model(self, node, model):
|
||||
"""
|
||||
Convenience method for setting a wireless model.
|
||||
|
||||
:param node: node to set wireless model for
|
||||
:param core.mobility.WirelessModel model: wireless model to set node to
|
||||
:return: nothing
|
||||
"""
|
||||
values = list(model.getdefaultvalues())
|
||||
node.setmodel(model, values)
|
||||
|
||||
def wireless_link_all(self, network, nodes):
|
||||
"""
|
||||
Link all nodes to the provided wireless network.
|
||||
|
||||
:param network: wireless network to link nodes to
|
||||
:param nodes: nodes to link to wireless network
|
||||
:return: nothing
|
||||
"""
|
||||
for node in nodes:
|
||||
for common_network, interface_one, interface_two in node.commonnets(network):
|
||||
common_network.link(interface_one, interface_two)
|
||||
|
|
0
daemon/core/legacy/__init__.py
Normal file
0
daemon/core/legacy/__init__.py
Normal file
|
@ -13,29 +13,31 @@ import time
|
|||
|
||||
from core import logger
|
||||
from core.api import coreapi
|
||||
from core.coreserver import CoreServer
|
||||
from core.data import ConfigData
|
||||
from core.data import EventData
|
||||
from core.enumerations import ConfigTlvs, LinkTypes
|
||||
from core.enumerations import ConfigTlvs
|
||||
from core.enumerations import EventTlvs
|
||||
from core.enumerations import EventTypes
|
||||
from core.enumerations import ExceptionTlvs
|
||||
from core.enumerations import ExecuteTlvs
|
||||
from core.enumerations import FileTlvs
|
||||
from core.enumerations import LinkTlvs
|
||||
from core.enumerations import LinkTypes
|
||||
from core.enumerations import MessageFlags
|
||||
from core.enumerations import MessageTypes
|
||||
from core.enumerations import NodeTlvs
|
||||
from core.enumerations import NodeTypes
|
||||
from core.enumerations import RegisterTlvs
|
||||
from core.enumerations import SessionTlvs
|
||||
from core.future.futuredata import NodeOptions, LinkOptions, InterfaceData
|
||||
from core.future.futuredata import InterfaceData
|
||||
from core.future.futuredata import LinkOptions
|
||||
from core.future.futuredata import NodeOptions
|
||||
from core.misc import nodeutils
|
||||
from core.misc import structutils
|
||||
from core.misc import utils
|
||||
|
||||
|
||||
class FutureHandler(SocketServer.BaseRequestHandler):
|
||||
class CoreHandler(SocketServer.BaseRequestHandler):
|
||||
"""
|
||||
The SocketServer class uses the RequestHandler class for servicing requests.
|
||||
"""
|
||||
|
@ -578,7 +580,7 @@ class FutureHandler(SocketServer.BaseRequestHandler):
|
|||
self.add_session_handlers()
|
||||
|
||||
# set initial session state
|
||||
self.session.set_state(state=EventTypes.DEFINITION_STATE.value)
|
||||
self.session.set_state(EventTypes.DEFINITION_STATE)
|
||||
|
||||
while True:
|
||||
try:
|
||||
|
@ -1032,13 +1034,13 @@ class FutureHandler(SocketServer.BaseRequestHandler):
|
|||
session=message.get_tlv(EventTlvs.SESSION.value)
|
||||
)
|
||||
|
||||
event_type = event_data.event_type
|
||||
if event_type is None:
|
||||
if event_data.event_type is None:
|
||||
raise NotImplementedError("Event message missing event type")
|
||||
event_type = EventTypes(event_data.event_type)
|
||||
node_id = event_data.node
|
||||
|
||||
logger.info("EVENT %d: %s at %s", event_type, EventTypes(event_type).name, time.ctime())
|
||||
if event_type <= EventTypes.SHUTDOWN_STATE.value:
|
||||
logger.info("EVENT %s at %s", event_type.name, time.ctime())
|
||||
if event_type.value <= EventTypes.SHUTDOWN_STATE.value:
|
||||
if node_id is not None:
|
||||
try:
|
||||
node = self.session.get_object(node_id)
|
||||
|
@ -1046,19 +1048,18 @@ class FutureHandler(SocketServer.BaseRequestHandler):
|
|||
raise KeyError("Event message for unknown node %d" % node_id)
|
||||
|
||||
# configure mobility models for WLAN added during runtime
|
||||
if event_type == EventTypes.INSTANTIATION_STATE.value and nodeutils.is_node(node,
|
||||
NodeTypes.WIRELESS_LAN):
|
||||
if event_type == EventTypes.INSTANTIATION_STATE and nodeutils.is_node(node, NodeTypes.WIRELESS_LAN):
|
||||
self.session.start_mobility(node_ids=(node.objid,))
|
||||
return ()
|
||||
|
||||
logger.warn("dropping unhandled Event message with node number")
|
||||
return ()
|
||||
self.session.set_state(state=event_type)
|
||||
self.session.set_state(event_type)
|
||||
|
||||
if event_type == EventTypes.DEFINITION_STATE.value:
|
||||
if event_type == EventTypes.DEFINITION_STATE:
|
||||
# clear all session objects in order to receive new definitions
|
||||
self.session.clear()
|
||||
elif event_type == EventTypes.INSTANTIATION_STATE.value:
|
||||
elif event_type == EventTypes.INSTANTIATION_STATE:
|
||||
if len(self.handler_threads) > 1:
|
||||
# TODO: sync handler threads here before continuing
|
||||
time.sleep(2.0) # XXX
|
||||
|
@ -1068,21 +1069,19 @@ class FutureHandler(SocketServer.BaseRequestHandler):
|
|||
# after booting nodes attempt to send emulation id for nodes waiting on status
|
||||
for obj in self.session.objects.itervalues():
|
||||
self.send_node_emulation_id(obj.objid)
|
||||
elif event_type == EventTypes.RUNTIME_STATE.value:
|
||||
elif event_type == EventTypes.RUNTIME_STATE:
|
||||
if self.session.master:
|
||||
logger.warn("Unexpected event message: RUNTIME state received at session master")
|
||||
else:
|
||||
# master event queue is started in session.checkruntime()
|
||||
self.session.start_events()
|
||||
elif event_type == EventTypes.DATACOLLECT_STATE.value:
|
||||
elif event_type == EventTypes.DATACOLLECT_STATE:
|
||||
self.session.data_collect()
|
||||
elif event_type == EventTypes.SHUTDOWN_STATE.value:
|
||||
elif event_type == EventTypes.SHUTDOWN_STATE:
|
||||
if self.session.master:
|
||||
logger.warn("Unexpected event message: SHUTDOWN state received at session master")
|
||||
elif event_type in (EventTypes.START.value, EventTypes.STOP.value,
|
||||
EventTypes.RESTART.value,
|
||||
EventTypes.PAUSE.value,
|
||||
EventTypes.RECONFIGURE.value):
|
||||
elif event_type in {EventTypes.START, EventTypes.STOP, EventTypes.RESTART, EventTypes.PAUSE,
|
||||
EventTypes.RECONFIGURE}:
|
||||
handled = False
|
||||
name = event_data.name
|
||||
if name:
|
||||
|
@ -1095,17 +1094,16 @@ class FutureHandler(SocketServer.BaseRequestHandler):
|
|||
self.session.mobility_event(event_data)
|
||||
handled = True
|
||||
if not handled:
|
||||
logger.warn("Unhandled event message: event type %s (%s)",
|
||||
event_type, coreapi.state_name(event_type))
|
||||
elif event_type == EventTypes.FILE_OPEN.value:
|
||||
logger.warn("Unhandled event message: event type %s ", event_type.name)
|
||||
elif event_type == EventTypes.FILE_OPEN:
|
||||
filename = event_data.name
|
||||
self.session.open_xml(filename, start=False)
|
||||
self.session.send_objects()
|
||||
return ()
|
||||
elif event_type == EventTypes.FILE_SAVE.value:
|
||||
elif event_type == EventTypes.FILE_SAVE:
|
||||
filename = event_data.name
|
||||
self.session.save_xml(filename, self.session.config["xmlfilever"])
|
||||
elif event_type == EventTypes.SCHEDULED.value:
|
||||
elif event_type == EventTypes.SCHEDULED:
|
||||
etime = event_data.time
|
||||
node = event_data.node
|
||||
name = event_data.name
|
||||
|
@ -1118,7 +1116,7 @@ class FutureHandler(SocketServer.BaseRequestHandler):
|
|||
else:
|
||||
raise NotImplementedError
|
||||
else:
|
||||
logger.warn("Unhandled event message: event type %d", event_type)
|
||||
logger.warn("Unhandled event message: event type %s", event_type)
|
||||
|
||||
return ()
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
"""
|
||||
Defines server classes and request handlers for TCP and UDP.
|
||||
Defines core server for handling TCP connections.
|
||||
"""
|
||||
|
||||
import SocketServer
|
||||
|
@ -7,7 +7,7 @@ import SocketServer
|
|||
from core.future.coreemu import CoreEmu
|
||||
|
||||
|
||||
class FutureServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
|
||||
class CoreServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
|
||||
"""
|
||||
TCP server class, manages sessions and spawns request handlers for
|
||||
incoming connections.
|
||||
|
@ -28,13 +28,3 @@ class FutureServer(SocketServer.ThreadingMixIn, SocketServer.TCPServer):
|
|||
self.coreemu = CoreEmu(config)
|
||||
self.config = config
|
||||
SocketServer.TCPServer.__init__(self, server_address, handler_class)
|
||||
|
||||
def shutdown(self):
|
||||
"""
|
||||
Shutdown the server, all known sessions, and remove server from known servers set.
|
||||
|
||||
:return: nothing
|
||||
"""
|
||||
# shutdown all known sessions
|
||||
for session in self.coreemu.sessions.itervalues():
|
||||
session.shutdown()
|
|
@ -300,27 +300,28 @@ class Session(object):
|
|||
"""
|
||||
Set the session's current state.
|
||||
|
||||
:param int state: state to set to
|
||||
:param core.enumerations.EventTypes state: state to set to
|
||||
:param send_event: if true, generate core API event messages
|
||||
:return: nothing
|
||||
"""
|
||||
state_name = coreapi.state_name(state)
|
||||
state_value = state.value
|
||||
state_name = state.name
|
||||
|
||||
if self.state == state:
|
||||
if self.state == state_value:
|
||||
logger.info("session is already in state: %s, skipping change", state_name)
|
||||
return
|
||||
|
||||
self.state = state
|
||||
self.state = state_value
|
||||
self._state_time = time.time()
|
||||
logger.info("changing session %s to state %s(%s) at %s",
|
||||
self.session_id, state, state_name, self._state_time)
|
||||
self.session_id, state_value, state_name, self._state_time)
|
||||
|
||||
self.write_state(state)
|
||||
self.run_hooks(state)
|
||||
self.run_state_hooks(state)
|
||||
self.write_state(state_value)
|
||||
self.run_hooks(state_value)
|
||||
self.run_state_hooks(state_value)
|
||||
|
||||
if send_event:
|
||||
event_data = EventData(event_type=state, time="%s" % time.time())
|
||||
event_data = EventData(event_type=state_value, time="%s" % time.time())
|
||||
self.broadcast_event(event_data)
|
||||
|
||||
def write_state(self, state):
|
||||
|
@ -868,7 +869,7 @@ class Session(object):
|
|||
|
||||
# start event loop and set to runtime
|
||||
self.event_loop.run()
|
||||
self.set_state(EventTypes.RUNTIME_STATE.value, send_event=True)
|
||||
self.set_state(EventTypes.RUNTIME_STATE, send_event=True)
|
||||
|
||||
def data_collect(self):
|
||||
"""
|
||||
|
@ -908,7 +909,7 @@ class Session(object):
|
|||
shutdown = False
|
||||
if node_count == 0:
|
||||
shutdown = True
|
||||
self.set_state(state=EventTypes.SHUTDOWN_STATE.value)
|
||||
self.set_state(EventTypes.SHUTDOWN_STATE)
|
||||
|
||||
return shutdown
|
||||
|
||||
|
|
|
@ -250,7 +250,7 @@ class CoreDocumentParser0(object):
|
|||
geo.append(a)
|
||||
location.setrefgeo(geo[0], geo[1], geo[2])
|
||||
scale = origin.getAttribute("scale100")
|
||||
if scale is not None:
|
||||
if scale is not None and scale:
|
||||
location.refscale = float(scale)
|
||||
point = xmlutils.get_one_element(origin, "point")
|
||||
if point is not None and point.firstChild is not None:
|
||||
|
|
|
@ -20,7 +20,7 @@ def example(options):
|
|||
session = coreemu.create_session()
|
||||
|
||||
# must be in configuration state for nodes to start, when using "node_add" below
|
||||
session.set_state(EventTypes.CONFIGURATION_STATE.value)
|
||||
session.set_state(EventTypes.CONFIGURATION_STATE)
|
||||
|
||||
# create emane network node
|
||||
emane_network = session.create_emane_network(
|
||||
|
@ -31,7 +31,7 @@ def example(options):
|
|||
|
||||
# create nodes
|
||||
for i in xrange(options.nodes):
|
||||
node = session.create_emane_node()
|
||||
node = session.create_wireless_node()
|
||||
node.setposition(x=150 * (i + 1), y=150)
|
||||
interface = prefixes.create_interface(node)
|
||||
session.add_link(node.objid, emane_network.objid, interface_one=interface)
|
||||
|
|
|
@ -22,7 +22,7 @@ def example(options):
|
|||
session = coreemu.create_session()
|
||||
|
||||
# must be in configuration state for nodes to start, when using "node_add" below
|
||||
session.set_state(EventTypes.CONFIGURATION_STATE.value)
|
||||
session.set_state(EventTypes.CONFIGURATION_STATE)
|
||||
|
||||
# create switch network node
|
||||
switch = session.add_node(_type=NodeTypes.SWITCH)
|
||||
|
|
|
@ -18,7 +18,7 @@ def example(nodes):
|
|||
session = coreemu.create_session()
|
||||
|
||||
# must be in configuration state for nodes to start, when using "node_add" below
|
||||
session.set_state(EventTypes.CONFIGURATION_STATE.value)
|
||||
session.set_state(EventTypes.CONFIGURATION_STATE)
|
||||
|
||||
# create switch network node
|
||||
switch = session.add_node(_type=NodeTypes.SWITCH)
|
||||
|
|
|
@ -23,11 +23,11 @@ def example(options):
|
|||
session = coreemu.create_session()
|
||||
|
||||
# must be in configuration state for nodes to start, when using "node_add" below
|
||||
session.set_state(EventTypes.CONFIGURATION_STATE.value)
|
||||
session.set_state(EventTypes.CONFIGURATION_STATE)
|
||||
|
||||
# create wlan network node
|
||||
wlan = session.add_node(_type=NodeTypes.WIRELESS_LAN)
|
||||
coreemu.set_wireless_model(wlan, BasicRangeModel)
|
||||
session.set_wireless_model(wlan, BasicRangeModel)
|
||||
|
||||
# create nodes
|
||||
wireless_nodes = []
|
||||
|
@ -38,7 +38,7 @@ def example(options):
|
|||
wireless_nodes.append(node)
|
||||
|
||||
# link all created nodes with the wireless network
|
||||
coreemu.wireless_link_all(wlan, wireless_nodes)
|
||||
session.wireless_link_all(wlan, wireless_nodes)
|
||||
|
||||
# instantiate session
|
||||
session.instantiate()
|
||||
|
|
|
@ -132,7 +132,7 @@ def main():
|
|||
session.broker.dorecvloop = False
|
||||
|
||||
# Change to configuration state on both machines
|
||||
session.set_state(EventTypes.CONFIGURATION_STATE.value)
|
||||
session.set_state(EventTypes.CONFIGURATION_STATE)
|
||||
tlvdata = coreapi.CoreEventTlv.pack(EventTlvs.TYPE.value, EventTypes.CONFIGURATION_STATE.value)
|
||||
session.broker.handlerawmsg(coreapi.CoreEventMessage.pack(0, tlvdata))
|
||||
|
||||
|
|
|
@ -69,7 +69,7 @@ def main():
|
|||
print "connecting to slave at %s:%d" % (slave, port)
|
||||
session.broker.addserver(slave, slave, port)
|
||||
session.broker.setupserver(slave)
|
||||
session.set_state(EventTypes.CONFIGURATION_STATE.value)
|
||||
session.set_state(EventTypes.CONFIGURATION_STATE)
|
||||
tlvdata = coreapi.CoreEventTlv.pack(EventTlvs.TYPE.value, EventTypes.CONFIGURATION_STATE.value)
|
||||
session.broker.handlerawmsg(coreapi.CoreEventMessage.pack(0, tlvdata))
|
||||
|
||||
|
|
40
daemon/scripts/core-daemon
Executable file → Normal file
40
daemon/scripts/core-daemon
Executable file → Normal file
|
@ -6,18 +6,16 @@ message handlers are defined and some support for sending messages.
|
|||
"""
|
||||
|
||||
import ConfigParser
|
||||
import atexit
|
||||
import optparse
|
||||
import signal
|
||||
import sys
|
||||
import time
|
||||
|
||||
from core import constants
|
||||
from core import corehandlers
|
||||
from core import coreserver
|
||||
from core import enumerations
|
||||
from core import logger
|
||||
from core import services
|
||||
from core.legacy.corehandler import CoreHandler
|
||||
from core.legacy.coreserver import CoreServer
|
||||
from core.misc import nodeutils
|
||||
from core.misc.utils import close_onexec
|
||||
from core.service import ServiceManager
|
||||
|
@ -45,7 +43,7 @@ def cored(cfg=None):
|
|||
host = "localhost"
|
||||
|
||||
try:
|
||||
server = coreserver.CoreServer((host, port), corehandlers.CoreRequestHandler, cfg)
|
||||
server = CoreServer((host, port), CoreHandler, cfg)
|
||||
except:
|
||||
logger.exception("error starting main server on: %s:%s", host, port)
|
||||
sys.exit(1)
|
||||
|
@ -55,38 +53,6 @@ def cored(cfg=None):
|
|||
server.serve_forever()
|
||||
|
||||
|
||||
# TODO: should sessions and the main core daemon both catch exit to shutdown independently?
|
||||
def cleanup():
|
||||
"""
|
||||
Runs server shutdown and cleanup when catching an exit signal.
|
||||
|
||||
:return: nothing
|
||||
"""
|
||||
while coreserver.CoreServer.servers:
|
||||
server = coreserver.CoreServer.servers.pop()
|
||||
server.shutdown()
|
||||
|
||||
|
||||
def sighandler(signum, stackframe):
|
||||
"""
|
||||
Signal handler when different signals are sent.
|
||||
|
||||
:param int signum: singal number sent
|
||||
:param stackframe: stack frame sent
|
||||
:return: nothing
|
||||
"""
|
||||
logger.error("terminated by signal: %s", signum)
|
||||
sys.exit(signum)
|
||||
|
||||
|
||||
signal.signal(signal.SIGHUP, sighandler)
|
||||
signal.signal(signal.SIGINT, sighandler)
|
||||
signal.signal(signal.SIGTERM, sighandler)
|
||||
signal.signal(signal.SIGUSR1, sighandler)
|
||||
signal.signal(signal.SIGUSR2, sighandler)
|
||||
atexit.register(cleanup)
|
||||
|
||||
|
||||
def get_merged_config(filename):
|
||||
"""
|
||||
Return a configuration after merging config file and command-line arguments.
|
||||
|
|
|
@ -1,145 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
"""
|
||||
core-daemon: the CORE daemon is a server process that receives CORE API
|
||||
messages and instantiates emulated nodes and networks within the kernel. Various
|
||||
message handlers are defined and some support for sending messages.
|
||||
"""
|
||||
|
||||
import ConfigParser
|
||||
import optparse
|
||||
import sys
|
||||
import time
|
||||
|
||||
from core import constants
|
||||
from core import enumerations
|
||||
from core import logger
|
||||
from core import services
|
||||
from core.future.futurehandler import FutureHandler
|
||||
from core.future.futureserver import FutureServer
|
||||
from core.misc import nodeutils
|
||||
from core.misc.utils import close_onexec
|
||||
from core.service import ServiceManager
|
||||
|
||||
|
||||
def banner():
|
||||
"""
|
||||
Output the program banner printed to the terminal or log file.
|
||||
|
||||
:return: nothing
|
||||
"""
|
||||
logger.info("CORE daemon v.%s started %s", constants.COREDPY_VERSION, time.ctime())
|
||||
|
||||
|
||||
def cored(cfg=None):
|
||||
"""
|
||||
Start the CoreServer object and enter the server loop.
|
||||
|
||||
:param dict cfg: core configuration
|
||||
:return: nothing
|
||||
"""
|
||||
host = cfg["listenaddr"]
|
||||
port = int(cfg["port"])
|
||||
if host == "" or host is None:
|
||||
host = "localhost"
|
||||
|
||||
try:
|
||||
server = FutureServer((host, port), FutureHandler, cfg)
|
||||
except:
|
||||
logger.exception("error starting main server on: %s:%s", host, port)
|
||||
sys.exit(1)
|
||||
|
||||
close_onexec(server.fileno())
|
||||
logger.info("main server started, listening on: %s:%s", host, port)
|
||||
server.serve_forever()
|
||||
|
||||
|
||||
def get_merged_config(filename):
|
||||
"""
|
||||
Return a configuration after merging config file and command-line arguments.
|
||||
|
||||
:param str filename: file name to merge configuration settings with
|
||||
:return: merged configuration
|
||||
:rtype: dict
|
||||
"""
|
||||
# these are the defaults used in the config file
|
||||
defaults = {
|
||||
"port": "%d" % enumerations.CORE_API_PORT,
|
||||
"listenaddr": "localhost",
|
||||
"xmlfilever": "1.0",
|
||||
"numthreads": "1",
|
||||
}
|
||||
|
||||
usagestr = "usage: %prog [-h] [options] [args]\n\n" + \
|
||||
"CORE daemon v.%s instantiates Linux network namespace " \
|
||||
"nodes." % constants.COREDPY_VERSION
|
||||
parser = optparse.OptionParser(usage=usagestr)
|
||||
parser.add_option("-f", "--configfile", dest="configfile", type="string",
|
||||
help="read config from specified file; default = %s" % filename)
|
||||
parser.add_option("-p", "--port", dest="port", type=int,
|
||||
help="port number to listen on; default = %s" % defaults["port"])
|
||||
parser.add_option("-t", "--numthreads", dest="numthreads", type=int,
|
||||
help="number of server threads; default = %s" % defaults["numthreads"])
|
||||
|
||||
# parse command line options
|
||||
options, args = parser.parse_args()
|
||||
|
||||
# read the config file
|
||||
if options.configfile is not None:
|
||||
filename = options.configfile
|
||||
del options.configfile
|
||||
cfg = ConfigParser.SafeConfigParser(defaults)
|
||||
cfg.read(filename)
|
||||
|
||||
section = "core-daemon"
|
||||
if not cfg.has_section(section):
|
||||
cfg.add_section(section)
|
||||
|
||||
# merge command line with config file
|
||||
for opt in options.__dict__:
|
||||
val = options.__dict__[opt]
|
||||
if val is not None:
|
||||
cfg.set(section, opt, val.__str__())
|
||||
|
||||
return dict(cfg.items(section)), args
|
||||
|
||||
|
||||
def main():
|
||||
"""
|
||||
Main program startup.
|
||||
|
||||
:return: nothing
|
||||
"""
|
||||
# get a configuration merged from config file and command-line arguments
|
||||
cfg, args = get_merged_config("%s/core.conf" % constants.CORE_CONF_DIR)
|
||||
for a in args:
|
||||
logger.error("ignoring command line argument: %s", a)
|
||||
|
||||
# attempt load custom services
|
||||
service_paths = cfg.get("custom_services_dir")
|
||||
logger.debug("custom service paths: %s", service_paths)
|
||||
if service_paths:
|
||||
for service_path in service_paths.split(','):
|
||||
service_path = service_path.strip()
|
||||
ServiceManager.add_services(service_path)
|
||||
|
||||
banner()
|
||||
|
||||
try:
|
||||
cored(cfg)
|
||||
except KeyboardInterrupt:
|
||||
logger.info("keyboard interrupt, stopping core daemon")
|
||||
|
||||
sys.exit(0)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
# configure nodes to use
|
||||
if len(sys.argv) == 2 and sys.argv[1] == "ovs":
|
||||
from core.netns.openvswitch import OVS_NODES
|
||||
|
||||
nodeutils.update_node_map(OVS_NODES)
|
||||
|
||||
# load default services
|
||||
services.load()
|
||||
|
||||
main()
|
|
@ -13,8 +13,6 @@ from core.api.coreapi import CoreEventMessage
|
|||
from core.api.coreapi import CoreExecMessage
|
||||
from core.api.coreapi import CoreLinkMessage
|
||||
from core.api.coreapi import CoreNodeMessage
|
||||
from core.corehandlers import CoreRequestHandler
|
||||
from core.coreserver import CoreServer
|
||||
from core.enumerations import CORE_API_PORT
|
||||
from core.enumerations import ConfigTlvs
|
||||
from core.enumerations import EventTlvs
|
||||
|
@ -25,10 +23,12 @@ from core.enumerations import LinkTypes
|
|||
from core.enumerations import MessageFlags
|
||||
from core.enumerations import NodeTlvs
|
||||
from core.enumerations import NodeTypes
|
||||
from core.future.coreemu import CoreEmu
|
||||
from core.future.futuredata import IpPrefixes
|
||||
from core.legacy.corehandler import CoreHandler
|
||||
from core.legacy.coreserver import CoreServer
|
||||
from core.misc import ipaddress
|
||||
from core.misc.ipaddress import MacAddress
|
||||
from core.netns import nodes
|
||||
from core.session import Session
|
||||
|
||||
EMANE_SERVICES = "zebra|OSPFv3MDR|IPForward"
|
||||
|
||||
|
@ -133,110 +133,12 @@ def state_message(state):
|
|||
])
|
||||
|
||||
|
||||
class Core(object):
|
||||
def __init__(self, session, ip_prefix):
|
||||
self.session = session
|
||||
self.ip_prefix = ip_prefix
|
||||
self.current_ip = 1
|
||||
self.nodes = {}
|
||||
self.node_ips = {}
|
||||
|
||||
def create_node(self, name, cls=nodes.CoreNode, objid=None, position=None, services=None, model="host"):
|
||||
node = self.session.add_object(cls=cls, name=name, objid=objid)
|
||||
node.type = model
|
||||
if position:
|
||||
node.setposition(*position)
|
||||
if services:
|
||||
self.session.services.addservicestonode(node, model, services)
|
||||
self.nodes[name] = node
|
||||
|
||||
def add_interface(self, network, name):
|
||||
node_ip = self.ip_prefix.addr(self.current_ip)
|
||||
self.current_ip += 1
|
||||
self.node_ips[name] = node_ip
|
||||
node = self.nodes[name]
|
||||
interface_id = node.newnetif(network, ["%s/%s" % (node_ip, self.ip_prefix.prefixlen)])
|
||||
return node.netif(interface_id)
|
||||
|
||||
def get_node(self, name):
|
||||
"""
|
||||
Retrieve node from current session.
|
||||
|
||||
:param str name: name of node to retrieve
|
||||
:return: core node
|
||||
:rtype: core.netns.nodes.CoreNode
|
||||
"""
|
||||
return self.nodes[name]
|
||||
|
||||
def get_ip(self, name):
|
||||
return self.node_ips[name]
|
||||
|
||||
def link(self, network, from_interface, to_interface):
|
||||
network.link(from_interface, to_interface)
|
||||
|
||||
def configure_link(self, network, interface_one, interface_two, values, unidirectional=False):
|
||||
network.linkconfig(netif=interface_one, netif2=interface_two, **values)
|
||||
|
||||
if not unidirectional:
|
||||
network.linkconfig(netif=interface_two, netif2=interface_one, **values)
|
||||
|
||||
def ping(self, from_name, to_name):
|
||||
from_node = self.nodes[from_name]
|
||||
to_ip = str(self.get_ip(to_name))
|
||||
return from_node.cmd(["ping", "-c", "3", to_ip])
|
||||
|
||||
def ping_output(self, from_name, to_name):
|
||||
from_node = self.nodes[from_name]
|
||||
to_ip = str(self.get_ip(to_name))
|
||||
output = from_node.check_cmd(["ping", "-i", "0.05", "-c", "3", to_ip])
|
||||
return output
|
||||
|
||||
def iperf(self, from_name, to_name):
|
||||
from_node = self.nodes[from_name]
|
||||
to_node = self.nodes[to_name]
|
||||
to_ip = str(self.get_ip(to_name))
|
||||
|
||||
# run iperf server, run client, kill iperf server
|
||||
vcmd, stdin, stdout, stderr = to_node.client.popen(["iperf", "-s", "-u", "-y", "C"])
|
||||
from_node.cmd(["iperf", "-u", "-t", "5", "-c", to_ip])
|
||||
to_node.cmd(["killall", "-9", "iperf"])
|
||||
|
||||
return stdout.read().strip()
|
||||
|
||||
def assert_nodes(self):
|
||||
for node in self.nodes.itervalues():
|
||||
assert os.path.exists(node.nodedir)
|
||||
|
||||
def create_link_network(self):
|
||||
# create switch
|
||||
ptp_node = self.session.add_object(cls=nodes.PtpNet)
|
||||
|
||||
# create nodes
|
||||
self.create_node("n1")
|
||||
self.create_node("n2")
|
||||
|
||||
# add interfaces
|
||||
interface_one = self.add_interface(ptp_node, "n1")
|
||||
interface_two = self.add_interface(ptp_node, "n2")
|
||||
|
||||
# instantiate session
|
||||
self.session.instantiate()
|
||||
|
||||
# assert node directories created
|
||||
self.assert_nodes()
|
||||
|
||||
return ptp_node, interface_one, interface_two
|
||||
|
||||
def set_emane_model(self, emane_node, emane_model):
|
||||
# set the emane model
|
||||
values = emane_model.getdefaultvalues()
|
||||
self.session.emane.setconfig(emane_node.objid, emane_model.name, values)
|
||||
|
||||
|
||||
class CoreServerTest(object):
|
||||
def __init__(self):
|
||||
address = ("localhost", CORE_API_PORT)
|
||||
self.server = CoreServer(address, CoreRequestHandler, {
|
||||
def __init__(self, port=CORE_API_PORT):
|
||||
self.host = "localhost"
|
||||
self.port = port
|
||||
address = (self.host, self.port)
|
||||
self.server = CoreServer(address, CoreHandler, {
|
||||
"numthreads": 1,
|
||||
"daemonize": False,
|
||||
})
|
||||
|
@ -246,29 +148,29 @@ class CoreServerTest(object):
|
|||
self.session = None
|
||||
self.request_handler = None
|
||||
|
||||
def setup(self, distributed_address):
|
||||
def setup(self, distributed_address, port):
|
||||
# validate address
|
||||
assert distributed_address, "distributed server address was not provided"
|
||||
|
||||
# create session
|
||||
self.session = self.server.create_session(1)
|
||||
self.session = self.server.coreemu.create_session(1)
|
||||
self.session.master = True
|
||||
|
||||
# create request handler
|
||||
request_mock = MagicMock()
|
||||
request_mock.fileno = MagicMock(return_value=1)
|
||||
self.request_handler = CoreRequestHandler(request_mock, "", self.server)
|
||||
self.request_handler = CoreHandler(request_mock, "", self.server)
|
||||
self.request_handler.session = self.session
|
||||
self.request_handler.add_session_handlers()
|
||||
self.session.broker.session_clients.append(self.request_handler)
|
||||
|
||||
# have broker handle a configuration state change
|
||||
self.session.set_state(state=EventTypes.DEFINITION_STATE.value)
|
||||
self.session.set_state(EventTypes.DEFINITION_STATE)
|
||||
message = state_message(EventTypes.CONFIGURATION_STATE)
|
||||
self.request_handler.handle_message(message)
|
||||
|
||||
# add broker server for distributed core
|
||||
distributed = "%s:%s:%s" % (self.distributed_server, distributed_address, CORE_API_PORT)
|
||||
distributed = "%s:%s:%s" % (self.distributed_server, distributed_address, port)
|
||||
message = CoreConfMessage.create(0, [
|
||||
(ConfigTlvs.OBJECT, "broker"),
|
||||
(ConfigTlvs.TYPE, 0),
|
||||
|
@ -301,38 +203,24 @@ class CoreServerTest(object):
|
|||
self.server.server_close()
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
@pytest.fixture
|
||||
def session():
|
||||
# load default services
|
||||
services.load()
|
||||
|
||||
# create and return session
|
||||
session_fixture = Session(1, persistent=True)
|
||||
session_fixture.master = True
|
||||
# use coreemu and create a session
|
||||
coreemu = CoreEmu()
|
||||
session_fixture = coreemu.create_session()
|
||||
session_fixture.set_state(EventTypes.CONFIGURATION_STATE)
|
||||
assert os.path.exists(session_fixture.session_dir)
|
||||
|
||||
# set location
|
||||
# session_fixture.master = True
|
||||
session_fixture.location.setrefgeo(47.57917, -122.13232, 2.00000)
|
||||
session_fixture.location.refscale = 150.0
|
||||
|
||||
# return session fixture
|
||||
# return created session
|
||||
yield session_fixture
|
||||
|
||||
# cleanup
|
||||
print "shutting down session"
|
||||
session_fixture.shutdown()
|
||||
assert not os.path.exists(session_fixture.session_dir)
|
||||
# shutdown coreemu
|
||||
coreemu.shutdown()
|
||||
|
||||
|
||||
@pytest.fixture(scope="module")
|
||||
def ip_prefix():
|
||||
return ipaddress.Ipv4Prefix("10.83.0.0/16")
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
def core(session, ip_prefix):
|
||||
return Core(session, ip_prefix)
|
||||
def ip_prefixes():
|
||||
return IpPrefixes(ip4_prefix="10.83.0.0/16")
|
||||
|
||||
|
||||
@pytest.fixture()
|
||||
|
@ -348,6 +236,11 @@ def cored():
|
|||
server.shutdown()
|
||||
|
||||
|
||||
def ping(from_node, to_node, ip_prefixes, count=3):
|
||||
address = ip_prefixes.ip4_address(to_node)
|
||||
return from_node.cmd(["ping", "-c", str(count), address])
|
||||
|
||||
|
||||
def pytest_addoption(parser):
|
||||
parser.addoption("--distributed", help="distributed server address")
|
||||
|
||||
|
|
|
@ -11,22 +11,22 @@ from xml.etree import ElementTree
|
|||
import pytest
|
||||
from mock import MagicMock
|
||||
|
||||
from conftest import EMANE_SERVICES
|
||||
from core.data import ConfigData
|
||||
from core.enumerations import MessageFlags
|
||||
from core.enumerations import MessageFlags, NodeTypes
|
||||
from core.future.futuredata import NodeOptions
|
||||
from core.mobility import BasicRangeModel
|
||||
from core.netns import nodes
|
||||
from core.netns import vnodeclient
|
||||
from core.netns.vnodeclient import VnodeClient
|
||||
from core.phys.pnodes import PhysicalNode
|
||||
from core.service import ServiceManager
|
||||
from core.xml import xmlsession
|
||||
|
||||
_PATH = os.path.abspath(os.path.dirname(__file__))
|
||||
_SERVICES_PATH = os.path.join(_PATH, "myservices")
|
||||
_MOBILITY_FILE = os.path.join(_PATH, "mobility.scen")
|
||||
_XML_VERSIONS = ["0.0", "1.0"]
|
||||
_NODE_CLASSES = [nodes.PtpNet, nodes.HubNode, nodes.SwitchNode]
|
||||
_WIRED = [
|
||||
NodeTypes.PEER_TO_PEER,
|
||||
NodeTypes.HUB,
|
||||
NodeTypes.SWITCH
|
||||
]
|
||||
|
||||
|
||||
def createclients(sessiondir, clientcls=VnodeClient, cmdchnlfilterfunc=None):
|
||||
|
@ -47,8 +47,13 @@ def createclients(sessiondir, clientcls=VnodeClient, cmdchnlfilterfunc=None):
|
|||
return map(lambda x: clientcls(os.path.basename(x), x), cmdchnls)
|
||||
|
||||
|
||||
def ping(from_node, to_node, ip_prefixes):
|
||||
address = ip_prefixes.ip4_address(to_node)
|
||||
return from_node.cmd(["ping", "-c", "3", address])
|
||||
|
||||
|
||||
class TestCore:
|
||||
def test_import_service(self, core):
|
||||
def test_import_service(self):
|
||||
"""
|
||||
Test importing a custom service.
|
||||
|
||||
|
@ -58,118 +63,115 @@ class TestCore:
|
|||
assert ServiceManager.get("MyService")
|
||||
assert ServiceManager.get("MyService2")
|
||||
|
||||
@pytest.mark.parametrize("cls", _NODE_CLASSES)
|
||||
def test_nodes(self, core, cls):
|
||||
@pytest.mark.parametrize("net_type", _WIRED)
|
||||
def test_wired_ping(self, session, net_type, ip_prefixes):
|
||||
"""
|
||||
Test ptp node network.
|
||||
|
||||
:param conftest.Core core: core fixture to test with
|
||||
:param cls: node classes that work within a simple network
|
||||
:param session: session for test
|
||||
:param core.enumerations.NodeTypes net_type: type of net node to create
|
||||
:param ip_prefixes: generates ip addresses for nodes
|
||||
"""
|
||||
|
||||
# create ptp
|
||||
network_node = core.session.add_object(cls=cls)
|
||||
# create net node
|
||||
net_node = session.add_node(_type=net_type)
|
||||
|
||||
# create nodes
|
||||
core.create_node("n1")
|
||||
core.create_node("n2")
|
||||
node_one = session.add_node()
|
||||
node_two = session.add_node()
|
||||
|
||||
# add interfaces
|
||||
core.add_interface(network_node, "n1")
|
||||
core.add_interface(network_node, "n2")
|
||||
# link nodes to net node
|
||||
for node in [node_one, node_two]:
|
||||
interface = ip_prefixes.create_interface(node)
|
||||
session.add_link(node.objid, net_node.objid, interface_one=interface)
|
||||
|
||||
# instantiate session
|
||||
core.session.instantiate()
|
||||
|
||||
# assert node directories created
|
||||
core.assert_nodes()
|
||||
session.instantiate()
|
||||
|
||||
# ping n2 from n1 and assert success
|
||||
status = core.ping("n1", "n2")
|
||||
status = ping(node_one, node_two, ip_prefixes)
|
||||
assert not status
|
||||
|
||||
@pytest.mark.parametrize("version", _XML_VERSIONS)
|
||||
def test_xml(self, core, tmpdir, version):
|
||||
def test_xml(self, session, tmpdir, version, ip_prefixes):
|
||||
"""
|
||||
Test xml client methods.
|
||||
|
||||
:param conftest.Core core: core fixture to test with
|
||||
:param session: session for test
|
||||
:param tmpdir: tmpdir to create data in
|
||||
:param str version: xml version to write and parse
|
||||
:param ip_prefixes: generates ip addresses for nodes
|
||||
"""
|
||||
|
||||
# create ptp
|
||||
ptp_node = core.session.add_object(cls=nodes.PtpNet)
|
||||
ptp_node = session.add_node(_type=NodeTypes.PEER_TO_PEER)
|
||||
|
||||
# create nodes
|
||||
core.create_node("n1")
|
||||
core.create_node("n2")
|
||||
node_one = session.add_node()
|
||||
node_two = session.add_node()
|
||||
|
||||
# add interfaces
|
||||
core.add_interface(ptp_node, "n1")
|
||||
core.add_interface(ptp_node, "n2")
|
||||
# link nodes to ptp net
|
||||
for node in [node_one, node_two]:
|
||||
interface = ip_prefixes.create_interface(node)
|
||||
session.add_link(node.objid, ptp_node.objid, interface_one=interface)
|
||||
|
||||
# instantiate session
|
||||
core.session.instantiate()
|
||||
|
||||
# assert node directories created
|
||||
core.assert_nodes()
|
||||
session.instantiate()
|
||||
|
||||
# get ids for nodes
|
||||
n1_id = core.get_node("n1").objid
|
||||
n2_id = core.get_node("n2").objid
|
||||
n1_id = node_one.objid
|
||||
n2_id = node_two.objid
|
||||
|
||||
# save xml
|
||||
xml_file = tmpdir.join("session.xml")
|
||||
file_path = xml_file.strpath
|
||||
xmlsession.save_session_xml(core.session, file_path, version)
|
||||
session.save_xml(file_path, version)
|
||||
|
||||
# verify xml file was created and can be parsed
|
||||
assert xml_file.isfile()
|
||||
assert ElementTree.parse(file_path)
|
||||
|
||||
# stop current session, clearing data
|
||||
core.session.shutdown()
|
||||
session.shutdown()
|
||||
|
||||
# verify nodes have been removed from session
|
||||
with pytest.raises(KeyError):
|
||||
assert not core.session.get_object_by_name(n1_id)
|
||||
assert not session.get_object(n1_id)
|
||||
with pytest.raises(KeyError):
|
||||
assert not core.session.get_object(n2_id)
|
||||
assert not session.get_object(n2_id)
|
||||
|
||||
# load saved xml
|
||||
xmlsession.open_session_xml(core.session, file_path, start=True)
|
||||
session.open_xml(file_path, start=True)
|
||||
|
||||
# verify nodes have been recreated
|
||||
assert core.session.get_object(n1_id)
|
||||
assert core.session.get_object(n2_id)
|
||||
assert session.get_object(n1_id)
|
||||
assert session.get_object(n2_id)
|
||||
|
||||
def test_vnode_client(self, core):
|
||||
def test_vnode_client(self, session, ip_prefixes):
|
||||
"""
|
||||
Test vnode client methods.
|
||||
|
||||
:param conftest.Core core: core fixture to test with
|
||||
:param session: session for test
|
||||
:param ip_prefixes: generates ip addresses for nodes
|
||||
"""
|
||||
|
||||
# create ptp
|
||||
ptp_node = core.session.add_object(cls=nodes.PtpNet)
|
||||
ptp_node = session.add_node(_type=NodeTypes.PEER_TO_PEER)
|
||||
|
||||
# create nodes
|
||||
core.create_node("n1")
|
||||
core.create_node("n2")
|
||||
node_one = session.add_node()
|
||||
node_two = session.add_node()
|
||||
|
||||
# add interfaces
|
||||
core.add_interface(ptp_node, "n1")
|
||||
core.add_interface(ptp_node, "n2")
|
||||
# link nodes to ptp net
|
||||
for node in [node_one, node_two]:
|
||||
interface = ip_prefixes.create_interface(node)
|
||||
session.add_link(node.objid, ptp_node.objid, interface_one=interface)
|
||||
|
||||
# get node client for testing
|
||||
n1 = core.get_node("n1")
|
||||
client = n1.client
|
||||
client = node_one.client
|
||||
|
||||
# instantiate session
|
||||
core.session.instantiate()
|
||||
|
||||
# assert node directories created
|
||||
core.assert_nodes()
|
||||
session.instantiate()
|
||||
|
||||
# check we are connected
|
||||
assert client.connected()
|
||||
|
@ -195,183 +197,154 @@ class TestCore:
|
|||
assert not client.shcmd(command[0])
|
||||
|
||||
# check module methods
|
||||
assert createclients(core.session.session_dir)
|
||||
assert createclients(session.session_dir)
|
||||
|
||||
# check convenience methods for interface information
|
||||
assert client.getaddr("eth0")
|
||||
assert client.netifstats()
|
||||
|
||||
def test_netif(self, core):
|
||||
def test_netif(self, session, ip_prefixes):
|
||||
"""
|
||||
Test netif methods.
|
||||
|
||||
:param conftest.Core core: core fixture to test with
|
||||
:param session: session for test
|
||||
:param ip_prefixes: generates ip addresses for nodes
|
||||
"""
|
||||
|
||||
# create ptp
|
||||
ptp_node = core.session.add_object(cls=nodes.PtpNet)
|
||||
ptp_node = session.add_node(_type=NodeTypes.PEER_TO_PEER)
|
||||
|
||||
# create nodes
|
||||
core.create_node("n1")
|
||||
core.create_node("n2")
|
||||
node_one = session.add_node()
|
||||
node_two = session.add_node()
|
||||
|
||||
# add interfaces
|
||||
n1_interface = core.add_interface(ptp_node, "n1")
|
||||
n2_interface = core.add_interface(ptp_node, "n2")
|
||||
|
||||
# get nodes
|
||||
n1 = core.get_node("n1")
|
||||
n2 = core.get_node("n2")
|
||||
# link nodes to ptp net
|
||||
for node in [node_one, node_two]:
|
||||
interface = ip_prefixes.create_interface(node)
|
||||
session.add_link(node.objid, ptp_node.objid, interface_one=interface)
|
||||
|
||||
# instantiate session
|
||||
core.session.instantiate()
|
||||
|
||||
# assert node directories created
|
||||
core.assert_nodes()
|
||||
session.instantiate()
|
||||
|
||||
# check link data gets generated
|
||||
assert ptp_node.all_link_data(MessageFlags.ADD.value)
|
||||
|
||||
# check common nets exist between linked nodes
|
||||
assert n1.commonnets(n2)
|
||||
assert n2.commonnets(n1)
|
||||
assert node_one.commonnets(node_two)
|
||||
assert node_two.commonnets(node_one)
|
||||
|
||||
# check we can retrieve netif index
|
||||
assert n1.getifindex(n1_interface) == 0
|
||||
assert n2.getifindex(n2_interface) == 0
|
||||
assert node_one.getifindex(0)
|
||||
assert node_two.getifindex(0)
|
||||
|
||||
# check interface parameters
|
||||
n1_interface.setparam("test", 1)
|
||||
assert n1_interface.getparam("test") == 1
|
||||
assert n1_interface.getparams()
|
||||
interface = node_one.netif(0)
|
||||
interface.setparam("test", 1)
|
||||
assert interface.getparam("test") == 1
|
||||
assert interface.getparams()
|
||||
|
||||
# delete netif and test that if no longer exists
|
||||
n1.delnetif(0)
|
||||
assert not n1.netif(0)
|
||||
node_one.delnetif(0)
|
||||
assert not node_one.netif(0)
|
||||
|
||||
def test_physical(self, core):
|
||||
"""
|
||||
Test physical node network.
|
||||
|
||||
:param conftest.Core core: core fixture to test with
|
||||
"""
|
||||
|
||||
# create switch node
|
||||
switch_node = core.session.add_object(cls=nodes.SwitchNode)
|
||||
|
||||
# create a physical node
|
||||
core.create_node(cls=PhysicalNode, name="p1")
|
||||
|
||||
# mock method that will not work
|
||||
physical_node = core.get_node("p1")
|
||||
physical_node.newnetif = MagicMock(return_value=0)
|
||||
|
||||
# create regular node
|
||||
core.create_node("n1")
|
||||
|
||||
# add interface
|
||||
core.add_interface(switch_node, "n1")
|
||||
core.add_interface(switch_node, "p1")
|
||||
|
||||
# instantiate session
|
||||
core.session.instantiate()
|
||||
|
||||
# assert node directories created
|
||||
core.assert_nodes()
|
||||
|
||||
def test_wlan_basic_range_good(self, core):
|
||||
def test_wlan_good(self, session, ip_prefixes):
|
||||
"""
|
||||
Test basic wlan network.
|
||||
|
||||
:param conftest.Core core: core fixture to test with
|
||||
:param core.future.coreemu.FutureSession session: session for test
|
||||
:param ip_prefixes: generates ip addresses for nodes
|
||||
"""
|
||||
|
||||
# create wlan
|
||||
wlan_node = core.session.add_object(cls=nodes.WlanNode)
|
||||
values = BasicRangeModel.getdefaultvalues()
|
||||
wlan_node.setmodel(BasicRangeModel, values)
|
||||
wlan_node = session.add_node(_type=NodeTypes.WIRELESS_LAN)
|
||||
session.set_wireless_model(wlan_node, BasicRangeModel)
|
||||
|
||||
# create nodes
|
||||
core.create_node("n1", position=(0, 0), services=EMANE_SERVICES, model="mdr")
|
||||
core.create_node("n2", position=(0, 0), services=EMANE_SERVICES, model="mdr")
|
||||
node_options = NodeOptions()
|
||||
node_options.set_position(0, 0)
|
||||
node_one = session.create_wireless_node(node_options=node_options)
|
||||
node_two = session.create_wireless_node(node_options=node_options)
|
||||
|
||||
# add interfaces
|
||||
interface_one = core.add_interface(wlan_node, "n1")
|
||||
interface_two = core.add_interface(wlan_node, "n2")
|
||||
# link nodes
|
||||
for node in [node_one, node_two]:
|
||||
interface = ip_prefixes.create_interface(node)
|
||||
session.add_link(node.objid, wlan_node.objid, interface_one=interface)
|
||||
|
||||
# link nodes in wlan
|
||||
core.link(wlan_node, interface_one, interface_two)
|
||||
session.wireless_link_all(wlan_node, [node_one, node_two])
|
||||
|
||||
# instantiate session
|
||||
core.session.instantiate()
|
||||
|
||||
# assert node directories created
|
||||
core.assert_nodes()
|
||||
session.instantiate()
|
||||
|
||||
# ping n2 from n1 and assert success
|
||||
status = core.ping("n1", "n2")
|
||||
status = ping(node_one, node_two, ip_prefixes)
|
||||
assert not status
|
||||
|
||||
def test_wlan_basic_range_bad(self, core):
|
||||
def test_wlan_bad(self, session, ip_prefixes):
|
||||
"""
|
||||
Test basic wlan network with leveraging basic range model.
|
||||
|
||||
:param conftest.Core core: core fixture to test with
|
||||
:param core.future.coreemu.FutureSession session: session for test
|
||||
:param ip_prefixes: generates ip addresses for nodes
|
||||
"""
|
||||
|
||||
# create wlan
|
||||
wlan_node = core.session.add_object(cls=nodes.WlanNode)
|
||||
values = BasicRangeModel.getdefaultvalues()
|
||||
wlan_node.setmodel(BasicRangeModel, values)
|
||||
wlan_node = session.add_node(_type=NodeTypes.WIRELESS_LAN)
|
||||
session.set_wireless_model(wlan_node, BasicRangeModel)
|
||||
|
||||
# create nodes
|
||||
core.create_node("n1", position=(0, 0), services=EMANE_SERVICES, model="mdr")
|
||||
core.create_node("n2", position=(0, 0), services=EMANE_SERVICES, model="mdr")
|
||||
node_options = NodeOptions()
|
||||
node_options.set_position(0, 0)
|
||||
node_one = session.create_wireless_node(node_options=node_options)
|
||||
node_two = session.create_wireless_node(node_options=node_options)
|
||||
|
||||
# add interfaces
|
||||
interface_one = core.add_interface(wlan_node, "n1")
|
||||
interface_two = core.add_interface(wlan_node, "n2")
|
||||
# link nodes
|
||||
for node in [node_one, node_two]:
|
||||
interface = ip_prefixes.create_interface(node)
|
||||
session.add_link(node.objid, wlan_node.objid, interface_one=interface)
|
||||
|
||||
# link nodes in wlan
|
||||
core.link(wlan_node, interface_one, interface_two)
|
||||
|
||||
# move nodes out of range, default range check is 275
|
||||
core.get_node("n1").setposition(0, 0)
|
||||
core.get_node("n2").setposition(500, 500)
|
||||
session.wireless_link_all(wlan_node, [node_one, node_two])
|
||||
|
||||
# instantiate session
|
||||
core.session.instantiate()
|
||||
session.instantiate()
|
||||
|
||||
# assert node directories created
|
||||
core.assert_nodes()
|
||||
# move node two out of range, default range check is 275
|
||||
time.sleep(5)
|
||||
update_options = NodeOptions()
|
||||
update_options.set_position(500, 500)
|
||||
session.update_node(node_two.objid, update_options)
|
||||
|
||||
# ping n2 from n1 and assert failure )
|
||||
time.sleep(3)
|
||||
status = core.ping("n1", "n2")
|
||||
# ping n2 from n1 and assert failure
|
||||
time.sleep(5)
|
||||
status = ping(node_one, node_two, ip_prefixes)
|
||||
assert status
|
||||
|
||||
def test_mobility(self, core):
|
||||
def test_mobility(self, session, ip_prefixes):
|
||||
"""
|
||||
Test basic wlan network.
|
||||
|
||||
:param conftest.Core core: core fixture to test with
|
||||
:param core.future.coreemu.FutureSession session: session for test
|
||||
:param ip_prefixes: generates ip addresses for nodes
|
||||
"""
|
||||
|
||||
# create wlan
|
||||
wlan_node = core.session.add_object(cls=nodes.WlanNode)
|
||||
values = BasicRangeModel.getdefaultvalues()
|
||||
wlan_node.setmodel(BasicRangeModel, values)
|
||||
wlan_node = session.add_node(_type=NodeTypes.WIRELESS_LAN)
|
||||
session.set_wireless_model(wlan_node, BasicRangeModel)
|
||||
|
||||
# create nodes
|
||||
core.create_node("n1", objid=1, position=(0, 0), services=EMANE_SERVICES, model="mdr")
|
||||
core.create_node("n2", objid=2, position=(0, 0), services=EMANE_SERVICES, model="mdr")
|
||||
node_options = NodeOptions()
|
||||
node_options.set_position(0, 0)
|
||||
node_one = session.create_wireless_node(node_options=node_options)
|
||||
node_two = session.create_wireless_node(node_options=node_options)
|
||||
|
||||
# add interfaces
|
||||
interface_one = core.add_interface(wlan_node, "n1")
|
||||
interface_two = core.add_interface(wlan_node, "n2")
|
||||
# link nodes
|
||||
for node in [node_one, node_two]:
|
||||
interface = ip_prefixes.create_interface(node)
|
||||
session.add_link(node.objid, wlan_node.objid, interface_one=interface)
|
||||
|
||||
# link nodes in wlan
|
||||
core.link(wlan_node, interface_one, interface_two)
|
||||
session.wireless_link_all(wlan_node, [node_one, node_two])
|
||||
|
||||
# configure mobility script for session
|
||||
config = ConfigData(
|
||||
|
@ -382,7 +355,7 @@ class TestCore:
|
|||
data_values="file=%s|refresh_ms=50|loop=1|autostart=0.0|"
|
||||
"map=|script_start=|script_pause=|script_stop=" % _MOBILITY_FILE
|
||||
)
|
||||
core.session.config_object(config)
|
||||
session.config_object(config)
|
||||
|
||||
# add handler for receiving node updates
|
||||
event = threading.Event()
|
||||
|
@ -390,138 +363,10 @@ class TestCore:
|
|||
def node_update(_):
|
||||
event.set()
|
||||
|
||||
core.session.node_handlers.append(node_update)
|
||||
session.node_handlers.append(node_update)
|
||||
|
||||
# instantiate session
|
||||
core.session.instantiate()
|
||||
|
||||
# assert node directories created
|
||||
core.assert_nodes()
|
||||
session.instantiate()
|
||||
|
||||
# validate we receive a node message for updating its location
|
||||
assert event.wait(5)
|
||||
|
||||
def test_link_bandwidth(self, core):
|
||||
"""
|
||||
Test ptp node network with modifying link bandwidth.
|
||||
|
||||
:param conftest.Core core: core fixture to test with
|
||||
"""
|
||||
|
||||
# create link network
|
||||
ptp_node, interface_one, interface_two = core.create_link_network()
|
||||
|
||||
# output csv index
|
||||
bandwidth_index = 8
|
||||
|
||||
# run iperf, validate normal bandwidth
|
||||
stdout = core.iperf("n1", "n2")
|
||||
assert stdout
|
||||
value = int(stdout.split(',')[bandwidth_index])
|
||||
assert 900000 <= value <= 1100000
|
||||
|
||||
# change bandwidth in bits per second
|
||||
bandwidth = 500000
|
||||
core.configure_link(ptp_node, interface_one, interface_two, {
|
||||
"bw": bandwidth
|
||||
})
|
||||
|
||||
# run iperf again
|
||||
stdout = core.iperf("n1", "n2")
|
||||
assert stdout
|
||||
value = int(stdout.split(',')[bandwidth_index])
|
||||
assert 400000 <= value <= 600000
|
||||
|
||||
def test_link_loss(self, core):
|
||||
"""
|
||||
Test ptp node network with modifying link packet loss.
|
||||
|
||||
:param conftest.Core core: core fixture to test with
|
||||
"""
|
||||
|
||||
# create link network
|
||||
ptp_node, interface_one, interface_two = core.create_link_network()
|
||||
|
||||
# output csv index
|
||||
loss_index = -2
|
||||
|
||||
# run iperf, validate normal bandwidth
|
||||
stdout = core.iperf("n1", "n2")
|
||||
assert stdout
|
||||
value = float(stdout.split(',')[loss_index])
|
||||
assert 0 <= value <= 0.5
|
||||
|
||||
# change bandwidth in bits per second
|
||||
loss = 50
|
||||
core.configure_link(ptp_node, interface_one, interface_two, {
|
||||
"loss": loss
|
||||
})
|
||||
|
||||
# run iperf again
|
||||
stdout = core.iperf("n1", "n2")
|
||||
assert stdout
|
||||
value = float(stdout.split(',')[loss_index])
|
||||
assert 40 <= value <= 60
|
||||
|
||||
def test_link_delay(self, core):
|
||||
"""
|
||||
Test ptp node network with modifying link packet delay.
|
||||
|
||||
:param conftest.Core core: core fixture to test with
|
||||
"""
|
||||
|
||||
# create link network
|
||||
ptp_node, interface_one, interface_two = core.create_link_network()
|
||||
|
||||
# run ping for delay information
|
||||
stdout = core.ping_output("n1", "n2")
|
||||
assert stdout
|
||||
rtt_line = stdout.split("\n")[-1]
|
||||
rtt_values = rtt_line.split("=")[1].split("ms")[0].strip()
|
||||
rtt_avg = float(rtt_values.split("/")[2])
|
||||
assert 0 <= rtt_avg <= 0.2
|
||||
|
||||
# change delay in microseconds
|
||||
delay = 1000000
|
||||
core.configure_link(ptp_node, interface_one, interface_two, {
|
||||
"delay": delay
|
||||
})
|
||||
|
||||
# run ping for delay information again
|
||||
stdout = core.ping_output("n1", "n2")
|
||||
assert stdout
|
||||
rtt_line = stdout.split("\n")[-1]
|
||||
rtt_values = rtt_line.split("=")[1].split("ms")[0].strip()
|
||||
rtt_avg = float(rtt_values.split("/")[2])
|
||||
assert 1800 <= rtt_avg <= 2200
|
||||
|
||||
def test_link_jitter(self, core):
|
||||
"""
|
||||
Test ptp node network with modifying link packet jitter.
|
||||
|
||||
:param conftest.Core core: core fixture to test with
|
||||
"""
|
||||
|
||||
# create link network
|
||||
ptp_node, interface_one, interface_two = core.create_link_network()
|
||||
|
||||
# output csv index
|
||||
jitter_index = 9
|
||||
|
||||
# run iperf
|
||||
stdout = core.iperf("n1", "n2")
|
||||
assert stdout
|
||||
value = float(stdout.split(",")[jitter_index])
|
||||
assert -0.5 <= value <= 0.05
|
||||
|
||||
# change jitter in microseconds
|
||||
jitter = 1000000
|
||||
core.configure_link(ptp_node, interface_one, interface_two, {
|
||||
"jitter": jitter
|
||||
})
|
||||
|
||||
# run iperf again
|
||||
stdout = core.iperf("n1", "n2")
|
||||
assert stdout
|
||||
value = float(stdout.split(",")[jitter_index])
|
||||
assert 200 <= value <= 500
|
||||
|
|
|
@ -4,16 +4,13 @@ Unit tests for testing CORE EMANE networks.
|
|||
|
||||
import pytest
|
||||
|
||||
from conftest import EMANE_SERVICES
|
||||
|
||||
from core.data import ConfigData
|
||||
from conftest import ping
|
||||
from core.emane.bypass import EmaneBypassModel
|
||||
from core.emane.commeffect import EmaneCommEffectModel
|
||||
from core.emane.ieee80211abg import EmaneIeee80211abgModel
|
||||
from core.emane.nodes import EmaneNode
|
||||
from core.emane.rfpipe import EmaneRfPipeModel
|
||||
from core.emane.tdma import EmaneTdmaModel
|
||||
|
||||
from core.future.futuredata import NodeOptions
|
||||
|
||||
_EMANE_MODELS = [
|
||||
EmaneIeee80211abgModel,
|
||||
|
@ -26,36 +23,37 @@ _EMANE_MODELS = [
|
|||
|
||||
class TestEmane:
|
||||
@pytest.mark.parametrize("model", _EMANE_MODELS)
|
||||
def test_models(self, core, model):
|
||||
def test_models(self, session, model, ip_prefixes):
|
||||
"""
|
||||
Test emane models within a basic network.
|
||||
|
||||
:param conftest.Core core: core fixture to test with
|
||||
:param core.future.coreemu.FutureSession session: session for test
|
||||
:param model: emane model to test
|
||||
:param func setup: setup function to configure emane node
|
||||
:param ip_prefixes: generates ip addresses for nodes
|
||||
"""
|
||||
|
||||
# create emane node for networking the core nodes
|
||||
emane_node = core.session.add_object(name="emane", cls=EmaneNode)
|
||||
emane_node.setposition(x=80, y=50)
|
||||
|
||||
# set the emane model
|
||||
core.set_emane_model(emane_node, model)
|
||||
emane_network = session.create_emane_network(
|
||||
model,
|
||||
geo_reference=(47.57917, -122.13232, 2.00000)
|
||||
)
|
||||
emane_network.setposition(x=80, y=50)
|
||||
|
||||
# create nodes
|
||||
core.create_node("n1", objid=1, position=(150, 150), services=EMANE_SERVICES, model="mdr")
|
||||
core.create_node("n2", objid=2, position=(300, 150), services=EMANE_SERVICES, model="mdr")
|
||||
node_options = NodeOptions()
|
||||
node_options.set_position(150, 150)
|
||||
node_one = session.create_wireless_node(node_options=node_options)
|
||||
node_options.set_position(300, 150)
|
||||
node_two = session.create_wireless_node(node_options=node_options)
|
||||
|
||||
# add interfaces to nodes
|
||||
core.add_interface(emane_node, "n1")
|
||||
core.add_interface(emane_node, "n2")
|
||||
for i, node in enumerate([node_one, node_two]):
|
||||
node.setposition(x=150 * (i + 1), y=150)
|
||||
interface = ip_prefixes.create_interface(node)
|
||||
session.add_link(node.objid, emane_network.objid, interface_one=interface)
|
||||
|
||||
# instantiate session
|
||||
core.session.instantiate()
|
||||
|
||||
# assert node directories created
|
||||
core.assert_nodes()
|
||||
session.instantiate()
|
||||
|
||||
# ping n2 from n1 and assert success
|
||||
status = core.ping("n1", "n2")
|
||||
status = ping(node_one, node_two, ip_prefixes, count=5)
|
||||
assert not status
|
||||
|
|
|
@ -1,201 +0,0 @@
|
|||
import os
|
||||
import time
|
||||
|
||||
import pytest
|
||||
|
||||
from core.enumerations import NodeTypes, EventTypes
|
||||
from core.future.coreemu import CoreEmu
|
||||
from core.future.futuredata import IpPrefixes, NodeOptions, LinkOptions
|
||||
from core.misc import utils
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
def future_session():
|
||||
# use coreemu and create a session
|
||||
coreemu = CoreEmu()
|
||||
session = coreemu.create_session()
|
||||
session.set_state(EventTypes.CONFIGURATION_STATE.value)
|
||||
|
||||
# return created session
|
||||
yield session
|
||||
|
||||
# shutdown coreemu
|
||||
coreemu.shutdown()
|
||||
|
||||
|
||||
IP4_PREFIX = "10.83.0.0/16"
|
||||
|
||||
MODELS = [
|
||||
"router",
|
||||
"host",
|
||||
"PC",
|
||||
"mdr",
|
||||
]
|
||||
|
||||
NET_TYPES = [
|
||||
NodeTypes.SWITCH,
|
||||
NodeTypes.HUB,
|
||||
NodeTypes.WIRELESS_LAN
|
||||
]
|
||||
|
||||
|
||||
class TestFuture:
|
||||
@pytest.mark.parametrize("model", MODELS)
|
||||
def test_node_add(self, future_session, model):
|
||||
# given
|
||||
node_options = NodeOptions(model=model)
|
||||
|
||||
# when
|
||||
node = future_session.add_node(node_options=node_options)
|
||||
|
||||
# give time for node services to boot
|
||||
time.sleep(1)
|
||||
|
||||
# then
|
||||
assert node
|
||||
assert os.path.exists(node.nodedir)
|
||||
assert node.alive()
|
||||
assert node.up
|
||||
assert node.check_cmd(["ip", "addr", "show", "lo"])
|
||||
node.validate()
|
||||
|
||||
def test_node_update(self, future_session):
|
||||
# given
|
||||
node = future_session.add_node()
|
||||
position_value = 100
|
||||
update_options = NodeOptions()
|
||||
update_options.set_position(x=position_value, y=position_value)
|
||||
|
||||
# when
|
||||
future_session.update_node(node.objid, update_options)
|
||||
|
||||
# then
|
||||
assert node.position.x == position_value
|
||||
assert node.position.y == position_value
|
||||
|
||||
def test_node_delete(self, future_session):
|
||||
# given
|
||||
node = future_session.add_node()
|
||||
|
||||
# when
|
||||
future_session.delete_node(node.objid)
|
||||
|
||||
# then
|
||||
with pytest.raises(KeyError):
|
||||
future_session.get_object(node.objid)
|
||||
|
||||
@pytest.mark.parametrize("net_type", NET_TYPES)
|
||||
def test_net(self, future_session, net_type):
|
||||
# given
|
||||
|
||||
# when
|
||||
node = future_session.add_node(_type=net_type)
|
||||
|
||||
# then
|
||||
assert node
|
||||
assert node.up
|
||||
assert utils.check_cmd(["brctl", "show", node.brname])
|
||||
|
||||
def test_ptp(self, future_session):
|
||||
# given
|
||||
prefixes = IpPrefixes(ip4_prefix=IP4_PREFIX)
|
||||
node_one = future_session.add_node()
|
||||
node_two = future_session.add_node()
|
||||
interface_one = prefixes.create_interface(node_one)
|
||||
inteface_two = prefixes.create_interface(node_two)
|
||||
|
||||
# when
|
||||
future_session.add_link(node_one.objid, node_two.objid, interface_one, inteface_two)
|
||||
|
||||
# then
|
||||
assert node_one.netif(interface_one.id)
|
||||
assert node_two.netif(inteface_two.id)
|
||||
|
||||
def test_node_to_net(self, future_session):
|
||||
# given
|
||||
prefixes = IpPrefixes(ip4_prefix=IP4_PREFIX)
|
||||
node_one = future_session.add_node()
|
||||
node_two = future_session.add_node(_type=NodeTypes.SWITCH)
|
||||
interface_one = prefixes.create_interface(node_one)
|
||||
|
||||
# when
|
||||
future_session.add_link(node_one.objid, node_two.objid, interface_one)
|
||||
|
||||
# then
|
||||
assert node_two.all_link_data(0)
|
||||
assert node_one.netif(interface_one.id)
|
||||
|
||||
def test_net_to_node(self, future_session):
|
||||
# given
|
||||
prefixes = IpPrefixes(ip4_prefix=IP4_PREFIX)
|
||||
node_one = future_session.add_node(_type=NodeTypes.SWITCH)
|
||||
node_two = future_session.add_node()
|
||||
interface_two = prefixes.create_interface(node_two)
|
||||
|
||||
# when
|
||||
future_session.add_link(node_one.objid, node_two.objid, interface_two=interface_two)
|
||||
|
||||
# then
|
||||
assert node_one.all_link_data(0)
|
||||
assert node_two.netif(interface_two.id)
|
||||
|
||||
def test_net_to_net(self, future_session):
|
||||
# given
|
||||
node_one = future_session.add_node(_type=NodeTypes.SWITCH)
|
||||
node_two = future_session.add_node(_type=NodeTypes.SWITCH)
|
||||
|
||||
# when
|
||||
future_session.add_link(node_one.objid, node_two.objid)
|
||||
|
||||
# then
|
||||
assert node_one.all_link_data(0)
|
||||
|
||||
def test_link_update(self, future_session):
|
||||
# given
|
||||
prefixes = IpPrefixes(ip4_prefix=IP4_PREFIX)
|
||||
node_one = future_session.add_node()
|
||||
node_two = future_session.add_node(_type=NodeTypes.SWITCH)
|
||||
interface_one = prefixes.create_interface(node_one)
|
||||
future_session.add_link(node_one.objid, node_two.objid, interface_one)
|
||||
interface = node_one.netif(interface_one.id)
|
||||
output = utils.check_cmd(["tc", "qdisc", "show", "dev", interface.localname])
|
||||
assert "delay" not in output
|
||||
assert "rate" not in output
|
||||
assert "loss" not in output
|
||||
assert "duplicate" not in output
|
||||
|
||||
# when
|
||||
link_options = LinkOptions()
|
||||
link_options.delay = 50
|
||||
link_options.bandwidth = 5000000
|
||||
link_options.per = 25
|
||||
link_options.dup = 25
|
||||
future_session.update_link(node_one.objid, node_two.objid,
|
||||
interface_one_id=interface_one.id, link_options=link_options)
|
||||
|
||||
# then
|
||||
output = utils.check_cmd(["tc", "qdisc", "show", "dev", interface.localname])
|
||||
assert "delay" in output
|
||||
assert "rate" in output
|
||||
assert "loss" in output
|
||||
assert "duplicate" in output
|
||||
|
||||
def test_link_delete(self, future_session):
|
||||
# given
|
||||
prefixes = IpPrefixes(ip4_prefix=IP4_PREFIX)
|
||||
node_one = future_session.add_node()
|
||||
node_two = future_session.add_node()
|
||||
interface_one = prefixes.create_interface(node_one)
|
||||
interface_two = prefixes.create_interface(node_two)
|
||||
future_session.add_link(node_one.objid, node_two.objid, interface_one, interface_two)
|
||||
assert node_one.netif(interface_one.id)
|
||||
assert node_two.netif(interface_two.id)
|
||||
assert future_session.get_node_count() == 3
|
||||
|
||||
# when
|
||||
future_session.delete_link(node_one.objid, node_two.objid, interface_one.id, interface_two.id)
|
||||
|
||||
# then
|
||||
assert not node_one.netif(interface_one.id)
|
||||
assert not node_two.netif(interface_two.id)
|
||||
assert future_session.get_node_count() == 2
|
|
@ -128,7 +128,7 @@ class TestGui:
|
|||
core.session.broker.dorecvloop = False
|
||||
|
||||
# have broker handle a configuration state change
|
||||
core.session.set_state(EventTypes.CONFIGURATION_STATE.value)
|
||||
core.session.set_state(EventTypes.CONFIGURATION_STATE)
|
||||
event_message = state_message(EventTypes.CONFIGURATION_STATE)
|
||||
core.session.broker.handlerawmsg(event_message)
|
||||
|
||||
|
|
260
daemon/tests/test_links.py
Normal file
260
daemon/tests/test_links.py
Normal file
|
@ -0,0 +1,260 @@
|
|||
from core.enumerations import NodeTypes
|
||||
from core.future.futuredata import LinkOptions
|
||||
from core.misc import utils
|
||||
|
||||
|
||||
def create_ptp_network(session, ip_prefixes):
|
||||
# create nodes
|
||||
node_one = session.add_node()
|
||||
node_two = session.add_node()
|
||||
|
||||
# link nodes to net node
|
||||
interface_one = ip_prefixes.create_interface(node_one)
|
||||
interface_two = ip_prefixes.create_interface(node_two)
|
||||
session.add_link(node_one.objid, node_two.objid, interface_one, interface_two)
|
||||
|
||||
# instantiate session
|
||||
session.instantiate()
|
||||
|
||||
return node_one, node_two
|
||||
|
||||
|
||||
def ping_output(from_node, to_node, ip_prefixes):
|
||||
address = ip_prefixes.ip4_address(to_node)
|
||||
output = from_node.check_cmd(["ping", "-i", "0.05", "-c", "3", address])
|
||||
return output
|
||||
|
||||
|
||||
def iperf(from_node, to_node, ip_prefixes):
|
||||
# run iperf server, run client, kill iperf server
|
||||
address = ip_prefixes.ip4_address(to_node)
|
||||
vcmd, stdin, stdout, stderr = to_node.client.popen(["iperf", "-s", "-u", "-y", "C"])
|
||||
from_node.cmd(["iperf", "-u", "-t", "5", "-c", address])
|
||||
to_node.cmd(["killall", "-9", "iperf"])
|
||||
return stdout.read().strip()
|
||||
|
||||
|
||||
class TestLinks:
|
||||
def test_ptp(self, session, ip_prefixes):
|
||||
# given
|
||||
node_one = session.add_node()
|
||||
node_two = session.add_node()
|
||||
interface_one = ip_prefixes.create_interface(node_one)
|
||||
inteface_two = ip_prefixes.create_interface(node_two)
|
||||
|
||||
# when
|
||||
session.add_link(node_one.objid, node_two.objid, interface_one, inteface_two)
|
||||
|
||||
# then
|
||||
assert node_one.netif(interface_one.id)
|
||||
assert node_two.netif(inteface_two.id)
|
||||
|
||||
def test_node_to_net(self, session, ip_prefixes):
|
||||
# given
|
||||
node_one = session.add_node()
|
||||
node_two = session.add_node(_type=NodeTypes.SWITCH)
|
||||
interface_one = ip_prefixes.create_interface(node_one)
|
||||
|
||||
# when
|
||||
session.add_link(node_one.objid, node_two.objid, interface_one)
|
||||
|
||||
# then
|
||||
assert node_two.all_link_data(0)
|
||||
assert node_one.netif(interface_one.id)
|
||||
|
||||
def test_net_to_node(self, session, ip_prefixes):
|
||||
# given
|
||||
node_one = session.add_node(_type=NodeTypes.SWITCH)
|
||||
node_two = session.add_node()
|
||||
interface_two = ip_prefixes.create_interface(node_two)
|
||||
|
||||
# when
|
||||
session.add_link(node_one.objid, node_two.objid, interface_two=interface_two)
|
||||
|
||||
# then
|
||||
assert node_one.all_link_data(0)
|
||||
assert node_two.netif(interface_two.id)
|
||||
|
||||
def test_net_to_net(self, session):
|
||||
# given
|
||||
node_one = session.add_node(_type=NodeTypes.SWITCH)
|
||||
node_two = session.add_node(_type=NodeTypes.SWITCH)
|
||||
|
||||
# when
|
||||
session.add_link(node_one.objid, node_two.objid)
|
||||
|
||||
# then
|
||||
assert node_one.all_link_data(0)
|
||||
|
||||
def test_link_update(self, session, ip_prefixes):
|
||||
# given
|
||||
node_one = session.add_node()
|
||||
node_two = session.add_node(_type=NodeTypes.SWITCH)
|
||||
interface_one = ip_prefixes.create_interface(node_one)
|
||||
session.add_link(node_one.objid, node_two.objid, interface_one)
|
||||
interface = node_one.netif(interface_one.id)
|
||||
output = utils.check_cmd(["tc", "qdisc", "show", "dev", interface.localname])
|
||||
assert "delay" not in output
|
||||
assert "rate" not in output
|
||||
assert "loss" not in output
|
||||
assert "duplicate" not in output
|
||||
|
||||
# when
|
||||
link_options = LinkOptions()
|
||||
link_options.delay = 50
|
||||
link_options.bandwidth = 5000000
|
||||
link_options.per = 25
|
||||
link_options.dup = 25
|
||||
session.update_link(node_one.objid, node_two.objid,
|
||||
interface_one_id=interface_one.id, link_options=link_options)
|
||||
|
||||
# then
|
||||
output = utils.check_cmd(["tc", "qdisc", "show", "dev", interface.localname])
|
||||
assert "delay" in output
|
||||
assert "rate" in output
|
||||
assert "loss" in output
|
||||
assert "duplicate" in output
|
||||
|
||||
def test_link_delete(self, session, ip_prefixes):
|
||||
# given
|
||||
node_one = session.add_node()
|
||||
node_two = session.add_node()
|
||||
interface_one = ip_prefixes.create_interface(node_one)
|
||||
interface_two = ip_prefixes.create_interface(node_two)
|
||||
session.add_link(node_one.objid, node_two.objid, interface_one, interface_two)
|
||||
assert node_one.netif(interface_one.id)
|
||||
assert node_two.netif(interface_two.id)
|
||||
assert session.get_node_count() == 3
|
||||
|
||||
# when
|
||||
session.delete_link(node_one.objid, node_two.objid, interface_one.id, interface_two.id)
|
||||
|
||||
# then
|
||||
assert not node_one.netif(interface_one.id)
|
||||
assert not node_two.netif(interface_two.id)
|
||||
assert session.get_node_count() == 2
|
||||
|
||||
def test_link_bandwidth(self, session, ip_prefixes):
|
||||
"""
|
||||
Test ptp node network with modifying link bandwidth.
|
||||
|
||||
:param core.future.coreemu.FutureSession session: session for test
|
||||
:param ip_prefixes: generates ip addresses for nodes
|
||||
"""
|
||||
|
||||
# create link network
|
||||
node_one, node_two = create_ptp_network(session, ip_prefixes)
|
||||
|
||||
# output csv index
|
||||
bandwidth_index = 8
|
||||
|
||||
# run iperf, validate normal bandwidth
|
||||
stdout = iperf(node_one, node_two, ip_prefixes)
|
||||
assert stdout
|
||||
value = int(stdout.split(',')[bandwidth_index])
|
||||
assert 900000 <= value <= 1100000
|
||||
|
||||
# change bandwidth in bits per second
|
||||
link_options = LinkOptions()
|
||||
link_options.bandwidth = 500000
|
||||
session.update_link(node_one.objid, node_two.objid, link_options=link_options)
|
||||
|
||||
# run iperf again
|
||||
stdout = iperf(node_one, node_two, ip_prefixes)
|
||||
assert stdout
|
||||
value = int(stdout.split(',')[bandwidth_index])
|
||||
assert 400000 <= value <= 600000
|
||||
|
||||
def test_link_loss(self, session, ip_prefixes):
|
||||
"""
|
||||
Test ptp node network with modifying link packet loss.
|
||||
|
||||
:param core.future.coreemu.FutureSession session: session for test
|
||||
:param ip_prefixes: generates ip addresses for nodes
|
||||
"""
|
||||
|
||||
# create link network
|
||||
node_one, node_two = create_ptp_network(session, ip_prefixes)
|
||||
|
||||
# output csv index
|
||||
loss_index = -2
|
||||
|
||||
# run iperf, validate normal bandwidth
|
||||
stdout = iperf(node_one, node_two, ip_prefixes)
|
||||
assert stdout
|
||||
value = float(stdout.split(',')[loss_index])
|
||||
assert 0 <= value <= 0.5
|
||||
|
||||
# change bandwidth in bits per second
|
||||
link_options = LinkOptions()
|
||||
link_options.per = 50
|
||||
session.update_link(node_one.objid, node_two.objid, link_options=link_options)
|
||||
|
||||
# run iperf again
|
||||
stdout = iperf(node_one, node_two, ip_prefixes)
|
||||
assert stdout
|
||||
value = float(stdout.split(',')[loss_index])
|
||||
assert 40 <= value <= 60
|
||||
|
||||
def test_link_delay(self, session, ip_prefixes):
|
||||
"""
|
||||
Test ptp node network with modifying link packet delay.
|
||||
|
||||
:param core.future.coreemu.FutureSession session: session for test
|
||||
:param ip_prefixes: generates ip addresses for nodes
|
||||
"""
|
||||
|
||||
# create link network
|
||||
node_one, node_two = create_ptp_network(session, ip_prefixes)
|
||||
|
||||
# run ping for delay information
|
||||
stdout = ping_output(node_one, node_two, ip_prefixes)
|
||||
assert stdout
|
||||
rtt_line = stdout.split("\n")[-1]
|
||||
rtt_values = rtt_line.split("=")[1].split("ms")[0].strip()
|
||||
rtt_avg = float(rtt_values.split("/")[2])
|
||||
assert 0 <= rtt_avg <= 0.2
|
||||
|
||||
# change delay in microseconds
|
||||
link_options = LinkOptions()
|
||||
link_options.delay = 1000000
|
||||
session.update_link(node_one.objid, node_two.objid, link_options=link_options)
|
||||
|
||||
# run ping for delay information again
|
||||
stdout = ping_output(node_one, node_two, ip_prefixes)
|
||||
assert stdout
|
||||
rtt_line = stdout.split("\n")[-1]
|
||||
rtt_values = rtt_line.split("=")[1].split("ms")[0].strip()
|
||||
rtt_avg = float(rtt_values.split("/")[2])
|
||||
assert 1800 <= rtt_avg <= 2200
|
||||
|
||||
def test_link_jitter(self, session, ip_prefixes):
|
||||
"""
|
||||
Test ptp node network with modifying link packet jitter.
|
||||
|
||||
:param core.future.coreemu.FutureSession session: session for test
|
||||
:param ip_prefixes: generates ip addresses for nodes
|
||||
"""
|
||||
|
||||
# create link network
|
||||
node_one, node_two = create_ptp_network(session, ip_prefixes)
|
||||
|
||||
# output csv index
|
||||
jitter_index = 9
|
||||
|
||||
# run iperf
|
||||
stdout = iperf(node_one, node_two, ip_prefixes)
|
||||
assert stdout
|
||||
value = float(stdout.split(",")[jitter_index])
|
||||
assert -0.5 <= value <= 0.05
|
||||
|
||||
# change jitter in microseconds
|
||||
link_options = LinkOptions()
|
||||
link_options.jitter = 1000000
|
||||
session.update_link(node_one.objid, node_two.objid, link_options=link_options)
|
||||
|
||||
# run iperf again
|
||||
stdout = iperf(node_one, node_two, ip_prefixes)
|
||||
assert stdout
|
||||
value = float(stdout.split(",")[jitter_index])
|
||||
assert 200 <= value <= 500
|
79
daemon/tests/test_nodes.py
Normal file
79
daemon/tests/test_nodes.py
Normal file
|
@ -0,0 +1,79 @@
|
|||
import os
|
||||
import time
|
||||
|
||||
import pytest
|
||||
|
||||
from core.enumerations import NodeTypes
|
||||
from core.future.futuredata import NodeOptions
|
||||
from core.misc import utils
|
||||
|
||||
MODELS = [
|
||||
"router",
|
||||
"host",
|
||||
"PC",
|
||||
"mdr",
|
||||
]
|
||||
|
||||
NET_TYPES = [
|
||||
NodeTypes.SWITCH,
|
||||
NodeTypes.HUB,
|
||||
NodeTypes.WIRELESS_LAN
|
||||
]
|
||||
|
||||
|
||||
class TestNodes:
|
||||
@pytest.mark.parametrize("model", MODELS)
|
||||
def test_node_add(self, session, model):
|
||||
# given
|
||||
node_options = NodeOptions(model=model)
|
||||
|
||||
# when
|
||||
node = session.add_node(node_options=node_options)
|
||||
|
||||
# give time for node services to boot
|
||||
time.sleep(1)
|
||||
|
||||
# then
|
||||
assert node
|
||||
assert os.path.exists(node.nodedir)
|
||||
assert node.alive()
|
||||
assert node.up
|
||||
assert node.check_cmd(["ip", "addr", "show", "lo"])
|
||||
node.validate()
|
||||
|
||||
def test_node_update(self, session):
|
||||
# given
|
||||
node = session.add_node()
|
||||
position_value = 100
|
||||
update_options = NodeOptions()
|
||||
update_options.set_position(x=position_value, y=position_value)
|
||||
|
||||
# when
|
||||
session.update_node(node.objid, update_options)
|
||||
|
||||
# then
|
||||
assert node.position.x == position_value
|
||||
assert node.position.y == position_value
|
||||
|
||||
def test_node_delete(self, session):
|
||||
# given
|
||||
node = session.add_node()
|
||||
|
||||
# when
|
||||
session.delete_node(node.objid)
|
||||
|
||||
# then
|
||||
with pytest.raises(KeyError):
|
||||
session.get_object(node.objid)
|
||||
|
||||
@pytest.mark.parametrize("net_type", NET_TYPES)
|
||||
def test_net(self, session, net_type):
|
||||
# given
|
||||
|
||||
# when
|
||||
node = session.add_node(_type=net_type)
|
||||
|
||||
# then
|
||||
assert node
|
||||
assert node.up
|
||||
assert utils.check_cmd(["brctl", "show", node.brname])
|
|
@ -386,7 +386,7 @@ class Ns3Session(Session):
|
|||
ns.core.Simulator.Run()
|
||||
|
||||
# self.evq.run() # event queue may have WayPointMobility events
|
||||
self.set_state(EventTypes.RUNTIME_STATE.value, send_event=True)
|
||||
self.set_state(EventTypes.RUNTIME_STATE, send_event=True)
|
||||
t = threading.Thread(target=runthread)
|
||||
t.daemon = True
|
||||
t.start()
|
||||
|
@ -454,7 +454,7 @@ class Ns3Session(Session):
|
|||
Start a thread that updates CORE nodes based on their ns-3
|
||||
positions.
|
||||
"""
|
||||
self.set_state(EventTypes.INSTANTIATION_STATE.value)
|
||||
self.set_state(EventTypes.INSTANTIATION_STATE)
|
||||
self.mobilitythread = threading.Thread(
|
||||
target=self.ns3mobilitythread,
|
||||
args=(refresh_ms,))
|
||||
|
|
Loading…
Add table
Reference in a new issue