Auto idle-pc feature and improvements/bug fixes for GNS3 preferences.

This commit is contained in:
grossmj
2014-10-13 19:53:17 -06:00
parent 4606e501bd
commit 76a6d09e98
16 changed files with 314 additions and 68 deletions

View File

@@ -0,0 +1,59 @@
# -*- 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/>.
from ..qt import QtCore, QtGui
from ..ui.exec_command_dialog_ui import Ui_ExecCommandDialog
class ExecCommandDialog(QtGui.QDialog, Ui_ExecCommandDialog):
"""
Execute a command and display its output.
"""
def __init__(self, parent, command, params):
QtGui.QDialog.__init__(self, parent)
self.setupUi(self)
self.setWindowTitle("Executing {}".format(command))
self._process = QtCore.QProcess(self)
self._process.readyRead.connect(self._dataReadySlot)
self._process.start(command, params, QtCore.QProcess.Unbuffered | QtCore.QProcess.ReadWrite)
def _dataReadySlot(self):
"""
Display the command output when data is ready.
"""
cursor = self.uiOutputTextEdit.textCursor()
cursor.movePosition(cursor.End)
for line in self._process.readAll():
cursor.insertText(line)
for line in self._process.readAllStandardError():
cursor.insertText(line)
self.uiOutputTextEdit.ensureCursorVisible()
def done(self, result):
"""
Called when the dialog is closed.
:param result: boolean (accepted or rejected)
"""
self._process.kill()
self._process.waitForFinished()
QtGui.QDialog.done(self, result)

View File

@@ -22,12 +22,31 @@ Wizard for IOS routers.
import os
import re
from gns3.qt import QtGui
from gns3.qt import QtCore, QtGui
from gns3.servers import Servers
from gns3.utils.message_box import MessageBox
from gns3.dialogs.exec_command_dialog import ExecCommandDialog
from ..ui.ios_router_wizard_ui import Ui_IOSRouterWizard
from ..settings import PLATFORMS_DEFAULT_RAM, CHASSIS, ADAPTER_MATRIX, WIC_MATRIX
from .. import Dynamips
from ..nodes.c1700 import C1700
from ..nodes.c2600 import C2600
from ..nodes.c2691 import C2691
from ..nodes.c3600 import C3600
from ..nodes.c3725 import C3725
from ..nodes.c3745 import C3745
from ..nodes.c7200 import C7200
PLATFORM_TO_CLASS = {
"c1700": C1700,
"c2600": C2600,
"c2691": C2691,
"c3600": C3600,
"c3725": C3725,
"c3745": C3745,
"c7200": C7200
}
class IOSRouterWizard(QtGui.QWizard, Ui_IOSRouterWizard):
@@ -45,6 +64,7 @@ class IOSRouterWizard(QtGui.QWizard, Ui_IOSRouterWizard):
self.setWizardStyle(QtGui.QWizard.ModernStyle)
self.uiIOSImageToolButton.clicked.connect(self._iosImageBrowserSlot)
self.uiTestIOSImagePushButton.clicked.connect(self._testIOSImageSlot)
self.uiIdlePCFinderPushButton.clicked.connect(self._idlePCFinderSlot)
self.uiPlatformComboBox.currentIndexChanged[str].connect(self._platformChangedSlot)
self.uiPlatformComboBox.addItems(list(PLATFORMS_DEFAULT_RAM.keys()))
@@ -65,6 +85,8 @@ class IOSRouterWizard(QtGui.QWizard, Ui_IOSRouterWizard):
1: self.uiWic1comboBox,
2: self.uiWic2comboBox}
self.uiTestIOSImagePushButton.hide() # hide it because it doesn't work
def _platformChangedSlot(self, platform):
"""
Updates the chassis comboBox based on the selected platform.
@@ -76,9 +98,66 @@ class IOSRouterWizard(QtGui.QWizard, Ui_IOSRouterWizard):
if platform in CHASSIS:
self.uiChassisComboBox.addItems(CHASSIS[platform])
def _idlePCFinderSlot(self):
def _testIOSImageSlot(self):
QtGui.QMessageBox.critical(self, "Idle-PC", "Sorry, this hasn't been implemented yet")
platform = self.uiPlatformComboBox.currentText()
ram = self.uiRamSpinBox.value()
ios_image = self.uiIOSImageLineEdit.text()
params = ["-P", platform[1:], "-r", str(ram), ios_image]
dialog = ExecCommandDialog(self, "/usr/bin/dynamips", params)
dialog.show()
dialog.exec_()
def _idlePCFinderSlot(self):
"""
Slot for the idle-PC finder.
"""
server = Servers.instance().localServer()
module = Dynamips.instance()
platform = self.uiPlatformComboBox.currentText()
ios_image = self.uiIOSImageLineEdit.text()
ram = self.uiRamSpinBox.value()
router_class = PLATFORM_TO_CLASS[platform]
self._router = router_class(module, server)
self._router.setup(ios_image, ram, name="AUTOIDLEPC")
self._router.created_signal.connect(self.createdSlot)
self.uiIdlePCFinderPushButton.setEnabled(False)
def createdSlot(self, node_id):
"""
The node for the auto idle-pc has been created.
:param node_id: not used
"""
self._router.computeAutoIdlepc(self._computeAutoIdlepcCallback)
self._auto_idlepc_progress_dialog = QtGui.QProgressDialog("Searching for an idle-pc value...", "Cancel", 0, 0, parent=self)
self._auto_idlepc_progress_dialog.setWindowModality(QtCore.Qt.WindowModal)
self._auto_idlepc_progress_dialog.setWindowTitle("Idle-PC finder")
self._auto_idlepc_progress_dialog.show()
def _computeAutoIdlepcCallback(self, result, error=False):
"""
Callback for computeAutoIdlepc.
:param result: server response
:param error: indicates an error (boolean)
"""
self._router.delete()
if self._auto_idlepc_progress_dialog.wasCanceled():
return
self._auto_idlepc_progress_dialog.accept()
if error:
QtGui.QMessageBox.critical(self, "Idle-PC finder", "Error: ".format(result["message"]))
else:
if result["idlepc"] and result["idlepc"] != "0x0":
self.uiIdlepcLineEdit.setText(result["idlepc"])
else:
logs = "\n".join(result["logs"])
MessageBox(self, "Idle-PC finder", "Could not find an idle-pc value", details=logs)
def _iosImageBrowserSlot(self):
"""

View File

@@ -628,6 +628,16 @@ class Router(Node):
self._idlepcs = result["idlepcs"]
self.idlepc_signal.emit()
def computeAutoIdlepc(self, callback):
"""
Automatically search for an Idle-PC value.
:param callback: Callback for the response
"""
log.debug("{} is starting an auto idle-pc lookup".format(self.name()))
self._server.send_message("dynamips.vm.auto_idlepc", {"id": self._router_id}, callback)
def idlepcs(self):
"""
Returns previously computed idle-pc values.

View File

@@ -537,6 +537,8 @@ class IOSRouterConfigurationPage(QtGui.QWidget, Ui_iosRouterConfigPageWidget):
# save the adapters and WICs configuration and
# check if a module port is connected before removing or replacing.
for slot_number, widget in self._widget_slots.items():
if not widget.isEnabled():
break
module = widget.currentText()
if module:
if settings["slot" + str(slot_number)] and settings["slot" + str(slot_number)] != module:
@@ -549,6 +551,8 @@ class IOSRouterConfigurationPage(QtGui.QWidget, Ui_iosRouterConfigPageWidget):
settings["slot" + str(slot_number)] = None
for wic_number, widget in self._widget_wics.items():
if not widget.isEnabled():
break
wic_name = str(widget.currentText())
if wic_name:
if settings["wic" + str(wic_number)] and settings["wic" + str(wic_number)] != wic_name:

View File

@@ -484,6 +484,7 @@ class IOSRouterPreferencesPage(QtGui.QWidget, Ui_IOSRouterPreferencesPageWidget)
if self._items:
self.uiIOSRoutersTreeWidget.setCurrentItem(self._items[0])
self.uiIOSRoutersTreeWidget.sortByColumn(0, QtCore.Qt.AscendingOrder)
def savePreferences(self):
"""

View File

@@ -117,6 +117,13 @@
</property>
</widget>
</item>
<item row="0" column="2">
<widget class="QPushButton" name="uiTestIOSImagePushButton">
<property name="text">
<string>&amp;Test IOS image</string>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWizardPage" name="uiNetworkAdaptersWizardPage">

View File

@@ -2,7 +2,7 @@
# Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/modules/dynamips/ui/ios_router_wizard.ui'
#
# Created: Fri Oct 10 10:43:48 2014
# Created: Mon Oct 13 16:55:45 2014
# by: PyQt4 UI code generator 4.10.4
#
# WARNING! All changes made in this file will be lost!
@@ -82,6 +82,9 @@ class Ui_IOSRouterWizard(object):
self.uiRamSpinBox.setProperty("value", 128)
self.uiRamSpinBox.setObjectName(_fromUtf8("uiRamSpinBox"))
self.gridLayout_2.addWidget(self.uiRamSpinBox, 0, 1, 1, 1)
self.uiTestIOSImagePushButton = QtGui.QPushButton(self.uiMemoryWizardPage)
self.uiTestIOSImagePushButton.setObjectName(_fromUtf8("uiTestIOSImagePushButton"))
self.gridLayout_2.addWidget(self.uiTestIOSImagePushButton, 0, 2, 1, 1)
IOSRouterWizard.addPage(self.uiMemoryWizardPage)
self.uiNetworkAdaptersWizardPage = QtGui.QWizardPage()
self.uiNetworkAdaptersWizardPage.setObjectName(_fromUtf8("uiNetworkAdaptersWizardPage"))
@@ -235,6 +238,7 @@ class Ui_IOSRouterWizard(object):
self.uiMemoryWizardPage.setSubTitle(_translate("IOSRouterWizard", "Please check the amount of memory (RAM) that you allocate to IOS. Not enough RAM could prevent IOS to start.", None))
self.uiRamLabel.setText(_translate("IOSRouterWizard", "RAM:", None))
self.uiRamSpinBox.setSuffix(_translate("IOSRouterWizard", " MiB", None))
self.uiTestIOSImagePushButton.setText(_translate("IOSRouterWizard", "&Test IOS image", None))
self.uiNetworkAdaptersWizardPage.setTitle(_translate("IOSRouterWizard", "Network adapters", None))
self.uiNetworkAdaptersWizardPage.setSubTitle(_translate("IOSRouterWizard", "Please choose the network adapters to insert in the router.", None))
self.uiSlot0Label.setText(_translate("IOSRouterWizard", "slot 0:", None))

View File

@@ -350,7 +350,7 @@ class IOUDevicePreferencesPage(QtGui.QWidget, Ui_IOUDevicePreferencesPageWidget)
if self._items:
self.uiIOUDevicesTreeWidget.setCurrentItem(self._items[0])
self.uiIOUDevicesTreeWidget.sortByColumn(0, QtCore.Qt.AscendingOrder)
def savePreferences(self):
"""

View File

@@ -278,6 +278,7 @@ class QemuVMPreferencesPage(QtGui.QWidget, Ui_QemuVMPreferencesPageWidget):
if self._items:
self.uiQemuVMsTreeWidget.setCurrentItem(self._items[0])
self.uiQemuVMsTreeWidget.sortByColumn(0, QtCore.Qt.AscendingOrder)
def savePreferences(self):
"""

View File

@@ -101,11 +101,12 @@ class virtualBoxVMConfigurationPage(QtGui.QWidget, Ui_virtualBoxVMConfigPageWidg
# in the node configurator.
if not group:
name = self.uiNameLineEdit.text()
if not name:
QtGui.QMessageBox.critical(self, "Name", "VirtualBox name cannot be empty!")
else:
settings["name"] = name
if "name" in settings:
name = self.uiNameLineEdit.text()
if not name:
QtGui.QMessageBox.critical(self, "Name", "VirtualBox name cannot be empty!")
else:
settings["name"] = name
settings["console"] = self.uiConsolePortSpinBox.value()
settings["enable_console"] = self.uiEnableConsoleCheckBox.isChecked()

View File

@@ -251,6 +251,7 @@ class VirtualBoxVMPreferencesPage(QtGui.QWidget, Ui_VirtualBoxVMPreferencesPageW
if self._items:
self.uiVirtualBoxVMsTreeWidget.setCurrentItem(self._items[0])
self.uiVirtualBoxVMsTreeWidget.sortByColumn(0, QtCore.Qt.AscendingOrder)
def savePreferences(self):
"""

View File

@@ -55,6 +55,8 @@ class NodesView(QtGui.QTreeWidget):
item.setText(0, node["name"])
item.setData(0, QtCore.Qt.UserRole, node)
self.sortByColumn(0, QtCore.Qt.AscendingOrder)
def mouseMoveEvent(self, event):
"""
Handles all mouse move events.

72
gns3/ui/exec_command_dialog.ui Executable file
View File

@@ -0,0 +1,72 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>ExecCommandDialog</class>
<widget class="QDialog" name="ExecCommandDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>651</width>
<height>343</height>
</rect>
</property>
<property name="windowTitle">
<string>Command execution</string>
</property>
<property name="modal">
<bool>true</bool>
</property>
<layout class="QGridLayout" name="gridLayout">
<item row="0" column="0" colspan="2">
<widget class="QPlainTextEdit" name="uiOutputTextEdit"/>
</item>
<item row="1" column="1">
<widget class="QDialogButtonBox" name="uiButtonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources>
<include location="../../resources/resources.qrc"/>
</resources>
<connections>
<connection>
<sender>uiButtonBox</sender>
<signal>accepted()</signal>
<receiver>ExecCommandDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>uiButtonBox</sender>
<signal>rejected()</signal>
<receiver>ExecCommandDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@@ -0,0 +1,50 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/ui/exec_command_dialog.ui'
#
# Created: Mon Oct 13 17:41:51 2014
# by: PyQt4 UI code generator 4.10.4
#
# 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_ExecCommandDialog(object):
def setupUi(self, ExecCommandDialog):
ExecCommandDialog.setObjectName(_fromUtf8("ExecCommandDialog"))
ExecCommandDialog.resize(651, 343)
ExecCommandDialog.setModal(True)
self.gridLayout = QtGui.QGridLayout(ExecCommandDialog)
self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
self.uiOutputTextEdit = QtGui.QPlainTextEdit(ExecCommandDialog)
self.uiOutputTextEdit.setObjectName(_fromUtf8("uiOutputTextEdit"))
self.gridLayout.addWidget(self.uiOutputTextEdit, 0, 0, 1, 2)
self.uiButtonBox = QtGui.QDialogButtonBox(ExecCommandDialog)
self.uiButtonBox.setOrientation(QtCore.Qt.Horizontal)
self.uiButtonBox.setStandardButtons(QtGui.QDialogButtonBox.Ok)
self.uiButtonBox.setObjectName(_fromUtf8("uiButtonBox"))
self.gridLayout.addWidget(self.uiButtonBox, 1, 1, 1, 1)
self.retranslateUi(ExecCommandDialog)
QtCore.QObject.connect(self.uiButtonBox, QtCore.SIGNAL(_fromUtf8("accepted()")), ExecCommandDialog.accept)
QtCore.QObject.connect(self.uiButtonBox, QtCore.SIGNAL(_fromUtf8("rejected()")), ExecCommandDialog.reject)
QtCore.QMetaObject.connectSlotsByName(ExecCommandDialog)
def retranslateUi(self, ExecCommandDialog):
ExecCommandDialog.setWindowTitle(_translate("ExecCommandDialog", "Command execution", None))
from . import resources_rc

View File

@@ -38,16 +38,7 @@ background-none;
</property>
<widget class="QWidget" name="uiCentralWidget">
<layout class="QGridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<property name="margin">
<number>0</number>
</property>
<property name="spacing">
@@ -71,7 +62,7 @@ background-none;
<x>0</x>
<y>0</y>
<width>980</width>
<height>22</height>
<height>25</height>
</rect>
</property>
<widget class="QMenu" name="uiEditMenu">
@@ -232,16 +223,7 @@ background-none;
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<property name="margin">
<number>0</number>
</property>
<item>
@@ -361,16 +343,7 @@ background-none;
<property name="spacing">
<number>0</number>
</property>
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<property name="margin">
<number>0</number>
</property>
<item>
@@ -434,16 +407,7 @@ background-none;
</attribute>
<widget class="QWidget" name="uiTopologySummaryDockWidgetContents">
<layout class="QGridLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<property name="margin">
<number>0</number>
</property>
<property name="spacing">
@@ -479,16 +443,7 @@ background-none;
</attribute>
<widget class="QWidget" name="uiCloudInspectorDockWidgetContents">
<layout class="QVBoxLayout" name="verticalLayout">
<property name="leftMargin">
<number>0</number>
</property>
<property name="topMargin">
<number>0</number>
</property>
<property name="rightMargin">
<number>0</number>
</property>
<property name="bottomMargin">
<property name="margin">
<number>0</number>
</property>
<item>

View File

@@ -1,8 +1,8 @@
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file '/Users/masci/devel/gns3/gns3-gui/gns3/ui/main_window.ui'
# Form implementation generated from reading ui file '/home/grossmj/PycharmProjects/gns3-gui/gns3/ui/main_window.ui'
#
# Created: Mon Sep 22 14:03:57 2014
# Created: Fri Oct 10 23:10:53 2014
# by: PyQt4 UI code generator 4.10.4
#
# WARNING! All changes made in this file will be lost!
@@ -48,8 +48,8 @@ class Ui_MainWindow(object):
self.uiCentralWidget = QtGui.QWidget(MainWindow)
self.uiCentralWidget.setObjectName(_fromUtf8("uiCentralWidget"))
self.gridlayout = QtGui.QGridLayout(self.uiCentralWidget)
self.gridlayout.setSpacing(0)
self.gridlayout.setMargin(0)
self.gridlayout.setSpacing(0)
self.gridlayout.setObjectName(_fromUtf8("gridlayout"))
self.uiGraphicsView = GraphicsView(self.uiCentralWidget)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
@@ -61,7 +61,7 @@ class Ui_MainWindow(object):
self.gridlayout.addWidget(self.uiGraphicsView, 0, 0, 1, 1)
MainWindow.setCentralWidget(self.uiCentralWidget)
self.uiMenuBar = QtGui.QMenuBar(MainWindow)
self.uiMenuBar.setGeometry(QtCore.QRect(0, 0, 980, 22))
self.uiMenuBar.setGeometry(QtCore.QRect(0, 0, 980, 25))
self.uiMenuBar.setObjectName(_fromUtf8("uiMenuBar"))
self.uiEditMenu = QtGui.QMenu(self.uiMenuBar)
self.uiEditMenu.setObjectName(_fromUtf8("uiEditMenu"))
@@ -166,8 +166,8 @@ class Ui_MainWindow(object):
self.uiTopologySummaryDockWidgetContents = QtGui.QWidget()
self.uiTopologySummaryDockWidgetContents.setObjectName(_fromUtf8("uiTopologySummaryDockWidgetContents"))
self.gridlayout1 = QtGui.QGridLayout(self.uiTopologySummaryDockWidgetContents)
self.gridlayout1.setSpacing(0)
self.gridlayout1.setMargin(0)
self.gridlayout1.setSpacing(0)
self.gridlayout1.setObjectName(_fromUtf8("gridlayout1"))
self.uiTopologySummaryTreeWidget = TopologySummaryView(self.uiTopologySummaryDockWidgetContents)
sizePolicy = QtGui.QSizePolicy(QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Expanding)
@@ -650,9 +650,9 @@ class Ui_MainWindow(object):
self.uiFitInViewAction.setText(_translate("MainWindow", "Fit in view", None))
self.uiExportProjectAction.setText(_translate("MainWindow", "Export project", None))
from ..nodes_view import NodesView
from ..console_view import ConsoleView
from ..cloud_inspector_view import CloudInspectorView
from ..console_view import ConsoleView
from ..nodes_view import NodesView
from ..graphics_view import GraphicsView
from ..topology_summary_view import TopologySummaryView
from . import resources_rc