Move the generation of the list of ports to the server

Ref #676
This commit is contained in:
Julien Duponchelle committed 2016-09-14 15:21:37 +02:00
1 parent f06c00fdb8
commit 2f0e2260ab
50 files changed
+1347 -240

No files matched your search

+67 -5
View File
@@ -23,6 +23,7 @@ import os
from .compute import ComputeConflict
from .ports.port_factory import PortFactory, StandardPortFactory, DynamipsPortFactory
from ..utils.images import images_directories
from ..utils.qt import qt_font_to_style
@@ -33,7 +34,8 @@ log = logging.getLogger(__name__)
class Node:
# This properties are used only on controller and are not forwarded to the compute
CONTROLLER_ONLY_PROPERTIES = ["x", "y", "z", "width", "height", "symbol", "label", "console_host"]
CONTROLLER_ONLY_PROPERTIES = ["x", "y", "z", "width", "height", "symbol", "label", "console_host",
"port_name_format", "first_port_name", "port_segment_size", "ports"]
def __init__(self, project, compute, name, node_id=None, node_type=None, **kwargs):
"""
@@ -69,12 +71,20 @@ class Node:
self._y = 0
self._z = 0
self._symbol = None
# Update node properties with additional elements
if node_type == "iou":
self._port_name_format = "Ethernet{segment0}/{port0}"
self._port_by_adapter = 4
self.port_segment_size = 4
else:
self._port_name_format = "Ethernet{0}"
self._port_by_adapter = 1
self._port_segment_size = 0
self._first_port_name = None
# This properties will be recompute
ignore_properties = ("width", "height")
# Update node properties with additional elements
for prop in kwargs:
if prop not in ignore_properties:
try:
@@ -220,6 +230,30 @@ class Node:
val["text"] = self._name
self._label = val
@property
def port_name_format(self):
return self._port_name_format
@port_name_format.setter
def port_name_format(self, val):
self._port_name_format = val
@property
def port_segment_size(self):
return self._port_segment_size
@port_segment_size.setter
def port_segment_size(self, val):
self._port_segment_size = val
@property
def first_port_name(self):
return self._first_port_name
@first_port_name.setter
def first_port_name(self, val):
self._first_port_name = val
@asyncio.coroutine
def create(self):
"""
@@ -423,6 +457,27 @@ class Node:
"""
return (yield from self._compute.get("/projects/{}/{}/nodes/{}/idlepc_proposals".format(self._project.id, self._node_type, self._id), timeout=240)).json
def _list_ports(self):
"""
Generate the list of port display in the client
if the compute has sent a list we return it (use by
node where you can not personnalize the port naming).
"""
ports = []
# Some special cases
if self._node_type == "atm_switch":
for adapter_number in range(0, len(self.properties["mappings"])):
ports.append(PortFactory("ATM{}".format(adapter_number), adapter_number, adapter_number, 0, "atm"))
return ports
elif self._node_type == "frame_relay_switch":
for adapter_number in range(0, len(self.properties["mappings"])):
ports.append(PortFactory("FrameRelay{}".format(adapter_number), adapter_number, adapter_number, 0, "frame_relay"))
return ports
elif self._node_type == "dynamips":
return DynamipsPortFactory(self.properties)
else:
return StandardPortFactory(self.properties, self._port_by_adapter, self._first_port_name, self._port_name_format, self._port_segment_size)
def __repr__(self):
return "<gns3server.controller.Node {} {}>".format(self._node_type, self._name)
@@ -450,7 +505,10 @@ class Node:
"z": self._z,
"width": self._width,
"height": self._height,
"symbol": self._symbol
"symbol": self._symbol,
"port_name_format": self._port_name_format,
"port_segment_size": self._port_segment_size,
"first_port_name": self._first_port_name
}
return {
"compute_id": str(self._compute.id),
@@ -471,5 +529,9 @@ class Node:
"z": self._z,
"width": self._width,
"height": self._height,
"symbol": self._symbol
"symbol": self._symbol,
"port_name_format": self._port_name_format,
"port_segment_size": self._port_segment_size,
"first_port_name": self._first_port_name,
"ports": [port.__json__() for port in self._list_ports()]
}
Whitespace-only changes.
+65
View File
@@ -0,0 +1,65 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
ATM port for ATM link end points.
"""
from .port import Port
class ATMPort(Port):
@staticmethod
def longNameType():
"""
Returns the long name type for this port.
:returns: string
"""
return "ATM"
@staticmethod
def shortNameType():
"""
Returns the short name type for this port.
:returns: string
"""
return "a"
@staticmethod
def linkType():
"""
Returns the link type to be used to connect this port.
:returns: string
"""
return "Serial"
@staticmethod
def dataLinkTypes():
"""
Returns the supported PCAP DLTs.
:return: dictionary
"""
return {"ATM": "DLT_ATM_RFC1483"}
@@ -0,0 +1,50 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Ethernet port for Ethernet link end points.
"""
from .port import Port
class EthernetPort(Port):
"""
Ethernet port.
"""
@staticmethod
def longNameType():
"""
Returns the long name type for this port.
:returns: string
"""
return "Ethernet"
@staticmethod
def shortNameType():
"""
Returns the short name type for this port.
:returns: string
"""
return "e"
@@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
FastEthernet port for Ethernet link end points.
"""
from .port import Port
class FastEthernetPort(Port):
@staticmethod
def longNameType():
"""
Returns the long name type for this port.
:returns: string
"""
return "FastEthernet"
@staticmethod
def shortNameType():
"""
Returns the short name type for this port.
:returns: string
"""
return "f"
@@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Frame relay port for serial link end points.
"""
from .serial_port import SerialPort
class FrameRelayPort(SerialPort):
@staticmethod
def longNameType():
"""
Returns the long name type for this port.
:returns: string
"""
return "FrameRelay"
@staticmethod
def dataLinkTypes():
"""
Returns the supported PCAP DLTs.
:return: dictionary
"""
return {"Frame Relay": "DLT_FRELAY"}
@@ -0,0 +1,45 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
GigabitEthernet port for Ethernet link end points.
"""
from .port import Port
class GigabitEthernetPort(Port):
@staticmethod
def longNameType():
"""
Returns the long name type for this port.
:returns: string
"""
return "GigabitEthernet"
@staticmethod
def shortNameType():
"""
Returns the short name type for this port.
:returns: string
"""
return "g"
+51
View File
@@ -0,0 +1,51 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
class Port:
"""
Base class for port objects.
"""
def __init__(self, name, interface_number, adapter_number, port_number):
self._interface_number = interface_number
self._adapter_number = adapter_number
self._port_number = port_number
self._name = name
@staticmethod
def dataLinkTypes():
"""
Returns the supported PCAP DLTs.
:return: dictionary
"""
return {"Ethernet": "DLT_EN10MB"}
@staticmethod
def linkType():
return "Ethernet"
def __json__(self):
return {
"name": self._name,
"short_name": self.shortNameType() + "{}/{}".format(self._interface_number, self._port_number),
"data_link_types": self.dataLinkTypes(),
"port_number": self._port_number,
"adapter_number": self._adapter_number,
"link_type": self.linkType().lower()
}
+189
View File
@@ -0,0 +1,189 @@
#!/usr/bin/env python
#
# Copyright (C) 2016 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
from .atm_port import ATMPort
from .frame_relay_port import FrameRelayPort
from .gigabitethernet_port import GigabitEthernetPort
from .fastethernet_port import FastEthernetPort
from .ethernet_port import EthernetPort
from .serial_port import SerialPort
from .pos_port import POSPort
import logging
log = logging.getLogger(__name__)
PORTS = {
'atm': ATMPort,
'frame_relay': FrameRelayPort,
'fastethernet': FastEthernetPort,
'gigabitethernet': GigabitEthernetPort,
'ethernet': EthernetPort,
'serial': SerialPort
}
class PortFactory:
"""
Factory to create an Port object based on the type
"""
def __new__(cls, name, interface_number, adapter_number, port_number, port_type, **kwargs):
return PORTS[port_type](name, interface_number, adapter_number, port_number, **kwargs)
class StandardPortFactory:
"""
Create ports for standard device
"""
def __new__(cls, properties, port_by_adapter, first_port_name, port_name_format, port_segment_size):
ports = []
interface_number = segment_number = 0
if "serial_adapters" in properties:
for adapter_number in range(0, properties["serial_adapters"]):
for port_number in range(0, port_by_adapter):
ports.append(PortFactory("Serial{}/{}".format(adapter_number, port_number), adapter_number, adapter_number, port_number, "serial"))
if "ethernet_adapters" in properties:
ethernet_adapters = properties["ethernet_adapters"]
else:
ethernet_adapters = properties.get("adapters", 1)
for adapter_number in range(0, ethernet_adapters):
for port_number in range(0, port_by_adapter):
if first_port_name and adapter_number == 0:
port_name = first_port_name
else:
port_name = port_name_format.format(
interface_number,
segment_number,
adapter=adapter_number,
**cls._generate_replacement(interface_number, segment_number))
interface_number += 1
if port_segment_size and interface_number % port_segment_size == 0:
segment_number += 1
interface_number = 0
ports.append(PortFactory(port_name, adapter_number, adapter_number, port_number, "ethernet"))
return ports
@staticmethod
def _generate_replacement(interface_number, segment_number):
"""
This will generate replacement string for
{port0} => {port9}
{segment0} => {segment9}
"""
replacements = {}
for i in range(0, 9):
replacements["port" + str(i)] = interface_number + i
replacements["segment" + str(i)] = segment_number + i
return replacements
class DynamipsPortFactory:
"""
Create port for dynamips devices
"""
ADAPTER_MATRIX = {
"C1700-MB-1FE": {"nb_ports": 1,
"port": FastEthernetPort},
"C1700-MB-WIC1": {"nb_ports": 0,
"port": None},
"C2600-MB-1E": {"nb_ports": 1,
"port": EthernetPort},
"C2600-MB-1FE": {"nb_ports": 1,
"port": FastEthernetPort},
"C2600-MB-2E": {"nb_ports": 2,
"port": EthernetPort},
"C2600-MB-2FE": {"nb_ports": 2,
"port": FastEthernetPort},
"C7200-IO-2FE": {"nb_ports": 2,
"port": FastEthernetPort},
"C7200-IO-FE": {"nb_ports": 1,
"port": FastEthernetPort},
"C7200-IO-GE-E": {"nb_ports": 1,
"port": GigabitEthernetPort},
"GT96100-FE": {"nb_ports": 2,
"port": FastEthernetPort},
"Leopard-2FE": {"nb_ports": 2,
"port": FastEthernetPort},
"NM-16ESW": {"nb_ports": 16,
"port": FastEthernetPort},
"NM-1E": {"nb_ports": 1,
"port": EthernetPort},
"NM-1FE-TX": {"nb_ports": 1,
"port": FastEthernetPort},
"NM-4E": {"nb_ports": 4,
"port": EthernetPort},
"NM-4T": {"nb_ports": 4,
"port": SerialPort},
"PA-2FE-TX": {"nb_ports": 2,
"port": FastEthernetPort},
"PA-4E": {"nb_ports": 4,
"port": EthernetPort},
"PA-4T+": {"nb_ports": 4,
"port": SerialPort},
"PA-8E": {"nb_ports": 8,
"port": EthernetPort},
"PA-8T": {"nb_ports": 8,
"port": SerialPort},
"PA-A1": {"nb_ports": 1,
"port": ATMPort},
"PA-FE-TX": {"nb_ports": 1,
"port": FastEthernetPort},
"PA-GE": {"nb_ports": 1,
"port": GigabitEthernetPort},
"PA-POS-OC3": {"nb_ports": 1,
"port": POSPort},
}
WIC_MATRIX = {"WIC-1ENET": {"nb_ports": 1,
"port": EthernetPort},
"WIC-1T": {"nb_ports": 1,
"port": SerialPort},
"WIC-2T": {"nb_ports": 2,
"port": SerialPort}
}
def __new__(cls, properties):
ports = []
interface_numbers = {}
adapter_number = 0
wic_port_number = 16
for name in sorted(properties.keys()):
if name.startswith("slot") and properties[name]:
port_class = cls.ADAPTER_MATRIX[properties[name]]["port"]
if port_class:
interface_numbers.setdefault(port_class, 0)
interface_number = interface_numbers[port_class]
for port_number in range(0, cls.ADAPTER_MATRIX[properties[name]]["nb_ports"]):
name = "{}{}/{}".format(port_class.longNameType(), interface_number, port_number)
ports.append(port_class(name, interface_number, adapter_number, port_number))
interface_numbers[port_class] += 1
adapter_number += 1
elif name.startswith("wic") and properties[name]:
port_class = cls.WIC_MATRIX[properties[name]]["port"]
if port_class:
for port_number in range(0, cls.WIC_MATRIX[properties[name]]["nb_ports"]):
name = "{}{}/{}".format(port_class.longNameType(), 0, wic_port_number)
ports.append(port_class(name, 0, 0, wic_port_number))
wic_port_number += 1
return ports
+66
View File
@@ -0,0 +1,66 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
POS port for Packet over SONET link end points.
"""
from .port import Port
class POSPort(Port):
@staticmethod
def longNameType():
"""
Returns the long name type for this port.
:returns: string
"""
return "POS"
@staticmethod
def shortNameType():
"""
Returns the short name type for this port.
:returns: string
"""
return "p"
@staticmethod
def linkType():
"""
Returns the link type to be used to connect this port.
:returns: string
"""
return "Serial"
@staticmethod
def dataLinkTypes():
"""
Returns the supported PCAP DLTs.
:return: dictionary
"""
# Packet capture on PoS is not supported
return {}
@@ -0,0 +1,67 @@
# -*- coding: utf-8 -*-
#
# Copyright (C) 2014 GNS3 Technologies Inc.
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
"""
Serial port for serial link end points.
"""
from .port import Port
class SerialPort(Port):
@staticmethod
def longNameType():
"""
Returns the long name type for this port.
:returns: string
"""
return "Serial"
@staticmethod
def shortNameType():
"""
Returns the short name type for this port.
:returns: string
"""
return "s"
@staticmethod
def linkType():
"""
Returns the link type to be used to connect this port.
:returns: string
"""
return "Serial"
@staticmethod
def dataLinkTypes():
"""
Returns the supported PCAP DLTs.
:return: dictionary
"""
return {"Frame Relay": "DLT_FRELAY",
"Cisco HDLC": "DLT_C_HDLC",
"Cisco PPP": "DLT_PPP_SERIAL"}
+9 -6
View File
@@ -179,6 +179,9 @@ def _convert_1_3_later(topo, topo_path):
node["x"] = int(old_node["x"])
node["y"] = int(old_node["y"])
node["z"] = int(old_node.get("z", 1))
node["port_name_format"] = old_node.get("port_name_format", "Ethernet{0}")
node["port_segment_size"] = int(old_node.get("port_segment_size", "0"))
node["first_port_name"] = old_node.get("first_port_name")
node["properties"] = {}
@@ -196,21 +199,21 @@ def _convert_1_3_later(topo, topo_path):
node["console_type"] = None
elif old_node["type"] == "EthernetHub":
node["node_type"] = "ethernet_hub"
node["symbol"] = ":/symbols/hub.svg"
node["console_type"] = None
node["properties"]["ports"] = []
node["symbol"] = ":/symbols/hub.svg"
node["properties"]["ports_mapping"] = []
for port in old_node["ports"]:
node["properties"]["ports"].append({
node["properties"]["ports_mapping"].append({
"name": "Ethernet{}".format(port["port_number"]),
"port_number": port["port_number"]
})
elif old_node["type"] == "EthernetSwitch":
node["node_type"] = "ethernet_switch"
node["symbol"] = ":/symbols/ethernet_switch.svg"
node["properties"]["ports"] = []
node["console_type"] = None
node["properties"]["ports_mapping"] = []
for port in old_node["ports"]:
node["properties"]["ports"].append({
node["properties"]["ports_mapping"].append({
"name": "Ethernet{}".format(port["port_number"]),
"port_number": port["port_number"],
"type": port["type"],
@@ -439,7 +442,7 @@ def _create_cloud(node, old_node, icon):
}
ports.append(port)
node["properties"]["ports"] = ports
node["properties"]["ports_mapping"] = ports
node["properties"]["interfaces"] = []