grpc: changes to support nodes containing configuration data, allowing for node creation with configs and querying nodes with their configs
This commit is contained in:
parent
8678922c92
commit
54ac807a4f
11 changed files with 290 additions and 291 deletions
|
@ -11,16 +11,7 @@ from typing import Any, Callable, Dict, Generator, Iterable, List, Optional, Tup
|
||||||
|
|
||||||
import grpc
|
import grpc
|
||||||
|
|
||||||
from core.api.grpc import (
|
from core.api.grpc import core_pb2, core_pb2_grpc, emane_pb2, wrappers
|
||||||
configservices_pb2,
|
|
||||||
core_pb2,
|
|
||||||
core_pb2_grpc,
|
|
||||||
emane_pb2,
|
|
||||||
mobility_pb2,
|
|
||||||
services_pb2,
|
|
||||||
wlan_pb2,
|
|
||||||
wrappers,
|
|
||||||
)
|
|
||||||
from core.api.grpc.configservices_pb2 import (
|
from core.api.grpc.configservices_pb2 import (
|
||||||
GetConfigServiceDefaultsRequest,
|
GetConfigServiceDefaultsRequest,
|
||||||
GetNodeConfigServiceRequest,
|
GetNodeConfigServiceRequest,
|
||||||
|
@ -233,95 +224,17 @@ class CoreGrpcClient:
|
||||||
self.proxy: bool = proxy
|
self.proxy: bool = proxy
|
||||||
|
|
||||||
def start_session(
|
def start_session(
|
||||||
self,
|
self, session: wrappers.Session, definition: bool = False
|
||||||
session: wrappers.Session,
|
|
||||||
asymmetric_links: List[wrappers.Link] = None,
|
|
||||||
definition: bool = False,
|
|
||||||
) -> Tuple[bool, List[str]]:
|
) -> Tuple[bool, List[str]]:
|
||||||
"""
|
"""
|
||||||
Start a session.
|
Start a session.
|
||||||
|
|
||||||
:param session: session to start
|
:param session: session to start
|
||||||
:param asymmetric_links: link configuration for asymmetric links
|
|
||||||
:param definition: True to only define session data, False to start session
|
:param definition: True to only define session data, False to start session
|
||||||
:return: tuple of result and exception strings
|
:return: tuple of result and exception strings
|
||||||
"""
|
"""
|
||||||
nodes = [x.to_proto() for x in session.nodes.values()]
|
|
||||||
links = [x.to_proto() for x in session.links]
|
|
||||||
if asymmetric_links:
|
|
||||||
asymmetric_links = [x.to_proto() for x in asymmetric_links]
|
|
||||||
hooks = [x.to_proto() for x in session.hooks.values()]
|
|
||||||
emane_model_configs = []
|
|
||||||
mobility_configs = []
|
|
||||||
wlan_configs = []
|
|
||||||
service_configs = []
|
|
||||||
service_file_configs = []
|
|
||||||
config_service_configs = []
|
|
||||||
for node in session.nodes.values():
|
|
||||||
for key, config in node.emane_model_configs.items():
|
|
||||||
model, iface_id = key
|
|
||||||
config = wrappers.ConfigOption.to_dict(config)
|
|
||||||
if iface_id is None:
|
|
||||||
iface_id = -1
|
|
||||||
emane_model_config = emane_pb2.EmaneModelConfig(
|
|
||||||
node_id=node.id, iface_id=iface_id, model=model, config=config
|
|
||||||
)
|
|
||||||
emane_model_configs.append(emane_model_config)
|
|
||||||
if node.wlan_config:
|
|
||||||
config = wrappers.ConfigOption.to_dict(node.wlan_config)
|
|
||||||
wlan_config = wlan_pb2.WlanConfig(node_id=node.id, config=config)
|
|
||||||
wlan_configs.append(wlan_config)
|
|
||||||
if node.mobility_config:
|
|
||||||
config = wrappers.ConfigOption.to_dict(node.mobility_config)
|
|
||||||
mobility_config = mobility_pb2.MobilityConfig(
|
|
||||||
node_id=node.id, config=config
|
|
||||||
)
|
|
||||||
mobility_configs.append(mobility_config)
|
|
||||||
for name, config in node.service_configs.items():
|
|
||||||
service_config = services_pb2.ServiceConfig(
|
|
||||||
node_id=node.id,
|
|
||||||
service=name,
|
|
||||||
directories=config.dirs,
|
|
||||||
files=config.configs,
|
|
||||||
startup=config.startup,
|
|
||||||
validate=config.validate,
|
|
||||||
shutdown=config.shutdown,
|
|
||||||
)
|
|
||||||
service_configs.append(service_config)
|
|
||||||
for service, file_configs in node.service_file_configs.items():
|
|
||||||
for file, data in file_configs.items():
|
|
||||||
service_file_config = services_pb2.ServiceFileConfig(
|
|
||||||
node_id=node.id, service=service, file=file, data=data
|
|
||||||
)
|
|
||||||
service_file_configs.append(service_file_config)
|
|
||||||
for name, service_config in node.config_service_configs.items():
|
|
||||||
config_service_config = configservices_pb2.ConfigServiceConfig(
|
|
||||||
node_id=node.id,
|
|
||||||
name=name,
|
|
||||||
templates=service_config.templates,
|
|
||||||
config=service_config.config,
|
|
||||||
)
|
|
||||||
config_service_configs.append(config_service_config)
|
|
||||||
options = {k: v.value for k, v in session.options.items()}
|
|
||||||
servers = [x.to_proto() for x in session.servers]
|
|
||||||
request = core_pb2.StartSessionRequest(
|
request = core_pb2.StartSessionRequest(
|
||||||
session_id=session.id,
|
session=session.to_proto(), definition=definition
|
||||||
nodes=nodes,
|
|
||||||
links=links,
|
|
||||||
location=session.location.to_proto(),
|
|
||||||
hooks=hooks,
|
|
||||||
emane_model_configs=emane_model_configs,
|
|
||||||
wlan_configs=wlan_configs,
|
|
||||||
mobility_configs=mobility_configs,
|
|
||||||
service_configs=service_configs,
|
|
||||||
service_file_configs=service_file_configs,
|
|
||||||
asymmetric_links=asymmetric_links,
|
|
||||||
config_service_configs=config_service_configs,
|
|
||||||
options=options,
|
|
||||||
user=session.user,
|
|
||||||
definition=definition,
|
|
||||||
metadata=session.metadata,
|
|
||||||
servers=servers,
|
|
||||||
)
|
)
|
||||||
response = self.stub.StartSession(request)
|
response = self.stub.StartSession(request)
|
||||||
return response.result, list(response.exceptions)
|
return response.result, list(response.exceptions)
|
||||||
|
|
|
@ -8,9 +8,8 @@ from grpc import ServicerContext
|
||||||
|
|
||||||
from core import utils
|
from core import utils
|
||||||
from core.api.grpc import common_pb2, core_pb2, wrappers
|
from core.api.grpc import common_pb2, core_pb2, wrappers
|
||||||
from core.api.grpc.common_pb2 import MappedConfig
|
|
||||||
from core.api.grpc.configservices_pb2 import ConfigServiceConfig
|
from core.api.grpc.configservices_pb2 import ConfigServiceConfig
|
||||||
from core.api.grpc.emane_pb2 import GetEmaneModelConfig
|
from core.api.grpc.emane_pb2 import NodeEmaneConfig
|
||||||
from core.api.grpc.services_pb2 import (
|
from core.api.grpc.services_pb2 import (
|
||||||
NodeServiceConfig,
|
NodeServiceConfig,
|
||||||
NodeServiceData,
|
NodeServiceData,
|
||||||
|
@ -252,12 +251,15 @@ def get_config_options(
|
||||||
return results
|
return results
|
||||||
|
|
||||||
|
|
||||||
def get_node_proto(session: Session, node: NodeBase) -> core_pb2.Node:
|
def get_node_proto(
|
||||||
|
session: Session, node: NodeBase, emane_configs: List[NodeEmaneConfig]
|
||||||
|
) -> core_pb2.Node:
|
||||||
"""
|
"""
|
||||||
Convert CORE node to protobuf representation.
|
Convert CORE node to protobuf representation.
|
||||||
|
|
||||||
:param session: session containing node
|
:param session: session containing node
|
||||||
:param node: node to convert
|
:param node: node to convert
|
||||||
|
:param emane_configs: emane configs related to node
|
||||||
:return: node proto
|
:return: node proto
|
||||||
"""
|
"""
|
||||||
node_type = session.get_node_type(node.__class__)
|
node_type = session.get_node_type(node.__class__)
|
||||||
|
@ -283,6 +285,42 @@ def get_node_proto(session: Session, node: NodeBase) -> core_pb2.Node:
|
||||||
image = None
|
image = None
|
||||||
if isinstance(node, (DockerNode, LxcNode)):
|
if isinstance(node, (DockerNode, LxcNode)):
|
||||||
image = node.image
|
image = node.image
|
||||||
|
# check for wlan config
|
||||||
|
wlan_config = session.mobility.get_configs(
|
||||||
|
node.id, config_type=BasicRangeModel.name
|
||||||
|
)
|
||||||
|
if wlan_config:
|
||||||
|
wlan_config = get_config_options(wlan_config, BasicRangeModel)
|
||||||
|
# check for mobility config
|
||||||
|
mobility_config = session.mobility.get_configs(
|
||||||
|
node.id, config_type=Ns2ScriptedMobility.name
|
||||||
|
)
|
||||||
|
if mobility_config:
|
||||||
|
mobility_config = get_config_options(mobility_config, Ns2ScriptedMobility)
|
||||||
|
# check for service configs
|
||||||
|
custom_services = session.services.custom_services.get(node.id)
|
||||||
|
service_configs = {}
|
||||||
|
if custom_services:
|
||||||
|
for service in custom_services.values():
|
||||||
|
service_proto = get_service_configuration(service)
|
||||||
|
service_configs[service.name] = NodeServiceConfig(
|
||||||
|
node_id=node.id,
|
||||||
|
service=service.name,
|
||||||
|
data=service_proto,
|
||||||
|
files=service.config_data,
|
||||||
|
)
|
||||||
|
# check for config service configs
|
||||||
|
config_service_configs = {}
|
||||||
|
if isinstance(node, CoreNode):
|
||||||
|
for service in node.config_services.values():
|
||||||
|
if not service.custom_templates and not service.custom_config:
|
||||||
|
continue
|
||||||
|
config_service_configs[service.name] = ConfigServiceConfig(
|
||||||
|
node_id=node.id,
|
||||||
|
name=service.name,
|
||||||
|
templates=service.custom_templates,
|
||||||
|
config=service.custom_config,
|
||||||
|
)
|
||||||
return core_pb2.Node(
|
return core_pb2.Node(
|
||||||
id=node.id,
|
id=node.id,
|
||||||
name=node.name,
|
name=node.name,
|
||||||
|
@ -298,6 +336,11 @@ def get_node_proto(session: Session, node: NodeBase) -> core_pb2.Node:
|
||||||
dir=node_dir,
|
dir=node_dir,
|
||||||
channel=channel,
|
channel=channel,
|
||||||
canvas=node.canvas,
|
canvas=node.canvas,
|
||||||
|
wlan_config=wlan_config,
|
||||||
|
mobility_config=mobility_config,
|
||||||
|
service_configs=service_configs,
|
||||||
|
config_service_configs=config_service_configs,
|
||||||
|
emane_configs=emane_configs,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -530,8 +573,8 @@ def get_nem_id(
|
||||||
return nem_id
|
return nem_id
|
||||||
|
|
||||||
|
|
||||||
def get_emane_model_configs(session: Session) -> List[GetEmaneModelConfig]:
|
def get_emane_model_configs_dict(session: Session) -> Dict[int, List[NodeEmaneConfig]]:
|
||||||
configs = []
|
configs = {}
|
||||||
for _id, model_configs in session.emane.node_configs.items():
|
for _id, model_configs in session.emane.node_configs.items():
|
||||||
for model_name in model_configs:
|
for model_name in model_configs:
|
||||||
model_class = session.emane.get_model(model_name)
|
model_class = session.emane.get_model(model_name)
|
||||||
|
@ -539,42 +582,11 @@ def get_emane_model_configs(session: Session) -> List[GetEmaneModelConfig]:
|
||||||
config = get_config_options(current_config, model_class)
|
config = get_config_options(current_config, model_class)
|
||||||
node_id, iface_id = utils.parse_iface_config_id(_id)
|
node_id, iface_id = utils.parse_iface_config_id(_id)
|
||||||
iface_id = iface_id if iface_id is not None else -1
|
iface_id = iface_id if iface_id is not None else -1
|
||||||
model_config = GetEmaneModelConfig(
|
node_config = NodeEmaneConfig(
|
||||||
node_id=node_id, model=model_name, iface_id=iface_id, config=config
|
model=model_name, iface_id=iface_id, config=config
|
||||||
)
|
)
|
||||||
configs.append(model_config)
|
node_configs = configs.setdefault(node_id, [])
|
||||||
return configs
|
node_configs.append(node_config)
|
||||||
|
|
||||||
|
|
||||||
def get_wlan_configs(session: Session) -> Dict[int, MappedConfig]:
|
|
||||||
configs = {}
|
|
||||||
for node_id in session.mobility.node_configurations:
|
|
||||||
model_config = session.mobility.node_configurations[node_id]
|
|
||||||
if node_id == -1:
|
|
||||||
continue
|
|
||||||
for model_name in model_config:
|
|
||||||
if model_name != BasicRangeModel.name:
|
|
||||||
continue
|
|
||||||
current_config = session.mobility.get_model_config(node_id, model_name)
|
|
||||||
config = get_config_options(current_config, BasicRangeModel)
|
|
||||||
mapped_config = MappedConfig(config=config)
|
|
||||||
configs[node_id] = mapped_config
|
|
||||||
return configs
|
|
||||||
|
|
||||||
|
|
||||||
def get_mobility_configs(session: Session) -> Dict[int, MappedConfig]:
|
|
||||||
configs = {}
|
|
||||||
for node_id in session.mobility.node_configurations:
|
|
||||||
model_config = session.mobility.node_configurations[node_id]
|
|
||||||
if node_id == -1:
|
|
||||||
continue
|
|
||||||
for model_name in model_config:
|
|
||||||
if model_name != Ns2ScriptedMobility.name:
|
|
||||||
continue
|
|
||||||
current_config = session.mobility.get_model_config(node_id, model_name)
|
|
||||||
config = get_config_options(current_config, Ns2ScriptedMobility)
|
|
||||||
mapped_config = MappedConfig(config=config)
|
|
||||||
configs[node_id] = mapped_config
|
|
||||||
return configs
|
return configs
|
||||||
|
|
||||||
|
|
||||||
|
@ -596,40 +608,6 @@ def get_default_services(session: Session) -> List[ServiceDefaults]:
|
||||||
return default_services
|
return default_services
|
||||||
|
|
||||||
|
|
||||||
def get_node_service_configs(session: Session) -> List[NodeServiceConfig]:
|
|
||||||
configs = []
|
|
||||||
for node_id, service_configs in session.services.custom_services.items():
|
|
||||||
for name in service_configs:
|
|
||||||
service = session.services.get_service(node_id, name)
|
|
||||||
service_proto = get_service_configuration(service)
|
|
||||||
config = NodeServiceConfig(
|
|
||||||
node_id=node_id,
|
|
||||||
service=name,
|
|
||||||
data=service_proto,
|
|
||||||
files=service.config_data,
|
|
||||||
)
|
|
||||||
configs.append(config)
|
|
||||||
return configs
|
|
||||||
|
|
||||||
|
|
||||||
def get_node_config_service_configs(session: Session) -> List[ConfigServiceConfig]:
|
|
||||||
configs = []
|
|
||||||
for node in session.nodes.values():
|
|
||||||
if not isinstance(node, CoreNodeBase):
|
|
||||||
continue
|
|
||||||
for name, service in node.config_services.items():
|
|
||||||
if not service.custom_templates and not service.custom_config:
|
|
||||||
continue
|
|
||||||
config_proto = ConfigServiceConfig(
|
|
||||||
node_id=node.id,
|
|
||||||
name=name,
|
|
||||||
templates=service.custom_templates,
|
|
||||||
config=service.custom_config,
|
|
||||||
)
|
|
||||||
configs.append(config_proto)
|
|
||||||
return configs
|
|
||||||
|
|
||||||
|
|
||||||
def get_mobility_node(
|
def get_mobility_node(
|
||||||
session: Session, node_id: int, context: ServicerContext
|
session: Session, node_id: int, context: ServicerContext
|
||||||
) -> Union[WlanNode, EmaneNet]:
|
) -> Union[WlanNode, EmaneNet]:
|
||||||
|
@ -645,10 +623,12 @@ def get_mobility_node(
|
||||||
def convert_session(session: Session) -> wrappers.Session:
|
def convert_session(session: Session) -> wrappers.Session:
|
||||||
links = []
|
links = []
|
||||||
nodes = []
|
nodes = []
|
||||||
|
emane_configs = get_emane_model_configs_dict(session)
|
||||||
for _id in session.nodes:
|
for _id in session.nodes:
|
||||||
node = session.nodes[_id]
|
node = session.nodes[_id]
|
||||||
if not isinstance(node, (PtpNet, CtrlNet)):
|
if not isinstance(node, (PtpNet, CtrlNet)):
|
||||||
node_proto = get_node_proto(session, node)
|
node_emane_configs = emane_configs.get(node.id, [])
|
||||||
|
node_proto = get_node_proto(session, node, node_emane_configs)
|
||||||
nodes.append(node_proto)
|
nodes.append(node_proto)
|
||||||
node_links = get_links(node)
|
node_links = get_links(node)
|
||||||
links.extend(node_links)
|
links.extend(node_links)
|
||||||
|
@ -659,11 +639,6 @@ def convert_session(session: Session) -> wrappers.Session:
|
||||||
x=x, y=y, z=z, lat=lat, lon=lon, alt=alt, scale=session.location.refscale
|
x=x, y=y, z=z, lat=lat, lon=lon, alt=alt, scale=session.location.refscale
|
||||||
)
|
)
|
||||||
hooks = get_hooks(session)
|
hooks = get_hooks(session)
|
||||||
emane_model_configs = get_emane_model_configs(session)
|
|
||||||
wlan_configs = get_wlan_configs(session)
|
|
||||||
mobility_configs = get_mobility_configs(session)
|
|
||||||
service_configs = get_node_service_configs(session)
|
|
||||||
config_service_configs = get_node_config_service_configs(session)
|
|
||||||
session_file = str(session.file_path) if session.file_path else None
|
session_file = str(session.file_path) if session.file_path else None
|
||||||
options = get_config_options(session.options.get_configs(), session.options)
|
options = get_config_options(session.options.get_configs(), session.options)
|
||||||
servers = [
|
servers = [
|
||||||
|
@ -680,13 +655,51 @@ def convert_session(session: Session) -> wrappers.Session:
|
||||||
default_services=default_services,
|
default_services=default_services,
|
||||||
location=location,
|
location=location,
|
||||||
hooks=hooks,
|
hooks=hooks,
|
||||||
emane_model_configs=emane_model_configs,
|
|
||||||
wlan_configs=wlan_configs,
|
|
||||||
service_configs=service_configs,
|
|
||||||
config_service_configs=config_service_configs,
|
|
||||||
mobility_configs=mobility_configs,
|
|
||||||
metadata=session.metadata,
|
metadata=session.metadata,
|
||||||
file=session_file,
|
file=session_file,
|
||||||
options=options,
|
options=options,
|
||||||
servers=servers,
|
servers=servers,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def configure_node(
|
||||||
|
session: Session, node: core_pb2.Node, core_node: NodeBase, context: ServicerContext
|
||||||
|
) -> None:
|
||||||
|
for emane_config in node.emane_configs:
|
||||||
|
_id = utils.iface_config_id(node.id, emane_config.iface_id)
|
||||||
|
config = {k: v.value for k, v in emane_config.config.items()}
|
||||||
|
session.emane.set_config(_id, emane_config.model, config)
|
||||||
|
if node.wlan_config:
|
||||||
|
config = {k: v.value for k, v in node.wlan_config.items()}
|
||||||
|
session.mobility.set_model_config(node.id, BasicRangeModel.name, config)
|
||||||
|
if node.mobility_config:
|
||||||
|
config = {k: v.value for k, v in node.mobility_config.items()}
|
||||||
|
session.mobility.set_model_config(node.id, Ns2ScriptedMobility.name, config)
|
||||||
|
for service_name, service_config in node.service_configs.items():
|
||||||
|
data = service_config.data
|
||||||
|
config = ServiceConfig(
|
||||||
|
node_id=node.id,
|
||||||
|
service=service_name,
|
||||||
|
startup=data.startup,
|
||||||
|
validate=data.validate,
|
||||||
|
shutdown=data.shutdown,
|
||||||
|
files=data.configs,
|
||||||
|
directories=data.dirs,
|
||||||
|
)
|
||||||
|
service_configuration(session, config)
|
||||||
|
for file_name, file_data in service_config.files.items():
|
||||||
|
session.services.set_service_file(
|
||||||
|
node.id, service_name, file_name, file_data
|
||||||
|
)
|
||||||
|
if node.config_service_configs:
|
||||||
|
if not isinstance(core_node, CoreNode):
|
||||||
|
context.abort(
|
||||||
|
grpc.StatusCode.INVALID_ARGUMENT,
|
||||||
|
"invalid node type with config service configs",
|
||||||
|
)
|
||||||
|
for service_name, service_config in node.config_service_configs.items():
|
||||||
|
service = core_node.config_services[service_name]
|
||||||
|
if service_config.config:
|
||||||
|
service.set_config(service_config.config)
|
||||||
|
for name, template in service_config.templates.items():
|
||||||
|
service.set_template(name, template)
|
||||||
|
|
|
@ -224,7 +224,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
|
||||||
:return: start session response
|
:return: start session response
|
||||||
"""
|
"""
|
||||||
logger.debug("start session: %s", request)
|
logger.debug("start session: %s", request)
|
||||||
session = self.get_session(request.session_id, context)
|
session = self.get_session(request.session.id, context)
|
||||||
|
|
||||||
# clear previous state and setup for creation
|
# clear previous state and setup for creation
|
||||||
session.clear()
|
session.clear()
|
||||||
|
@ -234,77 +234,51 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
|
||||||
state = EventTypes.CONFIGURATION_STATE
|
state = EventTypes.CONFIGURATION_STATE
|
||||||
session.directory.mkdir(exist_ok=True)
|
session.directory.mkdir(exist_ok=True)
|
||||||
session.set_state(state)
|
session.set_state(state)
|
||||||
session.user = request.user
|
session.user = request.session.user
|
||||||
|
|
||||||
# session options
|
# session options
|
||||||
session.options.config_reset()
|
session.options.config_reset()
|
||||||
for key, value in request.options.items():
|
for option in request.session.options.values():
|
||||||
session.options.set_config(key, value)
|
session.options.set_config(option.name, option.value)
|
||||||
session.metadata = dict(request.metadata)
|
session.metadata = dict(request.session.metadata)
|
||||||
|
|
||||||
# add servers
|
# add servers
|
||||||
for server in request.servers:
|
for server in request.session.servers:
|
||||||
session.distributed.add_server(server.name, server.host)
|
session.distributed.add_server(server.name, server.host)
|
||||||
|
|
||||||
# location
|
# location
|
||||||
if request.HasField("location"):
|
if request.session.HasField("location"):
|
||||||
grpcutils.session_location(session, request.location)
|
grpcutils.session_location(session, request.session.location)
|
||||||
|
|
||||||
# add all hooks
|
# add all hooks
|
||||||
for hook in request.hooks:
|
for hook in request.session.hooks:
|
||||||
state = EventTypes(hook.state)
|
state = EventTypes(hook.state)
|
||||||
session.add_hook(state, hook.file, hook.data)
|
session.add_hook(state, hook.file, hook.data)
|
||||||
|
|
||||||
# create nodes
|
# create nodes
|
||||||
_, exceptions = grpcutils.create_nodes(session, request.nodes)
|
_, exceptions = grpcutils.create_nodes(session, request.session.nodes)
|
||||||
if exceptions:
|
if exceptions:
|
||||||
exceptions = [str(x) for x in exceptions]
|
exceptions = [str(x) for x in exceptions]
|
||||||
return core_pb2.StartSessionResponse(result=False, exceptions=exceptions)
|
return core_pb2.StartSessionResponse(result=False, exceptions=exceptions)
|
||||||
|
|
||||||
# emane configs
|
# check for configurations
|
||||||
for config in request.emane_model_configs:
|
for node in request.session.nodes:
|
||||||
_id = utils.iface_config_id(config.node_id, config.iface_id)
|
core_node = self.get_node(session, node.id, context, NodeBase)
|
||||||
session.emane.set_config(_id, config.model, config.config)
|
grpcutils.configure_node(session, node, core_node, context)
|
||||||
|
|
||||||
# wlan configs
|
|
||||||
for config in request.wlan_configs:
|
|
||||||
session.mobility.set_model_config(
|
|
||||||
config.node_id, BasicRangeModel.name, config.config
|
|
||||||
)
|
|
||||||
|
|
||||||
# mobility configs
|
|
||||||
for config in request.mobility_configs:
|
|
||||||
session.mobility.set_model_config(
|
|
||||||
config.node_id, Ns2ScriptedMobility.name, config.config
|
|
||||||
)
|
|
||||||
|
|
||||||
# service configs
|
|
||||||
for config in request.service_configs:
|
|
||||||
grpcutils.service_configuration(session, config)
|
|
||||||
|
|
||||||
# service file configs
|
|
||||||
for config in request.service_file_configs:
|
|
||||||
session.services.set_service_file(
|
|
||||||
config.node_id, config.service, config.file, config.data
|
|
||||||
)
|
|
||||||
|
|
||||||
# config service configs
|
|
||||||
for config in request.config_service_configs:
|
|
||||||
node = self.get_node(session, config.node_id, context, CoreNode)
|
|
||||||
service = node.config_services[config.name]
|
|
||||||
if config.config:
|
|
||||||
service.set_config(config.config)
|
|
||||||
for name, template in config.templates.items():
|
|
||||||
service.set_template(name, template)
|
|
||||||
|
|
||||||
# create links
|
# create links
|
||||||
_, exceptions = grpcutils.create_links(session, request.links)
|
links = []
|
||||||
|
asym_links = []
|
||||||
|
for link in request.session.links:
|
||||||
|
if link.options.unidirectional:
|
||||||
|
asym_links.append(link)
|
||||||
|
else:
|
||||||
|
links.append(link)
|
||||||
|
_, exceptions = grpcutils.create_links(session, links)
|
||||||
if exceptions:
|
if exceptions:
|
||||||
exceptions = [str(x) for x in exceptions]
|
exceptions = [str(x) for x in exceptions]
|
||||||
return core_pb2.StartSessionResponse(result=False, exceptions=exceptions)
|
return core_pb2.StartSessionResponse(result=False, exceptions=exceptions)
|
||||||
|
_, exceptions = grpcutils.edit_links(session, asym_links)
|
||||||
# asymmetric links
|
|
||||||
_, exceptions = grpcutils.edit_links(session, request.asymmetric_links)
|
|
||||||
if exceptions:
|
if exceptions:
|
||||||
exceptions = [str(x) for x in exceptions]
|
exceptions = [str(x) for x in exceptions]
|
||||||
return core_pb2.StartSessionResponse(result=False, exceptions=exceptions)
|
return core_pb2.StartSessionResponse(result=False, exceptions=exceptions)
|
||||||
|
@ -541,6 +515,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
|
||||||
_type, _id, options = grpcutils.add_node_data(request.node)
|
_type, _id, options = grpcutils.add_node_data(request.node)
|
||||||
_class = session.get_node_class(_type)
|
_class = session.get_node_class(_type)
|
||||||
node = session.add_node(_class, _id, options)
|
node = session.add_node(_class, _id, options)
|
||||||
|
grpcutils.configure_node(session, request.node, node, context)
|
||||||
source = request.source if request.source else None
|
source = request.source if request.source else None
|
||||||
session.broadcast_node(node, MessageFlags.ADD, source)
|
session.broadcast_node(node, MessageFlags.ADD, source)
|
||||||
return core_pb2.AddNodeResponse(node_id=node.id)
|
return core_pb2.AddNodeResponse(node_id=node.id)
|
||||||
|
@ -563,7 +538,9 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer):
|
||||||
iface = node.ifaces[iface_id]
|
iface = node.ifaces[iface_id]
|
||||||
iface_proto = grpcutils.iface_to_proto(request.node_id, iface)
|
iface_proto = grpcutils.iface_to_proto(request.node_id, iface)
|
||||||
ifaces.append(iface_proto)
|
ifaces.append(iface_proto)
|
||||||
node_proto = grpcutils.get_node_proto(session, node)
|
emane_configs = grpcutils.get_emane_model_configs_dict(session)
|
||||||
|
node_emane_configs = emane_configs.get(node.id, [])
|
||||||
|
node_proto = grpcutils.get_node_proto(session, node, node_emane_configs)
|
||||||
links = get_links(node)
|
links = get_links(node)
|
||||||
return core_pb2.GetNodeResponse(node=node_proto, ifaces=ifaces, links=links)
|
return core_pb2.GetNodeResponse(node=node_proto, ifaces=ifaces, links=links)
|
||||||
|
|
||||||
|
|
|
@ -239,12 +239,26 @@ class NodeServiceData:
|
||||||
configs=proto.configs,
|
configs=proto.configs,
|
||||||
startup=proto.startup,
|
startup=proto.startup,
|
||||||
validate=proto.validate,
|
validate=proto.validate,
|
||||||
validation_mode=proto.validation_mode,
|
validation_mode=ServiceValidationMode(proto.validation_mode),
|
||||||
validation_timer=proto.validation_timer,
|
validation_timer=proto.validation_timer,
|
||||||
shutdown=proto.shutdown,
|
shutdown=proto.shutdown,
|
||||||
meta=proto.meta,
|
meta=proto.meta,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def to_proto(self) -> services_pb2.NodeServiceData:
|
||||||
|
return services_pb2.NodeServiceData(
|
||||||
|
executables=self.executables,
|
||||||
|
dependencies=self.dependencies,
|
||||||
|
dirs=self.dirs,
|
||||||
|
configs=self.configs,
|
||||||
|
startup=self.startup,
|
||||||
|
validate=self.validate,
|
||||||
|
validation_mode=self.validation_mode.value,
|
||||||
|
validation_timer=self.validation_timer,
|
||||||
|
shutdown=self.shutdown,
|
||||||
|
meta=self.meta,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class NodeServiceConfig:
|
class NodeServiceConfig:
|
||||||
|
@ -430,15 +444,27 @@ class ConfigOption:
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_proto(cls, proto: common_pb2.ConfigOption) -> "ConfigOption":
|
def from_proto(cls, proto: common_pb2.ConfigOption) -> "ConfigOption":
|
||||||
|
config_type = ConfigOptionType(proto.type) if proto.type is not None else None
|
||||||
return ConfigOption(
|
return ConfigOption(
|
||||||
label=proto.label,
|
label=proto.label,
|
||||||
name=proto.name,
|
name=proto.name,
|
||||||
value=proto.value,
|
value=proto.value,
|
||||||
type=ConfigOptionType(proto.type),
|
type=config_type,
|
||||||
group=proto.group,
|
group=proto.group,
|
||||||
select=proto.select,
|
select=proto.select,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def to_proto(self) -> common_pb2.ConfigOption:
|
||||||
|
config_type = self.type.value if self.type is not None else None
|
||||||
|
return common_pb2.ConfigOption(
|
||||||
|
label=self.label,
|
||||||
|
name=self.name,
|
||||||
|
value=self.value,
|
||||||
|
type=config_type,
|
||||||
|
select=self.select,
|
||||||
|
group=self.group,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
@dataclass
|
||||||
class Interface:
|
class Interface:
|
||||||
|
@ -714,6 +740,23 @@ class Node:
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_proto(cls, proto: core_pb2.Node) -> "Node":
|
def from_proto(cls, proto: core_pb2.Node) -> "Node":
|
||||||
|
service_configs = {}
|
||||||
|
service_file_configs = {}
|
||||||
|
for service, node_config in proto.service_configs.items():
|
||||||
|
service_configs[service] = NodeServiceData.from_proto(node_config.data)
|
||||||
|
service_file_configs[service] = dict(node_config.files)
|
||||||
|
emane_configs = {}
|
||||||
|
for emane_config in proto.emane_configs:
|
||||||
|
iface_id = None if emane_config.iface_id == -1 else emane_config.iface_id
|
||||||
|
model = emane_config.model
|
||||||
|
key = (model, iface_id)
|
||||||
|
emane_configs[key] = ConfigOption.from_dict(emane_config.config)
|
||||||
|
config_service_configs = {}
|
||||||
|
for service, service_config in proto.config_service_configs.items():
|
||||||
|
config_service_configs[service] = ConfigServiceData(
|
||||||
|
templates=dict(service_config.templates),
|
||||||
|
config=dict(service_config.config),
|
||||||
|
)
|
||||||
return Node(
|
return Node(
|
||||||
id=proto.id,
|
id=proto.id,
|
||||||
name=proto.name,
|
name=proto.name,
|
||||||
|
@ -730,9 +773,43 @@ class Node:
|
||||||
dir=proto.dir,
|
dir=proto.dir,
|
||||||
channel=proto.channel,
|
channel=proto.channel,
|
||||||
canvas=proto.canvas,
|
canvas=proto.canvas,
|
||||||
|
wlan_config=ConfigOption.from_dict(proto.wlan_config),
|
||||||
|
mobility_config=ConfigOption.from_dict(proto.mobility_config),
|
||||||
|
service_configs=service_configs,
|
||||||
|
service_file_configs=service_file_configs,
|
||||||
|
config_service_configs=config_service_configs,
|
||||||
|
emane_model_configs=emane_configs,
|
||||||
)
|
)
|
||||||
|
|
||||||
def to_proto(self) -> core_pb2.Node:
|
def to_proto(self) -> core_pb2.Node:
|
||||||
|
emane_configs = []
|
||||||
|
for key, config in self.emane_model_configs.items():
|
||||||
|
model, iface_id = key
|
||||||
|
if iface_id is None:
|
||||||
|
iface_id = -1
|
||||||
|
config = {k: v.to_proto() for k, v in config.items()}
|
||||||
|
emane_config = emane_pb2.NodeEmaneConfig(
|
||||||
|
iface_id=iface_id, model=model, config=config
|
||||||
|
)
|
||||||
|
emane_configs.append(emane_config)
|
||||||
|
service_configs = {}
|
||||||
|
for service, service_data in self.service_configs.items():
|
||||||
|
service_configs[service] = services_pb2.NodeServiceConfig(
|
||||||
|
service=service, data=service_data.to_proto()
|
||||||
|
)
|
||||||
|
for service, file_configs in self.service_file_configs.items():
|
||||||
|
service_config = service_configs.get(service)
|
||||||
|
if service_config:
|
||||||
|
service_config.files.update(file_configs)
|
||||||
|
else:
|
||||||
|
service_configs[service] = services_pb2.NodeServiceConfig(
|
||||||
|
service=service, files=file_configs
|
||||||
|
)
|
||||||
|
config_service_configs = {}
|
||||||
|
for service, service_config in self.config_service_configs.items():
|
||||||
|
config_service_configs[service] = configservices_pb2.ConfigServiceConfig(
|
||||||
|
templates=service_config.templates, config=service_config.config
|
||||||
|
)
|
||||||
return core_pb2.Node(
|
return core_pb2.Node(
|
||||||
id=self.id,
|
id=self.id,
|
||||||
name=self.name,
|
name=self.name,
|
||||||
|
@ -748,6 +825,11 @@ class Node:
|
||||||
dir=self.dir,
|
dir=self.dir,
|
||||||
channel=self.channel,
|
channel=self.channel,
|
||||||
canvas=self.canvas,
|
canvas=self.canvas,
|
||||||
|
wlan_config={k: v.to_proto() for k, v in self.wlan_config.items()},
|
||||||
|
mobility_config={k: v.to_proto() for k, v in self.mobility_config.items()},
|
||||||
|
service_configs=service_configs,
|
||||||
|
config_service_configs=config_service_configs,
|
||||||
|
emane_configs=emane_configs,
|
||||||
)
|
)
|
||||||
|
|
||||||
def set_wlan(self, config: Dict[str, str]) -> None:
|
def set_wlan(self, config: Dict[str, str]) -> None:
|
||||||
|
@ -796,32 +878,6 @@ class Session:
|
||||||
x.node_type: set(x.services) for x in proto.default_services
|
x.node_type: set(x.services) for x in proto.default_services
|
||||||
}
|
}
|
||||||
hooks = {x.file: Hook.from_proto(x) for x in proto.hooks}
|
hooks = {x.file: Hook.from_proto(x) for x in proto.hooks}
|
||||||
# update nodes with their current configurations
|
|
||||||
for model in proto.emane_model_configs:
|
|
||||||
iface_id = None
|
|
||||||
if model.iface_id != -1:
|
|
||||||
iface_id = model.iface_id
|
|
||||||
node = nodes[model.node_id]
|
|
||||||
key = (model.model, iface_id)
|
|
||||||
node.emane_model_configs[key] = ConfigOption.from_dict(model.config)
|
|
||||||
for node_id, mapped_config in proto.wlan_configs.items():
|
|
||||||
node = nodes[node_id]
|
|
||||||
node.wlan_config = ConfigOption.from_dict(mapped_config.config)
|
|
||||||
for config in proto.service_configs:
|
|
||||||
service = config.service
|
|
||||||
node = nodes[config.node_id]
|
|
||||||
node.service_configs[service] = NodeServiceData.from_proto(config.data)
|
|
||||||
for file, data in config.files.items():
|
|
||||||
files = node.service_file_configs.setdefault(service, {})
|
|
||||||
files[file] = data
|
|
||||||
for config in proto.config_service_configs:
|
|
||||||
node = nodes[config.node_id]
|
|
||||||
node.config_service_configs[config.name] = ConfigServiceData(
|
|
||||||
templates=dict(config.templates), config=dict(config.config)
|
|
||||||
)
|
|
||||||
for node_id, mapped_config in proto.mobility_configs.items():
|
|
||||||
node = nodes[node_id]
|
|
||||||
node.mobility_config = ConfigOption.from_dict(mapped_config.config)
|
|
||||||
file_path = Path(proto.file) if proto.file else None
|
file_path = Path(proto.file) if proto.file else None
|
||||||
options = ConfigOption.from_dict(proto.options)
|
options = ConfigOption.from_dict(proto.options)
|
||||||
servers = [Server.from_proto(x) for x in proto.servers]
|
servers = [Server.from_proto(x) for x in proto.servers]
|
||||||
|
@ -841,6 +897,35 @@ class Session:
|
||||||
servers=servers,
|
servers=servers,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def to_proto(self) -> core_pb2.Session:
|
||||||
|
nodes = [x.to_proto() for x in self.nodes.values()]
|
||||||
|
links = [x.to_proto() for x in self.links]
|
||||||
|
hooks = [x.to_proto() for x in self.hooks.values()]
|
||||||
|
options = {k: v.to_proto() for k, v in self.options.items()}
|
||||||
|
servers = [x.to_proto() for x in self.servers]
|
||||||
|
default_services = []
|
||||||
|
for node_type, services in self.default_services.items():
|
||||||
|
default_service = services_pb2.ServiceDefaults(
|
||||||
|
node_type=node_type, services=services
|
||||||
|
)
|
||||||
|
default_services.append(default_service)
|
||||||
|
file = str(self.file) if self.file else None
|
||||||
|
return core_pb2.Session(
|
||||||
|
id=self.id,
|
||||||
|
state=self.state.value,
|
||||||
|
nodes=nodes,
|
||||||
|
links=links,
|
||||||
|
dir=self.dir,
|
||||||
|
user=self.user,
|
||||||
|
default_services=default_services,
|
||||||
|
location=self.location.to_proto(),
|
||||||
|
hooks=hooks,
|
||||||
|
metadata=self.metadata,
|
||||||
|
file=file,
|
||||||
|
options=options,
|
||||||
|
servers=servers,
|
||||||
|
)
|
||||||
|
|
||||||
def add_node(
|
def add_node(
|
||||||
self,
|
self,
|
||||||
_id: int,
|
_id: int,
|
||||||
|
|
|
@ -439,7 +439,7 @@ class CoreClient:
|
||||||
def get_links(self, definition: bool = False) -> Tuple[List[Link], List[Link]]:
|
def get_links(self, definition: bool = False) -> Tuple[List[Link], List[Link]]:
|
||||||
if not definition:
|
if not definition:
|
||||||
self.ifaces_manager.set_macs([x.link for x in self.links.values()])
|
self.ifaces_manager.set_macs([x.link for x in self.links.values()])
|
||||||
links, asym_links = [], []
|
links = []
|
||||||
for edge in self.links.values():
|
for edge in self.links.values():
|
||||||
link = edge.link
|
link = edge.link
|
||||||
if not definition:
|
if not definition:
|
||||||
|
@ -449,12 +449,11 @@ class CoreClient:
|
||||||
link.iface2.mac = self.ifaces_manager.next_mac()
|
link.iface2.mac = self.ifaces_manager.next_mac()
|
||||||
links.append(link)
|
links.append(link)
|
||||||
if edge.asymmetric_link:
|
if edge.asymmetric_link:
|
||||||
asym_links.append(edge.asymmetric_link)
|
links.append(edge.asymmetric_link)
|
||||||
return links, asym_links
|
return links
|
||||||
|
|
||||||
def start_session(self, definition: bool = False) -> Tuple[bool, List[str]]:
|
def start_session(self, definition: bool = False) -> Tuple[bool, List[str]]:
|
||||||
links, asym_links = self.get_links(definition)
|
self.session.links = self.get_links(definition)
|
||||||
self.session.links = links
|
|
||||||
self.session.metadata = self.get_metadata()
|
self.session.metadata = self.get_metadata()
|
||||||
self.session.servers.clear()
|
self.session.servers.clear()
|
||||||
for server in self.servers.values():
|
for server in self.servers.values():
|
||||||
|
@ -462,9 +461,7 @@ class CoreClient:
|
||||||
result = False
|
result = False
|
||||||
exceptions = []
|
exceptions = []
|
||||||
try:
|
try:
|
||||||
result, exceptions = self.client.start_session(
|
result, exceptions = self.client.start_session(self.session, definition)
|
||||||
self.session, asym_links, definition
|
|
||||||
)
|
|
||||||
logger.info(
|
logger.info(
|
||||||
"start session(%s) definition(%s), result: %s",
|
"start session(%s) definition(%s), result: %s",
|
||||||
self.session.id,
|
self.session.id,
|
||||||
|
|
|
@ -310,9 +310,9 @@ class ConfigServiceConfigDialog(Dialog):
|
||||||
current_listbox.itemconfig(current_listbox.curselection()[0], bg="")
|
current_listbox.itemconfig(current_listbox.curselection()[0], bg="")
|
||||||
self.destroy()
|
self.destroy()
|
||||||
return
|
return
|
||||||
service_config = self.node.config_service_configs.get(self.service_name)
|
service_config = self.node.config_service_configs.setdefault(
|
||||||
if not service_config:
|
self.service_name, ConfigServiceData()
|
||||||
service_config = ConfigServiceData()
|
)
|
||||||
if self.config_frame:
|
if self.config_frame:
|
||||||
self.config_frame.parse_config()
|
self.config_frame.parse_config()
|
||||||
service_config.config = {x.name: x.value for x in self.config.values()}
|
service_config.config = {x.name: x.value for x in self.config.values()}
|
||||||
|
|
|
@ -31,6 +31,7 @@ class NodeConfigServiceDialog(Dialog):
|
||||||
if services is None:
|
if services is None:
|
||||||
services = set(node.config_services)
|
services = set(node.config_services)
|
||||||
self.current_services: Set[str] = services
|
self.current_services: Set[str] = services
|
||||||
|
self.protocol("WM_DELETE_WINDOW", self.click_cancel)
|
||||||
self.draw()
|
self.draw()
|
||||||
|
|
||||||
def draw(self) -> None:
|
def draw(self) -> None:
|
||||||
|
@ -131,13 +132,20 @@ class NodeConfigServiceDialog(Dialog):
|
||||||
if self.is_custom_service(name):
|
if self.is_custom_service(name):
|
||||||
self.current.listbox.itemconfig(tk.END, bg="green")
|
self.current.listbox.itemconfig(tk.END, bg="green")
|
||||||
|
|
||||||
|
def cleanup_custom_services(self) -> None:
|
||||||
|
for service in list(self.node.config_service_configs):
|
||||||
|
if service not in self.node.config_services:
|
||||||
|
self.node.config_service_configs.pop(service)
|
||||||
|
|
||||||
def click_save(self) -> None:
|
def click_save(self) -> None:
|
||||||
self.node.config_services = self.current_services.copy()
|
self.node.config_services = self.current_services.copy()
|
||||||
|
self.cleanup_custom_services()
|
||||||
logger.info("saved node config services: %s", self.node.config_services)
|
logger.info("saved node config services: %s", self.node.config_services)
|
||||||
self.destroy()
|
self.destroy()
|
||||||
|
|
||||||
def click_cancel(self) -> None:
|
def click_cancel(self) -> None:
|
||||||
self.current_services = None
|
self.current_services = None
|
||||||
|
self.cleanup_custom_services()
|
||||||
self.destroy()
|
self.destroy()
|
||||||
|
|
||||||
def click_remove(self) -> None:
|
def click_remove(self) -> None:
|
||||||
|
|
|
@ -25,6 +25,7 @@ class NodeServiceDialog(Dialog):
|
||||||
self.current: Optional[ListboxScroll] = None
|
self.current: Optional[ListboxScroll] = None
|
||||||
services = set(node.services)
|
services = set(node.services)
|
||||||
self.current_services: Set[str] = services
|
self.current_services: Set[str] = services
|
||||||
|
self.protocol("WM_DELETE_WINDOW", self.click_cancel)
|
||||||
self.draw()
|
self.draw()
|
||||||
|
|
||||||
def draw(self) -> None:
|
def draw(self) -> None:
|
||||||
|
@ -77,7 +78,7 @@ class NodeServiceDialog(Dialog):
|
||||||
button.grid(row=0, column=1, sticky=tk.EW, padx=PADX)
|
button.grid(row=0, column=1, sticky=tk.EW, padx=PADX)
|
||||||
button = ttk.Button(frame, text="Remove", command=self.click_remove)
|
button = ttk.Button(frame, text="Remove", command=self.click_remove)
|
||||||
button.grid(row=0, column=2, sticky=tk.EW, padx=PADX)
|
button.grid(row=0, column=2, sticky=tk.EW, padx=PADX)
|
||||||
button = ttk.Button(frame, text="Cancel", command=self.destroy)
|
button = ttk.Button(frame, text="Cancel", command=self.click_cancel)
|
||||||
button.grid(row=0, column=3, sticky=tk.EW)
|
button.grid(row=0, column=3, sticky=tk.EW)
|
||||||
|
|
||||||
# trigger group change
|
# trigger group change
|
||||||
|
@ -125,8 +126,21 @@ class NodeServiceDialog(Dialog):
|
||||||
"Service Configuration", "Select a service to configure", parent=self
|
"Service Configuration", "Select a service to configure", parent=self
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def cleanup_custom_services(self) -> None:
|
||||||
|
for service in list(self.node.service_configs):
|
||||||
|
if service not in self.node.services:
|
||||||
|
self.node.service_configs.pop(service)
|
||||||
|
for service in list(self.node.service_file_configs):
|
||||||
|
if service not in self.node.services:
|
||||||
|
self.node.service_file_configs.pop(service)
|
||||||
|
|
||||||
|
def click_cancel(self) -> None:
|
||||||
|
self.cleanup_custom_services()
|
||||||
|
self.destroy()
|
||||||
|
|
||||||
def click_save(self) -> None:
|
def click_save(self) -> None:
|
||||||
self.node.services = self.current_services.copy()
|
self.node.services = self.current_services.copy()
|
||||||
|
self.cleanup_custom_services()
|
||||||
self.destroy()
|
self.destroy()
|
||||||
|
|
||||||
def click_remove(self) -> None:
|
def click_remove(self) -> None:
|
||||||
|
|
|
@ -655,6 +655,7 @@ class CoreNode(CoreNodeBase):
|
||||||
:param dir_path: path to create
|
:param dir_path: path to create
|
||||||
:return: nothing
|
:return: nothing
|
||||||
"""
|
"""
|
||||||
|
logger.info("creating private directory: %s", dir_path)
|
||||||
if not str(dir_path).startswith("/"):
|
if not str(dir_path).startswith("/"):
|
||||||
raise CoreError(f"private directory path not fully qualified: {dir_path}")
|
raise CoreError(f"private directory path not fully qualified: {dir_path}")
|
||||||
host_path = self.host_path(dir_path, is_dir=True)
|
host_path = self.host_path(dir_path, is_dir=True)
|
||||||
|
|
|
@ -135,23 +135,8 @@ message GetConfigResponse {
|
||||||
|
|
||||||
|
|
||||||
message StartSessionRequest {
|
message StartSessionRequest {
|
||||||
int32 session_id = 1;
|
Session session = 1;
|
||||||
repeated Node nodes = 2;
|
bool definition = 2;
|
||||||
repeated Link links = 3;
|
|
||||||
repeated Hook hooks = 4;
|
|
||||||
SessionLocation location = 5;
|
|
||||||
repeated wlan.WlanConfig wlan_configs = 6;
|
|
||||||
repeated emane.EmaneModelConfig emane_model_configs = 7;
|
|
||||||
repeated mobility.MobilityConfig mobility_configs = 8;
|
|
||||||
repeated services.ServiceConfig service_configs = 9;
|
|
||||||
repeated services.ServiceFileConfig service_file_configs = 10;
|
|
||||||
repeated Link asymmetric_links = 11;
|
|
||||||
repeated configservices.ConfigServiceConfig config_service_configs = 12;
|
|
||||||
map<string, string> options = 13;
|
|
||||||
string user = 14;
|
|
||||||
bool definition = 15;
|
|
||||||
map<string, string> metadata = 16;
|
|
||||||
repeated Server servers = 17;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message StartSessionResponse {
|
message StartSessionResponse {
|
||||||
|
@ -577,15 +562,10 @@ message Session {
|
||||||
repeated services.ServiceDefaults default_services = 7;
|
repeated services.ServiceDefaults default_services = 7;
|
||||||
SessionLocation location = 8;
|
SessionLocation location = 8;
|
||||||
repeated Hook hooks = 9;
|
repeated Hook hooks = 9;
|
||||||
repeated emane.GetEmaneModelConfig emane_model_configs = 10;
|
map<string, string> metadata = 10;
|
||||||
map<int32, common.MappedConfig> wlan_configs = 11;
|
string file = 11;
|
||||||
repeated services.NodeServiceConfig service_configs = 12;
|
map<string, common.ConfigOption> options = 12;
|
||||||
repeated configservices.ConfigServiceConfig config_service_configs = 13;
|
repeated Server servers = 13;
|
||||||
map<int32, common.MappedConfig> mobility_configs = 14;
|
|
||||||
map<string, string> metadata = 15;
|
|
||||||
string file = 16;
|
|
||||||
map<string, common.ConfigOption> options = 17;
|
|
||||||
repeated Server servers = 18;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
message SessionSummary {
|
message SessionSummary {
|
||||||
|
@ -612,6 +592,11 @@ message Node {
|
||||||
string dir = 13;
|
string dir = 13;
|
||||||
string channel = 14;
|
string channel = 14;
|
||||||
int32 canvas = 15;
|
int32 canvas = 15;
|
||||||
|
map<string, common.ConfigOption> wlan_config = 16;
|
||||||
|
map<string, common.ConfigOption> mobility_config = 17;
|
||||||
|
map<string, services.NodeServiceConfig> service_configs = 18;
|
||||||
|
map<string, configservices.ConfigServiceConfig> config_service_configs= 19;
|
||||||
|
repeated emane.NodeEmaneConfig emane_configs = 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
message Link {
|
message Link {
|
||||||
|
|
|
@ -31,6 +31,12 @@ message GetEmaneModelConfig {
|
||||||
map<string, common.ConfigOption> config = 4;
|
map<string, common.ConfigOption> config = 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
message NodeEmaneConfig {
|
||||||
|
int32 iface_id = 1;
|
||||||
|
string model = 2;
|
||||||
|
map<string, common.ConfigOption> config = 3;
|
||||||
|
}
|
||||||
|
|
||||||
message GetEmaneEventChannelRequest {
|
message GetEmaneEventChannelRequest {
|
||||||
int32 session_id = 1;
|
int32 session_id = 1;
|
||||||
int32 nem_id = 2;
|
int32 nem_id = 2;
|
||||||
|
|
Loading…
Add table
Reference in a new issue