diff --git a/daemon/core/emulator/coreemu.py b/daemon/core/emulator/coreemu.py index fdb005c4..e82e9e29 100644 --- a/daemon/core/emulator/coreemu.py +++ b/daemon/core/emulator/coreemu.py @@ -512,8 +512,8 @@ class EmuSession(Session): # add services to default and physical nodes only if _type in [NodeTypes.DEFAULT, NodeTypes.PHYSICAL]: node.type = node_options.model - logger.debug("set node type: %s", node.type) services = "|".join(node_options.services) or None + logger.debug("set node type: %s - services(%s)", node.type, services) self.services.addservicestonode(node, node.type, services) # boot nodes if created after runtime, LcxNodes, Physical, and RJ45 are all PyCoreNodes diff --git a/webapp/app.py b/webapp/app.py index 9593b261..bd695b33 100644 --- a/webapp/app.py +++ b/webapp/app.py @@ -10,6 +10,7 @@ from flask_socketio import SocketIO from flask_socketio import emit from core import logger +from core.data import ConfigData from core.emulator.coreemu import CoreEmu from core.emulator.emudata import InterfaceData from core.emulator.emudata import LinkOptions @@ -172,6 +173,7 @@ def create_node(session_id): ) node_options.icon = data.get("icon") node_options.opaque = data.get("opaque") + node_options.services = data.get("services", []) node_options.set_position(data.get("x"), data.get("y")) node_options.set_location(data.get("lat"), data.get("lon"), data.get("alt")) node = session.add_node(_type=node_type, _id=node_id, node_options=node_options) @@ -268,6 +270,37 @@ def delete_node(session_id, node_id): return jsonify(error="failure to delete node"), 404 +@app.route("/sessions//nodes//services") +def node_services(session_id, node_id): + session = coreemu.sessions.get(session_id) + if not session: + return jsonify(error="session does not exist"), 404 + + config_data = ConfigData( + node=node_id, + object="services", + type=1, + ) + logger.debug("configuration message for %s node %s", config_data.object, config_data.node) + + # dispatch to any registered callback for this object type + replies = session.config_object(config_data) + if len(replies) != 1: + return jsonify(error="failure getting node services"), 404 + + service_data = replies[0] + names = service_data.captions.split("|") + services = {} + for group in service_data.groups.split("|"): + group = group.split(":") + group_name = group[0] + group_start, group_stop = [int(x) for x in group[1].split("-")] + group_start -= 1 + services[group_name] = names[group_start:group_stop] + + return jsonify(services) + + @app.route("/sessions//state", methods=["PUT"]) @synchronized def set_session_state(session_id): diff --git a/webapp/static/corenetwork.js b/webapp/static/corenetwork.js index 8d0acb2c..6919aaf5 100644 --- a/webapp/static/corenetwork.js +++ b/webapp/static/corenetwork.js @@ -108,7 +108,8 @@ class CoreNode { y: this.y, lat: this.lat, lon: this.lon, - alt: this.alt + alt: this.alt, + services: this.services } } } diff --git a/webapp/static/corerest.js b/webapp/static/corerest.js index 2fa75ce4..939363c7 100644 --- a/webapp/static/corerest.js +++ b/webapp/static/corerest.js @@ -89,6 +89,10 @@ class CoreRest { return await $.getJSON(`/sessions/${this.currentSession}/nodes/${nodeId}/links`) } + async getServices(nodeId) { + return await $.getJSON(`/sessions/${this.currentSession}/nodes/${nodeId}/services`) + } + async getNodeIps(nodeId, ip4Prefix, ip6Prefix) { return await postJson('/ips', { id: nodeId, diff --git a/webapp/static/coreui.js b/webapp/static/coreui.js new file mode 100644 index 00000000..24bb9a36 --- /dev/null +++ b/webapp/static/coreui.js @@ -0,0 +1,92 @@ +class ServicesModal { + constructor(coreRest, coreNetwork) { + this.coreRest = coreRest; + this.coreNetwork = coreNetwork; + this.$servicesModal = $('#services-modal'); + this.$servicesForm = this.$servicesModal.find('form'); + this.$serviceGroup = $('#service-group'); + this.$servicesList = $('#services-list'); + this.$servicesButton = $('#services-button'); + this.defaultServices = { + mdr: new Set(["zebra", "OSPFv3MDR", "IPForward"]), + PC: new Set(["DefaultRoute"]), + prouter: new Set(["zebra", "OSPFv2", "OSPFv3", "IPForward"]), + router: new Set(["zebra", "OSPFv2", "OSPFv3", "IPForward"]), + host: new Set(["DefaultRoute", "SSH"]) + }; + this.node = null; + this.nodeDefaults = null; + this.serviceGroups = null; + this.serviceOptions = new Map(); + this.$currentGroup = null; + this.groupChange(); + this.saveClicked(); + } + + async show(nodeId) { + this.node = this.coreNetwork.getCoreNode(nodeId); + if (this.node.services.length) { + this.nodeDefaults = new Set(this.node.services); + } else { + this.nodeDefaults = this.defaultServices[this.node.model] || new Set(); + } + this.serviceGroups = await coreRest.getServices(nodeId); + + // clear data + this.$serviceGroup.html(''); + this.$servicesList.html(''); + this.serviceOptions.clear(); + + for (let group in this.serviceGroups) { + const $option = $('