Merge branch 'develop' into coretk

This commit is contained in:
Blake Harnden 2019-10-31 09:42:14 -07:00
commit e19e8c12f7
66 changed files with 1702 additions and 1695 deletions

View file

@ -17,6 +17,8 @@ jobs:
pip install pipenv pip install pipenv
cd daemon cd daemon
cp setup.py.in setup.py cp setup.py.in setup.py
cp core/constants.py.in core/constants.py
sed -i 's/True/False/g' core/constants.py
pipenv install --dev pipenv install --dev
- name: isort - name: isort
run: | run: |
@ -30,3 +32,11 @@ jobs:
run: | run: |
cd daemon cd daemon
pipenv run flake8 pipenv run flake8
- name: grpc
run: |
cd daemon/proto
pipenv run python -m grpc_tools.protoc -I . --python_out=.. --grpc_python_out=.. core/api/grpc/core.proto
- name: test
run: |
cd daemon
pipenv run test --mock

View file

@ -14,7 +14,7 @@ from core.api.grpc import core_pb2, core_pb2_grpc
from core.nodes.ipaddress import Ipv4Prefix, Ipv6Prefix, MacAddress from core.nodes.ipaddress import Ipv4Prefix, Ipv6Prefix, MacAddress
class InterfaceHelper(object): class InterfaceHelper:
""" """
Convenience class to help generate IP4 and IP6 addresses for gRPC clients. Convenience class to help generate IP4 and IP6 addresses for gRPC clients.
""" """
@ -133,7 +133,7 @@ def start_streamer(stream, handler):
thread.start() thread.start()
class CoreGrpcClient(object): class CoreGrpcClient:
""" """
Provides convenience methods for interfacing with the CORE grpc server. Provides convenience methods for interfacing with the CORE grpc server.
""" """
@ -148,6 +148,57 @@ class CoreGrpcClient(object):
self.stub = None self.stub = None
self.channel = None self.channel = None
def start_session(
self,
session_id,
nodes,
links,
location=None,
hooks=None,
emane_config=None,
emane_model_configs=None,
wlan_configs=None,
mobility_configs=None,
):
"""
Start a session.
:param int session_id: id of session
:param list nodes: list of nodes to create
:param list links: list of links to create
:param core_pb2.SessionLocation location: location to set
:param list[core_pb2.Hook] hooks: session hooks to set
:param dict emane_config: emane configuration to set
:param list emane_model_configs: emane model configurations to set
:param list wlan_configs: wlan configurations to set
:param list mobility_configs: mobility configurations to set
:return: start session response
:rtype: core_pb2.StartSessionResponse
"""
request = core_pb2.StartSessionRequest(
session_id=session_id,
nodes=nodes,
links=links,
location=location,
hooks=hooks,
emane_config=emane_config,
emane_model_configs=emane_model_configs,
wlan_configs=wlan_configs,
mobility_configs=mobility_configs,
)
return self.stub.StartSession(request)
def stop_session(self, session_id):
"""
Stop a running session.
:param int session_id: id of session
:return: stop session response
:rtype: core_pb2.StopSessionResponse
"""
request = core_pb2.StopSessionRequest(session_id=session_id)
return self.stub.StopSession(request)
def create_session(self, session_id=None): def create_session(self, session_id=None):
""" """
Create a session. Create a session.
@ -204,18 +255,6 @@ class CoreGrpcClient(object):
request = core_pb2.GetSessionOptionsRequest(session_id=session_id) request = core_pb2.GetSessionOptionsRequest(session_id=session_id)
return self.stub.GetSessionOptions(request) return self.stub.GetSessionOptions(request)
def get_session_options_group(self, session_id):
"""
Retrieve session options in a group list.
:param int session_id: id of session
:return: response with a list of configuration groups
:rtype: core_pb2.GetSessionOptionsGroupResponse
:raises grpc.RpcError: when session doesn't exist
"""
request = core_pb2.GetSessionOptionsGroupRequest(session_id=session_id)
return self.stub.GetSessionOptionsGroup(request)
def set_session_options(self, session_id, config): def set_session_options(self, session_id, config):
""" """
Set options for a session. Set options for a session.
@ -231,6 +270,33 @@ class CoreGrpcClient(object):
) )
return self.stub.SetSessionOptions(request) return self.stub.SetSessionOptions(request)
def get_session_metadata(self, session_id):
"""
Retrieve session metadata as a dict with id mapping.
:param int session_id: id of session
:return: response with metadata dict
:rtype: core_pb2.GetSessionMetadataResponse
:raises grpc.RpcError: when session doesn't exist
"""
request = core_pb2.GetSessionMetadataRequest(session_id=session_id)
return self.stub.GetSessionMetadata(request)
def set_session_metadata(self, session_id, config):
"""
Set metadata for a session.
:param int session_id: id of session
:param dict[str, str] config: configuration values to set
:return: response with result of success or failure
:rtype: core_pb2.SetSessionMetadataResponse
:raises grpc.RpcError: when session doesn't exist
"""
request = core_pb2.SetSessionMetadataRequest(
session_id=session_id, config=config
)
return self.stub.SetSessionMetadata(request)
def get_session_location(self, session_id): def get_session_location(self, session_id):
""" """
Get session location. Get session location.
@ -269,9 +335,11 @@ class CoreGrpcClient(object):
:rtype: core_pb2.SetSessionLocationResponse :rtype: core_pb2.SetSessionLocationResponse
:raises grpc.RpcError: when session doesn't exist :raises grpc.RpcError: when session doesn't exist
""" """
position = core_pb2.SessionPosition(x=x, y=y, z=z, lat=lat, lon=lon, alt=alt) location = core_pb2.SessionLocation(
x=x, y=y, z=z, lat=lat, lon=lon, alt=alt, scale=scale
)
request = core_pb2.SetSessionLocationRequest( request = core_pb2.SetSessionLocationRequest(
session_id=session_id, position=position, scale=scale session_id=session_id, location=location
) )
return self.stub.SetSessionLocation(request) return self.stub.SetSessionLocation(request)
@ -587,8 +655,9 @@ class CoreGrpcClient(object):
:rtype: core_pb2.SetMobilityConfigResponse :rtype: core_pb2.SetMobilityConfigResponse
:raises grpc.RpcError: when session or node doesn't exist :raises grpc.RpcError: when session or node doesn't exist
""" """
mobility_config = core_pb2.MobilityConfig(node_id=node_id, config=config)
request = core_pb2.SetMobilityConfigRequest( request = core_pb2.SetMobilityConfigRequest(
session_id=session_id, node_id=node_id, config=config session_id=session_id, mobility_config=mobility_config
) )
return self.stub.SetMobilityConfig(request) return self.stub.SetMobilityConfig(request)
@ -772,8 +841,9 @@ class CoreGrpcClient(object):
:rtype: core_pb2.SetWlanConfigResponse :rtype: core_pb2.SetWlanConfigResponse
:raises grpc.RpcError: when session doesn't exist :raises grpc.RpcError: when session doesn't exist
""" """
wlan_config = core_pb2.WlanConfig(node_id=node_id, config=config)
request = core_pb2.SetWlanConfigRequest( request = core_pb2.SetWlanConfigRequest(
session_id=session_id, node_id=node_id, config=config session_id=session_id, wlan_config=wlan_config
) )
return self.stub.SetWlanConfig(request) return self.stub.SetWlanConfig(request)
@ -846,12 +916,11 @@ class CoreGrpcClient(object):
:rtype: core_pb2.SetEmaneModelConfigResponse :rtype: core_pb2.SetEmaneModelConfigResponse
:raises grpc.RpcError: when session doesn't exist :raises grpc.RpcError: when session doesn't exist
""" """
model_config = core_pb2.EmaneModelConfig(
node_id=node_id, model=model, config=config, interface_id=interface_id
)
request = core_pb2.SetEmaneModelConfigRequest( request = core_pb2.SetEmaneModelConfigRequest(
session_id=session_id, session_id=session_id, emane_model_config=model_config
node_id=node_id,
model=model,
config=config,
interface_id=interface_id,
) )
return self.stub.SetEmaneModelConfig(request) return self.stub.SetEmaneModelConfig(request)

View file

@ -0,0 +1,321 @@
import logging
import time
from core import utils
from core.api.grpc import core_pb2
from core.emulator.emudata import InterfaceData, LinkOptions, NodeOptions
from core.emulator.enumerations import LinkTypes, NodeTypes
from core.nodes.base import CoreNetworkBase
from core.nodes.ipaddress import MacAddress
WORKERS = 10
def add_node_data(node_proto):
"""
Convert node protobuf message to data for creating a node.
:param core_pb2.Node node_proto: node proto message
:return: node type, id, and options
:rtype: tuple
"""
_id = node_proto.id
_type = node_proto.type
if _type is None:
_type = NodeTypes.DEFAULT.value
_type = NodeTypes(_type)
options = NodeOptions(name=node_proto.name, model=node_proto.model)
options.icon = node_proto.icon
options.opaque = node_proto.opaque
options.image = node_proto.image
options.services = node_proto.services
if node_proto.server:
options.server = node_proto.server
position = node_proto.position
options.set_position(position.x, position.y)
options.set_location(position.lat, position.lon, position.alt)
return _type, _id, options
def link_interface(interface_proto):
"""
Create interface data from interface proto.
:param core_pb2.Interface interface_proto: interface proto
:return: interface data
:rtype: InterfaceData
"""
interface = None
if interface_proto:
name = interface_proto.name
if name == "":
name = None
mac = interface_proto.mac
if mac == "":
mac = None
else:
mac = MacAddress.from_string(mac)
interface = InterfaceData(
_id=interface_proto.id,
name=name,
mac=mac,
ip4=interface_proto.ip4,
ip4_mask=interface_proto.ip4mask,
ip6=interface_proto.ip6,
ip6_mask=interface_proto.ip6mask,
)
return interface
def add_link_data(link_proto):
"""
Convert link proto to link interfaces and options data.
:param core_pb2.Link link_proto: link proto
:return: link interfaces and options
:rtype: tuple
"""
interface_one = link_interface(link_proto.interface_one)
interface_two = link_interface(link_proto.interface_two)
link_type = None
link_type_value = link_proto.type
if link_type_value is not None:
link_type = LinkTypes(link_type_value)
options = LinkOptions(_type=link_type)
options_data = link_proto.options
if options_data:
options.delay = options_data.delay
options.bandwidth = options_data.bandwidth
options.per = options_data.per
options.dup = options_data.dup
options.jitter = options_data.jitter
options.mer = options_data.mer
options.burst = options_data.burst
options.mburst = options_data.mburst
options.unidirectional = options_data.unidirectional
options.key = options_data.key
options.opaque = options_data.opaque
return interface_one, interface_two, options
def create_nodes(session, node_protos):
"""
Create nodes using a thread pool and wait for completion.
:param core.emulator.session.Session session: session to create nodes in
:param list[core_pb2.Node] node_protos: node proto messages
:return: results and exceptions for created nodes
:rtype: tuple
"""
funcs = []
for node_proto in node_protos:
_type, _id, options = add_node_data(node_proto)
args = (_type, _id, options)
funcs.append((session.add_node, args, {}))
start = time.monotonic()
results, exceptions = utils.threadpool(funcs)
total = time.monotonic() - start
logging.debug("grpc created nodes time: %s", total)
return results, exceptions
def create_links(session, link_protos):
"""
Create nodes using a thread pool and wait for completion.
:param core.emulator.session.Session session: session to create nodes in
:param list[core_pb2.Link] link_protos: link proto messages
:return: results and exceptions for created links
:rtype: tuple
"""
funcs = []
for link_proto in link_protos:
node_one_id = link_proto.node_one_id
node_two_id = link_proto.node_two_id
interface_one, interface_two, options = add_link_data(link_proto)
args = (node_one_id, node_two_id, interface_one, interface_two, options)
funcs.append((session.add_link, args, {}))
start = time.monotonic()
results, exceptions = utils.threadpool(funcs)
total = time.monotonic() - start
logging.debug("grpc created links time: %s", total)
return results, exceptions
def convert_value(value):
"""
Convert value into string.
:param value: value
:return: string conversion of the value
:rtype: str
"""
if value is not None:
value = str(value)
return value
def get_config_options(config, configurable_options):
"""
Retrieve configuration options in a form that is used by the grpc server.
:param dict config: configuration
:param core.config.ConfigurableOptions configurable_options: configurable options
:return: mapping of configuration ids to configuration options
:rtype: dict[str,core.api.grpc.core_pb2.ConfigOption]
"""
results = {}
for configuration in configurable_options.configurations():
value = config[configuration.id]
config_option = core_pb2.ConfigOption(
label=configuration.label,
name=configuration.id,
value=value,
type=configuration.type.value,
select=configuration.options,
)
results[configuration.id] = config_option
for config_group in configurable_options.config_groups():
start = config_group.start - 1
stop = config_group.stop
options = list(results.values())[start:stop]
for option in options:
option.group = config_group.name
return results
def get_links(session, node):
"""
Retrieve a list of links for grpc to use
:param core.emulator.Session session: node's section
:param core.nodes.base.CoreNode node: node to get links from
:return: [core.api.grpc.core_pb2.Link]
"""
links = []
for link_data in node.all_link_data(0):
link = convert_link(session, link_data)
links.append(link)
return links
def get_emane_model_id(node_id, interface_id):
"""
Get EMANE model id
:param int node_id: node id
:param int interface_id: interface id
:return: EMANE model id
:rtype: int
"""
if interface_id >= 0:
return node_id * 1000 + interface_id
else:
return node_id
def convert_link(session, link_data):
"""
Convert link_data into core protobuf Link
:param core.emulator.session.Session session:
:param core.emulator.data.LinkData link_data:
:return: core protobuf Link
:rtype: core.api.grpc.core_pb2.Link
"""
interface_one = None
if link_data.interface1_id is not None:
node = session.get_node(link_data.node1_id)
interface_name = None
if not isinstance(node, CoreNetworkBase):
interface = node.netif(link_data.interface1_id)
interface_name = interface.name
interface_one = core_pb2.Interface(
id=link_data.interface1_id,
name=interface_name,
mac=convert_value(link_data.interface1_mac),
ip4=convert_value(link_data.interface1_ip4),
ip4mask=link_data.interface1_ip4_mask,
ip6=convert_value(link_data.interface1_ip6),
ip6mask=link_data.interface1_ip6_mask,
)
interface_two = None
if link_data.interface2_id is not None:
node = session.get_node(link_data.node2_id)
interface_name = None
if not isinstance(node, CoreNetworkBase):
interface = node.netif(link_data.interface2_id)
interface_name = interface.name
interface_two = core_pb2.Interface(
id=link_data.interface2_id,
name=interface_name,
mac=convert_value(link_data.interface2_mac),
ip4=convert_value(link_data.interface2_ip4),
ip4mask=link_data.interface2_ip4_mask,
ip6=convert_value(link_data.interface2_ip6),
ip6mask=link_data.interface2_ip6_mask,
)
options = core_pb2.LinkOptions(
opaque=link_data.opaque,
jitter=link_data.jitter,
key=link_data.key,
mburst=link_data.mburst,
mer=link_data.mer,
per=link_data.per,
bandwidth=link_data.bandwidth,
burst=link_data.burst,
delay=link_data.delay,
dup=link_data.dup,
unidirectional=link_data.unidirectional,
)
return core_pb2.Link(
type=link_data.link_type,
node_one_id=link_data.node1_id,
node_two_id=link_data.node2_id,
interface_one=interface_one,
interface_two=interface_two,
options=options,
)
def get_net_stats():
"""
Retrieve status about the current interfaces in the system
:return: send and receive status of the interfaces in the system
:rtype: dict
"""
with open("/proc/net/dev", "r") as f:
data = f.readlines()[2:]
stats = {}
for line in data:
line = line.strip()
if not line:
continue
line = line.split()
line[0] = line[0].strip(":")
stats[line[0]] = {"rx": float(line[1]), "tx": float(line[9])}
return stats
def session_location(session, location):
"""
Set session location based on location proto.
:param core.emulator.session.Session session: session for location
:param core_pb2.SessionLocation location: location to set
:return: nothing
"""
session.location.refxyz = (location.x, location.y, location.z)
session.location.setrefgeo(location.lat, location.lon, location.alt)
session.location.refscale = location.scale

View file

@ -9,7 +9,14 @@ from queue import Empty, Queue
import grpc import grpc
from core.api.grpc import core_pb2, core_pb2_grpc from core.api.grpc import core_pb2, core_pb2_grpc, grpcutils
from core.api.grpc.grpcutils import (
convert_value,
get_config_options,
get_emane_model_id,
get_links,
get_net_stats,
)
from core.emane.nodes import EmaneNet from core.emane.nodes import EmaneNet
from core.emulator.data import ( from core.emulator.data import (
ConfigData, ConfigData,
@ -19,13 +26,11 @@ from core.emulator.data import (
LinkData, LinkData,
NodeData, NodeData,
) )
from core.emulator.emudata import InterfaceData, LinkOptions, NodeOptions from core.emulator.emudata import LinkOptions, NodeOptions
from core.emulator.enumerations import EventTypes, LinkTypes, MessageFlags, NodeTypes from core.emulator.enumerations import EventTypes, LinkTypes, MessageFlags
from core.errors import CoreCommandError, CoreError from core.errors import CoreCommandError, CoreError
from core.location.mobility import BasicRangeModel, Ns2ScriptedMobility from core.location.mobility import BasicRangeModel, Ns2ScriptedMobility
from core.nodes.base import CoreNetworkBase
from core.nodes.docker import DockerNode from core.nodes.docker import DockerNode
from core.nodes.ipaddress import MacAddress
from core.nodes.lxd import LxcNode from core.nodes.lxd import LxcNode
from core.services.coreservices import ServiceManager from core.services.coreservices import ServiceManager
@ -33,167 +38,6 @@ _ONE_DAY_IN_SECONDS = 60 * 60 * 24
_INTERFACE_REGEX = re.compile(r"\d+") _INTERFACE_REGEX = re.compile(r"\d+")
def convert_value(value):
"""
Convert value into string.
:param value: value
:return: string conversion of the value
:rtype: str
"""
if value is not None:
value = str(value)
return value
def get_config_options(config, configurable_options):
"""
Retrieve configuration options in a form that is used by the grpc server.
:param dict config: configuration
:param core.config.ConfigurableOptions configurable_options: configurable options
:return: mapping of configuration ids to configuration options
:rtype: dict[str,core.api.grpc.core_pb2.ConfigOption]
"""
results = {}
for configuration in configurable_options.configurations():
value = config[configuration.id]
config_option = core_pb2.ConfigOption(
label=configuration.label,
name=configuration.id,
value=value,
type=configuration.type.value,
select=configuration.options,
)
results[configuration.id] = config_option
for config_group in configurable_options.config_groups():
start = config_group.start - 1
stop = config_group.stop
options = list(results.values())[start:stop]
for option in options:
option.group = config_group.name
return results
def get_links(session, node):
"""
Retrieve a list of links for grpc to use
:param core.emulator.Session session: node's section
:param core.nodes.base.CoreNode node: node to get links from
:return: [core.api.grpc.core_pb2.Link]
"""
links = []
for link_data in node.all_link_data(0):
link = convert_link(session, link_data)
links.append(link)
return links
def get_emane_model_id(node_id, interface_id):
"""
Get EMANE model id
:param int node_id: node id
:param int interface_id: interface id
:return: EMANE model id
:rtype: int
"""
if interface_id >= 0:
return node_id * 1000 + interface_id
else:
return node_id
def convert_link(session, link_data):
"""
Convert link_data into core protobuf Link
:param core.emulator.session.Session session:
:param core.emulator.data.LinkData link_data:
:return: core protobuf Link
:rtype: core.api.grpc.core_pb2.Link
"""
interface_one = None
if link_data.interface1_id is not None:
node = session.get_node(link_data.node1_id)
interface_name = None
if not isinstance(node, CoreNetworkBase):
interface = node.netif(link_data.interface1_id)
interface_name = interface.name
interface_one = core_pb2.Interface(
id=link_data.interface1_id,
name=interface_name,
mac=convert_value(link_data.interface1_mac),
ip4=convert_value(link_data.interface1_ip4),
ip4mask=link_data.interface1_ip4_mask,
ip6=convert_value(link_data.interface1_ip6),
ip6mask=link_data.interface1_ip6_mask,
)
interface_two = None
if link_data.interface2_id is not None:
node = session.get_node(link_data.node2_id)
interface_name = None
if not isinstance(node, CoreNetworkBase):
interface = node.netif(link_data.interface2_id)
interface_name = interface.name
interface_two = core_pb2.Interface(
id=link_data.interface2_id,
name=interface_name,
mac=convert_value(link_data.interface2_mac),
ip4=convert_value(link_data.interface2_ip4),
ip4mask=link_data.interface2_ip4_mask,
ip6=convert_value(link_data.interface2_ip6),
ip6mask=link_data.interface2_ip6_mask,
)
options = core_pb2.LinkOptions(
opaque=link_data.opaque,
jitter=link_data.jitter,
key=link_data.key,
mburst=link_data.mburst,
mer=link_data.mer,
per=link_data.per,
bandwidth=link_data.bandwidth,
burst=link_data.burst,
delay=link_data.delay,
dup=link_data.dup,
unidirectional=link_data.unidirectional,
)
return core_pb2.Link(
type=link_data.link_type,
node_one_id=link_data.node1_id,
node_two_id=link_data.node2_id,
interface_one=interface_one,
interface_two=interface_two,
options=options,
)
def get_net_stats():
"""
Retrieve status about the current interfaces in the system
:return: send and receive status of the interfaces in the system
:rtype: dict
"""
with open("/proc/net/dev", "r") as f:
data = f.readlines()[2:]
stats = {}
for line in data:
line = line.strip()
if not line:
continue
line = line.split()
line[0] = line[0].strip(":")
stats[line[0]] = {"rx": float(line[1]), "tx": float(line[9])}
return stats
class CoreGrpcServer(core_pb2_grpc.CoreApiServicer): class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
""" """
Create CoreGrpcServer instance Create CoreGrpcServer instance
@ -202,7 +46,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
""" """
def __init__(self, coreemu): def __init__(self, coreemu):
super(CoreGrpcServer, self).__init__() super().__init__()
self.coreemu = coreemu self.coreemu = coreemu
self.running = True self.running = True
self.server = None self.server = None
@ -237,7 +81,8 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
:param int session_id: session id :param int session_id: session id
:param grpc.ServicerContext context: :param grpc.ServicerContext context:
:return: session object that satisfies. If session not found then raise an exception. :return: session object that satisfies, if session not found then raise an
exception
:rtype: core.emulator.session.Session :rtype: core.emulator.session.Session
""" """
session = self.coreemu.sessions.get(session_id) session = self.coreemu.sessions.get(session_id)
@ -260,6 +105,80 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
except CoreError: except CoreError:
context.abort(grpc.StatusCode.NOT_FOUND, f"node {node_id} not found") context.abort(grpc.StatusCode.NOT_FOUND, f"node {node_id} not found")
def StartSession(self, request, context):
"""
Start a session.
:param core.api.grpc.core_pb2.StartSessionRequest request: start session request
:param context: grcp context
:return: start session response
:rtype: core.api.grpc.core_pb2.StartSessionResponse
"""
logging.debug("start session: %s", request)
session = self.get_session(request.session_id, context)
# clear previous state and setup for creation
session.clear()
session.set_state(EventTypes.CONFIGURATION_STATE)
if not os.path.exists(session.session_dir):
os.mkdir(session.session_dir)
# location
if request.HasField("location"):
grpcutils.session_location(session, request.location)
# add all hooks
for hook in request.hooks:
session.add_hook(hook.state, hook.file, None, hook.data)
# create nodes
grpcutils.create_nodes(session, request.nodes)
# emane configs
config = session.emane.get_configs()
config.update(request.emane_config)
for config in request.emane_model_configs:
_id = get_emane_model_id(config.node_id, config.interface_id)
session.emane.set_model_config(_id, config.model, config.config)
# wlan configs
for config in request.wlan_configs:
session.mobility.set_model_config(
config.node_id, BasicRangeModel.name, config.config
)
# mobility configs
for config in request.mobility_configs:
session.mobility.set_model_config(
config.node_id, Ns2ScriptedMobility.name, config.config
)
# create links
grpcutils.create_links(session, request.links)
# set to instantiation and start
session.set_state(EventTypes.INSTANTIATION_STATE)
session.instantiate()
return core_pb2.StartSessionResponse(result=True)
def StopSession(self, request, context):
"""
Stop a running session.
:param core.api.grpc.core_pb2.StopSessionRequest request: stop session request
:param context: grcp context
:return: stop session response
:rtype: core.api.grpc.core_pb2.StopSessionResponse
"""
logging.debug("stop session: %s", request)
session = self.get_session(request.session_id, context)
session.data_collect()
session.set_state(EventTypes.DATACOLLECT_STATE)
session.clear()
session.set_state(EventTypes.SHUTDOWN_STATE)
return core_pb2.StopSessionResponse(result=True)
def CreateSession(self, request, context): def CreateSession(self, request, context):
""" """
Create a session Create a session
@ -326,10 +245,11 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
session = self.get_session(request.session_id, context) session = self.get_session(request.session_id, context)
x, y, z = session.location.refxyz x, y, z = session.location.refxyz
lat, lon, alt = session.location.refgeo lat, lon, alt = session.location.refgeo
position = core_pb2.SessionPosition(x=x, y=y, z=z, lat=lat, lon=lon, alt=alt) scale = session.location.refscale
return core_pb2.GetSessionLocationResponse( location = core_pb2.SessionLocation(
position=position, scale=session.location.refscale x=x, y=y, z=z, lat=lat, lon=lon, alt=alt, scale=scale
) )
return core_pb2.GetSessionLocationResponse(location=location)
def SetSessionLocation(self, request, context): def SetSessionLocation(self, request, context):
""" """
@ -342,15 +262,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
""" """
logging.debug("set session location: %s", request) logging.debug("set session location: %s", request)
session = self.get_session(request.session_id, context) session = self.get_session(request.session_id, context)
session.location.refxyz = ( grpcutils.session_location(session, request.location)
request.position.x,
request.position.y,
request.position.z,
)
session.location.setrefgeo(
request.position.lat, request.position.lon, request.position.alt
)
session.location.refscale = request.scale
return core_pb2.SetSessionLocationResponse(result=True) return core_pb2.SetSessionLocationResponse(result=True)
def SetSessionState(self, request, context): def SetSessionState(self, request, context):
@ -419,6 +331,34 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
config.update(request.config) config.update(request.config)
return core_pb2.SetSessionOptionsResponse(result=True) return core_pb2.SetSessionOptionsResponse(result=True)
def GetSessionMetadata(self, request, context):
"""
Retrieve session metadata.
:param core.api.grpc.core_pb2.GetSessionMetadata request: get session metadata
request
:param grpc.ServicerContext context: context object
:return: get session metadata response
:rtype: core.api.grpc.core_pb2.GetSessionMetadata
"""
logging.debug("get session metadata: %s", request)
session = self.get_session(request.session_id, context)
return core_pb2.GetSessionMetadataResponse(config=session.metadata)
def SetSessionMetadata(self, request, context):
"""
Update a session's metadata.
:param core.api.grpc.core_pb2.SetSessionMetadata request: set metadata request
:param grpc.ServicerContext context: context object
:return: set metadata response
:rtype: core.api.grpc.core_pb2.SetSessionMetadataResponse
"""
logging.debug("set session metadata: %s", request)
session = self.get_session(request.session_id, context)
session.metadata = dict(request.config)
return core_pb2.SetSessionMetadataResponse(result=True)
def GetSession(self, request, context): def GetSession(self, request, context):
""" """
Retrieve requested session Retrieve requested session
@ -761,32 +701,12 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
""" """
logging.debug("add node: %s", request) logging.debug("add node: %s", request)
session = self.get_session(request.session_id, context) session = self.get_session(request.session_id, context)
_type, _id, options = grpcutils.add_node_data(request.node)
node_proto = request.node node = session.add_node(_type=_type, _id=_id, options=options)
node_id = node_proto.id
node_type = node_proto.type
if node_type is None:
node_type = NodeTypes.DEFAULT.value
node_type = NodeTypes(node_type)
node_options = NodeOptions(name=node_proto.name, model=node_proto.model)
node_options.icon = node_proto.icon
node_options.opaque = node_proto.opaque
node_options.image = node_proto.image
node_options.services = node_proto.services
if node_proto.server:
node_options.emulation_server = node_proto.server
position = node_proto.position
node_options.set_position(position.x, position.y)
node_options.set_location(position.lat, position.lon, position.alt)
node = session.add_node(_type=node_type, _id=node_id, node_options=node_options)
# configure emane if provided # configure emane if provided
emane_model = node_proto.emane emane_model = request.node.emane
if emane_model: if emane_model:
session.emane.set_model_config(node_id, emane_model) session.emane.set_model_config(id, emane_model)
return core_pb2.AddNodeResponse(node_id=node.id) return core_pb2.AddNodeResponse(node_id=node.id)
def GetNode(self, request, context): def GetNode(self, request, context):
@ -856,18 +776,18 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
logging.debug("edit node: %s", request) logging.debug("edit node: %s", request)
session = self.get_session(request.session_id, context) session = self.get_session(request.session_id, context)
node = self.get_node(session, request.node_id, context) node = self.get_node(session, request.node_id, context)
node_options = NodeOptions() options = NodeOptions()
node_options.icon = request.icon options.icon = request.icon
x = request.position.x x = request.position.x
y = request.position.y y = request.position.y
node_options.set_position(x, y) options.set_position(x, y)
lat = request.position.lat lat = request.position.lat
lon = request.position.lon lon = request.position.lon
alt = request.position.alt alt = request.position.alt
node_options.set_location(lat, lon, alt) options.set_location(lat, lon, alt)
result = True result = True
try: try:
session.update_node(node.id, node_options) session.edit_node(node.id, options)
node_data = node.data(0) node_data = node.data(0)
session.broadcast_node(node_data) session.broadcast_node(node_data)
except CoreError: except CoreError:
@ -944,82 +864,16 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
:rtype: core.api.grpc.AddLinkResponse :rtype: core.api.grpc.AddLinkResponse
""" """
logging.debug("add link: %s", request) logging.debug("add link: %s", request)
# validate session and nodes
session = self.get_session(request.session_id, context) session = self.get_session(request.session_id, context)
# validate node exist
self.get_node(session, request.link.node_one_id, context) self.get_node(session, request.link.node_one_id, context)
self.get_node(session, request.link.node_two_id, context) self.get_node(session, request.link.node_two_id, context)
node_one_id = request.link.node_one_id node_one_id = request.link.node_one_id
node_two_id = request.link.node_two_id node_two_id = request.link.node_two_id
interface_one, interface_two, options = grpcutils.add_link_data(request.link)
interface_one = None
interface_one_data = request.link.interface_one
if interface_one_data:
name = interface_one_data.name
if name == "":
name = None
mac = interface_one_data.mac
if mac == "":
mac = None
else:
mac = MacAddress.from_string(mac)
interface_one = InterfaceData(
_id=interface_one_data.id,
name=name,
mac=mac,
ip4=interface_one_data.ip4,
ip4_mask=interface_one_data.ip4mask,
ip6=interface_one_data.ip6,
ip6_mask=interface_one_data.ip6mask,
)
interface_two = None
interface_two_data = request.link.interface_two
if interface_two_data:
name = interface_two_data.name
if name == "":
name = None
mac = interface_two_data.mac
if mac == "":
mac = None
else:
mac = MacAddress.from_string(mac)
interface_two = InterfaceData(
_id=interface_two_data.id,
name=name,
mac=mac,
ip4=interface_two_data.ip4,
ip4_mask=interface_two_data.ip4mask,
ip6=interface_two_data.ip6,
ip6_mask=interface_two_data.ip6mask,
)
link_type = None
link_type_value = request.link.type
if link_type_value is not None:
link_type = LinkTypes(link_type_value)
options_data = request.link.options
link_options = LinkOptions(_type=link_type)
if options_data:
link_options.delay = options_data.delay
link_options.bandwidth = options_data.bandwidth
link_options.per = options_data.per
link_options.dup = options_data.dup
link_options.jitter = options_data.jitter
link_options.mer = options_data.mer
link_options.burst = options_data.burst
link_options.mburst = options_data.mburst
link_options.unidirectional = options_data.unidirectional
link_options.key = options_data.key
link_options.opaque = options_data.opaque
session.add_link( session.add_link(
node_one_id, node_one_id, node_two_id, interface_one, interface_two, link_options=options
node_two_id,
interface_one,
interface_two,
link_options=link_options,
) )
return core_pb2.AddLinkResponse(result=True) return core_pb2.AddLinkResponse(result=True)
@ -1166,8 +1020,9 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
""" """
logging.debug("set mobility config: %s", request) logging.debug("set mobility config: %s", request)
session = self.get_session(request.session_id, context) session = self.get_session(request.session_id, context)
mobility_config = request.mobility_config
session.mobility.set_model_config( session.mobility.set_model_config(
request.node_id, Ns2ScriptedMobility.name, request.config mobility_config.node_id, Ns2ScriptedMobility.name, mobility_config.config
) )
return core_pb2.SetMobilityConfigResponse(result=True) return core_pb2.SetMobilityConfigResponse(result=True)
@ -1408,12 +1263,13 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
""" """
logging.debug("set wlan config: %s", request) logging.debug("set wlan config: %s", request)
session = self.get_session(request.session_id, context) session = self.get_session(request.session_id, context)
wlan_config = request.wlan_config
session.mobility.set_model_config( session.mobility.set_model_config(
request.node_id, BasicRangeModel.name, request.config wlan_config.node_id, BasicRangeModel.name, wlan_config.config
) )
if session.state == EventTypes.RUNTIME_STATE.value: if session.state == EventTypes.RUNTIME_STATE.value:
node = self.get_node(session, request.node_id, context) node = self.get_node(session, wlan_config.node_id, context)
node.updatemodel(request.config) node.updatemodel(wlan_config.config)
return core_pb2.SetWlanConfigResponse(result=True) return core_pb2.SetWlanConfigResponse(result=True)
def GetEmaneConfig(self, request, context): def GetEmaneConfig(self, request, context):
@ -1494,8 +1350,9 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
""" """
logging.debug("set emane model config: %s", request) logging.debug("set emane model config: %s", request)
session = self.get_session(request.session_id, context) session = self.get_session(request.session_id, context)
_id = get_emane_model_id(request.node_id, request.interface_id) model_config = request.emane_model_config
session.emane.set_model_config(_id, request.model, request.config) _id = get_emane_model_id(model_config.node_id, model_config.interface_id)
session.emane.set_model_config(_id, model_config.model, model_config.config)
return core_pb2.SetEmaneModelConfigResponse(result=True) return core_pb2.SetEmaneModelConfigResponse(result=True)
def GetEmaneModelConfigs(self, request, context): def GetEmaneModelConfigs(self, request, context):

View file

@ -27,7 +27,7 @@ from core.emulator.enumerations import (
from core.nodes.ipaddress import IpAddress, MacAddress from core.nodes.ipaddress import IpAddress, MacAddress
class CoreTlvData(object): class CoreTlvData:
""" """
Helper base class used for packing and unpacking values using struct. Helper base class used for packing and unpacking values using struct.
""" """
@ -94,12 +94,12 @@ class CoreTlvDataObj(CoreTlvData):
""" """
Convenience method for packing custom object data. Convenience method for packing custom object data.
:param obj: custom object to pack :param value: custom object to pack
:return: length of data and the packed data itself :return: length of data and the packed data itself
:rtype: tuple :rtype: tuple
""" """
value = cls.get_value(value) value = cls.get_value(value)
return super(CoreTlvDataObj, cls).pack(value) return super().pack(value)
@classmethod @classmethod
def unpack(cls, data): def unpack(cls, data):
@ -109,7 +109,7 @@ class CoreTlvDataObj(CoreTlvData):
:param data: data to unpack custom object from :param data: data to unpack custom object from
:return: unpacked custom object :return: unpacked custom object
""" """
data = super(CoreTlvDataObj, cls).unpack(data) data = super().unpack(data)
return cls.new_obj(data) return cls.new_obj(data)
@staticmethod @staticmethod
@ -348,7 +348,7 @@ class CoreTlvDataMacAddr(CoreTlvDataObj):
return MacAddress(address=value[2:]) return MacAddress(address=value[2:])
class CoreTlv(object): class CoreTlv:
""" """
Base class for representing CORE TLVs. Base class for representing CORE TLVs.
""" """
@ -670,7 +670,7 @@ class CoreExceptionTlv(CoreTlv):
} }
class CoreMessage(object): class CoreMessage:
""" """
Base class for representing CORE messages. Base class for representing CORE messages.
""" """

View file

@ -83,13 +83,9 @@ class CoreHandler(socketserver.BaseRequestHandler):
self.handler_threads.append(thread) self.handler_threads.append(thread)
thread.start() thread.start()
self.master = False
self.session = None self.session = None
self.session_clients = {} self.session_clients = {}
# core emulator
self.coreemu = server.coreemu self.coreemu = server.coreemu
utils.close_onexec(request.fileno()) utils.close_onexec(request.fileno())
socketserver.BaseRequestHandler.__init__(self, request, client_address, server) socketserver.BaseRequestHandler.__init__(self, request, client_address, server)
@ -127,7 +123,7 @@ class CoreHandler(socketserver.BaseRequestHandler):
for thread in self.handler_threads: for thread in self.handler_threads:
logging.info("waiting for thread: %s", thread.getName()) logging.info("waiting for thread: %s", thread.getName())
thread.join(timeout) thread.join(timeout)
if thread.isAlive(): if thread.is_alive():
logging.warning( logging.warning(
"joining %s failed: still alive after %s sec", "joining %s failed: still alive after %s sec",
thread.getName(), thread.getName(),
@ -434,9 +430,7 @@ class CoreHandler(socketserver.BaseRequestHandler):
tlv_data += coreapi.CoreRegisterTlv.pack( tlv_data += coreapi.CoreRegisterTlv.pack(
self.session.options.config_type, self.session.options.name self.session.options.config_type, self.session.options.name
) )
tlv_data += coreapi.CoreRegisterTlv.pack( tlv_data += coreapi.CoreRegisterTlv.pack(RegisterTlvs.UTILITY.value, "metadata")
self.session.metadata.config_type, self.session.metadata.name
)
return coreapi.CoreRegMessage.pack(MessageFlags.ADD.value, tlv_data) return coreapi.CoreRegMessage.pack(MessageFlags.ADD.value, tlv_data)
@ -591,12 +585,8 @@ class CoreHandler(socketserver.BaseRequestHandler):
port = self.request.getpeername()[1] port = self.request.getpeername()[1]
# TODO: add shutdown handler for session # TODO: add shutdown handler for session
self.session = self.coreemu.create_session(port, master=False) self.session = self.coreemu.create_session(port)
logging.debug("created new session for client: %s", self.session.id) logging.debug("created new session for client: %s", self.session.id)
if self.master:
logging.debug("session set to master")
self.session.master = True
clients = self.session_clients.setdefault(self.session.id, []) clients = self.session_clients.setdefault(self.session.id, [])
clients.append(self) clients.append(self)
@ -698,12 +688,12 @@ class CoreHandler(socketserver.BaseRequestHandler):
node_id = message.get_tlv(NodeTlvs.NUMBER.value) node_id = message.get_tlv(NodeTlvs.NUMBER.value)
node_options = NodeOptions( options = NodeOptions(
name=message.get_tlv(NodeTlvs.NAME.value), name=message.get_tlv(NodeTlvs.NAME.value),
model=message.get_tlv(NodeTlvs.MODEL.value), model=message.get_tlv(NodeTlvs.MODEL.value),
) )
node_options.set_position( options.set_position(
x=message.get_tlv(NodeTlvs.X_POSITION.value), x=message.get_tlv(NodeTlvs.X_POSITION.value),
y=message.get_tlv(NodeTlvs.Y_POSITION.value), y=message.get_tlv(NodeTlvs.Y_POSITION.value),
) )
@ -717,19 +707,19 @@ class CoreHandler(socketserver.BaseRequestHandler):
alt = message.get_tlv(NodeTlvs.ALTITUDE.value) alt = message.get_tlv(NodeTlvs.ALTITUDE.value)
if alt is not None: if alt is not None:
alt = float(alt) alt = float(alt)
node_options.set_location(lat=lat, lon=lon, alt=alt) options.set_location(lat=lat, lon=lon, alt=alt)
node_options.icon = message.get_tlv(NodeTlvs.ICON.value) options.icon = message.get_tlv(NodeTlvs.ICON.value)
node_options.canvas = message.get_tlv(NodeTlvs.CANVAS.value) options.canvas = message.get_tlv(NodeTlvs.CANVAS.value)
node_options.opaque = message.get_tlv(NodeTlvs.OPAQUE.value) options.opaque = message.get_tlv(NodeTlvs.OPAQUE.value)
node_options.emulation_server = message.get_tlv(NodeTlvs.EMULATION_SERVER.value) options.server = message.get_tlv(NodeTlvs.EMULATION_SERVER.value)
services = message.get_tlv(NodeTlvs.SERVICES.value) services = message.get_tlv(NodeTlvs.SERVICES.value)
if services: if services:
node_options.services = services.split("|") options.services = services.split("|")
if message.flags & MessageFlags.ADD.value: if message.flags & MessageFlags.ADD.value:
node = self.session.add_node(node_type, node_id, node_options) node = self.session.add_node(node_type, node_id, options)
if node: if node:
if message.flags & MessageFlags.STRING.value: if message.flags & MessageFlags.STRING.value:
self.node_status_request[node.id] = True self.node_status_request[node.id] = True
@ -748,7 +738,7 @@ class CoreHandler(socketserver.BaseRequestHandler):
replies.append(coreapi.CoreNodeMessage.pack(flags, tlvdata)) replies.append(coreapi.CoreNodeMessage.pack(flags, tlvdata))
# node update # node update
else: else:
self.session.update_node(node_id, node_options) self.session.edit_node(node_id, options)
return replies return replies
@ -942,7 +932,7 @@ class CoreHandler(socketserver.BaseRequestHandler):
file_name = sys.argv[0] file_name = sys.argv[0]
if os.path.splitext(file_name)[1].lower() == ".xml": if os.path.splitext(file_name)[1].lower() == ".xml":
session = self.coreemu.create_session(master=False) session = self.coreemu.create_session()
try: try:
session.open_xml(file_name) session.open_xml(file_name)
except Exception: except Exception:
@ -1012,17 +1002,6 @@ class CoreHandler(socketserver.BaseRequestHandler):
logging.debug("ignoring Register message") logging.debug("ignoring Register message")
else: else:
# register capabilities with the GUI # register capabilities with the GUI
self.master = True
# find the session containing this client and set the session to master
for _id in self.coreemu.sessions:
clients = self.session_clients.get(_id, [])
if self in clients:
session = self.coreemu.sessions[_id]
logging.debug("setting session to master: %s", session.id)
session.master = True
break
replies.append(self.register()) replies.append(self.register())
replies.append(self.session_message()) replies.append(self.session_message())
@ -1065,7 +1044,7 @@ class CoreHandler(socketserver.BaseRequestHandler):
replies = self.handle_config_session(message_type, config_data) replies = self.handle_config_session(message_type, config_data)
elif config_data.object == self.session.location.name: elif config_data.object == self.session.location.name:
self.handle_config_location(message_type, config_data) self.handle_config_location(message_type, config_data)
elif config_data.object == self.session.metadata.name: elif config_data.object == "metadata":
replies = self.handle_config_metadata(message_type, config_data) replies = self.handle_config_metadata(message_type, config_data)
elif config_data.object == "broker": elif config_data.object == "broker":
self.handle_config_broker(message_type, config_data) self.handle_config_broker(message_type, config_data)
@ -1092,10 +1071,14 @@ class CoreHandler(socketserver.BaseRequestHandler):
if message_type == ConfigFlags.RESET: if message_type == ConfigFlags.RESET:
node_id = config_data.node node_id = config_data.node
self.session.location.reset() if node_id is not None:
self.session.services.reset() self.session.mobility.config_reset(node_id)
self.session.mobility.config_reset(node_id) self.session.emane.config_reset(node_id)
self.session.emane.config_reset(node_id) else:
self.session.location.reset()
self.session.services.reset()
self.session.mobility.config_reset()
self.session.emane.config_reset()
else: else:
raise Exception(f"cant handle config all: {message_type}") raise Exception(f"cant handle config all: {message_type}")
@ -1147,7 +1130,7 @@ class CoreHandler(socketserver.BaseRequestHandler):
replies = [] replies = []
if message_type == ConfigFlags.REQUEST: if message_type == ConfigFlags.REQUEST:
node_id = config_data.node node_id = config_data.node
metadata_configs = self.session.metadata.get_configs() metadata_configs = self.session.metadata
if metadata_configs is None: if metadata_configs is None:
metadata_configs = {} metadata_configs = {}
data_values = "|".join( data_values = "|".join(
@ -1157,7 +1140,7 @@ class CoreHandler(socketserver.BaseRequestHandler):
config_response = ConfigData( config_response = ConfigData(
message_type=0, message_type=0,
node=node_id, node=node_id,
object=self.session.metadata.name, object="metadata",
type=ConfigFlags.NONE.value, type=ConfigFlags.NONE.value,
data_types=data_types, data_types=data_types,
data_values=data_values, data_values=data_values,
@ -1167,7 +1150,7 @@ class CoreHandler(socketserver.BaseRequestHandler):
values = ConfigShim.str_to_dict(config_data.data_values) values = ConfigShim.str_to_dict(config_data.data_values)
for key in values: for key in values:
value = values[key] value = values[key]
self.session.metadata.set_config(key, value) self.session.metadata[key] = value
return replies return replies
def handle_config_broker(self, message_type, config_data): def handle_config_broker(self, message_type, config_data):
@ -1437,11 +1420,6 @@ class CoreHandler(socketserver.BaseRequestHandler):
config = ConfigShim.str_to_dict(values_str) config = ConfigShim.str_to_dict(values_str)
self.session.emane.set_configs(config) self.session.emane.set_configs(config)
# extra logic to start slave Emane object after nemid has been configured from the master
if message_type == ConfigFlags.UPDATE and self.session.master is False:
# instantiation was previously delayed by setup returning Emane.NOT_READY
self.session.instantiate()
return replies return replies
def handle_config_emane_models(self, message_type, config_data): def handle_config_emane_models(self, message_type, config_data):
@ -1609,20 +1587,11 @@ class CoreHandler(socketserver.BaseRequestHandler):
for _id in self.session.nodes: for _id in self.session.nodes:
self.send_node_emulation_id(_id) self.send_node_emulation_id(_id)
elif event_type == EventTypes.RUNTIME_STATE: elif event_type == EventTypes.RUNTIME_STATE:
if self.session.master: logging.warning("Unexpected event message: RUNTIME state received")
logging.warning(
"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: elif event_type == EventTypes.DATACOLLECT_STATE:
self.session.data_collect() self.session.data_collect()
elif event_type == EventTypes.SHUTDOWN_STATE: elif event_type == EventTypes.SHUTDOWN_STATE:
if self.session.master: logging.warning("Unexpected event message: SHUTDOWN state received")
logging.warning(
"Unexpected event message: SHUTDOWN state received at session master"
)
elif event_type in { elif event_type in {
EventTypes.START, EventTypes.START,
EventTypes.STOP, EventTypes.STOP,
@ -1820,9 +1789,7 @@ class CoreHandler(socketserver.BaseRequestHandler):
# set session to join # set session to join
self.session = session self.session = session
# add client to session broker and set master if needed # add client to session broker
if self.master:
self.session.master = True
clients = self.session_clients.setdefault(self.session.id, []) clients = self.session_clients.setdefault(self.session.id, [])
clients.append(self) clients.append(self)
@ -1982,18 +1949,17 @@ class CoreHandler(socketserver.BaseRequestHandler):
self.session.broadcast_config(config_data) self.session.broadcast_config(config_data)
# send session metadata # send session metadata
metadata_configs = self.session.metadata.get_configs() metadata_configs = self.session.metadata
if metadata_configs: if metadata_configs:
data_values = "|".join( data_values = "|".join(
[f"{x}={metadata_configs[x]}" for x in metadata_configs] [f"{x}={metadata_configs[x]}" for x in metadata_configs]
) )
data_types = tuple( data_types = tuple(
ConfigDataTypes.STRING.value ConfigDataTypes.STRING.value for _ in self.session.metadata
for _ in self.session.metadata.get_configs()
) )
config_data = ConfigData( config_data = ConfigData(
message_type=0, message_type=0,
object=self.session.metadata.name, object="metadata",
type=ConfigFlags.NONE.value, type=ConfigFlags.NONE.value,
data_types=data_types, data_types=data_types,
data_values=data_values, data_values=data_values,
@ -2018,7 +1984,6 @@ class CoreUdpHandler(CoreHandler):
MessageTypes.EVENT.value: self.handle_event_message, MessageTypes.EVENT.value: self.handle_event_message,
MessageTypes.SESSION.value: self.handle_session_message, MessageTypes.SESSION.value: self.handle_session_message,
} }
self.master = False
self.session = None self.session = None
self.coreemu = server.mainserver.coreemu self.coreemu = server.mainserver.coreemu
socketserver.BaseRequestHandler.__init__(self, request, client_address, server) socketserver.BaseRequestHandler.__init__(self, request, client_address, server)

View file

@ -24,7 +24,7 @@ def convert_node(node_data):
(NodeTlvs.IP6_ADDRESS, node_data.ip6_address), (NodeTlvs.IP6_ADDRESS, node_data.ip6_address),
(NodeTlvs.MODEL, node_data.model), (NodeTlvs.MODEL, node_data.model),
(NodeTlvs.EMULATION_ID, node_data.emulation_id), (NodeTlvs.EMULATION_ID, node_data.emulation_id),
(NodeTlvs.EMULATION_SERVER, node_data.emulation_server), (NodeTlvs.EMULATION_SERVER, node_data.server),
(NodeTlvs.SESSION, node_data.session), (NodeTlvs.SESSION, node_data.session),
(NodeTlvs.X_POSITION, node_data.x_position), (NodeTlvs.X_POSITION, node_data.x_position),
(NodeTlvs.Y_POSITION, node_data.y_position), (NodeTlvs.Y_POSITION, node_data.y_position),

View file

@ -8,7 +8,7 @@ from collections import OrderedDict
from core.emulator.data import ConfigData from core.emulator.data import ConfigData
class ConfigShim(object): class ConfigShim:
""" """
Provides helper methods for converting newer configuration values into TLV compatible formats. Provides helper methods for converting newer configuration values into TLV compatible formats.
""" """
@ -102,7 +102,7 @@ class ConfigShim(object):
) )
class Configuration(object): class Configuration:
""" """
Represents a configuration options. Represents a configuration options.
""" """
@ -131,7 +131,7 @@ class Configuration(object):
return f"{self.__class__.__name__}(id={self.id}, type={self.type}, default={self.default}, options={self.options})" return f"{self.__class__.__name__}(id={self.id}, type={self.type}, default={self.default}, options={self.options})"
class ConfigurableManager(object): class ConfigurableManager:
""" """
Provides convenience methods for storing and retrieving configuration options for nodes. Provides convenience methods for storing and retrieving configuration options for nodes.
""" """
@ -240,7 +240,7 @@ class ConfigurableManager(object):
return self.node_configurations.get(node_id) return self.node_configurations.get(node_id)
class ConfigGroup(object): class ConfigGroup:
""" """
Defines configuration group tabs used for display by ConfigurationOptions. Defines configuration group tabs used for display by ConfigurationOptions.
""" """
@ -258,7 +258,7 @@ class ConfigGroup(object):
self.stop = stop self.stop = stop
class ConfigurableOptions(object): class ConfigurableOptions:
""" """
Provides a base for defining configuration options within CORE. Provides a base for defining configuration options within CORE.
""" """
@ -309,7 +309,7 @@ class ModelManager(ConfigurableManager):
""" """
Creates a ModelManager object. Creates a ModelManager object.
""" """
super(ModelManager, self).__init__() super().__init__()
self.models = {} self.models = {}
self.node_models = {} self.node_models = {}

View file

@ -62,7 +62,7 @@ class EmaneManager(ModelManager):
:param core.session.Session session: session this manager is tied to :param core.session.Session session: session this manager is tied to
:return: nothing :return: nothing
""" """
super(EmaneManager, self).__init__() super().__init__()
self.session = session self.session = session
self._emane_nets = {} self._emane_nets = {}
self._emane_node_lock = threading.Lock() self._emane_node_lock = threading.Lock()
@ -128,7 +128,7 @@ class EmaneManager(ModelManager):
return config return config
def config_reset(self, node_id=None): def config_reset(self, node_id=None):
super(EmaneManager, self).config_reset(node_id) super().config_reset(node_id)
self.set_configs(self.emane_config.default_values()) self.set_configs(self.emane_config.default_values())
def emane_check(self): def emane_check(self):
@ -269,37 +269,34 @@ class EmaneManager(ModelManager):
# control network bridge required for EMANE 0.9.2 # control network bridge required for EMANE 0.9.2
# - needs to exist when eventservice binds to it (initeventservice) # - needs to exist when eventservice binds to it (initeventservice)
if self.session.master: otadev = self.get_config("otamanagerdevice")
otadev = self.get_config("otamanagerdevice") netidx = self.session.get_control_net_index(otadev)
netidx = self.session.get_control_net_index(otadev) logging.debug("emane ota manager device: index(%s) otadev(%s)", netidx, otadev)
logging.debug( if netidx < 0:
"emane ota manager device: index(%s) otadev(%s)", netidx, otadev logging.error(
"EMANE cannot start, check core config. invalid OTA device provided: %s",
otadev,
) )
return EmaneManager.NOT_READY
self.session.add_remove_control_net(
net_index=netidx, remove=False, conf_required=False
)
eventdev = self.get_config("eventservicedevice")
logging.debug("emane event service device: eventdev(%s)", eventdev)
if eventdev != otadev:
netidx = self.session.get_control_net_index(eventdev)
logging.debug("emane event service device index: %s", netidx)
if netidx < 0: if netidx < 0:
logging.error( logging.error(
"EMANE cannot start, check core config. invalid OTA device provided: %s", "EMANE cannot start, check core config. invalid event service device: %s",
otadev, eventdev,
) )
return EmaneManager.NOT_READY return EmaneManager.NOT_READY
self.session.add_remove_control_net( self.session.add_remove_control_net(
net_index=netidx, remove=False, conf_required=False net_index=netidx, remove=False, conf_required=False
) )
eventdev = self.get_config("eventservicedevice")
logging.debug("emane event service device: eventdev(%s)", eventdev)
if eventdev != otadev:
netidx = self.session.get_control_net_index(eventdev)
logging.debug("emane event service device index: %s", netidx)
if netidx < 0:
logging.error(
"EMANE cannot start, check core config. invalid event service device: %s",
eventdev,
)
return EmaneManager.NOT_READY
self.session.add_remove_control_net(
net_index=netidx, remove=False, conf_required=False
)
self.check_node_models() self.check_node_models()
return EmaneManager.SUCCESS return EmaneManager.SUCCESS
@ -376,7 +373,6 @@ class EmaneManager(ModelManager):
with self._emane_node_lock: with self._emane_node_lock:
self._emane_nets.clear() self._emane_nets.clear()
# don't clear self._ifccounts here; NEM counts are needed for buildxml
self.platformport = self.session.options.get_config_int( self.platformport = self.session.options.get_config_int(
"emane_platform_port", 8100 "emane_platform_port", 8100
) )
@ -585,7 +581,7 @@ class EmaneManager(ModelManager):
args = f"{emanecmd} -f {log_file} {platform_xml}" args = f"{emanecmd} -f {log_file} {platform_xml}"
output = node.cmd(args) output = node.cmd(args)
logging.info("node(%s) emane daemon running: %s", node.name, args) logging.info("node(%s) emane daemon running: %s", node.name, args)
logging.info("node(%s) emane daemon output: %s", node.name, output) logging.debug("node(%s) emane daemon output: %s", node.name, output)
if not run_emane_on_host: if not run_emane_on_host:
return return
@ -871,7 +867,7 @@ class EmaneGlobalModel(EmaneModel):
] ]
def __init__(self, session, _id=None): def __init__(self, session, _id=None):
super(EmaneGlobalModel, self).__init__(session, _id) super().__init__(session, _id)
def build_xml_files(self, config, interface=None): def build_xml_files(self, config, interface=None):
raise NotImplementedError raise NotImplementedError

View file

@ -19,4 +19,4 @@ class EmaneIeee80211abgModel(emanemodel.EmaneModel):
cls.mac_defaults["pcrcurveuri"] = os.path.join( cls.mac_defaults["pcrcurveuri"] = os.path.join(
emane_prefix, "share/emane/xml/models/mac/ieee80211abg/ieee80211pcr.xml" emane_prefix, "share/emane/xml/models/mac/ieee80211abg/ieee80211pcr.xml"
) )
super(EmaneIeee80211abgModel, cls).load(emane_prefix) super().load(emane_prefix)

View file

@ -30,7 +30,7 @@ class EmaneNet(CoreNetworkBase):
is_emane = True is_emane = True
def __init__(self, session, _id=None, name=None, start=True, server=None): def __init__(self, session, _id=None, name=None, start=True, server=None):
super(EmaneNet, self).__init__(session, _id, name, start, server) super().__init__(session, _id, name, start, server)
self.conf = "" self.conf = ""
self.up = False self.up = False
self.nemidmap = {} self.nemidmap = {}

View file

@ -19,4 +19,4 @@ class EmaneRfPipeModel(emanemodel.EmaneModel):
cls.mac_defaults["pcrcurveuri"] = os.path.join( cls.mac_defaults["pcrcurveuri"] = os.path.join(
emane_prefix, "share/emane/xml/models/mac/rfpipe/rfpipepcr.xml" emane_prefix, "share/emane/xml/models/mac/rfpipe/rfpipepcr.xml"
) )
super(EmaneRfPipeModel, cls).load(emane_prefix) super().load(emane_prefix)

View file

@ -32,7 +32,7 @@ class EmaneTdmaModel(emanemodel.EmaneModel):
emane_prefix, emane_prefix,
"share/emane/xml/models/mac/tdmaeventscheduler/tdmabasemodelpcr.xml", "share/emane/xml/models/mac/tdmaeventscheduler/tdmabasemodelpcr.xml",
) )
super(EmaneTdmaModel, cls).load(emane_prefix) super().load(emane_prefix)
cls.mac_config.insert( cls.mac_config.insert(
0, 0,
Configuration( Configuration(

View file

@ -29,7 +29,7 @@ signal.signal(signal.SIGUSR1, signal_handler)
signal.signal(signal.SIGUSR2, signal_handler) signal.signal(signal.SIGUSR2, signal_handler)
class CoreEmu(object): class CoreEmu:
""" """
Provides logic for creating and configuring CORE sessions and the nodes within them. Provides logic for creating and configuring CORE sessions and the nodes within them.
""" """
@ -49,7 +49,7 @@ class CoreEmu(object):
self.config = config self.config = config
# session management # session management
self.session_id_gen = IdGen(_id=0) self.session_id_gen = IdGen()
self.sessions = {} self.sessions = {}
# load services # load services
@ -79,18 +79,18 @@ class CoreEmu(object):
:return: nothing :return: nothing
""" """
logging.info("shutting down all sessions") logging.info("shutting down all sessions")
self.session_id_gen.id = 0
sessions = self.sessions.copy() sessions = self.sessions.copy()
self.sessions.clear() self.sessions.clear()
for _id in sessions: for _id in sessions:
session = sessions[_id] session = sessions[_id]
session.shutdown() session.shutdown()
def create_session(self, _id=None, master=True, _cls=Session): def create_session(self, _id=None, _cls=Session):
""" """
Create a new CORE session, set to master if running standalone. Create a new CORE session.
:param int _id: session id for new session :param int _id: session id for new session
:param bool master: sets session to master
:param class _cls: Session class to use :param class _cls: Session class to use
:return: created session :return: created session
:rtype: EmuSession :rtype: EmuSession
@ -103,9 +103,6 @@ class CoreEmu(object):
session = _cls(_id, config=self.config) session = _cls(_id, config=self.config)
logging.info("created session: %s", _id) logging.info("created session: %s", _id)
if master:
session.master = True
self.sessions[_id] = session self.sessions[_id] = session
return session return session

View file

@ -64,7 +64,7 @@ NodeData = collections.namedtuple(
"ip6_address", "ip6_address",
"model", "model",
"emulation_id", "emulation_id",
"emulation_server", "server",
"session", "session",
"x_position", "x_position",
"y_position", "y_position",

View file

@ -21,7 +21,7 @@ LOCK = threading.Lock()
CMD_HIDE = True CMD_HIDE = True
class DistributedServer(object): class DistributedServer:
""" """
Provides distributed server interactions. Provides distributed server interactions.
""" """
@ -101,7 +101,7 @@ class DistributedServer(object):
os.unlink(temp.name) os.unlink(temp.name)
class DistributedController(object): class DistributedController:
""" """
Provides logic for dealing with remote tunnels and distributed servers. Provides logic for dealing with remote tunnels and distributed servers.
""" """

View file

@ -4,7 +4,7 @@ from core.nodes.ipaddress import Ipv4Prefix, Ipv6Prefix, MacAddress
from core.nodes.physical import PhysicalNode from core.nodes.physical import PhysicalNode
class IdGen(object): class IdGen:
def __init__(self, _id=0): def __init__(self, _id=0):
self.id = _id self.id = _id
@ -29,7 +29,7 @@ def create_interface(node, network, interface_data):
ifindex=interface_data.id, ifindex=interface_data.id,
ifname=interface_data.name, ifname=interface_data.name,
) )
return node.netif(interface_data.id, network) return node.netif(interface_data.id)
def link_config(network, interface, link_options, devname=None, interface_two=None): def link_config(network, interface, link_options, devname=None, interface_two=None):
@ -61,7 +61,7 @@ def link_config(network, interface, link_options, devname=None, interface_two=No
network.linkconfig(**config) network.linkconfig(**config)
class NodeOptions(object): class NodeOptions:
""" """
Options for creating and updating nodes within core. Options for creating and updating nodes within core.
""" """
@ -87,7 +87,7 @@ class NodeOptions(object):
self.lon = None self.lon = None
self.alt = None self.alt = None
self.emulation_id = None self.emulation_id = None
self.emulation_server = None self.server = None
self.image = image self.image = image
def set_position(self, x, y): def set_position(self, x, y):
@ -115,7 +115,7 @@ class NodeOptions(object):
self.alt = alt self.alt = alt
class LinkOptions(object): class LinkOptions:
""" """
Options for creating and updating links within core. Options for creating and updating links within core.
""" """
@ -145,7 +145,7 @@ class LinkOptions(object):
self.opaque = None self.opaque = None
class IpPrefixes(object): class IpPrefixes:
""" """
Convenience class to help generate IP4 and IP6 addresses for nodes within CORE. Convenience class to help generate IP4 and IP6 addresses for nodes within CORE.
""" """
@ -236,7 +236,7 @@ class IpPrefixes(object):
) )
class InterfaceData(object): class InterfaceData:
""" """
Convenience class for storing interface data. Convenience class for storing interface data.
""" """

View file

@ -73,18 +73,15 @@ class NodeTypes(Enum):
DEFAULT = 0 DEFAULT = 0
PHYSICAL = 1 PHYSICAL = 1
TBD = 3
SWITCH = 4 SWITCH = 4
HUB = 5 HUB = 5
WIRELESS_LAN = 6 WIRELESS_LAN = 6
RJ45 = 7 RJ45 = 7
TUNNEL = 8 TUNNEL = 8
KTUNNEL = 9
EMANE = 10 EMANE = 10
TAP_BRIDGE = 11 TAP_BRIDGE = 11
PEER_TO_PEER = 12 PEER_TO_PEER = 12
CONTROL_NET = 13 CONTROL_NET = 13
EMANE_NET = 14
DOCKER = 15 DOCKER = 15
LXC = 16 LXC = 16

View file

@ -12,7 +12,6 @@ import subprocess
import tempfile import tempfile
import threading import threading
import time import time
from multiprocessing.pool import ThreadPool
from core import constants, utils from core import constants, utils
from core.emane.emanemanager import EmaneManager from core.emane.emanemanager import EmaneManager
@ -27,7 +26,7 @@ from core.emulator.emudata import (
link_config, link_config,
) )
from core.emulator.enumerations import EventTypes, ExceptionLevels, LinkTypes, NodeTypes from core.emulator.enumerations import EventTypes, ExceptionLevels, LinkTypes, NodeTypes
from core.emulator.sessionconfig import SessionConfig, SessionMetaData from core.emulator.sessionconfig import SessionConfig
from core.errors import CoreError from core.errors import CoreError
from core.location.corelocation import CoreLocation from core.location.corelocation import CoreLocation
from core.location.event import EventLoop from core.location.event import EventLoop
@ -55,15 +54,12 @@ from core.xml.corexml import CoreXmlReader, CoreXmlWriter
NODES = { NODES = {
NodeTypes.DEFAULT: CoreNode, NodeTypes.DEFAULT: CoreNode,
NodeTypes.PHYSICAL: PhysicalNode, NodeTypes.PHYSICAL: PhysicalNode,
NodeTypes.TBD: None,
NodeTypes.SWITCH: SwitchNode, NodeTypes.SWITCH: SwitchNode,
NodeTypes.HUB: HubNode, NodeTypes.HUB: HubNode,
NodeTypes.WIRELESS_LAN: WlanNode, NodeTypes.WIRELESS_LAN: WlanNode,
NodeTypes.RJ45: Rj45Node, NodeTypes.RJ45: Rj45Node,
NodeTypes.TUNNEL: TunnelNode, NodeTypes.TUNNEL: TunnelNode,
NodeTypes.KTUNNEL: None,
NodeTypes.EMANE: EmaneNet, NodeTypes.EMANE: EmaneNet,
NodeTypes.EMANE_NET: None,
NodeTypes.TAP_BRIDGE: GreTapBridge, NodeTypes.TAP_BRIDGE: GreTapBridge,
NodeTypes.PEER_TO_PEER: PtpNet, NodeTypes.PEER_TO_PEER: PtpNet,
NodeTypes.CONTROL_NET: CtrlNet, NodeTypes.CONTROL_NET: CtrlNet,
@ -74,7 +70,7 @@ NODES_TYPE = {NODES[x]: x for x in NODES}
CTRL_NET_ID = 9001 CTRL_NET_ID = 9001
class Session(object): class Session:
""" """
CORE session manager. CORE session manager.
""" """
@ -88,7 +84,6 @@ class Session(object):
:param bool mkdir: flag to determine if a directory should be made :param bool mkdir: flag to determine if a directory should be made
""" """
self.id = _id self.id = _id
self.master = False
# define and create session directory when desired # define and create session directory when desired
self.session_dir = os.path.join(tempfile.gettempdir(), f"pycore.{self.id}") self.session_dir = os.path.join(tempfile.gettempdir(), f"pycore.{self.id}")
@ -134,7 +129,7 @@ class Session(object):
for key in config: for key in config:
value = config[key] value = config[key]
self.options.set_config(key, value) self.options.set_config(key, value)
self.metadata = SessionMetaData() self.metadata = {}
# distributed support and logic # distributed support and logic
self.distributed = DistributedController(self) self.distributed = DistributedController(self)
@ -243,7 +238,6 @@ class Session(object):
) )
return node_one, node_two, net_one, net_two, tunnel return node_one, node_two, net_one, net_two, tunnel
# TODO: this doesn't appear to ever be used, EMANE or basic wireless range
def _link_wireless(self, objects, connect): def _link_wireless(self, objects, connect):
""" """
Objects to deal with when connecting/disconnecting wireless links. Objects to deal with when connecting/disconnecting wireless links.
@ -358,11 +352,7 @@ class Session(object):
net_one.name, net_one.name,
net_two.name, net_two.name,
) )
if isinstance(net_two, Rj45Node): interface = net_one.linknet(net_two)
interface = net_two.linknet(net_one)
else:
interface = net_one.linknet(net_two)
link_config(net_one, interface, link_options) link_config(net_one, interface, link_options)
if not link_options.unidirectional: if not link_options.unidirectional:
@ -597,11 +587,11 @@ class Session(object):
raise CoreError("modify link for unknown nodes") raise CoreError("modify link for unknown nodes")
elif not node_one: elif not node_one:
# node1 = layer 2node, node2 = layer3 node # node1 = layer 2node, node2 = layer3 node
interface = node_two.netif(interface_two_id, net_one) interface = node_two.netif(interface_two_id)
link_config(net_one, interface, link_options) link_config(net_one, interface, link_options)
elif not node_two: elif not node_two:
# node2 = layer 2node, node1 = layer3 node # node2 = layer 2node, node1 = layer3 node
interface = node_one.netif(interface_one_id, net_one) interface = node_one.netif(interface_one_id)
link_config(net_one, interface, link_options) link_config(net_one, interface, link_options)
else: else:
common_networks = node_one.commonnets(node_two) common_networks = node_one.commonnets(node_two)
@ -634,13 +624,13 @@ class Session(object):
if node_two: if node_two:
node_two.lock.release() node_two.lock.release()
def add_node(self, _type=NodeTypes.DEFAULT, _id=None, node_options=None, _cls=None): def add_node(self, _type=NodeTypes.DEFAULT, _id=None, options=None, _cls=None):
""" """
Add a node to the session, based on the provided node data. Add a node to the session, based on the provided node data.
:param core.emulator.enumerations.NodeTypes _type: type of node to create :param core.emulator.enumerations.NodeTypes _type: type of node to create
:param int _id: id for node, defaults to None for generated id :param int _id: id for node, defaults to None for generated id
:param core.emulator.emudata.NodeOptions node_options: data to create node with :param core.emulator.emudata.NodeOptions options: data to create node with
:param class _cls: optional custom class to use for a created node :param class _cls: optional custom class to use for a created node
:return: created node :return: created node
:raises core.CoreError: when an invalid node type is given :raises core.CoreError: when an invalid node type is given
@ -666,18 +656,16 @@ class Session(object):
break break
# generate name if not provided # generate name if not provided
if not node_options: if not options:
node_options = NodeOptions() options = NodeOptions()
name = node_options.name name = options.name
if not name: if not name:
name = f"{node_class.__name__}{_id}" name = f"{node_class.__name__}{_id}"
# verify distributed server # verify distributed server
server = self.distributed.servers.get(node_options.emulation_server) server = self.distributed.servers.get(options.server)
if node_options.emulation_server is not None and server is None: if options.server is not None and server is None:
raise CoreError( raise CoreError(f"invalid distributed server: {options.server}")
f"invalid distributed server: {node_options.emulation_server}"
)
# create node # create node
logging.info( logging.info(
@ -693,7 +681,7 @@ class Session(object):
_id=_id, _id=_id,
name=name, name=name,
start=start, start=start,
image=node_options.image, image=options.image,
server=server, server=server,
) )
else: else:
@ -702,20 +690,20 @@ class Session(object):
) )
# set node attributes # set node attributes
node.icon = node_options.icon node.icon = options.icon
node.canvas = node_options.canvas node.canvas = options.canvas
node.opaque = node_options.opaque node.opaque = options.opaque
# set node position and broadcast it # set node position and broadcast it
self.set_node_position(node, node_options) self.set_node_position(node, options)
# add services to needed nodes # add services to needed nodes
if isinstance(node, (CoreNode, PhysicalNode, DockerNode, LxcNode)): if isinstance(node, (CoreNode, PhysicalNode, DockerNode, LxcNode)):
node.type = node_options.model node.type = options.model
logging.debug("set node type: %s", node.type) logging.debug("set node type: %s", node.type)
self.services.add_services(node, node.type, node_options.services) self.services.add_services(node, node.type, options.services)
# boot nodes if created after runtime, CoreNodes, Physical, and RJ45 are all nodes # boot nodes after runtime, CoreNodes, Physical, and RJ45 are all nodes
is_boot_node = isinstance(node, CoreNodeBase) and not isinstance(node, Rj45Node) is_boot_node = isinstance(node, CoreNodeBase) and not isinstance(node, Rj45Node)
if self.state == EventTypes.RUNTIME_STATE.value and is_boot_node: if self.state == EventTypes.RUNTIME_STATE.value and is_boot_node:
self.write_nodes() self.write_nodes()
@ -724,12 +712,12 @@ class Session(object):
return node return node
def update_node(self, node_id, node_options): def edit_node(self, node_id, options):
""" """
Update node information. Edit node information.
:param int node_id: id of node to update :param int node_id: id of node to update
:param core.emulator.emudata.NodeOptions node_options: data to update node with :param core.emulator.emudata.NodeOptions options: data to update node with
:return: True if node updated, False otherwise :return: True if node updated, False otherwise
:rtype: bool :rtype: bool
:raises core.CoreError: when node to update does not exist :raises core.CoreError: when node to update does not exist
@ -738,26 +726,26 @@ class Session(object):
node = self.get_node(node_id) node = self.get_node(node_id)
# set node position and broadcast it # set node position and broadcast it
self.set_node_position(node, node_options) self.set_node_position(node, options)
# update attributes # update attributes
node.canvas = node_options.canvas node.canvas = options.canvas
node.icon = node_options.icon node.icon = options.icon
def set_node_position(self, node, node_options): def set_node_position(self, node, options):
""" """
Set position for a node, use lat/lon/alt if needed. Set position for a node, use lat/lon/alt if needed.
:param node: node to set position for :param node: node to set position for
:param core.emulator.emudata.NodeOptions node_options: data for node :param core.emulator.emudata.NodeOptions options: data for node
:return: nothing :return: nothing
""" """
# extract location values # extract location values
x = node_options.x x = options.x
y = node_options.y y = options.y
lat = node_options.lat lat = options.lat
lon = node_options.lon lon = options.lon
alt = node_options.alt alt = options.alt
# check if we need to generate position from lat/lon/alt # check if we need to generate position from lat/lon/alt
has_empty_position = all(i is None for i in [x, y]) has_empty_position = all(i is None for i in [x, y])
@ -886,10 +874,15 @@ class Session(object):
:return: nothing :return: nothing
""" """
self.emane.shutdown()
self.delete_nodes() self.delete_nodes()
self.distributed.shutdown() self.distributed.shutdown()
self.del_hooks() self.del_hooks()
self.emane.reset() self.emane.reset()
self.emane.config_reset()
self.location.reset()
self.services.reset()
self.mobility.config_reset()
def start_events(self): def start_events(self):
""" """
@ -908,49 +901,18 @@ class Session(object):
""" """
self.mobility.handleevent(event_data) self.mobility.handleevent(event_data)
def create_wireless_node(self, _id=None, node_options=None): def set_location(self, lat, lon, alt, scale):
""" """
Create a wireless node for use within an wireless/EMANE networks. Set session geospatial location.
:param int _id: int for node, defaults to None and will be generated :param float lat: latitude
:param core.emulator.emudata.NodeOptions node_options: options for emane node, model will always be "mdr" :param float lon: longitude
:return: new emane node :param float alt: altitude
:rtype: core.nodes.network.WlanNode :param float scale: reference scale
:return: nothing
""" """
if not node_options: self.location.setrefgeo(lat, lon, alt)
node_options = NodeOptions() self.location.refscale = scale
node_options.model = "mdr"
return self.add_node(
_type=NodeTypes.DEFAULT, _id=_id, node_options=node_options
)
def create_emane_network(
self,
model,
geo_reference,
geo_scale=None,
node_options=NodeOptions(),
config=None,
):
"""
Convenience method for creating an emane network.
:param model: emane model to use for emane network
:param geo_reference: geo reference point to use for emane node locations
:param geo_scale: geo scale to use for emane node locations, defaults to 1.0
:param core.emulator.emudata.NodeOptions node_options: options for emane node being created
:param dict config: emane model configuration
:return: create emane network
"""
# required to be set for emane to function properly
self.location.setrefgeo(*geo_reference)
if geo_scale:
self.location.refscale = geo_scale
# create and return network
emane_network = self.add_node(_type=NodeTypes.EMANE, node_options=node_options)
self.emane.set_model(emane_network, model, config)
return emane_network
def shutdown(self): def shutdown(self):
""" """
@ -960,13 +922,11 @@ class Session(object):
self.set_state(EventTypes.DATACOLLECT_STATE, send_event=True) self.set_state(EventTypes.DATACOLLECT_STATE, send_event=True)
self.set_state(EventTypes.SHUTDOWN_STATE, send_event=True) self.set_state(EventTypes.SHUTDOWN_STATE, send_event=True)
# shutdown/cleanup feature helpers # clear out current core session
self.emane.shutdown() self.clear()
self.sdt.shutdown()
# remove and shutdown all nodes and tunnels # shutdown sdt
self.delete_nodes() self.sdt.shutdown()
self.distributed.shutdown()
# remove this sessions working directory # remove this sessions working directory
preserve = self.options.get_config("preservedir") == "1" preserve = self.options.get_config("preservedir") == "1"
@ -1389,26 +1349,28 @@ class Session(object):
""" """
# delete node and check for session shutdown if a node was removed # delete node and check for session shutdown if a node was removed
logging.info("deleting node(%s)", _id) logging.info("deleting node(%s)", _id)
result = False node = None
with self._nodes_lock: with self._nodes_lock:
if _id in self.nodes: if _id in self.nodes:
node = self.nodes.pop(_id) node = self.nodes.pop(_id)
node.shutdown()
result = True
if result: if node:
node.shutdown()
self.check_shutdown() self.check_shutdown()
return result return node is not None
def delete_nodes(self): def delete_nodes(self):
""" """
Clear the nodes dictionary, and call shutdown for each node. Clear the nodes dictionary, and call shutdown for each node.
""" """
with self._nodes_lock: with self._nodes_lock:
funcs = []
while self.nodes: while self.nodes:
_, node = self.nodes.popitem() _, node = self.nodes.popitem()
node.shutdown() funcs.append((node.shutdown, [], {}))
utils.threadpool(funcs)
self.node_id_gen.id = 0
def write_nodes(self): def write_nodes(self):
""" """
@ -1547,11 +1509,13 @@ class Session(object):
# stop node services # stop node services
with self._nodes_lock: with self._nodes_lock:
funcs = []
for node_id in self.nodes: for node_id in self.nodes:
node = self.nodes[node_id] node = self.nodes[node_id]
# TODO: determine if checking for CoreNode alone is ok
if isinstance(node, CoreNodeBase): if isinstance(node, CoreNodeBase):
self.services.stop_services(node) args = (node,)
funcs.append((self.services.stop_services, args, {}))
utils.threadpool(funcs)
# shutdown emane # shutdown emane
self.emane.shutdown() self.emane.shutdown()
@ -1559,7 +1523,8 @@ class Session(object):
# update control interface hosts # update control interface hosts
self.update_control_interface_hosts(remove=True) self.update_control_interface_hosts(remove=True)
# remove all four possible control networks. Does nothing if ctrlnet is not installed. # remove all four possible control networks. Does nothing if ctrlnet is not
# installed.
self.add_remove_control_interface(node=None, net_index=0, remove=True) self.add_remove_control_interface(node=None, net_index=0, remove=True)
self.add_remove_control_interface(node=None, net_index=1, remove=True) self.add_remove_control_interface(node=None, net_index=1, remove=True)
self.add_remove_control_interface(node=None, net_index=2, remove=True) self.add_remove_control_interface(node=None, net_index=2, remove=True)
@ -1590,6 +1555,18 @@ class Session(object):
ssid = (self.id >> 8) ^ (self.id & ((1 << 8) - 1)) ssid = (self.id >> 8) ^ (self.id & ((1 << 8) - 1))
return f"{ssid:x}" return f"{ssid:x}"
def boot_node(self, node):
"""
Boot node by adding a control interface when necessary and starting
node services.
:param core.nodes.base.CoreNodeBase node: node to boot
:return: nothing
"""
logging.info("booting node(%s): %s", node.name, [x.name for x in node.services])
self.add_remove_control_interface(node=node, remove=False)
self.services.boot_services(node)
def boot_nodes(self): def boot_nodes(self):
""" """
Invoke the boot() procedure for all nodes and send back node Invoke the boot() procedure for all nodes and send back node
@ -1597,29 +1574,18 @@ class Session(object):
request flag. request flag.
""" """
with self._nodes_lock: with self._nodes_lock:
pool = ThreadPool() funcs = []
results = [] start = time.monotonic()
start = time.time()
for _id in self.nodes: for _id in self.nodes:
node = self.nodes[_id] node = self.nodes[_id]
if isinstance(node, CoreNodeBase) and not isinstance(node, Rj45Node): if isinstance(node, CoreNodeBase) and not isinstance(node, Rj45Node):
# add a control interface if configured args = (node,)
logging.info( funcs.append((self.boot_node, args, {}))
"booting node(%s): %s", results, exceptions = utils.threadpool(funcs)
node.name, total = time.monotonic() - start
[x.name for x in node.services], logging.debug("boot run time: %s", total)
) if exceptions:
self.add_remove_control_interface(node=node, remove=False) raise CoreError(exceptions)
result = pool.apply_async(self.services.boot_services, (node,))
results.append(result)
pool.close()
pool.join()
for result in results:
result.get()
logging.debug("boot run time: %s", time.time() - start)
self.update_control_interface_hosts() self.update_control_interface_hosts()
def get_control_net_prefixes(self): def get_control_net_prefixes(self):
@ -1732,28 +1698,19 @@ class Session(object):
prefixes = prefix_spec.split() prefixes = prefix_spec.split()
if len(prefixes) > 1: if len(prefixes) > 1:
# a list of per-host prefixes is provided # a list of per-host prefixes is provided
assign_address = True try:
if self.master: # split first (master) entry into server and prefix
try: prefix = prefixes[0].split(":", 1)[1]
# split first (master) entry into server and prefix except IndexError:
prefix = prefixes[0].split(":", 1)[1] # no server name. possibly only one server
except IndexError: prefix = prefixes[0]
# no server name. possibly only one server
prefix = prefixes[0]
# len(prefixes) == 1
else: else:
# TODO: can we get the server name from the servers.conf or from the node
# assignments?o
# with one prefix, only master gets a ctrlnet address
assign_address = self.master
prefix = prefixes[0] prefix = prefixes[0]
logging.info( logging.info(
"controlnet(%s) prefix(%s) assign(%s) updown(%s) serverintf(%s)", "controlnet(%s) prefix(%s) updown(%s) serverintf(%s)",
_id, _id,
prefix, prefix,
assign_address,
updown_script, updown_script,
server_interface, server_interface,
) )
@ -1761,7 +1718,7 @@ class Session(object):
cls=CtrlNet, cls=CtrlNet,
_id=_id, _id=_id,
prefix=prefix, prefix=prefix,
assign_address=assign_address, assign_address=True,
updown_script=updown_script, updown_script=updown_script,
serverintf=server_interface, serverintf=server_interface,
) )
@ -1778,7 +1735,7 @@ class Session(object):
If conf_reqd is False, the control network may be built even If conf_reqd is False, the control network may be built even
when the user has not configured one (e.g. for EMANE.) when the user has not configured one (e.g. for EMANE.)
:param core.nodes.base.CoreNode node: node to add or remove control interface :param core.nodes.base.CoreNodeBase node: node to add or remove control interface
:param int net_index: network index :param int net_index: network index
:param bool remove: flag to check if it should be removed :param bool remove: flag to check if it should be removed
:param bool conf_required: flag to check if conf is required :param bool conf_required: flag to check if conf is required

View file

@ -61,7 +61,7 @@ class SessionConfig(ConfigurableManager, ConfigurableOptions):
config_type = RegisterTlvs.UTILITY.value config_type = RegisterTlvs.UTILITY.value
def __init__(self): def __init__(self):
super(SessionConfig, self).__init__() super().__init__()
self.set_configs(self.default_values()) self.set_configs(self.default_values())
def get_config( def get_config(
@ -71,9 +71,7 @@ class SessionConfig(ConfigurableManager, ConfigurableOptions):
config_type=ConfigurableManager._default_type, config_type=ConfigurableManager._default_type,
default=None, default=None,
): ):
value = super(SessionConfig, self).get_config( value = super().get_config(_id, node_id, config_type, default)
_id, node_id, config_type, default
)
if value == "": if value == "":
value = default value = default
return value return value
@ -89,14 +87,3 @@ class SessionConfig(ConfigurableManager, ConfigurableOptions):
if value is not None: if value is not None:
value = int(value) value = int(value)
return value return value
class SessionMetaData(ConfigurableManager):
"""
Metadata is simply stored in a configs[] dict. Key=value pairs are
passed in from configure messages destined to the "metadata" object.
The data is not otherwise interpreted or processed.
"""
name = "metadata"
config_type = RegisterTlvs.UTILITY.value

View file

@ -11,7 +11,7 @@ from core.emulator.enumerations import RegisterTlvs
from core.location import utm from core.location import utm
class CoreLocation(object): class CoreLocation:
""" """
Member of session class for handling global location data. This keeps Member of session class for handling global location data. This keeps
track of a latitude/longitude/altitude reference point and scale in track of a latitude/longitude/altitude reference point and scale in

View file

@ -23,7 +23,7 @@ class Timer(threading.Thread):
:param args: function arguments :param args: function arguments
:param kwargs: function keyword arguments :param kwargs: function keyword arguments
""" """
super(Timer, self).__init__() super().__init__()
self.interval = interval self.interval = interval
self.function = function self.function = function
@ -70,7 +70,7 @@ class Timer(threading.Thread):
@total_ordering @total_ordering
class Event(object): class Event:
""" """
Provides event objects that can be used within the EventLoop class. Provides event objects that can be used within the EventLoop class.
""" """
@ -118,7 +118,7 @@ class Event(object):
self.canceled = True self.canceled = True
class EventLoop(object): class EventLoop:
""" """
Provides an event loop for running events. Provides an event loop for running events.
""" """

View file

@ -38,7 +38,7 @@ class MobilityManager(ModelManager):
:param core.emulator.session.Session session: session this manager is tied to :param core.emulator.session.Session session: session this manager is tied to
""" """
super(MobilityManager, self).__init__() super().__init__()
self.session = session self.session = session
self.models[BasicRangeModel.name] = BasicRangeModel self.models[BasicRangeModel.name] = BasicRangeModel
self.models[Ns2ScriptedMobility.name] = Ns2ScriptedMobility self.models[Ns2ScriptedMobility.name] = Ns2ScriptedMobility
@ -302,7 +302,7 @@ class BasicRangeModel(WirelessModel):
:param core.session.Session session: related core session :param core.session.Session session: related core session
:param int _id: object id :param int _id: object id
""" """
super(BasicRangeModel, self).__init__(session=session, _id=_id) super().__init__(session, _id)
self.session = session self.session = session
self.wlan = session.get_node(_id) self.wlan = session.get_node(_id)
self._netifs = {} self._netifs = {}
@ -535,7 +535,7 @@ class BasicRangeModel(WirelessModel):
@total_ordering @total_ordering
class WayPoint(object): class WayPoint:
""" """
Maintains information regarding waypoints. Maintains information regarding waypoints.
""" """
@ -587,8 +587,7 @@ class WayPointMobility(WirelessModel):
:param int _id: object id :param int _id: object id
:return: :return:
""" """
super(WayPointMobility, self).__init__(session=session, _id=_id) super().__init__(session=session, _id=_id)
self.state = self.STATE_STOPPED self.state = self.STATE_STOPPED
self.queue = [] self.queue = []
self.queue_copy = [] self.queue_copy = []
@ -945,7 +944,7 @@ class Ns2ScriptedMobility(WayPointMobility):
:param core.emulator.session.Session session: CORE session instance :param core.emulator.session.Session session: CORE session instance
:param int _id: object id :param int _id: object id
""" """
super(Ns2ScriptedMobility, self).__init__(session=session, _id=_id) super().__init__(session, _id)
self._netifs = {} self._netifs = {}
self._netifslock = threading.Lock() self._netifslock = threading.Lock()
@ -1137,7 +1136,7 @@ class Ns2ScriptedMobility(WayPointMobility):
""" """
logging.info("starting script") logging.info("starting script")
laststate = self.state laststate = self.state
super(Ns2ScriptedMobility, self).start() super().start()
if laststate == self.STATE_PAUSED: if laststate == self.STATE_PAUSED:
self.statescript("unpause") self.statescript("unpause")
@ -1147,7 +1146,7 @@ class Ns2ScriptedMobility(WayPointMobility):
:return: nothing :return: nothing
""" """
super(Ns2ScriptedMobility, self).run() super().run()
self.statescript("run") self.statescript("run")
def pause(self): def pause(self):
@ -1156,7 +1155,7 @@ class Ns2ScriptedMobility(WayPointMobility):
:return: nothing :return: nothing
""" """
super(Ns2ScriptedMobility, self).pause() super().pause()
self.statescript("pause") self.statescript("pause")
def stop(self, move_initial=True): def stop(self, move_initial=True):
@ -1166,7 +1165,7 @@ class Ns2ScriptedMobility(WayPointMobility):
:param bool move_initial: flag to check if we should move node to initial position :param bool move_initial: flag to check if we should move node to initial position
:return: nothing :return: nothing
""" """
super(Ns2ScriptedMobility, self).stop(move_initial=move_initial) super().stop(move_initial=move_initial)
self.statescript("stop") self.statescript("stop")
def statescript(self, typestr): def statescript(self, typestr):

View file

@ -21,7 +21,7 @@ from core.nodes.netclient import get_net_client
_DEFAULT_MTU = 1500 _DEFAULT_MTU = 1500
class NodeBase(object): class NodeBase:
""" """
Base class for CORE nodes (nodes and networks) Base class for CORE nodes (nodes and networks)
""" """
@ -139,7 +139,7 @@ class NodeBase(object):
if sort: if sort:
return [self._netif[x] for x in sorted(self._netif)] return [self._netif[x] for x in sorted(self._netif)]
else: else:
return self._netif.values() return list(self._netif.values())
def numnetif(self): def numnetif(self):
""" """
@ -158,11 +158,9 @@ class NodeBase(object):
:return: interface index if found, -1 otherwise :return: interface index if found, -1 otherwise
:rtype: int :rtype: int
""" """
for ifindex in self._netif: for ifindex in self._netif:
if self._netif[ifindex] is netif: if self._netif[ifindex] is netif:
return ifindex return ifindex
return -1 return -1
def newifindex(self): def newifindex(self):
@ -194,9 +192,9 @@ class NodeBase(object):
x, y, _ = self.getposition() x, y, _ = self.getposition()
model = self.type model = self.type
emulation_server = None server = None
if self.server is not None: if self.server is not None:
emulation_server = self.server.name server = self.server.name
services = self.services services = self.services
if services is not None: if services is not None:
@ -217,7 +215,7 @@ class NodeBase(object):
longitude=lon, longitude=lon,
altitude=alt, altitude=alt,
model=model, model=model,
emulation_server=emulation_server, server=server,
services=services, services=services,
) )
@ -252,7 +250,7 @@ class CoreNodeBase(NodeBase):
:param core.emulator.distributed.DistributedServer server: remote server node :param core.emulator.distributed.DistributedServer server: remote server node
will run on, default is None for localhost will run on, default is None for localhost
""" """
super(CoreNodeBase, self).__init__(session, _id, name, start, server) super().__init__(session, _id, name, start, server)
self.services = [] self.services = []
self.nodedir = None self.nodedir = None
self.tmpnodedir = False self.tmpnodedir = False
@ -294,7 +292,6 @@ class CoreNodeBase(NodeBase):
if ifindex in self._netif: if ifindex in self._netif:
raise ValueError(f"ifindex {ifindex} already exists") raise ValueError(f"ifindex {ifindex} already exists")
self._netif[ifindex] = netif self._netif[ifindex] = netif
# TODO: this should have probably been set ahead, seems bad to me, check for failure and fix
netif.netindex = ifindex netif.netindex = ifindex
def delnetif(self, ifindex): def delnetif(self, ifindex):
@ -310,13 +307,11 @@ class CoreNodeBase(NodeBase):
netif.shutdown() netif.shutdown()
del netif del netif
# TODO: net parameter is not used, remove def netif(self, ifindex):
def netif(self, ifindex, net=None):
""" """
Retrieve network interface. Retrieve network interface.
:param int ifindex: index of interface to retrieve :param int ifindex: index of interface to retrieve
:param core.nodes.interface.CoreInterface net: network node
:return: network interface, or None if not found :return: network interface, or None if not found
:rtype: core.nodes.interface.CoreInterface :rtype: core.nodes.interface.CoreInterface
""" """
@ -357,7 +352,7 @@ class CoreNodeBase(NodeBase):
:param z: z position :param z: z position
:return: nothing :return: nothing
""" """
changed = super(CoreNodeBase, self).setposition(x, y, z) changed = super().setposition(x, y, z)
if changed: if changed:
for netif in self.netifs(sort=True): for netif in self.netifs(sort=True):
netif.setposition(x, y, z) netif.setposition(x, y, z)
@ -435,7 +430,7 @@ class CoreNode(CoreNodeBase):
:param core.emulator.distributed.DistributedServer server: remote server node :param core.emulator.distributed.DistributedServer server: remote server node
will run on, default is None for localhost will run on, default is None for localhost
""" """
super(CoreNode, self).__init__(session, _id, name, start, server) super().__init__(session, _id, name, start, server)
self.nodedir = nodedir self.nodedir = nodedir
self.ctrlchnlname = os.path.abspath( self.ctrlchnlname = os.path.abspath(
os.path.join(self.session.session_dir, self.name) os.path.join(self.session.session_dir, self.name)
@ -632,15 +627,14 @@ class CoreNode(CoreNodeBase):
:rtype: int :rtype: int
""" """
with self.lock: with self.lock:
return super(CoreNode, self).newifindex() return super().newifindex()
def newveth(self, ifindex=None, ifname=None, net=None): def newveth(self, ifindex=None, ifname=None):
""" """
Create a new interface. Create a new interface.
:param int ifindex: index for the new interface :param int ifindex: index for the new interface
:param str ifname: name for the new interface :param str ifname: name for the new interface
:param core.nodes.base.CoreNetworkBase net: network to associate interface with
:return: nothing :return: nothing
""" """
with self.lock: with self.lock:
@ -692,13 +686,12 @@ class CoreNode(CoreNodeBase):
return ifindex return ifindex
def newtuntap(self, ifindex=None, ifname=None, net=None): def newtuntap(self, ifindex=None, ifname=None):
""" """
Create a new tunnel tap. Create a new tunnel tap.
:param int ifindex: interface index :param int ifindex: interface index
:param str ifname: interface name :param str ifname: interface name
:param net: network to associate with
:return: interface index :return: interface index
:rtype: int :rtype: int
""" """
@ -803,7 +796,7 @@ class CoreNode(CoreNodeBase):
with self.lock: with self.lock:
# TODO: emane specific code # TODO: emane specific code
if net.is_emane is True: if net.is_emane is True:
ifindex = self.newtuntap(ifindex=ifindex, ifname=ifname, net=net) ifindex = self.newtuntap(ifindex, ifname)
# TUN/TAP is not ready for addressing yet; the device may # TUN/TAP is not ready for addressing yet; the device may
# take some time to appear, and installing it into a # take some time to appear, and installing it into a
# namespace after it has been bound removes addressing; # namespace after it has been bound removes addressing;
@ -815,7 +808,7 @@ class CoreNode(CoreNodeBase):
netif.addaddr(address) netif.addaddr(address)
return ifindex return ifindex
else: else:
ifindex = self.newveth(ifindex=ifindex, ifname=ifname, net=net) ifindex = self.newveth(ifindex, ifname)
if net is not None: if net is not None:
self.attachnet(ifindex, net) self.attachnet(ifindex, net)
@ -930,7 +923,7 @@ class CoreNetworkBase(NodeBase):
:param core.emulator.distributed.DistributedServer server: remote server node :param core.emulator.distributed.DistributedServer server: remote server node
will run on, default is None for localhost will run on, default is None for localhost
""" """
super(CoreNetworkBase, self).__init__(session, _id, name, start, server) super().__init__(session, _id, name, start, server)
self._linked = {} self._linked = {}
self._linked_lock = threading.Lock() self._linked_lock = threading.Lock()
@ -1072,7 +1065,7 @@ class CoreNetworkBase(NodeBase):
return all_links return all_links
class Position(object): class Position:
""" """
Helper class for Cartesian coordinate position Helper class for Cartesian coordinate position
""" """

View file

@ -8,7 +8,7 @@ from core import utils
from core.constants import VCMD_BIN from core.constants import VCMD_BIN
class VnodeClient(object): class VnodeClient:
""" """
Provides client functionality for interacting with a virtual node. Provides client functionality for interacting with a virtual node.
""" """

View file

@ -10,7 +10,7 @@ from core.nodes.base import CoreNode
from core.nodes.netclient import get_net_client from core.nodes.netclient import get_net_client
class DockerClient(object): class DockerClient:
def __init__(self, name, image, run): def __init__(self, name, image, run):
self.name = name self.name = name
self.image = image self.image = image
@ -96,9 +96,7 @@ class DockerNode(CoreNode):
if image is None: if image is None:
image = "ubuntu" image = "ubuntu"
self.image = image self.image = image
super(DockerNode, self).__init__( super().__init__(session, _id, name, nodedir, bootsh, start, server)
session, _id, name, nodedir, bootsh, start, server
)
def create_node_net_client(self, use_ovs): def create_node_net_client(self, use_ovs):
""" """

View file

@ -10,7 +10,7 @@ from core.errors import CoreCommandError
from core.nodes.netclient import get_net_client from core.nodes.netclient import get_net_client
class CoreInterface(object): class CoreInterface:
""" """
Base class for network interfaces. Base class for network interfaces.
""" """
@ -40,8 +40,10 @@ class CoreInterface(object):
self.poshook = lambda a, b, c, d: None self.poshook = lambda a, b, c, d: None
# used with EMANE # used with EMANE
self.transport_type = None self.transport_type = None
# interface index on the network # node interface index
self.netindex = None self.netindex = None
# net interface index
self.netifi = None
# index used to find flow data # index used to find flow data
self.flow_id = None self.flow_id = None
self.server = server self.server = server
@ -230,7 +232,7 @@ class Veth(CoreInterface):
:raises CoreCommandError: when there is a command exception :raises CoreCommandError: when there is a command exception
""" """
# note that net arg is ignored # note that net arg is ignored
CoreInterface.__init__(self, session, node, name, mtu, server) super().__init__(session, node, name, mtu, server)
self.localname = localname self.localname = localname
self.up = False self.up = False
if start: if start:
@ -291,7 +293,7 @@ class TunTap(CoreInterface):
will run on, default is None for localhost will run on, default is None for localhost
:param bool start: start flag :param bool start: start flag
""" """
CoreInterface.__init__(self, session, node, name, mtu, server) super().__init__(session, node, name, mtu, server)
self.localname = localname self.localname = localname
self.up = False self.up = False
self.transport_type = "virtual" self.transport_type = "virtual"
@ -474,7 +476,7 @@ class GreTap(CoreInterface):
will run on, default is None for localhost will run on, default is None for localhost
:raises CoreCommandError: when there is a command exception :raises CoreCommandError: when there is a command exception
""" """
CoreInterface.__init__(self, session, node, name, mtu, server) super().__init__(session, node, name, mtu, server)
if _id is None: if _id is None:
# from PyCoreObj # from PyCoreObj
_id = ((id(self) >> 16) ^ (id(self) & 0xFFFF)) & 0xFFFF _id = ((id(self) >> 16) ^ (id(self) & 0xFFFF)) & 0xFFFF

View file

@ -9,7 +9,7 @@ import struct
from socket import AF_INET, AF_INET6 from socket import AF_INET, AF_INET6
class MacAddress(object): class MacAddress:
""" """
Provides mac address utilities for use within core. Provides mac address utilities for use within core.
""" """
@ -77,7 +77,7 @@ class MacAddress(object):
return cls(tmpbytes[2:]) return cls(tmpbytes[2:])
class IpAddress(object): class IpAddress:
""" """
Provides ip utilities and functionality for use within core. Provides ip utilities and functionality for use within core.
""" """
@ -202,7 +202,7 @@ class IpAddress(object):
return struct.unpack("!I", value)[0] return struct.unpack("!I", value)[0]
class IpPrefix(object): class IpPrefix:
""" """
Provides ip address generation and prefix utilities. Provides ip address generation and prefix utilities.
""" """
@ -401,7 +401,7 @@ class Ipv4Prefix(IpPrefix):
:param str prefixstr: ip prefix :param str prefixstr: ip prefix
""" """
IpPrefix.__init__(self, AF_INET, prefixstr) super().__init__(AF_INET, prefixstr)
class Ipv6Prefix(IpPrefix): class Ipv6Prefix(IpPrefix):
@ -415,7 +415,7 @@ class Ipv6Prefix(IpPrefix):
:param str prefixstr: ip prefix :param str prefixstr: ip prefix
""" """
IpPrefix.__init__(self, AF_INET6, prefixstr) super().__init__(AF_INET6, prefixstr)
def is_ip_address(af, addrstr): def is_ip_address(af, addrstr):

View file

@ -10,7 +10,7 @@ from core.errors import CoreCommandError
from core.nodes.base import CoreNode from core.nodes.base import CoreNode
class LxdClient(object): class LxdClient:
def __init__(self, name, image, run): def __init__(self, name, image, run):
self.name = name self.name = name
self.image = image self.image = image
@ -89,9 +89,7 @@ class LxcNode(CoreNode):
if image is None: if image is None:
image = "ubuntu" image = "ubuntu"
self.image = image self.image = image
super(LxcNode, self).__init__( super().__init__(session, _id, name, nodedir, bootsh, start, server)
session, _id, name, nodedir, bootsh, start, server
)
def alive(self): def alive(self):
""" """
@ -217,6 +215,6 @@ class LxcNode(CoreNode):
self.cmd(f"chmod {mode:o} {filename}") self.cmd(f"chmod {mode:o} {filename}")
def addnetif(self, netif, ifindex): def addnetif(self, netif, ifindex):
super(LxcNode, self).addnetif(netif, ifindex) super().addnetif(netif, ifindex)
# adding small delay to allow time for adding addresses to work correctly # adding small delay to allow time for adding addresses to work correctly
time.sleep(0.5) time.sleep(0.5)

View file

@ -19,7 +19,7 @@ def get_net_client(use_ovs, run):
return LinuxNetClient(run) return LinuxNetClient(run)
class LinuxNetClient(object): class LinuxNetClient:
""" """
Client for creating Linux bridges and ip interfaces for nodes. Client for creating Linux bridges and ip interfaces for nodes.
""" """

View file

@ -21,7 +21,7 @@ from core.nodes.netclient import get_net_client
ebtables_lock = threading.Lock() ebtables_lock = threading.Lock()
class EbtablesQueue(object): class EbtablesQueue:
""" """
Helper class for queuing up ebtables commands into rate-limited Helper class for queuing up ebtables commands into rate-limited
atomic commits. This improves performance and reliability when there are atomic commits. This improves performance and reliability when there are
@ -257,7 +257,7 @@ class CoreNetwork(CoreNetworkBase):
will run on, default is None for localhost will run on, default is None for localhost
:param policy: network policy :param policy: network policy
""" """
CoreNetworkBase.__init__(self, session, _id, name, start, server) super().__init__(session, _id, name, start, server)
if name is None: if name is None:
name = str(self.id) name = str(self.id)
if policy is not None: if policy is not None:
@ -337,8 +337,6 @@ class CoreNetwork(CoreNetworkBase):
del self.session del self.session
self.up = False self.up = False
# TODO: this depends on a subtype with localname defined, seems like the
# wrong place for this to live
def attach(self, netif): def attach(self, netif):
""" """
Attach a network interface. Attach a network interface.
@ -348,8 +346,7 @@ class CoreNetwork(CoreNetworkBase):
""" """
if self.up: if self.up:
netif.net_client.create_interface(self.brname, netif.localname) netif.net_client.create_interface(self.brname, netif.localname)
super().attach(netif)
CoreNetworkBase.attach(self, netif)
def detach(self, netif): def detach(self, netif):
""" """
@ -360,8 +357,7 @@ class CoreNetwork(CoreNetworkBase):
""" """
if self.up: if self.up:
netif.net_client.delete_interface(self.brname, netif.localname) netif.net_client.delete_interface(self.brname, netif.localname)
super().detach(netif)
CoreNetworkBase.detach(self, netif)
def linked(self, netif1, netif2): def linked(self, netif1, netif2):
""" """
@ -654,7 +650,7 @@ class GreTapBridge(CoreNetwork):
:return: nothing :return: nothing
""" """
CoreNetwork.startup(self) super().startup()
if self.gretap: if self.gretap:
self.attach(self.gretap) self.attach(self.gretap)
@ -668,7 +664,7 @@ class GreTapBridge(CoreNetwork):
self.detach(self.gretap) self.detach(self.gretap)
self.gretap.shutdown() self.gretap.shutdown()
self.gretap = None self.gretap = None
CoreNetwork.shutdown(self) super().shutdown()
def addrconfig(self, addrlist): def addrconfig(self, addrlist):
""" """
@ -755,7 +751,7 @@ class CtrlNet(CoreNetwork):
self.assign_address = assign_address self.assign_address = assign_address
self.updown_script = updown_script self.updown_script = updown_script
self.serverintf = serverintf self.serverintf = serverintf
CoreNetwork.__init__(self, session, _id, name, start, server) super().__init__(session, _id, name, start, server)
def add_addresses(self, address): def add_addresses(self, address):
""" """
@ -786,8 +782,7 @@ class CtrlNet(CoreNetwork):
if self.net_client.existing_bridges(self.id): if self.net_client.existing_bridges(self.id):
raise CoreError(f"old bridges exist for node: {self.id}") raise CoreError(f"old bridges exist for node: {self.id}")
CoreNetwork.startup(self) super().startup()
logging.info("added control network bridge: %s %s", self.brname, self.prefix) logging.info("added control network bridge: %s %s", self.brname, self.prefix)
if self.hostid and self.assign_address: if self.hostid and self.assign_address:
@ -835,7 +830,7 @@ class CtrlNet(CoreNetwork):
except CoreCommandError: except CoreCommandError:
logging.exception("error issuing shutdown script shutdown") logging.exception("error issuing shutdown script shutdown")
CoreNetwork.shutdown(self) super().shutdown()
def all_link_data(self, flags): def all_link_data(self, flags):
""" """
@ -866,8 +861,7 @@ class PtpNet(CoreNetwork):
raise ValueError( raise ValueError(
"Point-to-point links support at most 2 network interfaces" "Point-to-point links support at most 2 network interfaces"
) )
super().attach(netif)
CoreNetwork.attach(self, netif)
def data(self, message_type, lat=None, lon=None, alt=None): def data(self, message_type, lat=None, lon=None, alt=None):
""" """
@ -1007,23 +1001,14 @@ class HubNode(CoreNetwork):
policy = "ACCEPT" policy = "ACCEPT"
type = "hub" type = "hub"
def __init__(self, session, _id=None, name=None, start=True, server=None): def startup(self):
""" """
Creates a HubNode instance. Startup for a hub node, that disables mac learning after normal startup.
:param core.session.Session session: core session instance :return: nothing
:param int _id: node id
:param str name: node namee
:param bool start: start flag
:param core.emulator.distributed.DistributedServer server: remote server node
will run on, default is None for localhost
:raises CoreCommandError: when there is a command exception
""" """
CoreNetwork.__init__(self, session, _id, name, start, server) super().startup()
self.net_client.disable_mac_learning(self.brname)
# TODO: move to startup method
if start:
self.net_client.disable_mac_learning(self.brname)
class WlanNode(CoreNetwork): class WlanNode(CoreNetwork):
@ -1050,24 +1035,28 @@ class WlanNode(CoreNetwork):
will run on, default is None for localhost will run on, default is None for localhost
:param policy: wlan policy :param policy: wlan policy
""" """
CoreNetwork.__init__(self, session, _id, name, start, server, policy) super().__init__(session, _id, name, start, server, policy)
# wireless model such as basic range # wireless and mobility models (BasicRangeModel, Ns2WaypointMobility)
self.model = None self.model = None
# mobility model such as scripted
self.mobility = None self.mobility = None
# TODO: move to startup method def startup(self):
if start: """
self.net_client.disable_mac_learning(self.brname) Startup for a wlan node, that disables mac learning after normal startup.
:return: nothing
"""
super().startup()
self.net_client.disable_mac_learning(self.brname)
def attach(self, netif): def attach(self, netif):
""" """
Attach a network interface. Attach a network interface.
:param core.nodes.interface.CoreInterface netif: network interface :param core.nodes.interface.Veth netif: network interface
:return: nothing :return: nothing
""" """
CoreNetwork.attach(self, netif) super().attach(netif)
if self.model: if self.model:
netif.poshook = self.model.position_callback netif.poshook = self.model.position_callback
if netif.node is None: if netif.node is None:
@ -1099,12 +1088,12 @@ class WlanNode(CoreNetwork):
def update_mobility(self, config): def update_mobility(self, config):
if not self.mobility: if not self.mobility:
raise ValueError("no mobility set to update for node(%s)", self.id) raise ValueError(f"no mobility set to update for node({self.id})")
self.mobility.update_config(config) self.mobility.update_config(config)
def updatemodel(self, config): def updatemodel(self, config):
if not self.model: if not self.model:
raise ValueError("no model set to update for node(%s)", self.id) raise ValueError(f"no model set to update for node({self.id})")
logging.debug( logging.debug(
"node(%s) updating model(%s): %s", self.id, self.model.name, config "node(%s) updating model(%s): %s", self.id, self.model.name, config
) )
@ -1122,11 +1111,9 @@ class WlanNode(CoreNetwork):
:return: list of link data :return: list of link data
:rtype: list[core.emulator.data.LinkData] :rtype: list[core.emulator.data.LinkData]
""" """
all_links = CoreNetwork.all_link_data(self, flags) all_links = super().all_link_data(flags)
if self.model: if self.model:
all_links.extend(self.model.all_link_data(flags)) all_links.extend(self.model.all_link_data(flags))
return all_links return all_links

View file

@ -19,7 +19,7 @@ class PhysicalNode(CoreNodeBase):
def __init__( def __init__(
self, session, _id=None, name=None, nodedir=None, start=True, server=None self, session, _id=None, name=None, nodedir=None, start=True, server=None
): ):
CoreNodeBase.__init__(self, session, _id, name, start, server) super().__init__(session, _id, name, start, server)
if not self.server: if not self.server:
raise CoreError("physical nodes must be assigned to a remote server") raise CoreError("physical nodes must be assigned to a remote server")
self.nodedir = nodedir self.nodedir = nodedir

View file

@ -24,7 +24,7 @@ from core.nodes.network import WlanNode
# TODO: A named tuple may be more appropriate, than abusing a class dict like this # TODO: A named tuple may be more appropriate, than abusing a class dict like this
class Bunch(object): class Bunch:
""" """
Helper class for recording a collection of attributes. Helper class for recording a collection of attributes.
""" """
@ -38,7 +38,7 @@ class Bunch(object):
self.__dict__.update(kwargs) self.__dict__.update(kwargs)
class Sdt(object): class Sdt:
""" """
Helper class for exporting session objects to NRL"s SDT3D. Helper class for exporting session objects to NRL"s SDT3D.
The connect() method initializes the display, and can be invoked The connect() method initializes the display, and can be invoked

View file

@ -10,7 +10,6 @@ services.
import enum import enum
import logging import logging
import time import time
from multiprocessing.pool import ThreadPool
from core import utils from core import utils
from core.constants import which from core.constants import which
@ -29,7 +28,7 @@ class ServiceMode(enum.Enum):
TIMER = 2 TIMER = 2
class ServiceDependencies(object): class ServiceDependencies:
""" """
Can generate boot paths for services, based on their dependencies. Will validate Can generate boot paths for services, based on their dependencies. Will validate
that all services will be booted and that all dependencies exist within the services provided. that all services will be booted and that all dependencies exist within the services provided.
@ -127,7 +126,7 @@ class ServiceDependencies(object):
return self.path return self.path
class ServiceShim(object): class ServiceShim:
keys = [ keys = [
"dirs", "dirs",
"files", "files",
@ -235,7 +234,7 @@ class ServiceShim(object):
return servicesstring[1].split(",") return servicesstring[1].split(",")
class ServiceManager(object): class ServiceManager:
""" """
Manages services available for CORE nodes to use. Manages services available for CORE nodes to use.
""" """
@ -306,7 +305,7 @@ class ServiceManager(object):
return service_errors return service_errors
class CoreServices(object): class CoreServices:
""" """
Class for interacting with a list of available startup services for Class for interacting with a list of available startup services for
nodes. Mostly used to convert a CoreService into a Config API nodes. Mostly used to convert a CoreService into a Config API
@ -462,18 +461,14 @@ class CoreServices(object):
:param core.netns.vnode.LxcNode node: node to start services on :param core.netns.vnode.LxcNode node: node to start services on
:return: nothing :return: nothing
""" """
pool = ThreadPool() funcs = []
results = []
boot_paths = ServiceDependencies(node.services).boot_paths() boot_paths = ServiceDependencies(node.services).boot_paths()
for boot_path in boot_paths: for boot_path in boot_paths:
result = pool.apply_async(self._start_boot_paths, (node, boot_path)) args = (node, boot_path)
results.append(result) funcs.append((self._start_boot_paths, args, {}))
result, exceptions = utils.threadpool(funcs)
pool.close() if exceptions:
pool.join() raise ServiceBootError(exceptions)
for result in results:
result.get()
def _start_boot_paths(self, node, boot_path): def _start_boot_paths(self, node, boot_path):
""" """
@ -791,7 +786,7 @@ class CoreServices(object):
node.nodefile(file_name, cfg) node.nodefile(file_name, cfg)
class CoreService(object): class CoreService:
""" """
Parent class used for defining services. Parent class used for defining services.
""" """

View file

@ -2,6 +2,7 @@
Miscellaneous utility functions, wrappers around some subprocess procedures. Miscellaneous utility functions, wrappers around some subprocess procedures.
""" """
import concurrent.futures
import fcntl import fcntl
import hashlib import hashlib
import importlib import importlib
@ -223,34 +224,6 @@ def cmd(args, env=None, cwd=None, wait=True, shell=False):
raise CoreCommandError(-1, args) raise CoreCommandError(-1, args)
def hex_dump(s, bytes_per_word=2, words_per_line=8):
"""
Hex dump of a string.
:param str s: string to hex dump
:param bytes_per_word: number of bytes per word
:param words_per_line: number of words per line
:return: hex dump of string
"""
dump = ""
count = 0
total_bytes = bytes_per_word * words_per_line
while s:
line = s[:total_bytes]
s = s[total_bytes:]
tmp = map(
lambda x: (f"{bytes_per_word:02x}" * bytes_per_word) % x,
zip(*[iter(map(ord, line))] * bytes_per_word),
)
if len(line) % 2:
tmp.append(f"{ord(line[-1]):x}")
tmp = " ".join(tmp)
dump += f"0x{count:08x}: {tmp}\n"
count += len(line)
return dump[:-1]
def file_munge(pathname, header, text): def file_munge(pathname, header, text):
""" """
Insert text at the end of a file, surrounded by header comments. Insert text at the end of a file, surrounded by header comments.
@ -409,3 +382,29 @@ def load_logging_config(config_path):
with open(config_path, "r") as log_config_file: with open(config_path, "r") as log_config_file:
log_config = json.load(log_config_file) log_config = json.load(log_config_file)
logging.config.dictConfig(log_config) logging.config.dictConfig(log_config)
def threadpool(funcs, workers=10):
"""
Run provided functions, arguments, and keywords within a threadpool
collecting results and exceptions.
:param iter funcs: iterable that provides a func, args, kwargs
:param int workers: number of workers for the threadpool
:return: results and exceptions from running functions with args and kwargs
:rtype: tuple
"""
with concurrent.futures.ThreadPoolExecutor(max_workers=workers) as executor:
futures = []
for func, args, kwargs in funcs:
future = executor.submit(func, *args, **kwargs)
futures.append(future)
results = []
exceptions = []
for future in concurrent.futures.as_completed(futures):
try:
result = future.result()
results.append(result)
except Exception as e:
exceptions.append(e)
return results, exceptions

View file

@ -104,7 +104,7 @@ def add_configuration(parent, name, value):
add_attribute(config_element, "value", value) add_attribute(config_element, "value", value)
class NodeElement(object): class NodeElement:
def __init__(self, session, node, element_name): def __init__(self, session, node, element_name):
self.session = session self.session = session
self.node = node self.node = node
@ -131,7 +131,7 @@ class NodeElement(object):
add_attribute(position, "alt", alt) add_attribute(position, "alt", alt)
class ServiceElement(object): class ServiceElement:
def __init__(self, service): def __init__(self, service):
self.service = service self.service = service
self.element = etree.Element("service") self.element = etree.Element("service")
@ -197,7 +197,7 @@ class ServiceElement(object):
class DeviceElement(NodeElement): class DeviceElement(NodeElement):
def __init__(self, session, node): def __init__(self, session, node):
super(DeviceElement, self).__init__(session, node, "device") super().__init__(session, node, "device")
add_attribute(self.element, "type", node.type) add_attribute(self.element, "type", node.type)
self.add_services() self.add_services()
@ -212,7 +212,7 @@ class DeviceElement(NodeElement):
class NetworkElement(NodeElement): class NetworkElement(NodeElement):
def __init__(self, session, node): def __init__(self, session, node):
super(NetworkElement, self).__init__(session, node, "network") super().__init__(session, node, "network")
model = getattr(self.node, "model", None) model = getattr(self.node, "model", None)
if model: if model:
add_attribute(self.element, "model", model.name) add_attribute(self.element, "model", model.name)
@ -232,7 +232,7 @@ class NetworkElement(NodeElement):
add_attribute(self.element, "type", node_type) add_attribute(self.element, "type", node_type)
class CoreXmlWriter(object): class CoreXmlWriter:
def __init__(self, session): def __init__(self, session):
self.session = session self.session = session
self.scenario = etree.Element("scenario") self.scenario = etree.Element("scenario")
@ -313,13 +313,13 @@ class CoreXmlWriter(object):
def write_session_metadata(self): def write_session_metadata(self):
# metadata # metadata
metadata_elements = etree.Element("session_metadata") metadata_elements = etree.Element("session_metadata")
config = self.session.metadata.get_configs() config = self.session.metadata
if not config: if not config:
return return
for _id in config: for key in config:
value = config[_id] value = config[key]
add_configuration(metadata_elements, _id, value) add_configuration(metadata_elements, key, value)
if metadata_elements.getchildren(): if metadata_elements.getchildren():
self.scenario.append(metadata_elements) self.scenario.append(metadata_elements)
@ -527,7 +527,7 @@ class CoreXmlWriter(object):
return link_element return link_element
class CoreXmlReader(object): class CoreXmlReader:
def __init__(self, session): def __init__(self, session):
self.session = session self.session = session
self.scenario = None self.scenario = None
@ -574,7 +574,7 @@ class CoreXmlReader(object):
value = data.get("value") value = data.get("value")
configs[name] = value configs[name] = value
logging.info("reading session metadata: %s", configs) logging.info("reading session metadata: %s", configs)
self.session.metadata.set_configs(configs) self.session.metadata = configs
def read_session_options(self): def read_session_options(self):
session_options = self.scenario.find("session_options") session_options = self.scenario.find("session_options")
@ -737,53 +737,51 @@ class CoreXmlReader(object):
node_id = get_int(device_element, "id") node_id = get_int(device_element, "id")
name = device_element.get("name") name = device_element.get("name")
model = device_element.get("type") model = device_element.get("type")
node_options = NodeOptions(name, model) options = NodeOptions(name, model)
service_elements = device_element.find("services") service_elements = device_element.find("services")
if service_elements is not None: if service_elements is not None:
node_options.services = [ options.services = [x.get("name") for x in service_elements.iterchildren()]
x.get("name") for x in service_elements.iterchildren()
]
position_element = device_element.find("position") position_element = device_element.find("position")
if position_element is not None: if position_element is not None:
x = get_int(position_element, "x") x = get_int(position_element, "x")
y = get_int(position_element, "y") y = get_int(position_element, "y")
if all([x, y]): if all([x, y]):
node_options.set_position(x, y) options.set_position(x, y)
lat = get_float(position_element, "lat") lat = get_float(position_element, "lat")
lon = get_float(position_element, "lon") lon = get_float(position_element, "lon")
alt = get_float(position_element, "alt") alt = get_float(position_element, "alt")
if all([lat, lon, alt]): if all([lat, lon, alt]):
node_options.set_location(lat, lon, alt) options.set_location(lat, lon, alt)
logging.info("reading node id(%s) model(%s) name(%s)", node_id, model, name) logging.info("reading node id(%s) model(%s) name(%s)", node_id, model, name)
self.session.add_node(_id=node_id, node_options=node_options) self.session.add_node(_id=node_id, options=options)
def read_network(self, network_element): def read_network(self, network_element):
node_id = get_int(network_element, "id") node_id = get_int(network_element, "id")
name = network_element.get("name") name = network_element.get("name")
node_type = NodeTypes[network_element.get("type")] node_type = NodeTypes[network_element.get("type")]
node_options = NodeOptions(name) options = NodeOptions(name)
position_element = network_element.find("position") position_element = network_element.find("position")
if position_element is not None: if position_element is not None:
x = get_int(position_element, "x") x = get_int(position_element, "x")
y = get_int(position_element, "y") y = get_int(position_element, "y")
if all([x, y]): if all([x, y]):
node_options.set_position(x, y) options.set_position(x, y)
lat = get_float(position_element, "lat") lat = get_float(position_element, "lat")
lon = get_float(position_element, "lon") lon = get_float(position_element, "lon")
alt = get_float(position_element, "alt") alt = get_float(position_element, "alt")
if all([lat, lon, alt]): if all([lat, lon, alt]):
node_options.set_location(lat, lon, alt) options.set_location(lat, lon, alt)
logging.info( logging.info(
"reading node id(%s) node_type(%s) name(%s)", node_id, node_type, name "reading node id(%s) node_type(%s) name(%s)", node_id, node_type, name
) )
self.session.add_node(_type=node_type, _id=node_id, node_options=node_options) self.session.add_node(_type=node_type, _id=node_id, options=options)
def read_links(self): def read_links(self):
link_elements = self.scenario.find("links") link_elements = self.scenario.find("links")

View file

@ -84,7 +84,7 @@ def get_ipv4_addresses(hostname):
raise NotImplementedError raise NotImplementedError
class CoreXmlDeployment(object): class CoreXmlDeployment:
def __init__(self, session, scenario): def __init__(self, session, scenario):
self.session = session self.session = session
self.scenario = scenario self.scenario = scenario

View file

@ -15,7 +15,7 @@ if __name__ == "__main__":
options = NodeOptions(model=None, image="ubuntu") options = NodeOptions(model=None, image="ubuntu")
# create node one # create node one
node_one = session.add_node(_type=NodeTypes.DOCKER, node_options=options) node_one = session.add_node(_type=NodeTypes.DOCKER, options=options)
interface_one = prefixes.create_interface(node_one) interface_one = prefixes.create_interface(node_one)
# create node two # create node two

View file

@ -17,11 +17,11 @@ if __name__ == "__main__":
options = NodeOptions(model=None, image="ubuntu") options = NodeOptions(model=None, image="ubuntu")
# create node one # create node one
node_one = session.add_node(_type=NodeTypes.DOCKER, node_options=options) node_one = session.add_node(_type=NodeTypes.DOCKER, options=options)
interface_one = prefixes.create_interface(node_one) interface_one = prefixes.create_interface(node_one)
# create node two # create node two
node_two = session.add_node(_type=NodeTypes.DOCKER, node_options=options) node_two = session.add_node(_type=NodeTypes.DOCKER, options=options)
interface_two = prefixes.create_interface(node_two) interface_two = prefixes.create_interface(node_two)
# add link # add link

View file

@ -19,11 +19,11 @@ if __name__ == "__main__":
switch = session.add_node(_type=NodeTypes.SWITCH) switch = session.add_node(_type=NodeTypes.SWITCH)
# node one # node one
node_one = session.add_node(_type=NodeTypes.DOCKER, node_options=options) node_one = session.add_node(_type=NodeTypes.DOCKER, options=options)
interface_one = prefixes.create_interface(node_one) interface_one = prefixes.create_interface(node_one)
# node two # node two
node_two = session.add_node(_type=NodeTypes.DOCKER, node_options=options) node_two = session.add_node(_type=NodeTypes.DOCKER, options=options)
interface_two = prefixes.create_interface(node_two) interface_two = prefixes.create_interface(node_two)
# node three # node three

View file

@ -0,0 +1,54 @@
import logging
from core.api.grpc import client, core_pb2
def log_event(event):
logging.info("event: %s", event)
def main():
core = client.CoreGrpcClient()
with core.context_connect():
# create session
response = core.create_session()
session_id = response.session_id
logging.info("created session: %s", response)
# create nodes for session
nodes = []
position = core_pb2.Position(x=50, y=100)
switch = core_pb2.Node(id=1, type=core_pb2.NodeType.SWITCH, position=position)
nodes.append(switch)
for i in range(2, 50):
position = core_pb2.Position(x=50 + 50 * i, y=50)
node = core_pb2.Node(id=i, position=position, model="PC")
nodes.append(node)
# create links
interface_helper = client.InterfaceHelper(ip4_prefix="10.83.0.0/16")
links = []
for node in nodes:
interface_one = interface_helper.create_interface(node.id, 0)
link = core_pb2.Link(
type=core_pb2.LinkType.WIRED,
node_one_id=node.id,
node_two_id=switch.id,
interface_one=interface_one,
)
links.append(link)
# start session
response = core.start_session(session_id, nodes, links)
logging.info("started session: %s", response)
input("press enter to shutdown session")
response = core.stop_session(session_id)
logging.info("stop sessionL %s", response)
if __name__ == "__main__":
logging.basicConfig(level=logging.DEBUG)
main()

View file

@ -15,7 +15,7 @@ if __name__ == "__main__":
options = NodeOptions(image="ubuntu") options = NodeOptions(image="ubuntu")
# create node one # create node one
node_one = session.add_node(_type=NodeTypes.LXC, node_options=options) node_one = session.add_node(_type=NodeTypes.LXC, options=options)
interface_one = prefixes.create_interface(node_one) interface_one = prefixes.create_interface(node_one)
# create node two # create node two

View file

@ -17,11 +17,11 @@ if __name__ == "__main__":
options = NodeOptions(image="ubuntu:18.04") options = NodeOptions(image="ubuntu:18.04")
# create node one # create node one
node_one = session.add_node(_type=NodeTypes.LXC, node_options=options) node_one = session.add_node(_type=NodeTypes.LXC, options=options)
interface_one = prefixes.create_interface(node_one) interface_one = prefixes.create_interface(node_one)
# create node two # create node two
node_two = session.add_node(_type=NodeTypes.LXC, node_options=options) node_two = session.add_node(_type=NodeTypes.LXC, options=options)
interface_two = prefixes.create_interface(node_two) interface_two = prefixes.create_interface(node_two)
# add link # add link

View file

@ -19,11 +19,11 @@ if __name__ == "__main__":
switch = session.add_node(_type=NodeTypes.SWITCH) switch = session.add_node(_type=NodeTypes.SWITCH)
# node one # node one
node_one = session.add_node(_type=NodeTypes.LXC, node_options=options) node_one = session.add_node(_type=NodeTypes.LXC, options=options)
interface_one = prefixes.create_interface(node_one) interface_one = prefixes.create_interface(node_one)
# node two # node two
node_two = session.add_node(_type=NodeTypes.LXC, node_options=options) node_two = session.add_node(_type=NodeTypes.LXC, options=options)
interface_two = prefixes.create_interface(node_two) interface_two = prefixes.create_interface(node_two)
# node three # node three

View file

@ -31,11 +31,11 @@ def main(args):
# create local node, switch, and remote nodes # create local node, switch, and remote nodes
options = NodeOptions(model="mdr") options = NodeOptions(model="mdr")
options.set_position(0, 0) options.set_position(0, 0)
node_one = session.add_node(node_options=options) node_one = session.add_node(options=options)
emane_net = session.add_node(_type=NodeTypes.EMANE) emane_net = session.add_node(_type=NodeTypes.EMANE)
session.emane.set_model(emane_net, EmaneIeee80211abgModel) session.emane.set_model(emane_net, EmaneIeee80211abgModel)
options.emulation_server = server_name options.server = server_name
node_two = session.add_node(node_options=options) node_two = session.add_node(options=options)
# create node interfaces and link # create node interfaces and link
interface_one = prefixes.create_interface(node_one) interface_one = prefixes.create_interface(node_one)

View file

@ -23,9 +23,9 @@ def main(args):
# create local node, switch, and remote nodes # create local node, switch, and remote nodes
options = NodeOptions(image="ubuntu:18.04") options = NodeOptions(image="ubuntu:18.04")
node_one = session.add_node(_type=NodeTypes.LXC, node_options=options) node_one = session.add_node(_type=NodeTypes.LXC, options=options)
options.emulation_server = server_name options.server = server_name
node_two = session.add_node(_type=NodeTypes.LXC, node_options=options) node_two = session.add_node(_type=NodeTypes.LXC, options=options)
# create node interfaces and link # create node interfaces and link
interface_one = prefixes.create_interface(node_one) interface_one = prefixes.create_interface(node_one)

View file

@ -23,9 +23,9 @@ def main(args):
# create local node, switch, and remote nodes # create local node, switch, and remote nodes
options = NodeOptions() options = NodeOptions()
node_one = session.add_node(node_options=options) node_one = session.add_node(options=options)
options.emulation_server = server_name options.server = server_name
node_two = session.add_node(node_options=options) node_two = session.add_node(options=options)
# create node interfaces and link # create node interfaces and link
interface_one = prefixes.create_interface(node_one) interface_one = prefixes.create_interface(node_one)

View file

@ -27,8 +27,8 @@ def main(args):
node_one = session.add_node() node_one = session.add_node()
switch = session.add_node(_type=NodeTypes.SWITCH) switch = session.add_node(_type=NodeTypes.SWITCH)
options = NodeOptions() options = NodeOptions()
options.emulation_server = server_name options.server = server_name
node_two = session.add_node(node_options=options) node_two = session.add_node(options=options)
# create node interfaces and link # create node interfaces and link
interface_one = prefixes.create_interface(node_one) interface_one = prefixes.create_interface(node_one)

View file

@ -4,11 +4,11 @@ import parser
from core.emane.ieee80211abg import EmaneIeee80211abgModel from core.emane.ieee80211abg import EmaneIeee80211abgModel
from core.emulator.coreemu import CoreEmu from core.emulator.coreemu import CoreEmu
from core.emulator.emudata import IpPrefixes from core.emulator.emudata import IpPrefixes, NodeOptions
from core.emulator.enumerations import EventTypes from core.emulator.enumerations import EventTypes, NodeTypes
def example(options): def example(args):
# ip generator for example # ip generator for example
prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16") prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16")
@ -20,14 +20,16 @@ def example(options):
session.set_state(EventTypes.CONFIGURATION_STATE) session.set_state(EventTypes.CONFIGURATION_STATE)
# create emane network node # create emane network node
emane_network = session.create_emane_network( session.set_location(47.57917, -122.13232, 2.00000, 1.0)
model=EmaneIeee80211abgModel, geo_reference=(47.57917, -122.13232, 2.00000) options = NodeOptions()
) options.set_position(80, 50)
emane_network.setposition(x=80, y=50) emane_network = session.add_node(_type=NodeTypes.EMANE, options=options)
session.emane.set_model(emane_network, EmaneIeee80211abgModel)
# create nodes # create nodes
for i in range(options.nodes): options = NodeOptions(model="mdr")
node = session.create_wireless_node() for i in range(args.nodes):
node = session.add_node(options=options)
node.setposition(x=150 * (i + 1), y=150) node.setposition(x=150 * (i + 1), y=150)
interface = prefixes.create_interface(node) interface = prefixes.create_interface(node)
session.add_link(node.id, emane_network.id, interface_one=interface) session.add_link(node.id, emane_network.id, interface_one=interface)
@ -42,12 +44,12 @@ def example(options):
def main(): def main():
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)
options = parser.parse_options("emane80211") args = parser.parse("emane80211")
start = datetime.datetime.now() start = datetime.datetime.now()
logging.info( logging.info(
"running emane 80211 example: nodes(%s) time(%s)", options.nodes, options.time "running emane 80211 example: nodes(%s) time(%s)", args.nodes, args.time
) )
example(options) example(args)
logging.info("elapsed time: %s", datetime.datetime.now() - start) logging.info("elapsed time: %s", datetime.datetime.now() - start)

View file

@ -5,7 +5,7 @@ DEFAULT_TIME = 10
DEFAULT_STEP = 1 DEFAULT_STEP = 1
def parse_options(name): def parse(name):
parser = argparse.ArgumentParser(description=f"Run {name} example") parser = argparse.ArgumentParser(description=f"Run {name} example")
parser.add_argument( parser.add_argument(
"-n", "-n",
@ -22,11 +22,11 @@ def parse_options(name):
help="example iperf run time in seconds", help="example iperf run time in seconds",
) )
options = parser.parse_args() args = parser.parse_args()
if options.nodes < 2: if args.nodes < 2:
parser.error(f"invalid min number of nodes: {options.nodes}") parser.error(f"invalid min number of nodes: {args.nodes}")
if options.time < 1: if args.time < 1:
parser.error(f"invalid test time: {options.time}") parser.error(f"invalid test time: {args.time}")
return options return args

View file

@ -7,7 +7,7 @@ from core.emulator.emudata import IpPrefixes
from core.emulator.enumerations import EventTypes, NodeTypes from core.emulator.enumerations import EventTypes, NodeTypes
def example(options): def example(args):
# ip generator for example # ip generator for example
prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16") prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16")
@ -22,7 +22,7 @@ def example(options):
switch = session.add_node(_type=NodeTypes.SWITCH) switch = session.add_node(_type=NodeTypes.SWITCH)
# create nodes # create nodes
for _ in range(options.nodes): for _ in range(args.nodes):
node = session.add_node() node = session.add_node()
interface = prefixes.create_interface(node) interface = prefixes.create_interface(node)
session.add_link(node.id, switch.id, interface_one=interface) session.add_link(node.id, switch.id, interface_one=interface)
@ -32,13 +32,13 @@ def example(options):
# get nodes to run example # get nodes to run example
first_node = session.get_node(2) first_node = session.get_node(2)
last_node = session.get_node(options.nodes + 1) last_node = session.get_node(args.nodes + 1)
logging.info("starting iperf server on node: %s", first_node.name) logging.info("starting iperf server on node: %s", first_node.name)
first_node.cmd("iperf -s -D") first_node.cmd("iperf -s -D")
first_node_address = prefixes.ip4_address(first_node) first_node_address = prefixes.ip4_address(first_node)
logging.info("node %s connecting to %s", last_node.name, first_node_address) logging.info("node %s connecting to %s", last_node.name, first_node_address)
output = last_node.cmd(f"iperf -t {options.time} -c {first_node_address}") output = last_node.cmd(f"iperf -t {args.time} -c {first_node_address}")
logging.info(output) logging.info(output)
first_node.cmd("killall -9 iperf") first_node.cmd("killall -9 iperf")
@ -48,12 +48,10 @@ def example(options):
def main(): def main():
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)
options = parser.parse_options("switch") args = parser.parse("switch")
start = datetime.datetime.now() start = datetime.datetime.now()
logging.info( logging.info("running switch example: nodes(%s) time(%s)", args.nodes, args.time)
"running switch example: nodes(%s) time(%s)", options.nodes, options.time example(args)
)
example(options)
logging.info("elapsed time: %s", datetime.datetime.now() - start) logging.info("elapsed time: %s", datetime.datetime.now() - start)

View file

@ -8,7 +8,7 @@ from core.emulator.enumerations import EventTypes, NodeTypes
from core.location.mobility import BasicRangeModel from core.location.mobility import BasicRangeModel
def example(options): def example(args):
# ip generator for example # ip generator for example
prefixes = IpPrefixes("10.83.0.0/16") prefixes = IpPrefixes("10.83.0.0/16")
@ -24,10 +24,10 @@ def example(options):
session.mobility.set_model(wlan, BasicRangeModel) session.mobility.set_model(wlan, BasicRangeModel)
# create nodes, must set a position for wlan basic range model # create nodes, must set a position for wlan basic range model
node_options = NodeOptions() options = NodeOptions(model="mdr")
node_options.set_position(0, 0) options.set_position(0, 0)
for _ in range(options.nodes): for _ in range(args.nodes):
node = session.add_node(node_options=node_options) node = session.add_node(options=options)
interface = prefixes.create_interface(node) interface = prefixes.create_interface(node)
session.add_link(node.id, wlan.id, interface_one=interface) session.add_link(node.id, wlan.id, interface_one=interface)
@ -36,13 +36,14 @@ def example(options):
# get nodes for example run # get nodes for example run
first_node = session.get_node(2) first_node = session.get_node(2)
last_node = session.get_node(options.nodes + 1) last_node = session.get_node(args.nodes + 1)
logging.info("starting iperf server on node: %s", first_node.name) logging.info("starting iperf server on node: %s", first_node.name)
first_node.cmd("iperf -s -D") first_node.cmd("iperf -s -D")
address = prefixes.ip4_address(first_node) address = prefixes.ip4_address(first_node)
logging.info("node %s connecting to %s", last_node.name, address) logging.info("node %s connecting to %s", last_node.name, address)
last_node.cmd(f"iperf -t {options.time} -c {address}") output = last_node.cmd(f"iperf -t {args.time} -c {address}")
logging.info(output)
first_node.cmd("killall -9 iperf") first_node.cmd("killall -9 iperf")
# shutdown session # shutdown session
@ -51,13 +52,11 @@ def example(options):
def main(): def main():
logging.basicConfig(level=logging.INFO) logging.basicConfig(level=logging.INFO)
options = parser.parse_options("wlan") args = parser.parse("wlan")
start = datetime.datetime.now() start = datetime.datetime.now()
logging.info( logging.info("running wlan example: nodes(%s) time(%s)", args.nodes, args.time)
"running wlan example: nodes(%s) time(%s)", options.nodes, options.time example(args)
)
example(options)
logging.info("elapsed time: %s", datetime.datetime.now() - start) logging.info("elapsed time: %s", datetime.datetime.now() - start)

View file

@ -7,6 +7,10 @@ option java_outer_classname = "CoreProto";
service CoreApi { service CoreApi {
// session rpc // session rpc
rpc StartSession (StartSessionRequest) returns (StartSessionResponse) {
}
rpc StopSession (StopSessionRequest) returns (StopSessionResponse) {
}
rpc CreateSession (CreateSessionRequest) returns (CreateSessionResponse) { rpc CreateSession (CreateSessionRequest) returns (CreateSessionResponse) {
} }
rpc DeleteSession (DeleteSessionRequest) returns (DeleteSessionResponse) { rpc DeleteSession (DeleteSessionRequest) returns (DeleteSessionResponse) {
@ -19,6 +23,10 @@ service CoreApi {
} }
rpc SetSessionOptions (SetSessionOptionsRequest) returns (SetSessionOptionsResponse) { rpc SetSessionOptions (SetSessionOptionsRequest) returns (SetSessionOptionsResponse) {
} }
rpc SetSessionMetadata (SetSessionMetadataRequest) returns (SetSessionMetadataResponse) {
}
rpc GetSessionMetadata (GetSessionMetadataRequest) returns (GetSessionMetadataResponse) {
}
rpc GetSessionLocation (GetSessionLocationRequest) returns (GetSessionLocationResponse) { rpc GetSessionLocation (GetSessionLocationRequest) returns (GetSessionLocationResponse) {
} }
rpc SetSessionLocation (SetSessionLocationRequest) returns (SetSessionLocationResponse) { rpc SetSessionLocation (SetSessionLocationRequest) returns (SetSessionLocationResponse) {
@ -126,6 +134,30 @@ service CoreApi {
} }
// rpc request/response messages // rpc request/response messages
message StartSessionRequest {
int32 session_id = 1;
repeated Node nodes = 2;
repeated Link links = 3;
repeated Hook hooks = 4;
SessionLocation location = 5;
map<string, string> emane_config = 6;
repeated WlanConfig wlan_configs = 7;
repeated EmaneModelConfig emane_model_configs = 8;
repeated MobilityConfig mobility_configs = 9;
}
message StartSessionResponse {
bool result = 1;
}
message StopSessionRequest {
int32 session_id = 1;
}
message StopSessionResponse {
bool result = 1;
}
message CreateSessionRequest { message CreateSessionRequest {
int32 session_id = 1; int32 session_id = 1;
} }
@ -175,19 +207,34 @@ message SetSessionOptionsResponse {
bool result = 1; bool result = 1;
} }
message SetSessionMetadataRequest {
int32 session_id = 1;
map<string, string> config = 2;
}
message SetSessionMetadataResponse {
bool result = 1;
}
message GetSessionMetadataRequest {
int32 session_id = 1;
}
message GetSessionMetadataResponse {
map<string, string> config = 1;
}
message GetSessionLocationRequest { message GetSessionLocationRequest {
int32 session_id = 1; int32 session_id = 1;
} }
message GetSessionLocationResponse { message GetSessionLocationResponse {
SessionPosition position = 1; SessionLocation location = 1;
float scale = 2;
} }
message SetSessionLocationRequest { message SetSessionLocationRequest {
int32 session_id = 1; int32 session_id = 1;
SessionPosition position = 2; SessionLocation location = 2;
float scale = 3;
} }
message SetSessionLocationResponse { message SetSessionLocationResponse {
@ -442,8 +489,7 @@ message GetMobilityConfigResponse {
message SetMobilityConfigRequest { message SetMobilityConfigRequest {
int32 session_id = 1; int32 session_id = 1;
int32 node_id = 2; MobilityConfig mobility_config = 2;
map<string, string> config = 3;
} }
message SetMobilityConfigResponse { message SetMobilityConfigResponse {
@ -553,8 +599,7 @@ message GetWlanConfigResponse {
message SetWlanConfigRequest { message SetWlanConfigRequest {
int32 session_id = 1; int32 session_id = 1;
int32 node_id = 2; WlanConfig wlan_config = 2;
map<string, string> config = 3;
} }
message SetWlanConfigResponse { message SetWlanConfigResponse {
@ -599,10 +644,7 @@ message GetEmaneModelConfigResponse {
message SetEmaneModelConfigRequest { message SetEmaneModelConfigRequest {
int32 session_id = 1; int32 session_id = 1;
int32 node_id = 2; EmaneModelConfig emane_model_config = 2;
int32 interface_id = 3;
string model = 4;
map<string, string> config = 5;
} }
message SetEmaneModelConfigResponse { message SetEmaneModelConfigResponse {
@ -659,6 +701,23 @@ message EmaneLinkResponse {
} }
// data structures for messages below // data structures for messages below
message WlanConfig {
int32 node_id = 1;
map<string, string> config = 2;
}
message MobilityConfig {
int32 node_id = 1;
map<string, string> config = 2;
}
message EmaneModelConfig {
int32 node_id = 1;
int32 interface_id = 2;
string model = 3;
map<string, string> config = 4;
}
message MessageType { message MessageType {
enum Enum { enum Enum {
NONE = 0; NONE = 0;
@ -695,18 +754,15 @@ message NodeType {
enum Enum { enum Enum {
DEFAULT = 0; DEFAULT = 0;
PHYSICAL = 1; PHYSICAL = 1;
TBD = 3;
SWITCH = 4; SWITCH = 4;
HUB = 5; HUB = 5;
WIRELESS_LAN = 6; WIRELESS_LAN = 6;
RJ45 = 7; RJ45 = 7;
TUNNEL = 8; TUNNEL = 8;
KTUNNEL = 9;
EMANE = 10; EMANE = 10;
TAP_BRIDGE = 11; TAP_BRIDGE = 11;
PEER_TO_PEER = 12; PEER_TO_PEER = 12;
CONTROL_NET = 13; CONTROL_NET = 13;
EMANE_NET = 14;
DOCKER = 15; DOCKER = 15;
LXC = 16; LXC = 16;
} }
@ -853,13 +909,14 @@ message Interface {
int32 mtu = 10; int32 mtu = 10;
} }
message SessionPosition { message SessionLocation {
float x = 1; float x = 1;
float y = 2; float y = 2;
float z = 3; float z = 3;
float lat = 4; float lat = 4;
float lon = 5; float lon = 5;
float alt = 6; float alt = 6;
float scale = 7;
} }
message Position { message Position {

View file

@ -14,7 +14,7 @@ from core import services
from core.constants import CORE_CONF_DIR from core.constants import CORE_CONF_DIR
class FileUpdater(object): class FileUpdater:
""" """
Helper class for changing configuration files. Helper class for changing configuration files.
""" """

View file

@ -2,189 +2,140 @@
Unit test fixture module. Unit test fixture module.
""" """
import os
import threading import threading
import time import time
import mock
import pytest import pytest
from mock.mock import MagicMock from mock.mock import MagicMock
from core.api.grpc.client import InterfaceHelper from core.api.grpc.client import InterfaceHelper
from core.api.grpc.server import CoreGrpcServer from core.api.grpc.server import CoreGrpcServer
from core.api.tlv.coreapi import CoreConfMessage, CoreEventMessage
from core.api.tlv.corehandlers import CoreHandler from core.api.tlv.corehandlers import CoreHandler
from core.api.tlv.coreserver import CoreServer from core.emane.emanemanager import EmaneManager
from core.emulator.coreemu import CoreEmu from core.emulator.coreemu import CoreEmu
from core.emulator.distributed import DistributedServer
from core.emulator.emudata import IpPrefixes from core.emulator.emudata import IpPrefixes
from core.emulator.enumerations import CORE_API_PORT, ConfigTlvs, EventTlvs, EventTypes from core.emulator.enumerations import EventTypes
from core.nodes import ipaddress from core.emulator.session import Session
from core.services.coreservices import ServiceManager from core.nodes.base import CoreNode
EMANE_SERVICES = "zebra|OSPFv3MDR|IPForward" EMANE_SERVICES = "zebra|OSPFv3MDR|IPForward"
class CoreServerTest(object): class PatchManager:
def __init__(self, port=CORE_API_PORT): def __init__(self):
self.host = "localhost" self.patches = []
self.port = port
address = (self.host, self.port)
self.server = CoreServer(
address, CoreHandler, {"numthreads": 1, "daemonize": False}
)
self.distributed_server = "core2" def patch_obj(self, _cls, attribute):
self.prefix = ipaddress.Ipv4Prefix("10.83.0.0/16") p = mock.patch.object(_cls, attribute)
self.session = None p.start()
self.request_handler = None self.patches.append(p)
def setup_handler(self): def patch(self, func):
self.session = self.server.coreemu.create_session(1) p = mock.patch(func)
request_mock = MagicMock() p.start()
request_mock.fileno = MagicMock(return_value=1) self.patches.append(p)
self.request_handler = CoreHandler(request_mock, "", self.server)
self.request_handler.session = self.session
self.request_handler.add_session_handlers()
def setup(self, distributed_address):
# validate address
assert distributed_address, "distributed server address was not provided"
# create session
self.session = self.server.coreemu.create_session(1)
# create request handler
request_mock = MagicMock()
request_mock.fileno = MagicMock(return_value=1)
self.request_handler = CoreHandler(request_mock, "", self.server)
self.request_handler.session = self.session
self.request_handler.add_session_handlers()
# have broker handle a configuration state change
self.session.set_state(EventTypes.DEFINITION_STATE)
message = CoreEventMessage.create(
0, [(EventTlvs.TYPE, EventTypes.CONFIGURATION_STATE.value)]
)
self.request_handler.handle_message(message)
# add broker server for distributed core
distributed = f"{self.distributed_server}:{distributed_address}:{self.port}"
message = CoreConfMessage.create(
0,
[
(ConfigTlvs.OBJECT, "broker"),
(ConfigTlvs.TYPE, 0),
(ConfigTlvs.DATA_TYPES, (10,)),
(ConfigTlvs.VALUES, distributed),
],
)
self.request_handler.handle_message(message)
# set session location
message = CoreConfMessage.create(
0,
[
(ConfigTlvs.OBJECT, "location"),
(ConfigTlvs.TYPE, 0),
(ConfigTlvs.DATA_TYPES, (9, 9, 9, 9, 9, 9)),
(ConfigTlvs.VALUES, "0|0| 47.5766974863|-122.125920191|0.0|150.0"),
],
)
self.request_handler.handle_message(message)
# set services for host nodes
message = CoreConfMessage.create(
0,
[
(ConfigTlvs.SESSION, str(self.session.id)),
(ConfigTlvs.OBJECT, "services"),
(ConfigTlvs.TYPE, 0),
(ConfigTlvs.DATA_TYPES, (10, 10, 10)),
(ConfigTlvs.VALUES, "host|DefaultRoute|SSH"),
],
)
self.request_handler.handle_message(message)
def shutdown(self): def shutdown(self):
self.server.coreemu.shutdown() for p in self.patches:
self.server.server_close() p.stop()
@pytest.fixture class MockServer:
def grpc_server(): def __init__(self, config, coreemu):
coremu = CoreEmu() self.config = config
grpc_server = CoreGrpcServer(coremu) self.coreemu = coreemu
@pytest.fixture(scope="session")
def patcher(request):
patch_manager = PatchManager()
patch_manager.patch_obj(DistributedServer, "remote_cmd")
if request.config.getoption("mock"):
patch_manager.patch("os.mkdir")
patch_manager.patch("core.utils.cmd")
patch_manager.patch("core.nodes.netclient.get_net_client")
patch_manager.patch_obj(CoreNode, "nodefile")
patch_manager.patch_obj(Session, "write_state")
patch_manager.patch_obj(Session, "write_nodes")
patch_manager.patch_obj(EmaneManager, "buildxml")
yield patch_manager
patch_manager.shutdown()
@pytest.fixture(scope="session")
def global_coreemu(patcher):
coreemu = CoreEmu(config={"emane_prefix": "/usr"})
yield coreemu
coreemu.shutdown()
@pytest.fixture(scope="session")
def global_session(request, patcher, global_coreemu):
mkdir = not request.config.getoption("mock")
session = Session(1000, {"emane_prefix": "/usr"}, mkdir)
yield session
session.shutdown()
@pytest.fixture(scope="session")
def ip_prefixes():
return IpPrefixes(ip4_prefix="10.83.0.0/16")
@pytest.fixture(scope="session")
def interface_helper():
return InterfaceHelper(ip4_prefix="10.83.0.0/16")
@pytest.fixture(scope="module")
def module_grpc(global_coreemu):
grpc_server = CoreGrpcServer(global_coreemu)
thread = threading.Thread(target=grpc_server.listen, args=("localhost:50051",)) thread = threading.Thread(target=grpc_server.listen, args=("localhost:50051",))
thread.daemon = True thread.daemon = True
thread.start() thread.start()
time.sleep(0.1) time.sleep(0.1)
yield grpc_server yield grpc_server
coremu.shutdown()
grpc_server.server.stop(None) grpc_server.server.stop(None)
@pytest.fixture(scope="module")
def module_coretlv(patcher, global_coreemu, global_session):
request_mock = MagicMock()
request_mock.fileno = MagicMock(return_value=1)
server = MockServer({"numthreads": "1"}, global_coreemu)
request_handler = CoreHandler(request_mock, "", server)
request_handler.session = global_session
request_handler.add_session_handlers()
yield request_handler
@pytest.fixture @pytest.fixture
def session(): def grpc_server(module_grpc):
# use coreemu and create a session yield module_grpc
coreemu = CoreEmu(config={"emane_prefix": "/usr"}) module_grpc.coreemu.shutdown()
session_fixture = coreemu.create_session()
session_fixture.set_state(EventTypes.CONFIGURATION_STATE)
assert os.path.exists(session_fixture.session_dir)
# return created session
yield session_fixture
# clear session configurations @pytest.fixture
session_fixture.location.reset() def session(global_session):
session_fixture.services.reset() global_session.set_state(EventTypes.CONFIGURATION_STATE)
session_fixture.mobility.config_reset() yield global_session
session_fixture.emane.config_reset() global_session.clear()
# shutdown coreemu
@pytest.fixture
def coretlv(module_coretlv):
session = module_coretlv.session
coreemu = module_coretlv.coreemu
coreemu.sessions[session.id] = session
yield module_coretlv
coreemu.shutdown() coreemu.shutdown()
# clear services, since they will be reloaded
ServiceManager.services.clear()
@pytest.fixture(scope="module")
def ip_prefixes():
return IpPrefixes(ip4_prefix="10.83.0.0/16")
@pytest.fixture(scope="module")
def interface_helper():
return InterfaceHelper(ip4_prefix="10.83.0.0/16")
@pytest.fixture()
def cored():
# create and return server
server = CoreServerTest()
yield server
# cleanup
server.shutdown()
# cleanup services
ServiceManager.services.clear()
@pytest.fixture()
def coreserver():
# create and return server
server = CoreServerTest()
server.setup_handler()
yield server
# cleanup
server.shutdown()
# cleanup services
ServiceManager.services.clear()
def pytest_addoption(parser): def pytest_addoption(parser):
parser.addoption("--distributed", help="distributed server address") parser.addoption("--distributed", help="distributed server address")
parser.addoption("--mock", action="store_true", help="run without mocking")
def pytest_generate_tests(metafunc): def pytest_generate_tests(metafunc):

View file

@ -1,354 +0,0 @@
"""
Unit tests for testing CORE with distributed networks.
"""
from core.api.tlv.coreapi import (
CoreConfMessage,
CoreEventMessage,
CoreExecMessage,
CoreLinkMessage,
CoreNodeMessage,
)
from core.emane.ieee80211abg import EmaneIeee80211abgModel
from core.emulator.enumerations import (
ConfigFlags,
ConfigTlvs,
EventTlvs,
EventTypes,
ExecuteTlvs,
LinkTlvs,
LinkTypes,
MessageFlags,
NodeTlvs,
NodeTypes,
)
from core.nodes.ipaddress import IpAddress, MacAddress
def set_emane_model(node_id, model):
return CoreConfMessage.create(
0,
[
(ConfigTlvs.NODE, node_id),
(ConfigTlvs.OBJECT, model),
(ConfigTlvs.TYPE, ConfigFlags.UPDATE.value),
],
)
def node_message(
_id, name, emulation_server=None, node_type=NodeTypes.DEFAULT, model=None
):
"""
Convenience method for creating a node TLV messages.
:param int _id: node id
:param str name: node name
:param str emulation_server: distributed server name, if desired
:param core.emulator.enumerations.NodeTypes node_type: node type
:param str model: model for node
:return: tlv message
:rtype: core.api.tlv.coreapi.CoreNodeMessage
"""
values = [
(NodeTlvs.NUMBER, _id),
(NodeTlvs.TYPE, node_type.value),
(NodeTlvs.NAME, name),
(NodeTlvs.EMULATION_SERVER, emulation_server),
(NodeTlvs.X_POSITION, 0),
(NodeTlvs.Y_POSITION, 0),
]
if model:
values.append((NodeTlvs.MODEL, model))
return CoreNodeMessage.create(MessageFlags.ADD.value, values)
def link_message(
n1,
n2,
intf_one=None,
address_one=None,
intf_two=None,
address_two=None,
key=None,
mask=24,
):
"""
Convenience method for creating link TLV messages.
:param int n1: node one id
:param int n2: node two id
:param int intf_one: node one interface id
:param core.nodes.ipaddress.IpAddress address_one: node one ip4 address
:param int intf_two: node two interface id
:param core.nodes.ipaddress.IpAddress address_two: node two ip4 address
:param int key: tunnel key for link if needed
:param int mask: ip4 mask to use for link
:return: tlv mesage
:rtype: core.api.tlv.coreapi.CoreLinkMessage
"""
mac_one, mac_two = None, None
if address_one:
mac_one = MacAddress.random()
if address_two:
mac_two = MacAddress.random()
values = [
(LinkTlvs.N1_NUMBER, n1),
(LinkTlvs.N2_NUMBER, n2),
(LinkTlvs.DELAY, 0),
(LinkTlvs.BANDWIDTH, 0),
(LinkTlvs.PER, "0"),
(LinkTlvs.DUP, "0"),
(LinkTlvs.JITTER, 0),
(LinkTlvs.TYPE, LinkTypes.WIRED.value),
(LinkTlvs.INTERFACE1_NUMBER, intf_one),
(LinkTlvs.INTERFACE1_IP4, address_one),
(LinkTlvs.INTERFACE1_IP4_MASK, mask),
(LinkTlvs.INTERFACE1_MAC, mac_one),
(LinkTlvs.INTERFACE2_NUMBER, intf_two),
(LinkTlvs.INTERFACE2_IP4, address_two),
(LinkTlvs.INTERFACE2_IP4_MASK, mask),
(LinkTlvs.INTERFACE2_MAC, mac_two),
]
if key:
values.append((LinkTlvs.KEY, key))
return CoreLinkMessage.create(MessageFlags.ADD.value, values)
def command_message(node, command):
"""
Create an execute command TLV message.
:param node: node to execute command for
:param command: command to execute
:return: tlv message
:rtype: core.api.tlv.coreapi.CoreExecMessage
"""
flags = MessageFlags.STRING.value | MessageFlags.TEXT.value
return CoreExecMessage.create(
flags,
[
(ExecuteTlvs.NODE, node.id),
(ExecuteTlvs.NUMBER, 1),
(ExecuteTlvs.COMMAND, command),
],
)
def state_message(state):
"""
Create a event TLV message for a new state.
:param core.enumerations.EventTypes state: state to create message for
:return: tlv message
:rtype: core.api.tlv.coreapi.CoreEventMessage
"""
return CoreEventMessage.create(0, [(EventTlvs.TYPE, state.value)])
def validate_response(replies, _):
"""
Patch method for handling dispatch replies within a CoreRequestHandler to validate a response.
:param tuple replies: replies to handle
:param _: nothing
:return: nothing
"""
response = replies[0]
header = response[: CoreExecMessage.header_len]
tlv_data = response[CoreExecMessage.header_len :]
response = CoreExecMessage(MessageFlags.TEXT, header, tlv_data)
assert not response.get_tlv(ExecuteTlvs.STATUS.value)
class TestDistributed:
def test_switch(self, cored, distributed_address):
"""
Test creating a distributed switch network.
:param core.api.tlv.coreserver.CoreServer conftest.Core cored: core daemon server to test with
:param str distributed_address: distributed server to test against
"""
# initialize server for testing
cored.setup(distributed_address)
# create local node
message = node_message(_id=1, name="n1", model="host")
cored.request_handler.handle_message(message)
# create distributed node and assign to distributed server
message = node_message(
_id=2, name="n2", emulation_server=cored.distributed_server, model="host"
)
cored.request_handler.handle_message(message)
# create distributed switch and assign to distributed server
message = node_message(_id=3, name="n3", node_type=NodeTypes.SWITCH)
cored.request_handler.handle_message(message)
# link message one
ip4_address = cored.prefix.addr(1)
message = link_message(n1=1, n2=3, intf_one=0, address_one=ip4_address)
cored.request_handler.handle_message(message)
# link message two
ip4_address = cored.prefix.addr(2)
message = link_message(n1=3, n2=2, intf_two=0, address_two=ip4_address)
cored.request_handler.handle_message(message)
# change session to instantiation state
message = state_message(EventTypes.INSTANTIATION_STATE)
cored.request_handler.handle_message(message)
# test a ping command
node_one = cored.session.get_node(1)
message = command_message(node_one, f"ping -c 5 {ip4_address}")
cored.request_handler.dispatch_replies = validate_response
cored.request_handler.handle_message(message)
def test_emane(self, cored, distributed_address):
"""
Test creating a distributed emane network.
:param core.api.tlv.coreserver.CoreServer conftest.Core cored: core daemon server to test with
:param str distributed_address: distributed server to test against
"""
# initialize server for testing
cored.setup(distributed_address)
# configure required controlnet
cored.session.options.set_config(
"controlnet", "core1:172.16.1.0/24 core2:172.16.2.0/24"
)
# create local node
message = node_message(_id=1, name="n1", model="mdr")
cored.request_handler.handle_message(message)
# create distributed node and assign to distributed server
message = node_message(
_id=2, name="n2", emulation_server=cored.distributed_server, model="mdr"
)
cored.request_handler.handle_message(message)
# create distributed switch and assign to distributed server
message = node_message(_id=3, name="n3", node_type=NodeTypes.EMANE)
cored.request_handler.handle_message(message)
# set emane model
message = set_emane_model(3, EmaneIeee80211abgModel.name)
cored.request_handler.handle_message(message)
# link message one
ip4_address = cored.prefix.addr(1)
message = link_message(n1=1, n2=3, intf_one=0, address_one=ip4_address, mask=32)
cored.request_handler.handle_message(message)
# link message two
ip4_address = cored.prefix.addr(2)
message = link_message(n1=2, n2=3, intf_one=0, address_one=ip4_address, mask=32)
cored.request_handler.handle_message(message)
# change session to instantiation state
message = state_message(EventTypes.INSTANTIATION_STATE)
cored.request_handler.handle_message(message)
# test a ping command
node_one = cored.session.get_node(1)
message = command_message(node_one, f"ping -c 5 {ip4_address}")
cored.request_handler.dispatch_replies = validate_response
cored.request_handler.handle_message(message)
def test_prouter(self, cored, distributed_address):
"""
Test creating a distributed prouter node.
:param core.coreserver.CoreServer Core cored: core daemon server to test with
:param str distributed_address: distributed server to test against
"""
# initialize server for testing
cored.setup(distributed_address)
# create local node
message = node_message(_id=1, name="n1", model="host")
cored.request_handler.handle_message(message)
# create distributed node and assign to distributed server
message = node_message(
_id=2,
name="n2",
emulation_server=cored.distributed_server,
node_type=NodeTypes.PHYSICAL,
model="prouter",
)
cored.request_handler.handle_message(message)
# create distributed switch and assign to distributed server
message = node_message(_id=3, name="n3", node_type=NodeTypes.SWITCH)
cored.request_handler.handle_message(message)
# link message one
ip4_address = cored.prefix.addr(1)
message = link_message(n1=1, n2=3, intf_one=0, address_one=ip4_address)
cored.request_handler.handle_message(message)
# link message two
ip4_address = cored.prefix.addr(2)
message = link_message(n1=3, n2=2, intf_two=0, address_two=ip4_address)
cored.request_handler.handle_message(message)
# change session to instantiation state
message = state_message(EventTypes.INSTANTIATION_STATE)
cored.request_handler.handle_message(message)
# test a ping command
node_one = cored.session.get_node(1)
message = command_message(node_one, f"ping -c 5 {ip4_address}")
cored.request_handler.dispatch_replies = validate_response
cored.request_handler.handle_message(message)
cored.request_handler.handle_message(message)
def test_tunnel(self, cored, distributed_address):
"""
Test session broker creation.
:param core.coreserver.CoreServer Core cored: core daemon server to test with
:param str distributed_address: distributed server to test against
"""
# initialize server for testing
cored.setup(distributed_address)
# create local node
message = node_message(_id=1, name="n1", model="host")
cored.request_handler.handle_message(message)
# create distributed node and assign to distributed server
message = node_message(
_id=2,
name=distributed_address,
emulation_server=cored.distributed_server,
node_type=NodeTypes.TUNNEL,
)
cored.request_handler.handle_message(message)
# link message one
ip4_address = cored.prefix.addr(1)
address_two = IpAddress.from_string(distributed_address)
message = link_message(
n1=1,
n2=2,
intf_one=0,
address_one=ip4_address,
intf_two=0,
address_two=address_two,
key=1,
)
cored.request_handler.handle_message(message)
# change session to instantiation state
message = state_message(EventTypes.INSTANTIATION_STATE)
cored.request_handler.handle_message(message)

View file

@ -12,6 +12,7 @@ from core.emane.ieee80211abg import EmaneIeee80211abgModel
from core.emane.rfpipe import EmaneRfPipeModel from core.emane.rfpipe import EmaneRfPipeModel
from core.emane.tdma import EmaneTdmaModel from core.emane.tdma import EmaneTdmaModel
from core.emulator.emudata import NodeOptions from core.emulator.emudata import NodeOptions
from core.emulator.enumerations import NodeTypes
from core.errors import CoreCommandError, CoreError from core.errors import CoreCommandError, CoreError
_EMANE_MODELS = [ _EMANE_MODELS = [
@ -46,10 +47,11 @@ class TestEmane:
""" """
# create emane node for networking the core nodes # create emane node for networking the core nodes
emane_network = session.create_emane_network( session.set_location(47.57917, -122.13232, 2.00000, 1.0)
model, geo_reference=(47.57917, -122.13232, 2.00000) options = NodeOptions()
) options.set_position(80, 50)
emane_network.setposition(x=80, y=50) emane_network = session.add_node(_type=NodeTypes.EMANE, options=options)
session.emane.set_model(emane_network, model)
# configure tdma # configure tdma
if model == EmaneTdmaModel: if model == EmaneTdmaModel:
@ -60,11 +62,11 @@ class TestEmane:
) )
# create nodes # create nodes
node_options = NodeOptions() options = NodeOptions(model="mdr")
node_options.set_position(150, 150) options.set_position(150, 150)
node_one = session.create_wireless_node(node_options=node_options) node_one = session.add_node(options=options)
node_options.set_position(300, 150) options.set_position(300, 150)
node_two = session.create_wireless_node(node_options=node_options) node_two = session.add_node(options=options)
for i, node in enumerate([node_one, node_two]): for i, node in enumerate([node_one, node_two]):
node.setposition(x=150 * (i + 1), y=150) node.setposition(x=150 * (i + 1), y=150)
@ -87,19 +89,22 @@ class TestEmane:
:param ip_prefixes: generates ip addresses for nodes :param ip_prefixes: generates ip addresses for nodes
""" """
# create emane node for networking the core nodes # create emane node for networking the core nodes
emane_network = session.create_emane_network( session.set_location(47.57917, -122.13232, 2.00000, 1.0)
EmaneIeee80211abgModel, options = NodeOptions()
geo_reference=(47.57917, -122.13232, 2.00000), options.set_position(80, 50)
config={"test": "1"}, emane_network = session.add_node(_type=NodeTypes.EMANE, options=options)
config_key = "txpower"
config_value = "10"
session.emane.set_model(
emane_network, EmaneIeee80211abgModel, {config_key: config_value}
) )
emane_network.setposition(x=80, y=50)
# create nodes # create nodes
node_options = NodeOptions() options = NodeOptions(model="mdr")
node_options.set_position(150, 150) options.set_position(150, 150)
node_one = session.create_wireless_node(node_options=node_options) node_one = session.add_node(options=options)
node_options.set_position(300, 150) options.set_position(300, 150)
node_two = session.create_wireless_node(node_options=node_options) node_two = session.add_node(options=options)
for i, node in enumerate([node_one, node_two]): for i, node in enumerate([node_one, node_two]):
node.setposition(x=150 * (i + 1), y=150) node.setposition(x=150 * (i + 1), y=150)
@ -137,11 +142,11 @@ class TestEmane:
# retrieve configuration we set originally # retrieve configuration we set originally
value = str( value = str(
session.emane.get_config("test", emane_id, EmaneIeee80211abgModel.name) session.emane.get_config(config_key, emane_id, EmaneIeee80211abgModel.name)
) )
# verify nodes and configuration were restored # verify nodes and configuration were restored
assert session.get_node(n1_id) assert session.get_node(n1_id)
assert session.get_node(n2_id) assert session.get_node(n2_id)
assert session.get_node(emane_id) assert session.get_node(emane_id)
assert value == "1" assert value == config_value

View file

@ -20,7 +20,7 @@ _WIRED = [NodeTypes.PEER_TO_PEER, NodeTypes.HUB, NodeTypes.SWITCH]
def ping(from_node, to_node, ip_prefixes): def ping(from_node, to_node, ip_prefixes):
address = ip_prefixes.ip4_address(to_node) address = ip_prefixes.ip4_address(to_node)
try: try:
from_node.cmd(f"ping -c 3 {address}") from_node.cmd(f"ping -c 1 {address}")
status = 0 status = 0
except CoreCommandError as e: except CoreCommandError as e:
status = e.returncode status = e.returncode
@ -57,14 +57,14 @@ class TestCore:
status = ping(node_one, node_two, ip_prefixes) status = ping(node_one, node_two, ip_prefixes)
assert not status assert not status
def test_vnode_client(self, session, ip_prefixes): def test_vnode_client(self, request, session, ip_prefixes):
""" """
Test vnode client methods. Test vnode client methods.
:param request: pytest request
:param session: session for test :param session: session for test
:param ip_prefixes: generates ip addresses for nodes :param ip_prefixes: generates ip addresses for nodes
""" """
# create ptp # create ptp
ptp_node = session.add_node(_type=NodeTypes.PEER_TO_PEER) ptp_node = session.add_node(_type=NodeTypes.PEER_TO_PEER)
@ -87,7 +87,8 @@ class TestCore:
assert client.connected() assert client.connected()
# validate command # validate command
assert client.check_cmd("echo hello") == "hello" if not request.config.getoption("mock"):
assert client.check_cmd("echo hello") == "hello"
def test_netif(self, session, ip_prefixes): def test_netif(self, session, ip_prefixes):
""" """
@ -146,10 +147,10 @@ class TestCore:
session.mobility.set_model(wlan_node, BasicRangeModel) session.mobility.set_model(wlan_node, BasicRangeModel)
# create nodes # create nodes
node_options = NodeOptions() options = NodeOptions(model="mdr")
node_options.set_position(0, 0) options.set_position(0, 0)
node_one = session.create_wireless_node(node_options=node_options) node_one = session.add_node(options=options)
node_two = session.create_wireless_node(node_options=node_options) node_two = session.add_node(options=options)
# link nodes # link nodes
for node in [node_one, node_two]: for node in [node_one, node_two]:
@ -176,10 +177,10 @@ class TestCore:
session.mobility.set_model(wlan_node, BasicRangeModel) session.mobility.set_model(wlan_node, BasicRangeModel)
# create nodes # create nodes
node_options = NodeOptions() options = NodeOptions(model="mdr")
node_options.set_position(0, 0) options.set_position(0, 0)
node_one = session.create_wireless_node(node_options=node_options) node_one = session.add_node(options=options)
node_two = session.create_wireless_node(node_options=node_options) node_two = session.add_node(options=options)
# link nodes # link nodes
for node in [node_one, node_two]: for node in [node_one, node_two]:

View file

@ -0,0 +1,39 @@
from core.emulator.emudata import NodeOptions
from core.emulator.enumerations import NodeTypes
class TestDistributed:
def test_remote_node(self, session):
# given
server_name = "core2"
host = "127.0.0.1"
# when
session.distributed.add_server(server_name, host)
options = NodeOptions()
options.server = server_name
node = session.add_node(options=options)
# then
assert node.server is not None
assert node.server.name == server_name
assert node.server.host == host
def test_remote_bridge(self, session):
# given
server_name = "core2"
host = "127.0.0.1"
session.distributed.address = host
# when
session.distributed.add_server(server_name, host)
options = NodeOptions()
options.server = server_name
node = session.add_node(_type=NodeTypes.HUB, options=options)
session.instantiate()
# then
assert node.server is not None
assert node.server.name == server_name
assert node.server.host == host
assert len(session.distributed.tunnels) > 0

View file

@ -3,9 +3,10 @@ from queue import Queue
import grpc import grpc
import pytest import pytest
from mock import patch
from core.api.grpc import core_pb2 from core.api.grpc import core_pb2
from core.api.grpc.client import CoreGrpcClient from core.api.grpc.client import CoreGrpcClient, InterfaceHelper
from core.config import ConfigShim from core.config import ConfigShim
from core.emane.ieee80211abg import EmaneIeee80211abgModel from core.emane.ieee80211abg import EmaneIeee80211abgModel
from core.emulator.data import EventData from core.emulator.data import EventData
@ -18,9 +19,127 @@ from core.emulator.enumerations import (
) )
from core.errors import CoreError from core.errors import CoreError
from core.location.mobility import BasicRangeModel, Ns2ScriptedMobility from core.location.mobility import BasicRangeModel, Ns2ScriptedMobility
from core.xml.corexml import CoreXmlWriter
class TestGrpc: class TestGrpc:
def test_start_session(self, grpc_server):
# given
client = CoreGrpcClient()
session = grpc_server.coreemu.create_session()
nodes = []
position = core_pb2.Position(x=50, y=100)
node_one = core_pb2.Node(id=1, position=position, model="PC")
position = core_pb2.Position(x=100, y=100)
node_two = core_pb2.Node(id=2, position=position, model="PC")
position = core_pb2.Position(x=200, y=200)
wlan_node = core_pb2.Node(
id=3, type=NodeTypes.WIRELESS_LAN.value, position=position
)
nodes.extend([node_one, node_two, wlan_node])
links = []
interface_helper = InterfaceHelper(ip4_prefix="10.83.0.0/16")
interface_one = interface_helper.create_interface(node_one.id, 0)
interface_two = interface_helper.create_interface(node_two.id, 0)
link = core_pb2.Link(
type=core_pb2.LinkType.WIRED,
node_one_id=node_one.id,
node_two_id=node_two.id,
interface_one=interface_one,
interface_two=interface_two,
)
links.append(link)
hooks = []
hook = core_pb2.Hook(
state=core_pb2.SessionState.RUNTIME, file="echo.sh", data="echo hello"
)
hooks.append(hook)
location_x = 5
location_y = 10
location_z = 15
location_lat = 20
location_lon = 30
location_alt = 40
location_scale = 5
location = core_pb2.SessionLocation(
x=location_x,
y=location_y,
z=location_z,
lat=location_lat,
lon=location_lon,
alt=location_alt,
scale=location_scale,
)
emane_config_key = "platform_id_start"
emane_config_value = "2"
emane_config = {emane_config_key: emane_config_value}
model_configs = []
model_node_id = 20
model_config_key = "bandwidth"
model_config_value = "500000"
model_config = core_pb2.EmaneModelConfig(
node_id=model_node_id,
interface_id=-1,
model=EmaneIeee80211abgModel.name,
config={model_config_key: model_config_value},
)
model_configs.append(model_config)
wlan_configs = []
wlan_config_key = "range"
wlan_config_value = "333"
wlan_config = core_pb2.WlanConfig(
node_id=wlan_node.id, config={wlan_config_key: wlan_config_value}
)
wlan_configs.append(wlan_config)
mobility_config_key = "refresh_ms"
mobility_config_value = "60"
mobility_configs = []
mobility_config = core_pb2.MobilityConfig(
node_id=wlan_node.id, config={mobility_config_key: mobility_config_value}
)
mobility_configs.append(mobility_config)
# when
with patch.object(CoreXmlWriter, "write"):
with client.context_connect():
client.start_session(
session.id,
nodes,
links,
location,
hooks,
emane_config,
model_configs,
wlan_configs,
mobility_configs,
)
# then
assert node_one.id in session.nodes
assert node_two.id in session.nodes
assert wlan_node.id in session.nodes
assert session.nodes[node_one.id].netif(0) is not None
assert session.nodes[node_two.id].netif(0) is not None
hook_file, hook_data = session._hooks[core_pb2.SessionState.RUNTIME][0]
assert hook_file == hook.file
assert hook_data == hook.data
assert session.location.refxyz == (location_x, location_y, location_z)
assert session.location.refgeo == (location_lat, location_lon, location_alt)
assert session.location.refscale == location_scale
assert session.emane.get_config(emane_config_key) == emane_config_value
set_wlan_config = session.mobility.get_model_config(
wlan_node.id, BasicRangeModel.name
)
assert set_wlan_config[wlan_config_key] == wlan_config_value
set_mobility_config = session.mobility.get_model_config(
wlan_node.id, Ns2ScriptedMobility.name
)
assert set_mobility_config[mobility_config_key] == mobility_config_value
set_model_config = session.emane.get_model_config(
model_node_id, EmaneIeee80211abgModel.name
)
assert set_model_config[model_config_key] == model_config_value
@pytest.mark.parametrize("session_id", [None, 6013]) @pytest.mark.parametrize("session_id", [None, 6013])
def test_create_session(self, grpc_server, session_id): def test_create_session(self, grpc_server, session_id):
# given # given
@ -112,13 +231,13 @@ class TestGrpc:
response = client.get_session_location(session.id) response = client.get_session_location(session.id)
# then # then
assert response.scale == 1.0 assert response.location.scale == 1.0
assert response.position.x == 0 assert response.location.x == 0
assert response.position.y == 0 assert response.location.y == 0
assert response.position.z == 0 assert response.location.z == 0
assert response.position.lat == 0 assert response.location.lat == 0
assert response.position.lon == 0 assert response.location.lon == 0
assert response.position.alt == 0 assert response.location.alt == 0
def test_set_session_location(self, grpc_server): def test_set_session_location(self, grpc_server):
# given # given
@ -164,6 +283,36 @@ class TestGrpc:
config = session.options.get_configs() config = session.options.get_configs()
assert len(config) > 0 assert len(config) > 0
def test_set_session_metadata(self, grpc_server):
# given
client = CoreGrpcClient()
session = grpc_server.coreemu.create_session()
# then
key = "meta1"
value = "value1"
with client.context_connect():
response = client.set_session_metadata(session.id, {key: value})
# then
assert response.result is True
assert session.metadata[key] == value
def test_get_session_metadata(self, grpc_server):
# given
client = CoreGrpcClient()
session = grpc_server.coreemu.create_session()
key = "meta1"
value = "value1"
session.metadata[key] = value
# then
with client.context_connect():
response = client.get_session_metadata(session.id)
# then
assert response.config[key] == value
def test_set_session_state(self, grpc_server): def test_set_session_state(self, grpc_server):
# given # given
client = CoreGrpcClient() client = CoreGrpcClient()
@ -240,13 +389,16 @@ class TestGrpc:
with pytest.raises(CoreError): with pytest.raises(CoreError):
assert session.get_node(node.id) assert session.get_node(node.id)
def test_node_command(self, grpc_server): def test_node_command(self, request, grpc_server):
if request.config.getoption("mock"):
pytest.skip("mocking calls")
# given # given
client = CoreGrpcClient() client = CoreGrpcClient()
session = grpc_server.coreemu.create_session() session = grpc_server.coreemu.create_session()
session.set_state(EventTypes.CONFIGURATION_STATE) session.set_state(EventTypes.CONFIGURATION_STATE)
node_options = NodeOptions(model="Host") options = NodeOptions(model="Host")
node = session.add_node(node_options=node_options) node = session.add_node(options=options)
session.instantiate() session.instantiate()
output = "hello world" output = "hello world"
@ -263,8 +415,8 @@ class TestGrpc:
client = CoreGrpcClient() client = CoreGrpcClient()
session = grpc_server.coreemu.create_session() session = grpc_server.coreemu.create_session()
session.set_state(EventTypes.CONFIGURATION_STATE) session.set_state(EventTypes.CONFIGURATION_STATE)
node_options = NodeOptions(model="Host") options = NodeOptions(model="Host")
node = session.add_node(node_options=node_options) node = session.add_node(options=options)
session.instantiate() session.instantiate()
# then # then
@ -524,9 +676,9 @@ class TestGrpc:
# given # given
client = CoreGrpcClient() client = CoreGrpcClient()
session = grpc_server.coreemu.create_session() session = grpc_server.coreemu.create_session()
emane_network = session.create_emane_network( session.set_location(47.57917, -122.13232, 2.00000, 1.0)
model=EmaneIeee80211abgModel, geo_reference=(47.57917, -122.13232, 2.00000) emane_network = session.add_node(_type=NodeTypes.EMANE)
) session.emane.set_model(emane_network, EmaneIeee80211abgModel)
config_key = "platform_id_start" config_key = "platform_id_start"
config_value = "2" config_value = "2"
session.emane.set_model_config( session.emane.set_model_config(
@ -548,9 +700,9 @@ class TestGrpc:
# given # given
client = CoreGrpcClient() client = CoreGrpcClient()
session = grpc_server.coreemu.create_session() session = grpc_server.coreemu.create_session()
emane_network = session.create_emane_network( session.set_location(47.57917, -122.13232, 2.00000, 1.0)
model=EmaneIeee80211abgModel, geo_reference=(47.57917, -122.13232, 2.00000) emane_network = session.add_node(_type=NodeTypes.EMANE)
) session.emane.set_model(emane_network, EmaneIeee80211abgModel)
config_key = "bandwidth" config_key = "bandwidth"
config_value = "900000" config_value = "900000"
@ -574,9 +726,9 @@ class TestGrpc:
# given # given
client = CoreGrpcClient() client = CoreGrpcClient()
session = grpc_server.coreemu.create_session() session = grpc_server.coreemu.create_session()
emane_network = session.create_emane_network( session.set_location(47.57917, -122.13232, 2.00000, 1.0)
model=EmaneIeee80211abgModel, geo_reference=(47.57917, -122.13232, 2.00000) emane_network = session.add_node(_type=NodeTypes.EMANE)
) session.emane.set_model(emane_network, EmaneIeee80211abgModel)
# then # then
with client.context_connect(): with client.context_connect():
@ -834,7 +986,10 @@ class TestGrpc:
# then # then
queue.get(timeout=5) queue.get(timeout=5)
def test_throughputs(self, grpc_server): def test_throughputs(self, request, grpc_server):
if request.config.getoption("mock"):
pytest.skip("mocking calls")
# given # given
client = CoreGrpcClient() client = CoreGrpcClient()
grpc_server.coreemu.create_session() grpc_server.coreemu.create_session()

View file

@ -6,6 +6,7 @@ import time
import mock import mock
import pytest import pytest
from mock import MagicMock
from core.api.tlv import coreapi from core.api.tlv import coreapi
from core.emane.ieee80211abg import EmaneIeee80211abgModel from core.emane.ieee80211abg import EmaneIeee80211abgModel
@ -42,10 +43,9 @@ class TestGui:
(NodeTypes.SWITCH, None), (NodeTypes.SWITCH, None),
(NodeTypes.WIRELESS_LAN, None), (NodeTypes.WIRELESS_LAN, None),
(NodeTypes.TUNNEL, None), (NodeTypes.TUNNEL, None),
(NodeTypes.RJ45, None),
], ],
) )
def test_node_add(self, coreserver, node_type, model): def test_node_add(self, coretlv, node_type, model):
node_id = 1 node_id = 1
message = coreapi.CoreNodeMessage.create( message = coreapi.CoreNodeMessage.create(
MessageFlags.ADD.value, MessageFlags.ADD.value,
@ -59,13 +59,13 @@ class TestGui:
], ],
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
assert coreserver.session.get_node(node_id) is not None assert coretlv.session.get_node(node_id) is not None
def test_node_update(self, coreserver): def test_node_update(self, coretlv):
node_id = 1 node_id = 1
coreserver.session.add_node(_id=node_id) coretlv.session.add_node(_id=node_id)
x = 50 x = 50
y = 100 y = 100
message = coreapi.CoreNodeMessage.create( message = coreapi.CoreNodeMessage.create(
@ -77,30 +77,30 @@ class TestGui:
], ],
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
node = coreserver.session.get_node(node_id) node = coretlv.session.get_node(node_id)
assert node is not None assert node is not None
assert node.position.x == x assert node.position.x == x
assert node.position.y == y assert node.position.y == y
def test_node_delete(self, coreserver): def test_node_delete(self, coretlv):
node_id = 1 node_id = 1
coreserver.session.add_node(_id=node_id) coretlv.session.add_node(_id=node_id)
message = coreapi.CoreNodeMessage.create( message = coreapi.CoreNodeMessage.create(
MessageFlags.DELETE.value, [(NodeTlvs.NUMBER, node_id)] MessageFlags.DELETE.value, [(NodeTlvs.NUMBER, node_id)]
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
with pytest.raises(CoreError): with pytest.raises(CoreError):
coreserver.session.get_node(node_id) coretlv.session.get_node(node_id)
def test_link_add_node_to_net(self, coreserver): def test_link_add_node_to_net(self, coretlv):
node_one = 1 node_one = 1
coreserver.session.add_node(_id=node_one) coretlv.session.add_node(_id=node_one)
switch = 2 switch = 2
coreserver.session.add_node(_id=switch, _type=NodeTypes.SWITCH) coretlv.session.add_node(_id=switch, _type=NodeTypes.SWITCH)
ip_prefix = Ipv4Prefix("10.0.0.0/24") ip_prefix = Ipv4Prefix("10.0.0.0/24")
interface_one = ip_prefix.addr(node_one) interface_one = ip_prefix.addr(node_one)
message = coreapi.CoreLinkMessage.create( message = coreapi.CoreLinkMessage.create(
@ -114,17 +114,17 @@ class TestGui:
], ],
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
switch_node = coreserver.session.get_node(switch) switch_node = coretlv.session.get_node(switch)
all_links = switch_node.all_link_data(0) all_links = switch_node.all_link_data(0)
assert len(all_links) == 1 assert len(all_links) == 1
def test_link_add_net_to_node(self, coreserver): def test_link_add_net_to_node(self, coretlv):
node_one = 1 node_one = 1
coreserver.session.add_node(_id=node_one) coretlv.session.add_node(_id=node_one)
switch = 2 switch = 2
coreserver.session.add_node(_id=switch, _type=NodeTypes.SWITCH) coretlv.session.add_node(_id=switch, _type=NodeTypes.SWITCH)
ip_prefix = Ipv4Prefix("10.0.0.0/24") ip_prefix = Ipv4Prefix("10.0.0.0/24")
interface_one = ip_prefix.addr(node_one) interface_one = ip_prefix.addr(node_one)
message = coreapi.CoreLinkMessage.create( message = coreapi.CoreLinkMessage.create(
@ -138,17 +138,17 @@ class TestGui:
], ],
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
switch_node = coreserver.session.get_node(switch) switch_node = coretlv.session.get_node(switch)
all_links = switch_node.all_link_data(0) all_links = switch_node.all_link_data(0)
assert len(all_links) == 1 assert len(all_links) == 1
def test_link_add_node_to_node(self, coreserver): def test_link_add_node_to_node(self, coretlv):
node_one = 1 node_one = 1
coreserver.session.add_node(_id=node_one) coretlv.session.add_node(_id=node_one)
node_two = 2 node_two = 2
coreserver.session.add_node(_id=node_two) coretlv.session.add_node(_id=node_two)
ip_prefix = Ipv4Prefix("10.0.0.0/24") ip_prefix = Ipv4Prefix("10.0.0.0/24")
interface_one = ip_prefix.addr(node_one) interface_one = ip_prefix.addr(node_one)
interface_two = ip_prefix.addr(node_two) interface_two = ip_prefix.addr(node_two)
@ -166,19 +166,19 @@ class TestGui:
], ],
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
all_links = [] all_links = []
for node_id in coreserver.session.nodes: for node_id in coretlv.session.nodes:
node = coreserver.session.nodes[node_id] node = coretlv.session.nodes[node_id]
all_links += node.all_link_data(0) all_links += node.all_link_data(0)
assert len(all_links) == 1 assert len(all_links) == 1
def test_link_update(self, coreserver): def test_link_update(self, coretlv):
node_one = 1 node_one = 1
coreserver.session.add_node(_id=node_one) coretlv.session.add_node(_id=node_one)
switch = 2 switch = 2
coreserver.session.add_node(_id=switch, _type=NodeTypes.SWITCH) coretlv.session.add_node(_id=switch, _type=NodeTypes.SWITCH)
ip_prefix = Ipv4Prefix("10.0.0.0/24") ip_prefix = Ipv4Prefix("10.0.0.0/24")
interface_one = ip_prefix.addr(node_one) interface_one = ip_prefix.addr(node_one)
message = coreapi.CoreLinkMessage.create( message = coreapi.CoreLinkMessage.create(
@ -191,8 +191,8 @@ class TestGui:
(LinkTlvs.INTERFACE1_IP4_MASK, 24), (LinkTlvs.INTERFACE1_IP4_MASK, 24),
], ],
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
switch_node = coreserver.session.get_node(switch) switch_node = coretlv.session.get_node(switch)
all_links = switch_node.all_link_data(0) all_links = switch_node.all_link_data(0)
assert len(all_links) == 1 assert len(all_links) == 1
link = all_links[0] link = all_links[0]
@ -208,19 +208,19 @@ class TestGui:
(LinkTlvs.BANDWIDTH, bandwidth), (LinkTlvs.BANDWIDTH, bandwidth),
], ],
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
switch_node = coreserver.session.get_node(switch) switch_node = coretlv.session.get_node(switch)
all_links = switch_node.all_link_data(0) all_links = switch_node.all_link_data(0)
assert len(all_links) == 1 assert len(all_links) == 1
link = all_links[0] link = all_links[0]
assert link.bandwidth == bandwidth assert link.bandwidth == bandwidth
def test_link_delete_node_to_node(self, coreserver): def test_link_delete_node_to_node(self, coretlv):
node_one = 1 node_one = 1
coreserver.session.add_node(_id=node_one) coretlv.session.add_node(_id=node_one)
node_two = 2 node_two = 2
coreserver.session.add_node(_id=node_two) coretlv.session.add_node(_id=node_two)
ip_prefix = Ipv4Prefix("10.0.0.0/24") ip_prefix = Ipv4Prefix("10.0.0.0/24")
interface_one = ip_prefix.addr(node_one) interface_one = ip_prefix.addr(node_one)
interface_two = ip_prefix.addr(node_two) interface_two = ip_prefix.addr(node_two)
@ -236,10 +236,10 @@ class TestGui:
(LinkTlvs.INTERFACE2_IP4_MASK, 24), (LinkTlvs.INTERFACE2_IP4_MASK, 24),
], ],
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
all_links = [] all_links = []
for node_id in coreserver.session.nodes: for node_id in coretlv.session.nodes:
node = coreserver.session.nodes[node_id] node = coretlv.session.nodes[node_id]
all_links += node.all_link_data(0) all_links += node.all_link_data(0)
assert len(all_links) == 1 assert len(all_links) == 1
@ -252,19 +252,19 @@ class TestGui:
(LinkTlvs.INTERFACE2_NUMBER, 0), (LinkTlvs.INTERFACE2_NUMBER, 0),
], ],
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
all_links = [] all_links = []
for node_id in coreserver.session.nodes: for node_id in coretlv.session.nodes:
node = coreserver.session.nodes[node_id] node = coretlv.session.nodes[node_id]
all_links += node.all_link_data(0) all_links += node.all_link_data(0)
assert len(all_links) == 0 assert len(all_links) == 0
def test_link_delete_node_to_net(self, coreserver): def test_link_delete_node_to_net(self, coretlv):
node_one = 1 node_one = 1
coreserver.session.add_node(_id=node_one) coretlv.session.add_node(_id=node_one)
switch = 2 switch = 2
coreserver.session.add_node(_id=switch, _type=NodeTypes.SWITCH) coretlv.session.add_node(_id=switch, _type=NodeTypes.SWITCH)
ip_prefix = Ipv4Prefix("10.0.0.0/24") ip_prefix = Ipv4Prefix("10.0.0.0/24")
interface_one = ip_prefix.addr(node_one) interface_one = ip_prefix.addr(node_one)
message = coreapi.CoreLinkMessage.create( message = coreapi.CoreLinkMessage.create(
@ -277,8 +277,8 @@ class TestGui:
(LinkTlvs.INTERFACE1_IP4_MASK, 24), (LinkTlvs.INTERFACE1_IP4_MASK, 24),
], ],
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
switch_node = coreserver.session.get_node(switch) switch_node = coretlv.session.get_node(switch)
all_links = switch_node.all_link_data(0) all_links = switch_node.all_link_data(0)
assert len(all_links) == 1 assert len(all_links) == 1
@ -290,17 +290,17 @@ class TestGui:
(LinkTlvs.INTERFACE1_NUMBER, 0), (LinkTlvs.INTERFACE1_NUMBER, 0),
], ],
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
switch_node = coreserver.session.get_node(switch) switch_node = coretlv.session.get_node(switch)
all_links = switch_node.all_link_data(0) all_links = switch_node.all_link_data(0)
assert len(all_links) == 0 assert len(all_links) == 0
def test_link_delete_net_to_node(self, coreserver): def test_link_delete_net_to_node(self, coretlv):
node_one = 1 node_one = 1
coreserver.session.add_node(_id=node_one) coretlv.session.add_node(_id=node_one)
switch = 2 switch = 2
coreserver.session.add_node(_id=switch, _type=NodeTypes.SWITCH) coretlv.session.add_node(_id=switch, _type=NodeTypes.SWITCH)
ip_prefix = Ipv4Prefix("10.0.0.0/24") ip_prefix = Ipv4Prefix("10.0.0.0/24")
interface_one = ip_prefix.addr(node_one) interface_one = ip_prefix.addr(node_one)
message = coreapi.CoreLinkMessage.create( message = coreapi.CoreLinkMessage.create(
@ -313,8 +313,8 @@ class TestGui:
(LinkTlvs.INTERFACE1_IP4_MASK, 24), (LinkTlvs.INTERFACE1_IP4_MASK, 24),
], ],
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
switch_node = coreserver.session.get_node(switch) switch_node = coretlv.session.get_node(switch)
all_links = switch_node.all_link_data(0) all_links = switch_node.all_link_data(0)
assert len(all_links) == 1 assert len(all_links) == 1
@ -326,58 +326,58 @@ class TestGui:
(LinkTlvs.INTERFACE2_NUMBER, 0), (LinkTlvs.INTERFACE2_NUMBER, 0),
], ],
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
switch_node = coreserver.session.get_node(switch) switch_node = coretlv.session.get_node(switch)
all_links = switch_node.all_link_data(0) all_links = switch_node.all_link_data(0)
assert len(all_links) == 0 assert len(all_links) == 0
def test_session_update(self, coreserver): def test_session_update(self, coretlv):
session_id = coreserver.session.id session_id = coretlv.session.id
name = "test" name = "test"
message = coreapi.CoreSessionMessage.create( message = coreapi.CoreSessionMessage.create(
0, [(SessionTlvs.NUMBER, str(session_id)), (SessionTlvs.NAME, name)] 0, [(SessionTlvs.NUMBER, str(session_id)), (SessionTlvs.NAME, name)]
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
assert coreserver.session.name == name assert coretlv.session.name == name
def test_session_query(self, coreserver): def test_session_query(self, coretlv):
coreserver.request_handler.dispatch_replies = mock.MagicMock() coretlv.dispatch_replies = mock.MagicMock()
message = coreapi.CoreSessionMessage.create(MessageFlags.STRING.value, []) message = coreapi.CoreSessionMessage.create(MessageFlags.STRING.value, [])
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
args, _ = coreserver.request_handler.dispatch_replies.call_args args, _ = coretlv.dispatch_replies.call_args
replies = args[0] replies = args[0]
assert len(replies) == 1 assert len(replies) == 1
def test_session_join(self, coreserver): def test_session_join(self, coretlv):
coreserver.request_handler.dispatch_replies = mock.MagicMock() coretlv.dispatch_replies = mock.MagicMock()
session_id = coreserver.session.id session_id = coretlv.session.id
message = coreapi.CoreSessionMessage.create( message = coreapi.CoreSessionMessage.create(
MessageFlags.ADD.value, [(SessionTlvs.NUMBER, str(session_id))] MessageFlags.ADD.value, [(SessionTlvs.NUMBER, str(session_id))]
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
assert coreserver.request_handler.session.id == session_id assert coretlv.session.id == session_id
def test_session_delete(self, coreserver): def test_session_delete(self, coretlv):
assert len(coreserver.server.coreemu.sessions) == 1 assert len(coretlv.coreemu.sessions) == 1
session_id = coreserver.session.id session_id = coretlv.session.id
message = coreapi.CoreSessionMessage.create( message = coreapi.CoreSessionMessage.create(
MessageFlags.DELETE.value, [(SessionTlvs.NUMBER, str(session_id))] MessageFlags.DELETE.value, [(SessionTlvs.NUMBER, str(session_id))]
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
assert len(coreserver.server.coreemu.sessions) == 0 assert len(coretlv.coreemu.sessions) == 0
def test_file_hook_add(self, coreserver): def test_file_hook_add(self, coretlv):
state = EventTypes.DATACOLLECT_STATE.value state = EventTypes.DATACOLLECT_STATE.value
assert coreserver.session._hooks.get(state) is None assert coretlv.session._hooks.get(state) is None
file_name = "test.sh" file_name = "test.sh"
file_data = "echo hello" file_data = "echo hello"
message = coreapi.CoreFileMessage.create( message = coreapi.CoreFileMessage.create(
@ -389,16 +389,16 @@ class TestGui:
], ],
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
hooks = coreserver.session._hooks.get(state) hooks = coretlv.session._hooks.get(state)
assert len(hooks) == 1 assert len(hooks) == 1
name, data = hooks[0] name, data = hooks[0]
assert file_name == name assert file_name == name
assert file_data == data assert file_data == data
def test_file_service_file_set(self, coreserver): def test_file_service_file_set(self, coretlv):
node = coreserver.session.add_node() node = coretlv.session.add_node()
service = "DefaultRoute" service = "DefaultRoute"
file_name = "defaultroute.sh" file_name = "defaultroute.sh"
file_data = "echo hello" file_data = "echo hello"
@ -412,16 +412,16 @@ class TestGui:
], ],
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
service_file = coreserver.session.services.get_service_file( service_file = coretlv.session.services.get_service_file(
node, service, file_name node, service, file_name
) )
assert file_data == service_file.data assert file_data == service_file.data
def test_file_node_file_copy(self, coreserver): def test_file_node_file_copy(self, request, coretlv):
file_name = "/var/log/test/node.log" file_name = "/var/log/test/node.log"
node = coreserver.session.add_node() node = coretlv.session.add_node()
node.makenodedir() node.makenodedir()
file_data = "echo hello" file_data = "echo hello"
message = coreapi.CoreFileMessage.create( message = coreapi.CoreFileMessage.create(
@ -433,17 +433,17 @@ class TestGui:
], ],
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
directory, basename = os.path.split(file_name) if not request.config.getoption("mock"):
created_directory = directory[1:].replace("/", ".") directory, basename = os.path.split(file_name)
create_path = os.path.join(node.nodedir, created_directory, basename) created_directory = directory[1:].replace("/", ".")
assert os.path.exists(create_path) create_path = os.path.join(node.nodedir, created_directory, basename)
assert os.path.exists(create_path)
def test_exec_node_tty(self, coreserver): def test_exec_node_tty(self, coretlv):
coreserver.request_handler.dispatch_replies = mock.MagicMock() coretlv.dispatch_replies = mock.MagicMock()
node = coreserver.session.add_node() node = coretlv.session.add_node()
node.startup()
message = coreapi.CoreExecMessage.create( message = coreapi.CoreExecMessage.create(
MessageFlags.TTY.value, MessageFlags.TTY.value,
[ [
@ -453,49 +453,51 @@ class TestGui:
], ],
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
args, _ = coreserver.request_handler.dispatch_replies.call_args args, _ = coretlv.dispatch_replies.call_args
replies = args[0] replies = args[0]
assert len(replies) == 1 assert len(replies) == 1
def test_exec_local_command(self, coreserver): def test_exec_local_command(self, request, coretlv):
coreserver.request_handler.dispatch_replies = mock.MagicMock() if request.config.getoption("mock"):
node = coreserver.session.add_node() pytest.skip("mocking calls")
node.startup()
coretlv.dispatch_replies = mock.MagicMock()
node = coretlv.session.add_node()
cmd = "echo hello"
message = coreapi.CoreExecMessage.create( message = coreapi.CoreExecMessage.create(
MessageFlags.TEXT.value | MessageFlags.LOCAL.value, MessageFlags.TEXT.value | MessageFlags.LOCAL.value,
[ [
(ExecuteTlvs.NODE, node.id), (ExecuteTlvs.NODE, node.id),
(ExecuteTlvs.NUMBER, 1), (ExecuteTlvs.NUMBER, 1),
(ExecuteTlvs.COMMAND, "echo hello"), (ExecuteTlvs.COMMAND, cmd),
], ],
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
args, _ = coreserver.request_handler.dispatch_replies.call_args args, _ = coretlv.dispatch_replies.call_args
replies = args[0] replies = args[0]
assert len(replies) == 1 assert len(replies) == 1
def test_exec_node_command(self, coreserver): def test_exec_node_command(self, coretlv):
coreserver.request_handler.dispatch_replies = mock.MagicMock() coretlv.dispatch_replies = mock.MagicMock()
node = coreserver.session.add_node() node = coretlv.session.add_node()
node.startup() cmd = "echo hello"
message = coreapi.CoreExecMessage.create( message = coreapi.CoreExecMessage.create(
MessageFlags.TEXT.value, MessageFlags.TEXT.value,
[ [
(ExecuteTlvs.NODE, node.id), (ExecuteTlvs.NODE, node.id),
(ExecuteTlvs.NUMBER, 1), (ExecuteTlvs.NUMBER, 1),
(ExecuteTlvs.COMMAND, "echo hello"), (ExecuteTlvs.COMMAND, cmd),
], ],
) )
node.cmd = MagicMock(return_value="hello")
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
args, _ = coreserver.request_handler.dispatch_replies.call_args node.cmd.assert_called_with(cmd)
replies = args[0]
assert len(replies) == 1
@pytest.mark.parametrize( @pytest.mark.parametrize(
"state", "state",
@ -507,16 +509,16 @@ class TestGui:
EventTypes.DEFINITION_STATE, EventTypes.DEFINITION_STATE,
], ],
) )
def test_event_state(self, coreserver, state): def test_event_state(self, coretlv, state):
message = coreapi.CoreEventMessage.create(0, [(EventTlvs.TYPE, state.value)]) message = coreapi.CoreEventMessage.create(0, [(EventTlvs.TYPE, state.value)])
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
assert coreserver.session.state == state.value assert coretlv.session.state == state.value
def test_event_schedule(self, coreserver): def test_event_schedule(self, coretlv):
coreserver.session.add_event = mock.MagicMock() coretlv.session.add_event = mock.MagicMock()
node = coreserver.session.add_node() node = coretlv.session.add_node()
message = coreapi.CoreEventMessage.create( message = coreapi.CoreEventMessage.create(
MessageFlags.ADD.value, MessageFlags.ADD.value,
[ [
@ -528,37 +530,37 @@ class TestGui:
], ],
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
coreserver.session.add_event.assert_called_once() coretlv.session.add_event.assert_called_once()
def test_event_save_xml(self, coreserver, tmpdir): def test_event_save_xml(self, coretlv, tmpdir):
xml_file = tmpdir.join("session.xml") xml_file = tmpdir.join("coretlv.session.xml")
file_path = xml_file.strpath file_path = xml_file.strpath
coreserver.session.add_node() coretlv.session.add_node()
message = coreapi.CoreEventMessage.create( message = coreapi.CoreEventMessage.create(
0, 0,
[(EventTlvs.TYPE, EventTypes.FILE_SAVE.value), (EventTlvs.NAME, file_path)], [(EventTlvs.TYPE, EventTypes.FILE_SAVE.value), (EventTlvs.NAME, file_path)],
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
assert os.path.exists(file_path) assert os.path.exists(file_path)
def test_event_open_xml(self, coreserver, tmpdir): def test_event_open_xml(self, coretlv, tmpdir):
xml_file = tmpdir.join("session.xml") xml_file = tmpdir.join("coretlv.session.xml")
file_path = xml_file.strpath file_path = xml_file.strpath
node = coreserver.session.add_node() node = coretlv.session.add_node()
coreserver.session.save_xml(file_path) coretlv.session.save_xml(file_path)
coreserver.session.delete_node(node.id) coretlv.session.delete_node(node.id)
message = coreapi.CoreEventMessage.create( message = coreapi.CoreEventMessage.create(
0, 0,
[(EventTlvs.TYPE, EventTypes.FILE_OPEN.value), (EventTlvs.NAME, file_path)], [(EventTlvs.TYPE, EventTypes.FILE_OPEN.value), (EventTlvs.NAME, file_path)],
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
assert coreserver.session.get_node(node.id) assert coretlv.session.get_node(node.id)
@pytest.mark.parametrize( @pytest.mark.parametrize(
"state", "state",
@ -570,10 +572,9 @@ class TestGui:
EventTypes.RECONFIGURE, EventTypes.RECONFIGURE,
], ],
) )
def test_event_service(self, coreserver, state): def test_event_service(self, coretlv, state):
coreserver.session.broadcast_event = mock.MagicMock() coretlv.session.broadcast_event = mock.MagicMock()
node = coreserver.session.add_node() node = coretlv.session.add_node()
node.startup()
message = coreapi.CoreEventMessage.create( message = coreapi.CoreEventMessage.create(
0, 0,
[ [
@ -583,9 +584,9 @@ class TestGui:
], ],
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
coreserver.session.broadcast_event.assert_called_once() coretlv.session.broadcast_event.assert_called_once()
@pytest.mark.parametrize( @pytest.mark.parametrize(
"state", "state",
@ -597,69 +598,60 @@ class TestGui:
EventTypes.RECONFIGURE, EventTypes.RECONFIGURE,
], ],
) )
def test_event_mobility(self, coreserver, state): def test_event_mobility(self, coretlv, state):
message = coreapi.CoreEventMessage.create( message = coreapi.CoreEventMessage.create(
0, [(EventTlvs.TYPE, state.value), (EventTlvs.NAME, "mobility:ns2script")] 0, [(EventTlvs.TYPE, state.value), (EventTlvs.NAME, "mobility:ns2script")]
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
def test_register_gui(self, coreserver): def test_register_gui(self, coretlv):
coreserver.request_handler.master = False
message = coreapi.CoreRegMessage.create(0, [(RegisterTlvs.GUI, "gui")]) message = coreapi.CoreRegMessage.create(0, [(RegisterTlvs.GUI, "gui")])
coretlv.handle_message(message)
coreserver.request_handler.handle_message(message) def test_register_xml(self, coretlv, tmpdir):
xml_file = tmpdir.join("coretlv.session.xml")
assert coreserver.request_handler.master is True
def test_register_xml(self, coreserver, tmpdir):
xml_file = tmpdir.join("session.xml")
file_path = xml_file.strpath file_path = xml_file.strpath
node = coreserver.session.add_node() node = coretlv.session.add_node()
coreserver.session.save_xml(file_path) coretlv.session.save_xml(file_path)
coreserver.session.delete_node(node.id) coretlv.session.delete_node(node.id)
message = coreapi.CoreRegMessage.create( message = coreapi.CoreRegMessage.create(
0, [(RegisterTlvs.EXECUTE_SERVER, file_path)] 0, [(RegisterTlvs.EXECUTE_SERVER, file_path)]
) )
coreserver.session.instantiate() coretlv.session.instantiate()
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
assert coreserver.server.coreemu.sessions[2].get_node(node.id) assert coretlv.coreemu.sessions[1].get_node(node.id)
def test_register_python(self, coreserver, tmpdir): def test_register_python(self, coretlv, tmpdir):
xml_file = tmpdir.join("test.py") xml_file = tmpdir.join("test.py")
file_path = xml_file.strpath file_path = xml_file.strpath
with open(file_path, "w") as f: with open(file_path, "w") as f:
f.write("coreemu = globals()['coreemu']\n") f.write("coreemu = globals()['coreemu']\n")
f.write("session = coreemu.sessions[1]\n") f.write(f"session = coreemu.sessions[{coretlv.session.id}]\n")
f.write("session.add_node()\n") f.write("session.add_node()\n")
message = coreapi.CoreRegMessage.create( message = coreapi.CoreRegMessage.create(
0, [(RegisterTlvs.EXECUTE_SERVER, file_path)] 0, [(RegisterTlvs.EXECUTE_SERVER, file_path)]
) )
coreserver.session.instantiate() coretlv.session.instantiate()
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
assert len(coreserver.session.nodes) == 1 assert len(coretlv.session.nodes) == 1
def test_config_all(self, coreserver): def test_config_all(self, coretlv):
node = coreserver.session.add_node()
message = coreapi.CoreConfMessage.create( message = coreapi.CoreConfMessage.create(
MessageFlags.ADD.value, MessageFlags.ADD.value,
[ [(ConfigTlvs.OBJECT, "all"), (ConfigTlvs.TYPE, ConfigFlags.RESET.value)],
(ConfigTlvs.OBJECT, "all"),
(ConfigTlvs.NODE, node.id),
(ConfigTlvs.TYPE, ConfigFlags.RESET.value),
],
) )
coreserver.session.location.reset = mock.MagicMock() coretlv.session.location.refxyz = (10, 10, 10)
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
coreserver.session.location.reset.assert_called_once() assert coretlv.session.location.refxyz == (0, 0, 0)
def test_config_options_request(self, coreserver): def test_config_options_request(self, coretlv):
message = coreapi.CoreConfMessage.create( message = coreapi.CoreConfMessage.create(
0, 0,
[ [
@ -667,13 +659,13 @@ class TestGui:
(ConfigTlvs.TYPE, ConfigFlags.REQUEST.value), (ConfigTlvs.TYPE, ConfigFlags.REQUEST.value),
], ],
) )
coreserver.request_handler.handle_broadcast_config = mock.MagicMock() coretlv.handle_broadcast_config = mock.MagicMock()
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
coreserver.request_handler.handle_broadcast_config.assert_called_once() coretlv.handle_broadcast_config.assert_called_once()
def test_config_options_update(self, coreserver): def test_config_options_update(self, coretlv):
test_key = "test" test_key = "test"
test_value = "test" test_value = "test"
values = {test_key: test_value} values = {test_key: test_value}
@ -686,11 +678,11 @@ class TestGui:
], ],
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
assert coreserver.session.options.get_config(test_key) == test_value assert coretlv.session.options.get_config(test_key) == test_value
def test_config_location_reset(self, coreserver): def test_config_location_reset(self, coretlv):
message = coreapi.CoreConfMessage.create( message = coreapi.CoreConfMessage.create(
0, 0,
[ [
@ -698,13 +690,13 @@ class TestGui:
(ConfigTlvs.TYPE, ConfigFlags.RESET.value), (ConfigTlvs.TYPE, ConfigFlags.RESET.value),
], ],
) )
coreserver.session.location.refxyz = (10, 10, 10) coretlv.session.location.refxyz = (10, 10, 10)
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
assert coreserver.session.location.refxyz == (0, 0, 0) assert coretlv.session.location.refxyz == (0, 0, 0)
def test_config_location_update(self, coreserver): def test_config_location_update(self, coretlv):
message = coreapi.CoreConfMessage.create( message = coreapi.CoreConfMessage.create(
0, 0,
[ [
@ -714,13 +706,13 @@ class TestGui:
], ],
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
assert coreserver.session.location.refxyz == (10, 10, 0.0) assert coretlv.session.location.refxyz == (10, 10, 0.0)
assert coreserver.session.location.refgeo == (70, 50, 0) assert coretlv.session.location.refgeo == (70, 50, 0)
assert coreserver.session.location.refscale == 0.5 assert coretlv.session.location.refscale == 0.5
def test_config_metadata_request(self, coreserver): def test_config_metadata_request(self, coretlv):
message = coreapi.CoreConfMessage.create( message = coreapi.CoreConfMessage.create(
0, 0,
[ [
@ -728,13 +720,13 @@ class TestGui:
(ConfigTlvs.TYPE, ConfigFlags.REQUEST.value), (ConfigTlvs.TYPE, ConfigFlags.REQUEST.value),
], ],
) )
coreserver.request_handler.handle_broadcast_config = mock.MagicMock() coretlv.handle_broadcast_config = mock.MagicMock()
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
coreserver.request_handler.handle_broadcast_config.assert_called_once() coretlv.handle_broadcast_config.assert_called_once()
def test_config_metadata_update(self, coreserver): def test_config_metadata_update(self, coretlv):
test_key = "test" test_key = "test"
test_value = "test" test_value = "test"
values = {test_key: test_value} values = {test_key: test_value}
@ -747,11 +739,11 @@ class TestGui:
], ],
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
assert coreserver.session.metadata.get_config(test_key) == test_value assert coretlv.session.metadata[test_key] == test_value
def test_config_broker_request(self, coreserver): def test_config_broker_request(self, coretlv):
server = "test" server = "test"
host = "10.0.0.1" host = "10.0.0.1"
port = 50000 port = 50000
@ -763,13 +755,13 @@ class TestGui:
(ConfigTlvs.VALUES, f"{server}:{host}:{port}"), (ConfigTlvs.VALUES, f"{server}:{host}:{port}"),
], ],
) )
coreserver.session.distributed.add_server = mock.MagicMock() coretlv.session.distributed.add_server = mock.MagicMock()
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
coreserver.session.distributed.add_server.assert_called_once_with(server, host) coretlv.session.distributed.add_server.assert_called_once_with(server, host)
def test_config_services_request_all(self, coreserver): def test_config_services_request_all(self, coretlv):
message = coreapi.CoreConfMessage.create( message = coreapi.CoreConfMessage.create(
0, 0,
[ [
@ -777,14 +769,14 @@ class TestGui:
(ConfigTlvs.TYPE, ConfigFlags.REQUEST.value), (ConfigTlvs.TYPE, ConfigFlags.REQUEST.value),
], ],
) )
coreserver.request_handler.handle_broadcast_config = mock.MagicMock() coretlv.handle_broadcast_config = mock.MagicMock()
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
coreserver.request_handler.handle_broadcast_config.assert_called_once() coretlv.handle_broadcast_config.assert_called_once()
def test_config_services_request_specific(self, coreserver): def test_config_services_request_specific(self, coretlv):
node = coreserver.session.add_node() node = coretlv.session.add_node()
message = coreapi.CoreConfMessage.create( message = coreapi.CoreConfMessage.create(
0, 0,
[ [
@ -794,14 +786,14 @@ class TestGui:
(ConfigTlvs.OPAQUE, "service:DefaultRoute"), (ConfigTlvs.OPAQUE, "service:DefaultRoute"),
], ],
) )
coreserver.request_handler.handle_broadcast_config = mock.MagicMock() coretlv.handle_broadcast_config = mock.MagicMock()
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
coreserver.request_handler.handle_broadcast_config.assert_called_once() coretlv.handle_broadcast_config.assert_called_once()
def test_config_services_request_specific_file(self, coreserver): def test_config_services_request_specific_file(self, coretlv):
node = coreserver.session.add_node() node = coretlv.session.add_node()
message = coreapi.CoreConfMessage.create( message = coreapi.CoreConfMessage.create(
0, 0,
[ [
@ -811,16 +803,16 @@ class TestGui:
(ConfigTlvs.OPAQUE, "service:DefaultRoute:defaultroute.sh"), (ConfigTlvs.OPAQUE, "service:DefaultRoute:defaultroute.sh"),
], ],
) )
coreserver.session.broadcast_file = mock.MagicMock() coretlv.session.broadcast_file = mock.MagicMock()
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
coreserver.session.broadcast_file.assert_called_once() coretlv.session.broadcast_file.assert_called_once()
def test_config_services_reset(self, coreserver): def test_config_services_reset(self, coretlv):
node = coreserver.session.add_node() node = coretlv.session.add_node()
service = "DefaultRoute" service = "DefaultRoute"
coreserver.session.services.set_service(node.id, service) coretlv.session.services.set_service(node.id, service)
message = coreapi.CoreConfMessage.create( message = coreapi.CoreConfMessage.create(
0, 0,
[ [
@ -828,14 +820,14 @@ class TestGui:
(ConfigTlvs.TYPE, ConfigFlags.RESET.value), (ConfigTlvs.TYPE, ConfigFlags.RESET.value),
], ],
) )
assert coreserver.session.services.get_service(node.id, service) is not None assert coretlv.session.services.get_service(node.id, service) is not None
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
assert coreserver.session.services.get_service(node.id, service) is None assert coretlv.session.services.get_service(node.id, service) is None
def test_config_services_set(self, coreserver): def test_config_services_set(self, coretlv):
node = coreserver.session.add_node() node = coretlv.session.add_node()
service = "DefaultRoute" service = "DefaultRoute"
values = {"meta": "metadata"} values = {"meta": "metadata"}
message = coreapi.CoreConfMessage.create( message = coreapi.CoreConfMessage.create(
@ -848,14 +840,14 @@ class TestGui:
(ConfigTlvs.VALUES, dict_to_str(values)), (ConfigTlvs.VALUES, dict_to_str(values)),
], ],
) )
assert coreserver.session.services.get_service(node.id, service) is None assert coretlv.session.services.get_service(node.id, service) is None
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
assert coreserver.session.services.get_service(node.id, service) is not None assert coretlv.session.services.get_service(node.id, service) is not None
def test_config_mobility_reset(self, coreserver): def test_config_mobility_reset(self, coretlv):
wlan = coreserver.session.add_node(_type=NodeTypes.WIRELESS_LAN) wlan = coretlv.session.add_node(_type=NodeTypes.WIRELESS_LAN)
message = coreapi.CoreConfMessage.create( message = coreapi.CoreConfMessage.create(
0, 0,
[ [
@ -863,15 +855,15 @@ class TestGui:
(ConfigTlvs.TYPE, ConfigFlags.RESET.value), (ConfigTlvs.TYPE, ConfigFlags.RESET.value),
], ],
) )
coreserver.session.mobility.set_model_config(wlan.id, BasicRangeModel.name, {}) coretlv.session.mobility.set_model_config(wlan.id, BasicRangeModel.name, {})
assert len(coreserver.session.mobility.node_configurations) == 1 assert len(coretlv.session.mobility.node_configurations) == 1
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
assert len(coreserver.session.mobility.node_configurations) == 0 assert len(coretlv.session.mobility.node_configurations) == 0
def test_config_mobility_model_request(self, coreserver): def test_config_mobility_model_request(self, coretlv):
wlan = coreserver.session.add_node(_type=NodeTypes.WIRELESS_LAN) wlan = coretlv.session.add_node(_type=NodeTypes.WIRELESS_LAN)
message = coreapi.CoreConfMessage.create( message = coreapi.CoreConfMessage.create(
0, 0,
[ [
@ -880,14 +872,14 @@ class TestGui:
(ConfigTlvs.TYPE, ConfigFlags.REQUEST.value), (ConfigTlvs.TYPE, ConfigFlags.REQUEST.value),
], ],
) )
coreserver.request_handler.handle_broadcast_config = mock.MagicMock() coretlv.handle_broadcast_config = mock.MagicMock()
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
coreserver.request_handler.handle_broadcast_config.assert_called_once() coretlv.handle_broadcast_config.assert_called_once()
def test_config_mobility_model_update(self, coreserver): def test_config_mobility_model_update(self, coretlv):
wlan = coreserver.session.add_node(_type=NodeTypes.WIRELESS_LAN) wlan = coretlv.session.add_node(_type=NodeTypes.WIRELESS_LAN)
config_key = "range" config_key = "range"
config_value = "1000" config_value = "1000"
values = {config_key: config_value} values = {config_key: config_value}
@ -901,15 +893,15 @@ class TestGui:
], ],
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
config = coreserver.session.mobility.get_model_config( config = coretlv.session.mobility.get_model_config(
wlan.id, BasicRangeModel.name wlan.id, BasicRangeModel.name
) )
assert config[config_key] == config_value assert config[config_key] == config_value
def test_config_emane_model_request(self, coreserver): def test_config_emane_model_request(self, coretlv):
wlan = coreserver.session.add_node(_type=NodeTypes.WIRELESS_LAN) wlan = coretlv.session.add_node(_type=NodeTypes.WIRELESS_LAN)
message = coreapi.CoreConfMessage.create( message = coreapi.CoreConfMessage.create(
0, 0,
[ [
@ -918,14 +910,14 @@ class TestGui:
(ConfigTlvs.TYPE, ConfigFlags.REQUEST.value), (ConfigTlvs.TYPE, ConfigFlags.REQUEST.value),
], ],
) )
coreserver.request_handler.handle_broadcast_config = mock.MagicMock() coretlv.handle_broadcast_config = mock.MagicMock()
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
coreserver.request_handler.handle_broadcast_config.assert_called_once() coretlv.handle_broadcast_config.assert_called_once()
def test_config_emane_model_update(self, coreserver): def test_config_emane_model_update(self, coretlv):
wlan = coreserver.session.add_node(_type=NodeTypes.WIRELESS_LAN) wlan = coretlv.session.add_node(_type=NodeTypes.WIRELESS_LAN)
config_key = "distance" config_key = "distance"
config_value = "50051" config_value = "50051"
values = {config_key: config_value} values = {config_key: config_value}
@ -939,14 +931,14 @@ class TestGui:
], ],
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
config = coreserver.session.emane.get_model_config( config = coretlv.session.emane.get_model_config(
wlan.id, EmaneIeee80211abgModel.name wlan.id, EmaneIeee80211abgModel.name
) )
assert config[config_key] == config_value assert config[config_key] == config_value
def test_config_emane_request(self, coreserver): def test_config_emane_request(self, coretlv):
message = coreapi.CoreConfMessage.create( message = coreapi.CoreConfMessage.create(
0, 0,
[ [
@ -954,13 +946,13 @@ class TestGui:
(ConfigTlvs.TYPE, ConfigFlags.REQUEST.value), (ConfigTlvs.TYPE, ConfigFlags.REQUEST.value),
], ],
) )
coreserver.request_handler.handle_broadcast_config = mock.MagicMock() coretlv.handle_broadcast_config = mock.MagicMock()
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
coreserver.request_handler.handle_broadcast_config.assert_called_once() coretlv.handle_broadcast_config.assert_called_once()
def test_config_emane_update(self, coreserver): def test_config_emane_update(self, coretlv):
config_key = "eventservicedevice" config_key = "eventservicedevice"
config_value = "eth4" config_value = "eth4"
values = {config_key: config_value} values = {config_key: config_value}
@ -973,7 +965,7 @@ class TestGui:
], ],
) )
coreserver.request_handler.handle_message(message) coretlv.handle_message(message)
config = coreserver.session.emane.get_configs() config = coretlv.session.emane.get_configs()
assert config[config_key] == config_value assert config[config_key] == config_value

View file

@ -1,15 +1,10 @@
import os
import time
import pytest import pytest
from core import utils
from core.emulator.emudata import NodeOptions from core.emulator.emudata import NodeOptions
from core.emulator.enumerations import NodeTypes from core.emulator.enumerations import NodeTypes
from core.errors import CoreError from core.errors import CoreError
MODELS = ["router", "host", "PC", "mdr"] MODELS = ["router", "host", "PC", "mdr"]
NET_TYPES = [NodeTypes.SWITCH, NodeTypes.HUB, NodeTypes.WIRELESS_LAN] NET_TYPES = [NodeTypes.SWITCH, NodeTypes.HUB, NodeTypes.WIRELESS_LAN]
@ -17,20 +12,15 @@ class TestNodes:
@pytest.mark.parametrize("model", MODELS) @pytest.mark.parametrize("model", MODELS)
def test_node_add(self, session, model): def test_node_add(self, session, model):
# given # given
node_options = NodeOptions(model=model) options = NodeOptions(model=model)
# when # when
node = session.add_node(node_options=node_options) node = session.add_node(options=options)
# give time for node services to boot
time.sleep(1)
# then # then
assert node assert node
assert os.path.exists(node.nodedir)
assert node.alive() assert node.alive()
assert node.up assert node.up
assert node.cmd("ip address show lo")
def test_node_update(self, session): def test_node_update(self, session):
# given # given
@ -40,7 +30,7 @@ class TestNodes:
update_options.set_position(x=position_value, y=position_value) update_options.set_position(x=position_value, y=position_value)
# when # when
session.update_node(node.id, update_options) session.edit_node(node.id, update_options)
# then # then
assert node.position.x == position_value assert node.position.x == position_value
@ -67,4 +57,3 @@ class TestNodes:
# then # then
assert node assert node
assert node.up assert node.up
assert utils.cmd(f"brctl show {node.brname}")

View file

@ -1,7 +1,9 @@
import os import os
import pytest import pytest
from mock import MagicMock
from core.errors import CoreCommandError
from core.services.coreservices import CoreService, ServiceDependencies, ServiceManager from core.services.coreservices import CoreService, ServiceDependencies, ServiceManager
_PATH = os.path.abspath(os.path.dirname(__file__)) _PATH = os.path.abspath(os.path.dirname(__file__))
@ -88,7 +90,7 @@ class TestServices:
assert node.services assert node.services
assert len(node.services) == total_service + 2 assert len(node.services) == total_service + 2
def test_service_file(self, session): def test_service_file(self, request, session):
# given # given
ServiceManager.add_services(_SERVICES_PATH) ServiceManager.add_services(_SERVICES_PATH)
my_service = ServiceManager.get(SERVICE_ONE) my_service = ServiceManager.get(SERVICE_ONE)
@ -100,7 +102,8 @@ class TestServices:
session.services.create_service_files(node, my_service) session.services.create_service_files(node, my_service)
# then # then
assert os.path.exists(file_path) if not request.config.getoption("mock"):
assert os.path.exists(file_path)
def test_service_validate(self, session): def test_service_validate(self, session):
# given # given
@ -121,6 +124,7 @@ class TestServices:
my_service = ServiceManager.get(SERVICE_TWO) my_service = ServiceManager.get(SERVICE_TWO)
node = session.add_node() node = session.add_node()
session.services.create_service_files(node, my_service) session.services.create_service_files(node, my_service)
node.cmd = MagicMock(side_effect=CoreCommandError(-1, "invalid"))
# when # when
status = session.services.validate_service(node, my_service) status = session.services.validate_service(node, my_service)
@ -147,6 +151,7 @@ class TestServices:
my_service = ServiceManager.get(SERVICE_TWO) my_service = ServiceManager.get(SERVICE_TWO)
node = session.add_node() node = session.add_node()
session.services.create_service_files(node, my_service) session.services.create_service_files(node, my_service)
node.cmd = MagicMock(side_effect=CoreCommandError(-1, "invalid"))
# when # when
status = session.services.startup_service(node, my_service, wait=True) status = session.services.startup_service(node, my_service, wait=True)
@ -173,6 +178,7 @@ class TestServices:
my_service = ServiceManager.get(SERVICE_TWO) my_service = ServiceManager.get(SERVICE_TWO)
node = session.add_node() node = session.add_node()
session.services.create_service_files(node, my_service) session.services.create_service_files(node, my_service)
node.cmd = MagicMock(side_effect=CoreCommandError(-1, "invalid"))
# when # when
status = session.services.stop_service(node, my_service) status = session.services.stop_service(node, my_service)
@ -216,17 +222,6 @@ class TestServices:
custom_service_two = session.services.get_service(node_two.id, my_service.name) custom_service_two = session.services.get_service(node_two.id, my_service.name)
session.services.create_service_files(node_two, custom_service_two) session.services.create_service_files(node_two, custom_service_two)
# then
file_path_one = node_one.hostfilename(file_name)
assert os.path.exists(file_path_one)
with open(file_path_one, "r") as custom_file:
assert custom_file.read() == file_data_one
file_path_two = node_two.hostfilename(file_name)
assert os.path.exists(file_path_two)
with open(file_path_two, "r") as custom_file:
assert custom_file.read() == file_data_two
def test_service_import(self): def test_service_import(self):
""" """
Test importing a custom service. Test importing a custom service.

View file

@ -108,8 +108,8 @@ class TestXml:
ptp_node = session.add_node(_type=NodeTypes.PEER_TO_PEER) ptp_node = session.add_node(_type=NodeTypes.PEER_TO_PEER)
# create nodes # create nodes
node_options = NodeOptions(model="host") options = NodeOptions(model="host")
node_one = session.add_node(node_options=node_options) node_one = session.add_node(options=options)
node_two = session.add_node() node_two = session.add_node()
# link nodes to ptp net # link nodes to ptp net
@ -174,10 +174,10 @@ class TestXml:
session.mobility.set_model(wlan_node, BasicRangeModel, {"test": "1"}) session.mobility.set_model(wlan_node, BasicRangeModel, {"test": "1"})
# create nodes # create nodes
node_options = NodeOptions() options = NodeOptions(model="mdr")
node_options.set_position(0, 0) options.set_position(0, 0)
node_one = session.create_wireless_node(node_options=node_options) node_one = session.add_node(options=options)
node_two = session.create_wireless_node(node_options=node_options) node_two = session.add_node(options=options)
# link nodes # link nodes
for node in [node_one, node_two]: for node in [node_one, node_two]:

View file

@ -108,13 +108,12 @@ Examples for configuring custom emane model settings.
# create session and emane network # create session and emane network
coreemu = CoreEmu() coreemu = CoreEmu()
session = coreemu.create_session() session = coreemu.create_session()
emane_network = session.create_emane_network( session.set_location(47.57917, -122.13232, 2.00000, 1.0)
model=EmaneIeee80211abgModel, options = NodeOptions()
geo_reference=(47.57917, -122.13232, 2.00000) options.set_position(80, 50)
) emane_network = session.add_node(_type=NodeTypes.EMANE, options=options)
emane_network.setposition(x=80, y=50)
# set custom emane model config # set custom emane model config
config = {} config = {}
session.emane.set_model_config(emane_network.id, EmaneIeee80211abgModel.name, config) session.emane.set_model(emane_network, EmaneIeee80211abgModel, config)
``` ```

View file

@ -60,7 +60,7 @@ class CoreNs3Node(CoreNode, ns.network.Node):
if not isinstance(net, CoreNs3Net): if not isinstance(net, CoreNs3Net):
return CoreNode.newnetif(self, net, addrlist, hwaddr, ifindex, ifname) return CoreNode.newnetif(self, net, addrlist, hwaddr, ifindex, ifname)
ifindex = self.newtuntap(ifindex=ifindex, ifname=ifname, net=net) ifindex = self.newtuntap(ifindex, ifname)
self.attachnet(ifindex, net) self.attachnet(ifindex, net)
netif = self.netif(ifindex) netif = self.netif(ifindex)
netif.sethwaddr(hwaddr) netif.sethwaddr(hwaddr)
@ -68,7 +68,7 @@ class CoreNs3Node(CoreNode, ns.network.Node):
netif.addaddr(addr) netif.addaddr(addr)
addrstr = netif.addrlist[0] addrstr = netif.addrlist[0]
(addr, mask) = addrstr.split('/') addr, mask = addrstr.split('/')
tap = net._tapdevs[netif] tap = net._tapdevs[netif]
tap.SetAttribute( tap.SetAttribute(
"IpAddress", "IpAddress",
@ -76,9 +76,9 @@ class CoreNs3Node(CoreNode, ns.network.Node):
) )
tap.SetAttribute( tap.SetAttribute(
"Netmask", "Netmask",
ns.network.Ipv4MaskValue(ns.network.Ipv4Mask("/" + mask)) ns.network.Ipv4MaskValue(ns.network.Ipv4Mask(f"/{mask}"))
) )
ns.core.Simulator.Schedule(ns.core.Time('0'), netif.install) ns.core.Simulator.Schedule(ns.core.Time("0"), netif.install)
return ifindex return ifindex
def getns3position(self): def getns3position(self):
@ -118,7 +118,7 @@ class CoreNs3Net(CoreNetworkBase):
type = "wlan" type = "wlan"
def __init__( def __init__(
self, session, _id=None, name=None, start=True, server=None, policy=None self, session, _id=None, name=None, start=True, server=None
): ):
CoreNetworkBase.__init__(self, session, _id, name, start, server) CoreNetworkBase.__init__(self, session, _id, name, start, server)
self.tapbridge = ns.tap_bridge.TapBridgeHelper() self.tapbridge = ns.tap_bridge.TapBridgeHelper()