diff --git a/daemon/core/api/grpc/client.py b/daemon/core/api/grpc/client.py index a8cb324a..96c7ae33 100644 --- a/daemon/core/api/grpc/client.py +++ b/daemon/core/api/grpc/client.py @@ -748,9 +748,9 @@ class CoreGrpcClient: :raises grpc.RpcError: when session doesn't exist """ defaults = [] - for node_type in service_defaults: - services = service_defaults[node_type] - default = ServiceDefaults(node_type=node_type, services=services) + for model in service_defaults: + services = service_defaults[model] + default = ServiceDefaults(model=model, services=services) defaults.append(default) request = SetServiceDefaultsRequest(session_id=session_id, defaults=defaults) response = self.stub.SetServiceDefaults(request) diff --git a/daemon/core/api/grpc/events.py b/daemon/core/api/grpc/events.py index b15862ac..1a716364 100644 --- a/daemon/core/api/grpc/events.py +++ b/daemon/core/api/grpc/events.py @@ -33,7 +33,7 @@ def handle_node_event(node_data: NodeData) -> core_pb2.Event: node_proto = core_pb2.Node( id=node.id, name=node.name, - model=node.type, + model=node.model, icon=node.icon, position=position, geo=geo, diff --git a/daemon/core/api/grpc/grpcutils.py b/daemon/core/api/grpc/grpcutils.py index bf4212d6..c0771ced 100644 --- a/daemon/core/api/grpc/grpcutils.py +++ b/daemon/core/api/grpc/grpcutils.py @@ -286,7 +286,6 @@ def get_node_proto( lat=node.position.lat, lon=node.position.lon, alt=node.position.alt ) services = [x.name for x in node.services] - model = node.type node_dir = None config_services = [] if isinstance(node, CoreNodeBase): @@ -341,7 +340,7 @@ def get_node_proto( id=node.id, name=node.name, emane=emane_model, - model=model, + model=node.model, type=node_type.value, position=position, geo=geo, @@ -729,8 +728,8 @@ def get_default_services(session: Session) -> List[ServiceDefaults]: :return: list of default service sets """ default_services = [] - for name, services in session.services.default_services.items(): - default_service = ServiceDefaults(node_type=name, services=services) + for model, services in session.services.default_services.items(): + default_service = ServiceDefaults(model=model, services=services) default_services.append(default_service) return default_services diff --git a/daemon/core/api/grpc/server.py b/daemon/core/api/grpc/server.py index af8deee6..6234f959 100644 --- a/daemon/core/api/grpc/server.py +++ b/daemon/core/api/grpc/server.py @@ -920,7 +920,7 @@ class CoreGrpcServer(core_pb2_grpc.CoreApiServicer): session.services.default_services.clear() for service_defaults in request.defaults: session.services.default_services[ - service_defaults.node_type + service_defaults.model ] = service_defaults.services return SetServiceDefaultsResponse(result=True) diff --git a/daemon/core/api/grpc/wrappers.py b/daemon/core/api/grpc/wrappers.py index 7bbfdd7b..1cb703f5 100644 --- a/daemon/core/api/grpc/wrappers.py +++ b/daemon/core/api/grpc/wrappers.py @@ -210,12 +210,12 @@ class Service: @dataclass class ServiceDefault: - node_type: str + model: str services: List[str] @classmethod def from_proto(cls, proto: services_pb2.ServiceDefaults) -> "ServiceDefault": - return ServiceDefault(node_type=proto.node_type, services=list(proto.services)) + return ServiceDefault(model=proto.model, services=list(proto.services)) @dataclass @@ -884,9 +884,7 @@ class Session: def from_proto(cls, proto: core_pb2.Session) -> "Session": nodes: Dict[int, Node] = {x.id: Node.from_proto(x) for x in proto.nodes} links = [Link.from_proto(x) for x in proto.links] - default_services = { - x.node_type: set(x.services) for x in proto.default_services - } + default_services = {x.model: set(x.services) for x in proto.default_services} hooks = {x.file: Hook.from_proto(x) for x in proto.hooks} file_path = Path(proto.file) if proto.file else None options = ConfigOption.from_dict(proto.options) @@ -914,9 +912,9 @@ class Session: 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(): + for model, services in self.default_services.items(): default_service = services_pb2.ServiceDefaults( - node_type=node_type, services=services + model=model, services=services ) default_services.append(default_service) file = str(self.file) if self.file else None diff --git a/daemon/core/emulator/session.py b/daemon/core/emulator/session.py index b5e6e410..84919f3a 100644 --- a/daemon/core/emulator/session.py +++ b/daemon/core/emulator/session.py @@ -536,15 +536,15 @@ class Session: # add services to needed nodes if isinstance(node, (CoreNode, PhysicalNode)): - node.type = options.model + node.model = options.model if options.legacy or options.services: - logger.debug("set node type: %s", node.type) - self.services.add_services(node, node.type, options.services) + logger.debug("set node type: %s", node.model) + self.services.add_services(node, node.model, options.services) # add config services config_services = options.config_services if not options.legacy and not config_services and not node.services: - config_services = self.services.default_services.get(node.type, []) + config_services = self.services.default_services.get(node.model, []) logger.info("setting node config services: %s", config_services) for name in config_services: service_class = self.service_manager.get_service(name) diff --git a/daemon/core/nodes/base.py b/daemon/core/nodes/base.py index 1fc117df..a9125df1 100644 --- a/daemon/core/nodes/base.py +++ b/daemon/core/nodes/base.py @@ -62,11 +62,9 @@ class NodeBase(abc.ABC): if _id is None: _id = session.next_node_id() self.id: int = _id - if name is None: - name = f"o{self.id}" - self.name: str = name + self.name: str = name or f"o{self.id}" self.server: "DistributedServer" = server - self.type: Optional[str] = None + self.model: Optional[str] = None self.services: CoreServices = [] self.ifaces: Dict[int, CoreInterface] = {} self.iface_id: int = 0 diff --git a/daemon/core/nodes/network.py b/daemon/core/nodes/network.py index decfdbc0..73eda0da 100644 --- a/daemon/core/nodes/network.py +++ b/daemon/core/nodes/network.py @@ -663,7 +663,6 @@ class SwitchNode(CoreNetwork): apitype: NodeTypes = NodeTypes.SWITCH policy: NetworkPolicy = NetworkPolicy.ACCEPT - type: str = "lanswitch" class HubNode(CoreNetwork): @@ -674,7 +673,6 @@ class HubNode(CoreNetwork): apitype: NodeTypes = NodeTypes.HUB policy: NetworkPolicy = NetworkPolicy.ACCEPT - type: str = "hub" def startup(self) -> None: """ @@ -694,7 +692,6 @@ class WlanNode(CoreNetwork): apitype: NodeTypes = NodeTypes.WIRELESS_LAN linktype: LinkTypes = LinkTypes.WIRED policy: NetworkPolicy = NetworkPolicy.DROP - type: str = "wlan" def __init__( self, @@ -794,4 +791,3 @@ class TunnelNode(GreTapBridge): apitype: NodeTypes = NodeTypes.TUNNEL policy: NetworkPolicy = NetworkPolicy.ACCEPT - type: str = "tunnel" diff --git a/daemon/core/nodes/physical.py b/daemon/core/nodes/physical.py index ae1b07af..393d497f 100644 --- a/daemon/core/nodes/physical.py +++ b/daemon/core/nodes/physical.py @@ -29,7 +29,6 @@ class Rj45Node(CoreNodeBase): """ apitype: NodeTypes = NodeTypes.RJ45 - type: str = "rj45" def __init__( self, diff --git a/daemon/core/plugins/sdt.py b/daemon/core/plugins/sdt.py index 4532c8ef..48a6cdf0 100644 --- a/daemon/core/plugins/sdt.py +++ b/daemon/core/plugins/sdt.py @@ -4,16 +4,18 @@ sdt.py: Scripted Display Tool (SDT3D) helper import logging import socket -from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple +from pathlib import Path +from typing import TYPE_CHECKING, Dict, List, Optional, Set, Tuple, Type from urllib.parse import urlparse -from core.constants import CORE_CONF_DIR, CORE_DATA_DIR +from core.constants import CORE_CONF_DIR from core.emane.nodes import EmaneNet from core.emulator.data import LinkData, NodeData from core.emulator.enumerations import EventTypes, MessageFlags from core.errors import CoreError -from core.nodes.base import NodeBase -from core.nodes.network import WlanNode +from core.nodes.base import CoreNode, NodeBase +from core.nodes.network import HubNode, SwitchNode, TunnelNode, WlanNode +from core.nodes.physical import Rj45Node from core.nodes.wireless import WirelessNode logger = logging.getLogger(__name__) @@ -21,12 +23,22 @@ logger = logging.getLogger(__name__) if TYPE_CHECKING: from core.emulator.session import Session +LOCAL_ICONS_PATH: Path = Path(__file__).parent.parent / "gui" / "data" / "icons" CORE_LAYER: str = "CORE" NODE_LAYER: str = "CORE::Nodes" LINK_LAYER: str = "CORE::Links" WIRED_LINK_LAYER: str = f"{LINK_LAYER}::wired" CORE_LAYERS: List[str] = [CORE_LAYER, LINK_LAYER, NODE_LAYER, WIRED_LINK_LAYER] DEFAULT_LINK_COLOR: str = "red" +NODE_TYPES: Dict[Type[NodeBase], str] = { + HubNode: "hub", + SwitchNode: "lanswitch", + TunnelNode: "tunnel", + WlanNode: "wlan", + EmaneNet: "emane", + WirelessNode: "wireless", + Rj45Node: "rj45", +} def is_wireless(node: NodeBase) -> bool: @@ -52,16 +64,18 @@ class Sdt: DEFAULT_ALT: int = 2500 # TODO: read in user"s nodes.conf here; below are default node types from the GUI DEFAULT_SPRITES: Dict[str, str] = [ - ("router", "router.gif"), - ("host", "host.gif"), - ("PC", "pc.gif"), - ("mdr", "mdr.gif"), - ("prouter", "router_green.gif"), - ("hub", "hub.gif"), - ("lanswitch", "lanswitch.gif"), - ("wlan", "wlan.gif"), - ("rj45", "rj45.gif"), - ("tunnel", "tunnel.gif"), + ("router", "router.png"), + ("host", "host.png"), + ("PC", "pc.png"), + ("mdr", "mdr.png"), + ("prouter", "prouter.png"), + ("hub", "hub.png"), + ("lanswitch", "lanswitch.png"), + ("wlan", "wlan.png"), + ("emane", "emane.png"), + ("wireless", "wireless.png"), + ("rj45", "rj45.png"), + ("tunnel", "tunnel.png"), ] def __init__(self, session: "Session") -> None: @@ -144,7 +158,7 @@ class Sdt: :return: initialize command status """ - if not self.cmd(f'path "{CORE_DATA_DIR}/icons/normal"'): + if not self.cmd(f'path "{LOCAL_ICONS_PATH.absolute()}"'): return False # send node type to icon mappings for node_type, icon in self.DEFAULT_SPRITES: @@ -166,7 +180,6 @@ class Sdt: logger.error("error closing socket") finally: self.sock = None - self.connected = False def shutdown(self) -> None: @@ -194,7 +207,6 @@ class Sdt: """ if self.sock is None: return False - try: cmd = f"{cmdstr}\n".encode() logger.debug("sdt cmd: %s", cmd) @@ -259,13 +271,14 @@ class Sdt: pos = self.get_node_position(node) if not pos: return - node_type = node.type - if node_type is None: - node_type = type(node).type + if isinstance(node, CoreNode): + node_type = node.model + else: + node_type = NODE_TYPES.get(type(node), "PC") icon = node.icon if icon: node_type = node.name - icon = icon.replace("$CORE_DATA_DIR", str(CORE_DATA_DIR)) + icon = icon.replace("$CORE_DATA_DIR", str(LOCAL_ICONS_PATH.absolute())) icon = icon.replace("$CORE_CONF_DIR", str(CORE_CONF_DIR)) self.cmd(f"sprite {node_type} image {icon}") self.cmd( diff --git a/daemon/core/services/coreservices.py b/daemon/core/services/coreservices.py index f77a2136..6e52b5d6 100644 --- a/daemon/core/services/coreservices.py +++ b/daemon/core/services/coreservices.py @@ -234,26 +234,6 @@ class CoreServices: """ self.custom_services.clear() - def get_default_services(self, node_type: str) -> List[Type["CoreService"]]: - """ - Get the list of default services that should be enabled for a - node for the given node type. - - :param node_type: node type to get default services for - :return: default services - """ - logger.debug("getting default services for type: %s", node_type) - results = [] - defaults = self.default_services.get(node_type, []) - for name in defaults: - logger.debug("checking for service with service manager: %s", name) - service = ServiceManager.get(name) - if not service: - logger.warning("default service %s is unknown", name) - else: - results.append(service) - return results - def get_service( self, node_id: int, service_name: str, default_service: bool = False ) -> "CoreService": @@ -293,21 +273,21 @@ class CoreServices: node_services[service.name] = service def add_services( - self, node: CoreNode, node_type: str, services: List[str] = None + self, node: CoreNode, model: str, services: List[str] = None ) -> None: """ Add services to a node. :param node: node to add services to - :param node_type: node type to add services to + :param model: node model type to add services for :param services: names of services to add to node :return: nothing """ if not services: logger.info( - "using default services for node(%s) type(%s)", node.name, node_type + "using default services for node(%s) type(%s)", node.name, model ) - services = self.default_services.get(node_type, []) + services = self.default_services.get(model, []) logger.info("setting services for node(%s): %s", node.name, services) for service_name in services: service = self.get_service(node.id, service_name, default_service=True) diff --git a/daemon/core/xml/corexml.py b/daemon/core/xml/corexml.py index 9a186b8b..49ec72d8 100644 --- a/daemon/core/xml/corexml.py +++ b/daemon/core/xml/corexml.py @@ -211,7 +211,7 @@ class ServiceElement: class DeviceElement(NodeElement): def __init__(self, session: "Session", node: NodeBase) -> None: super().__init__(session, node, "device") - add_attribute(self.element, "type", node.type) + add_attribute(self.element, "type", node.model) self.add_class() self.add_services() @@ -434,15 +434,14 @@ class CoreXmlWriter: self.scenario.append(service_configurations) def write_default_services(self) -> None: - node_types = etree.Element("default_services") - for node_type in self.session.services.default_services: - services = self.session.services.default_services[node_type] - node_type = etree.SubElement(node_types, "node", type=node_type) + models = etree.Element("default_services") + for model in self.session.services.default_services: + services = self.session.services.default_services[model] + model = etree.SubElement(models, "node", type=model) for service in services: - etree.SubElement(node_type, "service", name=service) - - if node_types.getchildren(): - self.scenario.append(node_types) + etree.SubElement(model, "service", name=service) + if models.getchildren(): + self.scenario.append(models) def write_nodes(self) -> None: for node_id in self.session.nodes: @@ -586,14 +585,12 @@ class CoreXmlReader: return for node in default_services.iterchildren(): - node_type = node.get("type") + model = node.get("type") services = [] for service in node.iterchildren(): services.append(service.get("name")) - logger.info( - "reading default services for nodes(%s): %s", node_type, services - ) - self.session.services.default_services[node_type] = services + logger.info("reading default services for nodes(%s): %s", model, services) + self.session.services.default_services[model] = services def read_session_metadata(self) -> None: session_metadata = self.scenario.find("session_metadata") diff --git a/daemon/proto/core/api/grpc/services.proto b/daemon/proto/core/api/grpc/services.proto index dc451c40..1b430f99 100644 --- a/daemon/proto/core/api/grpc/services.proto +++ b/daemon/proto/core/api/grpc/services.proto @@ -37,7 +37,7 @@ message ServiceAction { } message ServiceDefaults { - string node_type = 1; + string model = 1; repeated string services = 2; } diff --git a/daemon/tests/test_grpc.py b/daemon/tests/test_grpc.py index 5fc56383..27ebcfc5 100644 --- a/daemon/tests/test_grpc.py +++ b/daemon/tests/test_grpc.py @@ -641,16 +641,16 @@ class TestGrpc: # given client = CoreGrpcClient() session = grpc_server.coreemu.create_session() - node_type = "test" + model = "test" services = ["SSH"] # then with client.context_connect(): - result = client.set_service_defaults(session.id, {node_type: services}) + result = client.set_service_defaults(session.id, {model: services}) # then assert result is True - assert session.services.default_services[node_type] == services + assert session.services.default_services[model] == services def test_get_node_service(self, grpc_server: CoreGrpcServer): # given diff --git a/daemon/tests/test_services.py b/daemon/tests/test_services.py index bbccaaac..69234e3a 100644 --- a/daemon/tests/test_services.py +++ b/daemon/tests/test_services.py @@ -53,7 +53,7 @@ class TestServices: total_service = len(node.services) # when - session.services.add_services(node, node.type, [SERVICE_ONE, SERVICE_TWO]) + session.services.add_services(node, node.model, [SERVICE_ONE, SERVICE_TWO]) # then assert node.services