daemon: removing python tlv related code and tests related to it
This commit is contained in:
parent
dc7bb37252
commit
c8a589ef76
29 changed files with 29 additions and 5439 deletions
|
@ -1,9 +1,5 @@
|
||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
#
|
#
|
||||||
# (c)2010-2012 the Boeing Company
|
|
||||||
#
|
|
||||||
# author: Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
|
|
||||||
#
|
|
||||||
# Bootstrap the autoconf system.
|
# Bootstrap the autoconf system.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
# CORE
|
# CORE
|
||||||
# (c)2010-2012 the Boeing Company.
|
|
||||||
# See the LICENSE file included in this distribution.
|
|
||||||
#
|
|
||||||
# author: Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
|
|
||||||
#
|
#
|
||||||
# Makefile for building netns components.
|
# Makefile for building netns components.
|
||||||
#
|
#
|
||||||
|
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,60 +0,0 @@
|
||||||
"""
|
|
||||||
Defines core server for handling TCP connections.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import socketserver
|
|
||||||
|
|
||||||
from core.emulator.coreemu import CoreEmu
|
|
||||||
|
|
||||||
|
|
||||||
class CoreServer(socketserver.ThreadingMixIn, socketserver.TCPServer):
|
|
||||||
"""
|
|
||||||
TCP server class, manages sessions and spawns request handlers for
|
|
||||||
incoming connections.
|
|
||||||
"""
|
|
||||||
|
|
||||||
daemon_threads = True
|
|
||||||
allow_reuse_address = True
|
|
||||||
|
|
||||||
def __init__(self, server_address, handler_class, config=None):
|
|
||||||
"""
|
|
||||||
Server class initialization takes configuration data and calls
|
|
||||||
the socketserver constructor.
|
|
||||||
|
|
||||||
:param tuple[str, int] server_address: server host and port to use
|
|
||||||
:param class handler_class: request handler
|
|
||||||
:param dict config: configuration setting
|
|
||||||
"""
|
|
||||||
self.coreemu = CoreEmu(config)
|
|
||||||
self.config = config
|
|
||||||
socketserver.TCPServer.__init__(self, server_address, handler_class)
|
|
||||||
|
|
||||||
|
|
||||||
class CoreUdpServer(socketserver.ThreadingMixIn, socketserver.UDPServer):
|
|
||||||
"""
|
|
||||||
UDP server class, manages sessions and spawns request handlers for
|
|
||||||
incoming connections.
|
|
||||||
"""
|
|
||||||
|
|
||||||
daemon_threads = True
|
|
||||||
allow_reuse_address = True
|
|
||||||
|
|
||||||
def __init__(self, server_address, handler_class, mainserver):
|
|
||||||
"""
|
|
||||||
Server class initialization takes configuration data and calls
|
|
||||||
the SocketServer constructor
|
|
||||||
|
|
||||||
:param server_address:
|
|
||||||
:param class handler_class: request handler
|
|
||||||
:param mainserver:
|
|
||||||
"""
|
|
||||||
self.mainserver = mainserver
|
|
||||||
socketserver.UDPServer.__init__(self, server_address, handler_class)
|
|
||||||
|
|
||||||
def start(self):
|
|
||||||
"""
|
|
||||||
Thread target to run concurrently with the TCP server.
|
|
||||||
|
|
||||||
:return: nothing
|
|
||||||
"""
|
|
||||||
self.serve_forever()
|
|
|
@ -1,178 +0,0 @@
|
||||||
"""
|
|
||||||
Converts CORE data objects into legacy API messages.
|
|
||||||
"""
|
|
||||||
import logging
|
|
||||||
from collections import OrderedDict
|
|
||||||
from typing import Dict, List
|
|
||||||
|
|
||||||
from core.api.tlv import coreapi, structutils
|
|
||||||
from core.api.tlv.enumerations import ConfigTlvs, NodeTlvs
|
|
||||||
from core.config import ConfigGroup, ConfigurableOptions
|
|
||||||
from core.emulator.data import ConfigData, NodeData
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
def convert_node(node_data: NodeData):
|
|
||||||
"""
|
|
||||||
Convenience method for converting NodeData to a packed TLV message.
|
|
||||||
|
|
||||||
:param core.emulator.data.NodeData node_data: node data to convert
|
|
||||||
:return: packed node message
|
|
||||||
"""
|
|
||||||
node = node_data.node
|
|
||||||
services = None
|
|
||||||
if node.services is not None:
|
|
||||||
services = "|".join([x.name for x in node.services])
|
|
||||||
server = None
|
|
||||||
if node.server is not None:
|
|
||||||
server = node.server.name
|
|
||||||
tlv_data = structutils.pack_values(
|
|
||||||
coreapi.CoreNodeTlv,
|
|
||||||
[
|
|
||||||
(NodeTlvs.NUMBER, node.id),
|
|
||||||
(NodeTlvs.TYPE, node.apitype.value),
|
|
||||||
(NodeTlvs.NAME, node.name),
|
|
||||||
(NodeTlvs.MODEL, node.type),
|
|
||||||
(NodeTlvs.EMULATION_SERVER, server),
|
|
||||||
(NodeTlvs.X_POSITION, int(node.position.x)),
|
|
||||||
(NodeTlvs.Y_POSITION, int(node.position.y)),
|
|
||||||
(NodeTlvs.CANVAS, node.canvas),
|
|
||||||
(NodeTlvs.SERVICES, services),
|
|
||||||
(NodeTlvs.LATITUDE, str(node.position.lat)),
|
|
||||||
(NodeTlvs.LONGITUDE, str(node.position.lon)),
|
|
||||||
(NodeTlvs.ALTITUDE, str(node.position.alt)),
|
|
||||||
(NodeTlvs.ICON, node.icon),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
return coreapi.CoreNodeMessage.pack(node_data.message_type.value, tlv_data)
|
|
||||||
|
|
||||||
|
|
||||||
def convert_config(config_data):
|
|
||||||
"""
|
|
||||||
Convenience method for converting ConfigData to a packed TLV message.
|
|
||||||
|
|
||||||
:param core.emulator.data.ConfigData config_data: config data to convert
|
|
||||||
:return: packed message
|
|
||||||
"""
|
|
||||||
session = None
|
|
||||||
if config_data.session is not None:
|
|
||||||
session = str(config_data.session)
|
|
||||||
tlv_data = structutils.pack_values(
|
|
||||||
coreapi.CoreConfigTlv,
|
|
||||||
[
|
|
||||||
(ConfigTlvs.NODE, config_data.node),
|
|
||||||
(ConfigTlvs.OBJECT, config_data.object),
|
|
||||||
(ConfigTlvs.TYPE, config_data.type),
|
|
||||||
(ConfigTlvs.DATA_TYPES, config_data.data_types),
|
|
||||||
(ConfigTlvs.VALUES, config_data.data_values),
|
|
||||||
(ConfigTlvs.CAPTIONS, config_data.captions),
|
|
||||||
(ConfigTlvs.BITMAP, config_data.bitmap),
|
|
||||||
(ConfigTlvs.POSSIBLE_VALUES, config_data.possible_values),
|
|
||||||
(ConfigTlvs.GROUPS, config_data.groups),
|
|
||||||
(ConfigTlvs.SESSION, session),
|
|
||||||
(ConfigTlvs.IFACE_ID, config_data.iface_id),
|
|
||||||
(ConfigTlvs.NETWORK_ID, config_data.network_id),
|
|
||||||
(ConfigTlvs.OPAQUE, config_data.opaque),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
return coreapi.CoreConfMessage.pack(config_data.message_type, tlv_data)
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigShim:
|
|
||||||
"""
|
|
||||||
Provides helper methods for converting newer configuration values into TLV
|
|
||||||
compatible formats.
|
|
||||||
"""
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def str_to_dict(cls, key_values: str) -> Dict[str, str]:
|
|
||||||
"""
|
|
||||||
Converts a TLV key/value string into an ordered mapping.
|
|
||||||
|
|
||||||
:param key_values:
|
|
||||||
:return: ordered mapping of key/value pairs
|
|
||||||
"""
|
|
||||||
key_values = key_values.split("|")
|
|
||||||
values = OrderedDict()
|
|
||||||
for key_value in key_values:
|
|
||||||
key, value = key_value.split("=", 1)
|
|
||||||
values[key] = value
|
|
||||||
return values
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def groups_to_str(cls, config_groups: List[ConfigGroup]) -> str:
|
|
||||||
"""
|
|
||||||
Converts configuration groups to a TLV formatted string.
|
|
||||||
|
|
||||||
:param config_groups: configuration groups to format
|
|
||||||
:return: TLV configuration group string
|
|
||||||
"""
|
|
||||||
group_strings = []
|
|
||||||
for config_group in config_groups:
|
|
||||||
group_string = (
|
|
||||||
f"{config_group.name}:{config_group.start}-{config_group.stop}"
|
|
||||||
)
|
|
||||||
group_strings.append(group_string)
|
|
||||||
return "|".join(group_strings)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def config_data(
|
|
||||||
cls,
|
|
||||||
flags: int,
|
|
||||||
node_id: int,
|
|
||||||
type_flags: int,
|
|
||||||
configurable_options: ConfigurableOptions,
|
|
||||||
config: Dict[str, str],
|
|
||||||
) -> ConfigData:
|
|
||||||
"""
|
|
||||||
Convert this class to a Config API message. Some TLVs are defined
|
|
||||||
by the class, but node number, conf type flags, and values must
|
|
||||||
be passed in.
|
|
||||||
|
|
||||||
:param flags: message flags
|
|
||||||
:param node_id: node id
|
|
||||||
:param type_flags: type flags
|
|
||||||
:param configurable_options: options to create config data for
|
|
||||||
:param config: configuration values for options
|
|
||||||
:return: configuration data object
|
|
||||||
"""
|
|
||||||
key_values = None
|
|
||||||
captions = None
|
|
||||||
data_types = []
|
|
||||||
possible_values = []
|
|
||||||
logger.debug("configurable: %s", configurable_options)
|
|
||||||
logger.debug("configuration options: %s", configurable_options.configurations)
|
|
||||||
logger.debug("configuration data: %s", config)
|
|
||||||
for configuration in configurable_options.configurations():
|
|
||||||
if not captions:
|
|
||||||
captions = configuration.label
|
|
||||||
else:
|
|
||||||
captions += f"|{configuration.label}"
|
|
||||||
|
|
||||||
data_types.append(configuration.type.value)
|
|
||||||
|
|
||||||
options = ",".join(configuration.options)
|
|
||||||
possible_values.append(options)
|
|
||||||
|
|
||||||
_id = configuration.id
|
|
||||||
config_value = config.get(_id, configuration.default)
|
|
||||||
key_value = f"{_id}={config_value}"
|
|
||||||
if not key_values:
|
|
||||||
key_values = key_value
|
|
||||||
else:
|
|
||||||
key_values += f"|{key_value}"
|
|
||||||
|
|
||||||
groups_str = cls.groups_to_str(configurable_options.config_groups())
|
|
||||||
return ConfigData(
|
|
||||||
message_type=flags,
|
|
||||||
node=node_id,
|
|
||||||
object=configurable_options.name,
|
|
||||||
type=type_flags,
|
|
||||||
data_types=tuple(data_types),
|
|
||||||
data_values=key_values,
|
|
||||||
captions=captions,
|
|
||||||
possible_values="|".join(possible_values),
|
|
||||||
bitmap=configurable_options.bitmap,
|
|
||||||
groups=groups_str,
|
|
||||||
)
|
|
|
@ -1,212 +0,0 @@
|
||||||
"""
|
|
||||||
Enumerations specific to the CORE TLV API.
|
|
||||||
"""
|
|
||||||
from enum import Enum
|
|
||||||
|
|
||||||
CORE_API_PORT = 4038
|
|
||||||
|
|
||||||
|
|
||||||
class MessageTypes(Enum):
|
|
||||||
"""
|
|
||||||
CORE message types.
|
|
||||||
"""
|
|
||||||
|
|
||||||
NODE = 0x01
|
|
||||||
LINK = 0x02
|
|
||||||
EXECUTE = 0x03
|
|
||||||
REGISTER = 0x04
|
|
||||||
CONFIG = 0x05
|
|
||||||
FILE = 0x06
|
|
||||||
INTERFACE = 0x07
|
|
||||||
EVENT = 0x08
|
|
||||||
SESSION = 0x09
|
|
||||||
EXCEPTION = 0x0A
|
|
||||||
|
|
||||||
|
|
||||||
class NodeTlvs(Enum):
|
|
||||||
"""
|
|
||||||
Node type, length, value enumerations.
|
|
||||||
"""
|
|
||||||
|
|
||||||
NUMBER = 0x01
|
|
||||||
TYPE = 0x02
|
|
||||||
NAME = 0x03
|
|
||||||
IP_ADDRESS = 0x04
|
|
||||||
MAC_ADDRESS = 0x05
|
|
||||||
IP6_ADDRESS = 0x06
|
|
||||||
MODEL = 0x07
|
|
||||||
EMULATION_SERVER = 0x08
|
|
||||||
SESSION = 0x0A
|
|
||||||
X_POSITION = 0x20
|
|
||||||
Y_POSITION = 0x21
|
|
||||||
CANVAS = 0x22
|
|
||||||
EMULATION_ID = 0x23
|
|
||||||
NETWORK_ID = 0x24
|
|
||||||
SERVICES = 0x25
|
|
||||||
LATITUDE = 0x30
|
|
||||||
LONGITUDE = 0x31
|
|
||||||
ALTITUDE = 0x32
|
|
||||||
ICON = 0x42
|
|
||||||
OPAQUE = 0x50
|
|
||||||
|
|
||||||
|
|
||||||
class LinkTlvs(Enum):
|
|
||||||
"""
|
|
||||||
Link type, length, value enumerations.
|
|
||||||
"""
|
|
||||||
|
|
||||||
N1_NUMBER = 0x01
|
|
||||||
N2_NUMBER = 0x02
|
|
||||||
DELAY = 0x03
|
|
||||||
BANDWIDTH = 0x04
|
|
||||||
LOSS = 0x05
|
|
||||||
DUP = 0x06
|
|
||||||
JITTER = 0x07
|
|
||||||
MER = 0x08
|
|
||||||
BURST = 0x09
|
|
||||||
SESSION = 0x0A
|
|
||||||
MBURST = 0x10
|
|
||||||
TYPE = 0x20
|
|
||||||
GUI_ATTRIBUTES = 0x21
|
|
||||||
UNIDIRECTIONAL = 0x22
|
|
||||||
EMULATION_ID = 0x23
|
|
||||||
NETWORK_ID = 0x24
|
|
||||||
KEY = 0x25
|
|
||||||
IFACE1_NUMBER = 0x30
|
|
||||||
IFACE1_IP4 = 0x31
|
|
||||||
IFACE1_IP4_MASK = 0x32
|
|
||||||
IFACE1_MAC = 0x33
|
|
||||||
IFACE1_IP6 = 0x34
|
|
||||||
IFACE1_IP6_MASK = 0x35
|
|
||||||
IFACE2_NUMBER = 0x36
|
|
||||||
IFACE2_IP4 = 0x37
|
|
||||||
IFACE2_IP4_MASK = 0x38
|
|
||||||
IFACE2_MAC = 0x39
|
|
||||||
IFACE2_IP6 = 0x40
|
|
||||||
IFACE2_IP6_MASK = 0x41
|
|
||||||
IFACE1_NAME = 0x42
|
|
||||||
IFACE2_NAME = 0x43
|
|
||||||
OPAQUE = 0x50
|
|
||||||
|
|
||||||
|
|
||||||
class ExecuteTlvs(Enum):
|
|
||||||
"""
|
|
||||||
Execute type, length, value enumerations.
|
|
||||||
"""
|
|
||||||
|
|
||||||
NODE = 0x01
|
|
||||||
NUMBER = 0x02
|
|
||||||
TIME = 0x03
|
|
||||||
COMMAND = 0x04
|
|
||||||
RESULT = 0x05
|
|
||||||
STATUS = 0x06
|
|
||||||
SESSION = 0x0A
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigTlvs(Enum):
|
|
||||||
"""
|
|
||||||
Configuration type, length, value enumerations.
|
|
||||||
"""
|
|
||||||
|
|
||||||
NODE = 0x01
|
|
||||||
OBJECT = 0x02
|
|
||||||
TYPE = 0x03
|
|
||||||
DATA_TYPES = 0x04
|
|
||||||
VALUES = 0x05
|
|
||||||
CAPTIONS = 0x06
|
|
||||||
BITMAP = 0x07
|
|
||||||
POSSIBLE_VALUES = 0x08
|
|
||||||
GROUPS = 0x09
|
|
||||||
SESSION = 0x0A
|
|
||||||
IFACE_ID = 0x0B
|
|
||||||
NETWORK_ID = 0x24
|
|
||||||
OPAQUE = 0x50
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigFlags(Enum):
|
|
||||||
"""
|
|
||||||
Configuration flags.
|
|
||||||
"""
|
|
||||||
|
|
||||||
NONE = 0x00
|
|
||||||
REQUEST = 0x01
|
|
||||||
UPDATE = 0x02
|
|
||||||
RESET = 0x03
|
|
||||||
|
|
||||||
|
|
||||||
class FileTlvs(Enum):
|
|
||||||
"""
|
|
||||||
File type, length, value enumerations.
|
|
||||||
"""
|
|
||||||
|
|
||||||
NODE = 0x01
|
|
||||||
NAME = 0x02
|
|
||||||
MODE = 0x03
|
|
||||||
NUMBER = 0x04
|
|
||||||
TYPE = 0x05
|
|
||||||
SOURCE_NAME = 0x06
|
|
||||||
SESSION = 0x0A
|
|
||||||
DATA = 0x10
|
|
||||||
COMPRESSED_DATA = 0x11
|
|
||||||
|
|
||||||
|
|
||||||
class InterfaceTlvs(Enum):
|
|
||||||
"""
|
|
||||||
Interface type, length, value enumerations.
|
|
||||||
"""
|
|
||||||
|
|
||||||
NODE = 0x01
|
|
||||||
NUMBER = 0x02
|
|
||||||
NAME = 0x03
|
|
||||||
IP_ADDRESS = 0x04
|
|
||||||
MASK = 0x05
|
|
||||||
MAC_ADDRESS = 0x06
|
|
||||||
IP6_ADDRESS = 0x07
|
|
||||||
IP6_MASK = 0x08
|
|
||||||
TYPE = 0x09
|
|
||||||
SESSION = 0x0A
|
|
||||||
STATE = 0x0B
|
|
||||||
EMULATION_ID = 0x23
|
|
||||||
NETWORK_ID = 0x24
|
|
||||||
|
|
||||||
|
|
||||||
class EventTlvs(Enum):
|
|
||||||
"""
|
|
||||||
Event type, length, value enumerations.
|
|
||||||
"""
|
|
||||||
|
|
||||||
NODE = 0x01
|
|
||||||
TYPE = 0x02
|
|
||||||
NAME = 0x03
|
|
||||||
DATA = 0x04
|
|
||||||
TIME = 0x05
|
|
||||||
SESSION = 0x0A
|
|
||||||
|
|
||||||
|
|
||||||
class SessionTlvs(Enum):
|
|
||||||
"""
|
|
||||||
Session type, length, value enumerations.
|
|
||||||
"""
|
|
||||||
|
|
||||||
NUMBER = 0x01
|
|
||||||
NAME = 0x02
|
|
||||||
FILE = 0x03
|
|
||||||
NODE_COUNT = 0x04
|
|
||||||
DATE = 0x05
|
|
||||||
THUMB = 0x06
|
|
||||||
USER = 0x07
|
|
||||||
OPAQUE = 0x0A
|
|
||||||
|
|
||||||
|
|
||||||
class ExceptionTlvs(Enum):
|
|
||||||
"""
|
|
||||||
Exception type, length, value enumerations.
|
|
||||||
"""
|
|
||||||
|
|
||||||
NODE = 0x01
|
|
||||||
SESSION = 0x02
|
|
||||||
LEVEL = 0x03
|
|
||||||
SOURCE = 0x04
|
|
||||||
DATE = 0x05
|
|
||||||
TEXT = 0x06
|
|
||||||
OPAQUE = 0x0A
|
|
|
@ -1,45 +0,0 @@
|
||||||
"""
|
|
||||||
Utilities for working with python struct data.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import logging
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
|
|
||||||
def pack_values(clazz, packers):
|
|
||||||
"""
|
|
||||||
Pack values for a given legacy class.
|
|
||||||
|
|
||||||
:param class clazz: class that will provide a pack method
|
|
||||||
:param list packers: a list of tuples that are used to pack values and transform them
|
|
||||||
:return: packed data string of all values
|
|
||||||
"""
|
|
||||||
|
|
||||||
# iterate through tuples of values to pack
|
|
||||||
logger.debug("packing: %s", packers)
|
|
||||||
data = b""
|
|
||||||
for packer in packers:
|
|
||||||
# check if a transformer was provided for valid values
|
|
||||||
transformer = None
|
|
||||||
if len(packer) == 2:
|
|
||||||
tlv_type, value = packer
|
|
||||||
elif len(packer) == 3:
|
|
||||||
tlv_type, value, transformer = packer
|
|
||||||
else:
|
|
||||||
raise RuntimeError("packer had more than 3 arguments")
|
|
||||||
|
|
||||||
# only pack actual values and avoid packing empty strings
|
|
||||||
# protobuf defaults to empty strings and does no imply a value to set
|
|
||||||
if value is None or (isinstance(value, str) and not value):
|
|
||||||
continue
|
|
||||||
|
|
||||||
# transform values as needed
|
|
||||||
if transformer:
|
|
||||||
value = transformer(value)
|
|
||||||
|
|
||||||
# pack and add to existing data
|
|
||||||
logger.debug("packing: %s - %s type(%s)", tlv_type, value, type(value))
|
|
||||||
data += clazz.pack(tlv_type.value, value)
|
|
||||||
|
|
||||||
return data
|
|
|
@ -20,6 +20,17 @@ class MessageFlags(Enum):
|
||||||
TTY = 0x40
|
TTY = 0x40
|
||||||
|
|
||||||
|
|
||||||
|
class ConfigFlags(Enum):
|
||||||
|
"""
|
||||||
|
Configuration flags.
|
||||||
|
"""
|
||||||
|
|
||||||
|
NONE = 0x00
|
||||||
|
REQUEST = 0x01
|
||||||
|
UPDATE = 0x02
|
||||||
|
RESET = 0x03
|
||||||
|
|
||||||
|
|
||||||
class NodeTypes(Enum):
|
class NodeTypes(Enum):
|
||||||
"""
|
"""
|
||||||
Node types.
|
Node types.
|
||||||
|
|
|
@ -1007,15 +1007,14 @@ class Session:
|
||||||
env["SESSION_STATE"] = str(self.state)
|
env["SESSION_STATE"] = str(self.state)
|
||||||
# try reading and merging optional environments from:
|
# try reading and merging optional environments from:
|
||||||
# /etc/core/environment
|
# /etc/core/environment
|
||||||
# /home/user/.core/environment
|
# /home/user/.coregui/environment
|
||||||
# /tmp/pycore.<session id>/environment
|
# /tmp/pycore.<session id>/environment
|
||||||
core_env_path = constants.CORE_CONF_DIR / "environment"
|
core_env_path = constants.CORE_CONF_DIR / "environment"
|
||||||
session_env_path = self.directory / "environment"
|
session_env_path = self.directory / "environment"
|
||||||
if self.user:
|
if self.user:
|
||||||
user_home_path = Path(f"~{self.user}").expanduser()
|
user_home_path = Path(f"~{self.user}").expanduser()
|
||||||
user_env1 = user_home_path / ".core" / "environment"
|
user_env = user_home_path / ".coregui" / "environment"
|
||||||
user_env2 = user_home_path / ".coregui" / "environment"
|
paths = [core_env_path, user_env, session_env_path]
|
||||||
paths = [core_env_path, user_env1, user_env2, session_env_path]
|
|
||||||
else:
|
else:
|
||||||
paths = [core_env_path, session_env_path]
|
paths = [core_env_path, session_env_path]
|
||||||
for path in paths:
|
for path in paths:
|
||||||
|
|
|
@ -716,8 +716,7 @@ class PtpNet(CoreNetwork):
|
||||||
|
|
||||||
def links(self, flags: MessageFlags = MessageFlags.NONE) -> List[LinkData]:
|
def links(self, flags: MessageFlags = MessageFlags.NONE) -> List[LinkData]:
|
||||||
"""
|
"""
|
||||||
Build CORE API TLVs for a point-to-point link. One Link message
|
Get peer to peer link.
|
||||||
describes this network.
|
|
||||||
|
|
||||||
:param flags: message flags
|
:param flags: message flags
|
||||||
:return: list of link data
|
:return: list of link data
|
||||||
|
|
|
@ -109,114 +109,6 @@ class ServiceDependencies:
|
||||||
return self.boot_paths
|
return self.boot_paths
|
||||||
|
|
||||||
|
|
||||||
class ServiceShim:
|
|
||||||
keys: List[str] = [
|
|
||||||
"dirs",
|
|
||||||
"files",
|
|
||||||
"startidx",
|
|
||||||
"cmdup",
|
|
||||||
"cmddown",
|
|
||||||
"cmdval",
|
|
||||||
"meta",
|
|
||||||
"starttime",
|
|
||||||
]
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def tovaluelist(cls, node: CoreNode, service: "CoreService") -> str:
|
|
||||||
"""
|
|
||||||
Convert service properties into a string list of key=value pairs,
|
|
||||||
separated by "|".
|
|
||||||
|
|
||||||
:param node: node to get value list for
|
|
||||||
:param service: service to get value list for
|
|
||||||
:return: value list string
|
|
||||||
"""
|
|
||||||
start_time = 0
|
|
||||||
start_index = 0
|
|
||||||
valmap = [
|
|
||||||
service.dirs,
|
|
||||||
service.configs,
|
|
||||||
start_index,
|
|
||||||
service.startup,
|
|
||||||
service.shutdown,
|
|
||||||
service.validate,
|
|
||||||
service.meta,
|
|
||||||
start_time,
|
|
||||||
]
|
|
||||||
if not service.custom:
|
|
||||||
valmap[1] = service.get_configs(node)
|
|
||||||
valmap[3] = service.get_startup(node)
|
|
||||||
vals = ["%s=%s" % (x, y) for x, y in zip(cls.keys, valmap)]
|
|
||||||
return "|".join(vals)
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def fromvaluelist(cls, service: "CoreService", values: List[str]) -> None:
|
|
||||||
"""
|
|
||||||
Convert list of values into properties for this instantiated
|
|
||||||
(customized) service.
|
|
||||||
|
|
||||||
:param service: service to get value list for
|
|
||||||
:param values: value list to set properties from
|
|
||||||
:return: nothing
|
|
||||||
"""
|
|
||||||
# TODO: support empty value? e.g. override default meta with ''
|
|
||||||
for key in cls.keys:
|
|
||||||
try:
|
|
||||||
cls.setvalue(service, key, values[cls.keys.index(key)])
|
|
||||||
except IndexError:
|
|
||||||
# old config does not need to have new keys
|
|
||||||
logger.exception("error indexing into key")
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def setvalue(cls, service: "CoreService", key: str, value: str) -> None:
|
|
||||||
"""
|
|
||||||
Set values for this service.
|
|
||||||
|
|
||||||
:param service: service to get value list for
|
|
||||||
:param key: key to set value for
|
|
||||||
:param value: value of key to set
|
|
||||||
:return: nothing
|
|
||||||
"""
|
|
||||||
if key not in cls.keys:
|
|
||||||
raise ValueError("key `%s` not in `%s`" % (key, cls.keys))
|
|
||||||
# this handles data conversion to int, string, and tuples
|
|
||||||
if value:
|
|
||||||
if key == "startidx":
|
|
||||||
value = int(value)
|
|
||||||
elif key == "starttime":
|
|
||||||
value = float(value)
|
|
||||||
elif key == "meta":
|
|
||||||
value = str(value)
|
|
||||||
else:
|
|
||||||
value = utils.make_tuple_fromstr(value, str)
|
|
||||||
|
|
||||||
if key == "dirs":
|
|
||||||
service.dirs = value
|
|
||||||
elif key == "files":
|
|
||||||
service.configs = value
|
|
||||||
elif key == "cmdup":
|
|
||||||
service.startup = value
|
|
||||||
elif key == "cmddown":
|
|
||||||
service.shutdown = value
|
|
||||||
elif key == "cmdval":
|
|
||||||
service.validate = value
|
|
||||||
elif key == "meta":
|
|
||||||
service.meta = value
|
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def servicesfromopaque(cls, opaque: str) -> List[str]:
|
|
||||||
"""
|
|
||||||
Build a list of services from an opaque data string.
|
|
||||||
|
|
||||||
:param opaque: opaque data string
|
|
||||||
:return: services
|
|
||||||
"""
|
|
||||||
servicesstring = opaque.split(":")
|
|
||||||
if servicesstring[0] != "service":
|
|
||||||
return []
|
|
||||||
return servicesstring[1].split(",")
|
|
||||||
|
|
||||||
|
|
||||||
class ServiceManager:
|
class ServiceManager:
|
||||||
"""
|
"""
|
||||||
Manages services available for CORE nodes to use.
|
Manages services available for CORE nodes to use.
|
||||||
|
|
|
@ -1,7 +1,5 @@
|
||||||
[core-daemon]
|
[core-daemon]
|
||||||
#distributed_address = 127.0.0.1
|
#distributed_address = 127.0.0.1
|
||||||
listenaddr = localhost
|
|
||||||
port = 4038
|
|
||||||
grpcaddress = localhost
|
grpcaddress = localhost
|
||||||
grpcport = 50051
|
grpcport = 50051
|
||||||
quagga_bin_search = "/usr/local/bin /usr/bin /usr/lib/quagga"
|
quagga_bin_search = "/usr/local/bin /usr/bin /usr/lib/quagga"
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
# CORE
|
# CORE
|
||||||
# (c)2012 the Boeing Company.
|
|
||||||
# See the LICENSE file included in this distribution.
|
|
||||||
#
|
|
||||||
# author: Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
|
|
||||||
#
|
#
|
||||||
# Builds html and pdf documentation using Sphinx.
|
# Builds html and pdf documentation using Sphinx.
|
||||||
#
|
#
|
||||||
|
|
|
@ -8,19 +8,15 @@ message handlers are defined and some support for sending messages.
|
||||||
import argparse
|
import argparse
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import sys
|
|
||||||
import threading
|
|
||||||
import time
|
import time
|
||||||
from configparser import ConfigParser
|
from configparser import ConfigParser
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
|
|
||||||
from core import constants
|
from core import constants
|
||||||
from core.api.grpc.server import CoreGrpcServer
|
from core.api.grpc.server import CoreGrpcServer
|
||||||
from core.api.tlv.corehandlers import CoreHandler, CoreUdpHandler
|
|
||||||
from core.api.tlv.coreserver import CoreServer, CoreUdpServer
|
|
||||||
from core.api.tlv.enumerations import CORE_API_PORT
|
|
||||||
from core.constants import CORE_CONF_DIR, COREDPY_VERSION
|
from core.constants import CORE_CONF_DIR, COREDPY_VERSION
|
||||||
from core.utils import close_onexec, load_logging_config
|
from core.emulator.coreemu import CoreEmu
|
||||||
|
from core.utils import load_logging_config
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
@ -34,20 +30,6 @@ def banner():
|
||||||
logger.info("CORE daemon v.%s started %s", constants.COREDPY_VERSION, time.ctime())
|
logger.info("CORE daemon v.%s started %s", constants.COREDPY_VERSION, time.ctime())
|
||||||
|
|
||||||
|
|
||||||
def start_udp(mainserver, server_address):
|
|
||||||
"""
|
|
||||||
Start a thread running a UDP server on the same host,port for
|
|
||||||
connectionless requests.
|
|
||||||
|
|
||||||
:param CoreServer mainserver: main core tcp server to piggy back off of
|
|
||||||
:param server_address:
|
|
||||||
:return: CoreUdpServer
|
|
||||||
"""
|
|
||||||
mainserver.udpserver = CoreUdpServer(server_address, CoreUdpHandler, mainserver)
|
|
||||||
mainserver.udpthread = threading.Thread(target=mainserver.udpserver.start, daemon=True)
|
|
||||||
mainserver.udpthread.start()
|
|
||||||
|
|
||||||
|
|
||||||
def cored(cfg):
|
def cored(cfg):
|
||||||
"""
|
"""
|
||||||
Start the CoreServer object and enter the server loop.
|
Start the CoreServer object and enter the server loop.
|
||||||
|
@ -55,34 +37,13 @@ def cored(cfg):
|
||||||
:param dict cfg: core configuration
|
:param dict cfg: core configuration
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
host = cfg["listenaddr"]
|
|
||||||
port = int(cfg["port"])
|
|
||||||
if host == "" or host is None:
|
|
||||||
host = "localhost"
|
|
||||||
|
|
||||||
try:
|
|
||||||
address = (host, port)
|
|
||||||
server = CoreServer(address, CoreHandler, cfg)
|
|
||||||
except:
|
|
||||||
logger.exception("error starting main server on: %s:%s", host, port)
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# initialize grpc api
|
# initialize grpc api
|
||||||
grpc_server = CoreGrpcServer(server.coreemu)
|
coreemu = CoreEmu(cfg)
|
||||||
|
grpc_server = CoreGrpcServer(coreemu)
|
||||||
address_config = cfg["grpcaddress"]
|
address_config = cfg["grpcaddress"]
|
||||||
port_config = cfg["grpcport"]
|
port_config = cfg["grpcport"]
|
||||||
grpc_address = f"{address_config}:{port_config}"
|
grpc_address = f"{address_config}:{port_config}"
|
||||||
grpc_thread = threading.Thread(target=grpc_server.listen, args=(grpc_address,), daemon=True)
|
grpc_server.listen(grpc_address)
|
||||||
grpc_thread.start()
|
|
||||||
|
|
||||||
# start udp server
|
|
||||||
start_udp(server, address)
|
|
||||||
|
|
||||||
# close handlers
|
|
||||||
close_onexec(server.fileno())
|
|
||||||
|
|
||||||
logger.info("CORE TLV API TCP/UDP listening on: %s:%s", host, port)
|
|
||||||
server.serve_forever()
|
|
||||||
|
|
||||||
|
|
||||||
def get_merged_config(filename):
|
def get_merged_config(filename):
|
||||||
|
@ -98,49 +59,38 @@ def get_merged_config(filename):
|
||||||
default_grpc_port = "50051"
|
default_grpc_port = "50051"
|
||||||
default_address = "localhost"
|
default_address = "localhost"
|
||||||
defaults = {
|
defaults = {
|
||||||
"port": str(CORE_API_PORT),
|
|
||||||
"listenaddr": default_address,
|
|
||||||
"grpcport": default_grpc_port,
|
"grpcport": default_grpc_port,
|
||||||
"grpcaddress": default_address,
|
"grpcaddress": default_address,
|
||||||
"logfile": default_log
|
"logfile": default_log
|
||||||
}
|
}
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
description=f"CORE daemon v.{COREDPY_VERSION} instantiates Linux network namespace nodes.")
|
description=f"CORE daemon v.{COREDPY_VERSION} instantiates Linux network namespace nodes.")
|
||||||
parser.add_argument("-f", "--configfile", dest="configfile",
|
parser.add_argument("-f", "--configfile", dest="configfile",
|
||||||
help=f"read config from specified file; default = {filename}")
|
help=f"read config from specified file; default = {filename}")
|
||||||
parser.add_argument("-p", "--port", dest="port", type=int,
|
|
||||||
help=f"port number to listen on; default = {CORE_API_PORT}")
|
|
||||||
parser.add_argument("--ovs", action="store_true", help="enable experimental ovs mode, default is false")
|
parser.add_argument("--ovs", action="store_true", help="enable experimental ovs mode, default is false")
|
||||||
parser.add_argument("--grpc-port", dest="grpcport",
|
parser.add_argument("--grpc-port", dest="grpcport",
|
||||||
help=f"grpc port to listen on; default {default_grpc_port}")
|
help=f"grpc port to listen on; default {default_grpc_port}")
|
||||||
parser.add_argument("--grpc-address", dest="grpcaddress",
|
parser.add_argument("--grpc-address", dest="grpcaddress",
|
||||||
help=f"grpc address to listen on; default {default_address}")
|
help=f"grpc address to listen on; default {default_address}")
|
||||||
parser.add_argument("-l", "--logfile", help=f"core logging configuration; default {default_log}")
|
parser.add_argument("-l", "--logfile", help=f"core logging configuration; default {default_log}")
|
||||||
|
|
||||||
# parse command line options
|
# parse command line options
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
|
||||||
# convert ovs to internal format
|
# convert ovs to internal format
|
||||||
args.ovs = "1" if args.ovs else "0"
|
args.ovs = "1" if args.ovs else "0"
|
||||||
|
|
||||||
# read the config file
|
# read the config file
|
||||||
if args.configfile is not None:
|
if args.configfile is not None:
|
||||||
filename = args.configfile
|
filename = args.configfile
|
||||||
del args.configfile
|
del args.configfile
|
||||||
cfg = ConfigParser(defaults)
|
cfg = ConfigParser(defaults)
|
||||||
cfg.read(filename)
|
cfg.read(filename)
|
||||||
|
|
||||||
section = "core-daemon"
|
section = "core-daemon"
|
||||||
if not cfg.has_section(section):
|
if not cfg.has_section(section):
|
||||||
cfg.add_section(section)
|
cfg.add_section(section)
|
||||||
|
|
||||||
# merge argparse with configparser
|
# merge argparse with configparser
|
||||||
for opt in vars(args):
|
for opt in vars(args):
|
||||||
val = getattr(args, opt)
|
val = getattr(args, opt)
|
||||||
if val is not None:
|
if val is not None:
|
||||||
cfg.set(section, opt, str(val))
|
cfg.set(section, opt, str(val))
|
||||||
|
|
||||||
return dict(cfg.items(section))
|
return dict(cfg.items(section))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,70 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
import argparse
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
from core import utils
|
|
||||||
from core.api.grpc.client import CoreGrpcClient
|
|
||||||
from core.errors import CoreCommandError
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
# parse flags
|
|
||||||
parser = argparse.ArgumentParser(description="Converts CORE imn files to xml")
|
|
||||||
parser.add_argument("-f", "--file", dest="file", help="imn file to convert")
|
|
||||||
parser.add_argument(
|
|
||||||
"-d", "--dest", dest="dest", default=None, help="destination for xml file, defaults to same location as imn"
|
|
||||||
)
|
|
||||||
args = parser.parse_args()
|
|
||||||
|
|
||||||
# validate provided file exists
|
|
||||||
imn_file = Path(args.file)
|
|
||||||
if not imn_file.exists():
|
|
||||||
print(f"{args.file} does not exist")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# validate destination
|
|
||||||
if args.dest is not None:
|
|
||||||
dest = Path(args.dest)
|
|
||||||
if not dest.exists() or not dest.is_dir():
|
|
||||||
print(f"{dest.resolve()} does not exist or is not a directory")
|
|
||||||
sys.exit(1)
|
|
||||||
xml_file = Path(dest, imn_file.with_suffix(".xml").name)
|
|
||||||
else:
|
|
||||||
xml_file = Path(imn_file.with_suffix(".xml").name)
|
|
||||||
|
|
||||||
# validate xml file
|
|
||||||
if xml_file.exists():
|
|
||||||
print(f"{xml_file.resolve()} already exists")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# run provided imn using core-gui batch mode
|
|
||||||
try:
|
|
||||||
print(f"running {imn_file.resolve()} in batch mode")
|
|
||||||
output = utils.cmd(f"core-gui --batch {imn_file.resolve()}")
|
|
||||||
last_line = output.split("\n")[-1].strip()
|
|
||||||
|
|
||||||
# check for active session
|
|
||||||
if last_line == "Another session is active.":
|
|
||||||
print("need to restart core-daemon or shutdown previous batch session")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
# parse session id
|
|
||||||
m = re.search(r"Session id is (\d+)\.", last_line)
|
|
||||||
if not m:
|
|
||||||
print(f"failed to find session id: {output}")
|
|
||||||
sys.exit(1)
|
|
||||||
session_id = int(m.group(1))
|
|
||||||
print(f"created session {session_id}")
|
|
||||||
|
|
||||||
# save xml and delete session
|
|
||||||
client = CoreGrpcClient()
|
|
||||||
with client.context_connect():
|
|
||||||
print(f"saving xml {xml_file.resolve()}")
|
|
||||||
client.save_xml(session_id, str(xml_file))
|
|
||||||
|
|
||||||
print(f"deleting session {session_id}")
|
|
||||||
client.delete_session(session_id)
|
|
||||||
except CoreCommandError as e:
|
|
||||||
print(f"core-gui batch failed for {imn_file.resolve()}: {e}")
|
|
||||||
sys.exit(1)
|
|
|
@ -1,247 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
"""
|
|
||||||
core-manage: Helper tool to add, remove, or check for services, models, and
|
|
||||||
node types in a CORE installation.
|
|
||||||
"""
|
|
||||||
|
|
||||||
import ast
|
|
||||||
import optparse
|
|
||||||
import os
|
|
||||||
import re
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from core import services
|
|
||||||
from core.constants import CORE_CONF_DIR
|
|
||||||
|
|
||||||
|
|
||||||
class FileUpdater:
|
|
||||||
"""
|
|
||||||
Helper class for changing configuration files.
|
|
||||||
"""
|
|
||||||
actions = ("add", "remove", "check")
|
|
||||||
targets = ("service", "model", "nodetype")
|
|
||||||
|
|
||||||
def __init__(self, action, target, data, options):
|
|
||||||
"""
|
|
||||||
"""
|
|
||||||
self.action = action
|
|
||||||
self.target = target
|
|
||||||
self.data = data
|
|
||||||
self.options = options
|
|
||||||
self.verbose = options.verbose
|
|
||||||
self.search, self.filename = self.get_filename(target)
|
|
||||||
|
|
||||||
def process(self):
|
|
||||||
""" Invoke update_file() using a helper method depending on target.
|
|
||||||
"""
|
|
||||||
if self.verbose:
|
|
||||||
txt = "Updating"
|
|
||||||
if self.action == "check":
|
|
||||||
txt = "Checking"
|
|
||||||
sys.stdout.write(f"{txt} file: {self.filename}\n")
|
|
||||||
|
|
||||||
if self.target == "service":
|
|
||||||
r = self.update_file(fn=self.update_services)
|
|
||||||
elif self.target == "model":
|
|
||||||
r = self.update_file(fn=self.update_emane_models)
|
|
||||||
elif self.target == "nodetype":
|
|
||||||
r = self.update_nodes_conf()
|
|
||||||
|
|
||||||
if self.verbose:
|
|
||||||
txt = ""
|
|
||||||
if not r:
|
|
||||||
txt = "NOT "
|
|
||||||
if self.action == "check":
|
|
||||||
sys.stdout.write(f"String {txt} found.\n")
|
|
||||||
else:
|
|
||||||
sys.stdout.write(f"File {txt} updated.\n")
|
|
||||||
|
|
||||||
return r
|
|
||||||
|
|
||||||
def update_services(self, line):
|
|
||||||
""" Modify the __init__.py file having this format:
|
|
||||||
__all__ = ["quagga", "nrl", "xorp", "bird", ]
|
|
||||||
Returns True or False when "check" is the action, a modified line
|
|
||||||
otherwise.
|
|
||||||
"""
|
|
||||||
line = line.strip("\n")
|
|
||||||
key, valstr = line.split("= ")
|
|
||||||
vals = ast.literal_eval(valstr)
|
|
||||||
r = self.update_keyvals(key, vals)
|
|
||||||
if self.action == "check":
|
|
||||||
return r
|
|
||||||
valstr = str(r)
|
|
||||||
return "= ".join([key, valstr]) + "\n"
|
|
||||||
|
|
||||||
def update_emane_models(self, line):
|
|
||||||
""" Modify the core.conf file having this format:
|
|
||||||
emane_models = RfPipe, Ieee80211abg, CommEffect, Bypass
|
|
||||||
Returns True or False when "check" is the action, a modified line
|
|
||||||
otherwise.
|
|
||||||
"""
|
|
||||||
line = line.strip("\n")
|
|
||||||
key, valstr = line.split("= ")
|
|
||||||
vals = valstr.split(", ")
|
|
||||||
r = self.update_keyvals(key, vals)
|
|
||||||
if self.action == "check":
|
|
||||||
return r
|
|
||||||
valstr = ", ".join(r)
|
|
||||||
return "= ".join([key, valstr]) + "\n"
|
|
||||||
|
|
||||||
def update_keyvals(self, key, vals):
|
|
||||||
""" Perform self.action on (key, vals).
|
|
||||||
Returns True or False when "check" is the action, a modified line
|
|
||||||
otherwise.
|
|
||||||
"""
|
|
||||||
if self.action == "check":
|
|
||||||
if self.data in vals:
|
|
||||||
return True
|
|
||||||
else:
|
|
||||||
return False
|
|
||||||
elif self.action == "add":
|
|
||||||
if self.data not in vals:
|
|
||||||
vals.append(self.data)
|
|
||||||
elif self.action == "remove":
|
|
||||||
try:
|
|
||||||
vals.remove(self.data)
|
|
||||||
except ValueError:
|
|
||||||
pass
|
|
||||||
return vals
|
|
||||||
|
|
||||||
def get_filename(self, target):
|
|
||||||
""" Return search string and filename based on target.
|
|
||||||
"""
|
|
||||||
if target == "service":
|
|
||||||
filename = os.path.abspath(services.__file__)
|
|
||||||
search = "__all__ ="
|
|
||||||
elif target == "model":
|
|
||||||
filename = os.path.join(CORE_CONF_DIR, "core.conf")
|
|
||||||
search = "emane_models ="
|
|
||||||
elif target == "nodetype":
|
|
||||||
if self.options.userpath is None:
|
|
||||||
raise ValueError("missing user path")
|
|
||||||
filename = os.path.join(self.options.userpath, "nodes.conf")
|
|
||||||
search = self.data
|
|
||||||
else:
|
|
||||||
raise ValueError("unknown target")
|
|
||||||
if not os.path.exists(filename):
|
|
||||||
raise ValueError(f"file {filename} does not exist")
|
|
||||||
return search, filename
|
|
||||||
|
|
||||||
def update_file(self, fn=None):
|
|
||||||
""" Open a file and search for self.search, invoking the supplied
|
|
||||||
function on the matching line. Write file changes if necessary.
|
|
||||||
Returns True if the file has changed (or action is "check" and the
|
|
||||||
search string is found), False otherwise.
|
|
||||||
"""
|
|
||||||
changed = False
|
|
||||||
output = "" # this accumulates output, assumes input is small
|
|
||||||
with open(self.filename, "r") as f:
|
|
||||||
for line in f:
|
|
||||||
if line[:len(self.search)] == self.search:
|
|
||||||
r = fn(line) # line may be modified by fn() here
|
|
||||||
if self.action == "check":
|
|
||||||
return r
|
|
||||||
else:
|
|
||||||
if line != r:
|
|
||||||
changed = True
|
|
||||||
line = r
|
|
||||||
output += line
|
|
||||||
if changed:
|
|
||||||
with open(self.filename, "w") as f:
|
|
||||||
f.write(output)
|
|
||||||
|
|
||||||
return changed
|
|
||||||
|
|
||||||
def update_nodes_conf(self):
|
|
||||||
""" Add/remove/check entries from nodes.conf. This file
|
|
||||||
contains a Tcl-formatted array of node types. The array index must be
|
|
||||||
properly set for new entries. Uses self.{action, filename, search,
|
|
||||||
data} variables as input and returns the same value as update_file().
|
|
||||||
"""
|
|
||||||
changed = False
|
|
||||||
output = "" # this accumulates output, assumes input is small
|
|
||||||
with open(self.filename, "r") as f:
|
|
||||||
for line in f:
|
|
||||||
# make sure data is not added twice
|
|
||||||
if line.find(self.search) >= 0:
|
|
||||||
if self.action == "check":
|
|
||||||
return True
|
|
||||||
elif self.action == "add":
|
|
||||||
return False
|
|
||||||
elif self.action == "remove":
|
|
||||||
changed = True
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
output += line
|
|
||||||
|
|
||||||
if self.action == "add":
|
|
||||||
index = int(re.match("^\d+", line).group(0))
|
|
||||||
output += str(index + 1) + " " + self.data + "\n"
|
|
||||||
changed = True
|
|
||||||
if changed:
|
|
||||||
with open(self.filename, "w") as f:
|
|
||||||
f.write(output)
|
|
||||||
|
|
||||||
return changed
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
actions = ", ".join(FileUpdater.actions)
|
|
||||||
targets = ", ".join(FileUpdater.targets)
|
|
||||||
usagestr = "usage: %prog [-h] [options] <action> <target> <string>\n"
|
|
||||||
usagestr += "\nHelper tool to add, remove, or check for "
|
|
||||||
usagestr += "services, models, and node types\nin a CORE installation.\n"
|
|
||||||
usagestr += "\nExamples:\n %prog add service newrouting"
|
|
||||||
usagestr += "\n %prog -v check model RfPipe"
|
|
||||||
usagestr += "\n %prog --userpath=\"$HOME/.core\" add nodetype \"{ftp ftp.gif ftp.gif {DefaultRoute FTP} netns {FTP server} }\" \n"
|
|
||||||
usagestr += f"\nArguments:\n <action> should be one of: {actions}"
|
|
||||||
usagestr += f"\n <target> should be one of: {targets}"
|
|
||||||
usagestr += f"\n <string> is the text to {actions}"
|
|
||||||
parser = optparse.OptionParser(usage=usagestr)
|
|
||||||
parser.set_defaults(userpath=None, verbose=False, )
|
|
||||||
|
|
||||||
parser.add_option("--userpath", dest="userpath", type="string",
|
|
||||||
help="use the specified user path (e.g. \"$HOME/.core" \
|
|
||||||
"\") to access nodes.conf")
|
|
||||||
parser.add_option("-v", "--verbose", dest="verbose", action="store_true",
|
|
||||||
help="be verbose when performing action")
|
|
||||||
|
|
||||||
def usage(msg=None, err=0):
|
|
||||||
sys.stdout.write("\n")
|
|
||||||
if msg:
|
|
||||||
sys.stdout.write(msg + "\n\n")
|
|
||||||
parser.print_help()
|
|
||||||
sys.exit(err)
|
|
||||||
|
|
||||||
(options, args) = parser.parse_args()
|
|
||||||
|
|
||||||
if len(args) != 3:
|
|
||||||
usage("Missing required arguments!", 1)
|
|
||||||
|
|
||||||
action = args[0]
|
|
||||||
if action not in FileUpdater.actions:
|
|
||||||
usage(f"invalid action {action}", 1)
|
|
||||||
|
|
||||||
target = args[1]
|
|
||||||
if target not in FileUpdater.targets:
|
|
||||||
usage(f"invalid target {target}", 1)
|
|
||||||
|
|
||||||
if target == "nodetype" and not options.userpath:
|
|
||||||
usage(f"user path option required for this target ({target})")
|
|
||||||
|
|
||||||
data = args[2]
|
|
||||||
|
|
||||||
try:
|
|
||||||
up = FileUpdater(action, target, data, options)
|
|
||||||
r = up.process()
|
|
||||||
except Exception as e:
|
|
||||||
sys.stderr.write(f"Exception: {e}\n")
|
|
||||||
sys.exit(1)
|
|
||||||
if not r:
|
|
||||||
sys.exit(1)
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
|
@ -1,279 +0,0 @@
|
||||||
#!/usr/bin/env python3
|
|
||||||
"""
|
|
||||||
coresendmsg: utility for generating CORE messages
|
|
||||||
"""
|
|
||||||
|
|
||||||
import optparse
|
|
||||||
import os
|
|
||||||
import socket
|
|
||||||
import sys
|
|
||||||
|
|
||||||
from core.api.tlv import coreapi
|
|
||||||
from core.api.tlv.enumerations import CORE_API_PORT, MessageTypes, SessionTlvs
|
|
||||||
from core.emulator.enumerations import MessageFlags
|
|
||||||
|
|
||||||
|
|
||||||
def print_available_tlvs(t, tlv_class):
|
|
||||||
"""
|
|
||||||
Print a TLV list.
|
|
||||||
"""
|
|
||||||
print(f"TLVs available for {t} message:")
|
|
||||||
for tlv in sorted([tlv for tlv in tlv_class.tlv_type_map], key=lambda x: x.name):
|
|
||||||
print(tlv.name.lower())
|
|
||||||
|
|
||||||
|
|
||||||
def print_examples(name):
|
|
||||||
"""
|
|
||||||
Print example usage of this script.
|
|
||||||
"""
|
|
||||||
examples = [
|
|
||||||
("node number=3 x_position=125 y_position=525",
|
|
||||||
"move node number 3 to x,y=(125,525)"),
|
|
||||||
("node number=4 icon=/usr/local/share/core/icons/normal/router_red.gif",
|
|
||||||
"change node number 4\"s icon to red"),
|
|
||||||
("node flags=add number=5 type=0 name=\"n5\" x_position=500 y_position=500",
|
|
||||||
"add a new router node n5"),
|
|
||||||
("link n1_number=2 n2_number=3 delay=15000",
|
|
||||||
"set a 15ms delay on the link between n2 and n3"),
|
|
||||||
("link n1_number=2 n2_number=3 gui_attributes=\"color=blue\"",
|
|
||||||
"change the color of the link between n2 and n3"),
|
|
||||||
("link flags=add n1_number=4 n2_number=5 interface1_ip4=\"10.0.3.2\" "
|
|
||||||
"interface1_ip4_mask=24 interface2_ip4=\"10.0.3.1\" interface2_ip4_mask=24",
|
|
||||||
"link node n5 with n4 using the given interface addresses"),
|
|
||||||
("execute flags=string,text node=1 number=1000 command=\"uname -a\" -l",
|
|
||||||
"run a command on node 1 and wait for the result"),
|
|
||||||
("execute node=2 number=1001 command=\"killall ospfd\"",
|
|
||||||
"run a command on node 2 and ignore the result"),
|
|
||||||
("file flags=add node=1 name=\"/var/log/test.log\" data=\"hello world.\"",
|
|
||||||
"write a test.log file on node 1 with the given contents"),
|
|
||||||
("file flags=add node=2 name=\"test.log\" source_name=\"./test.log\"",
|
|
||||||
"move a test.log file from host to node 2"),
|
|
||||||
]
|
|
||||||
print(f"Example {name} invocations:")
|
|
||||||
for cmd, descr in examples:
|
|
||||||
print(f" {name} {cmd}\n\t\t{descr}")
|
|
||||||
|
|
||||||
|
|
||||||
def receive_message(sock):
|
|
||||||
"""
|
|
||||||
Retrieve a message from a socket and return the CoreMessage object or
|
|
||||||
None upon disconnect. Socket data beyond the first message is dropped.
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
# large receive buffer used for UDP sockets, instead of just receiving
|
|
||||||
# the 4-byte header
|
|
||||||
data = sock.recv(4096)
|
|
||||||
msghdr = data[:coreapi.CoreMessage.header_len]
|
|
||||||
except KeyboardInterrupt:
|
|
||||||
print("CTRL+C pressed")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if len(msghdr) == 0:
|
|
||||||
return None
|
|
||||||
|
|
||||||
msgdata = None
|
|
||||||
msgtype, msgflags, msglen = coreapi.CoreMessage.unpack_header(msghdr)
|
|
||||||
|
|
||||||
if msglen:
|
|
||||||
msgdata = data[coreapi.CoreMessage.header_len:]
|
|
||||||
try:
|
|
||||||
msgcls = coreapi.CLASS_MAP[msgtype]
|
|
||||||
except KeyError:
|
|
||||||
msg = coreapi.CoreMessage(msgflags, msghdr, msgdata)
|
|
||||||
msg.message_type = msgtype
|
|
||||||
print(f"unimplemented CORE message type: {msg.type_str()}")
|
|
||||||
return msg
|
|
||||||
if len(data) > msglen + coreapi.CoreMessage.header_len:
|
|
||||||
data_size = len(data) - (msglen + coreapi.CoreMessage.header_len)
|
|
||||||
print(f"received a message of type {msgtype}, dropping {data_size} bytes of extra data")
|
|
||||||
return msgcls(msgflags, msghdr, msgdata)
|
|
||||||
|
|
||||||
|
|
||||||
def connect_to_session(sock, requested):
|
|
||||||
"""
|
|
||||||
Use Session Messages to retrieve the current list of sessions and
|
|
||||||
connect to the first one.
|
|
||||||
"""
|
|
||||||
# request the session list
|
|
||||||
tlvdata = coreapi.CoreSessionTlv.pack(SessionTlvs.NUMBER.value, "")
|
|
||||||
flags = MessageFlags.STRING.value
|
|
||||||
smsg = coreapi.CoreSessionMessage.pack(flags, tlvdata)
|
|
||||||
sock.sendall(smsg)
|
|
||||||
|
|
||||||
print("waiting for session list...")
|
|
||||||
smsgreply = receive_message(sock)
|
|
||||||
if smsgreply is None:
|
|
||||||
print("disconnected")
|
|
||||||
return False
|
|
||||||
|
|
||||||
sessstr = smsgreply.get_tlv(SessionTlvs.NUMBER.value)
|
|
||||||
if sessstr is None:
|
|
||||||
print("missing session numbers")
|
|
||||||
return False
|
|
||||||
|
|
||||||
# join the first session (that is not our own connection)
|
|
||||||
tmp, localport = sock.getsockname()
|
|
||||||
sessions = sessstr.split("|")
|
|
||||||
sessions.remove(str(localport))
|
|
||||||
if len(sessions) == 0:
|
|
||||||
print("no sessions to join")
|
|
||||||
return False
|
|
||||||
|
|
||||||
if not requested:
|
|
||||||
session = sessions[0]
|
|
||||||
elif requested in sessions:
|
|
||||||
session = requested
|
|
||||||
else:
|
|
||||||
print("requested session not found!")
|
|
||||||
return False
|
|
||||||
|
|
||||||
print(f"joining session: {session}")
|
|
||||||
tlvdata = coreapi.CoreSessionTlv.pack(SessionTlvs.NUMBER.value, session)
|
|
||||||
flags = MessageFlags.ADD.value
|
|
||||||
smsg = coreapi.CoreSessionMessage.pack(flags, tlvdata)
|
|
||||||
sock.sendall(smsg)
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def receive_response(sock, opt):
|
|
||||||
"""
|
|
||||||
Receive and print a CORE message from the given socket.
|
|
||||||
"""
|
|
||||||
print("waiting for response...")
|
|
||||||
msg = receive_message(sock)
|
|
||||||
if msg is None:
|
|
||||||
print(f"disconnected from {opt.address}:{opt.port}")
|
|
||||||
sys.exit(0)
|
|
||||||
print(f"received message: {msg}")
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
"""
|
|
||||||
Parse command-line arguments to build and send a CORE message.
|
|
||||||
"""
|
|
||||||
types = [message_type.name.lower() for message_type in MessageTypes]
|
|
||||||
flags = [flag.name.lower() for flag in MessageFlags]
|
|
||||||
types_usage = " ".join(types)
|
|
||||||
flags_usage = " ".join(flags)
|
|
||||||
usagestr = (
|
|
||||||
"usage: %prog [-h|-H] [options] [message-type] [flags=flags] "
|
|
||||||
"[message-TLVs]\n\n"
|
|
||||||
f"Supported message types:\n {types_usage}\n"
|
|
||||||
f"Supported message flags (flags=f1,f2,...):\n {flags_usage}"
|
|
||||||
)
|
|
||||||
parser = optparse.OptionParser(usage=usagestr)
|
|
||||||
default_address = "localhost"
|
|
||||||
default_session = None
|
|
||||||
default_tcp = False
|
|
||||||
parser.set_defaults(
|
|
||||||
port=CORE_API_PORT,
|
|
||||||
address=default_address,
|
|
||||||
session=default_session,
|
|
||||||
listen=False,
|
|
||||||
examples=False,
|
|
||||||
tlvs=False,
|
|
||||||
tcp=default_tcp
|
|
||||||
)
|
|
||||||
parser.add_option("-H", dest="examples", action="store_true",
|
|
||||||
help="show example usage help message and exit")
|
|
||||||
parser.add_option("-p", "--port", dest="port", type=int,
|
|
||||||
help=f"TCP port to connect to, default: {CORE_API_PORT}")
|
|
||||||
parser.add_option("-a", "--address", dest="address", type=str,
|
|
||||||
help=f"Address to connect to, default: {default_address}")
|
|
||||||
parser.add_option("-s", "--session", dest="session", type=str,
|
|
||||||
help=f"Session to join, default: {default_session}")
|
|
||||||
parser.add_option("-l", "--listen", dest="listen", action="store_true",
|
|
||||||
help="Listen for a response message and print it.")
|
|
||||||
parser.add_option("-t", "--list-tlvs", dest="tlvs", action="store_true",
|
|
||||||
help="List TLVs for the specified message type.")
|
|
||||||
parser.add_option("--tcp", dest="tcp", action="store_true",
|
|
||||||
help=f"Use TCP instead of UDP and connect to a session default: {default_tcp}")
|
|
||||||
|
|
||||||
def usage(msg=None, err=0):
|
|
||||||
print()
|
|
||||||
if msg:
|
|
||||||
print(f"{msg}\n")
|
|
||||||
parser.print_help()
|
|
||||||
sys.exit(err)
|
|
||||||
|
|
||||||
# parse command line opt
|
|
||||||
opt, args = parser.parse_args()
|
|
||||||
if opt.examples:
|
|
||||||
print_examples(os.path.basename(sys.argv[0]))
|
|
||||||
sys.exit(0)
|
|
||||||
if len(args) == 0:
|
|
||||||
usage("Please specify a message type to send.")
|
|
||||||
|
|
||||||
# given a message type t, determine the message and TLV classes
|
|
||||||
t = args.pop(0)
|
|
||||||
t = t.lower()
|
|
||||||
if t not in types:
|
|
||||||
usage(f"Unknown message type requested: {t}")
|
|
||||||
message_type = MessageTypes[t.upper()]
|
|
||||||
msg_cls = coreapi.CLASS_MAP[message_type.value]
|
|
||||||
tlv_cls = msg_cls.tlv_class
|
|
||||||
|
|
||||||
# list TLV types for this message type
|
|
||||||
if opt.tlvs:
|
|
||||||
print_available_tlvs(t, tlv_cls)
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
# build a message consisting of TLVs from "type=value" arguments
|
|
||||||
flagstr = ""
|
|
||||||
tlvdata = b""
|
|
||||||
for a in args:
|
|
||||||
typevalue = a.split("=")
|
|
||||||
if len(typevalue) < 2:
|
|
||||||
usage(f"Use \"type=value\" syntax instead of \"{a}\".")
|
|
||||||
tlv_typestr = typevalue[0].lower()
|
|
||||||
tlv_valstr = "=".join(typevalue[1:])
|
|
||||||
if tlv_typestr == "flags":
|
|
||||||
flagstr = tlv_valstr
|
|
||||||
continue
|
|
||||||
try:
|
|
||||||
tlv_type = tlv_cls.tlv_type_map[tlv_typestr.upper()]
|
|
||||||
tlvdata += tlv_cls.pack_string(tlv_type.value, tlv_valstr)
|
|
||||||
except KeyError:
|
|
||||||
usage(f"Unknown TLV: \"{tlv_typestr}\"")
|
|
||||||
|
|
||||||
flags = 0
|
|
||||||
for f in flagstr.split(","):
|
|
||||||
if f == "":
|
|
||||||
continue
|
|
||||||
try:
|
|
||||||
flag_enum = MessageFlags[f.upper()]
|
|
||||||
n = flag_enum.value
|
|
||||||
flags |= n
|
|
||||||
except KeyError:
|
|
||||||
usage(f"Invalid flag \"{f}\".")
|
|
||||||
|
|
||||||
msg = msg_cls.pack(flags, tlvdata)
|
|
||||||
|
|
||||||
if opt.tcp:
|
|
||||||
protocol = socket.SOCK_STREAM
|
|
||||||
else:
|
|
||||||
protocol = socket.SOCK_DGRAM
|
|
||||||
|
|
||||||
sock = socket.socket(socket.AF_INET, protocol)
|
|
||||||
sock.setblocking(True)
|
|
||||||
|
|
||||||
try:
|
|
||||||
sock.connect((opt.address, opt.port))
|
|
||||||
except Exception as e:
|
|
||||||
print(f"Error connecting to {opt.address}:{opt.port}:\n\t{e}")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
if opt.tcp and not connect_to_session(sock, opt.session):
|
|
||||||
print("warning: continuing without joining a session!")
|
|
||||||
|
|
||||||
sock.sendall(msg)
|
|
||||||
if opt.listen:
|
|
||||||
receive_response(sock, opt)
|
|
||||||
if opt.tcp:
|
|
||||||
sock.shutdown(socket.SHUT_RDWR)
|
|
||||||
sock.close()
|
|
||||||
sys.exit(0)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
|
@ -7,11 +7,9 @@ import time
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
import pytest
|
import pytest
|
||||||
from mock.mock import MagicMock
|
|
||||||
|
|
||||||
from core.api.grpc.client import InterfaceHelper
|
from core.api.grpc.client import InterfaceHelper
|
||||||
from core.api.grpc.server import CoreGrpcServer
|
from core.api.grpc.server import CoreGrpcServer
|
||||||
from core.api.tlv.corehandlers import CoreHandler
|
|
||||||
from core.emulator.coreemu import CoreEmu
|
from core.emulator.coreemu import CoreEmu
|
||||||
from core.emulator.data import IpPrefixes
|
from core.emulator.data import IpPrefixes
|
||||||
from core.emulator.distributed import DistributedServer
|
from core.emulator.distributed import DistributedServer
|
||||||
|
@ -104,17 +102,6 @@ def module_grpc(global_coreemu):
|
||||||
grpc_server.server.stop(None)
|
grpc_server.server.stop(None)
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture(scope="module")
|
|
||||||
def module_coretlv(patcher, global_coreemu, global_session):
|
|
||||||
request_mock = MagicMock()
|
|
||||||
request_mock.fileno = MagicMock(return_value=1)
|
|
||||||
server = MockServer(global_coreemu)
|
|
||||||
request_handler = CoreHandler(request_mock, "", server)
|
|
||||||
request_handler.session = global_session
|
|
||||||
request_handler.add_session_handlers()
|
|
||||||
yield request_handler
|
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def grpc_server(module_grpc):
|
def grpc_server(module_grpc):
|
||||||
yield module_grpc
|
yield module_grpc
|
||||||
|
@ -130,16 +117,6 @@ def session(global_session):
|
||||||
global_session.clear()
|
global_session.clear()
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
|
||||||
def coretlv(module_coretlv):
|
|
||||||
session = module_coretlv.session
|
|
||||||
session.set_state(EventTypes.CONFIGURATION_STATE)
|
|
||||||
coreemu = module_coretlv.coreemu
|
|
||||||
coreemu.sessions[session.id] = session
|
|
||||||
yield module_coretlv
|
|
||||||
coreemu.shutdown()
|
|
||||||
|
|
||||||
|
|
||||||
def pytest_addoption(parser):
|
def pytest_addoption(parser):
|
||||||
parser.addoption("--distributed", help="distributed server address")
|
parser.addoption("--distributed", help="distributed server address")
|
||||||
parser.addoption("--mock", action="store_true", help="run without mocking")
|
parser.addoption("--mock", action="store_true", help="run without mocking")
|
||||||
|
|
|
@ -31,8 +31,6 @@ from core.api.grpc.wrappers import (
|
||||||
SessionLocation,
|
SessionLocation,
|
||||||
SessionState,
|
SessionState,
|
||||||
)
|
)
|
||||||
from core.api.tlv.dataconversion import ConfigShim
|
|
||||||
from core.api.tlv.enumerations import ConfigFlags
|
|
||||||
from core.emane.models.ieee80211abg import EmaneIeee80211abgModel
|
from core.emane.models.ieee80211abg import EmaneIeee80211abgModel
|
||||||
from core.emane.nodes import EmaneNet
|
from core.emane.nodes import EmaneNet
|
||||||
from core.emulator.data import EventData, IpPrefixes, NodeData, NodeOptions
|
from core.emulator.data import EventData, IpPrefixes, NodeData, NodeOptions
|
||||||
|
@ -820,30 +818,6 @@ class TestGrpc:
|
||||||
# then
|
# then
|
||||||
queue.get(timeout=5)
|
queue.get(timeout=5)
|
||||||
|
|
||||||
def test_config_events(self, grpc_server: CoreGrpcServer):
|
|
||||||
# given
|
|
||||||
client = CoreGrpcClient()
|
|
||||||
session = grpc_server.coreemu.create_session()
|
|
||||||
queue = Queue()
|
|
||||||
|
|
||||||
def handle_event(event: Event) -> None:
|
|
||||||
assert event.session_id == session.id
|
|
||||||
assert event.config_event is not None
|
|
||||||
queue.put(event)
|
|
||||||
|
|
||||||
# then
|
|
||||||
with client.context_connect():
|
|
||||||
client.events(session.id, handle_event)
|
|
||||||
time.sleep(0.1)
|
|
||||||
session_config = session.options.get_configs()
|
|
||||||
config_data = ConfigShim.config_data(
|
|
||||||
0, None, ConfigFlags.UPDATE.value, session.options, session_config
|
|
||||||
)
|
|
||||||
session.broadcast_config(config_data)
|
|
||||||
|
|
||||||
# then
|
|
||||||
queue.get(timeout=5)
|
|
||||||
|
|
||||||
def test_exception_events(self, grpc_server: CoreGrpcServer):
|
def test_exception_events(self, grpc_server: CoreGrpcServer):
|
||||||
# given
|
# given
|
||||||
client = CoreGrpcClient()
|
client = CoreGrpcClient()
|
||||||
|
|
|
@ -1,941 +0,0 @@
|
||||||
"""
|
|
||||||
Tests for testing tlv message handling.
|
|
||||||
"""
|
|
||||||
import time
|
|
||||||
from pathlib import Path
|
|
||||||
from typing import Optional
|
|
||||||
|
|
||||||
import mock
|
|
||||||
import netaddr
|
|
||||||
import pytest
|
|
||||||
from mock import MagicMock
|
|
||||||
|
|
||||||
from core.api.tlv import coreapi
|
|
||||||
from core.api.tlv.corehandlers import CoreHandler
|
|
||||||
from core.api.tlv.enumerations import (
|
|
||||||
ConfigFlags,
|
|
||||||
ConfigTlvs,
|
|
||||||
EventTlvs,
|
|
||||||
ExecuteTlvs,
|
|
||||||
FileTlvs,
|
|
||||||
LinkTlvs,
|
|
||||||
NodeTlvs,
|
|
||||||
SessionTlvs,
|
|
||||||
)
|
|
||||||
from core.emane.models.ieee80211abg import EmaneIeee80211abgModel
|
|
||||||
from core.emulator.enumerations import EventTypes, MessageFlags, NodeTypes, RegisterTlvs
|
|
||||||
from core.errors import CoreError
|
|
||||||
from core.location.mobility import BasicRangeModel
|
|
||||||
from core.nodes.base import CoreNode, NodeBase
|
|
||||||
from core.nodes.network import SwitchNode, WlanNode
|
|
||||||
|
|
||||||
|
|
||||||
def dict_to_str(values) -> str:
|
|
||||||
return "|".join(f"{x}={values[x]}" for x in values)
|
|
||||||
|
|
||||||
|
|
||||||
class TestGui:
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"node_type, model",
|
|
||||||
[
|
|
||||||
(NodeTypes.DEFAULT, "PC"),
|
|
||||||
(NodeTypes.EMANE, None),
|
|
||||||
(NodeTypes.HUB, None),
|
|
||||||
(NodeTypes.SWITCH, None),
|
|
||||||
(NodeTypes.WIRELESS_LAN, None),
|
|
||||||
(NodeTypes.TUNNEL, None),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
def test_node_add(
|
|
||||||
self, coretlv: CoreHandler, node_type: NodeTypes, model: Optional[str]
|
|
||||||
):
|
|
||||||
node_id = 1
|
|
||||||
name = "node1"
|
|
||||||
message = coreapi.CoreNodeMessage.create(
|
|
||||||
MessageFlags.ADD.value,
|
|
||||||
[
|
|
||||||
(NodeTlvs.NUMBER, node_id),
|
|
||||||
(NodeTlvs.TYPE, node_type.value),
|
|
||||||
(NodeTlvs.NAME, name),
|
|
||||||
(NodeTlvs.X_POSITION, 0),
|
|
||||||
(NodeTlvs.Y_POSITION, 0),
|
|
||||||
(NodeTlvs.MODEL, model),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
node = coretlv.session.get_node(node_id, NodeBase)
|
|
||||||
assert node
|
|
||||||
assert node.name == name
|
|
||||||
|
|
||||||
def test_node_update(self, coretlv: CoreHandler):
|
|
||||||
node_id = 1
|
|
||||||
coretlv.session.add_node(CoreNode, _id=node_id)
|
|
||||||
x = 50
|
|
||||||
y = 100
|
|
||||||
message = coreapi.CoreNodeMessage.create(
|
|
||||||
0,
|
|
||||||
[
|
|
||||||
(NodeTlvs.NUMBER, node_id),
|
|
||||||
(NodeTlvs.X_POSITION, x),
|
|
||||||
(NodeTlvs.Y_POSITION, y),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
node = coretlv.session.get_node(node_id, NodeBase)
|
|
||||||
assert node is not None
|
|
||||||
assert node.position.x == x
|
|
||||||
assert node.position.y == y
|
|
||||||
|
|
||||||
def test_node_delete(self, coretlv: CoreHandler):
|
|
||||||
node_id = 1
|
|
||||||
coretlv.session.add_node(CoreNode, _id=node_id)
|
|
||||||
message = coreapi.CoreNodeMessage.create(
|
|
||||||
MessageFlags.DELETE.value, [(NodeTlvs.NUMBER, node_id)]
|
|
||||||
)
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
with pytest.raises(CoreError):
|
|
||||||
coretlv.session.get_node(node_id, NodeBase)
|
|
||||||
|
|
||||||
def test_link_add_node_to_net(self, coretlv: CoreHandler):
|
|
||||||
node1_id = 1
|
|
||||||
coretlv.session.add_node(CoreNode, _id=node1_id)
|
|
||||||
switch_id = 2
|
|
||||||
coretlv.session.add_node(SwitchNode, _id=switch_id)
|
|
||||||
ip_prefix = netaddr.IPNetwork("10.0.0.0/24")
|
|
||||||
iface1_ip4 = str(ip_prefix[node1_id])
|
|
||||||
message = coreapi.CoreLinkMessage.create(
|
|
||||||
MessageFlags.ADD.value,
|
|
||||||
[
|
|
||||||
(LinkTlvs.N1_NUMBER, node1_id),
|
|
||||||
(LinkTlvs.N2_NUMBER, switch_id),
|
|
||||||
(LinkTlvs.IFACE1_NUMBER, 0),
|
|
||||||
(LinkTlvs.IFACE1_IP4, iface1_ip4),
|
|
||||||
(LinkTlvs.IFACE1_IP4_MASK, 24),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
switch_node = coretlv.session.get_node(switch_id, SwitchNode)
|
|
||||||
all_links = switch_node.links()
|
|
||||||
assert len(all_links) == 1
|
|
||||||
|
|
||||||
def test_link_add_net_to_node(self, coretlv: CoreHandler):
|
|
||||||
node1_id = 1
|
|
||||||
coretlv.session.add_node(CoreNode, _id=node1_id)
|
|
||||||
switch_id = 2
|
|
||||||
coretlv.session.add_node(SwitchNode, _id=switch_id)
|
|
||||||
ip_prefix = netaddr.IPNetwork("10.0.0.0/24")
|
|
||||||
iface2_ip4 = str(ip_prefix[node1_id])
|
|
||||||
message = coreapi.CoreLinkMessage.create(
|
|
||||||
MessageFlags.ADD.value,
|
|
||||||
[
|
|
||||||
(LinkTlvs.N1_NUMBER, switch_id),
|
|
||||||
(LinkTlvs.N2_NUMBER, node1_id),
|
|
||||||
(LinkTlvs.IFACE2_NUMBER, 0),
|
|
||||||
(LinkTlvs.IFACE2_IP4, iface2_ip4),
|
|
||||||
(LinkTlvs.IFACE2_IP4_MASK, 24),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
switch_node = coretlv.session.get_node(switch_id, SwitchNode)
|
|
||||||
all_links = switch_node.links()
|
|
||||||
assert len(all_links) == 1
|
|
||||||
|
|
||||||
def test_link_add_node_to_node(self, coretlv: CoreHandler):
|
|
||||||
node1_id = 1
|
|
||||||
coretlv.session.add_node(CoreNode, _id=node1_id)
|
|
||||||
node2_id = 2
|
|
||||||
coretlv.session.add_node(CoreNode, _id=node2_id)
|
|
||||||
ip_prefix = netaddr.IPNetwork("10.0.0.0/24")
|
|
||||||
iface1_ip4 = str(ip_prefix[node1_id])
|
|
||||||
iface2_ip4 = str(ip_prefix[node2_id])
|
|
||||||
message = coreapi.CoreLinkMessage.create(
|
|
||||||
MessageFlags.ADD.value,
|
|
||||||
[
|
|
||||||
(LinkTlvs.N1_NUMBER, node1_id),
|
|
||||||
(LinkTlvs.N2_NUMBER, node2_id),
|
|
||||||
(LinkTlvs.IFACE1_NUMBER, 0),
|
|
||||||
(LinkTlvs.IFACE1_IP4, iface1_ip4),
|
|
||||||
(LinkTlvs.IFACE1_IP4_MASK, 24),
|
|
||||||
(LinkTlvs.IFACE2_NUMBER, 0),
|
|
||||||
(LinkTlvs.IFACE2_IP4, iface2_ip4),
|
|
||||||
(LinkTlvs.IFACE2_IP4_MASK, 24),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
all_links = []
|
|
||||||
for node_id in coretlv.session.nodes:
|
|
||||||
node = coretlv.session.nodes[node_id]
|
|
||||||
all_links += node.links()
|
|
||||||
assert len(all_links) == 1
|
|
||||||
|
|
||||||
def test_link_update(self, coretlv: CoreHandler):
|
|
||||||
node1_id = 1
|
|
||||||
coretlv.session.add_node(CoreNode, _id=node1_id)
|
|
||||||
switch_id = 2
|
|
||||||
coretlv.session.add_node(SwitchNode, _id=switch_id)
|
|
||||||
ip_prefix = netaddr.IPNetwork("10.0.0.0/24")
|
|
||||||
iface1_ip4 = str(ip_prefix[node1_id])
|
|
||||||
message = coreapi.CoreLinkMessage.create(
|
|
||||||
MessageFlags.ADD.value,
|
|
||||||
[
|
|
||||||
(LinkTlvs.N1_NUMBER, node1_id),
|
|
||||||
(LinkTlvs.N2_NUMBER, switch_id),
|
|
||||||
(LinkTlvs.IFACE1_NUMBER, 0),
|
|
||||||
(LinkTlvs.IFACE1_IP4, iface1_ip4),
|
|
||||||
(LinkTlvs.IFACE1_IP4_MASK, 24),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
switch_node = coretlv.session.get_node(switch_id, SwitchNode)
|
|
||||||
all_links = switch_node.links()
|
|
||||||
assert len(all_links) == 1
|
|
||||||
link = all_links[0]
|
|
||||||
assert link.options.bandwidth is None
|
|
||||||
|
|
||||||
bandwidth = 50000
|
|
||||||
message = coreapi.CoreLinkMessage.create(
|
|
||||||
0,
|
|
||||||
[
|
|
||||||
(LinkTlvs.N1_NUMBER, node1_id),
|
|
||||||
(LinkTlvs.N2_NUMBER, switch_id),
|
|
||||||
(LinkTlvs.IFACE1_NUMBER, 0),
|
|
||||||
(LinkTlvs.BANDWIDTH, bandwidth),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
switch_node = coretlv.session.get_node(switch_id, SwitchNode)
|
|
||||||
all_links = switch_node.links()
|
|
||||||
assert len(all_links) == 1
|
|
||||||
link = all_links[0]
|
|
||||||
assert link.options.bandwidth == bandwidth
|
|
||||||
|
|
||||||
def test_link_delete_node_to_node(self, coretlv: CoreHandler):
|
|
||||||
node1_id = 1
|
|
||||||
coretlv.session.add_node(CoreNode, _id=node1_id)
|
|
||||||
node2_id = 2
|
|
||||||
coretlv.session.add_node(CoreNode, _id=node2_id)
|
|
||||||
ip_prefix = netaddr.IPNetwork("10.0.0.0/24")
|
|
||||||
iface1_ip4 = str(ip_prefix[node1_id])
|
|
||||||
iface2_ip4 = str(ip_prefix[node2_id])
|
|
||||||
message = coreapi.CoreLinkMessage.create(
|
|
||||||
MessageFlags.ADD.value,
|
|
||||||
[
|
|
||||||
(LinkTlvs.N1_NUMBER, node1_id),
|
|
||||||
(LinkTlvs.N2_NUMBER, node2_id),
|
|
||||||
(LinkTlvs.IFACE1_NUMBER, 0),
|
|
||||||
(LinkTlvs.IFACE1_IP4, iface1_ip4),
|
|
||||||
(LinkTlvs.IFACE1_IP4_MASK, 24),
|
|
||||||
(LinkTlvs.IFACE2_IP4, iface2_ip4),
|
|
||||||
(LinkTlvs.IFACE2_IP4_MASK, 24),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
all_links = []
|
|
||||||
for node_id in coretlv.session.nodes:
|
|
||||||
node = coretlv.session.nodes[node_id]
|
|
||||||
all_links += node.links()
|
|
||||||
assert len(all_links) == 1
|
|
||||||
|
|
||||||
message = coreapi.CoreLinkMessage.create(
|
|
||||||
MessageFlags.DELETE.value,
|
|
||||||
[
|
|
||||||
(LinkTlvs.N1_NUMBER, node1_id),
|
|
||||||
(LinkTlvs.N2_NUMBER, node2_id),
|
|
||||||
(LinkTlvs.IFACE1_NUMBER, 0),
|
|
||||||
(LinkTlvs.IFACE2_NUMBER, 0),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
all_links = []
|
|
||||||
for node_id in coretlv.session.nodes:
|
|
||||||
node = coretlv.session.nodes[node_id]
|
|
||||||
all_links += node.links()
|
|
||||||
assert len(all_links) == 0
|
|
||||||
|
|
||||||
def test_link_delete_node_to_net(self, coretlv: CoreHandler):
|
|
||||||
node1_id = 1
|
|
||||||
coretlv.session.add_node(CoreNode, _id=node1_id)
|
|
||||||
switch_id = 2
|
|
||||||
coretlv.session.add_node(SwitchNode, _id=switch_id)
|
|
||||||
ip_prefix = netaddr.IPNetwork("10.0.0.0/24")
|
|
||||||
iface1_ip4 = str(ip_prefix[node1_id])
|
|
||||||
message = coreapi.CoreLinkMessage.create(
|
|
||||||
MessageFlags.ADD.value,
|
|
||||||
[
|
|
||||||
(LinkTlvs.N1_NUMBER, node1_id),
|
|
||||||
(LinkTlvs.N2_NUMBER, switch_id),
|
|
||||||
(LinkTlvs.IFACE1_NUMBER, 0),
|
|
||||||
(LinkTlvs.IFACE1_IP4, iface1_ip4),
|
|
||||||
(LinkTlvs.IFACE1_IP4_MASK, 24),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
switch_node = coretlv.session.get_node(switch_id, SwitchNode)
|
|
||||||
all_links = switch_node.links()
|
|
||||||
assert len(all_links) == 1
|
|
||||||
|
|
||||||
message = coreapi.CoreLinkMessage.create(
|
|
||||||
MessageFlags.DELETE.value,
|
|
||||||
[
|
|
||||||
(LinkTlvs.N1_NUMBER, node1_id),
|
|
||||||
(LinkTlvs.N2_NUMBER, switch_id),
|
|
||||||
(LinkTlvs.IFACE1_NUMBER, 0),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
switch_node = coretlv.session.get_node(switch_id, SwitchNode)
|
|
||||||
all_links = switch_node.links()
|
|
||||||
assert len(all_links) == 0
|
|
||||||
|
|
||||||
def test_link_delete_net_to_node(self, coretlv: CoreHandler):
|
|
||||||
node1_id = 1
|
|
||||||
coretlv.session.add_node(CoreNode, _id=node1_id)
|
|
||||||
switch_id = 2
|
|
||||||
coretlv.session.add_node(SwitchNode, _id=switch_id)
|
|
||||||
ip_prefix = netaddr.IPNetwork("10.0.0.0/24")
|
|
||||||
iface1_ip4 = str(ip_prefix[node1_id])
|
|
||||||
message = coreapi.CoreLinkMessage.create(
|
|
||||||
MessageFlags.ADD.value,
|
|
||||||
[
|
|
||||||
(LinkTlvs.N1_NUMBER, node1_id),
|
|
||||||
(LinkTlvs.N2_NUMBER, switch_id),
|
|
||||||
(LinkTlvs.IFACE1_NUMBER, 0),
|
|
||||||
(LinkTlvs.IFACE1_IP4, iface1_ip4),
|
|
||||||
(LinkTlvs.IFACE1_IP4_MASK, 24),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
switch_node = coretlv.session.get_node(switch_id, SwitchNode)
|
|
||||||
all_links = switch_node.links()
|
|
||||||
assert len(all_links) == 1
|
|
||||||
|
|
||||||
message = coreapi.CoreLinkMessage.create(
|
|
||||||
MessageFlags.DELETE.value,
|
|
||||||
[
|
|
||||||
(LinkTlvs.N1_NUMBER, switch_id),
|
|
||||||
(LinkTlvs.N2_NUMBER, node1_id),
|
|
||||||
(LinkTlvs.IFACE2_NUMBER, 0),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
switch_node = coretlv.session.get_node(switch_id, SwitchNode)
|
|
||||||
all_links = switch_node.links()
|
|
||||||
assert len(all_links) == 0
|
|
||||||
|
|
||||||
def test_session_update(self, coretlv: CoreHandler):
|
|
||||||
session_id = coretlv.session.id
|
|
||||||
name = "test"
|
|
||||||
message = coreapi.CoreSessionMessage.create(
|
|
||||||
0, [(SessionTlvs.NUMBER, str(session_id)), (SessionTlvs.NAME, name)]
|
|
||||||
)
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
assert coretlv.session.name == name
|
|
||||||
|
|
||||||
def test_session_query(self, coretlv: CoreHandler):
|
|
||||||
coretlv.dispatch_replies = mock.MagicMock()
|
|
||||||
message = coreapi.CoreSessionMessage.create(MessageFlags.STRING.value, [])
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
args, _ = coretlv.dispatch_replies.call_args
|
|
||||||
replies = args[0]
|
|
||||||
assert len(replies) == 1
|
|
||||||
|
|
||||||
def test_session_join(self, coretlv: CoreHandler):
|
|
||||||
coretlv.dispatch_replies = mock.MagicMock()
|
|
||||||
session_id = coretlv.session.id
|
|
||||||
message = coreapi.CoreSessionMessage.create(
|
|
||||||
MessageFlags.ADD.value, [(SessionTlvs.NUMBER, str(session_id))]
|
|
||||||
)
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
assert coretlv.session.id == session_id
|
|
||||||
|
|
||||||
def test_session_delete(self, coretlv: CoreHandler):
|
|
||||||
assert len(coretlv.coreemu.sessions) == 1
|
|
||||||
session_id = coretlv.session.id
|
|
||||||
message = coreapi.CoreSessionMessage.create(
|
|
||||||
MessageFlags.DELETE.value, [(SessionTlvs.NUMBER, str(session_id))]
|
|
||||||
)
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
assert len(coretlv.coreemu.sessions) == 0
|
|
||||||
|
|
||||||
def test_file_hook_add(self, coretlv: CoreHandler):
|
|
||||||
state = EventTypes.DATACOLLECT_STATE
|
|
||||||
assert coretlv.session.hooks.get(state) is None
|
|
||||||
file_name = "test.sh"
|
|
||||||
file_data = "echo hello"
|
|
||||||
message = coreapi.CoreFileMessage.create(
|
|
||||||
MessageFlags.ADD.value,
|
|
||||||
[
|
|
||||||
(FileTlvs.TYPE, f"hook:{state.value}"),
|
|
||||||
(FileTlvs.NAME, file_name),
|
|
||||||
(FileTlvs.DATA, file_data),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
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, coretlv: CoreHandler):
|
|
||||||
node = coretlv.session.add_node(CoreNode)
|
|
||||||
service = "DefaultRoute"
|
|
||||||
file_name = "defaultroute.sh"
|
|
||||||
file_data = "echo hello"
|
|
||||||
message = coreapi.CoreFileMessage.create(
|
|
||||||
MessageFlags.ADD.value,
|
|
||||||
[
|
|
||||||
(FileTlvs.NODE, node.id),
|
|
||||||
(FileTlvs.TYPE, f"service:{service}"),
|
|
||||||
(FileTlvs.NAME, file_name),
|
|
||||||
(FileTlvs.DATA, file_data),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
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, request, coretlv: CoreHandler):
|
|
||||||
file_path = Path("/var/log/test/node.log")
|
|
||||||
node = coretlv.session.add_node(CoreNode)
|
|
||||||
node.makenodedir()
|
|
||||||
file_data = "echo hello"
|
|
||||||
message = coreapi.CoreFileMessage.create(
|
|
||||||
MessageFlags.ADD.value,
|
|
||||||
[
|
|
||||||
(FileTlvs.NODE, node.id),
|
|
||||||
(FileTlvs.NAME, str(file_path)),
|
|
||||||
(FileTlvs.DATA, file_data),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
if not request.config.getoption("mock"):
|
|
||||||
expected_path = node.directory / "var.log/test" / file_path.name
|
|
||||||
assert expected_path.exists()
|
|
||||||
|
|
||||||
def test_exec_node_tty(self, coretlv: CoreHandler):
|
|
||||||
coretlv.dispatch_replies = mock.MagicMock()
|
|
||||||
node = coretlv.session.add_node(CoreNode)
|
|
||||||
message = coreapi.CoreExecMessage.create(
|
|
||||||
MessageFlags.TTY.value,
|
|
||||||
[
|
|
||||||
(ExecuteTlvs.NODE, node.id),
|
|
||||||
(ExecuteTlvs.NUMBER, 1),
|
|
||||||
(ExecuteTlvs.COMMAND, "bash"),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
args, _ = coretlv.dispatch_replies.call_args
|
|
||||||
replies = args[0]
|
|
||||||
assert len(replies) == 1
|
|
||||||
|
|
||||||
def test_exec_local_command(self, request, coretlv: CoreHandler):
|
|
||||||
if request.config.getoption("mock"):
|
|
||||||
pytest.skip("mocking calls")
|
|
||||||
|
|
||||||
coretlv.dispatch_replies = mock.MagicMock()
|
|
||||||
node = coretlv.session.add_node(CoreNode)
|
|
||||||
cmd = "echo hello"
|
|
||||||
message = coreapi.CoreExecMessage.create(
|
|
||||||
MessageFlags.TEXT.value | MessageFlags.LOCAL.value,
|
|
||||||
[
|
|
||||||
(ExecuteTlvs.NODE, node.id),
|
|
||||||
(ExecuteTlvs.NUMBER, 1),
|
|
||||||
(ExecuteTlvs.COMMAND, cmd),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
args, _ = coretlv.dispatch_replies.call_args
|
|
||||||
replies = args[0]
|
|
||||||
assert len(replies) == 1
|
|
||||||
|
|
||||||
def test_exec_node_command(self, coretlv: CoreHandler):
|
|
||||||
coretlv.dispatch_replies = mock.MagicMock()
|
|
||||||
node = coretlv.session.add_node(CoreNode)
|
|
||||||
cmd = "echo hello"
|
|
||||||
message = coreapi.CoreExecMessage.create(
|
|
||||||
MessageFlags.TEXT.value,
|
|
||||||
[
|
|
||||||
(ExecuteTlvs.NODE, node.id),
|
|
||||||
(ExecuteTlvs.NUMBER, 1),
|
|
||||||
(ExecuteTlvs.COMMAND, cmd),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
node.cmd = MagicMock(return_value="hello")
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
node.cmd.assert_called_with(cmd)
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"state",
|
|
||||||
[
|
|
||||||
EventTypes.SHUTDOWN_STATE,
|
|
||||||
EventTypes.RUNTIME_STATE,
|
|
||||||
EventTypes.DATACOLLECT_STATE,
|
|
||||||
EventTypes.CONFIGURATION_STATE,
|
|
||||||
EventTypes.DEFINITION_STATE,
|
|
||||||
],
|
|
||||||
)
|
|
||||||
def test_event_state(self, coretlv: CoreHandler, state: EventTypes):
|
|
||||||
message = coreapi.CoreEventMessage.create(0, [(EventTlvs.TYPE, state.value)])
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
assert coretlv.session.state == state
|
|
||||||
|
|
||||||
def test_event_schedule(self, coretlv: CoreHandler):
|
|
||||||
coretlv.session.add_event = mock.MagicMock()
|
|
||||||
node = coretlv.session.add_node(CoreNode)
|
|
||||||
message = coreapi.CoreEventMessage.create(
|
|
||||||
MessageFlags.ADD.value,
|
|
||||||
[
|
|
||||||
(EventTlvs.TYPE, EventTypes.SCHEDULED.value),
|
|
||||||
(EventTlvs.TIME, str(time.monotonic() + 100)),
|
|
||||||
(EventTlvs.NODE, node.id),
|
|
||||||
(EventTlvs.NAME, "event"),
|
|
||||||
(EventTlvs.DATA, "data"),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
coretlv.session.add_event.assert_called_once()
|
|
||||||
|
|
||||||
def test_event_save_xml(self, coretlv: CoreHandler, tmpdir):
|
|
||||||
xml_file = tmpdir.join("coretlv.session.xml")
|
|
||||||
file_path = xml_file.strpath
|
|
||||||
coretlv.session.add_node(CoreNode)
|
|
||||||
message = coreapi.CoreEventMessage.create(
|
|
||||||
0,
|
|
||||||
[(EventTlvs.TYPE, EventTypes.FILE_SAVE.value), (EventTlvs.NAME, file_path)],
|
|
||||||
)
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
assert Path(file_path).exists()
|
|
||||||
|
|
||||||
def test_event_open_xml(self, coretlv: CoreHandler, tmpdir):
|
|
||||||
xml_file = tmpdir.join("coretlv.session.xml")
|
|
||||||
file_path = Path(xml_file.strpath)
|
|
||||||
node = coretlv.session.add_node(CoreNode)
|
|
||||||
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, str(file_path)),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
assert coretlv.session.get_node(node.id, NodeBase)
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"state",
|
|
||||||
[
|
|
||||||
EventTypes.START,
|
|
||||||
EventTypes.STOP,
|
|
||||||
EventTypes.RESTART,
|
|
||||||
EventTypes.PAUSE,
|
|
||||||
EventTypes.RECONFIGURE,
|
|
||||||
],
|
|
||||||
)
|
|
||||||
def test_event_service(self, coretlv: CoreHandler, state: EventTypes):
|
|
||||||
coretlv.session.broadcast_event = mock.MagicMock()
|
|
||||||
node = coretlv.session.add_node(CoreNode)
|
|
||||||
message = coreapi.CoreEventMessage.create(
|
|
||||||
0,
|
|
||||||
[
|
|
||||||
(EventTlvs.TYPE, state.value),
|
|
||||||
(EventTlvs.NODE, node.id),
|
|
||||||
(EventTlvs.NAME, "service:DefaultRoute"),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
coretlv.session.broadcast_event.assert_called_once()
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
|
||||||
"state",
|
|
||||||
[
|
|
||||||
EventTypes.START,
|
|
||||||
EventTypes.STOP,
|
|
||||||
EventTypes.RESTART,
|
|
||||||
EventTypes.PAUSE,
|
|
||||||
EventTypes.RECONFIGURE,
|
|
||||||
],
|
|
||||||
)
|
|
||||||
def test_event_mobility(self, coretlv: CoreHandler, state: EventTypes):
|
|
||||||
message = coreapi.CoreEventMessage.create(
|
|
||||||
0, [(EventTlvs.TYPE, state.value), (EventTlvs.NAME, "mobility:ns2script")]
|
|
||||||
)
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
def test_register_gui(self, coretlv: CoreHandler):
|
|
||||||
message = coreapi.CoreRegMessage.create(0, [(RegisterTlvs.GUI, "gui")])
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
def test_register_xml(self, coretlv: CoreHandler, tmpdir):
|
|
||||||
xml_file = tmpdir.join("coretlv.session.xml")
|
|
||||||
file_path = xml_file.strpath
|
|
||||||
node = coretlv.session.add_node(CoreNode)
|
|
||||||
coretlv.session.save_xml(file_path)
|
|
||||||
coretlv.session.delete_node(node.id)
|
|
||||||
message = coreapi.CoreRegMessage.create(
|
|
||||||
0, [(RegisterTlvs.EXECUTE_SERVER, file_path)]
|
|
||||||
)
|
|
||||||
coretlv.session.instantiate()
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
assert coretlv.coreemu.sessions[1].get_node(node.id, CoreNode)
|
|
||||||
|
|
||||||
def test_register_python(self, coretlv: CoreHandler, tmpdir):
|
|
||||||
xml_file = tmpdir.join("test.py")
|
|
||||||
file_path = xml_file.strpath
|
|
||||||
with open(file_path, "w") as f:
|
|
||||||
f.write("from core.nodes.base import CoreNode\n")
|
|
||||||
f.write("coreemu = globals()['coreemu']\n")
|
|
||||||
f.write(f"session = coreemu.sessions[{coretlv.session.id}]\n")
|
|
||||||
f.write("session.add_node(CoreNode)\n")
|
|
||||||
message = coreapi.CoreRegMessage.create(
|
|
||||||
0, [(RegisterTlvs.EXECUTE_SERVER, file_path)]
|
|
||||||
)
|
|
||||||
coretlv.session.instantiate()
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
assert len(coretlv.session.nodes) == 1
|
|
||||||
|
|
||||||
def test_config_all(self, coretlv: CoreHandler):
|
|
||||||
message = coreapi.CoreConfMessage.create(
|
|
||||||
MessageFlags.ADD.value,
|
|
||||||
[(ConfigTlvs.OBJECT, "all"), (ConfigTlvs.TYPE, ConfigFlags.RESET.value)],
|
|
||||||
)
|
|
||||||
coretlv.session.location.refxyz = (10, 10, 10)
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
assert coretlv.session.location.refxyz == (0, 0, 0)
|
|
||||||
|
|
||||||
def test_config_options_request(self, coretlv: CoreHandler):
|
|
||||||
message = coreapi.CoreConfMessage.create(
|
|
||||||
0,
|
|
||||||
[
|
|
||||||
(ConfigTlvs.OBJECT, "session"),
|
|
||||||
(ConfigTlvs.TYPE, ConfigFlags.REQUEST.value),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
coretlv.handle_broadcast_config = mock.MagicMock()
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
coretlv.handle_broadcast_config.assert_called_once()
|
|
||||||
|
|
||||||
def test_config_options_update(self, coretlv: CoreHandler):
|
|
||||||
test_key = "test"
|
|
||||||
test_value = "test"
|
|
||||||
values = {test_key: test_value}
|
|
||||||
message = coreapi.CoreConfMessage.create(
|
|
||||||
0,
|
|
||||||
[
|
|
||||||
(ConfigTlvs.OBJECT, "session"),
|
|
||||||
(ConfigTlvs.TYPE, ConfigFlags.UPDATE.value),
|
|
||||||
(ConfigTlvs.VALUES, dict_to_str(values)),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
assert coretlv.session.options.get_config(test_key) == test_value
|
|
||||||
|
|
||||||
def test_config_location_reset(self, coretlv: CoreHandler):
|
|
||||||
message = coreapi.CoreConfMessage.create(
|
|
||||||
0,
|
|
||||||
[
|
|
||||||
(ConfigTlvs.OBJECT, "location"),
|
|
||||||
(ConfigTlvs.TYPE, ConfigFlags.RESET.value),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
coretlv.session.location.refxyz = (10, 10, 10)
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
assert coretlv.session.location.refxyz == (0, 0, 0)
|
|
||||||
|
|
||||||
def test_config_location_update(self, coretlv: CoreHandler):
|
|
||||||
message = coreapi.CoreConfMessage.create(
|
|
||||||
0,
|
|
||||||
[
|
|
||||||
(ConfigTlvs.OBJECT, "location"),
|
|
||||||
(ConfigTlvs.TYPE, ConfigFlags.UPDATE.value),
|
|
||||||
(ConfigTlvs.VALUES, "10|10|70|50|0|0.5"),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
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, coretlv: CoreHandler):
|
|
||||||
message = coreapi.CoreConfMessage.create(
|
|
||||||
0,
|
|
||||||
[
|
|
||||||
(ConfigTlvs.OBJECT, "metadata"),
|
|
||||||
(ConfigTlvs.TYPE, ConfigFlags.REQUEST.value),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
coretlv.handle_broadcast_config = mock.MagicMock()
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
coretlv.handle_broadcast_config.assert_called_once()
|
|
||||||
|
|
||||||
def test_config_metadata_update(self, coretlv: CoreHandler):
|
|
||||||
test_key = "test"
|
|
||||||
test_value = "test"
|
|
||||||
values = {test_key: test_value}
|
|
||||||
message = coreapi.CoreConfMessage.create(
|
|
||||||
0,
|
|
||||||
[
|
|
||||||
(ConfigTlvs.OBJECT, "metadata"),
|
|
||||||
(ConfigTlvs.TYPE, ConfigFlags.UPDATE.value),
|
|
||||||
(ConfigTlvs.VALUES, dict_to_str(values)),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
assert coretlv.session.metadata[test_key] == test_value
|
|
||||||
|
|
||||||
def test_config_broker_request(self, coretlv: CoreHandler):
|
|
||||||
server = "test"
|
|
||||||
host = "10.0.0.1"
|
|
||||||
port = 50000
|
|
||||||
message = coreapi.CoreConfMessage.create(
|
|
||||||
0,
|
|
||||||
[
|
|
||||||
(ConfigTlvs.OBJECT, "broker"),
|
|
||||||
(ConfigTlvs.TYPE, ConfigFlags.UPDATE.value),
|
|
||||||
(ConfigTlvs.VALUES, f"{server}:{host}:{port}"),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
coretlv.session.distributed.add_server = mock.MagicMock()
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
coretlv.session.distributed.add_server.assert_called_once_with(server, host)
|
|
||||||
|
|
||||||
def test_config_services_request_all(self, coretlv: CoreHandler):
|
|
||||||
message = coreapi.CoreConfMessage.create(
|
|
||||||
0,
|
|
||||||
[
|
|
||||||
(ConfigTlvs.OBJECT, "services"),
|
|
||||||
(ConfigTlvs.TYPE, ConfigFlags.REQUEST.value),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
coretlv.handle_broadcast_config = mock.MagicMock()
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
coretlv.handle_broadcast_config.assert_called_once()
|
|
||||||
|
|
||||||
def test_config_services_request_specific(self, coretlv: CoreHandler):
|
|
||||||
node = coretlv.session.add_node(CoreNode)
|
|
||||||
message = coreapi.CoreConfMessage.create(
|
|
||||||
0,
|
|
||||||
[
|
|
||||||
(ConfigTlvs.NODE, node.id),
|
|
||||||
(ConfigTlvs.OBJECT, "services"),
|
|
||||||
(ConfigTlvs.TYPE, ConfigFlags.REQUEST.value),
|
|
||||||
(ConfigTlvs.OPAQUE, "service:DefaultRoute"),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
coretlv.handle_broadcast_config = mock.MagicMock()
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
coretlv.handle_broadcast_config.assert_called_once()
|
|
||||||
|
|
||||||
def test_config_services_request_specific_file(self, coretlv: CoreHandler):
|
|
||||||
node = coretlv.session.add_node(CoreNode)
|
|
||||||
message = coreapi.CoreConfMessage.create(
|
|
||||||
0,
|
|
||||||
[
|
|
||||||
(ConfigTlvs.NODE, node.id),
|
|
||||||
(ConfigTlvs.OBJECT, "services"),
|
|
||||||
(ConfigTlvs.TYPE, ConfigFlags.REQUEST.value),
|
|
||||||
(ConfigTlvs.OPAQUE, "service:DefaultRoute:defaultroute.sh"),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
coretlv.session.broadcast_file = mock.MagicMock()
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
coretlv.session.broadcast_file.assert_called_once()
|
|
||||||
|
|
||||||
def test_config_services_reset(self, coretlv: CoreHandler):
|
|
||||||
node = coretlv.session.add_node(CoreNode)
|
|
||||||
service = "DefaultRoute"
|
|
||||||
coretlv.session.services.set_service(node.id, service)
|
|
||||||
message = coreapi.CoreConfMessage.create(
|
|
||||||
0,
|
|
||||||
[
|
|
||||||
(ConfigTlvs.OBJECT, "services"),
|
|
||||||
(ConfigTlvs.TYPE, ConfigFlags.RESET.value),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
assert coretlv.session.services.get_service(node.id, service) is not None
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
assert coretlv.session.services.get_service(node.id, service) is None
|
|
||||||
|
|
||||||
def test_config_services_set(self, coretlv: CoreHandler):
|
|
||||||
node = coretlv.session.add_node(CoreNode)
|
|
||||||
service = "DefaultRoute"
|
|
||||||
values = {"meta": "metadata"}
|
|
||||||
message = coreapi.CoreConfMessage.create(
|
|
||||||
0,
|
|
||||||
[
|
|
||||||
(ConfigTlvs.NODE, node.id),
|
|
||||||
(ConfigTlvs.OBJECT, "services"),
|
|
||||||
(ConfigTlvs.TYPE, ConfigFlags.UPDATE.value),
|
|
||||||
(ConfigTlvs.OPAQUE, f"service:{service}"),
|
|
||||||
(ConfigTlvs.VALUES, dict_to_str(values)),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
assert coretlv.session.services.get_service(node.id, service) is None
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
assert coretlv.session.services.get_service(node.id, service) is not None
|
|
||||||
|
|
||||||
def test_config_mobility_reset(self, coretlv: CoreHandler):
|
|
||||||
wlan = coretlv.session.add_node(WlanNode)
|
|
||||||
message = coreapi.CoreConfMessage.create(
|
|
||||||
0,
|
|
||||||
[
|
|
||||||
(ConfigTlvs.OBJECT, "MobilityManager"),
|
|
||||||
(ConfigTlvs.TYPE, ConfigFlags.RESET.value),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
coretlv.session.mobility.set_model_config(wlan.id, BasicRangeModel.name, {})
|
|
||||||
assert len(coretlv.session.mobility.node_configurations) == 1
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
assert len(coretlv.session.mobility.node_configurations) == 0
|
|
||||||
|
|
||||||
def test_config_mobility_model_request(self, coretlv: CoreHandler):
|
|
||||||
wlan = coretlv.session.add_node(WlanNode)
|
|
||||||
message = coreapi.CoreConfMessage.create(
|
|
||||||
0,
|
|
||||||
[
|
|
||||||
(ConfigTlvs.NODE, wlan.id),
|
|
||||||
(ConfigTlvs.OBJECT, BasicRangeModel.name),
|
|
||||||
(ConfigTlvs.TYPE, ConfigFlags.REQUEST.value),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
coretlv.handle_broadcast_config = mock.MagicMock()
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
coretlv.handle_broadcast_config.assert_called_once()
|
|
||||||
|
|
||||||
def test_config_mobility_model_update(self, coretlv: CoreHandler):
|
|
||||||
wlan = coretlv.session.add_node(WlanNode)
|
|
||||||
config_key = "range"
|
|
||||||
config_value = "1000"
|
|
||||||
values = {config_key: config_value}
|
|
||||||
message = coreapi.CoreConfMessage.create(
|
|
||||||
0,
|
|
||||||
[
|
|
||||||
(ConfigTlvs.NODE, wlan.id),
|
|
||||||
(ConfigTlvs.OBJECT, BasicRangeModel.name),
|
|
||||||
(ConfigTlvs.TYPE, ConfigFlags.UPDATE.value),
|
|
||||||
(ConfigTlvs.VALUES, dict_to_str(values)),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
config = coretlv.session.mobility.get_model_config(
|
|
||||||
wlan.id, BasicRangeModel.name
|
|
||||||
)
|
|
||||||
assert config[config_key] == config_value
|
|
||||||
|
|
||||||
def test_config_emane_model_request(self, coretlv: CoreHandler):
|
|
||||||
wlan = coretlv.session.add_node(WlanNode)
|
|
||||||
message = coreapi.CoreConfMessage.create(
|
|
||||||
0,
|
|
||||||
[
|
|
||||||
(ConfigTlvs.NODE, wlan.id),
|
|
||||||
(ConfigTlvs.OBJECT, EmaneIeee80211abgModel.name),
|
|
||||||
(ConfigTlvs.TYPE, ConfigFlags.REQUEST.value),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
coretlv.handle_broadcast_config = mock.MagicMock()
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
coretlv.handle_broadcast_config.assert_called_once()
|
|
||||||
|
|
||||||
def test_config_emane_model_update(self, coretlv: CoreHandler):
|
|
||||||
wlan = coretlv.session.add_node(WlanNode)
|
|
||||||
config_key = "distance"
|
|
||||||
config_value = "50051"
|
|
||||||
values = {config_key: config_value}
|
|
||||||
message = coreapi.CoreConfMessage.create(
|
|
||||||
0,
|
|
||||||
[
|
|
||||||
(ConfigTlvs.NODE, wlan.id),
|
|
||||||
(ConfigTlvs.OBJECT, EmaneIeee80211abgModel.name),
|
|
||||||
(ConfigTlvs.TYPE, ConfigFlags.UPDATE.value),
|
|
||||||
(ConfigTlvs.VALUES, dict_to_str(values)),
|
|
||||||
],
|
|
||||||
)
|
|
||||||
|
|
||||||
coretlv.handle_message(message)
|
|
||||||
|
|
||||||
config = coretlv.session.emane.get_config(wlan.id, EmaneIeee80211abgModel.name)
|
|
||||||
assert config[config_key] == config_value
|
|
18
docs/gui.md
18
docs/gui.md
|
@ -432,7 +432,7 @@ firewall is not blocking the GRE traffic.
|
||||||
The host machine that runs the CORE GUI and/or daemon is not necessarily
|
The host machine that runs the CORE GUI and/or daemon is not necessarily
|
||||||
accessible from a node. Running an X11 application on a node, for example,
|
accessible from a node. Running an X11 application on a node, for example,
|
||||||
requires some channel of communication for the application to connect with
|
requires some channel of communication for the application to connect with
|
||||||
the X server for graphical display. There are several different ways to
|
the X server for graphical display. There are different ways to
|
||||||
connect from the node to the host and vice versa.
|
connect from the node to the host and vice versa.
|
||||||
|
|
||||||
#### Control Network
|
#### Control Network
|
||||||
|
@ -449,12 +449,6 @@ the node, and SSH with X11 forwarding can be used from the host to the node.
|
||||||
ssh -X 172.16.0.5 xclock
|
ssh -X 172.16.0.5 xclock
|
||||||
```
|
```
|
||||||
|
|
||||||
Note that the **coresendmsg** utility can be used for a node to send
|
|
||||||
messages to the CORE daemon running on the host (if the **listenaddr = 0.0.0.0**
|
|
||||||
is set in the **/etc/core/core.conf** file) to interact with the running
|
|
||||||
emulation. For example, a node may move itself or other nodes, or change
|
|
||||||
its icon based on some node state.
|
|
||||||
|
|
||||||
#### Other Methods
|
#### Other Methods
|
||||||
|
|
||||||
There are still other ways to connect a host with a node. The RJ45 Tool
|
There are still other ways to connect a host with a node. The RJ45 Tool
|
||||||
|
@ -552,11 +546,11 @@ See the [EMANE](emane.md) chapter for details on using EMANE.
|
||||||
|
|
||||||
CORE has a few ways to script mobility.
|
CORE has a few ways to script mobility.
|
||||||
|
|
||||||
| Option | Description |
|
| Option | Description |
|
||||||
|--------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
|--------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
| ns-2 script | The script specifies either absolute positions or waypoints with a velocity. Locations are given with Cartesian coordinates. |
|
| ns-2 script | The script specifies either absolute positions or waypoints with a velocity. Locations are given with Cartesian coordinates. |
|
||||||
| CORE API | An external entity can move nodes by sending CORE API Node messages with updated X,Y coordinates; the **coresendmsg** utility allows a shell script to generate these messages. |
|
| gRPC API | An external entity can move nodes by leveraging the gRPC API |
|
||||||
| EMANE events | See [EMANE](emane.md) for details on using EMANE scripts to move nodes around. Location information is typically given as latitude, longitude, and altitude. |
|
| EMANE events | See [EMANE](emane.md) for details on using EMANE scripts to move nodes around. Location information is typically given as latitude, longitude, and altitude. |
|
||||||
|
|
||||||
For the first method, you can create a mobility script using a text
|
For the first method, you can create a mobility script using a text
|
||||||
editor, or using a tool such as [BonnMotion](http://net.cs.uni-bonn.de/wg/cs/applications/bonnmotion/), and associate the script with one of the wireless
|
editor, or using a tool such as [BonnMotion](http://net.cs.uni-bonn.de/wg/cs/applications/bonnmotion/), and associate the script with one of the wireless
|
||||||
|
|
|
@ -74,7 +74,6 @@ After the installation complete it will have installed the following scripts.
|
||||||
| core-cli | tool to query, open xml files, and send commands using gRPC |
|
| core-cli | tool to query, open xml files, and send commands using gRPC |
|
||||||
| core-daemon | runs the backed core server providing a gRPC API |
|
| core-daemon | runs the backed core server providing a gRPC API |
|
||||||
| core-gui | starts GUI |
|
| core-gui | starts GUI |
|
||||||
| core-manage | tool to add, remove, or check for services, models, and node types |
|
|
||||||
| core-python | provides a convenience for running the core python virtual environment |
|
| core-python | provides a convenience for running the core python virtual environment |
|
||||||
| core-route-monitor | tool to help monitor traffic across nodes and feed that to SDT |
|
| core-route-monitor | tool to help monitor traffic across nodes and feed that to SDT |
|
||||||
| core-service-update | tool to update automate modifying a legacy service to match current naming |
|
| core-service-update | tool to update automate modifying a legacy service to match current naming |
|
||||||
|
|
|
@ -1,21 +1,10 @@
|
||||||
# CORE
|
# CORE
|
||||||
# (c)2012-2013 the Boeing Company.
|
|
||||||
# See the LICENSE file included in this distribution.
|
|
||||||
#
|
|
||||||
# author: Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
|
|
||||||
#
|
|
||||||
# Makefile for building man pages.
|
|
||||||
#
|
|
||||||
|
|
||||||
if WANT_GUI
|
|
||||||
GUI_MANS = core-gui.1
|
|
||||||
endif
|
|
||||||
|
|
||||||
if WANT_DAEMON
|
if WANT_DAEMON
|
||||||
DAEMON_MANS = vnoded.1 vcmd.1 netns.1 core-daemon.1 coresendmsg.1 \
|
DAEMON_MANS = vnoded.1 vcmd.1 netns.1 core-daemon.1 core-gui.1 \
|
||||||
core-cleanup.1 core-manage.1
|
core-cleanup.1
|
||||||
endif
|
endif
|
||||||
man_MANS = $(GUI_MANS) $(DAEMON_MANS)
|
man_MANS = $(DAEMON_MANS)
|
||||||
|
|
||||||
.PHONY: generate-mans
|
.PHONY: generate-mans
|
||||||
generate-mans:
|
generate-mans:
|
||||||
|
@ -24,9 +13,7 @@ generate-mans:
|
||||||
$(HELP2MAN) --no-info --source CORE $(top_srcdir)/netns/vcmd -o vcmd.1
|
$(HELP2MAN) --no-info --source CORE $(top_srcdir)/netns/vcmd -o vcmd.1
|
||||||
$(HELP2MAN) --no-info --source CORE $(top_srcdir)/netns/netns -o netns.1
|
$(HELP2MAN) --no-info --source CORE $(top_srcdir)/netns/netns -o netns.1
|
||||||
$(HELP2MAN) --version-string=$(PACKAGE_VERSION) --no-info --source CORE $(top_srcdir)/daemon/scripts/core-daemon -o core-daemon.1
|
$(HELP2MAN) --version-string=$(PACKAGE_VERSION) --no-info --source CORE $(top_srcdir)/daemon/scripts/core-daemon -o core-daemon.1
|
||||||
$(HELP2MAN) --version-string=$(PACKAGE_VERSION) --no-info --source CORE $(top_srcdir)/daemon/scripts/coresendmsg -o coresendmsg.1
|
|
||||||
$(HELP2MAN) --version-string=$(PACKAGE_VERSION) --no-info --source CORE $(top_srcdir)/daemon/scripts/core-cleanup -o core-cleanup.1
|
$(HELP2MAN) --version-string=$(PACKAGE_VERSION) --no-info --source CORE $(top_srcdir)/daemon/scripts/core-cleanup -o core-cleanup.1
|
||||||
$(HELP2MAN) --version-string=$(PACKAGE_VERSION) --no-info --source CORE $(top_srcdir)/daemon/scripts/core-manage -o core-manage.1
|
|
||||||
|
|
||||||
.PHONY: diff
|
.PHONY: diff
|
||||||
diff:
|
diff:
|
||||||
|
|
|
@ -1,31 +0,0 @@
|
||||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6.
|
|
||||||
.TH CORE-MANAGE "1" "June 2020" "CORE" "User Commands"
|
|
||||||
.SH NAME
|
|
||||||
core-manage \- manual page for core-manage 6.4.0
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.B core-manage
|
|
||||||
[\fI\,-h\/\fR] [\fI\,options\/\fR] \fI\,<action> <target> <string>\/\fR
|
|
||||||
.SH DESCRIPTION
|
|
||||||
Helper tool to add, remove, or check for services, models, and node types
|
|
||||||
in a CORE installation.
|
|
||||||
.SH OPTIONS
|
|
||||||
.TP
|
|
||||||
\fB\-h\fR, \fB\-\-help\fR
|
|
||||||
show this help message and exit
|
|
||||||
.TP
|
|
||||||
\fB\-\-userpath\fR=\fI\,USERPATH\/\fR
|
|
||||||
use the specified user path (e.g. "$HOME/.core") to
|
|
||||||
access nodes.conf
|
|
||||||
.TP
|
|
||||||
\fB\-v\fR, \fB\-\-verbose\fR
|
|
||||||
be verbose when performing action
|
|
||||||
.SH EXAMPLES
|
|
||||||
.IP
|
|
||||||
core\-manage add service newrouting
|
|
||||||
core\-manage \-v check model RfPipe
|
|
||||||
core\-manage \-\-userpath="$HOME/.core" add nodetype "{ftp ftp.gif ftp.gif {DefaultRoute FTP} netns {FTP server} }"
|
|
||||||
.SS "Arguments:"
|
|
||||||
.IP
|
|
||||||
<action> should be one of: add, remove, check
|
|
||||||
<target> should be one of: service, model, nodetype
|
|
||||||
<string> is the text to add, remove, check
|
|
|
@ -1,40 +0,0 @@
|
||||||
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.47.6.
|
|
||||||
.TH CORESENDMSG "1" "June 2020" "CORE" "User Commands"
|
|
||||||
.SH NAME
|
|
||||||
coresendmsg \- manual page for coresendmsg 6.4.0
|
|
||||||
.SH SYNOPSIS
|
|
||||||
.B coresendmsg
|
|
||||||
[\fI\,-h|-H\/\fR] [\fI\,options\/\fR] [\fI\,message-type\/\fR] [\fI\,flags=flags\/\fR] [\fI\,message-TLVs\/\fR]
|
|
||||||
.SH DESCRIPTION
|
|
||||||
.SS "Supported message types:"
|
|
||||||
.IP
|
|
||||||
node link execute register config file interface event session exception
|
|
||||||
.SS "Supported message flags (flags=f1,f2,...):"
|
|
||||||
.IP
|
|
||||||
none add delete cri local string text tty
|
|
||||||
.SH OPTIONS
|
|
||||||
.TP
|
|
||||||
\fB\-h\fR, \fB\-\-help\fR
|
|
||||||
show this help message and exit
|
|
||||||
.TP
|
|
||||||
\fB\-H\fR
|
|
||||||
show example usage help message and exit
|
|
||||||
.TP
|
|
||||||
\fB\-p\fR PORT, \fB\-\-port\fR=\fI\,PORT\/\fR
|
|
||||||
TCP port to connect to, default: 4038
|
|
||||||
.TP
|
|
||||||
\fB\-a\fR ADDRESS, \fB\-\-address\fR=\fI\,ADDRESS\/\fR
|
|
||||||
Address to connect to, default: localhost
|
|
||||||
.TP
|
|
||||||
\fB\-s\fR SESSION, \fB\-\-session\fR=\fI\,SESSION\/\fR
|
|
||||||
Session to join, default: None
|
|
||||||
.TP
|
|
||||||
\fB\-l\fR, \fB\-\-listen\fR
|
|
||||||
Listen for a response message and print it.
|
|
||||||
.TP
|
|
||||||
\fB\-t\fR, \fB\-\-list\-tlvs\fR
|
|
||||||
List TLVs for the specified message type.
|
|
||||||
.TP
|
|
||||||
\fB\-\-tcp\fR
|
|
||||||
Use TCP instead of UDP and connect to a session
|
|
||||||
default: False
|
|
|
@ -1,8 +1,4 @@
|
||||||
# CORE
|
# CORE
|
||||||
# (c)2010-2013 the Boeing Company.
|
|
||||||
# See the LICENSE file included in this distribution.
|
|
||||||
#
|
|
||||||
# author: Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
|
|
||||||
#
|
#
|
||||||
# Makefile for building netns.
|
# Makefile for building netns.
|
||||||
#
|
#
|
||||||
|
|
|
@ -1,9 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* CORE
|
* CORE
|
||||||
* Copyright (c)2012 the Boeing Company.
|
|
||||||
* See the LICENSE file included in this distribution.
|
|
||||||
*
|
|
||||||
* author: Jeff Ahrenholz <jeffrey.m.ahrenholz@boeing.com>
|
|
||||||
*
|
*
|
||||||
* version.h
|
* version.h
|
||||||
*
|
*
|
||||||
|
|
Loading…
Reference in a new issue