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
cd daemon
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
- name: isort
run: |
@ -30,3 +32,11 @@ jobs:
run: |
cd daemon
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
class InterfaceHelper(object):
class InterfaceHelper:
"""
Convenience class to help generate IP4 and IP6 addresses for gRPC clients.
"""
@ -133,7 +133,7 @@ def start_streamer(stream, handler):
thread.start()
class CoreGrpcClient(object):
class CoreGrpcClient:
"""
Provides convenience methods for interfacing with the CORE grpc server.
"""
@ -148,6 +148,57 @@ class CoreGrpcClient(object):
self.stub = 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):
"""
Create a session.
@ -204,18 +255,6 @@ class CoreGrpcClient(object):
request = core_pb2.GetSessionOptionsRequest(session_id=session_id)
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):
"""
Set options for a session.
@ -231,6 +270,33 @@ class CoreGrpcClient(object):
)
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):
"""
Get session location.
@ -269,9 +335,11 @@ class CoreGrpcClient(object):
:rtype: core_pb2.SetSessionLocationResponse
: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(
session_id=session_id, position=position, scale=scale
session_id=session_id, location=location
)
return self.stub.SetSessionLocation(request)
@ -587,8 +655,9 @@ class CoreGrpcClient(object):
:rtype: core_pb2.SetMobilityConfigResponse
: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(
session_id=session_id, node_id=node_id, config=config
session_id=session_id, mobility_config=mobility_config
)
return self.stub.SetMobilityConfig(request)
@ -772,8 +841,9 @@ class CoreGrpcClient(object):
:rtype: core_pb2.SetWlanConfigResponse
:raises grpc.RpcError: when session doesn't exist
"""
wlan_config = core_pb2.WlanConfig(node_id=node_id, config=config)
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)
@ -846,12 +916,11 @@ class CoreGrpcClient(object):
:rtype: core_pb2.SetEmaneModelConfigResponse
: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(
session_id=session_id,
node_id=node_id,
model=model,
config=config,
interface_id=interface_id,
session_id=session_id, emane_model_config=model_config
)
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
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.emulator.data import (
ConfigData,
@ -19,13 +26,11 @@ from core.emulator.data import (
LinkData,
NodeData,
)
from core.emulator.emudata import InterfaceData, LinkOptions, NodeOptions
from core.emulator.enumerations import EventTypes, LinkTypes, MessageFlags, NodeTypes
from core.emulator.emudata import LinkOptions, NodeOptions
from core.emulator.enumerations import EventTypes, LinkTypes, MessageFlags
from core.errors import CoreCommandError, CoreError
from core.location.mobility import BasicRangeModel, Ns2ScriptedMobility
from core.nodes.base import CoreNetworkBase
from core.nodes.docker import DockerNode
from core.nodes.ipaddress import MacAddress
from core.nodes.lxd import LxcNode
from core.services.coreservices import ServiceManager
@ -33,167 +38,6 @@ _ONE_DAY_IN_SECONDS = 60 * 60 * 24
_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):
"""
Create CoreGrpcServer instance
@ -202,7 +46,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
"""
def __init__(self, coreemu):
super(CoreGrpcServer, self).__init__()
super().__init__()
self.coreemu = coreemu
self.running = True
self.server = None
@ -237,7 +81,8 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
:param int session_id: session id
: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
"""
session = self.coreemu.sessions.get(session_id)
@ -260,6 +105,80 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
except CoreError:
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):
"""
Create a session
@ -326,10 +245,11 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
session = self.get_session(request.session_id, context)
x, y, z = session.location.refxyz
lat, lon, alt = session.location.refgeo
position = core_pb2.SessionPosition(x=x, y=y, z=z, lat=lat, lon=lon, alt=alt)
return core_pb2.GetSessionLocationResponse(
position=position, scale=session.location.refscale
scale = session.location.refscale
location = core_pb2.SessionLocation(
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):
"""
@ -342,15 +262,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
"""
logging.debug("set session location: %s", request)
session = self.get_session(request.session_id, context)
session.location.refxyz = (
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
grpcutils.session_location(session, request.location)
return core_pb2.SetSessionLocationResponse(result=True)
def SetSessionState(self, request, context):
@ -419,6 +331,34 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
config.update(request.config)
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):
"""
Retrieve requested session
@ -761,32 +701,12 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
"""
logging.debug("add node: %s", request)
session = self.get_session(request.session_id, context)
node_proto = request.node
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)
_type, _id, options = grpcutils.add_node_data(request.node)
node = session.add_node(_type=_type, _id=_id, options=options)
# configure emane if provided
emane_model = node_proto.emane
emane_model = request.node.emane
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)
def GetNode(self, request, context):
@ -856,18 +776,18 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
logging.debug("edit node: %s", request)
session = self.get_session(request.session_id, context)
node = self.get_node(session, request.node_id, context)
node_options = NodeOptions()
node_options.icon = request.icon
options = NodeOptions()
options.icon = request.icon
x = request.position.x
y = request.position.y
node_options.set_position(x, y)
options.set_position(x, y)
lat = request.position.lat
lon = request.position.lon
alt = request.position.alt
node_options.set_location(lat, lon, alt)
options.set_location(lat, lon, alt)
result = True
try:
session.update_node(node.id, node_options)
session.edit_node(node.id, options)
node_data = node.data(0)
session.broadcast_node(node_data)
except CoreError:
@ -944,82 +864,16 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
:rtype: core.api.grpc.AddLinkResponse
"""
logging.debug("add link: %s", request)
# validate session and nodes
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_two_id, context)
node_one_id = request.link.node_one_id
node_two_id = request.link.node_two_id
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
interface_one, interface_two, options = grpcutils.add_link_data(request.link)
session.add_link(
node_one_id,
node_two_id,
interface_one,
interface_two,
link_options=link_options,
node_one_id, node_two_id, interface_one, interface_two, link_options=options
)
return core_pb2.AddLinkResponse(result=True)
@ -1166,8 +1020,9 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
"""
logging.debug("set mobility config: %s", request)
session = self.get_session(request.session_id, context)
mobility_config = request.mobility_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)
@ -1408,12 +1263,13 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
"""
logging.debug("set wlan config: %s", request)
session = self.get_session(request.session_id, context)
wlan_config = request.wlan_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:
node = self.get_node(session, request.node_id, context)
node.updatemodel(request.config)
node = self.get_node(session, wlan_config.node_id, context)
node.updatemodel(wlan_config.config)
return core_pb2.SetWlanConfigResponse(result=True)
def GetEmaneConfig(self, request, context):
@ -1494,8 +1350,9 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
"""
logging.debug("set emane model config: %s", request)
session = self.get_session(request.session_id, context)
_id = get_emane_model_id(request.node_id, request.interface_id)
session.emane.set_model_config(_id, request.model, request.config)
model_config = request.emane_model_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)
def GetEmaneModelConfigs(self, request, context):

View file

@ -27,7 +27,7 @@ from core.emulator.enumerations import (
from core.nodes.ipaddress import IpAddress, MacAddress
class CoreTlvData(object):
class CoreTlvData:
"""
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.
:param obj: custom object to pack
:param value: custom object to pack
:return: length of data and the packed data itself
:rtype: tuple
"""
value = cls.get_value(value)
return super(CoreTlvDataObj, cls).pack(value)
return super().pack(value)
@classmethod
def unpack(cls, data):
@ -109,7 +109,7 @@ class CoreTlvDataObj(CoreTlvData):
:param data: data to unpack custom object from
:return: unpacked custom object
"""
data = super(CoreTlvDataObj, cls).unpack(data)
data = super().unpack(data)
return cls.new_obj(data)
@staticmethod
@ -348,7 +348,7 @@ class CoreTlvDataMacAddr(CoreTlvDataObj):
return MacAddress(address=value[2:])
class CoreTlv(object):
class CoreTlv:
"""
Base class for representing CORE TLVs.
"""
@ -670,7 +670,7 @@ class CoreExceptionTlv(CoreTlv):
}
class CoreMessage(object):
class CoreMessage:
"""
Base class for representing CORE messages.
"""

View file

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

View file

@ -8,7 +8,7 @@ from collections import OrderedDict
from core.emulator.data import ConfigData
class ConfigShim(object):
class ConfigShim:
"""
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.
"""
@ -131,7 +131,7 @@ class Configuration(object):
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.
"""
@ -240,7 +240,7 @@ class ConfigurableManager(object):
return self.node_configurations.get(node_id)
class ConfigGroup(object):
class ConfigGroup:
"""
Defines configuration group tabs used for display by ConfigurationOptions.
"""
@ -258,7 +258,7 @@ class ConfigGroup(object):
self.stop = stop
class ConfigurableOptions(object):
class ConfigurableOptions:
"""
Provides a base for defining configuration options within CORE.
"""
@ -309,7 +309,7 @@ class ModelManager(ConfigurableManager):
"""
Creates a ModelManager object.
"""
super(ModelManager, self).__init__()
super().__init__()
self.models = {}
self.node_models = {}

View file

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

View file

@ -19,4 +19,4 @@ class EmaneIeee80211abgModel(emanemodel.EmaneModel):
cls.mac_defaults["pcrcurveuri"] = os.path.join(
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
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.up = False
self.nemidmap = {}

View file

@ -19,4 +19,4 @@ class EmaneRfPipeModel(emanemodel.EmaneModel):
cls.mac_defaults["pcrcurveuri"] = os.path.join(
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,
"share/emane/xml/models/mac/tdmaeventscheduler/tdmabasemodelpcr.xml",
)
super(EmaneTdmaModel, cls).load(emane_prefix)
super().load(emane_prefix)
cls.mac_config.insert(
0,
Configuration(

View file

@ -29,7 +29,7 @@ signal.signal(signal.SIGUSR1, 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.
"""
@ -49,7 +49,7 @@ class CoreEmu(object):
self.config = config
# session management
self.session_id_gen = IdGen(_id=0)
self.session_id_gen = IdGen()
self.sessions = {}
# load services
@ -79,18 +79,18 @@ class CoreEmu(object):
:return: nothing
"""
logging.info("shutting down all sessions")
self.session_id_gen.id = 0
sessions = self.sessions.copy()
self.sessions.clear()
for _id in sessions:
session = sessions[_id]
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 bool master: sets session to master
:param class _cls: Session class to use
:return: created session
:rtype: EmuSession
@ -103,9 +103,6 @@ class CoreEmu(object):
session = _cls(_id, config=self.config)
logging.info("created session: %s", _id)
if master:
session.master = True
self.sessions[_id] = session
return session

View file

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

View file

@ -21,7 +21,7 @@ LOCK = threading.Lock()
CMD_HIDE = True
class DistributedServer(object):
class DistributedServer:
"""
Provides distributed server interactions.
"""
@ -101,7 +101,7 @@ class DistributedServer(object):
os.unlink(temp.name)
class DistributedController(object):
class DistributedController:
"""
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
class IdGen(object):
class IdGen:
def __init__(self, _id=0):
self.id = _id
@ -29,7 +29,7 @@ def create_interface(node, network, interface_data):
ifindex=interface_data.id,
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):
@ -61,7 +61,7 @@ def link_config(network, interface, link_options, devname=None, interface_two=No
network.linkconfig(**config)
class NodeOptions(object):
class NodeOptions:
"""
Options for creating and updating nodes within core.
"""
@ -87,7 +87,7 @@ class NodeOptions(object):
self.lon = None
self.alt = None
self.emulation_id = None
self.emulation_server = None
self.server = None
self.image = image
def set_position(self, x, y):
@ -115,7 +115,7 @@ class NodeOptions(object):
self.alt = alt
class LinkOptions(object):
class LinkOptions:
"""
Options for creating and updating links within core.
"""
@ -145,7 +145,7 @@ class LinkOptions(object):
self.opaque = None
class IpPrefixes(object):
class IpPrefixes:
"""
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.
"""

View file

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

View file

@ -12,7 +12,6 @@ import subprocess
import tempfile
import threading
import time
from multiprocessing.pool import ThreadPool
from core import constants, utils
from core.emane.emanemanager import EmaneManager
@ -27,7 +26,7 @@ from core.emulator.emudata import (
link_config,
)
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.location.corelocation import CoreLocation
from core.location.event import EventLoop
@ -55,15 +54,12 @@ from core.xml.corexml import CoreXmlReader, CoreXmlWriter
NODES = {
NodeTypes.DEFAULT: CoreNode,
NodeTypes.PHYSICAL: PhysicalNode,
NodeTypes.TBD: None,
NodeTypes.SWITCH: SwitchNode,
NodeTypes.HUB: HubNode,
NodeTypes.WIRELESS_LAN: WlanNode,
NodeTypes.RJ45: Rj45Node,
NodeTypes.TUNNEL: TunnelNode,
NodeTypes.KTUNNEL: None,
NodeTypes.EMANE: EmaneNet,
NodeTypes.EMANE_NET: None,
NodeTypes.TAP_BRIDGE: GreTapBridge,
NodeTypes.PEER_TO_PEER: PtpNet,
NodeTypes.CONTROL_NET: CtrlNet,
@ -74,7 +70,7 @@ NODES_TYPE = {NODES[x]: x for x in NODES}
CTRL_NET_ID = 9001
class Session(object):
class Session:
"""
CORE session manager.
"""
@ -88,7 +84,6 @@ class Session(object):
:param bool mkdir: flag to determine if a directory should be made
"""
self.id = _id
self.master = False
# define and create session directory when desired
self.session_dir = os.path.join(tempfile.gettempdir(), f"pycore.{self.id}")
@ -134,7 +129,7 @@ class Session(object):
for key in config:
value = config[key]
self.options.set_config(key, value)
self.metadata = SessionMetaData()
self.metadata = {}
# distributed support and logic
self.distributed = DistributedController(self)
@ -243,7 +238,6 @@ class Session(object):
)
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):
"""
Objects to deal with when connecting/disconnecting wireless links.
@ -358,11 +352,7 @@ class Session(object):
net_one.name,
net_two.name,
)
if isinstance(net_two, Rj45Node):
interface = net_two.linknet(net_one)
else:
interface = net_one.linknet(net_two)
interface = net_one.linknet(net_two)
link_config(net_one, interface, link_options)
if not link_options.unidirectional:
@ -597,11 +587,11 @@ class Session(object):
raise CoreError("modify link for unknown nodes")
elif not node_one:
# 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)
elif not node_two:
# 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)
else:
common_networks = node_one.commonnets(node_two)
@ -634,13 +624,13 @@ class Session(object):
if node_two:
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.
:param core.emulator.enumerations.NodeTypes _type: type of node to create
: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
:return: created node
:raises core.CoreError: when an invalid node type is given
@ -666,18 +656,16 @@ class Session(object):
break
# generate name if not provided
if not node_options:
node_options = NodeOptions()
name = node_options.name
if not options:
options = NodeOptions()
name = options.name
if not name:
name = f"{node_class.__name__}{_id}"
# verify distributed server
server = self.distributed.servers.get(node_options.emulation_server)
if node_options.emulation_server is not None and server is None:
raise CoreError(
f"invalid distributed server: {node_options.emulation_server}"
)
server = self.distributed.servers.get(options.server)
if options.server is not None and server is None:
raise CoreError(f"invalid distributed server: {options.server}")
# create node
logging.info(
@ -693,7 +681,7 @@ class Session(object):
_id=_id,
name=name,
start=start,
image=node_options.image,
image=options.image,
server=server,
)
else:
@ -702,20 +690,20 @@ class Session(object):
)
# set node attributes
node.icon = node_options.icon
node.canvas = node_options.canvas
node.opaque = node_options.opaque
node.icon = options.icon
node.canvas = options.canvas
node.opaque = options.opaque
# set node position and broadcast it
self.set_node_position(node, node_options)
self.set_node_position(node, options)
# add services to needed nodes
if isinstance(node, (CoreNode, PhysicalNode, DockerNode, LxcNode)):
node.type = node_options.model
node.type = options.model
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)
if self.state == EventTypes.RUNTIME_STATE.value and is_boot_node:
self.write_nodes()
@ -724,12 +712,12 @@ class Session(object):
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 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
:rtype: bool
:raises core.CoreError: when node to update does not exist
@ -738,26 +726,26 @@ class Session(object):
node = self.get_node(node_id)
# set node position and broadcast it
self.set_node_position(node, node_options)
self.set_node_position(node, options)
# update attributes
node.canvas = node_options.canvas
node.icon = node_options.icon
node.canvas = options.canvas
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.
: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
"""
# extract location values
x = node_options.x
y = node_options.y
lat = node_options.lat
lon = node_options.lon
alt = node_options.alt
x = options.x
y = options.y
lat = options.lat
lon = options.lon
alt = options.alt
# check if we need to generate position from lat/lon/alt
has_empty_position = all(i is None for i in [x, y])
@ -886,10 +874,15 @@ class Session(object):
:return: nothing
"""
self.emane.shutdown()
self.delete_nodes()
self.distributed.shutdown()
self.del_hooks()
self.emane.reset()
self.emane.config_reset()
self.location.reset()
self.services.reset()
self.mobility.config_reset()
def start_events(self):
"""
@ -908,49 +901,18 @@ class Session(object):
"""
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 core.emulator.emudata.NodeOptions node_options: options for emane node, model will always be "mdr"
:return: new emane node
:rtype: core.nodes.network.WlanNode
:param float lat: latitude
:param float lon: longitude
:param float alt: altitude
:param float scale: reference scale
:return: nothing
"""
if not node_options:
node_options = NodeOptions()
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
self.location.setrefgeo(lat, lon, alt)
self.location.refscale = scale
def shutdown(self):
"""
@ -960,13 +922,11 @@ class Session(object):
self.set_state(EventTypes.DATACOLLECT_STATE, send_event=True)
self.set_state(EventTypes.SHUTDOWN_STATE, send_event=True)
# shutdown/cleanup feature helpers
self.emane.shutdown()
self.sdt.shutdown()
# clear out current core session
self.clear()
# remove and shutdown all nodes and tunnels
self.delete_nodes()
self.distributed.shutdown()
# shutdown sdt
self.sdt.shutdown()
# remove this sessions working directory
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
logging.info("deleting node(%s)", _id)
result = False
node = None
with self._nodes_lock:
if _id in self.nodes:
node = self.nodes.pop(_id)
node.shutdown()
result = True
if result:
if node:
node.shutdown()
self.check_shutdown()
return result
return node is not None
def delete_nodes(self):
"""
Clear the nodes dictionary, and call shutdown for each node.
"""
with self._nodes_lock:
funcs = []
while self.nodes:
_, node = self.nodes.popitem()
node.shutdown()
funcs.append((node.shutdown, [], {}))
utils.threadpool(funcs)
self.node_id_gen.id = 0
def write_nodes(self):
"""
@ -1547,11 +1509,13 @@ class Session(object):
# stop node services
with self._nodes_lock:
funcs = []
for node_id in self.nodes:
node = self.nodes[node_id]
# TODO: determine if checking for CoreNode alone is ok
if isinstance(node, CoreNodeBase):
self.services.stop_services(node)
args = (node,)
funcs.append((self.services.stop_services, args, {}))
utils.threadpool(funcs)
# shutdown emane
self.emane.shutdown()
@ -1559,7 +1523,8 @@ class Session(object):
# update control interface hosts
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=1, 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))
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):
"""
Invoke the boot() procedure for all nodes and send back node
@ -1597,29 +1574,18 @@ class Session(object):
request flag.
"""
with self._nodes_lock:
pool = ThreadPool()
results = []
start = time.time()
funcs = []
start = time.monotonic()
for _id in self.nodes:
node = self.nodes[_id]
if isinstance(node, CoreNodeBase) and not isinstance(node, Rj45Node):
# add a control interface if configured
logging.info(
"booting node(%s): %s",
node.name,
[x.name for x in node.services],
)
self.add_remove_control_interface(node=node, remove=False)
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)
args = (node,)
funcs.append((self.boot_node, args, {}))
results, exceptions = utils.threadpool(funcs)
total = time.monotonic() - start
logging.debug("boot run time: %s", total)
if exceptions:
raise CoreError(exceptions)
self.update_control_interface_hosts()
def get_control_net_prefixes(self):
@ -1732,28 +1698,19 @@ class Session(object):
prefixes = prefix_spec.split()
if len(prefixes) > 1:
# a list of per-host prefixes is provided
assign_address = True
if self.master:
try:
# split first (master) entry into server and prefix
prefix = prefixes[0].split(":", 1)[1]
except IndexError:
# no server name. possibly only one server
prefix = prefixes[0]
# len(prefixes) == 1
try:
# split first (master) entry into server and prefix
prefix = prefixes[0].split(":", 1)[1]
except IndexError:
# no server name. possibly only one server
prefix = prefixes[0]
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]
logging.info(
"controlnet(%s) prefix(%s) assign(%s) updown(%s) serverintf(%s)",
"controlnet(%s) prefix(%s) updown(%s) serverintf(%s)",
_id,
prefix,
assign_address,
updown_script,
server_interface,
)
@ -1761,7 +1718,7 @@ class Session(object):
cls=CtrlNet,
_id=_id,
prefix=prefix,
assign_address=assign_address,
assign_address=True,
updown_script=updown_script,
serverintf=server_interface,
)
@ -1778,7 +1735,7 @@ class Session(object):
If conf_reqd is False, the control network may be built even
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 bool remove: flag to check if it should be removed
: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
def __init__(self):
super(SessionConfig, self).__init__()
super().__init__()
self.set_configs(self.default_values())
def get_config(
@ -71,9 +71,7 @@ class SessionConfig(ConfigurableManager, ConfigurableOptions):
config_type=ConfigurableManager._default_type,
default=None,
):
value = super(SessionConfig, self).get_config(
_id, node_id, config_type, default
)
value = super().get_config(_id, node_id, config_type, default)
if value == "":
value = default
return value
@ -89,14 +87,3 @@ class SessionConfig(ConfigurableManager, ConfigurableOptions):
if value is not None:
value = int(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
class CoreLocation(object):
class CoreLocation:
"""
Member of session class for handling global location data. This keeps
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 kwargs: function keyword arguments
"""
super(Timer, self).__init__()
super().__init__()
self.interval = interval
self.function = function
@ -70,7 +70,7 @@ class Timer(threading.Thread):
@total_ordering
class Event(object):
class Event:
"""
Provides event objects that can be used within the EventLoop class.
"""
@ -118,7 +118,7 @@ class Event(object):
self.canceled = True
class EventLoop(object):
class EventLoop:
"""
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
"""
super(MobilityManager, self).__init__()
super().__init__()
self.session = session
self.models[BasicRangeModel.name] = BasicRangeModel
self.models[Ns2ScriptedMobility.name] = Ns2ScriptedMobility
@ -302,7 +302,7 @@ class BasicRangeModel(WirelessModel):
:param core.session.Session session: related core session
:param int _id: object id
"""
super(BasicRangeModel, self).__init__(session=session, _id=_id)
super().__init__(session, _id)
self.session = session
self.wlan = session.get_node(_id)
self._netifs = {}
@ -535,7 +535,7 @@ class BasicRangeModel(WirelessModel):
@total_ordering
class WayPoint(object):
class WayPoint:
"""
Maintains information regarding waypoints.
"""
@ -587,8 +587,7 @@ class WayPointMobility(WirelessModel):
:param int _id: object id
:return:
"""
super(WayPointMobility, self).__init__(session=session, _id=_id)
super().__init__(session=session, _id=_id)
self.state = self.STATE_STOPPED
self.queue = []
self.queue_copy = []
@ -945,7 +944,7 @@ class Ns2ScriptedMobility(WayPointMobility):
:param core.emulator.session.Session session: CORE session instance
:param int _id: object id
"""
super(Ns2ScriptedMobility, self).__init__(session=session, _id=_id)
super().__init__(session, _id)
self._netifs = {}
self._netifslock = threading.Lock()
@ -1137,7 +1136,7 @@ class Ns2ScriptedMobility(WayPointMobility):
"""
logging.info("starting script")
laststate = self.state
super(Ns2ScriptedMobility, self).start()
super().start()
if laststate == self.STATE_PAUSED:
self.statescript("unpause")
@ -1147,7 +1146,7 @@ class Ns2ScriptedMobility(WayPointMobility):
:return: nothing
"""
super(Ns2ScriptedMobility, self).run()
super().run()
self.statescript("run")
def pause(self):
@ -1156,7 +1155,7 @@ class Ns2ScriptedMobility(WayPointMobility):
:return: nothing
"""
super(Ns2ScriptedMobility, self).pause()
super().pause()
self.statescript("pause")
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
:return: nothing
"""
super(Ns2ScriptedMobility, self).stop(move_initial=move_initial)
super().stop(move_initial=move_initial)
self.statescript("stop")
def statescript(self, typestr):

View file

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

View file

@ -8,7 +8,7 @@ from core import utils
from core.constants import VCMD_BIN
class VnodeClient(object):
class VnodeClient:
"""
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
class DockerClient(object):
class DockerClient:
def __init__(self, name, image, run):
self.name = name
self.image = image
@ -96,9 +96,7 @@ class DockerNode(CoreNode):
if image is None:
image = "ubuntu"
self.image = image
super(DockerNode, self).__init__(
session, _id, name, nodedir, bootsh, start, server
)
super().__init__(session, _id, name, nodedir, bootsh, start, server)
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
class CoreInterface(object):
class CoreInterface:
"""
Base class for network interfaces.
"""
@ -40,8 +40,10 @@ class CoreInterface(object):
self.poshook = lambda a, b, c, d: None
# used with EMANE
self.transport_type = None
# interface index on the network
# node interface index
self.netindex = None
# net interface index
self.netifi = None
# index used to find flow data
self.flow_id = None
self.server = server
@ -230,7 +232,7 @@ class Veth(CoreInterface):
:raises CoreCommandError: when there is a command exception
"""
# 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.up = False
if start:
@ -291,7 +293,7 @@ class TunTap(CoreInterface):
will run on, default is None for localhost
:param bool start: start flag
"""
CoreInterface.__init__(self, session, node, name, mtu, server)
super().__init__(session, node, name, mtu, server)
self.localname = localname
self.up = False
self.transport_type = "virtual"
@ -474,7 +476,7 @@ class GreTap(CoreInterface):
will run on, default is None for localhost
: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:
# from PyCoreObj
_id = ((id(self) >> 16) ^ (id(self) & 0xFFFF)) & 0xFFFF

View file

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

View file

@ -10,7 +10,7 @@ from core.errors import CoreCommandError
from core.nodes.base import CoreNode
class LxdClient(object):
class LxdClient:
def __init__(self, name, image, run):
self.name = name
self.image = image
@ -89,9 +89,7 @@ class LxcNode(CoreNode):
if image is None:
image = "ubuntu"
self.image = image
super(LxcNode, self).__init__(
session, _id, name, nodedir, bootsh, start, server
)
super().__init__(session, _id, name, nodedir, bootsh, start, server)
def alive(self):
"""
@ -217,6 +215,6 @@ class LxcNode(CoreNode):
self.cmd(f"chmod {mode:o} {filename}")
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
time.sleep(0.5)

View file

@ -19,7 +19,7 @@ def get_net_client(use_ovs, run):
return LinuxNetClient(run)
class LinuxNetClient(object):
class LinuxNetClient:
"""
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()
class EbtablesQueue(object):
class EbtablesQueue:
"""
Helper class for queuing up ebtables commands into rate-limited
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
:param policy: network policy
"""
CoreNetworkBase.__init__(self, session, _id, name, start, server)
super().__init__(session, _id, name, start, server)
if name is None:
name = str(self.id)
if policy is not None:
@ -337,8 +337,6 @@ class CoreNetwork(CoreNetworkBase):
del self.session
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):
"""
Attach a network interface.
@ -348,8 +346,7 @@ class CoreNetwork(CoreNetworkBase):
"""
if self.up:
netif.net_client.create_interface(self.brname, netif.localname)
CoreNetworkBase.attach(self, netif)
super().attach(netif)
def detach(self, netif):
"""
@ -360,8 +357,7 @@ class CoreNetwork(CoreNetworkBase):
"""
if self.up:
netif.net_client.delete_interface(self.brname, netif.localname)
CoreNetworkBase.detach(self, netif)
super().detach(netif)
def linked(self, netif1, netif2):
"""
@ -654,7 +650,7 @@ class GreTapBridge(CoreNetwork):
:return: nothing
"""
CoreNetwork.startup(self)
super().startup()
if self.gretap:
self.attach(self.gretap)
@ -668,7 +664,7 @@ class GreTapBridge(CoreNetwork):
self.detach(self.gretap)
self.gretap.shutdown()
self.gretap = None
CoreNetwork.shutdown(self)
super().shutdown()
def addrconfig(self, addrlist):
"""
@ -755,7 +751,7 @@ class CtrlNet(CoreNetwork):
self.assign_address = assign_address
self.updown_script = updown_script
self.serverintf = serverintf
CoreNetwork.__init__(self, session, _id, name, start, server)
super().__init__(session, _id, name, start, server)
def add_addresses(self, address):
"""
@ -786,8 +782,7 @@ class CtrlNet(CoreNetwork):
if self.net_client.existing_bridges(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)
if self.hostid and self.assign_address:
@ -835,7 +830,7 @@ class CtrlNet(CoreNetwork):
except CoreCommandError:
logging.exception("error issuing shutdown script shutdown")
CoreNetwork.shutdown(self)
super().shutdown()
def all_link_data(self, flags):
"""
@ -866,8 +861,7 @@ class PtpNet(CoreNetwork):
raise ValueError(
"Point-to-point links support at most 2 network interfaces"
)
CoreNetwork.attach(self, netif)
super().attach(netif)
def data(self, message_type, lat=None, lon=None, alt=None):
"""
@ -1007,23 +1001,14 @@ class HubNode(CoreNetwork):
policy = "ACCEPT"
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
: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
:return: nothing
"""
CoreNetwork.__init__(self, session, _id, name, start, server)
# TODO: move to startup method
if start:
self.net_client.disable_mac_learning(self.brname)
super().startup()
self.net_client.disable_mac_learning(self.brname)
class WlanNode(CoreNetwork):
@ -1050,24 +1035,28 @@ class WlanNode(CoreNetwork):
will run on, default is None for localhost
:param policy: wlan policy
"""
CoreNetwork.__init__(self, session, _id, name, start, server, policy)
# wireless model such as basic range
super().__init__(session, _id, name, start, server, policy)
# wireless and mobility models (BasicRangeModel, Ns2WaypointMobility)
self.model = None
# mobility model such as scripted
self.mobility = None
# TODO: move to startup method
if start:
self.net_client.disable_mac_learning(self.brname)
def startup(self):
"""
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):
"""
Attach a network interface.
:param core.nodes.interface.CoreInterface netif: network interface
:param core.nodes.interface.Veth netif: network interface
:return: nothing
"""
CoreNetwork.attach(self, netif)
super().attach(netif)
if self.model:
netif.poshook = self.model.position_callback
if netif.node is None:
@ -1099,12 +1088,12 @@ class WlanNode(CoreNetwork):
def update_mobility(self, config):
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)
def updatemodel(self, config):
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(
"node(%s) updating model(%s): %s", self.id, self.model.name, config
)
@ -1122,11 +1111,9 @@ class WlanNode(CoreNetwork):
:return: list of link data
:rtype: list[core.emulator.data.LinkData]
"""
all_links = CoreNetwork.all_link_data(self, flags)
all_links = super().all_link_data(flags)
if self.model:
all_links.extend(self.model.all_link_data(flags))
return all_links

View file

@ -19,7 +19,7 @@ class PhysicalNode(CoreNodeBase):
def __init__(
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:
raise CoreError("physical nodes must be assigned to a remote server")
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
class Bunch(object):
class Bunch:
"""
Helper class for recording a collection of attributes.
"""
@ -38,7 +38,7 @@ class Bunch(object):
self.__dict__.update(kwargs)
class Sdt(object):
class Sdt:
"""
Helper class for exporting session objects to NRL"s SDT3D.
The connect() method initializes the display, and can be invoked

View file

@ -10,7 +10,6 @@ services.
import enum
import logging
import time
from multiprocessing.pool import ThreadPool
from core import utils
from core.constants import which
@ -29,7 +28,7 @@ class ServiceMode(enum.Enum):
TIMER = 2
class ServiceDependencies(object):
class ServiceDependencies:
"""
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.
@ -127,7 +126,7 @@ class ServiceDependencies(object):
return self.path
class ServiceShim(object):
class ServiceShim:
keys = [
"dirs",
"files",
@ -235,7 +234,7 @@ class ServiceShim(object):
return servicesstring[1].split(",")
class ServiceManager(object):
class ServiceManager:
"""
Manages services available for CORE nodes to use.
"""
@ -306,7 +305,7 @@ class ServiceManager(object):
return service_errors
class CoreServices(object):
class CoreServices:
"""
Class for interacting with a list of available startup services for
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
:return: nothing
"""
pool = ThreadPool()
results = []
funcs = []
boot_paths = ServiceDependencies(node.services).boot_paths()
for boot_path in boot_paths:
result = pool.apply_async(self._start_boot_paths, (node, boot_path))
results.append(result)
pool.close()
pool.join()
for result in results:
result.get()
args = (node, boot_path)
funcs.append((self._start_boot_paths, args, {}))
result, exceptions = utils.threadpool(funcs)
if exceptions:
raise ServiceBootError(exceptions)
def _start_boot_paths(self, node, boot_path):
"""
@ -791,7 +786,7 @@ class CoreServices(object):
node.nodefile(file_name, cfg)
class CoreService(object):
class CoreService:
"""
Parent class used for defining services.
"""

View file

@ -2,6 +2,7 @@
Miscellaneous utility functions, wrappers around some subprocess procedures.
"""
import concurrent.futures
import fcntl
import hashlib
import importlib
@ -223,34 +224,6 @@ def cmd(args, env=None, cwd=None, wait=True, shell=False):
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):
"""
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:
log_config = json.load(log_config_file)
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)
class NodeElement(object):
class NodeElement:
def __init__(self, session, node, element_name):
self.session = session
self.node = node
@ -131,7 +131,7 @@ class NodeElement(object):
add_attribute(position, "alt", alt)
class ServiceElement(object):
class ServiceElement:
def __init__(self, service):
self.service = service
self.element = etree.Element("service")
@ -197,7 +197,7 @@ class ServiceElement(object):
class DeviceElement(NodeElement):
def __init__(self, session, node):
super(DeviceElement, self).__init__(session, node, "device")
super().__init__(session, node, "device")
add_attribute(self.element, "type", node.type)
self.add_services()
@ -212,7 +212,7 @@ class DeviceElement(NodeElement):
class NetworkElement(NodeElement):
def __init__(self, session, node):
super(NetworkElement, self).__init__(session, node, "network")
super().__init__(session, node, "network")
model = getattr(self.node, "model", None)
if model:
add_attribute(self.element, "model", model.name)
@ -232,7 +232,7 @@ class NetworkElement(NodeElement):
add_attribute(self.element, "type", node_type)
class CoreXmlWriter(object):
class CoreXmlWriter:
def __init__(self, session):
self.session = session
self.scenario = etree.Element("scenario")
@ -313,13 +313,13 @@ class CoreXmlWriter(object):
def write_session_metadata(self):
# metadata
metadata_elements = etree.Element("session_metadata")
config = self.session.metadata.get_configs()
config = self.session.metadata
if not config:
return
for _id in config:
value = config[_id]
add_configuration(metadata_elements, _id, value)
for key in config:
value = config[key]
add_configuration(metadata_elements, key, value)
if metadata_elements.getchildren():
self.scenario.append(metadata_elements)
@ -527,7 +527,7 @@ class CoreXmlWriter(object):
return link_element
class CoreXmlReader(object):
class CoreXmlReader:
def __init__(self, session):
self.session = session
self.scenario = None
@ -574,7 +574,7 @@ class CoreXmlReader(object):
value = data.get("value")
configs[name] = value
logging.info("reading session metadata: %s", configs)
self.session.metadata.set_configs(configs)
self.session.metadata = configs
def read_session_options(self):
session_options = self.scenario.find("session_options")
@ -737,53 +737,51 @@ class CoreXmlReader(object):
node_id = get_int(device_element, "id")
name = device_element.get("name")
model = device_element.get("type")
node_options = NodeOptions(name, model)
options = NodeOptions(name, model)
service_elements = device_element.find("services")
if service_elements is not None:
node_options.services = [
x.get("name") for x in service_elements.iterchildren()
]
options.services = [x.get("name") for x in service_elements.iterchildren()]
position_element = device_element.find("position")
if position_element is not None:
x = get_int(position_element, "x")
y = get_int(position_element, "y")
if all([x, y]):
node_options.set_position(x, y)
options.set_position(x, y)
lat = get_float(position_element, "lat")
lon = get_float(position_element, "lon")
alt = get_float(position_element, "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)
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):
node_id = get_int(network_element, "id")
name = network_element.get("name")
node_type = NodeTypes[network_element.get("type")]
node_options = NodeOptions(name)
options = NodeOptions(name)
position_element = network_element.find("position")
if position_element is not None:
x = get_int(position_element, "x")
y = get_int(position_element, "y")
if all([x, y]):
node_options.set_position(x, y)
options.set_position(x, y)
lat = get_float(position_element, "lat")
lon = get_float(position_element, "lon")
alt = get_float(position_element, "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) 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):
link_elements = self.scenario.find("links")

View file

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

View file

@ -15,7 +15,7 @@ if __name__ == "__main__":
options = NodeOptions(model=None, image="ubuntu")
# 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)
# create node two

View file

@ -17,11 +17,11 @@ if __name__ == "__main__":
options = NodeOptions(model=None, image="ubuntu")
# 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)
# 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)
# add link

View file

@ -19,11 +19,11 @@ if __name__ == "__main__":
switch = session.add_node(_type=NodeTypes.SWITCH)
# 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)
# 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)
# 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")
# 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)
# create node two

View file

@ -17,11 +17,11 @@ if __name__ == "__main__":
options = NodeOptions(image="ubuntu:18.04")
# 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)
# 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)
# add link

View file

@ -19,11 +19,11 @@ if __name__ == "__main__":
switch = session.add_node(_type=NodeTypes.SWITCH)
# 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)
# 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)
# node three

View file

@ -31,11 +31,11 @@ def main(args):
# create local node, switch, and remote nodes
options = NodeOptions(model="mdr")
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)
session.emane.set_model(emane_net, EmaneIeee80211abgModel)
options.emulation_server = server_name
node_two = session.add_node(node_options=options)
options.server = server_name
node_two = session.add_node(options=options)
# create node interfaces and link
interface_one = prefixes.create_interface(node_one)

View file

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

View file

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

View file

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

View file

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

View file

@ -5,7 +5,7 @@ DEFAULT_TIME = 10
DEFAULT_STEP = 1
def parse_options(name):
def parse(name):
parser = argparse.ArgumentParser(description=f"Run {name} example")
parser.add_argument(
"-n",
@ -22,11 +22,11 @@ def parse_options(name):
help="example iperf run time in seconds",
)
options = parser.parse_args()
args = parser.parse_args()
if options.nodes < 2:
parser.error(f"invalid min number of nodes: {options.nodes}")
if options.time < 1:
parser.error(f"invalid test time: {options.time}")
if args.nodes < 2:
parser.error(f"invalid min number of nodes: {args.nodes}")
if args.time < 1:
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
def example(options):
def example(args):
# ip generator for example
prefixes = IpPrefixes(ip4_prefix="10.83.0.0/16")
@ -22,7 +22,7 @@ def example(options):
switch = session.add_node(_type=NodeTypes.SWITCH)
# create nodes
for _ in range(options.nodes):
for _ in range(args.nodes):
node = session.add_node()
interface = prefixes.create_interface(node)
session.add_link(node.id, switch.id, interface_one=interface)
@ -32,13 +32,13 @@ def example(options):
# get nodes to run example
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)
first_node.cmd("iperf -s -D")
first_node_address = prefixes.ip4_address(first_node)
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)
first_node.cmd("killall -9 iperf")
@ -48,12 +48,10 @@ def example(options):
def main():
logging.basicConfig(level=logging.INFO)
options = parser.parse_options("switch")
args = parser.parse("switch")
start = datetime.datetime.now()
logging.info(
"running switch example: nodes(%s) time(%s)", options.nodes, options.time
)
example(options)
logging.info("running switch example: nodes(%s) time(%s)", args.nodes, args.time)
example(args)
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
def example(options):
def example(args):
# ip generator for example
prefixes = IpPrefixes("10.83.0.0/16")
@ -24,10 +24,10 @@ def example(options):
session.mobility.set_model(wlan, BasicRangeModel)
# create nodes, must set a position for wlan basic range model
node_options = NodeOptions()
node_options.set_position(0, 0)
for _ in range(options.nodes):
node = session.add_node(node_options=node_options)
options = NodeOptions(model="mdr")
options.set_position(0, 0)
for _ in range(args.nodes):
node = session.add_node(options=options)
interface = prefixes.create_interface(node)
session.add_link(node.id, wlan.id, interface_one=interface)
@ -36,13 +36,14 @@ def example(options):
# get nodes for example run
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)
first_node.cmd("iperf -s -D")
address = prefixes.ip4_address(first_node)
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")
# shutdown session
@ -51,13 +52,11 @@ def example(options):
def main():
logging.basicConfig(level=logging.INFO)
options = parser.parse_options("wlan")
args = parser.parse("wlan")
start = datetime.datetime.now()
logging.info(
"running wlan example: nodes(%s) time(%s)", options.nodes, options.time
)
example(options)
logging.info("running wlan example: nodes(%s) time(%s)", args.nodes, args.time)
example(args)
logging.info("elapsed time: %s", datetime.datetime.now() - start)

View file

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

View file

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

View file

@ -2,189 +2,140 @@
Unit test fixture module.
"""
import os
import threading
import time
import mock
import pytest
from mock.mock import MagicMock
from core.api.grpc.client import InterfaceHelper
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.coreserver import CoreServer
from core.emane.emanemanager import EmaneManager
from core.emulator.coreemu import CoreEmu
from core.emulator.distributed import DistributedServer
from core.emulator.emudata import IpPrefixes
from core.emulator.enumerations import CORE_API_PORT, ConfigTlvs, EventTlvs, EventTypes
from core.nodes import ipaddress
from core.services.coreservices import ServiceManager
from core.emulator.enumerations import EventTypes
from core.emulator.session import Session
from core.nodes.base import CoreNode
EMANE_SERVICES = "zebra|OSPFv3MDR|IPForward"
class CoreServerTest(object):
def __init__(self, port=CORE_API_PORT):
self.host = "localhost"
self.port = port
address = (self.host, self.port)
self.server = CoreServer(
address, CoreHandler, {"numthreads": 1, "daemonize": False}
)
class PatchManager:
def __init__(self):
self.patches = []
self.distributed_server = "core2"
self.prefix = ipaddress.Ipv4Prefix("10.83.0.0/16")
self.session = None
self.request_handler = None
def patch_obj(self, _cls, attribute):
p = mock.patch.object(_cls, attribute)
p.start()
self.patches.append(p)
def setup_handler(self):
self.session = self.server.coreemu.create_session(1)
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()
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 patch(self, func):
p = mock.patch(func)
p.start()
self.patches.append(p)
def shutdown(self):
self.server.coreemu.shutdown()
self.server.server_close()
for p in self.patches:
p.stop()
@pytest.fixture
def grpc_server():
coremu = CoreEmu()
grpc_server = CoreGrpcServer(coremu)
class MockServer:
def __init__(self, config, coreemu):
self.config = config
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.daemon = True
thread.start()
time.sleep(0.1)
yield grpc_server
coremu.shutdown()
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
def session():
# use coreemu and create a session
coreemu = CoreEmu(config={"emane_prefix": "/usr"})
session_fixture = coreemu.create_session()
session_fixture.set_state(EventTypes.CONFIGURATION_STATE)
assert os.path.exists(session_fixture.session_dir)
def grpc_server(module_grpc):
yield module_grpc
module_grpc.coreemu.shutdown()
# return created session
yield session_fixture
# clear session configurations
session_fixture.location.reset()
session_fixture.services.reset()
session_fixture.mobility.config_reset()
session_fixture.emane.config_reset()
@pytest.fixture
def session(global_session):
global_session.set_state(EventTypes.CONFIGURATION_STATE)
yield global_session
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()
# 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):
parser.addoption("--distributed", help="distributed server address")
parser.addoption("--mock", action="store_true", help="run without mocking")
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.tdma import EmaneTdmaModel
from core.emulator.emudata import NodeOptions
from core.emulator.enumerations import NodeTypes
from core.errors import CoreCommandError, CoreError
_EMANE_MODELS = [
@ -46,10 +47,11 @@ class TestEmane:
"""
# create emane node for networking the core nodes
emane_network = session.create_emane_network(
model, geo_reference=(47.57917, -122.13232, 2.00000)
)
emane_network.setposition(x=80, y=50)
session.set_location(47.57917, -122.13232, 2.00000, 1.0)
options = NodeOptions()
options.set_position(80, 50)
emane_network = session.add_node(_type=NodeTypes.EMANE, options=options)
session.emane.set_model(emane_network, model)
# configure tdma
if model == EmaneTdmaModel:
@ -60,11 +62,11 @@ class TestEmane:
)
# create nodes
node_options = NodeOptions()
node_options.set_position(150, 150)
node_one = session.create_wireless_node(node_options=node_options)
node_options.set_position(300, 150)
node_two = session.create_wireless_node(node_options=node_options)
options = NodeOptions(model="mdr")
options.set_position(150, 150)
node_one = session.add_node(options=options)
options.set_position(300, 150)
node_two = session.add_node(options=options)
for i, node in enumerate([node_one, node_two]):
node.setposition(x=150 * (i + 1), y=150)
@ -87,19 +89,22 @@ class TestEmane:
:param ip_prefixes: generates ip addresses for nodes
"""
# create emane node for networking the core nodes
emane_network = session.create_emane_network(
EmaneIeee80211abgModel,
geo_reference=(47.57917, -122.13232, 2.00000),
config={"test": "1"},
session.set_location(47.57917, -122.13232, 2.00000, 1.0)
options = NodeOptions()
options.set_position(80, 50)
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
node_options = NodeOptions()
node_options.set_position(150, 150)
node_one = session.create_wireless_node(node_options=node_options)
node_options.set_position(300, 150)
node_two = session.create_wireless_node(node_options=node_options)
options = NodeOptions(model="mdr")
options.set_position(150, 150)
node_one = session.add_node(options=options)
options.set_position(300, 150)
node_two = session.add_node(options=options)
for i, node in enumerate([node_one, node_two]):
node.setposition(x=150 * (i + 1), y=150)
@ -137,11 +142,11 @@ class TestEmane:
# retrieve configuration we set originally
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
assert session.get_node(n1_id)
assert session.get_node(n2_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):
address = ip_prefixes.ip4_address(to_node)
try:
from_node.cmd(f"ping -c 3 {address}")
from_node.cmd(f"ping -c 1 {address}")
status = 0
except CoreCommandError as e:
status = e.returncode
@ -57,14 +57,14 @@ class TestCore:
status = ping(node_one, node_two, ip_prefixes)
assert not status
def test_vnode_client(self, session, ip_prefixes):
def test_vnode_client(self, request, session, ip_prefixes):
"""
Test vnode client methods.
:param request: pytest request
:param session: session for test
:param ip_prefixes: generates ip addresses for nodes
"""
# create ptp
ptp_node = session.add_node(_type=NodeTypes.PEER_TO_PEER)
@ -87,7 +87,8 @@ class TestCore:
assert client.connected()
# 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):
"""
@ -146,10 +147,10 @@ class TestCore:
session.mobility.set_model(wlan_node, BasicRangeModel)
# create nodes
node_options = NodeOptions()
node_options.set_position(0, 0)
node_one = session.create_wireless_node(node_options=node_options)
node_two = session.create_wireless_node(node_options=node_options)
options = NodeOptions(model="mdr")
options.set_position(0, 0)
node_one = session.add_node(options=options)
node_two = session.add_node(options=options)
# link nodes
for node in [node_one, node_two]:
@ -176,10 +177,10 @@ class TestCore:
session.mobility.set_model(wlan_node, BasicRangeModel)
# create nodes
node_options = NodeOptions()
node_options.set_position(0, 0)
node_one = session.create_wireless_node(node_options=node_options)
node_two = session.create_wireless_node(node_options=node_options)
options = NodeOptions(model="mdr")
options.set_position(0, 0)
node_one = session.add_node(options=options)
node_two = session.add_node(options=options)
# link nodes
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 pytest
from mock import patch
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.emane.ieee80211abg import EmaneIeee80211abgModel
from core.emulator.data import EventData
@ -18,9 +19,127 @@ from core.emulator.enumerations import (
)
from core.errors import CoreError
from core.location.mobility import BasicRangeModel, Ns2ScriptedMobility
from core.xml.corexml import CoreXmlWriter
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])
def test_create_session(self, grpc_server, session_id):
# given
@ -112,13 +231,13 @@ class TestGrpc:
response = client.get_session_location(session.id)
# then
assert response.scale == 1.0
assert response.position.x == 0
assert response.position.y == 0
assert response.position.z == 0
assert response.position.lat == 0
assert response.position.lon == 0
assert response.position.alt == 0
assert response.location.scale == 1.0
assert response.location.x == 0
assert response.location.y == 0
assert response.location.z == 0
assert response.location.lat == 0
assert response.location.lon == 0
assert response.location.alt == 0
def test_set_session_location(self, grpc_server):
# given
@ -164,6 +283,36 @@ class TestGrpc:
config = session.options.get_configs()
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):
# given
client = CoreGrpcClient()
@ -240,13 +389,16 @@ class TestGrpc:
with pytest.raises(CoreError):
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
client = CoreGrpcClient()
session = grpc_server.coreemu.create_session()
session.set_state(EventTypes.CONFIGURATION_STATE)
node_options = NodeOptions(model="Host")
node = session.add_node(node_options=node_options)
options = NodeOptions(model="Host")
node = session.add_node(options=options)
session.instantiate()
output = "hello world"
@ -263,8 +415,8 @@ class TestGrpc:
client = CoreGrpcClient()
session = grpc_server.coreemu.create_session()
session.set_state(EventTypes.CONFIGURATION_STATE)
node_options = NodeOptions(model="Host")
node = session.add_node(node_options=node_options)
options = NodeOptions(model="Host")
node = session.add_node(options=options)
session.instantiate()
# then
@ -524,9 +676,9 @@ class TestGrpc:
# given
client = CoreGrpcClient()
session = grpc_server.coreemu.create_session()
emane_network = session.create_emane_network(
model=EmaneIeee80211abgModel, geo_reference=(47.57917, -122.13232, 2.00000)
)
session.set_location(47.57917, -122.13232, 2.00000, 1.0)
emane_network = session.add_node(_type=NodeTypes.EMANE)
session.emane.set_model(emane_network, EmaneIeee80211abgModel)
config_key = "platform_id_start"
config_value = "2"
session.emane.set_model_config(
@ -548,9 +700,9 @@ class TestGrpc:
# given
client = CoreGrpcClient()
session = grpc_server.coreemu.create_session()
emane_network = session.create_emane_network(
model=EmaneIeee80211abgModel, geo_reference=(47.57917, -122.13232, 2.00000)
)
session.set_location(47.57917, -122.13232, 2.00000, 1.0)
emane_network = session.add_node(_type=NodeTypes.EMANE)
session.emane.set_model(emane_network, EmaneIeee80211abgModel)
config_key = "bandwidth"
config_value = "900000"
@ -574,9 +726,9 @@ class TestGrpc:
# given
client = CoreGrpcClient()
session = grpc_server.coreemu.create_session()
emane_network = session.create_emane_network(
model=EmaneIeee80211abgModel, geo_reference=(47.57917, -122.13232, 2.00000)
)
session.set_location(47.57917, -122.13232, 2.00000, 1.0)
emane_network = session.add_node(_type=NodeTypes.EMANE)
session.emane.set_model(emane_network, EmaneIeee80211abgModel)
# then
with client.context_connect():
@ -834,7 +986,10 @@ class TestGrpc:
# then
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
client = CoreGrpcClient()
grpc_server.coreemu.create_session()

View file

@ -6,6 +6,7 @@ import time
import mock
import pytest
from mock import MagicMock
from core.api.tlv import coreapi
from core.emane.ieee80211abg import EmaneIeee80211abgModel
@ -42,10 +43,9 @@ class TestGui:
(NodeTypes.SWITCH, None),
(NodeTypes.WIRELESS_LAN, 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
message = coreapi.CoreNodeMessage.create(
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
coreserver.session.add_node(_id=node_id)
coretlv.session.add_node(_id=node_id)
x = 50
y = 100
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.position.x == x
assert node.position.y == y
def test_node_delete(self, coreserver):
def test_node_delete(self, coretlv):
node_id = 1
coreserver.session.add_node(_id=node_id)
coretlv.session.add_node(_id=node_id)
message = coreapi.CoreNodeMessage.create(
MessageFlags.DELETE.value, [(NodeTlvs.NUMBER, node_id)]
)
coreserver.request_handler.handle_message(message)
coretlv.handle_message(message)
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
coreserver.session.add_node(_id=node_one)
coretlv.session.add_node(_id=node_one)
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")
interface_one = ip_prefix.addr(node_one)
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)
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
coreserver.session.add_node(_id=node_one)
coretlv.session.add_node(_id=node_one)
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")
interface_one = ip_prefix.addr(node_one)
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)
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
coreserver.session.add_node(_id=node_one)
coretlv.session.add_node(_id=node_one)
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")
interface_one = ip_prefix.addr(node_one)
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 = []
for node_id in coreserver.session.nodes:
node = coreserver.session.nodes[node_id]
for node_id in coretlv.session.nodes:
node = coretlv.session.nodes[node_id]
all_links += node.all_link_data(0)
assert len(all_links) == 1
def test_link_update(self, coreserver):
def test_link_update(self, coretlv):
node_one = 1
coreserver.session.add_node(_id=node_one)
coretlv.session.add_node(_id=node_one)
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")
interface_one = ip_prefix.addr(node_one)
message = coreapi.CoreLinkMessage.create(
@ -191,8 +191,8 @@ class TestGui:
(LinkTlvs.INTERFACE1_IP4_MASK, 24),
],
)
coreserver.request_handler.handle_message(message)
switch_node = coreserver.session.get_node(switch)
coretlv.handle_message(message)
switch_node = coretlv.session.get_node(switch)
all_links = switch_node.all_link_data(0)
assert len(all_links) == 1
link = all_links[0]
@ -208,19 +208,19 @@ class TestGui:
(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)
assert len(all_links) == 1
link = all_links[0]
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
coreserver.session.add_node(_id=node_one)
coretlv.session.add_node(_id=node_one)
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")
interface_one = ip_prefix.addr(node_one)
interface_two = ip_prefix.addr(node_two)
@ -236,10 +236,10 @@ class TestGui:
(LinkTlvs.INTERFACE2_IP4_MASK, 24),
],
)
coreserver.request_handler.handle_message(message)
coretlv.handle_message(message)
all_links = []
for node_id in coreserver.session.nodes:
node = coreserver.session.nodes[node_id]
for node_id in coretlv.session.nodes:
node = coretlv.session.nodes[node_id]
all_links += node.all_link_data(0)
assert len(all_links) == 1
@ -252,19 +252,19 @@ class TestGui:
(LinkTlvs.INTERFACE2_NUMBER, 0),
],
)
coreserver.request_handler.handle_message(message)
coretlv.handle_message(message)
all_links = []
for node_id in coreserver.session.nodes:
node = coreserver.session.nodes[node_id]
for node_id in coretlv.session.nodes:
node = coretlv.session.nodes[node_id]
all_links += node.all_link_data(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
coreserver.session.add_node(_id=node_one)
coretlv.session.add_node(_id=node_one)
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")
interface_one = ip_prefix.addr(node_one)
message = coreapi.CoreLinkMessage.create(
@ -277,8 +277,8 @@ class TestGui:
(LinkTlvs.INTERFACE1_IP4_MASK, 24),
],
)
coreserver.request_handler.handle_message(message)
switch_node = coreserver.session.get_node(switch)
coretlv.handle_message(message)
switch_node = coretlv.session.get_node(switch)
all_links = switch_node.all_link_data(0)
assert len(all_links) == 1
@ -290,17 +290,17 @@ class TestGui:
(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)
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
coreserver.session.add_node(_id=node_one)
coretlv.session.add_node(_id=node_one)
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")
interface_one = ip_prefix.addr(node_one)
message = coreapi.CoreLinkMessage.create(
@ -313,8 +313,8 @@ class TestGui:
(LinkTlvs.INTERFACE1_IP4_MASK, 24),
],
)
coreserver.request_handler.handle_message(message)
switch_node = coreserver.session.get_node(switch)
coretlv.handle_message(message)
switch_node = coretlv.session.get_node(switch)
all_links = switch_node.all_link_data(0)
assert len(all_links) == 1
@ -326,58 +326,58 @@ class TestGui:
(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)
assert len(all_links) == 0
def test_session_update(self, coreserver):
session_id = coreserver.session.id
def test_session_update(self, coretlv):
session_id = coretlv.session.id
name = "test"
message = coreapi.CoreSessionMessage.create(
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):
coreserver.request_handler.dispatch_replies = mock.MagicMock()
def test_session_query(self, coretlv):
coretlv.dispatch_replies = mock.MagicMock()
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]
assert len(replies) == 1
def test_session_join(self, coreserver):
coreserver.request_handler.dispatch_replies = mock.MagicMock()
session_id = coreserver.session.id
def test_session_join(self, coretlv):
coretlv.dispatch_replies = mock.MagicMock()
session_id = coretlv.session.id
message = coreapi.CoreSessionMessage.create(
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):
assert len(coreserver.server.coreemu.sessions) == 1
session_id = coreserver.session.id
def test_session_delete(self, coretlv):
assert len(coretlv.coreemu.sessions) == 1
session_id = coretlv.session.id
message = coreapi.CoreSessionMessage.create(
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
assert coreserver.session._hooks.get(state) is None
assert coretlv.session._hooks.get(state) is None
file_name = "test.sh"
file_data = "echo hello"
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
name, data = hooks[0]
assert file_name == name
assert file_data == data
def test_file_service_file_set(self, coreserver):
node = coreserver.session.add_node()
def test_file_service_file_set(self, coretlv):
node = coretlv.session.add_node()
service = "DefaultRoute"
file_name = "defaultroute.sh"
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
)
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"
node = coreserver.session.add_node()
node = coretlv.session.add_node()
node.makenodedir()
file_data = "echo hello"
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)
created_directory = directory[1:].replace("/", ".")
create_path = os.path.join(node.nodedir, created_directory, basename)
assert os.path.exists(create_path)
if not request.config.getoption("mock"):
directory, basename = os.path.split(file_name)
created_directory = directory[1:].replace("/", ".")
create_path = os.path.join(node.nodedir, created_directory, basename)
assert os.path.exists(create_path)
def test_exec_node_tty(self, coreserver):
coreserver.request_handler.dispatch_replies = mock.MagicMock()
node = coreserver.session.add_node()
node.startup()
def test_exec_node_tty(self, coretlv):
coretlv.dispatch_replies = mock.MagicMock()
node = coretlv.session.add_node()
message = coreapi.CoreExecMessage.create(
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]
assert len(replies) == 1
def test_exec_local_command(self, coreserver):
coreserver.request_handler.dispatch_replies = mock.MagicMock()
node = coreserver.session.add_node()
node.startup()
def test_exec_local_command(self, request, coretlv):
if request.config.getoption("mock"):
pytest.skip("mocking calls")
coretlv.dispatch_replies = mock.MagicMock()
node = coretlv.session.add_node()
cmd = "echo hello"
message = coreapi.CoreExecMessage.create(
MessageFlags.TEXT.value | MessageFlags.LOCAL.value,
[
(ExecuteTlvs.NODE, node.id),
(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]
assert len(replies) == 1
def test_exec_node_command(self, coreserver):
coreserver.request_handler.dispatch_replies = mock.MagicMock()
node = coreserver.session.add_node()
node.startup()
def test_exec_node_command(self, coretlv):
coretlv.dispatch_replies = mock.MagicMock()
node = coretlv.session.add_node()
cmd = "echo hello"
message = coreapi.CoreExecMessage.create(
MessageFlags.TEXT.value,
[
(ExecuteTlvs.NODE, node.id),
(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
replies = args[0]
assert len(replies) == 1
node.cmd.assert_called_with(cmd)
@pytest.mark.parametrize(
"state",
@ -507,16 +509,16 @@ class TestGui:
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)])
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):
coreserver.session.add_event = mock.MagicMock()
node = coreserver.session.add_node()
def test_event_schedule(self, coretlv):
coretlv.session.add_event = mock.MagicMock()
node = coretlv.session.add_node()
message = coreapi.CoreEventMessage.create(
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):
xml_file = tmpdir.join("session.xml")
def test_event_save_xml(self, coretlv, tmpdir):
xml_file = tmpdir.join("coretlv.session.xml")
file_path = xml_file.strpath
coreserver.session.add_node()
coretlv.session.add_node()
message = coreapi.CoreEventMessage.create(
0,
[(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)
def test_event_open_xml(self, coreserver, tmpdir):
xml_file = tmpdir.join("session.xml")
def test_event_open_xml(self, coretlv, tmpdir):
xml_file = tmpdir.join("coretlv.session.xml")
file_path = xml_file.strpath
node = coreserver.session.add_node()
coreserver.session.save_xml(file_path)
coreserver.session.delete_node(node.id)
node = coretlv.session.add_node()
coretlv.session.save_xml(file_path)
coretlv.session.delete_node(node.id)
message = coreapi.CoreEventMessage.create(
0,
[(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(
"state",
@ -570,10 +572,9 @@ class TestGui:
EventTypes.RECONFIGURE,
],
)
def test_event_service(self, coreserver, state):
coreserver.session.broadcast_event = mock.MagicMock()
node = coreserver.session.add_node()
node.startup()
def test_event_service(self, coretlv, state):
coretlv.session.broadcast_event = mock.MagicMock()
node = coretlv.session.add_node()
message = coreapi.CoreEventMessage.create(
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(
"state",
@ -597,69 +598,60 @@ class TestGui:
EventTypes.RECONFIGURE,
],
)
def test_event_mobility(self, coreserver, state):
def test_event_mobility(self, coretlv, state):
message = coreapi.CoreEventMessage.create(
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):
coreserver.request_handler.master = False
def test_register_gui(self, coretlv):
message = coreapi.CoreRegMessage.create(0, [(RegisterTlvs.GUI, "gui")])
coretlv.handle_message(message)
coreserver.request_handler.handle_message(message)
assert coreserver.request_handler.master is True
def test_register_xml(self, coreserver, tmpdir):
xml_file = tmpdir.join("session.xml")
def test_register_xml(self, coretlv, tmpdir):
xml_file = tmpdir.join("coretlv.session.xml")
file_path = xml_file.strpath
node = coreserver.session.add_node()
coreserver.session.save_xml(file_path)
coreserver.session.delete_node(node.id)
node = coretlv.session.add_node()
coretlv.session.save_xml(file_path)
coretlv.session.delete_node(node.id)
message = coreapi.CoreRegMessage.create(
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")
file_path = xml_file.strpath
with open(file_path, "w") as f:
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")
message = coreapi.CoreRegMessage.create(
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):
node = coreserver.session.add_node()
def test_config_all(self, coretlv):
message = coreapi.CoreConfMessage.create(
MessageFlags.ADD.value,
[
(ConfigTlvs.OBJECT, "all"),
(ConfigTlvs.NODE, node.id),
(ConfigTlvs.TYPE, ConfigFlags.RESET.value),
],
[(ConfigTlvs.OBJECT, "all"), (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(
0,
[
@ -667,13 +659,13 @@ class TestGui:
(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_value = "test"
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(
0,
[
@ -698,13 +690,13 @@ class TestGui:
(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(
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 coreserver.session.location.refgeo == (70, 50, 0)
assert coreserver.session.location.refscale == 0.5
assert coretlv.session.location.refxyz == (10, 10, 0.0)
assert coretlv.session.location.refgeo == (70, 50, 0)
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(
0,
[
@ -728,13 +720,13 @@ class TestGui:
(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_value = "test"
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"
host = "10.0.0.1"
port = 50000
@ -763,13 +755,13 @@ class TestGui:
(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(
0,
[
@ -777,14 +769,14 @@ class TestGui:
(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):
node = coreserver.session.add_node()
def test_config_services_request_specific(self, coretlv):
node = coretlv.session.add_node()
message = coreapi.CoreConfMessage.create(
0,
[
@ -794,14 +786,14 @@ class TestGui:
(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):
node = coreserver.session.add_node()
def test_config_services_request_specific_file(self, coretlv):
node = coretlv.session.add_node()
message = coreapi.CoreConfMessage.create(
0,
[
@ -811,16 +803,16 @@ class TestGui:
(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):
node = coreserver.session.add_node()
def test_config_services_reset(self, coretlv):
node = coretlv.session.add_node()
service = "DefaultRoute"
coreserver.session.services.set_service(node.id, service)
coretlv.session.services.set_service(node.id, service)
message = coreapi.CoreConfMessage.create(
0,
[
@ -828,14 +820,14 @@ class TestGui:
(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):
node = coreserver.session.add_node()
def test_config_services_set(self, coretlv):
node = coretlv.session.add_node()
service = "DefaultRoute"
values = {"meta": "metadata"}
message = coreapi.CoreConfMessage.create(
@ -848,14 +840,14 @@ class TestGui:
(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):
wlan = coreserver.session.add_node(_type=NodeTypes.WIRELESS_LAN)
def test_config_mobility_reset(self, coretlv):
wlan = coretlv.session.add_node(_type=NodeTypes.WIRELESS_LAN)
message = coreapi.CoreConfMessage.create(
0,
[
@ -863,15 +855,15 @@ class TestGui:
(ConfigTlvs.TYPE, ConfigFlags.RESET.value),
],
)
coreserver.session.mobility.set_model_config(wlan.id, BasicRangeModel.name, {})
assert len(coreserver.session.mobility.node_configurations) == 1
coretlv.session.mobility.set_model_config(wlan.id, BasicRangeModel.name, {})
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):
wlan = coreserver.session.add_node(_type=NodeTypes.WIRELESS_LAN)
def test_config_mobility_model_request(self, coretlv):
wlan = coretlv.session.add_node(_type=NodeTypes.WIRELESS_LAN)
message = coreapi.CoreConfMessage.create(
0,
[
@ -880,14 +872,14 @@ class TestGui:
(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):
wlan = coreserver.session.add_node(_type=NodeTypes.WIRELESS_LAN)
def test_config_mobility_model_update(self, coretlv):
wlan = coretlv.session.add_node(_type=NodeTypes.WIRELESS_LAN)
config_key = "range"
config_value = "1000"
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
)
assert config[config_key] == config_value
def test_config_emane_model_request(self, coreserver):
wlan = coreserver.session.add_node(_type=NodeTypes.WIRELESS_LAN)
def test_config_emane_model_request(self, coretlv):
wlan = coretlv.session.add_node(_type=NodeTypes.WIRELESS_LAN)
message = coreapi.CoreConfMessage.create(
0,
[
@ -918,14 +910,14 @@ class TestGui:
(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):
wlan = coreserver.session.add_node(_type=NodeTypes.WIRELESS_LAN)
def test_config_emane_model_update(self, coretlv):
wlan = coretlv.session.add_node(_type=NodeTypes.WIRELESS_LAN)
config_key = "distance"
config_value = "50051"
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
)
assert config[config_key] == config_value
def test_config_emane_request(self, coreserver):
def test_config_emane_request(self, coretlv):
message = coreapi.CoreConfMessage.create(
0,
[
@ -954,13 +946,13 @@ class TestGui:
(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_value = "eth4"
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

View file

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

View file

@ -1,7 +1,9 @@
import os
import pytest
from mock import MagicMock
from core.errors import CoreCommandError
from core.services.coreservices import CoreService, ServiceDependencies, ServiceManager
_PATH = os.path.abspath(os.path.dirname(__file__))
@ -88,7 +90,7 @@ class TestServices:
assert node.services
assert len(node.services) == total_service + 2
def test_service_file(self, session):
def test_service_file(self, request, session):
# given
ServiceManager.add_services(_SERVICES_PATH)
my_service = ServiceManager.get(SERVICE_ONE)
@ -100,7 +102,8 @@ class TestServices:
session.services.create_service_files(node, my_service)
# 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):
# given
@ -121,6 +124,7 @@ class TestServices:
my_service = ServiceManager.get(SERVICE_TWO)
node = session.add_node()
session.services.create_service_files(node, my_service)
node.cmd = MagicMock(side_effect=CoreCommandError(-1, "invalid"))
# when
status = session.services.validate_service(node, my_service)
@ -147,6 +151,7 @@ class TestServices:
my_service = ServiceManager.get(SERVICE_TWO)
node = session.add_node()
session.services.create_service_files(node, my_service)
node.cmd = MagicMock(side_effect=CoreCommandError(-1, "invalid"))
# when
status = session.services.startup_service(node, my_service, wait=True)
@ -173,6 +178,7 @@ class TestServices:
my_service = ServiceManager.get(SERVICE_TWO)
node = session.add_node()
session.services.create_service_files(node, my_service)
node.cmd = MagicMock(side_effect=CoreCommandError(-1, "invalid"))
# when
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)
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):
"""
Test importing a custom service.

View file

@ -108,8 +108,8 @@ class TestXml:
ptp_node = session.add_node(_type=NodeTypes.PEER_TO_PEER)
# create nodes
node_options = NodeOptions(model="host")
node_one = session.add_node(node_options=node_options)
options = NodeOptions(model="host")
node_one = session.add_node(options=options)
node_two = session.add_node()
# link nodes to ptp net
@ -174,10 +174,10 @@ class TestXml:
session.mobility.set_model(wlan_node, BasicRangeModel, {"test": "1"})
# create nodes
node_options = NodeOptions()
node_options.set_position(0, 0)
node_one = session.create_wireless_node(node_options=node_options)
node_two = session.create_wireless_node(node_options=node_options)
options = NodeOptions(model="mdr")
options.set_position(0, 0)
node_one = session.add_node(options=options)
node_two = session.add_node(options=options)
# link nodes
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
coreemu = CoreEmu()
session = coreemu.create_session()
emane_network = session.create_emane_network(
model=EmaneIeee80211abgModel,
geo_reference=(47.57917, -122.13232, 2.00000)
)
emane_network.setposition(x=80, y=50)
session.set_location(47.57917, -122.13232, 2.00000, 1.0)
options = NodeOptions()
options.set_position(80, 50)
emane_network = session.add_node(_type=NodeTypes.EMANE, options=options)
# set custom emane model 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):
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)
netif = self.netif(ifindex)
netif.sethwaddr(hwaddr)
@ -68,7 +68,7 @@ class CoreNs3Node(CoreNode, ns.network.Node):
netif.addaddr(addr)
addrstr = netif.addrlist[0]
(addr, mask) = addrstr.split('/')
addr, mask = addrstr.split('/')
tap = net._tapdevs[netif]
tap.SetAttribute(
"IpAddress",
@ -76,9 +76,9 @@ class CoreNs3Node(CoreNode, ns.network.Node):
)
tap.SetAttribute(
"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
def getns3position(self):
@ -118,7 +118,7 @@ class CoreNs3Net(CoreNetworkBase):
type = "wlan"
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)
self.tapbridge = ns.tap_bridge.TapBridgeHelper()