cleanup and support for editing links within the web app and rest api

This commit is contained in:
Blake J. Harnden 2018-05-11 10:23:06 -07:00
parent 5f6f718e92
commit f9200db939
8 changed files with 180 additions and 38 deletions

View file

@ -578,6 +578,7 @@ class PyCoreNet(PyCoreObj):
delay=netif.getparam("delay"),
bandwidth=netif.getparam("bw"),
dup=netif.getparam("duplicate"),
per=netif.getparam("loss"),
jitter=netif.getparam("jitter")
)
@ -595,6 +596,7 @@ class PyCoreNet(PyCoreObj):
delay=netif.getparam("delay"),
bandwidth=netif.getparam("bw"),
dup=netif.getparam("duplicate"),
per=netif.getparam("loss"),
jitter=netif.getparam("jitter")
)
netif.swapparams('_params_up')

View file

@ -83,6 +83,7 @@ def link_config(network, interface, link_options, devname=None, interface_two=No
if not nodeutils.is_node(network, [NodeTypes.EMANE, NodeTypes.PHYSICAL]):
config["devname"] = devname
logger.info("configuring link for network(%s): %s", network.name, config)
network.linkconfig(**config)

View file

@ -264,6 +264,7 @@ class PtpNet(LxBrNet):
delay=if1.getparam("delay"),
bandwidth=if1.getparam("bw"),
dup=if1.getparam("duplicate"),
per=if1.getparam("loss"),
jitter=if1.getparam("jitter"),
interface1_id=if1.node.getifindex(if1),
interface1_mac=if1.hwaddr,
@ -291,6 +292,7 @@ class PtpNet(LxBrNet):
delay=if1.getparam("delay"),
bandwidth=if1.getparam("bw"),
dup=if1.getparam("duplicate"),
per=if1.getparam("loss"),
jitter=if1.getparam("jitter"),
unidirectional=1,
interface1_id=if2.node.getifindex(if2),

View file

@ -1,5 +1,4 @@
import os
from functools import wraps
from threading import Lock
@ -12,7 +11,7 @@ from flask_socketio import emit
from core import logger
from core.emulator.coreemu import CoreEmu
from core.emulator.emudata import InterfaceData, IpPrefixes
from core.emulator.emudata import InterfaceData
from core.emulator.emudata import LinkOptions
from core.emulator.emudata import NodeOptions
from core.enumerations import EventTypes
@ -357,9 +356,41 @@ def add_link(session_id):
link_options.key = options_data.get("key")
link_options.opaque = options_data.get("opaque")
link_options = LinkOptions()
session.add_link(node_one, node_two, interface_one, interface_two, link_options=link_options)
return jsonify(), 201
@app.route("/sessions/<int:session_id>/links", methods=["PUT"])
@synchronized
def edit_link(session_id):
session = coreemu.sessions.get(session_id)
if not session:
return jsonify(error="session does not exist"), 404
data = request.get_json()
node_one = data.get("node_one")
node_two = data.get("node_two")
interface_one = data.get("interface_one")
interface_two = data.get("interface_two")
options_data = data.get("options")
link_options = LinkOptions()
if options_data:
link_options.delay = options_data.get("delay")
link_options.bandwidth = options_data.get("bandwidth")
link_options.session = options_data.get("session")
link_options.per = options_data.get("per")
link_options.dup = options_data.get("dup")
link_options.jitter = options_data.get("jitter")
link_options.mer = options_data.get("mer")
link_options.burst = options_data.get("burst")
link_options.mburst = options_data.get("mburst")
link_options.unidirectional = options_data.get("unidirectional")
link_options.key = options_data.get("key")
link_options.opaque = options_data.get("opaque")
session.update_link(node_one, node_two, link_options, interface_one, interface_two)
return jsonify(), 201

View file

@ -119,6 +119,11 @@ class CoreLink {
this.nodeTwo = nodeTwo;
this.interfaceOne = interfaceOne;
this.interfaceTwo = interfaceTwo;
this.bandwidth = null;
this.delay = null;
this.loss = null;
this.duplicate = null;
this.jitter = null;
}
json() {
@ -126,7 +131,14 @@ class CoreLink {
node_one: this.nodeOne,
node_two: this.nodeTwo,
interface_one: this.interfaceOne,
interface_two: this.interfaceTwo
interface_two: this.interfaceTwo,
options: {
bandwidth: this.bandwidth,
delay: this.delay,
per: this.loss,
dup: this.duplicate,
jitter: this.jitter
}
}
}
}
@ -313,6 +325,11 @@ class CoreNetwork {
}
const link = new CoreLink(fromNode.id, toNode.id, interfaceOne, interfaceTwo);
link.bandwidth = linkData.bandwidth;
link.delay = linkData.delay;
link.duplicate = linkData.dup;
link.loss = linkData.per;
link.jitter = linkData.jitter;
this.links[linkId] = link;
const edge = {

View file

@ -81,6 +81,10 @@ class CoreRest {
return await postJson(`/sessions/${this.currentSession}/links`, link);
}
async editLink(link) {
return await putJson(`/sessions/${this.currentSession}/links`, link);
}
async getLinks(nodeId) {
return await $.getJSON(`/sessions/${this.currentSession}/nodes/${nodeId}/links`)
}

View file

@ -11,7 +11,7 @@
<div class="container-fluid d-flex flex-column p-0">
<nav class="navbar navbar-expand navbar-dark bg-dark mb-2">
<div class="navbar-brand mb-0 h1">
<img src="static/core-icon.png" />
<img src="static/core-icon.png"/>
<span>CORE</span>
</div>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-target="#nb-content"
@ -58,7 +58,7 @@
<span id="session-id" class="navbar-text p-2 mr-3">Session #</span>
<div>
<span id="node-display" class="navbar-text p-2">Create:</span>
<img id="node-select" src="static/router.svg" />
<img id="node-select" src="static/router.svg"/>
</div>
</div>
</nav>
@ -113,12 +113,12 @@
{% include 'nodeedit_modal.html' %}
{% include 'linkedit_modal.html' %}
<ul id="node-context" class="list-group invisible context">
<ul id="node-context" class="list-group context d-none">
<a class="list-group-item list-group-item-action" href="#" data-option="edit">Edit Node</a>
<a class="list-group-item list-group-item-action" href="#" data-option="services">Services</a>
</ul>
<ul id="edge-context" class="list-group invisible context">
<ul id="edge-context" class="list-group context d-none">
<a class="list-group-item list-group-item-action" href="#" data-option="edit">Edit Link</a>
</ul>
@ -155,7 +155,7 @@
const coreRest = new CoreRest();
const coreNetwork = new CoreNetwork('core-network', coreRest);
coreNetwork.initialSession()
.then(function(session) {
.then(function (session) {
joinSession(session);
})
.catch(function (err) {
@ -195,19 +195,18 @@
}
// handle network clicks
coreNetwork.network.on('click', function(properties) {
coreNetwork.network.on('click', function (properties) {
console.log('click properties: ', properties);
$nodeContext.addClass('invisible');
$edgeContext.addClass('invisible');
$nodeContext.addClass('d-none');
$edgeContext.addClass('d-none');
$infoCard.removeClass('visible invisible');
if (properties.nodes.length === 1) {
const nodeId = properties.nodes[0];
const node = coreNetwork.nodes.get(nodeId).coreNode;
const node = coreNetwork.getCoreNode(nodeId);
$infoCardHeader.text(node.name);
$infoCard.addClass('visible');
$infoCardTable.find('tbody tr').remove();
addInfoTable('Name', node.name);
addInfoTable('Model', node.model);
addInfoTable('X', node.x);
addInfoTable('Y', node.y);
@ -226,13 +225,16 @@
const edgeId = properties.edges[0];
const edge = coreNetwork.edges.get(edgeId);
const link = edge.link;
const nodeOne = coreNetwork.getCoreNode(link.nodeOne);
const nodeTwo = coreNetwork.getCoreNode(link.nodeTwo);
console.log('clicked edge: ', link);
$infoCard.addClass('visible');
$infoCardHeader.text('Edge');
$infoCardTable.find('tbody tr').remove();
addInfoTable(link.nodeOne, null);
addInfoTable(nodeOne.name, null);
const interfaceOne = link.interfaceOne;
if (interfaceOne) {
addInfoTable('Interface', `eth${interfaceOne.id}`);
if (interfaceOne.ip4) {
addInfoTable('IP4', `${interfaceOne.ip4}/${interfaceOne.ip4mask}`);
}
@ -240,9 +242,10 @@
addInfoTable('IP6', `${interfaceOne.ip6}/${interfaceOne.ip6mask}`);
}
}
addInfoTable(link.nodeTwo, null);
addInfoTable(nodeTwo.name, null);
const interfaceTwo = link.interfaceTwo;
if (interfaceTwo) {
addInfoTable('Interface', `eth${interfaceTwo.id}`);
if (interfaceTwo.ip4) {
addInfoTable('IP4', `${interfaceTwo.ip4}/${interfaceTwo.ip4mask}`);
}
@ -250,16 +253,21 @@
addInfoTable('IP6', `${interfaceTwo.ip6}/${interfaceTwo.ip6mask}`);
}
}
addInfoTable('Bandwidth', edge.link.bandwidth);
addInfoTable('Delay', edge.link.delay);
addInfoTable('Duplicate', edge.link.duplicate);
addInfoTable('Loss', edge.link.loss);
addInfoTable('Jitter', edge.link.jitter);
} else {
$infoCard.addClass('invisible');
}
});
coreNetwork.network.on('oncontext', function(properties) {
coreNetwork.network.on('oncontext', function (properties) {
console.log('context event: ', properties);
properties.event.preventDefault();
$nodeContext.addClass('invisible');
$edgeContext.addClass('invisible');
$nodeContext.addClass('d-none');
$edgeContext.addClass('d-none');
const location = properties.pointer.DOM;
const x = properties.event.pageX;
@ -275,7 +283,7 @@
left: x,
top: y
});
$nodeContext.removeClass('invisible');
$nodeContext.removeClass('d-none');
} else {
const edgeId = coreNetwork.network.getEdgeAt(location);
if (edgeId) {
@ -287,13 +295,13 @@
left: x,
top: y
});
$edgeContext.removeClass('invisible');
$edgeContext.removeClass('d-none');
}
}
});
$nodeContext.click(function(event) {
$nodeContext.addClass('invisible');
$nodeContext.click(function (event) {
$nodeContext.addClass('d-none');
console.log('node context click: ', event);
const nodeId = $nodeContext.data('node');
const node = coreNetwork.nodes.get(nodeId).coreNode;
@ -307,48 +315,100 @@
}
});
$nodeEditButton.click(function() {
$nodeEditButton.click(function () {
const $form = $nodeEditModal.find('form');
console.log('form data: ', $form.serialize());
console.log('node edit data: ', $form.serialize());
});
$edgeContext.click(function(event) {
$edgeContext.addClass('invisible');
$edgeContext.click(function (event) {
$edgeContext.addClass('d-none');
console.log('edge context click: ', event);
const edgeId = $edgeContext.data('edge');
const edge = coreNetwork.edges.get(edgeId);
const link = edge.link;
const $target = $(event.target);
const option = $target.data('option');
console.log('edge context: ', edgeId, option);
if (option === 'edit') {
// populate form with current link data
$linkEditModal.data('link', edgeId);
$linkEditModal.find('#link-bandwidth').val(link.bandwidth);
$linkEditModal.find('#link-delay').val(link.delay);
$linkEditModal.find('#link-per').val(link.loss);
$linkEditModal.find('#link-dup').val(link.duplicate);
$linkEditModal.find('#link-jitter').val(link.jitter);
// set modal name and show
$linkEditModal.find('.modal-title').text('Edit Edge');
$linkEditModal.modal('show');
}
});
$newSessionButton.click(function() {
$linkEditButton.click(function () {
const $form = $linkEditModal.find('form');
const formData = {};
$form.serializeArray().map(function (x) {
let value = x.value;
if (value === '') {
value = null;
} else if (!isNaN(value)) {
value = parseInt(value);
}
formData[x.name] = value;
});
console.log('link edit data: ', formData);
const edgeId = $linkEditModal.data('link');
const edge = coreNetwork.edges.get(edgeId);
const link = edge.link;
link.bandwidth = formData.bandwidth;
link.delay = formData.delay;
link.duplicate = formData.duplicate;
link.loss = formData.loss;
link.jitter = formData.jitter;
coreRest.isRunning()
.then(function (isRunning) {
if (isRunning) {
const linkEdit = link.json();
linkEdit.interface_one = linkEdit.interface_one.id;
linkEdit.interface_two = linkEdit.interface_two.id;
return coreRest.editLink(linkEdit);
}
})
.then(function (response) {
console.log('link edit success');
})
.catch(function (err) {
console.log('error editing link: ', err);
});
$linkEditModal.modal('hide');
});
$newSessionButton.click(function () {
coreNetwork.newSession()
.then(function(session) {
.then(function (session) {
joinSession(session);
})
.catch(function(err) {
console.log('error creating new session: ', err);
.catch(function (err) {
console.log('error creating new session: ', err);
});
});
$sessionsTable.on('click', 'td', function(event) {
$sessionsTable.on('click', 'td', function (event) {
const sessionId = $(this).parent('tr').data('session');
console.log('clicked session to join: ', sessionId);
if (sessionId === coreRest.currentSession) {
console.log('same session, not changing');
} else {
coreNetwork.joinSession(sessionId)
.then(function(session) {
.then(function (session) {
joinSession(session);
$sessionsModal.modal('hide');
})
.catch(function(err) {
console.log('join session error: ', err);
.catch(function (err) {
console.log('join session error: ', err);
});
}
});
@ -364,10 +424,10 @@
const start = $this.text() === 'Start';
if (start) {
coreNetwork.start()
.then(function() {
.then(function () {
setRunButton(false);
})
.catch(function(err) {
.catch(function (err) {
console.log('start error: ', err);
});
} else {

View file

@ -8,7 +8,32 @@
</button>
</div>
<div class="modal-body">
<p>edit stuff goes here</p>
<form>
<div class="form-group">
<label for="link-bandwidth">Bandwidth</label>
<input id="link-bandwidth" name="bandwidth" class="form-control" type="text">
</div>
<div class="form-group">
<label for="link-delay">Delay</label>
<input id="link-delay" name="delay" class="form-control" type="text">
</div>
<div class="form-group">
<label for="link-loss">Loss</label>
<input id="link-loss" name="loss" class="form-control" type="text">
</div>
<div class="form-group">
<label for="link-duplicate">Duplicates</label>
<input id="link-duplicate" name="duplicate" class="form-control" type="text">
</div>
<div class="form-group">
<label for="link-jitter">Jitter</label>
<input id="link-jitter" name="jitter" class="form-control" type="text">
</div>
</form>
</div>
<div class="modal-footer">
<button id="linkedit-button" type="button" class="btn btn-primary">Edit</button>