From 870feac7909dfe5c90e7e5468e42ef7d5f9561cf Mon Sep 17 00:00:00 2001 From: Tim Gerhard Date: Mon, 12 Dec 2016 14:33:43 +0100 Subject: [PATCH 1/9] fixed tutorials for new element types --- contrib/tutorials/basic/steps.js | 44 +++++++++---------- contrib/tutorials/chat/steps.js | 10 ++--- contrib/tutorials/device_data_access/steps.js | 8 ++-- .../device_data_access/topology.json | 8 ++-- .../executable_archives/topology.json | 2 +- contrib/tutorials/link_emulation/steps.js | 4 +- .../tutorials/link_emulation/topology.json | 2 +- contrib/tutorials/openflow/steps.js | 14 +++--- contrib/tutorials/openflow_ryu/steps.js | 18 ++++---- contrib/tutorials/packet_capturing/steps.js | 4 +- .../tutorials/packet_capturing/topology.json | 2 +- 11 files changed, 58 insertions(+), 58 deletions(-) diff --git a/contrib/tutorials/basic/steps.js b/contrib/tutorials/basic/steps.js index 71010a9bf..7475db0ee 100644 --- a/contrib/tutorials/basic/steps.js +++ b/contrib/tutorials/basic/steps.js @@ -69,7 +69,7 @@ mask = { attrs: { state: "created", - type: "openvz" + type: "container" }, component: "element", operation: "create", @@ -79,16 +79,16 @@ }, text: '

\ - To add a first device to your topology, click on OpenVZ (blue screen) \ + To add a first device to your topology, select the Container element (blue screen) \ in \'Common elements\' in the menu, and then click somewhere in the workspace.

' }, { text: '

\ - Congratulations! You have placed your first OpenVZ device.
\ - You can always identify OpenVZ devices by a blue screen.\ - OpenVZ devices are virtual machines which use their host\'s kernel to operate, but have their own virtual file system.\ + Congratulations! You have placed your first container device.
\ + You can always identify container devices by a blue screen.\ + Container-based virual machines use their host\'s kernel to operate, but have their own virtual file system, and their own processes.\ This makes them more efficient to run, but prohibits modifying the VM\'s kernel \ - which also means you can only run Linux systems in OpenVZ devices.

\ + which also means you can only run Linux systems in container devices.

\

Did you notice the ? button, which just appeared in the top-right corner of this window?\ This leads you to a help page which tells you more about what you just did (Don\'t worry, it opens in a new browser tab).

', help_page:'DeviceTypes', @@ -127,7 +127,7 @@ mask = { attrs: { state: "created", - type: "kvmqm" + type: "full" }, component: "element", operation: "create", @@ -137,16 +137,16 @@ }, text: '

\ - You will need more devices to get a whole topology. This time, let\'s create a KVM device.

\ + You will need more devices to get a whole topology. This time, let\'s create a full-virtualization device.

\

\ - Click KVM (green screen) in Common elements in the menu above, and the place it in the editor by\ + Click "Full Virt." (green screen) in Common elements in the menu above, and the place it in the editor by\ clicking somewhere into the white.

' }, { text: '

\ - You just created a KVM device.\ - KVM devices can be identified by a green screen.\ - Contrary to OpenVZ, KVM devices run completely separated from their host systems.\ + You just created a full-virtualization device.\ + Full-virtualization devices can be identified by a green screen.\ + Contrary to containers, fully virtualized VMs run completely separated from their host systems.\ This means that you can modify the kernel and/or use any operating system.

', skip_button:'continue' }, @@ -316,25 +316,25 @@ { trigger:function(obj) { - mask_openvz = { + mask_container = { object: { data: { - type: "openvz" + type: "container" }}, component: "element", operation: "remove", phase: "end" }; - mask_kvmqm = { + mask_full = { object: { data: { - type: "kvmqm" + type: "full" }}, component: "element", operation: "remove", phase: "end" }; - return compareToMask(obj,mask_openvz) || compareToMask(obj,mask_kvmqm); + return compareToMask(obj,mask_container) || compareToMask(obj,mask_full); }, text: '

\ @@ -347,25 +347,25 @@ { trigger:function(obj) { - mask_openvz = { + mask_container = { object: { data: { - type: "openvz" + type: "container" }}, component: "element", operation: "remove", phase: "end" }; - mask_kvmqm = { + mask_full = { object: { data: { - type: "kvmqm" + type: "full" }}, component: "element", operation: "remove", phase: "end" }; - return compareToMask(obj,mask_openvz) || compareToMask(obj,mask_kvmqm); + return compareToMask(obj,mask_container) || compareToMask(obj,mask_full); }, text: '

\ diff --git a/contrib/tutorials/chat/steps.js b/contrib/tutorials/chat/steps.js index 2c5790cf2..340877f92 100644 --- a/contrib/tutorials/chat/steps.js +++ b/contrib/tutorials/chat/steps.js @@ -18,10 +18,10 @@ skip_button: 'Continue' }, { - text: '

As first step we add two virtual machines to the topology. These virtual machines will use OpenVZ technology since we only want to run a simple program on it.
\ + text: '

As first step we add two virtual machines to the topology. These virtual machines will use container-based virtualization technology since we only want to run a simple program on it.
\ Click on the blue computer icon on the right of the menu and then click into the work space to position that element. You can later move it by dragging the icon in the work space.
\ You can move this tutorial window if it covers your work space.

\ -

Add two OpenVZ devices to your topology

', +

Add two container devices to your topology

', trigger: function(event) { data = getTutorialData(); if (! data.tmp) data.tmp = 0; @@ -30,7 +30,7 @@ component: "element", phase: "end", attrs: { - type: "openvz" + type: "container" }, }); if(match) data.tmp++; @@ -448,7 +448,7 @@ Note that you can not type any text into the consoles of these agents as the Rep help_page: 'LinkEmulation' }, { - text: '

Now we will add a delay of 2 seconds to a link and check if we can see the difference. Open the attributes of the link of one OpenVZ VM as you learned in the the first part. Enable link emulation and add a delay of 2000 ms on one of the directions.

\ + text: '

Now we will add a delay of 2 seconds to a link and check if we can see the difference. Open the attributes of the link of one container VM as you learned in the the first part. Enable link emulation and add a delay of 2000 ms on one of the directions.

\

Add 2 seconds delay to one link

', trigger: function(event) { var data = getTutorialData(); @@ -471,7 +471,7 @@ Note that you can not type any text into the consoles of these agents as the Rep help_page: 'LinkEmulation' }, { - text: '

You should see the delay when you send messages between your OpenVZ VMs. The delay should only exist in one direction.
\ + text: '

You should see the delay when you send messages between your container VMs. The delay should only exist in one direction.
\ Now you can play around with the settings a little. Maybe add some jitter to the connection. If you apply packet duplication or packet loss you can use the sequence numbers to check this functionality.

\

Click continue when you want to continue

', skip_button: 'Continue', diff --git a/contrib/tutorials/device_data_access/steps.js b/contrib/tutorials/device_data_access/steps.js index ed60de468..d29f7520d 100644 --- a/contrib/tutorials/device_data_access/steps.js +++ b/contrib/tutorials/device_data_access/steps.js @@ -61,7 +61,7 @@ }); }, text: '

\ - Now after the devices started right click on the left device (openvz1) and use

> Executable archive > Upload Archive
to upload and run the archive on your device

\ + Now after the devices started right click on the left device (container1) and use
> Executable archive > Upload Archive
to upload and run the archive on your device

\

\ After the upload, the archive will be automatically executed by running the auto_exec.sh file inside it if the file exists.\ Executable archives are a good way to run programms on a device. If you want to learn more about them feel free to visite the Executable Archives tutorial.

', @@ -177,9 +177,9 @@ The simulation will create some output on your console and also create data in a return match; }, text: '

\ - You can upload any image to a device of the same technology. You can not use images accross technologies (e.g., you can\'t upload an OpenVZ image to a KVM device, and vice versa).

\ + You can upload any image to a device of the same technology. You can not use images accross technologies (e.g., you can\'t upload a container image to a full-virtualization device, and vice versa).

\

\ - Upload your image again to the second device (openvz2).

\ + Upload your image again to the second device (container2).

\

\ You can skip this step if a big upload might cause you trouble. Then please run the executable archive on the second device so we can continue the tutorial.

\

\ @@ -218,7 +218,7 @@ The simulation will create some output on your console and also create data in a text: '

\ SSH is deactivated by default. In order to use it we have to remote connect to our device (with NoVNC) and run ssh-enable.
Let\'s do it, so we can use SSH to get access to our device.

\

\ - Use NoVNC to run ssh-enable on the second device (openvz2). Press "Continue" if you did so.

', + Use NoVNC to run ssh-enable on the second device (container2). Press "Continue" if you did so.

', skip_button: "Continue" }, { diff --git a/contrib/tutorials/device_data_access/topology.json b/contrib/tutorials/device_data_access/topology.json index 14acdefe8..b296b25ce 100644 --- a/contrib/tutorials/device_data_access/topology.json +++ b/contrib/tutorials/device_data_access/topology.json @@ -74,8 +74,8 @@ "parent": null, "attrs": { "profile": "normal", - "name": "openvz2", - "hostname": "openvz2", + "name": "container2", + "hostname": "container2", "site": null, "_pos": { "y": 0.042092427720118612, @@ -104,8 +104,8 @@ "parent": null, "attrs": { "profile": "normal", - "name": "openvz1", - "hostname": "openvz1", + "name": "container1", + "hostname": "container1", "site": null, "_pos": { "y": 0.036617975165374086, diff --git a/contrib/tutorials/executable_archives/topology.json b/contrib/tutorials/executable_archives/topology.json index 536cabe3d..c8003c0c6 100644 --- a/contrib/tutorials/executable_archives/topology.json +++ b/contrib/tutorials/executable_archives/topology.json @@ -12,7 +12,7 @@ "attrs": { "profile": "normal", "site": null, - "name": "openvz1", + "name": "container1", "template": "debian-6.0_x86", "_pos": { "y": 0.3181818181818182, diff --git a/contrib/tutorials/link_emulation/steps.js b/contrib/tutorials/link_emulation/steps.js index 17e396593..e8d5d34db 100644 --- a/contrib/tutorials/link_emulation/steps.js +++ b/contrib/tutorials/link_emulation/steps.js @@ -29,7 +29,7 @@ }, text: '

\ - You see a topology where an OpenVZ device is connected to a switch, and the switch is connected to the internet.
\ + You see a topology where a container device is connected to a switch, and the switch is connected to the internet.
\ Link emulation does not work when the connection is directly at an external network. Therefore, we need a switch in order to use link emulation.\

\ All devices connected to a switch which is connected to to the internet will have a direct connection to the internet (no NAT router or similar).
\ @@ -57,7 +57,7 @@ 1: { parent: { data: { - type: "openvz", + type: "container", } } } diff --git a/contrib/tutorials/link_emulation/topology.json b/contrib/tutorials/link_emulation/topology.json index d96883c74..39995e2bc 100644 --- a/contrib/tutorials/link_emulation/topology.json +++ b/contrib/tutorials/link_emulation/topology.json @@ -98,7 +98,7 @@ "type": "openvz", "attrs": { "profile": "normal", - "name": "openvz1", + "name": "container1", "site": null, "_pos": { "y": 0.090909090909090912, diff --git a/contrib/tutorials/openflow/steps.js b/contrib/tutorials/openflow/steps.js index c6ac3ea18..4d456f8e0 100644 --- a/contrib/tutorials/openflow/steps.js +++ b/contrib/tutorials/openflow/steps.js @@ -7,7 +7,7 @@ }, { text: '

In this tutorial we will use the OpenVSwitch software to emulate an OpenFlow switch. It will behave like a hardware OpenFlow switch and support all OpenFlow commands. However it does not provide the same forwarding speed as a physical switch.

\ -

OpenVSwitch is available as a KVM template, so you can find it directly in the menu.

\ +

OpenVSwitch is available as a full-virtualization template, so you can find it directly in the menu.

\
\

Add an OpenFlow Switch to your topology.

', trigger: function(event) { @@ -16,7 +16,7 @@ component: "element", phase: "end", attrs: { - type: "kvmqm", + type: "full", template: "openvswitch" }, }); @@ -25,7 +25,7 @@ { text: '

In this tutorial, we will modify the communication between the connected nodes. For this, you need to add three nodes.

\
\ -

Add 3 OpenVZ nodes around the switch and name them node1, node2 and node3

', +

Add 3 container nodes around the switch and name them node1, node2 and node3

', trigger: function(event) { var data = getTutorialData(); if (! data.tmp1) data.tmp1 = 0; @@ -35,7 +35,7 @@ component: "element", phase: "end", attrs: { - type: "openvz" + type: "container" }, })) data.tmp1++; if (compareToMask(event, { @@ -74,7 +74,7 @@ } }, { - text: '

To be able to ping between the nodes we have to configure their IP addresses. You could do that using the console of the nodes, but ToMaTo provides an easier way to configure interfaces on OpenVZ machines.

\ + text: '

To be able to ping between the nodes we have to configure their IP addresses. You could do that using the console of the nodes, but ToMaTo provides an easier way to configure interfaces on container machines.

\

Right-click on the network interfaces of the nodes and select configure. A configuration dialog will open and allow you to set the IPv4 address of the interface.

\

Configure the following addresses on the nodes:\

\ @@ -124,7 +124,7 @@ } }, { - text: '

To be able to configure the switch later, we need to assign an IP address to it. Since the switch is based on KVM you cannot configure its interface using ToMaTo. Instead you can set the IP address by using the command

address 10.0.0.100
on the console of the switch. The switch will remember this address even after reboot. Click on continue when you are done.

\ + text: '

To be able to configure the switch later, we need to assign an IP address to it. Since the switch is based on full virtualization you cannot configure its interface using ToMaTo. Instead you can set the IP address by using the command

address 10.0.0.100
on the console of the switch. The switch will remember this address even after reboot. Click on continue when you are done.

\
\

Set the IP address of the switch to 10.0.0.100.

', skip_button: 'Continue' @@ -163,7 +163,7 @@ component: "element", phase: "end", attrs: { - type: "openvz", + type: "container", template: "floodlight" }, }); diff --git a/contrib/tutorials/openflow_ryu/steps.js b/contrib/tutorials/openflow_ryu/steps.js index 11e8d2e65..38da92329 100644 --- a/contrib/tutorials/openflow_ryu/steps.js +++ b/contrib/tutorials/openflow_ryu/steps.js @@ -9,7 +9,7 @@ }, { text: '

In this tutorial we will use the OpenVSwitch software to emulate an OpenFlow switch. It will behave like a hardware OpenFlow switch and support all OpenFlow commands. However it does not provide the same forwarding speed as a physical switch.

\ -

OpenVSwitch is available as a KVM template, so you can find it directly in the menu.

\ +

OpenVSwitch is available as a full-virtualization template, so you can find it directly in the menu.

\
\

Add an OpenFlow Switch to your topology.

', trigger: function(event) { @@ -18,7 +18,7 @@ component: "element", phase: "end", attrs: { - type: "kvmqm", + type: "full", template: "openvswitch" }, }); @@ -40,8 +40,8 @@ { text: '

Ok now we will configure some things on the switch:

\
\

Rename the switch and configure it to use English (US) keyboard layout and to connect network segments

', @@ -56,7 +56,7 @@ { text: '

In this tutorial, we will modify the communication between the connected nodes. For this, you need to add three nodes.

\
\ -

Add 3 OpenVZ nodes around the switch and name them node1, node2 and node3

', +

Add 3 container nodes around the switch and name them node1, node2 and node3

', trigger: function(event) { var data = getTutorialData(); if (! data.tmp1) data.tmp1 = 0; @@ -66,7 +66,7 @@ component: "element", phase: "end", attrs: { - type: "openvz" + type: "container" }, })) data.tmp1++; if (compareToMask(event, { @@ -105,7 +105,7 @@ } }, { - text: '

To be able to ping between the nodes, they need to have proper IP addresses. You can configure them using the console of the nodes, but ToMaTo provides an easier way to configure interfaces on OpenVZ machines.

\ + text: '

To be able to ping between the nodes, they need to have proper IP addresses. You can configure them using the console of the nodes, but ToMaTo provides an easier way to configure interfaces on container machines.

\

If you right-click on the network interfaces of the nodes and select configure, a configuration dialog will open and allow you to set the IPv4 address of the interface.

\

ToMaTo even assignes addresses automaticaly and if you configured the switch correctly, those IPs are correct too.

\

Make sure the nodes use the following addresses:\ @@ -141,7 +141,7 @@ } }, { - text: '

To be able to configure the switch later, we need to assign an IP address to it. Since the switch is based on KVM you cannot configure its interface using ToMaTo. Instead you can set the IP address by using the command

address 10.0.0.100
on the console of the switch. The switch will remember this address even after reboot. Click on continue when you are done.

\ + text: '

To be able to configure the switch later, we need to assign an IP address to it. Since the switch is based on full virtualization, you cannot configure its interface using ToMaTo. Instead you can set the IP address by using the command

address 10.0.0.100
on the console of the switch. The switch will remember this address even after reboot. Click on continue when you are done.

\
\

Set the IP address of the switch to 10.0.0.100.

', skip_button: 'Continue' @@ -180,7 +180,7 @@ component: "element", phase: "end", attrs: { - type: "openvz", + type: "container", template: "ryu" }, }); diff --git a/contrib/tutorials/packet_capturing/steps.js b/contrib/tutorials/packet_capturing/steps.js index 20b274837..b01c64756 100644 --- a/contrib/tutorials/packet_capturing/steps.js +++ b/contrib/tutorials/packet_capturing/steps.js @@ -70,7 +70,7 @@ }, 1: { data: { - type: "openvz_interface" + type: "container_interface" } } } @@ -92,7 +92,7 @@ }, 0: { data: { - type: "openvz_interface" + type: "container_interface" } } } diff --git a/contrib/tutorials/packet_capturing/topology.json b/contrib/tutorials/packet_capturing/topology.json index 6cfa09737..e189c25b3 100644 --- a/contrib/tutorials/packet_capturing/topology.json +++ b/contrib/tutorials/packet_capturing/topology.json @@ -98,7 +98,7 @@ "type": "openvz", "attrs": { "profile": "normal", - "name": "openvz1", + "name": "container1", "site": null, "_pos": { "y": 0.090909090909090912, From 4e4596011797de36ae4f0823cabd5823a4393b09 Mon Sep 17 00:00:00 2001 From: Tim Gerhard Date: Mon, 9 Jan 2017 14:58:24 +0100 Subject: [PATCH 2/9] added simple link statistics to connections --- backend_core/tomato/api/misc.py | 2 +- backend_core/tomato/connections.py | 56 +++++++++++++++++++++++++++++- backend_core/tomato/link.py | 40 ++++++++++++++++++--- shared/lib/constants.py | 5 +++ 4 files changed, 96 insertions(+), 7 deletions(-) diff --git a/backend_core/tomato/api/misc.py b/backend_core/tomato/api/misc.py index 6b83e7baa..1aea3c9bf 100644 --- a/backend_core/tomato/api/misc.py +++ b/backend_core/tomato/api/misc.py @@ -22,7 +22,7 @@ from ..lib.userflags import Flags def link_statistics(siteA, siteB): - return link.getStatistics(siteA, siteB) + return link.getStatisticsInfo(siteA, siteB) def notifyAdmins(subject, text, global_contact, issue, user_orga, user_name): api = get_backend_users_proxy() diff --git a/backend_core/tomato/connections.py b/backend_core/tomato/connections.py index cc1ba94a7..9e07ed223 100644 --- a/backend_core/tomato/connections.py +++ b/backend_core/tomato/connections.py @@ -24,8 +24,9 @@ from .lib import logging #@UnresolvedImport from .lib.error import UserError, InternalError from .lib.cache import cached #@UnresolvedImport -from .lib.constants import ActionName, StateName, TypeName +from .lib.constants import ActionName, StateName, TypeName, ConnectionDistance from .lib.exceptionhandling import wrap_and_handle_current_exception +from .link import getStatistics REMOVE_ACTION = "(remove)" @@ -463,6 +464,58 @@ def host_info(self): 'fileserver_port': host.hostInfo.get('fileserver_port', None) } + def link_stats(self): + if self.elementFrom.state == ST_CREATED or self.elementTo.state == ST_CREATED: + return None + + hostA = self.elementFrom.host.name + siteA = self.elementFrom.host.site.name + hostB = self.elementTo.host.name + siteB = self.elementTo.host.site.name + + if hostA != hostB: + distance = ConnectionDistance.INTRA_HOST + link_stats = None + + else: + + if siteA == siteB: + distance = ConnectionDistance.INTRA_SITE + else: + distance = ConnectionDistance.INTER_SITE + + link_stats_ = getStatistics(siteA, siteB) + if link_stats_: + link_stats_info = link_stats_.quickInfo() + recent = None + average = None + for key in ["5minutes", "hour", "day", "month", "year"]: + if link_stats_info[key]: + recent = link_stats_info[key] + break + for key in ["year", "month", "day", "hour", "5minutes"]: + if link_stats_info[key]: + average = link_stats_info[key] + break + if recent or average: + link_stats = { + "recent": recent.info(), + "average": average.info() + } + else: + link_stats = None + else: + link_stats = None + + return { + "hostA": hostA, + "siteA": siteA, + "hostB": hostB, + "siteB": siteB, + "distance": distance, + "statistics": link_stats + } + ACTIONS = { Entity.REMOVE_ACTION: StatefulAction(_remove, check=checkRemove) } @@ -479,6 +532,7 @@ def host_info(self): 'host_elements': schema.List(items=schema.List(minLength=2, maxLength=2)), 'host_connections': schema.List(items=schema.List(minLength=2, maxLength=2)) }, required=['host_elements', 'host_connections'])), + "link_statistics": Attribute(get=link_stats, readOnly=True), "host": Attribute(get=lambda self: self.host.name if self.host else None, readOnly=True), "host_info": Attribute(field=host_info, readOnly=True) } diff --git a/backend_core/tomato/link.py b/backend_core/tomato/link.py index 65e0052cc..1828d1bbe 100644 --- a/backend_core/tomato/link.py +++ b/backend_core/tomato/link.py @@ -119,6 +119,35 @@ def add(self, measurement): self.single.append(measurement) self.save() + def quickInfo(self): + if self.by5minutes: + fminutes = max(self.by5minutes, key=lambda r: r.end) + else: + fminutes = None + if self.byHour: + hour = max(self.byHour, key=lambda r: r.end) + else: + hour = None + if self.byDay: + day = max(self.byDay, key=lambda r: r.end) + else: + day = None + if self.byMonth: + month = max(self.byMonth, key=lambda r: r.end) + else: + month = None + if self.byYear: + year = max(self.byYear, key=lambda r: r.end) + else: + year = None + + return { + "5minutes": fminutes, + "hour": hour, + "day": day, + "month": month, + "year": year + } pingingLock = threading.RLock() pinging = set() @@ -195,7 +224,7 @@ def get_site_pairs(): def housekeep(): exec_js(js_code("link_housekeep"), now=time.time(), types=TYPES, keep_records=KEEP_RECORDS, max_age={k: v.total_seconds() for k, v in MAX_AGE.items()}) -def getStatistics(siteA, siteB): #@ReservedAssignment +def getStatistics(siteA, siteB): _siteA = Site.get(siteA) _siteB = Site.get(siteB) UserError.check(_siteA is not None, UserError.ENTITY_DOES_NOT_EXIST, "site does not exist", data={"site": siteA}) @@ -203,12 +232,13 @@ def getStatistics(siteA, siteB): #@ReservedAssignment if _siteA.id > _siteB.id: _siteA, _siteB = _siteB, _siteA try: - stats = LinkStatistics.objects.get(siteA=_siteA, siteB=_siteB) - return stats.info() + return LinkStatistics.objects.get(siteA=_siteA, siteB=_siteB) except LinkStatistics.DoesNotExist: ping(_siteA, _siteB) - stats = LinkStatistics.objects.get(siteA=_siteA, siteB=_siteB) - return stats.info() + return LinkStatistics.objects.get(siteA=_siteA, siteB=_siteB) + +def getStatisticsInfo(siteA, siteB): #@ReservedAssignment + return getStatistics(siteA, siteB).info() scheduler.scheduleMaintenance(60, get_site_pairs, lambda pair: ping(pair[0], pair[1], ignore_missing_site=True)) # every minute diff --git a/shared/lib/constants.py b/shared/lib/constants.py index a1e0a813b..e35c3595c 100644 --- a/shared/lib/constants.py +++ b/shared/lib/constants.py @@ -1,3 +1,8 @@ +class ConnectionDistance: + INTRA_HOST = "intra-host" + INTRA_SITE = "intra-site" + INTER_SITE = "inter-site" + class DumpSourcePrefix: API = "api:" From 5a77b5e6862cc7ee0b658404f6ad46f1b38c7888 Mon Sep 17 00:00:00 2001 From: Tim Gerhard Date: Mon, 9 Jan 2017 15:26:49 +0100 Subject: [PATCH 3/9] added a page for connection link info in webfrontend --- web/tomato/site_map.py | 2 ++ .../templates/topology/connection_link.html | 34 +++++++++++++++++++ web/tomato/topology.py | 10 ++++++ web/tomato/urls.py | 1 + 4 files changed, 47 insertions(+) create mode 100644 web/tomato/templates/topology/connection_link.html diff --git a/web/tomato/site_map.py b/web/tomato/site_map.py index 1e0df71d4..306cb91a0 100644 --- a/web/tomato/site_map.py +++ b/web/tomato/site_map.py @@ -191,6 +191,8 @@ def map_kml(api, request): @wrap_rpc def details_link(api, request, src, dst): + if src==dst: + return details_site(request, src) return render(request, "map/usage.html",{'usage':api.link_statistics(src,dst),'name': api.site_info(src)['label'] + " <-> " + api.site_info(dst)['label'],'user':api.user}); @wrap_rpc diff --git a/web/tomato/templates/topology/connection_link.html b/web/tomato/templates/topology/connection_link.html new file mode 100644 index 000000000..1463ff9c2 --- /dev/null +++ b/web/tomato/templates/topology/connection_link.html @@ -0,0 +1,34 @@ +{% extends "base.html" %} + +{% load url from future %} +{% load tomato %} + +{% block title %} +Connection Link - ToMaTo Testbed +{% endblock %} + +{% block page %} +

{{conn.label|safe}}

+ + + {% if conn.link_statistics %} + + + + + + {% endif %} + + +
Distance:{{conn.link_statistics.distance}}
+{% if conn.link_statistics %} +{% if conn.link_statistics.statistics %} + +{% endif %} +{% else %} +

No statistics available.

+{% endif %} +{% endblock %} \ No newline at end of file diff --git a/web/tomato/topology.py b/web/tomato/topology.py index 9c757ad56..288502b93 100644 --- a/web/tomato/topology.py +++ b/web/tomato/topology.py @@ -180,6 +180,16 @@ def tabbed_console(api, request, id): top["elements"].sort(key=lambda x: x.get('name', x.get('id', None))) return render(request, "topology/console_tabbed.html", {"topology": top}) +@wrap_rpc +def connection_stats(api, request, id): + conn = api.connection_info(id) + elemA_if = api.element_info(conn["elements"][0]) + elemB_if = api.element_info(conn["elements"][1]) + elemA = api.element_info(elemA_if["parent"]) + elemB = api.element_info(elemB_if["parent"]) + conn["label"] = "%s.%s ⇆ %s.%s" % (elemA["name"], elemA_if["name"], elemB["name"], elemB_if["name"]) + return render(request, "topology/connection_link.html", {"conn": conn}) + @wrap_rpc def export(api, request, id): if not api.user: diff --git a/web/tomato/urls.py b/web/tomato/urls.py index 1f15c6d5c..def39777c 100644 --- a/web/tomato/urls.py +++ b/web/tomato/urls.py @@ -73,6 +73,7 @@ (r'^tutorial$', 'tomato.tutorial.list'), (r'^tutorial/start$', 'tomato.tutorial.start'), (r'^connection/(?P\w{24})/usage$', 'tomato.usage.connection'), + (r'^connection/(?P\w{24})/link$', 'tomato.topology.connection_stats'), (r'^element/(?P\w{24})/usage$', 'tomato.usage.element'), (r'^element/(?P\w{24})/rextfv_status$', 'tomato.element.rextfv_status'), (r'^element/(?P\w{24})/console$', 'tomato.element.console'), From 489e8e8f859fffd217334365661e1f171481b130 Mon Sep 17 00:00:00 2001 From: Tim Gerhard Date: Mon, 9 Jan 2017 15:45:31 +0100 Subject: [PATCH 4/9] fixed a debugging decision --- backend_core/tomato/connections.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend_core/tomato/connections.py b/backend_core/tomato/connections.py index 9e07ed223..16fe347e9 100644 --- a/backend_core/tomato/connections.py +++ b/backend_core/tomato/connections.py @@ -473,7 +473,7 @@ def link_stats(self): hostB = self.elementTo.host.name siteB = self.elementTo.host.site.name - if hostA != hostB: + if hostA == hostB: distance = ConnectionDistance.INTRA_HOST link_stats = None From 2f85db8f7414c98618ba3319fca749e0aa374741 Mon Sep 17 00:00:00 2001 From: Tim Gerhard Date: Mon, 9 Jan 2017 15:45:48 +0100 Subject: [PATCH 5/9] fixed layout for connection link stats page --- .../templates/topology/connection_link.html | 38 +++++++++---------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/web/tomato/templates/topology/connection_link.html b/web/tomato/templates/topology/connection_link.html index 1463ff9c2..49b660011 100644 --- a/web/tomato/templates/topology/connection_link.html +++ b/web/tomato/templates/topology/connection_link.html @@ -8,27 +8,25 @@ {% endblock %} {% block page %} -

{{conn.label|safe}}

- - - {% if conn.link_statistics %} - - - - - - {% endif %} - - -
Distance:{{conn.link_statistics.distance}}
+

{{conn.label|safe}}

{% if conn.link_statistics %} -{% if conn.link_statistics.statistics %} - -{% endif %} +

{{conn.link_statistics.distance}} connection

+ {% if conn.link_statistics.statistics %} + + {% else %} +
+

This is an intra-host connection.

+

The connectivity inside a single host is not measured.

+
+ {% endif %} {% else %} -

No statistics available.

+
+

No statistics available

+

There are no statistics available for this link. Most likely, the connected elements have not been prepared yet.

+
{% endif %} {% endblock %} \ No newline at end of file From 8d2bac7d4747e16f698dbdbf3de653fb21c8132f Mon Sep 17 00:00:00 2001 From: Tim Gerhard Date: Mon, 9 Jan 2017 15:45:57 +0100 Subject: [PATCH 6/9] integrated link statistics into editor --- web/tomato/js/editor/components/connection.js | 4 ++++ web/tomato/js/editor/menus/menus/connection_menu.js | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/web/tomato/js/editor/components/connection.js b/web/tomato/js/editor/components/connection.js index 18be322e7..a0a4d6f18 100644 --- a/web/tomato/js/editor/components/connection.js +++ b/web/tomato/js/editor/components/connection.js @@ -128,6 +128,10 @@ var Connection = Component.extend({ window.location.href = url; }}) }, + showLinkInfo: function() { + window.open('../connection/'+this.id+'/link', '_blank', "innerWidth=768,innerheight=700,status=no,toolbar=no,menubar=no,location=no,hotkeys=no,scrollbars=no"); + this.triggerEvent({operation: "console-dialog"}); + }, /* viewCapture: function() { this.action("download_grant", {params: {limitSize: 1024*1024}, callback: function(con, res) { diff --git a/web/tomato/js/editor/menus/menus/connection_menu.js b/web/tomato/js/editor/menus/menus/connection_menu.js index 420d6960f..77fc7ad66 100644 --- a/web/tomato/js/editor/menus/menus/connection_menu.js +++ b/web/tomato/js/editor/menus/menus/connection_menu.js @@ -12,6 +12,13 @@ var createConnectionMenu = function(obj) { obj.showUsage(); } }, + "link": { + name:"Link statistics", + icon:"info", + callback: function(){ + obj.showLinkInfo(); + } + }, "sep1": "---", /* "cloudshark_capture": obj.captureDownloadable() ? { From 195e4116fcf71c7e5407671ec6eacb81a9cdd49f Mon Sep 17 00:00:00 2001 From: Tim Gerhard Date: Mon, 9 Jan 2017 15:56:50 +0100 Subject: [PATCH 7/9] now showing link distance in editor workspace --- web/tomato/js/editor/components/connection.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/web/tomato/js/editor/components/connection.js b/web/tomato/js/editor/components/connection.js index a0a4d6f18..3dee4f5a6 100644 --- a/web/tomato/js/editor/components/connection.js +++ b/web/tomato/js/editor/components/connection.js @@ -50,12 +50,25 @@ var Connection = Component.extend({ var pos2 = this.fromElement().getAbsPos(); return Raphael.angle(pos1.x, pos1.y, pos2.x, pos2.y); }, + getHandleColor: function() { + if (this.data.link_statistics == null) { + return "#CDCDB3"; + } else if (this.data.link_statistics.distance == "intra-host") { + return "#63dd37"; + } else if (this.data.link_statistics.distance == "intra-site") { + return "#e8e417"; + } else if (this.data.link_statistics.distance == "inter-site") { + return "#e28706"; + } else { + return "#474747"; + } + }, paint: function() { this.path = this.canvas.path(this.getPath()); this.path.toBack(); var pos = this.getAbsPos(); var width = settings.connectionHandleWidth; - this.handle = this.canvas.rect(pos.x-(width/2), pos.y-(width/2), width, width).attr({fill: "#4040FF", transform: "R"+this.getAngle()}); + this.handle = this.canvas.rect(pos.x-(width/2), pos.y-(width/2), width, width).attr({fill: this.getHandleColor(), transform: "R"+this.getAngle()}); $(this.handle.node).attr("class", "tomato connection"); this.handle.node.obj = this; var t = this; @@ -86,7 +99,7 @@ var Connection = Component.extend({ this.path.attr({path: this.getPath()}); var pos = this.getAbsPos(); var width = settings.connectionHandleWidth; - this.handle.attr({x: pos.x-(width/2), y: pos.y-(width/2), transform: "R"+this.getAngle()}); + this.handle.attr({x: pos.x-(width/2), y: pos.y-(width/2), transform: "R"+this.getAngle(), fill: this.getHandleColor()}); if (this.editor.options.show_connection_controls) { this.handle.attr({'width': width}); //fixme: this should be a global parameter } else { From 01235c3a155766678eb3b14070c8e9f558d9a07e Mon Sep 17 00:00:00 2001 From: Tim Gerhard Date: Mon, 9 Jan 2017 15:58:41 +0100 Subject: [PATCH 8/9] some doc --- web/tomato/js/editor/components/connection.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/web/tomato/js/editor/components/connection.js b/web/tomato/js/editor/components/connection.js index 3dee4f5a6..c5da731b2 100644 --- a/web/tomato/js/editor/components/connection.js +++ b/web/tomato/js/editor/components/connection.js @@ -51,7 +51,7 @@ var Connection = Component.extend({ return Raphael.angle(pos1.x, pos1.y, pos2.x, pos2.y); }, getHandleColor: function() { - if (this.data.link_statistics == null) { + if (this.data.link_statistics == null) { // links that have not been deployed return "#CDCDB3"; } else if (this.data.link_statistics.distance == "intra-host") { return "#63dd37"; @@ -59,7 +59,7 @@ var Connection = Component.extend({ return "#e8e417"; } else if (this.data.link_statistics.distance == "inter-site") { return "#e28706"; - } else { + } else { // unexpected value return "#474747"; } }, From ef73379dbcd86add0b6559714745341e5ed375fb Mon Sep 17 00:00:00 2001 From: Tim Gerhard Date: Tue, 10 Jan 2017 10:18:00 +0100 Subject: [PATCH 9/9] added a hint to the connection link statistics in the link emulation tutorial --- contrib/tutorials/link_emulation/steps.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/contrib/tutorials/link_emulation/steps.js b/contrib/tutorials/link_emulation/steps.js index e8d5d34db..3c7f39bfe 100644 --- a/contrib/tutorials/link_emulation/steps.js +++ b/contrib/tutorials/link_emulation/steps.js @@ -9,9 +9,10 @@ text: '

\ Let\'s take a closer look at a connection.

\

\ - Every connection consits of two network interfaces and the connection itself.
\ + Every connection consists of two network interfaces and the connection itself.
\ An interface is represented by a grey circle at a device. Here you can configure the device\'s network preferences (e.g., ip address).
\ - The connection is represented by a blue square at its center. Here, you can configure the link (e.g., bandwidth, loss rate, etc).

\ + The connection is represented by blue square at its center. Here, you can configure the link (e.g., bandwidth, loss rate, etc).
\ + The square changes its color depending on the nature of the connection: whether it connects elements inside a host, inside a single site, or over multiple sites. You can find more information in the \'Link statistics\' in the connection\'s right-click menu.

\

\ The options available to a connection depend on the connected devices. The same is true for interfaces.

', skip_button: 'Continue'