mirror of
https://github.com/GNS3/gns3-gui.git
synced 2026-05-17 08:56:06 +03:00
First draft of VPCS module
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -45,3 +45,5 @@ nosetests.xml
|
||||
*_log.txt
|
||||
*.log
|
||||
|
||||
# Gedit Temp Files
|
||||
*~
|
||||
|
||||
@@ -17,5 +17,6 @@
|
||||
|
||||
from gns3.modules.dynamips import Dynamips
|
||||
from gns3.modules.iou import IOU
|
||||
from gns3.modules.vpcs import VPCS
|
||||
|
||||
MODULES = [Dynamips, IOU]
|
||||
MODULES = [Dynamips, IOU, VPCS]
|
||||
|
||||
450
gns3/modules/vpcs/__init__.py
Normal file
450
gns3/modules/vpcs/__init__.py
Normal file
@@ -0,0 +1,450 @@
|
||||
# -*- 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/>.
|
||||
|
||||
"""
|
||||
VPCS module implementation.
|
||||
"""
|
||||
|
||||
import socket
|
||||
import base64
|
||||
import os
|
||||
from gns3.qt import QtCore, QtGui
|
||||
from gns3.servers import Servers
|
||||
from ..module import Module
|
||||
from ..module_error import ModuleError
|
||||
from .vpcs_device import VPCSDevice
|
||||
from .settings import VPCS_SETTINGS, VPCS_SETTING_TYPES
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class VPCS(Module):
|
||||
"""
|
||||
VPCS module.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
Module.__init__(self)
|
||||
|
||||
self._settings = {}
|
||||
self._nodes = []
|
||||
self._vpcs_images = {}
|
||||
self._servers = []
|
||||
self._working_dir = ""
|
||||
|
||||
# load the settings
|
||||
self._loadSettings()
|
||||
self._loadVPCSImages()
|
||||
|
||||
def _loadSettings(self):
|
||||
"""
|
||||
Loads the settings from the persistent settings file.
|
||||
"""
|
||||
|
||||
# load the settings
|
||||
settings = QtCore.QSettings()
|
||||
settings.beginGroup(self.__class__.__name__)
|
||||
for name, value in VPCS_SETTINGS.items():
|
||||
self._settings[name] = settings.value(name, value, type=VPCS_SETTING_TYPES[name])
|
||||
settings.endGroup()
|
||||
|
||||
def _saveSettings(self):
|
||||
"""
|
||||
Saves the settings to the persistent settings file.
|
||||
"""
|
||||
|
||||
# save the settings
|
||||
settings = QtCore.QSettings()
|
||||
settings.beginGroup(self.__class__.__name__)
|
||||
for name, value in self._settings.items():
|
||||
settings.setValue(name, value)
|
||||
settings.endGroup()
|
||||
|
||||
def _loadVPCSImages(self):
|
||||
"""
|
||||
Load the VPCS images from the persistent settings file.
|
||||
"""
|
||||
|
||||
# load the settings
|
||||
settings = QtCore.QSettings()
|
||||
settings.beginGroup("VPCSImages")
|
||||
|
||||
# load the VPCS images
|
||||
size = settings.beginReadArray("vpcs_image")
|
||||
for index in range(0, size):
|
||||
settings.setArrayIndex(index)
|
||||
path = settings.value("path", "")
|
||||
image = settings.value("image", "")
|
||||
startup_config = settings.value("startup_config", "")
|
||||
ram = settings.value("ram", 256, type=int)
|
||||
nvram = settings.value("nvram", 128, type=int)
|
||||
server = settings.value("server", "local")
|
||||
key = "{server}:{image}".format(server=server, image=image)
|
||||
self._vpcs_images[key] = {"path": path,
|
||||
"image": image,
|
||||
"startup_config": startup_config,
|
||||
"ram": ram,
|
||||
"nvram": nvram,
|
||||
"server": server}
|
||||
|
||||
settings.endArray()
|
||||
settings.endGroup()
|
||||
|
||||
def _saveVPCSImages(self):
|
||||
"""
|
||||
Saves the VPCS images to the persistent settings file.
|
||||
"""
|
||||
|
||||
# save the settings
|
||||
settings = QtCore.QSettings()
|
||||
settings.beginGroup("VPCSImages")
|
||||
settings.remove("")
|
||||
|
||||
# save the VPCS images
|
||||
settings.beginWriteArray("vpcs_image", len(self._vpcs_images))
|
||||
index = 0
|
||||
for ios_image in self._vpcs_images.values():
|
||||
settings.setArrayIndex(index)
|
||||
for name, value in ios_image.items():
|
||||
settings.setValue(name, value)
|
||||
index += 1
|
||||
settings.endArray()
|
||||
settings.endGroup()
|
||||
|
||||
def setProjectFilesDir(self, path):
|
||||
"""
|
||||
Sets the project files directory path this module.
|
||||
|
||||
:param path: path to the local project files directory
|
||||
"""
|
||||
|
||||
self._working_dir = path
|
||||
log.info("local working directory for VPCS module: {}".format(self._working_dir))
|
||||
|
||||
# update the server with the new working directory / project name
|
||||
for server in self._servers:
|
||||
if server.connected():
|
||||
self._sendSettings(server)
|
||||
|
||||
def addServer(self, server):
|
||||
"""
|
||||
Adds a server to be used by this module.
|
||||
|
||||
:param server: WebSocketClient instance
|
||||
"""
|
||||
|
||||
log.info("adding server {}:{} to VPCS module".format(server.host, server.port))
|
||||
self._servers.append(server)
|
||||
self._sendSettings(server)
|
||||
|
||||
def removeServer(self, server):
|
||||
"""
|
||||
Removes a server from being used by this module.
|
||||
|
||||
:param server: WebSocketClient instance
|
||||
"""
|
||||
|
||||
log.info("removing server {}:{} from VPCS module".format(server.host, server.port))
|
||||
self._servers.remove(server)
|
||||
|
||||
def servers(self):
|
||||
"""
|
||||
Returns all the servers used by this module.
|
||||
|
||||
:returns: list of WebSocketClient instances
|
||||
"""
|
||||
|
||||
return self._servers
|
||||
|
||||
def addNode(self, node):
|
||||
"""
|
||||
Adds a node to this module.
|
||||
|
||||
:param node: Node instance
|
||||
"""
|
||||
|
||||
self._nodes.append(node)
|
||||
|
||||
def removeNode(self, node):
|
||||
"""
|
||||
Removes a node from this module.
|
||||
|
||||
:param node: Node instance
|
||||
"""
|
||||
|
||||
if node in self._nodes:
|
||||
self._nodes.remove(node)
|
||||
|
||||
def vpcsImages(self):
|
||||
"""
|
||||
Returns VPCS images settings.
|
||||
|
||||
:returns: VPCS images settings (dictionary)
|
||||
"""
|
||||
|
||||
return self._vpcs_images
|
||||
|
||||
def setVPCSImages(self, new_vpcs_images):
|
||||
"""
|
||||
Sets IOS images settings.
|
||||
|
||||
:param new_vpcs_images: IOS images settings (dictionary)
|
||||
"""
|
||||
|
||||
self._vpcs_images = new_vpcs_images.copy()
|
||||
self._saveVPCSImages()
|
||||
|
||||
def settings(self):
|
||||
"""
|
||||
Returns the module settings
|
||||
|
||||
:returns: module settings (dictionary)
|
||||
"""
|
||||
|
||||
return self._settings
|
||||
|
||||
def _base64vpcsrc(self, vpcsrc_path):
|
||||
"""
|
||||
Get the content of the VPCSRC file base64 encoded.
|
||||
|
||||
:param config_path: path to the vpcsrc file.
|
||||
|
||||
:returns: base64 encoded string
|
||||
"""
|
||||
|
||||
try:
|
||||
with open(vpcsrc_path, "r") as f:
|
||||
log.info("opening vpcsrc file: {}".format(vpcsrc_path))
|
||||
config = f.read()
|
||||
encoded = ("").join(base64.encodestring(config.encode("utf-8")).decode("utf-8").split())
|
||||
return encoded
|
||||
except OSError as e:
|
||||
log.warn("could not base64 encode {}: {}".format(vpcsrc_path, e))
|
||||
return ""
|
||||
|
||||
def setSettings(self, settings):
|
||||
"""
|
||||
Sets the module settings
|
||||
|
||||
:param settings: module settings (dictionary)
|
||||
"""
|
||||
|
||||
params = {}
|
||||
for name, value in settings.items():
|
||||
if name in self._settings and self._settings[name] != value:
|
||||
params[name] = value
|
||||
|
||||
if params:
|
||||
if "vpcsrc" in params:
|
||||
# encode the vpcsrc file in base64
|
||||
params["vpcsrc"] = self._base64vpcsrc(params["vpcsrc"])
|
||||
for server in self._servers:
|
||||
# send the local working directory only if this is a local server
|
||||
if server.isLocal():
|
||||
params.update({"working_dir": self._working_dir})
|
||||
else:
|
||||
if "vpcsyap" in params:
|
||||
del params["vpcsyap"] # do not send vpcsyap path to remote servers
|
||||
project_name = os.path.basename(self._working_dir)
|
||||
if project_name.endswith("-files"):
|
||||
project_name = project_name[:-6]
|
||||
params.update({"project_name": project_name})
|
||||
server.send_notification("vpcs.settings", params)
|
||||
|
||||
self._settings.update(settings)
|
||||
self._saveSettings()
|
||||
|
||||
def _sendSettings(self, server):
|
||||
"""
|
||||
Sends the module settings to the server.
|
||||
|
||||
:param server: WebSocketClient instance
|
||||
"""
|
||||
|
||||
log.info("sending VPCS settings to server {}:{}".format(server.host, server.port))
|
||||
params = self._settings.copy()
|
||||
|
||||
# encode the vpcsrc file in base64
|
||||
params["vpcsrc"] = self._base64vpcsrc(params["vpcsrc"])
|
||||
|
||||
# send the local working directory only if this is a local server
|
||||
if server.isLocal():
|
||||
params.update({"working_dir": self._working_dir})
|
||||
else:
|
||||
if "vpcsyap" in params:
|
||||
del params["vpcsyap"] # do not send vpcsyap path to remote servers
|
||||
project_name = os.path.basename(self._working_dir)
|
||||
if project_name.endswith("-files"):
|
||||
project_name = project_name[:-6]
|
||||
params.update({"project_name": project_name})
|
||||
server.send_notification("vpcs.settings", params)
|
||||
|
||||
def allocateServer(self, node_class):
|
||||
"""
|
||||
Allocates a server.
|
||||
|
||||
:param node_class: Node object
|
||||
|
||||
:returns: allocated server (WebSocketClient instance)
|
||||
"""
|
||||
|
||||
# allocate a server for the node
|
||||
servers = Servers.instance()
|
||||
if self._settings["use_local_server"]:
|
||||
# use the local server
|
||||
server = servers.localServer()
|
||||
else:
|
||||
# pick up a remote server (round-robin method)
|
||||
server = next(iter(servers))
|
||||
if not server:
|
||||
raise ModuleError("No remote server is configured")
|
||||
return server
|
||||
|
||||
def createNode(self, node_class, server):
|
||||
"""
|
||||
Creates a new node.
|
||||
|
||||
:param node_class: Node object
|
||||
:param server: WebSocketClient instance
|
||||
"""
|
||||
|
||||
log.info("creating node {}".format(node_class))
|
||||
|
||||
if not self._settings["vpcsrc"] or not os.path.isfile(self._settings["vpcsrc"]):
|
||||
raise ModuleError("The path to VPCSRC must be configured")
|
||||
|
||||
if not server.connected():
|
||||
try:
|
||||
log.info("reconnecting to server {}:{}".format(server.host, server.port))
|
||||
server.reconnect()
|
||||
except OSError as e:
|
||||
raise ModuleError("Could not connect to server {}:{}: {}".format(server.host,
|
||||
server.port,
|
||||
e))
|
||||
if server not in self._servers:
|
||||
self.addServer(server)
|
||||
|
||||
# create an instance of the node class
|
||||
return node_class(self, server)
|
||||
|
||||
def setupNode(self, node):
|
||||
"""
|
||||
Setups a node.
|
||||
|
||||
:param node: Node instance
|
||||
"""
|
||||
|
||||
log.info("configuring node {}".format(node))
|
||||
settings = {}
|
||||
|
||||
selected_images = []
|
||||
for image, info in self._vpcs_images.items():
|
||||
if info["server"] == node.server().host or (node.server().isLocal() and info["server"] == "local"):
|
||||
selected_images.append(image)
|
||||
|
||||
if not selected_images:
|
||||
raise ModuleError("No VPCS image found for this device")
|
||||
elif len(selected_images) > 1:
|
||||
|
||||
from gns3.main_window import MainWindow
|
||||
mainwindow = MainWindow.instance()
|
||||
|
||||
(selection, ok) = QtGui.QInputDialog.getItem(mainwindow, "VPCS image", "Please choose an image", selected_images, 0, False)
|
||||
if ok:
|
||||
vpcsimage = selection
|
||||
else:
|
||||
raise ModuleError("Please select an VPCS image")
|
||||
|
||||
else:
|
||||
vpcsimage = selected_images[0]
|
||||
|
||||
startup_config = self._vpcs_images[vpcsimage]["startup_config"]
|
||||
vpcs_path = self._vpcs_images[vpcsimage]["path"]
|
||||
if startup_config:
|
||||
settings = {"startup_config": startup_config}
|
||||
node.setup(vpcs_path, initial_settings=settings)
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Resets the servers.
|
||||
"""
|
||||
|
||||
log.info("VPCS module reset")
|
||||
for server in self._servers:
|
||||
if server.connected():
|
||||
server.send_notification("vpcs.reset")
|
||||
self._servers.clear()
|
||||
|
||||
def notification(self, destination, params):
|
||||
"""
|
||||
To received notifications from the server.
|
||||
|
||||
:param destination: JSON-RPC method
|
||||
:param params: JSON-RPC params
|
||||
"""
|
||||
|
||||
if "id" in params:
|
||||
for node in self._nodes:
|
||||
if node.id() == params["id"]:
|
||||
message = "node {}: {}".format(node.name(), params["message"])
|
||||
self.notification_signal.emit(message, params["details"])
|
||||
node.stop()
|
||||
|
||||
@staticmethod
|
||||
def getNodeClass(name):
|
||||
"""
|
||||
Returns the object with the corresponding name.
|
||||
|
||||
:param name: object name
|
||||
"""
|
||||
|
||||
if name in globals():
|
||||
return globals()[name]
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def nodes():
|
||||
"""
|
||||
Returns all the node classes supported by this module.
|
||||
|
||||
:returns: list of classes
|
||||
"""
|
||||
|
||||
return [VPCSDevice]
|
||||
|
||||
@staticmethod
|
||||
def preferencePages():
|
||||
"""
|
||||
:returns: QWidget object list
|
||||
"""
|
||||
|
||||
from .pages.vpcs_preferences_page import VPCSPreferencesPage
|
||||
from .pages.vpcs_device_preferences_page import VPCSDevicePreferencesPage
|
||||
return [VPCSPreferencesPage, VPCSDevicePreferencesPage]
|
||||
|
||||
@staticmethod
|
||||
def instance():
|
||||
"""
|
||||
Singleton to return only on instance of VPCS module.
|
||||
|
||||
:returns: instance of VPCS
|
||||
"""
|
||||
|
||||
if not hasattr(VPCS, "_instance"):
|
||||
VPCS._instance = VPCS()
|
||||
return VPCS._instance
|
||||
0
gns3/modules/vpcs/pages/__init__.py
Normal file
0
gns3/modules/vpcs/pages/__init__.py
Normal file
153
gns3/modules/vpcs/pages/vpcs_device_configuration_page.py
Normal file
153
gns3/modules/vpcs/pages/vpcs_device_configuration_page.py
Normal file
@@ -0,0 +1,153 @@
|
||||
# -*- 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/>.
|
||||
|
||||
"""
|
||||
Configuration page for IOU devices.
|
||||
"""
|
||||
|
||||
import os
|
||||
from gns3.qt import QtGui
|
||||
from .. import IOU
|
||||
from gns3.node_configurator import ConfigurationError
|
||||
from ..ui.iou_device_configuration_page_ui import Ui_iouDeviceConfigPageWidget
|
||||
|
||||
|
||||
class iouDeviceConfigurationPage(QtGui.QWidget, Ui_iouDeviceConfigPageWidget):
|
||||
"""
|
||||
QWidget configuration page for IOU devices.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
|
||||
QtGui.QWidget.__init__(self)
|
||||
self.setupUi(self)
|
||||
self.uiStartupConfigToolButton.clicked.connect(self._startupConfigBrowserSlot)
|
||||
|
||||
def _startupConfigBrowserSlot(self):
|
||||
"""
|
||||
Slot to open a file browser and select a startup-config file.
|
||||
"""
|
||||
|
||||
#TODO: current directory for startup-config + filter?
|
||||
path = QtGui.QFileDialog.getOpenFileName(self, "Select a startup configuration", ".")
|
||||
if not path:
|
||||
return
|
||||
|
||||
if not os.access(path, os.R_OK):
|
||||
QtGui.QMessageBox.critical(self, "Startup configuration", "Cannot read {}".format(path))
|
||||
return
|
||||
|
||||
self.uiStartupConfigLineEdit.clear()
|
||||
self.uiStartupConfigLineEdit.setText(path)
|
||||
|
||||
def loadSettings(self, settings, node, group=False):
|
||||
"""
|
||||
Loads the IOU device settings.
|
||||
|
||||
:param settings: the settings (dictionary)
|
||||
:param node: Node instance
|
||||
:param group: indicates the settings apply to a group of routers
|
||||
"""
|
||||
|
||||
if not group:
|
||||
self.uiNameLineEdit.setText(settings["name"])
|
||||
self.uiConsolePortSpinBox.setValue(settings["console"])
|
||||
|
||||
# load the startup-config
|
||||
self.uiStartupConfigLineEdit.setText(settings["startup_config"])
|
||||
|
||||
# load the available IOU images
|
||||
iou_images = IOU.instance().iouImages()
|
||||
for iou_image in iou_images.values():
|
||||
#TODO: remote server aware
|
||||
self.uiIOUImageComboBox.addItem(iou_image["image"], iou_image["path"])
|
||||
|
||||
index = self.uiIOUImageComboBox.findText(os.path.basename(settings["path"]))
|
||||
if index != -1:
|
||||
self.uiIOUImageComboBox.setCurrentIndex(index)
|
||||
|
||||
else:
|
||||
self.uiNameLabel.hide()
|
||||
self.uiNameLineEdit.hide()
|
||||
self.uiIOUImageLabel.hide()
|
||||
self.uiIOUImageComboBox.hide()
|
||||
self.uiConsolePortLabel.hide()
|
||||
self.uiConsolePortSpinBox.hide()
|
||||
self.uiStartupConfigLabel.hide()
|
||||
self.uiStartupConfigLineEdit.hide()
|
||||
self.uiStartupConfigToolButton.hide()
|
||||
|
||||
# load the memories and disks settings
|
||||
self.uiRamSpinBox.setValue(settings["ram"])
|
||||
self.uiNvramSpinBox.setValue(settings["nvram"])
|
||||
|
||||
# load the number of adapters
|
||||
self.uiEthernetAdaptersSpinBox.setValue(settings["ethernet_adapters"])
|
||||
self.uiSerialAdaptersSpinBox.setValue(settings["serial_adapters"])
|
||||
|
||||
def saveSettings(self, settings, node, group=False):
|
||||
"""
|
||||
Saves the IOU device settings.
|
||||
|
||||
:param settings: the settings (dictionary)
|
||||
:param node: Node instance
|
||||
:param group: indicates the settings apply to a group of routers
|
||||
"""
|
||||
|
||||
# these settings cannot be shared by nodes and updated
|
||||
# in the node configurator.
|
||||
if not group:
|
||||
settings["name"] = self.uiNameLineEdit.text()
|
||||
settings["console"] = self.uiConsolePortSpinBox.value()
|
||||
|
||||
startup_config = self.uiStartupConfigLineEdit.text()
|
||||
if startup_config != settings["startup_config"]:
|
||||
if os.access(startup_config, os.R_OK):
|
||||
settings["startup_config"] = startup_config
|
||||
else:
|
||||
QtGui.QMessageBox.critical(self, "Startup-config", "Cannot read the startup-config file")
|
||||
|
||||
# save the IOU image path
|
||||
index = self.uiIOUImageComboBox.currentIndex()
|
||||
ios_path = self.uiIOUImageComboBox.itemData(index)
|
||||
settings["path"] = ios_path
|
||||
else:
|
||||
del settings["name"]
|
||||
del settings["console"]
|
||||
|
||||
# save the memories and disks settings
|
||||
settings["ram"] = self.uiRamSpinBox.value()
|
||||
settings["nvram"] = self.uiNvramSpinBox.value()
|
||||
|
||||
ethernet_adapters = self.uiEthernetAdaptersSpinBox.value()
|
||||
serial_adapters = self.uiSerialAdaptersSpinBox.value()
|
||||
if ethernet_adapters + serial_adapters > 16:
|
||||
QtGui.QMessageBox.warning(self, node.name(), "The total number of adapters cannot exceed 16")
|
||||
raise ConfigurationError()
|
||||
|
||||
node_ports = node.ports()
|
||||
for node_port in node_ports:
|
||||
if not node_port.isFree():
|
||||
QtGui.QMessageBox.critical(self, node.name(), "Changing the number of adapters while links are connected isn't supported yet! Please delete all the links first.")
|
||||
# if (node_port.linkType() == "Ethernet" and node_port.slotNumber() > ethernet_adapters) or \
|
||||
# (node_port.linkType() == "Serial" and node_port.slotNumber() > serial_adapters) and not node_port.isFree():
|
||||
# QtGui.QMessageBox.critical(self, node.name(), "A link is connected to port {} on adapter in slot {}, please remove it first".format(node_port.name(),
|
||||
# node_port.slotNumber()))
|
||||
raise ConfigurationError()
|
||||
|
||||
settings["ethernet_adapters"] = ethernet_adapters
|
||||
settings["serial_adapters"] = serial_adapters
|
||||
220
gns3/modules/vpcs/pages/vpcs_device_preferences_page.py
Normal file
220
gns3/modules/vpcs/pages/vpcs_device_preferences_page.py
Normal file
@@ -0,0 +1,220 @@
|
||||
# -*- 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/>.
|
||||
|
||||
"""
|
||||
Configuration page for IOU image & device preferences.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from gns3.qt import QtGui
|
||||
from gns3.servers import Servers
|
||||
from .. import IOU
|
||||
from ..ui.iou_device_preferences_page_ui import Ui_IOUDevicePreferencesPageWidget
|
||||
|
||||
|
||||
class IOUDevicePreferencesPage(QtGui.QWidget, Ui_IOUDevicePreferencesPageWidget):
|
||||
"""
|
||||
QWidget preference page for IOU image & device preferences.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
QtGui.QWidget.__init__(self)
|
||||
self.setupUi(self)
|
||||
|
||||
self._iou_images = {}
|
||||
|
||||
self.uiSaveIOUImagePushButton.clicked.connect(self._iouImageSaveSlot)
|
||||
self.uiDeleteIOUImagePushButton.clicked.connect(self._iouImageDeleteSlot)
|
||||
self.uiIOUImagesTreeWidget.itemClicked.connect(self._iouImageClickedSlot)
|
||||
self.uiIOUImagesTreeWidget.itemSelectionChanged.connect(self._iouImageChangedSlot)
|
||||
self.uiIOUPathToolButton.clicked.connect(self._iouImageBrowserSlot)
|
||||
self.uiStartupConfigToolButton.clicked.connect(self._startupConfigBrowserSlot)
|
||||
self.uiIOUImageTestSettingsPushButton.clicked.connect(self._testSettingsSlot)
|
||||
|
||||
def _iouImageClickedSlot(self, item, column):
|
||||
"""
|
||||
Loads a selected IOU image from the tree widget.
|
||||
|
||||
:param item: selected QTreeWidgetItem instance
|
||||
:param column: ignored
|
||||
"""
|
||||
|
||||
image = item.text(0)
|
||||
server = item.text(1)
|
||||
key = "{server}:{image}".format(server=server, image=image)
|
||||
iou_image = self._iou_images[key]
|
||||
|
||||
self.uiIOUPathLineEdit.setText(iou_image["path"])
|
||||
self.uiStartupConfigLineEdit.setText(iou_image["startup_config"])
|
||||
self.uiRAMSpinBox.setValue(iou_image["ram"])
|
||||
self.uiNVRAMSpinBox.setValue(iou_image["nvram"])
|
||||
|
||||
def _iouImageChangedSlot(self):
|
||||
"""
|
||||
Enables the use of the delete button.
|
||||
"""
|
||||
|
||||
item = self.uiIOUImagesTreeWidget.currentItem()
|
||||
if item:
|
||||
self.uiDeleteIOUImagePushButton.setEnabled(True)
|
||||
else:
|
||||
self.uiDeleteIOUImagePushButton.setEnabled(False)
|
||||
|
||||
def _iouImageSaveSlot(self):
|
||||
"""
|
||||
Adds/Saves an IOU image.
|
||||
"""
|
||||
|
||||
path = self.uiIOUPathLineEdit.text()
|
||||
startup_config = self.uiStartupConfigLineEdit.text()
|
||||
nvram = self.uiNVRAMSpinBox.value()
|
||||
ram = self.uiRAMSpinBox.value()
|
||||
|
||||
# basename doesn't work on Unix with Windows paths
|
||||
if not sys.platform.startswith('win') and len(path) > 2 and path[1] == ":":
|
||||
import ntpath
|
||||
image = ntpath.basename(path)
|
||||
else:
|
||||
image = os.path.basename(path)
|
||||
|
||||
#TODO: mutiple remote server
|
||||
if IOU.instance().settings()["use_local_server"]:
|
||||
server = "local"
|
||||
else:
|
||||
server = next(iter(Servers.instance()))
|
||||
if not server:
|
||||
QtGui.QMessageBox.critical(self, "IOU image", "No remote server available!")
|
||||
return
|
||||
server = server.host
|
||||
|
||||
key = "{server}:{image}".format(server=server, image=image)
|
||||
item = self.uiIOUImagesTreeWidget.currentItem()
|
||||
|
||||
if key in self._iou_images and item and item.text(0) == image:
|
||||
item.setText(0, image)
|
||||
item.setText(1, server)
|
||||
elif key in self._iou_images:
|
||||
return
|
||||
else:
|
||||
# add a new entry in the tree widget
|
||||
item = QtGui.QTreeWidgetItem(self.uiIOUImagesTreeWidget)
|
||||
item.setText(0, image)
|
||||
item.setText(1, server)
|
||||
self.uiIOUImagesTreeWidget.setCurrentItem(item)
|
||||
|
||||
self._iou_images[key] = {"path": path,
|
||||
"image": image,
|
||||
"startup_config": startup_config,
|
||||
"ram": ram,
|
||||
"nvram": nvram,
|
||||
"server": server}
|
||||
|
||||
self.uiIOUImagesTreeWidget.resizeColumnToContents(0)
|
||||
self.uiIOUImagesTreeWidget.resizeColumnToContents(1)
|
||||
|
||||
def _iouImageDeleteSlot(self):
|
||||
"""
|
||||
Deletes an IOU image.
|
||||
"""
|
||||
|
||||
item = self.uiIOUImagesTreeWidget.currentItem()
|
||||
if item:
|
||||
image = item.text(0)
|
||||
server = item.text(1)
|
||||
key = "{server}:{image}".format(server=server, image=image)
|
||||
del self._iou_images[key]
|
||||
self.uiIOUImagesTreeWidget.takeTopLevelItem(self.uiIOUImagesTreeWidget.indexOfTopLevelItem(item))
|
||||
|
||||
def _iouImageBrowserSlot(self):
|
||||
"""
|
||||
Slot to open a file browser and select an IOU image.
|
||||
"""
|
||||
|
||||
#TODO: current directory for IOU image + filter?
|
||||
path = QtGui.QFileDialog.getOpenFileName(self, "Select an IOU image", ".", "IOU image (*.bin *.image)")
|
||||
if not path:
|
||||
return
|
||||
|
||||
if not os.access(path, os.R_OK):
|
||||
QtGui.QMessageBox.critical(self, "IOU image", "Cannot read {}".format(path))
|
||||
return
|
||||
|
||||
try:
|
||||
with open(path, "rb") as f:
|
||||
# read the first 7 bytes of the file.
|
||||
elf_header_start = f.read(7)
|
||||
except OSError as e:
|
||||
QtGui.QMessageBox.critical(self, "IOU image", "Cannot read ELF magic number: {}".format(e))
|
||||
return
|
||||
|
||||
# file must start with the ELF magic number, be 32-bit, little endian and have an ELF version of 1
|
||||
# normal IOS image are big endian!
|
||||
if elf_header_start != b'\x7fELF\x01\x01\x01':
|
||||
QtGui.QMessageBox.critical(self, "IOU image", "Sorry, this is not a valid IOU image!")
|
||||
return
|
||||
|
||||
self.uiIOUPathLineEdit.clear()
|
||||
self.uiIOUPathLineEdit.setText(path)
|
||||
self.uiRAMSpinBox.setValue(256)
|
||||
self.uiNVRAMSpinBox.setValue(128)
|
||||
|
||||
def _startupConfigBrowserSlot(self):
|
||||
"""
|
||||
Slot to open a file browser and select a startup-config file.
|
||||
"""
|
||||
|
||||
#TODO: current directory for startup-config + filter?
|
||||
path = QtGui.QFileDialog.getOpenFileName(self, "Select a startup configuration", ".")
|
||||
if not path:
|
||||
return
|
||||
|
||||
if not os.access(path, os.R_OK):
|
||||
QtGui.QMessageBox.critical(self, "Startup configuration", "Cannot read {}".format(path))
|
||||
return
|
||||
|
||||
self.uiStartupConfigLineEdit.clear()
|
||||
self.uiStartupConfigLineEdit.setText(path)
|
||||
|
||||
def _testSettingsSlot(self):
|
||||
|
||||
QtGui.QMessageBox.critical(self, "Test settings", "Sorry, not yet implemented!")
|
||||
|
||||
def loadPreferences(self):
|
||||
"""
|
||||
Loads the IOU image & device preferences.
|
||||
"""
|
||||
|
||||
self._iou_images.clear()
|
||||
self.uiIOUImagesTreeWidget.clear()
|
||||
|
||||
iou_images = IOU.instance().iouImages()
|
||||
for iou_image in iou_images.values():
|
||||
item = QtGui.QTreeWidgetItem(self.uiIOUImagesTreeWidget)
|
||||
item.setText(0, iou_image["image"])
|
||||
item.setText(1, iou_image["server"])
|
||||
|
||||
self.uiIOUImagesTreeWidget.resizeColumnToContents(0)
|
||||
self.uiIOUImagesTreeWidget.resizeColumnToContents(1)
|
||||
self._iou_images.update(iou_images)
|
||||
|
||||
def savePreferences(self):
|
||||
"""
|
||||
Saves the IOU image & device preferences.
|
||||
"""
|
||||
|
||||
IOU.instance().setIOUImages(self._iou_images)
|
||||
204
gns3/modules/vpcs/pages/vpcs_preferences_page.py
Normal file
204
gns3/modules/vpcs/pages/vpcs_preferences_page.py
Normal file
@@ -0,0 +1,204 @@
|
||||
# -*- 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/>.
|
||||
|
||||
"""
|
||||
Configuration page for IOU preferences.
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
from gns3.qt import QtCore, QtGui
|
||||
from gns3.servers import Servers
|
||||
from .. import IOU
|
||||
from ..ui.iou_preferences_page_ui import Ui_IOUPreferencesPageWidget
|
||||
from ..settings import IOU_SETTINGS
|
||||
|
||||
|
||||
class IOUPreferencesPage(QtGui.QWidget, Ui_IOUPreferencesPageWidget):
|
||||
"""
|
||||
QWidget preference page for IOU.
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
|
||||
QtGui.QWidget.__init__(self)
|
||||
self.setupUi(self)
|
||||
|
||||
if not sys.platform.startswith("linux"):
|
||||
self.uiIouyapPathLineEdit.setEnabled(False)
|
||||
self.uiIouyapPathToolButton.setEnabled(False)
|
||||
self.uiUseLocalServercheckBox.setEnabled(False)
|
||||
|
||||
# connect signals
|
||||
self.uiIOURCPathToolButton.clicked.connect(self._iourcPathBrowserSlot)
|
||||
self.uiIouyapPathToolButton.clicked.connect(self._iouyapPathBrowserSlot)
|
||||
self.uiRestoreDefaultsPushButton.clicked.connect(self._restoreDefaultsSlot)
|
||||
self.uiUseLocalServercheckBox.stateChanged.connect(self._useLocalServerSlot)
|
||||
self.uiTestSettingsPushButton.clicked.connect(self._testSettingsSlot)
|
||||
|
||||
def _iourcPathBrowserSlot(self):
|
||||
"""
|
||||
Slot to open a file browser and select an iourc file
|
||||
"""
|
||||
|
||||
path = QtGui.QFileDialog.getOpenFileName(self, "Select the IOURC file", ".")
|
||||
if not path:
|
||||
return
|
||||
|
||||
if not os.access(path, os.R_OK):
|
||||
QtGui.QMessageBox.critical(self, "IOURC file", "{} cannot be read".format(os.path.basename(path)))
|
||||
return
|
||||
|
||||
self.uiIOURCPathLineEdit.setText(os.path.normpath(path))
|
||||
|
||||
def _iouyapPathBrowserSlot(self):
|
||||
"""
|
||||
Slot to open a file browser and select iouyap.
|
||||
"""
|
||||
|
||||
path = QtGui.QFileDialog.getOpenFileName(self, "Select iouyap", ".")
|
||||
if not path:
|
||||
return
|
||||
|
||||
if not os.access(path, os.X_OK):
|
||||
QtGui.QMessageBox.critical(self, "iouyap", "{} is not an executable".format(os.path.basename(path)))
|
||||
return
|
||||
|
||||
self.uiIouyapPathLineEdit.setText(os.path.normpath(path))
|
||||
|
||||
def _testSettingsSlot(self):
|
||||
|
||||
QtGui.QMessageBox.critical(self, "Test settings", "Sorry, not yet implemented!")
|
||||
return
|
||||
|
||||
servers = Servers.instance()
|
||||
if self.uiUseLocalServercheckBox.isChecked():
|
||||
server = servers.localServer()
|
||||
else:
|
||||
QtGui.QMessageBox.critical(self, "Test settings", "Sorry, not yet implemented!")
|
||||
|
||||
try:
|
||||
if not server.connected():
|
||||
server.reconnect()
|
||||
except OSError as e:
|
||||
QtGui.QMessageBox.critical(self, "Local server", "Could not connect to the local server {host} on port {port}: {error}".format(host=server.host,
|
||||
port=server.port,
|
||||
error=e))
|
||||
|
||||
self._progress_dialog = QtGui.QProgressDialog("Testing settings...", "Cancel", 0, 0, parent=self)
|
||||
self._progress_dialog.setWindowModality(QtCore.Qt.WindowModal)
|
||||
self._progress_dialog.setWindowTitle("Settings")
|
||||
self._progress_dialog.show()
|
||||
|
||||
iou_module = IOU.instance()
|
||||
if server not in iou_module.servers():
|
||||
server_added = True
|
||||
iou_module.addServer(server)
|
||||
self.savePreferences()
|
||||
if server_added:
|
||||
iou_module.removeServer(server)
|
||||
server.send_message("iou.test_settings", None, self._testSettingsCallback)
|
||||
|
||||
def _testSettingsCallback(self, result, error=False):
|
||||
|
||||
if self._progress_dialog.wasCanceled():
|
||||
print("Was canceled")
|
||||
return
|
||||
|
||||
self._progress_dialog.accept()
|
||||
|
||||
if error:
|
||||
pass
|
||||
#log.error("error while allocating an UDP port for {}: {}".format(self.name(), result["message"]))
|
||||
|
||||
print("Report received")
|
||||
print(result)
|
||||
|
||||
def _restoreDefaultsSlot(self):
|
||||
"""
|
||||
Slot to populate the page widgets with the default settings.
|
||||
"""
|
||||
|
||||
self._populateWidgets(IOU_SETTINGS)
|
||||
|
||||
def _useLocalServerSlot(self, state):
|
||||
"""
|
||||
Slot to enable or not the QTreeWidget for remote servers.
|
||||
"""
|
||||
|
||||
if state:
|
||||
self.uiRemoteServersTreeWidget.setEnabled(False)
|
||||
else:
|
||||
self.uiRemoteServersTreeWidget.setEnabled(True)
|
||||
|
||||
def _populateWidgets(self, settings):
|
||||
"""
|
||||
Populates the widgets with the settings.
|
||||
|
||||
:param settings: IOU settings
|
||||
"""
|
||||
|
||||
self.uiIOURCPathLineEdit.setText(settings["iourc"])
|
||||
self.uiIouyapPathLineEdit.setText(settings["iouyap"])
|
||||
self.uiUseLocalServercheckBox.setChecked(settings["use_local_server"])
|
||||
self.uiConsoleStartPortSpinBox.setValue(settings["console_start_port_range"])
|
||||
self.uiConsoleEndPortSpinBox.setValue(settings["console_end_port_range"])
|
||||
self.uiUDPStartPortSpinBox.setValue(settings["udp_start_port_range"])
|
||||
self.uiUDPEndPortSpinBox.setValue(settings["udp_end_port_range"])
|
||||
|
||||
def _updateRemoteServersSlot(self):
|
||||
"""
|
||||
Adds/Updates the available remote servers.
|
||||
"""
|
||||
|
||||
servers = Servers.instance()
|
||||
self.uiRemoteServersTreeWidget.clear()
|
||||
for server in servers.remoteServers().values():
|
||||
host = server.host
|
||||
port = server.port
|
||||
item = QtGui.QTreeWidgetItem(self.uiRemoteServersTreeWidget)
|
||||
item.setText(0, host)
|
||||
item.setText(1, str(port))
|
||||
|
||||
self.uiRemoteServersTreeWidget.resizeColumnToContents(0)
|
||||
|
||||
def loadPreferences(self):
|
||||
"""
|
||||
Loads IOU preferences.
|
||||
"""
|
||||
|
||||
iou_settings = IOU.instance().settings()
|
||||
self._populateWidgets(iou_settings)
|
||||
|
||||
servers = Servers.instance()
|
||||
servers.updated_signal.connect(self._updateRemoteServersSlot)
|
||||
self._updateRemoteServersSlot()
|
||||
|
||||
def savePreferences(self):
|
||||
"""
|
||||
Saves IOU preferences.
|
||||
"""
|
||||
|
||||
new_settings = {}
|
||||
new_settings["iourc"] = self.uiIOURCPathLineEdit.text()
|
||||
new_settings["iouyap"] = self.uiIouyapPathLineEdit.text()
|
||||
new_settings["use_local_server"] = self.uiUseLocalServercheckBox.isChecked()
|
||||
new_settings["console_start_port_range"] = self.uiConsoleStartPortSpinBox.value()
|
||||
new_settings["console_end_port_range"] = self.uiConsoleEndPortSpinBox.value()
|
||||
new_settings["udp_start_port_range"] = self.uiUDPStartPortSpinBox.value()
|
||||
new_settings["udp_end_port_range"] = self.uiUDPEndPortSpinBox.value()
|
||||
IOU.instance().setSettings(new_settings)
|
||||
46
gns3/modules/vpcs/settings.py
Normal file
46
gns3/modules/vpcs/settings.py
Normal file
@@ -0,0 +1,46 @@
|
||||
# -*- 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/>.
|
||||
|
||||
import sys
|
||||
|
||||
"""
|
||||
Default IOU settings.
|
||||
"""
|
||||
|
||||
IOU_SETTINGS = {
|
||||
"iourc": "",
|
||||
"iouyap": "",
|
||||
"console_start_port_range": 4001,
|
||||
"console_end_port_range": 4512,
|
||||
"udp_start_port_range": 30001,
|
||||
"udp_end_port_range": 40000,
|
||||
"use_local_server": True,
|
||||
}
|
||||
|
||||
# IOU is only available on Linux
|
||||
if not sys.platform.startswith("linux"):
|
||||
IOU_SETTINGS["use_local_server"] = False
|
||||
|
||||
IOU_SETTING_TYPES = {
|
||||
"iourc": str,
|
||||
"iouyap": str,
|
||||
"console_start_port_range": int,
|
||||
"console_end_port_range": int,
|
||||
"udp_start_port_range": int,
|
||||
"udp_end_port_range": int,
|
||||
"use_local_server": bool,
|
||||
}
|
||||
0
gns3/modules/vpcs/ui/__init__.py
Normal file
0
gns3/modules/vpcs/ui/__init__.py
Normal file
196
gns3/modules/vpcs/ui/vpcs_device_configuration_page.ui
Executable file
196
gns3/modules/vpcs/ui/vpcs_device_configuration_page.ui
Executable file
@@ -0,0 +1,196 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>iouDeviceConfigPageWidget</class>
|
||||
<widget class="QWidget" name="iouDeviceConfigPageWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>403</width>
|
||||
<height>461</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>IOU device configuration</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="uiNameLabel">
|
||||
<property name="text">
|
||||
<string>Name:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="uiNameLineEdit"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="uiIOUImageLabel">
|
||||
<property name="text">
|
||||
<string>IOU image:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QComboBox" name="uiIOUImageComboBox"/>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="uiStartupConfigLabel">
|
||||
<property name="text">
|
||||
<string>Startup-config:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="uiStartupConfigLineEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="uiStartupConfigToolButton">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextOnly</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="uiConsolePortLabel">
|
||||
<property name="text">
|
||||
<string>Console port:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QSpinBox" name="uiConsolePortSpinBox">
|
||||
<property name="maximum">
|
||||
<number>65535</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="uiRamLabel">
|
||||
<property name="text">
|
||||
<string>RAM size:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QSpinBox" name="uiRamSpinBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> MiB</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>4096</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>128</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QLabel" name="uiNvramLabel">
|
||||
<property name="text">
|
||||
<string>NVRAM size:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="1">
|
||||
<widget class="QSpinBox" name="uiNvramSpinBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string> KiB</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>4096</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>4</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>128</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QLabel" name="uiEthernetAdaptersLabel">
|
||||
<property name="text">
|
||||
<string>Ethernet adapters:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<widget class="QSpinBox" name="uiEthernetAdaptersSpinBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>2</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<widget class="QLabel" name="uiSerialAdaptersLabel">
|
||||
<property name="text">
|
||||
<string>Serial adapters:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="1">
|
||||
<widget class="QSpinBox" name="uiSerialAdaptersSpinBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>2</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="1">
|
||||
<spacer name="spacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>263</width>
|
||||
<height>212</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
137
gns3/modules/vpcs/ui/vpcs_device_configuration_page_ui.py
Normal file
137
gns3/modules/vpcs/ui/vpcs_device_configuration_page_ui.py
Normal file
@@ -0,0 +1,137 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file '/home/grossmj/workspace/git/gns3-gui/gns3/modules/iou/ui/iou_device_configuration_page.ui'
|
||||
#
|
||||
# Created: Fri Mar 21 10:37:58 2014
|
||||
# by: PyQt4 UI code generator 4.10
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
try:
|
||||
_fromUtf8 = QtCore.QString.fromUtf8
|
||||
except AttributeError:
|
||||
def _fromUtf8(s):
|
||||
return s
|
||||
|
||||
try:
|
||||
_encoding = QtGui.QApplication.UnicodeUTF8
|
||||
def _translate(context, text, disambig):
|
||||
return QtGui.QApplication.translate(context, text, disambig, _encoding)
|
||||
except AttributeError:
|
||||
def _translate(context, text, disambig):
|
||||
return QtGui.QApplication.translate(context, text, disambig)
|
||||
|
||||
class Ui_iouDeviceConfigPageWidget(object):
|
||||
def setupUi(self, iouDeviceConfigPageWidget):
|
||||
iouDeviceConfigPageWidget.setObjectName(_fromUtf8("iouDeviceConfigPageWidget"))
|
||||
iouDeviceConfigPageWidget.resize(403, 461)
|
||||
self.gridLayout = QtGui.QGridLayout(iouDeviceConfigPageWidget)
|
||||
self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
|
||||
self.uiNameLabel = QtGui.QLabel(iouDeviceConfigPageWidget)
|
||||
self.uiNameLabel.setObjectName(_fromUtf8("uiNameLabel"))
|
||||
self.gridLayout.addWidget(self.uiNameLabel, 0, 0, 1, 1)
|
||||
self.uiNameLineEdit = QtGui.QLineEdit(iouDeviceConfigPageWidget)
|
||||
self.uiNameLineEdit.setObjectName(_fromUtf8("uiNameLineEdit"))
|
||||
self.gridLayout.addWidget(self.uiNameLineEdit, 0, 1, 1, 1)
|
||||
self.uiIOUImageLabel = QtGui.QLabel(iouDeviceConfigPageWidget)
|
||||
self.uiIOUImageLabel.setObjectName(_fromUtf8("uiIOUImageLabel"))
|
||||
self.gridLayout.addWidget(self.uiIOUImageLabel, 1, 0, 1, 1)
|
||||
self.uiIOUImageComboBox = QtGui.QComboBox(iouDeviceConfigPageWidget)
|
||||
self.uiIOUImageComboBox.setObjectName(_fromUtf8("uiIOUImageComboBox"))
|
||||
self.gridLayout.addWidget(self.uiIOUImageComboBox, 1, 1, 1, 1)
|
||||
self.uiStartupConfigLabel = QtGui.QLabel(iouDeviceConfigPageWidget)
|
||||
self.uiStartupConfigLabel.setObjectName(_fromUtf8("uiStartupConfigLabel"))
|
||||
self.gridLayout.addWidget(self.uiStartupConfigLabel, 2, 0, 1, 1)
|
||||
self.horizontalLayout_4 = QtGui.QHBoxLayout()
|
||||
self.horizontalLayout_4.setObjectName(_fromUtf8("horizontalLayout_4"))
|
||||
self.uiStartupConfigLineEdit = QtGui.QLineEdit(iouDeviceConfigPageWidget)
|
||||
self.uiStartupConfigLineEdit.setObjectName(_fromUtf8("uiStartupConfigLineEdit"))
|
||||
self.horizontalLayout_4.addWidget(self.uiStartupConfigLineEdit)
|
||||
self.uiStartupConfigToolButton = QtGui.QToolButton(iouDeviceConfigPageWidget)
|
||||
self.uiStartupConfigToolButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextOnly)
|
||||
self.uiStartupConfigToolButton.setObjectName(_fromUtf8("uiStartupConfigToolButton"))
|
||||
self.horizontalLayout_4.addWidget(self.uiStartupConfigToolButton)
|
||||
self.gridLayout.addLayout(self.horizontalLayout_4, 2, 1, 1, 1)
|
||||
self.uiConsolePortLabel = QtGui.QLabel(iouDeviceConfigPageWidget)
|
||||
self.uiConsolePortLabel.setObjectName(_fromUtf8("uiConsolePortLabel"))
|
||||
self.gridLayout.addWidget(self.uiConsolePortLabel, 3, 0, 1, 1)
|
||||
self.uiConsolePortSpinBox = QtGui.QSpinBox(iouDeviceConfigPageWidget)
|
||||
self.uiConsolePortSpinBox.setMaximum(65535)
|
||||
self.uiConsolePortSpinBox.setObjectName(_fromUtf8("uiConsolePortSpinBox"))
|
||||
self.gridLayout.addWidget(self.uiConsolePortSpinBox, 3, 1, 1, 1)
|
||||
self.uiRamLabel = QtGui.QLabel(iouDeviceConfigPageWidget)
|
||||
self.uiRamLabel.setObjectName(_fromUtf8("uiRamLabel"))
|
||||
self.gridLayout.addWidget(self.uiRamLabel, 4, 0, 1, 1)
|
||||
self.uiRamSpinBox = QtGui.QSpinBox(iouDeviceConfigPageWidget)
|
||||
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.uiRamSpinBox.sizePolicy().hasHeightForWidth())
|
||||
self.uiRamSpinBox.setSizePolicy(sizePolicy)
|
||||
self.uiRamSpinBox.setMaximum(4096)
|
||||
self.uiRamSpinBox.setSingleStep(4)
|
||||
self.uiRamSpinBox.setProperty("value", 128)
|
||||
self.uiRamSpinBox.setObjectName(_fromUtf8("uiRamSpinBox"))
|
||||
self.gridLayout.addWidget(self.uiRamSpinBox, 4, 1, 1, 1)
|
||||
self.uiNvramLabel = QtGui.QLabel(iouDeviceConfigPageWidget)
|
||||
self.uiNvramLabel.setObjectName(_fromUtf8("uiNvramLabel"))
|
||||
self.gridLayout.addWidget(self.uiNvramLabel, 5, 0, 1, 1)
|
||||
self.uiNvramSpinBox = QtGui.QSpinBox(iouDeviceConfigPageWidget)
|
||||
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.uiNvramSpinBox.sizePolicy().hasHeightForWidth())
|
||||
self.uiNvramSpinBox.setSizePolicy(sizePolicy)
|
||||
self.uiNvramSpinBox.setMaximum(4096)
|
||||
self.uiNvramSpinBox.setSingleStep(4)
|
||||
self.uiNvramSpinBox.setProperty("value", 128)
|
||||
self.uiNvramSpinBox.setObjectName(_fromUtf8("uiNvramSpinBox"))
|
||||
self.gridLayout.addWidget(self.uiNvramSpinBox, 5, 1, 1, 1)
|
||||
self.uiEthernetAdaptersLabel = QtGui.QLabel(iouDeviceConfigPageWidget)
|
||||
self.uiEthernetAdaptersLabel.setObjectName(_fromUtf8("uiEthernetAdaptersLabel"))
|
||||
self.gridLayout.addWidget(self.uiEthernetAdaptersLabel, 6, 0, 1, 1)
|
||||
self.uiEthernetAdaptersSpinBox = QtGui.QSpinBox(iouDeviceConfigPageWidget)
|
||||
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.uiEthernetAdaptersSpinBox.sizePolicy().hasHeightForWidth())
|
||||
self.uiEthernetAdaptersSpinBox.setSizePolicy(sizePolicy)
|
||||
self.uiEthernetAdaptersSpinBox.setMaximum(16)
|
||||
self.uiEthernetAdaptersSpinBox.setSingleStep(2)
|
||||
self.uiEthernetAdaptersSpinBox.setObjectName(_fromUtf8("uiEthernetAdaptersSpinBox"))
|
||||
self.gridLayout.addWidget(self.uiEthernetAdaptersSpinBox, 6, 1, 1, 1)
|
||||
self.uiSerialAdaptersLabel = QtGui.QLabel(iouDeviceConfigPageWidget)
|
||||
self.uiSerialAdaptersLabel.setObjectName(_fromUtf8("uiSerialAdaptersLabel"))
|
||||
self.gridLayout.addWidget(self.uiSerialAdaptersLabel, 7, 0, 1, 1)
|
||||
self.uiSerialAdaptersSpinBox = QtGui.QSpinBox(iouDeviceConfigPageWidget)
|
||||
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.uiSerialAdaptersSpinBox.sizePolicy().hasHeightForWidth())
|
||||
self.uiSerialAdaptersSpinBox.setSizePolicy(sizePolicy)
|
||||
self.uiSerialAdaptersSpinBox.setMaximum(16)
|
||||
self.uiSerialAdaptersSpinBox.setSingleStep(2)
|
||||
self.uiSerialAdaptersSpinBox.setObjectName(_fromUtf8("uiSerialAdaptersSpinBox"))
|
||||
self.gridLayout.addWidget(self.uiSerialAdaptersSpinBox, 7, 1, 1, 1)
|
||||
spacerItem = QtGui.QSpacerItem(263, 212, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
|
||||
self.gridLayout.addItem(spacerItem, 8, 1, 1, 1)
|
||||
|
||||
self.retranslateUi(iouDeviceConfigPageWidget)
|
||||
QtCore.QMetaObject.connectSlotsByName(iouDeviceConfigPageWidget)
|
||||
|
||||
def retranslateUi(self, iouDeviceConfigPageWidget):
|
||||
iouDeviceConfigPageWidget.setWindowTitle(_translate("iouDeviceConfigPageWidget", "IOU device configuration", None))
|
||||
self.uiNameLabel.setText(_translate("iouDeviceConfigPageWidget", "Name:", None))
|
||||
self.uiIOUImageLabel.setText(_translate("iouDeviceConfigPageWidget", "IOU image:", None))
|
||||
self.uiStartupConfigLabel.setText(_translate("iouDeviceConfigPageWidget", "Startup-config:", None))
|
||||
self.uiStartupConfigToolButton.setText(_translate("iouDeviceConfigPageWidget", "...", None))
|
||||
self.uiConsolePortLabel.setText(_translate("iouDeviceConfigPageWidget", "Console port:", None))
|
||||
self.uiRamLabel.setText(_translate("iouDeviceConfigPageWidget", "RAM size:", None))
|
||||
self.uiRamSpinBox.setSuffix(_translate("iouDeviceConfigPageWidget", " MiB", None))
|
||||
self.uiNvramLabel.setText(_translate("iouDeviceConfigPageWidget", "NVRAM size:", None))
|
||||
self.uiNvramSpinBox.setSuffix(_translate("iouDeviceConfigPageWidget", " KiB", None))
|
||||
self.uiEthernetAdaptersLabel.setText(_translate("iouDeviceConfigPageWidget", "Ethernet adapters:", None))
|
||||
self.uiSerialAdaptersLabel.setText(_translate("iouDeviceConfigPageWidget", "Serial adapters:", None))
|
||||
|
||||
275
gns3/modules/vpcs/ui/vpcs_device_preferences_page.ui
Executable file
275
gns3/modules/vpcs/ui/vpcs_device_preferences_page.ui
Executable file
@@ -0,0 +1,275 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>IOUDevicePreferencesPageWidget</class>
|
||||
<widget class="QWidget" name="IOUDevicePreferencesPageWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>404</width>
|
||||
<height>487</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>IOU devices</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="uiTabWidget">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="uiIOUDeviceTabWidget">
|
||||
<attribute name="title">
|
||||
<string>IOU images</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="2" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QPushButton" name="uiIOUImageTestSettingsPushButton">
|
||||
<property name="text">
|
||||
<string>Test settings</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="uiSaveIOUImagePushButton">
|
||||
<property name="text">
|
||||
<string>Save</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="uiDeleteIOUImagePushButton">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Delete</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>76</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="1" column="0" colspan="2">
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>Settings</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="uiIOUPathLabel">
|
||||
<property name="text">
|
||||
<string>IOU path:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="uiIOUPathLineEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="uiIOUPathToolButton">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextOnly</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="uiStartupConfigLabel">
|
||||
<property name="text">
|
||||
<string>Startup-config:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="uiStartupConfigLineEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="uiStartupConfigToolButton">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextOnly</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="uiNVRAMLabel">
|
||||
<property name="text">
|
||||
<string>NVRAM:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QSpinBox" name="uiNVRAMSpinBox">
|
||||
<property name="suffix">
|
||||
<string> KB</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65535</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>128</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<widget class="QLabel" name="uiRAMLabel">
|
||||
<property name="text">
|
||||
<string>RAM:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QSpinBox" name="uiRAMSpinBox">
|
||||
<property name="suffix">
|
||||
<string> MB</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>16</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65535</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>256</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0" colspan="2">
|
||||
<widget class="QTreeWidget" name="uiIOUImagesTreeWidget">
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>File</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Server</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="uiIOSRoutersTabWidget">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<attribute name="title">
|
||||
<string>IOU devices</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0" rowspan="2">
|
||||
<widget class="QTreeWidget" name="treeWidget_2">
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>IOU device</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>IOU file</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_3">
|
||||
<property name="text">
|
||||
<string>New</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_4">
|
||||
<property name="text">
|
||||
<string>Edit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton_5">
|
||||
<property name="text">
|
||||
<string>Delete</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>354</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
<designerdata>
|
||||
<property name="gridDeltaX">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="gridDeltaY">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="gridSnapX">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="gridSnapY">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="gridVisible">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</designerdata>
|
||||
</ui>
|
||||
159
gns3/modules/vpcs/ui/vpcs_device_preferences_page_ui.py
Normal file
159
gns3/modules/vpcs/ui/vpcs_device_preferences_page_ui.py
Normal file
@@ -0,0 +1,159 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file '/home/grossmj/workspace/git/gns3-gui/gns3/modules/iou/ui/iou_device_preferences_page.ui'
|
||||
#
|
||||
# Created: Sat Apr 12 14:54:36 2014
|
||||
# by: PyQt4 UI code generator 4.10
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
try:
|
||||
_fromUtf8 = QtCore.QString.fromUtf8
|
||||
except AttributeError:
|
||||
def _fromUtf8(s):
|
||||
return s
|
||||
|
||||
try:
|
||||
_encoding = QtGui.QApplication.UnicodeUTF8
|
||||
def _translate(context, text, disambig):
|
||||
return QtGui.QApplication.translate(context, text, disambig, _encoding)
|
||||
except AttributeError:
|
||||
def _translate(context, text, disambig):
|
||||
return QtGui.QApplication.translate(context, text, disambig)
|
||||
|
||||
class Ui_IOUDevicePreferencesPageWidget(object):
|
||||
def setupUi(self, IOUDevicePreferencesPageWidget):
|
||||
IOUDevicePreferencesPageWidget.setObjectName(_fromUtf8("IOUDevicePreferencesPageWidget"))
|
||||
IOUDevicePreferencesPageWidget.resize(404, 487)
|
||||
self.vboxlayout = QtGui.QVBoxLayout(IOUDevicePreferencesPageWidget)
|
||||
self.vboxlayout.setObjectName(_fromUtf8("vboxlayout"))
|
||||
self.uiTabWidget = QtGui.QTabWidget(IOUDevicePreferencesPageWidget)
|
||||
self.uiTabWidget.setEnabled(True)
|
||||
self.uiTabWidget.setObjectName(_fromUtf8("uiTabWidget"))
|
||||
self.uiIOUDeviceTabWidget = QtGui.QWidget()
|
||||
self.uiIOUDeviceTabWidget.setObjectName(_fromUtf8("uiIOUDeviceTabWidget"))
|
||||
self.gridLayout_3 = QtGui.QGridLayout(self.uiIOUDeviceTabWidget)
|
||||
self.gridLayout_3.setObjectName(_fromUtf8("gridLayout_3"))
|
||||
self.horizontalLayout_5 = QtGui.QHBoxLayout()
|
||||
self.horizontalLayout_5.setObjectName(_fromUtf8("horizontalLayout_5"))
|
||||
self.uiIOUImageTestSettingsPushButton = QtGui.QPushButton(self.uiIOUDeviceTabWidget)
|
||||
self.uiIOUImageTestSettingsPushButton.setObjectName(_fromUtf8("uiIOUImageTestSettingsPushButton"))
|
||||
self.horizontalLayout_5.addWidget(self.uiIOUImageTestSettingsPushButton)
|
||||
self.uiSaveIOUImagePushButton = QtGui.QPushButton(self.uiIOUDeviceTabWidget)
|
||||
self.uiSaveIOUImagePushButton.setObjectName(_fromUtf8("uiSaveIOUImagePushButton"))
|
||||
self.horizontalLayout_5.addWidget(self.uiSaveIOUImagePushButton)
|
||||
self.uiDeleteIOUImagePushButton = QtGui.QPushButton(self.uiIOUDeviceTabWidget)
|
||||
self.uiDeleteIOUImagePushButton.setEnabled(False)
|
||||
self.uiDeleteIOUImagePushButton.setObjectName(_fromUtf8("uiDeleteIOUImagePushButton"))
|
||||
self.horizontalLayout_5.addWidget(self.uiDeleteIOUImagePushButton)
|
||||
self.gridLayout_3.addLayout(self.horizontalLayout_5, 2, 0, 1, 1)
|
||||
spacerItem = QtGui.QSpacerItem(76, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
|
||||
self.gridLayout_3.addItem(spacerItem, 2, 1, 1, 1)
|
||||
self.groupBox = QtGui.QGroupBox(self.uiIOUDeviceTabWidget)
|
||||
self.groupBox.setObjectName(_fromUtf8("groupBox"))
|
||||
self.gridLayout_2 = QtGui.QGridLayout(self.groupBox)
|
||||
self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2"))
|
||||
self.uiIOUPathLabel = QtGui.QLabel(self.groupBox)
|
||||
self.uiIOUPathLabel.setObjectName(_fromUtf8("uiIOUPathLabel"))
|
||||
self.gridLayout_2.addWidget(self.uiIOUPathLabel, 0, 0, 1, 1)
|
||||
self.horizontalLayout_3 = QtGui.QHBoxLayout()
|
||||
self.horizontalLayout_3.setObjectName(_fromUtf8("horizontalLayout_3"))
|
||||
self.uiIOUPathLineEdit = QtGui.QLineEdit(self.groupBox)
|
||||
self.uiIOUPathLineEdit.setObjectName(_fromUtf8("uiIOUPathLineEdit"))
|
||||
self.horizontalLayout_3.addWidget(self.uiIOUPathLineEdit)
|
||||
self.uiIOUPathToolButton = QtGui.QToolButton(self.groupBox)
|
||||
self.uiIOUPathToolButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextOnly)
|
||||
self.uiIOUPathToolButton.setObjectName(_fromUtf8("uiIOUPathToolButton"))
|
||||
self.horizontalLayout_3.addWidget(self.uiIOUPathToolButton)
|
||||
self.gridLayout_2.addLayout(self.horizontalLayout_3, 0, 1, 1, 1)
|
||||
self.uiStartupConfigLabel = QtGui.QLabel(self.groupBox)
|
||||
self.uiStartupConfigLabel.setObjectName(_fromUtf8("uiStartupConfigLabel"))
|
||||
self.gridLayout_2.addWidget(self.uiStartupConfigLabel, 1, 0, 1, 1)
|
||||
self.horizontalLayout_4 = QtGui.QHBoxLayout()
|
||||
self.horizontalLayout_4.setObjectName(_fromUtf8("horizontalLayout_4"))
|
||||
self.uiStartupConfigLineEdit = QtGui.QLineEdit(self.groupBox)
|
||||
self.uiStartupConfigLineEdit.setObjectName(_fromUtf8("uiStartupConfigLineEdit"))
|
||||
self.horizontalLayout_4.addWidget(self.uiStartupConfigLineEdit)
|
||||
self.uiStartupConfigToolButton = QtGui.QToolButton(self.groupBox)
|
||||
self.uiStartupConfigToolButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextOnly)
|
||||
self.uiStartupConfigToolButton.setObjectName(_fromUtf8("uiStartupConfigToolButton"))
|
||||
self.horizontalLayout_4.addWidget(self.uiStartupConfigToolButton)
|
||||
self.gridLayout_2.addLayout(self.horizontalLayout_4, 1, 1, 1, 1)
|
||||
self.uiNVRAMLabel = QtGui.QLabel(self.groupBox)
|
||||
self.uiNVRAMLabel.setObjectName(_fromUtf8("uiNVRAMLabel"))
|
||||
self.gridLayout_2.addWidget(self.uiNVRAMLabel, 2, 0, 1, 1)
|
||||
self.uiNVRAMSpinBox = QtGui.QSpinBox(self.groupBox)
|
||||
self.uiNVRAMSpinBox.setMinimum(16)
|
||||
self.uiNVRAMSpinBox.setMaximum(65535)
|
||||
self.uiNVRAMSpinBox.setProperty("value", 128)
|
||||
self.uiNVRAMSpinBox.setObjectName(_fromUtf8("uiNVRAMSpinBox"))
|
||||
self.gridLayout_2.addWidget(self.uiNVRAMSpinBox, 2, 1, 1, 1)
|
||||
self.uiRAMLabel = QtGui.QLabel(self.groupBox)
|
||||
self.uiRAMLabel.setObjectName(_fromUtf8("uiRAMLabel"))
|
||||
self.gridLayout_2.addWidget(self.uiRAMLabel, 3, 0, 1, 1)
|
||||
self.uiRAMSpinBox = QtGui.QSpinBox(self.groupBox)
|
||||
self.uiRAMSpinBox.setMinimum(16)
|
||||
self.uiRAMSpinBox.setMaximum(65535)
|
||||
self.uiRAMSpinBox.setProperty("value", 256)
|
||||
self.uiRAMSpinBox.setObjectName(_fromUtf8("uiRAMSpinBox"))
|
||||
self.gridLayout_2.addWidget(self.uiRAMSpinBox, 3, 1, 1, 1)
|
||||
self.gridLayout_3.addWidget(self.groupBox, 1, 0, 1, 2)
|
||||
self.uiIOUImagesTreeWidget = QtGui.QTreeWidget(self.uiIOUDeviceTabWidget)
|
||||
self.uiIOUImagesTreeWidget.setObjectName(_fromUtf8("uiIOUImagesTreeWidget"))
|
||||
self.gridLayout_3.addWidget(self.uiIOUImagesTreeWidget, 0, 0, 1, 2)
|
||||
self.uiTabWidget.addTab(self.uiIOUDeviceTabWidget, _fromUtf8(""))
|
||||
self.uiIOSRoutersTabWidget = QtGui.QWidget()
|
||||
self.uiIOSRoutersTabWidget.setEnabled(False)
|
||||
self.uiIOSRoutersTabWidget.setObjectName(_fromUtf8("uiIOSRoutersTabWidget"))
|
||||
self.gridLayout = QtGui.QGridLayout(self.uiIOSRoutersTabWidget)
|
||||
self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
|
||||
self.treeWidget_2 = QtGui.QTreeWidget(self.uiIOSRoutersTabWidget)
|
||||
self.treeWidget_2.setObjectName(_fromUtf8("treeWidget_2"))
|
||||
self.gridLayout.addWidget(self.treeWidget_2, 0, 0, 2, 1)
|
||||
self.verticalLayout = QtGui.QVBoxLayout()
|
||||
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
|
||||
self.pushButton_3 = QtGui.QPushButton(self.uiIOSRoutersTabWidget)
|
||||
self.pushButton_3.setObjectName(_fromUtf8("pushButton_3"))
|
||||
self.verticalLayout.addWidget(self.pushButton_3)
|
||||
self.pushButton_4 = QtGui.QPushButton(self.uiIOSRoutersTabWidget)
|
||||
self.pushButton_4.setObjectName(_fromUtf8("pushButton_4"))
|
||||
self.verticalLayout.addWidget(self.pushButton_4)
|
||||
self.pushButton_5 = QtGui.QPushButton(self.uiIOSRoutersTabWidget)
|
||||
self.pushButton_5.setObjectName(_fromUtf8("pushButton_5"))
|
||||
self.verticalLayout.addWidget(self.pushButton_5)
|
||||
self.gridLayout.addLayout(self.verticalLayout, 0, 1, 1, 1)
|
||||
spacerItem1 = QtGui.QSpacerItem(20, 354, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
|
||||
self.gridLayout.addItem(spacerItem1, 1, 1, 1, 1)
|
||||
self.uiTabWidget.addTab(self.uiIOSRoutersTabWidget, _fromUtf8(""))
|
||||
self.vboxlayout.addWidget(self.uiTabWidget)
|
||||
|
||||
self.retranslateUi(IOUDevicePreferencesPageWidget)
|
||||
self.uiTabWidget.setCurrentIndex(0)
|
||||
QtCore.QMetaObject.connectSlotsByName(IOUDevicePreferencesPageWidget)
|
||||
|
||||
def retranslateUi(self, IOUDevicePreferencesPageWidget):
|
||||
IOUDevicePreferencesPageWidget.setWindowTitle(_translate("IOUDevicePreferencesPageWidget", "IOU devices", None))
|
||||
self.uiIOUImageTestSettingsPushButton.setText(_translate("IOUDevicePreferencesPageWidget", "Test settings", None))
|
||||
self.uiSaveIOUImagePushButton.setText(_translate("IOUDevicePreferencesPageWidget", "Save", None))
|
||||
self.uiDeleteIOUImagePushButton.setText(_translate("IOUDevicePreferencesPageWidget", "Delete", None))
|
||||
self.groupBox.setTitle(_translate("IOUDevicePreferencesPageWidget", "Settings", None))
|
||||
self.uiIOUPathLabel.setText(_translate("IOUDevicePreferencesPageWidget", "IOU path:", None))
|
||||
self.uiIOUPathToolButton.setText(_translate("IOUDevicePreferencesPageWidget", "...", None))
|
||||
self.uiStartupConfigLabel.setText(_translate("IOUDevicePreferencesPageWidget", "Startup-config:", None))
|
||||
self.uiStartupConfigToolButton.setText(_translate("IOUDevicePreferencesPageWidget", "...", None))
|
||||
self.uiNVRAMLabel.setText(_translate("IOUDevicePreferencesPageWidget", "NVRAM:", None))
|
||||
self.uiNVRAMSpinBox.setSuffix(_translate("IOUDevicePreferencesPageWidget", " KB", None))
|
||||
self.uiRAMLabel.setText(_translate("IOUDevicePreferencesPageWidget", "RAM:", None))
|
||||
self.uiRAMSpinBox.setSuffix(_translate("IOUDevicePreferencesPageWidget", " MB", None))
|
||||
self.uiIOUImagesTreeWidget.headerItem().setText(0, _translate("IOUDevicePreferencesPageWidget", "File", None))
|
||||
self.uiIOUImagesTreeWidget.headerItem().setText(1, _translate("IOUDevicePreferencesPageWidget", "Server", None))
|
||||
self.uiTabWidget.setTabText(self.uiTabWidget.indexOf(self.uiIOUDeviceTabWidget), _translate("IOUDevicePreferencesPageWidget", "IOU images", None))
|
||||
self.treeWidget_2.headerItem().setText(0, _translate("IOUDevicePreferencesPageWidget", "IOU device", None))
|
||||
self.treeWidget_2.headerItem().setText(1, _translate("IOUDevicePreferencesPageWidget", "IOU file", None))
|
||||
self.pushButton_3.setText(_translate("IOUDevicePreferencesPageWidget", "New", None))
|
||||
self.pushButton_4.setText(_translate("IOUDevicePreferencesPageWidget", "Edit", None))
|
||||
self.pushButton_5.setText(_translate("IOUDevicePreferencesPageWidget", "Delete", None))
|
||||
self.uiTabWidget.setTabText(self.uiTabWidget.indexOf(self.uiIOSRoutersTabWidget), _translate("IOUDevicePreferencesPageWidget", "IOU devices", None))
|
||||
|
||||
317
gns3/modules/vpcs/ui/vpcs_preferences_page.ui
Executable file
317
gns3/modules/vpcs/ui/vpcs_preferences_page.ui
Executable file
@@ -0,0 +1,317 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>IOUPreferencesPageWidget</class>
|
||||
<widget class="QWidget" name="IOUPreferencesPageWidget">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>432</width>
|
||||
<height>508</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>IOS on UNIX</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout">
|
||||
<item>
|
||||
<widget class="QTabWidget" name="uiTabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="uiGeneralSettingsTabWidget">
|
||||
<attribute name="title">
|
||||
<string>General settings</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="3" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="uiIOURCPathLineEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="uiIOURCPathToolButton">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextOnly</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="6" column="1">
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>164</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="uiTestSettingsPushButton">
|
||||
<property name="text">
|
||||
<string>Test settings</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="uiRestoreDefaultsPushButton">
|
||||
<property name="text">
|
||||
<string>Restore defaults</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="uiIouyapPathLabel">
|
||||
<property name="text">
|
||||
<string>Path to iouyap (local Linux server only):</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="uiIOURCPathLabel">
|
||||
<property name="text">
|
||||
<string>Path to IOURC (pushed to the server):</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0" colspan="2">
|
||||
<spacer name="spacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>390</width>
|
||||
<height>193</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="uiIouyapPathLineEdit"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QToolButton" name="uiIouyapPathToolButton">
|
||||
<property name="text">
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="toolButtonStyle">
|
||||
<enum>Qt::ToolButtonTextOnly</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="uiServerSettingsTabWidget">
|
||||
<attribute name="title">
|
||||
<string>Server settings</string>
|
||||
</attribute>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="uiUseLocalServercheckBox">
|
||||
<property name="text">
|
||||
<string>Use the local server (Linux only)</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QGroupBox" name="uiRemoteServersGroupBox">
|
||||
<property name="title">
|
||||
<string>Remote servers</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="uiRemoteServersTreeWidget">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Host</string>
|
||||
</property>
|
||||
</column>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Port</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tab">
|
||||
<attribute name="title">
|
||||
<string>Advanced settings</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QGroupBox" name="uiConsolePortRangeGroupBox">
|
||||
<property name="title">
|
||||
<string>Console port range</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="uiConsoleStartPortSpinBox">
|
||||
<property name="suffix">
|
||||
<string notr="true"> TCP</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65535</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>4001</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="uiConsolePortRangeLabel">
|
||||
<property name="text">
|
||||
<string>to</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="uiConsoleEndPortSpinBox">
|
||||
<property name="suffix">
|
||||
<string notr="true"> TCP</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65535</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>4500</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="uiUDPPortRangeGroupBox">
|
||||
<property name="title">
|
||||
<string>UDP tunneling port range</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QSpinBox" name="uiUDPStartPortSpinBox">
|
||||
<property name="suffix">
|
||||
<string notr="true"> UDP</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65535</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>30001</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="uiUDPPortRangeLabel">
|
||||
<property name="text">
|
||||
<string>to</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="uiUDPEndPortSpinBox">
|
||||
<property name="suffix">
|
||||
<string notr="true"> UDP</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>65535</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>40000</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>147</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>304</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
<designerdata>
|
||||
<property name="gridDeltaX">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="gridDeltaY">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="gridSnapX">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="gridSnapY">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="gridVisible">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</designerdata>
|
||||
</ui>
|
||||
172
gns3/modules/vpcs/ui/vpcs_preferences_page_ui.py
Normal file
172
gns3/modules/vpcs/ui/vpcs_preferences_page_ui.py
Normal file
@@ -0,0 +1,172 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file '/home/grossmj/workspace/git/gns3-gui/gns3/modules/iou/ui/iou_preferences_page.ui'
|
||||
#
|
||||
# Created: Wed Apr 30 16:43:13 2014
|
||||
# by: PyQt4 UI code generator 4.10
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
from PyQt4 import QtCore, QtGui
|
||||
|
||||
try:
|
||||
_fromUtf8 = QtCore.QString.fromUtf8
|
||||
except AttributeError:
|
||||
def _fromUtf8(s):
|
||||
return s
|
||||
|
||||
try:
|
||||
_encoding = QtGui.QApplication.UnicodeUTF8
|
||||
def _translate(context, text, disambig):
|
||||
return QtGui.QApplication.translate(context, text, disambig, _encoding)
|
||||
except AttributeError:
|
||||
def _translate(context, text, disambig):
|
||||
return QtGui.QApplication.translate(context, text, disambig)
|
||||
|
||||
class Ui_IOUPreferencesPageWidget(object):
|
||||
def setupUi(self, IOUPreferencesPageWidget):
|
||||
IOUPreferencesPageWidget.setObjectName(_fromUtf8("IOUPreferencesPageWidget"))
|
||||
IOUPreferencesPageWidget.resize(432, 508)
|
||||
self.vboxlayout = QtGui.QVBoxLayout(IOUPreferencesPageWidget)
|
||||
self.vboxlayout.setObjectName(_fromUtf8("vboxlayout"))
|
||||
self.uiTabWidget = QtGui.QTabWidget(IOUPreferencesPageWidget)
|
||||
self.uiTabWidget.setObjectName(_fromUtf8("uiTabWidget"))
|
||||
self.uiGeneralSettingsTabWidget = QtGui.QWidget()
|
||||
self.uiGeneralSettingsTabWidget.setObjectName(_fromUtf8("uiGeneralSettingsTabWidget"))
|
||||
self.gridLayout = QtGui.QGridLayout(self.uiGeneralSettingsTabWidget)
|
||||
self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
|
||||
self.horizontalLayout_5 = QtGui.QHBoxLayout()
|
||||
self.horizontalLayout_5.setObjectName(_fromUtf8("horizontalLayout_5"))
|
||||
self.uiIOURCPathLineEdit = QtGui.QLineEdit(self.uiGeneralSettingsTabWidget)
|
||||
self.uiIOURCPathLineEdit.setObjectName(_fromUtf8("uiIOURCPathLineEdit"))
|
||||
self.horizontalLayout_5.addWidget(self.uiIOURCPathLineEdit)
|
||||
self.uiIOURCPathToolButton = QtGui.QToolButton(self.uiGeneralSettingsTabWidget)
|
||||
self.uiIOURCPathToolButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextOnly)
|
||||
self.uiIOURCPathToolButton.setObjectName(_fromUtf8("uiIOURCPathToolButton"))
|
||||
self.horizontalLayout_5.addWidget(self.uiIOURCPathToolButton)
|
||||
self.gridLayout.addLayout(self.horizontalLayout_5, 3, 0, 1, 2)
|
||||
spacerItem = QtGui.QSpacerItem(164, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
|
||||
self.gridLayout.addItem(spacerItem, 6, 1, 1, 1)
|
||||
self.horizontalLayout_2 = QtGui.QHBoxLayout()
|
||||
self.horizontalLayout_2.setObjectName(_fromUtf8("horizontalLayout_2"))
|
||||
self.uiTestSettingsPushButton = QtGui.QPushButton(self.uiGeneralSettingsTabWidget)
|
||||
self.uiTestSettingsPushButton.setObjectName(_fromUtf8("uiTestSettingsPushButton"))
|
||||
self.horizontalLayout_2.addWidget(self.uiTestSettingsPushButton)
|
||||
self.uiRestoreDefaultsPushButton = QtGui.QPushButton(self.uiGeneralSettingsTabWidget)
|
||||
self.uiRestoreDefaultsPushButton.setObjectName(_fromUtf8("uiRestoreDefaultsPushButton"))
|
||||
self.horizontalLayout_2.addWidget(self.uiRestoreDefaultsPushButton)
|
||||
self.gridLayout.addLayout(self.horizontalLayout_2, 6, 0, 1, 1)
|
||||
self.uiIouyapPathLabel = QtGui.QLabel(self.uiGeneralSettingsTabWidget)
|
||||
self.uiIouyapPathLabel.setObjectName(_fromUtf8("uiIouyapPathLabel"))
|
||||
self.gridLayout.addWidget(self.uiIouyapPathLabel, 4, 0, 1, 1)
|
||||
self.uiIOURCPathLabel = QtGui.QLabel(self.uiGeneralSettingsTabWidget)
|
||||
self.uiIOURCPathLabel.setObjectName(_fromUtf8("uiIOURCPathLabel"))
|
||||
self.gridLayout.addWidget(self.uiIOURCPathLabel, 2, 0, 1, 1)
|
||||
spacerItem1 = QtGui.QSpacerItem(390, 193, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
|
||||
self.gridLayout.addItem(spacerItem1, 7, 0, 1, 2)
|
||||
self.horizontalLayout_6 = QtGui.QHBoxLayout()
|
||||
self.horizontalLayout_6.setObjectName(_fromUtf8("horizontalLayout_6"))
|
||||
self.uiIouyapPathLineEdit = QtGui.QLineEdit(self.uiGeneralSettingsTabWidget)
|
||||
self.uiIouyapPathLineEdit.setObjectName(_fromUtf8("uiIouyapPathLineEdit"))
|
||||
self.horizontalLayout_6.addWidget(self.uiIouyapPathLineEdit)
|
||||
self.uiIouyapPathToolButton = QtGui.QToolButton(self.uiGeneralSettingsTabWidget)
|
||||
self.uiIouyapPathToolButton.setToolButtonStyle(QtCore.Qt.ToolButtonTextOnly)
|
||||
self.uiIouyapPathToolButton.setObjectName(_fromUtf8("uiIouyapPathToolButton"))
|
||||
self.horizontalLayout_6.addWidget(self.uiIouyapPathToolButton)
|
||||
self.gridLayout.addLayout(self.horizontalLayout_6, 5, 0, 1, 2)
|
||||
self.uiTabWidget.addTab(self.uiGeneralSettingsTabWidget, _fromUtf8(""))
|
||||
self.uiServerSettingsTabWidget = QtGui.QWidget()
|
||||
self.uiServerSettingsTabWidget.setObjectName(_fromUtf8("uiServerSettingsTabWidget"))
|
||||
self.gridLayout_2 = QtGui.QGridLayout(self.uiServerSettingsTabWidget)
|
||||
self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2"))
|
||||
self.uiUseLocalServercheckBox = QtGui.QCheckBox(self.uiServerSettingsTabWidget)
|
||||
self.uiUseLocalServercheckBox.setChecked(True)
|
||||
self.uiUseLocalServercheckBox.setObjectName(_fromUtf8("uiUseLocalServercheckBox"))
|
||||
self.gridLayout_2.addWidget(self.uiUseLocalServercheckBox, 0, 0, 1, 1)
|
||||
self.uiRemoteServersGroupBox = QtGui.QGroupBox(self.uiServerSettingsTabWidget)
|
||||
self.uiRemoteServersGroupBox.setObjectName(_fromUtf8("uiRemoteServersGroupBox"))
|
||||
self.horizontalLayout_3 = QtGui.QHBoxLayout(self.uiRemoteServersGroupBox)
|
||||
self.horizontalLayout_3.setObjectName(_fromUtf8("horizontalLayout_3"))
|
||||
self.uiRemoteServersTreeWidget = QtGui.QTreeWidget(self.uiRemoteServersGroupBox)
|
||||
self.uiRemoteServersTreeWidget.setEnabled(False)
|
||||
self.uiRemoteServersTreeWidget.setObjectName(_fromUtf8("uiRemoteServersTreeWidget"))
|
||||
self.horizontalLayout_3.addWidget(self.uiRemoteServersTreeWidget)
|
||||
self.gridLayout_2.addWidget(self.uiRemoteServersGroupBox, 1, 0, 1, 1)
|
||||
self.uiTabWidget.addTab(self.uiServerSettingsTabWidget, _fromUtf8(""))
|
||||
self.tab = QtGui.QWidget()
|
||||
self.tab.setObjectName(_fromUtf8("tab"))
|
||||
self.verticalLayout = QtGui.QVBoxLayout(self.tab)
|
||||
self.verticalLayout.setObjectName(_fromUtf8("verticalLayout"))
|
||||
self.uiConsolePortRangeGroupBox = QtGui.QGroupBox(self.tab)
|
||||
self.uiConsolePortRangeGroupBox.setObjectName(_fromUtf8("uiConsolePortRangeGroupBox"))
|
||||
self.horizontalLayout = QtGui.QHBoxLayout(self.uiConsolePortRangeGroupBox)
|
||||
self.horizontalLayout.setObjectName(_fromUtf8("horizontalLayout"))
|
||||
self.uiConsoleStartPortSpinBox = QtGui.QSpinBox(self.uiConsolePortRangeGroupBox)
|
||||
self.uiConsoleStartPortSpinBox.setSuffix(_fromUtf8(" TCP"))
|
||||
self.uiConsoleStartPortSpinBox.setMaximum(65535)
|
||||
self.uiConsoleStartPortSpinBox.setProperty("value", 4001)
|
||||
self.uiConsoleStartPortSpinBox.setObjectName(_fromUtf8("uiConsoleStartPortSpinBox"))
|
||||
self.horizontalLayout.addWidget(self.uiConsoleStartPortSpinBox)
|
||||
self.uiConsolePortRangeLabel = QtGui.QLabel(self.uiConsolePortRangeGroupBox)
|
||||
self.uiConsolePortRangeLabel.setObjectName(_fromUtf8("uiConsolePortRangeLabel"))
|
||||
self.horizontalLayout.addWidget(self.uiConsolePortRangeLabel)
|
||||
self.uiConsoleEndPortSpinBox = QtGui.QSpinBox(self.uiConsolePortRangeGroupBox)
|
||||
self.uiConsoleEndPortSpinBox.setSuffix(_fromUtf8(" TCP"))
|
||||
self.uiConsoleEndPortSpinBox.setMaximum(65535)
|
||||
self.uiConsoleEndPortSpinBox.setProperty("value", 4500)
|
||||
self.uiConsoleEndPortSpinBox.setObjectName(_fromUtf8("uiConsoleEndPortSpinBox"))
|
||||
self.horizontalLayout.addWidget(self.uiConsoleEndPortSpinBox)
|
||||
spacerItem2 = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
|
||||
self.horizontalLayout.addItem(spacerItem2)
|
||||
self.verticalLayout.addWidget(self.uiConsolePortRangeGroupBox)
|
||||
self.uiUDPPortRangeGroupBox = QtGui.QGroupBox(self.tab)
|
||||
self.uiUDPPortRangeGroupBox.setObjectName(_fromUtf8("uiUDPPortRangeGroupBox"))
|
||||
self.horizontalLayout_4 = QtGui.QHBoxLayout(self.uiUDPPortRangeGroupBox)
|
||||
self.horizontalLayout_4.setObjectName(_fromUtf8("horizontalLayout_4"))
|
||||
self.uiUDPStartPortSpinBox = QtGui.QSpinBox(self.uiUDPPortRangeGroupBox)
|
||||
self.uiUDPStartPortSpinBox.setSuffix(_fromUtf8(" UDP"))
|
||||
self.uiUDPStartPortSpinBox.setMaximum(65535)
|
||||
self.uiUDPStartPortSpinBox.setProperty("value", 30001)
|
||||
self.uiUDPStartPortSpinBox.setObjectName(_fromUtf8("uiUDPStartPortSpinBox"))
|
||||
self.horizontalLayout_4.addWidget(self.uiUDPStartPortSpinBox)
|
||||
self.uiUDPPortRangeLabel = QtGui.QLabel(self.uiUDPPortRangeGroupBox)
|
||||
self.uiUDPPortRangeLabel.setObjectName(_fromUtf8("uiUDPPortRangeLabel"))
|
||||
self.horizontalLayout_4.addWidget(self.uiUDPPortRangeLabel)
|
||||
self.uiUDPEndPortSpinBox = QtGui.QSpinBox(self.uiUDPPortRangeGroupBox)
|
||||
self.uiUDPEndPortSpinBox.setSuffix(_fromUtf8(" UDP"))
|
||||
self.uiUDPEndPortSpinBox.setMaximum(65535)
|
||||
self.uiUDPEndPortSpinBox.setProperty("value", 40000)
|
||||
self.uiUDPEndPortSpinBox.setObjectName(_fromUtf8("uiUDPEndPortSpinBox"))
|
||||
self.horizontalLayout_4.addWidget(self.uiUDPEndPortSpinBox)
|
||||
spacerItem3 = QtGui.QSpacerItem(147, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
|
||||
self.horizontalLayout_4.addItem(spacerItem3)
|
||||
self.verticalLayout.addWidget(self.uiUDPPortRangeGroupBox)
|
||||
spacerItem4 = QtGui.QSpacerItem(20, 304, QtGui.QSizePolicy.Minimum, QtGui.QSizePolicy.Expanding)
|
||||
self.verticalLayout.addItem(spacerItem4)
|
||||
self.uiTabWidget.addTab(self.tab, _fromUtf8(""))
|
||||
self.vboxlayout.addWidget(self.uiTabWidget)
|
||||
|
||||
self.retranslateUi(IOUPreferencesPageWidget)
|
||||
self.uiTabWidget.setCurrentIndex(0)
|
||||
QtCore.QMetaObject.connectSlotsByName(IOUPreferencesPageWidget)
|
||||
|
||||
def retranslateUi(self, IOUPreferencesPageWidget):
|
||||
IOUPreferencesPageWidget.setWindowTitle(_translate("IOUPreferencesPageWidget", "IOS on UNIX", None))
|
||||
self.uiIOURCPathToolButton.setText(_translate("IOUPreferencesPageWidget", "...", None))
|
||||
self.uiTestSettingsPushButton.setText(_translate("IOUPreferencesPageWidget", "Test settings", None))
|
||||
self.uiRestoreDefaultsPushButton.setText(_translate("IOUPreferencesPageWidget", "Restore defaults", None))
|
||||
self.uiIouyapPathLabel.setText(_translate("IOUPreferencesPageWidget", "Path to iouyap (local Linux server only):", None))
|
||||
self.uiIOURCPathLabel.setText(_translate("IOUPreferencesPageWidget", "Path to IOURC (pushed to the server):", None))
|
||||
self.uiIouyapPathToolButton.setText(_translate("IOUPreferencesPageWidget", "...", None))
|
||||
self.uiTabWidget.setTabText(self.uiTabWidget.indexOf(self.uiGeneralSettingsTabWidget), _translate("IOUPreferencesPageWidget", "General settings", None))
|
||||
self.uiUseLocalServercheckBox.setText(_translate("IOUPreferencesPageWidget", "Use the local server (Linux only)", None))
|
||||
self.uiRemoteServersGroupBox.setTitle(_translate("IOUPreferencesPageWidget", "Remote servers", None))
|
||||
self.uiRemoteServersTreeWidget.headerItem().setText(0, _translate("IOUPreferencesPageWidget", "Host", None))
|
||||
self.uiRemoteServersTreeWidget.headerItem().setText(1, _translate("IOUPreferencesPageWidget", "Port", None))
|
||||
self.uiTabWidget.setTabText(self.uiTabWidget.indexOf(self.uiServerSettingsTabWidget), _translate("IOUPreferencesPageWidget", "Server settings", None))
|
||||
self.uiConsolePortRangeGroupBox.setTitle(_translate("IOUPreferencesPageWidget", "Console port range", None))
|
||||
self.uiConsolePortRangeLabel.setText(_translate("IOUPreferencesPageWidget", "to", None))
|
||||
self.uiUDPPortRangeGroupBox.setTitle(_translate("IOUPreferencesPageWidget", "UDP tunneling port range", None))
|
||||
self.uiUDPPortRangeLabel.setText(_translate("IOUPreferencesPageWidget", "to", None))
|
||||
self.uiTabWidget.setTabText(self.uiTabWidget.indexOf(self.tab), _translate("IOUPreferencesPageWidget", "Advanced settings", None))
|
||||
|
||||
623
gns3/modules/vpcs/vpcs_device.py
Normal file
623
gns3/modules/vpcs/vpcs_device.py
Normal file
@@ -0,0 +1,623 @@
|
||||
# -*- 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/>.
|
||||
|
||||
"""
|
||||
VPCS device implementation.
|
||||
"""
|
||||
|
||||
import os
|
||||
import base64
|
||||
from gns3.node import Node
|
||||
from gns3.ports.port import Port
|
||||
from gns3.ports.ethernet_port import EthernetPort
|
||||
from gns3.ports.serial_port import SerialPort
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class VPCSDevice(Node):
|
||||
"""
|
||||
VPCS device.
|
||||
|
||||
:param module: parent module for this node
|
||||
:param server: GNS3 server instance
|
||||
"""
|
||||
|
||||
def __init__(self, module, server):
|
||||
Node.__init__(self, server)
|
||||
|
||||
log.info("VPCS instance is being created")
|
||||
self._vpcs_id = None
|
||||
self._defaults = {}
|
||||
self._inital_settings = None
|
||||
self._loading = False
|
||||
self._module = module
|
||||
self._ports = []
|
||||
self._settings = {"name": "",
|
||||
"path": "",
|
||||
"startup_config": "",
|
||||
"ram": 256,
|
||||
"nvram": 128,
|
||||
"ethernet_adapters": 2,
|
||||
"serial_adapters": 2,
|
||||
"console": None}
|
||||
|
||||
#self._occupied_slots = []
|
||||
self._addAdapters(2, 2)
|
||||
|
||||
# save the default settings
|
||||
self._defaults = self._settings.copy()
|
||||
|
||||
def _addAdapters(self, nb_ethernet_adapters, nb_serial_adapters):
|
||||
"""
|
||||
Adds ports based on what adapter is inserted in which slot.
|
||||
|
||||
:param adapter: adapter name
|
||||
:param slot_number: slot number (integer)
|
||||
"""
|
||||
|
||||
nb_adapters = nb_ethernet_adapters + nb_serial_adapters
|
||||
for slot_number in range(0, nb_adapters):
|
||||
# if slot_number in self._occupied_slots:
|
||||
# continue
|
||||
for port_number in range(0, 4):
|
||||
if slot_number < nb_ethernet_adapters:
|
||||
port = EthernetPort
|
||||
else:
|
||||
port = SerialPort
|
||||
port_name = port.longNameType() + str(slot_number) + "/" + str(port_number)
|
||||
new_port = port(port_name)
|
||||
new_port.setPortNumber(port_number)
|
||||
new_port.setSlotNumber(slot_number)
|
||||
#self._occupied_slots.append(slot_number)
|
||||
self._ports.append(new_port)
|
||||
log.debug("port {} has been added".format(port_name))
|
||||
|
||||
def _removeAdapters(self, nb_ethernet_adapters, nb_serial_adapters):
|
||||
"""
|
||||
Removes ports when an adapter is removed from a slot.
|
||||
|
||||
:param slot_number: slot number (integer)
|
||||
"""
|
||||
|
||||
for port in self._ports.copy():
|
||||
if (port.slotNumber() >= nb_ethernet_adapters and port.linkType() == "Ethernet") or \
|
||||
(port.slotNumber() >= nb_serial_adapters and port.linkType() == "Serial"):
|
||||
#self._occupied_slots.remove(port.slotNumber())
|
||||
self._ports.remove(port)
|
||||
log.info("port {} has been removed".format(port.name()))
|
||||
|
||||
def setup(self, vpcs_path, name=None, initial_settings={}):
|
||||
"""
|
||||
Setups this VPCS device.
|
||||
|
||||
:param name: optional name
|
||||
"""
|
||||
params = {"path": vpcs_path}
|
||||
|
||||
if name:
|
||||
params["name"] = self._settings["name"] = name
|
||||
|
||||
# other initial settings will be applied when the router has been created
|
||||
if initial_settings:
|
||||
self._inital_settings = initial_settings
|
||||
|
||||
self._server.send_message("vpcs.create", params, self._setupCallback)
|
||||
|
||||
def _setupCallback(self, result, error=False):
|
||||
"""
|
||||
Callback for setup.
|
||||
|
||||
:param result: server response
|
||||
:param error: indicates an error (boolean)
|
||||
"""
|
||||
|
||||
if error:
|
||||
log.error("error while setting up {}: {}".format(self.name(), result["message"]))
|
||||
self.server_error_signal.emit(self.id(), result["code"], result["message"])
|
||||
return
|
||||
|
||||
self._vpcs_id = result["id"]
|
||||
if not self._vpcs_id:
|
||||
self.error_signal.emit(self.id(), "returned ID from server is null")
|
||||
return
|
||||
|
||||
# update the settings using the defaults sent by the server
|
||||
for name, value in result.items():
|
||||
if name in self._settings and self._settings[name] != value:
|
||||
log.info("VPCS instance setting up and updating {} from '{}' to '{}'".format(name, self._settings[name], value))
|
||||
self._settings[name] = value
|
||||
|
||||
# update the node with setup initial settings if any
|
||||
if self._inital_settings:
|
||||
self.update(self._inital_settings)
|
||||
elif self._loading:
|
||||
self.updated_signal.emit()
|
||||
else:
|
||||
self.setInitialized(True)
|
||||
log.info("VPCS instance {} has been created".format(self.name()))
|
||||
self.created_signal.emit(self.id())
|
||||
self._module.addNode(self)
|
||||
|
||||
def delete(self):
|
||||
"""
|
||||
Deletes this VPCS instance.
|
||||
"""
|
||||
|
||||
log.debug("VPCS device {} is being deleted".format(self.name()))
|
||||
# first delete all the links attached to this node
|
||||
self.delete_links_signal.emit()
|
||||
if self._vpcs_id:
|
||||
self._server.send_message("vpcs.delete", {"id": self._vpcs_id}, self._deleteCallback)
|
||||
else:
|
||||
self.deleted_signal.emit()
|
||||
self._module.removeNode(self)
|
||||
|
||||
def _deleteCallback(self, result, error=False):
|
||||
"""
|
||||
Callback for delete.
|
||||
|
||||
:param result: server response
|
||||
:param error: indicates an error (boolean)
|
||||
"""
|
||||
|
||||
if error:
|
||||
log.error("error while deleting {}: {}".format(self.name(), result["message"]))
|
||||
self.server_error_signal.emit(self.id(), result["code"], result["message"])
|
||||
log.info("{} has been deleted".format(self.name()))
|
||||
self.deleted_signal.emit()
|
||||
self._module.removeNode(self)
|
||||
|
||||
def _base64Config(self, config_path):
|
||||
"""
|
||||
Get the base64 encoded config from a file.
|
||||
|
||||
:param config_path: path to the configuration file.
|
||||
|
||||
:returns: base64 encoded string
|
||||
"""
|
||||
|
||||
try:
|
||||
with open(config_path, "r") as f:
|
||||
log.info("opening configuration file: {}".format(config_path))
|
||||
config = f.read()
|
||||
config = '!\n' + config.replace('\r', "")
|
||||
encoded = ("").join(base64.encodestring(config.encode("utf-8")).decode("utf-8").split())
|
||||
return encoded
|
||||
except OSError as e:
|
||||
log.warn("could not base64 encode {}: {}".format(config_path, e))
|
||||
return ""
|
||||
|
||||
def update(self, new_settings):
|
||||
"""
|
||||
Updates the settings for this VPCS device.
|
||||
|
||||
:param new_settings: settings dictionary
|
||||
"""
|
||||
|
||||
params = {"id": self._vpcs_id}
|
||||
for name, value in new_settings.items():
|
||||
if name in self._settings and self._settings[name] != value:
|
||||
params[name] = value
|
||||
|
||||
if "startup_config" in new_settings and self._settings["startup_config"] != new_settings["startup_config"] \
|
||||
and os.path.isfile(new_settings["startup_config"]):
|
||||
params["startup_config_base64"] = self._base64Config(new_settings["startup_config"])
|
||||
|
||||
log.debug("{} is updating settings: {}".format(self.name(), params))
|
||||
self._server.send_message("vpcs.update", params, self._updateCallback)
|
||||
|
||||
def _updateCallback(self, result, error=False):
|
||||
"""
|
||||
Callback for update.
|
||||
|
||||
:param result: server response
|
||||
:param error: indicates an error (boolean)
|
||||
"""
|
||||
|
||||
if error:
|
||||
log.error("error while deleting {}: {}".format(self.name(), result["message"]))
|
||||
self.server_error_signal.emit(self.id(), result["code"], result["message"])
|
||||
return
|
||||
|
||||
updated = False
|
||||
nb_adapters_changed = False
|
||||
for name, value in result.items():
|
||||
if name in self._settings and self._settings[name] != value:
|
||||
log.info("{}: updating {} from '{}' to '{}'".format(self.name(), name, self._settings[name], value))
|
||||
updated = True
|
||||
if (name == "ethernet_adapters" or name == "serial_adapters"):
|
||||
nb_adapters_changed = True
|
||||
self._settings[name] = value
|
||||
|
||||
if nb_adapters_changed:
|
||||
log.debug("number of adapters has changed: Ethernet={} Serial={}".format(self._settings["ethernet_adapters"], self._settings["serial_adapters"]))
|
||||
#TODO: dynamically add/remove adapters
|
||||
self._ports.clear()
|
||||
self._addAdapters(self._settings["ethernet_adapters"], self._settings["serial_adapters"])
|
||||
|
||||
if self._inital_settings and not self._loading:
|
||||
self.setInitialized(True)
|
||||
log.info("VPCS device {} has been created".format(self.name()))
|
||||
self.created_signal.emit(self.id())
|
||||
self._module.addNode(self)
|
||||
self._inital_settings = None
|
||||
elif updated or self._loading:
|
||||
log.info("VPCS device {} has been updated".format(self.name()))
|
||||
self.updated_signal.emit()
|
||||
|
||||
def start(self):
|
||||
"""
|
||||
Starts this VPCS instance.
|
||||
"""
|
||||
|
||||
log.debug("{} is starting".format(self.name()))
|
||||
self._server.send_message("vpcs.start", {"id": self._vpcs_id}, self._startCallback)
|
||||
|
||||
def _startCallback(self, result, error=False):
|
||||
"""
|
||||
Callback for start.
|
||||
|
||||
:param result: server response
|
||||
:param error: indicates an error (boolean)
|
||||
"""
|
||||
|
||||
if error:
|
||||
log.error("error while starting {}: {}".format(self.name(), result["message"]))
|
||||
self.server_error_signal.emit(self.id(), result["code"], result["message"])
|
||||
else:
|
||||
log.info("{} has started".format(self.name()))
|
||||
self.setStatus(Node.started)
|
||||
for port in self._ports:
|
||||
# set ports as started
|
||||
port.setStatus(Port.started)
|
||||
self.started_signal.emit()
|
||||
|
||||
def stop(self):
|
||||
"""
|
||||
Stops this VPCS instance.
|
||||
"""
|
||||
|
||||
log.debug("{} is stopping".format(self.name()))
|
||||
self._server.send_message("vpcs.stop", {"id": self._vpcs_id}, self._stopCallback)
|
||||
|
||||
def _stopCallback(self, result, error=False):
|
||||
"""
|
||||
Callback for stop.
|
||||
|
||||
:param result: server response
|
||||
:param error: indicates an error (boolean)
|
||||
"""
|
||||
|
||||
if error:
|
||||
log.error("error while stopping {}: {}".format(self.name(), result["message"]))
|
||||
self.server_error_signal.emit(self.id(), result["code"], result["message"])
|
||||
else:
|
||||
log.info("{} has stopped".format(self.name()))
|
||||
self.setStatus(Node.stopped)
|
||||
for port in self._ports:
|
||||
# set ports as stopped
|
||||
port.setStatus(Port.stopped)
|
||||
self.stopped_signal.emit()
|
||||
|
||||
def reload(self):
|
||||
"""
|
||||
Reloads this VPCS instance.
|
||||
"""
|
||||
|
||||
log.debug("{} is being reloaded".format(self.name()))
|
||||
self._server.send_message("vpcs.reload", {"id": self._vpcs_id}, self._reloadCallback)
|
||||
|
||||
def _reloadCallback(self, result, error=False):
|
||||
"""
|
||||
Callback for reload.
|
||||
|
||||
:param result: server response
|
||||
:param error: indicates an error (boolean)
|
||||
"""
|
||||
|
||||
if error:
|
||||
log.error("error while suspending {}: {}".format(self.name(), result["message"]))
|
||||
self.server_error_signal.emit(self.id(), result["code"], result["message"])
|
||||
else:
|
||||
log.info("{} has reloaded".format(self.name()))
|
||||
|
||||
def allocateUDPPort(self, port_id):
|
||||
"""
|
||||
Requests an UDP port allocation.
|
||||
|
||||
:param port_id: port identifier
|
||||
"""
|
||||
|
||||
log.debug("{} is requesting an UDP port allocation".format(self.name()))
|
||||
self._server.send_message("vpcs.allocate_udp_port", {"id": self._vpcs_id, "port_id": port_id}, self._allocateUDPPortCallback)
|
||||
|
||||
def _allocateUDPPortCallback(self, result, error=False):
|
||||
"""
|
||||
Callback for allocateUDPPort.
|
||||
|
||||
:param result: server response
|
||||
:param error: indicates an error (boolean)
|
||||
"""
|
||||
|
||||
if error:
|
||||
log.error("error while allocating an UDP port for {}: {}".format(self.name(), result["message"]))
|
||||
self.server_error_signal.emit(self.id(), result["code"], result["message"])
|
||||
else:
|
||||
port_id = result["port_id"]
|
||||
lport = result["lport"]
|
||||
log.debug("{} has allocated UDP port {}".format(self.name(), port_id, lport))
|
||||
self.allocate_udp_nio_signal.emit(self.id(), port_id, lport)
|
||||
|
||||
def addNIO(self, port, nio):
|
||||
"""
|
||||
Adds a new NIO on the specified port for this VPCS instance.
|
||||
|
||||
:param port: Port instance
|
||||
:param nio: NIO instance
|
||||
"""
|
||||
|
||||
params = {"id": self._vpcs_id,
|
||||
"slot": port.slotNumber(),
|
||||
"port": port.portNumber(),
|
||||
"port_id": port.id()}
|
||||
|
||||
params["nio"] = self.getNIOInfo(nio)
|
||||
log.debug("{} is adding an {}: {}".format(self.name(), nio, params))
|
||||
self._server.send_message("vpcs.add_nio", params, self._addNIOCallback)
|
||||
|
||||
def _addNIOCallback(self, result, error=False):
|
||||
"""
|
||||
Callback for addNIO.
|
||||
|
||||
:param result: server response
|
||||
:param error: indicates an error (boolean)
|
||||
"""
|
||||
|
||||
if error:
|
||||
log.error("error while adding an UDP NIO for {}: {}".format(self.name(), result["message"]))
|
||||
self.server_error_signal.emit(self.id(), result["code"], result["message"])
|
||||
self.nio_cancel_signal.emit(self.id())
|
||||
else:
|
||||
self.nio_signal.emit(self.id(), result["port_id"])
|
||||
|
||||
def deleteNIO(self, port):
|
||||
"""
|
||||
Deletes an NIO from the specified port on this VPCS instance
|
||||
|
||||
:param port: Port instance
|
||||
"""
|
||||
|
||||
params = {"id": self._vpcs_id,
|
||||
"port": port.portNumber(),
|
||||
"slot": port.slotNumber()}
|
||||
|
||||
log.debug("{} is deleting an NIO: {}".format(self.name(), params))
|
||||
self._server.send_message("vpcs.delete_nio", params, self._deleteNIOCallback)
|
||||
|
||||
def _deleteNIOCallback(self, result, error=False):
|
||||
"""
|
||||
Callback for deleteNIO.
|
||||
|
||||
:param result: server response
|
||||
:param error: indicates an error (boolean)
|
||||
"""
|
||||
|
||||
if error:
|
||||
log.error("error while deleting NIO {}: {}".format(self.name(), result["message"]))
|
||||
self.server_error_signal.emit(self.id(), result["code"], result["message"])
|
||||
return
|
||||
|
||||
log.debug("{} has deleted a NIO: {}".format(self.name(), result))
|
||||
|
||||
def info(self):
|
||||
"""
|
||||
Returns information about this VPCS device.
|
||||
|
||||
:returns: formated string
|
||||
"""
|
||||
|
||||
if self.status() == Node.started:
|
||||
state = "started"
|
||||
else:
|
||||
state = "stopped"
|
||||
|
||||
info = """Device {name} is {state}
|
||||
Node ID is {id}, server's VPCS device ID is {vpcs_id}
|
||||
Hardware is Cisco VPCS generic device with {ram} MB RAM and {nvram} KB NVRAM
|
||||
Device's server runs on {host}:{port}, console is on port {console}
|
||||
Image is {image_name}
|
||||
{nb_ethernet} Ethernet adapters and {nb_serial} serial adapters installed
|
||||
""".format(name=self.name(),
|
||||
id=self.id(),
|
||||
vpcs_id=self._vpcs_id,
|
||||
state=state,
|
||||
ram=self._settings["ram"],
|
||||
nvram=self._settings["nvram"],
|
||||
host=self._server.host,
|
||||
port=self._server.port,
|
||||
console=self._settings["console"],
|
||||
image_name=os.path.basename(self._settings["path"]),
|
||||
nb_ethernet=self._settings["ethernet_adapters"],
|
||||
nb_serial=self._settings["serial_adapters"])
|
||||
|
||||
port_info = ""
|
||||
for port in self._ports:
|
||||
if port.isFree():
|
||||
port_info += " {port_name} is empty\n".format(port_name=port.name())
|
||||
else:
|
||||
port_info += " {port_name} {port_description}\n".format(port_name=port.name(),
|
||||
port_description=port.description())
|
||||
|
||||
return info + port_info
|
||||
|
||||
def dump(self):
|
||||
"""
|
||||
Returns a representation of this VPCS device.
|
||||
(to be saved in a topology file).
|
||||
|
||||
:returns: representation of the node (dictionary)
|
||||
"""
|
||||
|
||||
router = {"id": self.id(),
|
||||
"type": self.__class__.__name__,
|
||||
"description": str(self),
|
||||
"properties": {},
|
||||
"server_id": self._server.id()}
|
||||
|
||||
# add the properties
|
||||
for name, value in self._settings.items():
|
||||
if name in self._defaults and self._defaults[name] != value:
|
||||
router["properties"][name] = value
|
||||
|
||||
# add the ports
|
||||
if self._ports:
|
||||
ports = router["ports"] = []
|
||||
for port in self._ports:
|
||||
ports.append(port.dump())
|
||||
|
||||
#TODO: handle the image path
|
||||
# router["properties"]["image"]
|
||||
|
||||
return router
|
||||
|
||||
def load(self, node_info):
|
||||
"""
|
||||
Loads an VPCS device representation
|
||||
(from a topology file).
|
||||
|
||||
:param node_info: representation of the node (dictionary)
|
||||
"""
|
||||
|
||||
self.node_info = node_info
|
||||
settings = node_info["properties"]
|
||||
name = settings.pop("name")
|
||||
path = settings.pop("path")
|
||||
self.updated_signal.connect(self._updatePortSettings)
|
||||
# block the created signal, it will be triggered when loading is completely done
|
||||
self._loading = True
|
||||
log.info("vpcs device {} is loading".format(name))
|
||||
self.setup(path, name, settings)
|
||||
|
||||
def _updatePortSettings(self):
|
||||
"""
|
||||
Updates port settings when loading a topology.
|
||||
"""
|
||||
|
||||
self.updated_signal.disconnect(self._updatePortSettings)
|
||||
# update the port with the correct names and IDs
|
||||
if "ports" in self.node_info:
|
||||
ports = self.node_info["ports"]
|
||||
for topology_port in ports:
|
||||
for port in self._ports:
|
||||
if topology_port["port_number"] == port.portNumber() and topology_port["slot_number"] == port.slotNumber():
|
||||
port.setName(topology_port["name"])
|
||||
port.setId(topology_port["id"])
|
||||
|
||||
# now we can set the node has initialized and trigger the signal
|
||||
self.setInitialized(True)
|
||||
log.info("router {} has been loaded".format(self.name()))
|
||||
self.created_signal.emit(self.id())
|
||||
self._module.addNode(self)
|
||||
self._inital_settings = None
|
||||
self._loading = False
|
||||
|
||||
def name(self):
|
||||
"""
|
||||
Returns the name of this VPCS device.
|
||||
|
||||
:returns: name (string)
|
||||
"""
|
||||
|
||||
return self._settings["name"]
|
||||
|
||||
def settings(self):
|
||||
"""
|
||||
Returns all this VPCS device settings.
|
||||
|
||||
:returns: settings dictionary
|
||||
"""
|
||||
|
||||
return self._settings
|
||||
|
||||
def ports(self):
|
||||
"""
|
||||
Returns all the ports for this VPCS device.
|
||||
|
||||
:returns: list of Port instances
|
||||
"""
|
||||
|
||||
return self._ports
|
||||
|
||||
def console(self):
|
||||
"""
|
||||
Returns the console port for this VPCS device.
|
||||
|
||||
:returns: port (integer)
|
||||
"""
|
||||
|
||||
return self._settings["console"]
|
||||
|
||||
def configPage(self):
|
||||
"""
|
||||
Returns the configuration page widget to be used by the node configurator.
|
||||
|
||||
:returns: QWidget object
|
||||
"""
|
||||
|
||||
from .pages.vpcs_device_configuration_page import vpcsDeviceConfigurationPage
|
||||
return vpcsDeviceConfigurationPage
|
||||
|
||||
@staticmethod
|
||||
def defaultSymbol():
|
||||
"""
|
||||
Returns the default symbol path for this node.
|
||||
|
||||
:returns: symbol path (or resource).
|
||||
"""
|
||||
|
||||
return ":/symbols/multilayer_switch.normal.svg"
|
||||
|
||||
@staticmethod
|
||||
def hoverSymbol():
|
||||
"""
|
||||
Returns the symbol to use when this node is hovered.
|
||||
|
||||
:returns: symbol path (or resource).
|
||||
"""
|
||||
|
||||
return ":/symbols/multilayer_switch.selected.svg"
|
||||
|
||||
@staticmethod
|
||||
def symbolName():
|
||||
|
||||
return "VPCS device"
|
||||
|
||||
@staticmethod
|
||||
def categories():
|
||||
"""
|
||||
Returns the node categories the node is part of (used by the device panel).
|
||||
|
||||
:returns: list of node category (integer)
|
||||
"""
|
||||
|
||||
return [Node.routers, Node.switches]
|
||||
|
||||
def __str__(self):
|
||||
|
||||
return "VPCS device"
|
||||
Reference in New Issue
Block a user