mirror of
https://github.com/GNS3/gns3-gui.git
synced 2026-05-17 00:46:01 +03:00
Merge branch 'master' into 1.5
This commit is contained in:
135
gns3/dialogs/console_command_dialog.py
Normal file
135
gns3/dialogs/console_command_dialog.py
Normal file
@@ -0,0 +1,135 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
#
|
||||
# Copyright (C) 2016 GNS3 Technologies Inc.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import sys
|
||||
import copy
|
||||
|
||||
from gns3.qt import QtWidgets
|
||||
from gns3.local_config import LocalConfig
|
||||
from gns3.ui.console_command_dialog_ui import Ui_uiConsoleCommandDialog
|
||||
from gns3.settings import PRECONFIGURED_TELNET_CONSOLE_COMMANDS, \
|
||||
PRECONFIGURED_SERIAL_CONSOLE_COMMANDS, \
|
||||
PRECONFIGURED_VNC_CONSOLE_COMMANDS, \
|
||||
CUSTOM_CONSOLE_COMMANDS_SETTINGS
|
||||
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ConsoleCommandDialog(QtWidgets.QDialog, Ui_uiConsoleCommandDialog):
|
||||
"""
|
||||
This dialog allow user to select the command used to start a
|
||||
console.
|
||||
"""
|
||||
|
||||
def __init__(self, parent, console_type="telnet", current=None):
|
||||
"""
|
||||
:params console_type: telnet, serial or vnc
|
||||
:params current: Current console command
|
||||
"""
|
||||
super().__init__(parent)
|
||||
self.setupUi(self)
|
||||
self._console_type = console_type
|
||||
self._current = current
|
||||
|
||||
self._settings = LocalConfig.instance().loadSectionSettings("CustomConsoleCommands", CUSTOM_CONSOLE_COMMANDS_SETTINGS)
|
||||
|
||||
self.uiCommandComboBox.currentIndexChanged.connect(self.commandComboBoxCurrentIndexChangedSlot)
|
||||
self.uiCommandPlainTextEdit.textChanged.connect(self.textChangedSlot)
|
||||
self.uiSavePushButton.clicked.connect(self.savePushButtonClickedSlot)
|
||||
self.uiRemovePushButton.clicked.connect(self.removePushButtonClickedSlot)
|
||||
|
||||
self._refreshList()
|
||||
|
||||
def _refreshList(self):
|
||||
if self._console_type == "telnet":
|
||||
self._consoles = copy.copy(PRECONFIGURED_TELNET_CONSOLE_COMMANDS)
|
||||
self._consoles.update(self._settings[self._console_type])
|
||||
elif self._console_type == "vnc":
|
||||
self._consoles = copy.copy(PRECONFIGURED_VNC_CONSOLE_COMMANDS)
|
||||
self._consoles.update(self._settings[self._console_type])
|
||||
else:
|
||||
self._consoles = copy.copy(PRECONFIGURED_SERIAL_CONSOLE_COMMANDS)
|
||||
self._consoles.update(self._settings[self._console_type])
|
||||
|
||||
self.uiCommandComboBox.clear()
|
||||
self.uiCommandComboBox.addItem("Custom", "")
|
||||
for name, cmd in sorted(self._consoles.items(), key=(lambda item: item[0].lower())):
|
||||
self.uiCommandComboBox.addItem(name, cmd)
|
||||
|
||||
if self._current:
|
||||
self.uiCommandPlainTextEdit.setPlainText(self._current)
|
||||
else:
|
||||
self.uiCommandComboBox.setCurrentIndex(1)
|
||||
|
||||
def removePushButtonClickedSlot(self):
|
||||
"""
|
||||
Remove the custom command from the custom list
|
||||
"""
|
||||
self._settings[self._console_type].pop(self.uiCommandComboBox.currentText())
|
||||
LocalConfig.instance().saveSectionSettings("CustomConsoleCommands", self._settings)
|
||||
self._current = None
|
||||
self._refreshList()
|
||||
|
||||
def savePushButtonClickedSlot(self):
|
||||
"""
|
||||
Save a custom command to the list
|
||||
"""
|
||||
name, ok = QtWidgets.QInputDialog.getText(self, "Add a command", "Command name:", QtWidgets.QLineEdit.Normal)
|
||||
command = self.uiCommandPlainTextEdit.toPlainText().strip()
|
||||
if ok and len(command) > 0:
|
||||
if command not in self._consoles.values():
|
||||
self._settings[self._console_type][name] = command
|
||||
self._current = command
|
||||
LocalConfig.instance().saveSectionSettings("CustomConsoleCommands", self._settings)
|
||||
self._refreshList()
|
||||
|
||||
def textChangedSlot(self):
|
||||
index = self.uiCommandComboBox.findData(self.uiCommandPlainTextEdit.toPlainText())
|
||||
if index == -1:
|
||||
index = 0
|
||||
self.uiCommandComboBox.setCurrentIndex(index)
|
||||
|
||||
def commandComboBoxCurrentIndexChangedSlot(self, index):
|
||||
self.uiRemovePushButton.hide()
|
||||
# Ignore custom command
|
||||
if index != 0:
|
||||
self.uiCommandPlainTextEdit.setPlainText(self.uiCommandComboBox.currentData())
|
||||
self.uiSavePushButton.hide()
|
||||
if self.uiCommandComboBox.currentText() in self._settings[self._console_type].keys():
|
||||
self.uiRemovePushButton.show()
|
||||
else:
|
||||
self.uiSavePushButton.show()
|
||||
|
||||
@staticmethod
|
||||
def getCommand(parent, console_type="telnet", current=None):
|
||||
dialog = ConsoleCommandDialog(parent, console_type=console_type, current=current)
|
||||
dialog.show()
|
||||
if dialog.exec_():
|
||||
return (True, dialog.uiCommandPlainTextEdit.toPlainText().replace("\n", " "))
|
||||
return (False, None)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
app = QtWidgets.QApplication(sys.argv)
|
||||
main = QtWidgets.QMainWindow()
|
||||
(ok, command) = ConsoleCommandDialog.getCommand(main, console_type="telnet", current=list(PRECONFIGURED_TELNET_CONSOLE_COMMANDS.items())[0][1])
|
||||
print(ok)
|
||||
print(command)
|
||||
|
||||
@@ -167,6 +167,19 @@ class DoctorDialog(QtWidgets.QDialog, Ui_DoctorDialog):
|
||||
return(2, "Dynamips require CAP_NET_RAW. Run sudo setcap cap_net_raw,cap_net_admin+eip {path}".format(path=path))
|
||||
return (0, None)
|
||||
|
||||
def checkGNS3InstalledTwice(self):
|
||||
"""Check if gns3 is not installed twice"""
|
||||
|
||||
if not sys.platform.startswith("win"):
|
||||
return (0, None)
|
||||
|
||||
try:
|
||||
if os.path.exists("/usr/local/bin/gns3server") and os.path.exists("/usr/bin/gns3server"):
|
||||
return(2, "GNS3 is installed twice please remove it from /usr/local/bin")
|
||||
except OSError:
|
||||
pass
|
||||
return (0, None)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
|
||||
@@ -41,6 +41,7 @@ from .dialogs.style_editor_dialog import StyleEditorDialog
|
||||
from .dialogs.text_editor_dialog import TextEditorDialog
|
||||
from .dialogs.symbol_selection_dialog import SymbolSelectionDialog
|
||||
from .dialogs.idlepc_dialog import IdlePCDialog
|
||||
from .dialogs.console_command_dialog import ConsoleCommandDialog
|
||||
from .local_config import LocalConfig
|
||||
from .progress import Progress
|
||||
from .utils.server_select import server_select
|
||||
@@ -760,6 +761,12 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
console_action.triggered.connect(self.consoleActionSlot)
|
||||
menu.addAction(console_action)
|
||||
|
||||
if True in list(map(lambda item: isinstance(item, NodeItem) and hasattr(item.node(), "console"), items)):
|
||||
console_edit_action = QtWidgets.QAction("Edit console", menu)
|
||||
console_edit_action.setIcon(QtGui.QIcon(':/icons/console_edit.svg'))
|
||||
console_edit_action.triggered.connect(self.consoleEditActionSlot)
|
||||
menu.addAction(console_edit_action)
|
||||
|
||||
if True in list(map(lambda item: isinstance(item, NodeItem) and hasattr(item.node(), "auxConsole"), items)):
|
||||
aux_console_action = QtWidgets.QAction("Auxiliary console", menu)
|
||||
aux_console_action.setIcon(QtGui.QIcon(':/icons/aux-console.svg'))
|
||||
@@ -1006,38 +1013,11 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
# returns True to ignore this node.
|
||||
return True
|
||||
|
||||
if hasattr(node, "serialConsole") and node.serialConsole():
|
||||
try:
|
||||
from .serial_console import serialConsole
|
||||
serialConsole(node.name(), node.serialPipe())
|
||||
except (OSError, ValueError) as e:
|
||||
QtWidgets.QMessageBox.critical(self, "Console", "Cannot start serial console application: {}".format(e))
|
||||
return False
|
||||
else:
|
||||
name = node.name()
|
||||
if aux:
|
||||
console_port = node.auxConsole()
|
||||
if console_port is None:
|
||||
QtWidgets.QMessageBox.critical(self, "Console", "AUX console port not allocated for {}".format(name))
|
||||
return False
|
||||
else:
|
||||
console_port = node.console()
|
||||
|
||||
console_type = "telnet"
|
||||
if "console_type" in node.settings():
|
||||
console_type = node.settings()["console_type"]
|
||||
|
||||
try:
|
||||
from .telnet_console import nodeTelnetConsole
|
||||
from .vnc_console import vncConsole
|
||||
|
||||
if console_type == "telnet":
|
||||
nodeTelnetConsole(name, node.server(), console_port)
|
||||
elif console_type == "vnc":
|
||||
vncConsole(node.server().host(), console_port)
|
||||
except (OSError, ValueError) as e:
|
||||
QtWidgets.QMessageBox.critical(self, "Console", "Cannot start console application: {}".format(e))
|
||||
return False
|
||||
try:
|
||||
node.openConsole(aux)
|
||||
except (OSError, ValueError) as e:
|
||||
QtWidgets.QMessageBox.critical(self, "Console", "Cannot start console application: {}".format(e))
|
||||
return False
|
||||
return True
|
||||
|
||||
def consoleFromItems(self, items):
|
||||
@@ -1069,6 +1049,25 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
|
||||
self.consoleFromItems(self.scene().selectedItems())
|
||||
|
||||
def consoleEditActionSlot(self):
|
||||
"""
|
||||
Allow user to use a custom console for this VM
|
||||
"""
|
||||
|
||||
current_cmd = None
|
||||
console_type = "telnet"
|
||||
for item in self.scene().selectedItems():
|
||||
if isinstance(item, NodeItem) and hasattr(item.node(), "console"):
|
||||
current_cmd = item.node().consoleCommand()
|
||||
console_type = item.node().consoleType()
|
||||
|
||||
(ok, cmd) = ConsoleCommandDialog.getCommand(self, console_type=console_type, current=current_cmd)
|
||||
if ok:
|
||||
for item in self.scene().selectedItems():
|
||||
if isinstance(item, NodeItem) and hasattr(item.node(), "console"):
|
||||
node = item.node()
|
||||
node.setCustomConsoleCommand(cmd)
|
||||
|
||||
def auxConsoleFromItems(self, items):
|
||||
"""
|
||||
Aux console from scene items.
|
||||
|
||||
@@ -186,6 +186,8 @@ class NodeItem():
|
||||
when a the node has been updated.
|
||||
"""
|
||||
|
||||
if self is None:
|
||||
return
|
||||
if self._node_label:
|
||||
if self._node_label.toPlainText() != self._node.name():
|
||||
self._node_label.setPlainText(self._node.name())
|
||||
|
||||
@@ -289,33 +289,6 @@ class MainWindow(QtWidgets.QMainWindow, Ui_MainWindow):
|
||||
self._project = project
|
||||
self._setCurrentFile(project.topologyFile())
|
||||
|
||||
def telnetConsoleCommand(self):
|
||||
"""
|
||||
Returns the Telnet console command line.
|
||||
|
||||
:returns: command (string)
|
||||
"""
|
||||
|
||||
return self._settings["telnet_console_command"]
|
||||
|
||||
def serialConsoleCommand(self):
|
||||
"""
|
||||
Returns the Serial console command line.
|
||||
|
||||
:returns: command (string)
|
||||
"""
|
||||
|
||||
return self._settings["serial_console_command"]
|
||||
|
||||
def vncConsoleCommand(self):
|
||||
"""
|
||||
Returns the VNC command line.
|
||||
|
||||
:returns: command (string)
|
||||
"""
|
||||
|
||||
return self._settings["vnc_console_command"]
|
||||
|
||||
def setUnsavedState(self):
|
||||
"""
|
||||
Sets the project in a unsaved state.
|
||||
|
||||
@@ -200,14 +200,9 @@ class DockerVM(VM):
|
||||
|
||||
:returns: representation of the node (dictionary)
|
||||
"""
|
||||
container = {
|
||||
"id": self.id(),
|
||||
"vm_id": self._vm_id,
|
||||
"type": self.__class__.__name__,
|
||||
"description": str(self),
|
||||
"properties": {},
|
||||
"server_id": self._server.id()
|
||||
}
|
||||
docker = super().dump()
|
||||
docker["id"] = self.id()
|
||||
docker["vm_id"] = self._vm_id
|
||||
|
||||
# add the properties
|
||||
for name, value in self._settings.items():
|
||||
@@ -259,13 +254,13 @@ class DockerVM(VM):
|
||||
|
||||
:param node_info: representation of the node (dictionary)
|
||||
"""
|
||||
|
||||
super().load(node_info)
|
||||
|
||||
settings = node_info["properties"]
|
||||
name = settings.pop("name")
|
||||
image = settings.pop("image")
|
||||
log.info("Docker container {} is loading".format(name))
|
||||
self._loading = True
|
||||
self._node_info = node_info
|
||||
self.loaded_signal.connect(self._updatePortSettings)
|
||||
self.setup(image, name=name, additional_settings=settings)
|
||||
|
||||
def _updatePortSettings(self):
|
||||
|
||||
@@ -340,10 +340,8 @@ class Router(VM):
|
||||
: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["message"])
|
||||
return
|
||||
if not super()._updateCallback(result, error=error, **kwargs):
|
||||
return False
|
||||
|
||||
updated = False
|
||||
for name, value in result.items():
|
||||
@@ -599,25 +597,15 @@ class Router(VM):
|
||||
:returns: representation of the node (dictionary)
|
||||
"""
|
||||
|
||||
router = {"id": self.id(),
|
||||
"vm_id": self._vm_id,
|
||||
"dynamips_id": self._dynamips_id,
|
||||
"type": self.__class__.__name__,
|
||||
"description": str(self),
|
||||
"properties": {},
|
||||
"server_id": self._server.id()}
|
||||
router = super().dump()
|
||||
router["vm_id"] = self._vm_id
|
||||
router["dynamips_id"] = self._dynamips_id
|
||||
|
||||
# add the properties
|
||||
for name, value in self._settings.items():
|
||||
if value is not None and value != "":
|
||||
router["properties"][name] = value
|
||||
|
||||
# add the ports
|
||||
if self._ports:
|
||||
ports = router["ports"] = []
|
||||
for port in self._ports:
|
||||
ports.append(port.dump())
|
||||
|
||||
return router
|
||||
|
||||
def load(self, node_info):
|
||||
@@ -628,6 +616,8 @@ class Router(VM):
|
||||
:param node_info: representation of the node (dictionary)
|
||||
"""
|
||||
|
||||
super().load(node_info)
|
||||
|
||||
# for backward compatibility
|
||||
vm_id = dynamips_id = node_info.get("router_id")
|
||||
if not vm_id:
|
||||
@@ -657,35 +647,8 @@ class Router(VM):
|
||||
|
||||
log.info("router {} is loading".format(name))
|
||||
self.setName(name)
|
||||
self._loading = True
|
||||
self._node_info = node_info
|
||||
self.loaded_signal.connect(self._updatePortSettings)
|
||||
self.setup(image, ram, name, vm_id, dynamips_id, vm_settings)
|
||||
|
||||
def _updatePortSettings(self):
|
||||
"""
|
||||
Updates port settings when loading a topology.
|
||||
"""
|
||||
|
||||
self.loaded_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.get("adapter_number", None) == port.adapterNumber() or topology_port.get("slot_number", None) == port.adapterNumber()):
|
||||
port.setName(topology_port["name"])
|
||||
port.setId(topology_port["id"])
|
||||
|
||||
# now we can set the node as initialized and trigger the created signal
|
||||
self.setInitialized(True)
|
||||
log.info("router {} has been loaded".format(self.name()))
|
||||
self.created_signal.emit(self.id())
|
||||
self._module.addNode(self)
|
||||
self._loading = False
|
||||
self._node_info = None
|
||||
|
||||
def saveConfig(self):
|
||||
"""
|
||||
Save the configs
|
||||
|
||||
@@ -241,10 +241,8 @@ class IOUDevice(VM):
|
||||
: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["message"])
|
||||
return
|
||||
if not super()._updateCallback(result, error=error, **kwargs):
|
||||
return False
|
||||
|
||||
updated = False
|
||||
nb_adapters_changed = False
|
||||
@@ -323,24 +321,14 @@ class IOUDevice(VM):
|
||||
:returns: representation of the node (dictionary)
|
||||
"""
|
||||
|
||||
iou = {"id": self.id(),
|
||||
"vm_id": self._vm_id,
|
||||
"type": self.__class__.__name__,
|
||||
"description": str(self),
|
||||
"properties": {},
|
||||
"server_id": self._server.id()}
|
||||
iou = super().dump()
|
||||
iou["vm_id"] = self._vm_id
|
||||
|
||||
# add the properties
|
||||
for name, value in self._settings.items():
|
||||
if value is not None and value != "":
|
||||
iou["properties"][name] = value
|
||||
|
||||
# add the ports
|
||||
if self._ports:
|
||||
ports = iou["ports"] = []
|
||||
for port in self._ports:
|
||||
ports.append(port.dump())
|
||||
|
||||
return iou
|
||||
|
||||
def load(self, node_info):
|
||||
@@ -351,6 +339,8 @@ class IOUDevice(VM):
|
||||
:param node_info: representation of the node (dictionary)
|
||||
"""
|
||||
|
||||
super().load(node_info)
|
||||
|
||||
# for backward compatibility
|
||||
vm_id = node_info.get("iou_id")
|
||||
if not vm_id:
|
||||
@@ -382,30 +372,6 @@ class IOUDevice(VM):
|
||||
self.loaded_signal.connect(self._updatePortSettings)
|
||||
self.setup(path, name, vm_id, vm_settings)
|
||||
|
||||
def _updatePortSettings(self):
|
||||
"""
|
||||
Updates port settings when loading a topology.
|
||||
"""
|
||||
|
||||
self.loaded_signal.disconnect(self._updatePortSettings)
|
||||
|
||||
# assign the correct names and IDs to the ports
|
||||
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.get("adapter_number", None) == port.adapterNumber() or topology_port.get("slot_number", None) == port.adapterNumber()):
|
||||
port.setName(topology_port["name"])
|
||||
port.setId(topology_port["id"])
|
||||
|
||||
# now we can set the node as initialized and trigger the created signal
|
||||
self.setInitialized(True)
|
||||
log.info("IOU device {} has been loaded".format(self.name()))
|
||||
self.created_signal.emit(self.id())
|
||||
self._module.addNode(self)
|
||||
self._loading = False
|
||||
self._node_info = None
|
||||
|
||||
def saveConfig(self):
|
||||
"""
|
||||
Save the configs
|
||||
|
||||
@@ -207,10 +207,8 @@ class QemuVM(VM):
|
||||
: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["message"])
|
||||
return
|
||||
if not super()._updateCallback(result, error=error, **kwargs):
|
||||
return False
|
||||
|
||||
updated = False
|
||||
nb_adapters_changed = False
|
||||
@@ -296,14 +294,10 @@ class QemuVM(VM):
|
||||
:returns: representation of the node (dictionary)
|
||||
"""
|
||||
|
||||
qemu_vm = {"id": self.id(),
|
||||
"vm_id": self._vm_id,
|
||||
"linked_clone": self._linked_clone,
|
||||
"type": self.__class__.__name__,
|
||||
"description": str(self),
|
||||
"properties": {},
|
||||
"port_name_format": self._port_name_format,
|
||||
"server_id": self._server.id()}
|
||||
qemu_vm = super().dump()
|
||||
qemu_vm["vm_id"] = self._vm_id
|
||||
qemu_vm["linked_clone"] = self._linked_clone
|
||||
qemu_vm["port_name_format"] = self._port_name_format
|
||||
|
||||
if self._port_segment_size:
|
||||
qemu_vm["port_segment_size"] = self._port_segment_size
|
||||
@@ -315,12 +309,6 @@ class QemuVM(VM):
|
||||
if value is not None and value != "":
|
||||
qemu_vm["properties"][name] = value
|
||||
|
||||
# add the ports
|
||||
if self._ports:
|
||||
ports = qemu_vm["ports"] = []
|
||||
for port in self._ports:
|
||||
ports.append(port.dump())
|
||||
|
||||
return qemu_vm
|
||||
|
||||
def info(self):
|
||||
@@ -369,6 +357,7 @@ class QemuVM(VM):
|
||||
:param node_info: representation of the node (dictionary)
|
||||
"""
|
||||
|
||||
super().load(node_info)
|
||||
# for backward compatibility
|
||||
vm_id = node_info.get("qemu_id")
|
||||
if not vm_id:
|
||||
@@ -387,36 +376,8 @@ class QemuVM(VM):
|
||||
qemu_path = vm_settings.pop("qemu_path")
|
||||
log.info("QEMU VM {} is loading".format(name))
|
||||
self.setName(name)
|
||||
self._loading = True
|
||||
self._node_info = node_info
|
||||
self.loaded_signal.connect(self._updatePortSettings)
|
||||
self.setup(qemu_path, name, vm_id, port_name_format, port_segment_size, first_port_name, linked_clone, vm_settings)
|
||||
|
||||
def _updatePortSettings(self):
|
||||
"""
|
||||
Updates port settings when loading a topology.
|
||||
"""
|
||||
|
||||
self.loaded_signal.disconnect(self._updatePortSettings)
|
||||
|
||||
# assign the correct names and IDs to the ports
|
||||
if "ports" in self._node_info:
|
||||
ports = self._node_info["ports"]
|
||||
for topology_port in ports:
|
||||
for port in self._ports:
|
||||
adapter_number = topology_port.get("adapter_number", topology_port["port_number"])
|
||||
if adapter_number == port.adapterNumber():
|
||||
port.setName(topology_port["name"])
|
||||
port.setId(topology_port["id"])
|
||||
|
||||
# now we can set the node as initialized and trigger the created signal
|
||||
self.setInitialized(True)
|
||||
log.info("QEMU VM {} has been loaded".format(self.name()))
|
||||
self.created_signal.emit(self.id())
|
||||
self._module.addNode(self)
|
||||
self._loading = False
|
||||
self._node_info = None
|
||||
|
||||
def name(self):
|
||||
"""
|
||||
Returns the name of this QEMU VM instance.
|
||||
|
||||
@@ -188,10 +188,8 @@ class VirtualBoxVM(VM):
|
||||
: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["message"])
|
||||
return
|
||||
if not super()._updateCallback(result, error=error, **kwargs):
|
||||
return False
|
||||
|
||||
updated = False
|
||||
nb_adapters_changed = False
|
||||
@@ -293,14 +291,10 @@ class VirtualBoxVM(VM):
|
||||
:returns: representation of the node (dictionary)
|
||||
"""
|
||||
|
||||
vbox_vm = {"id": self.id(),
|
||||
"vm_id": self._vm_id,
|
||||
"linked_clone": self._linked_clone,
|
||||
"type": self.__class__.__name__,
|
||||
"description": str(self),
|
||||
"properties": {},
|
||||
"port_name_format": self._port_name_format,
|
||||
"server_id": self._server.id()}
|
||||
vbox_vm = super().dump()
|
||||
vbox_vm["vm_id"] = self._vm_id
|
||||
vbox_vm["linked_clone"] = self._linked_clone
|
||||
vbox_vm["port_name_format"] = self._port_name_format
|
||||
|
||||
if self._port_segment_size:
|
||||
vbox_vm["port_segment_size"] = self._port_segment_size
|
||||
@@ -312,12 +306,6 @@ class VirtualBoxVM(VM):
|
||||
if value is not None and value != "":
|
||||
vbox_vm["properties"][name] = value
|
||||
|
||||
# add the ports
|
||||
if self._ports:
|
||||
ports = vbox_vm["ports"] = []
|
||||
for port in self._ports:
|
||||
ports.append(port.dump())
|
||||
|
||||
return vbox_vm
|
||||
|
||||
def load(self, node_info):
|
||||
@@ -328,6 +316,8 @@ class VirtualBoxVM(VM):
|
||||
:param node_info: representation of the node (dictionary)
|
||||
"""
|
||||
|
||||
super().load(node_info)
|
||||
|
||||
# for backward compatibility
|
||||
vm_id = node_info.get("vbox_id")
|
||||
if not vm_id:
|
||||
@@ -347,36 +337,8 @@ class VirtualBoxVM(VM):
|
||||
|
||||
log.info("VirtualBox VM {} is loading".format(name))
|
||||
self.setName(name)
|
||||
self._loading = True
|
||||
self._node_info = node_info
|
||||
self.loaded_signal.connect(self._updatePortSettings)
|
||||
self.setup(vmname, name, vm_id, port_name_format, port_segment_size, first_port_name, linked_clone, vm_settings)
|
||||
|
||||
def _updatePortSettings(self):
|
||||
"""
|
||||
Updates port settings when loading a topology.
|
||||
"""
|
||||
|
||||
self.loaded_signal.disconnect(self._updatePortSettings)
|
||||
|
||||
# assign the correct names and IDs to the ports
|
||||
if "ports" in self._node_info:
|
||||
ports = self._node_info["ports"]
|
||||
for topology_port in ports:
|
||||
for port in self._ports:
|
||||
adapter_number = topology_port.get("adapter_number", topology_port["port_number"])
|
||||
if adapter_number == port.adapterNumber():
|
||||
port.setName(topology_port["name"])
|
||||
port.setId(topology_port["id"])
|
||||
|
||||
# now we can set the node as initialized and trigger the created signal
|
||||
self.setInitialized(True)
|
||||
log.info("VirtualBox VM {} has been loaded".format(self.name()))
|
||||
self.created_signal.emit(self.id())
|
||||
self._module.addNode(self)
|
||||
self._loading = False
|
||||
self._node_info = None
|
||||
|
||||
def name(self):
|
||||
"""
|
||||
Returns the name of this VirtualBox VM instance.
|
||||
|
||||
@@ -191,10 +191,8 @@ class VMwareVM(VM):
|
||||
: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["message"])
|
||||
return
|
||||
if not super()._updateCallback(result, error=error, **kwargs):
|
||||
return False
|
||||
|
||||
updated = False
|
||||
nb_adapters_changed = False
|
||||
@@ -300,14 +298,10 @@ class VMwareVM(VM):
|
||||
:returns: representation of the node (dictionary)
|
||||
"""
|
||||
|
||||
vmware_vm = {"id": self.id(),
|
||||
"vm_id": self._vm_id,
|
||||
"linked_clone": self._linked_clone,
|
||||
"type": self.__class__.__name__,
|
||||
"description": str(self),
|
||||
"properties": {},
|
||||
"port_name_format": self._port_name_format,
|
||||
"server_id": self._server.id()}
|
||||
vmware_vm = super().dump()
|
||||
vmware_vm["vm_id"] = self._vm_id
|
||||
vmware_vm["linked_clone"] = self._linked_clone
|
||||
vmware_vm["port_name_format"] = self._port_name_format
|
||||
|
||||
if self._port_segment_size:
|
||||
vmware_vm["port_segment_size"] = self._port_segment_size
|
||||
@@ -319,12 +313,6 @@ class VMwareVM(VM):
|
||||
if value is not None and value != "":
|
||||
vmware_vm["properties"][name] = value
|
||||
|
||||
# add the ports
|
||||
if self._ports:
|
||||
ports = vmware_vm["ports"] = []
|
||||
for port in self._ports:
|
||||
ports.append(port.dump())
|
||||
|
||||
return vmware_vm
|
||||
|
||||
def load(self, node_info):
|
||||
@@ -335,6 +323,8 @@ class VMwareVM(VM):
|
||||
:param node_info: representation of the node (dictionary)
|
||||
"""
|
||||
|
||||
super().load(node_info)
|
||||
|
||||
vm_id = node_info["vm_id"]
|
||||
linked_clone = node_info.get("linked_clone", False)
|
||||
port_name_format = node_info.get("port_name_format", "Ethernet{0}")
|
||||
@@ -350,35 +340,8 @@ class VMwareVM(VM):
|
||||
|
||||
log.info("VMware VM {} is loading".format(name))
|
||||
self.setName(name)
|
||||
self._loading = True
|
||||
self._node_info = node_info
|
||||
self.loaded_signal.connect(self._updatePortSettings)
|
||||
self.setup(vmx_path, name, vm_id, port_name_format, port_segment_size, first_port_name, linked_clone, vm_settings)
|
||||
|
||||
def _updatePortSettings(self):
|
||||
"""
|
||||
Updates port settings when loading a topology.
|
||||
"""
|
||||
|
||||
self.loaded_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:
|
||||
adapter_number = topology_port.get("adapter_number")
|
||||
if adapter_number == port.adapterNumber():
|
||||
port.setName(topology_port["name"])
|
||||
port.setId(topology_port["id"])
|
||||
|
||||
# now we can set the node as initialized and trigger the created signal
|
||||
self.setInitialized(True)
|
||||
log.info("VMware VM {} has been loaded".format(self.name()))
|
||||
self.created_signal.emit(self.id())
|
||||
self._module.addNode(self)
|
||||
self._loading = False
|
||||
self._node_info = None
|
||||
|
||||
def allocateVMnetInterface(self, port_id):
|
||||
"""
|
||||
Requests an UDP port allocation.
|
||||
|
||||
@@ -157,10 +157,8 @@ class VPCSDevice(VM):
|
||||
: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["message"])
|
||||
return
|
||||
if not super()._updateCallback(result, error=error, **kwargs):
|
||||
return False
|
||||
|
||||
updated = False
|
||||
for name, value in result.items():
|
||||
@@ -218,12 +216,8 @@ class VPCSDevice(VM):
|
||||
:returns: representation of the node (dictionary)
|
||||
"""
|
||||
|
||||
vpcs_device = {"id": self.id(),
|
||||
"vm_id": self._vm_id,
|
||||
"type": self.__class__.__name__,
|
||||
"description": str(self),
|
||||
"properties": {},
|
||||
"server_id": self._server.id()}
|
||||
vpcs_device = super().dump()
|
||||
vpcs_device["vm_id"] = self._vm_id
|
||||
|
||||
# add the properties
|
||||
for name, value in self._settings.items():
|
||||
@@ -233,12 +227,6 @@ class VPCSDevice(VM):
|
||||
value = os.path.basename(value)
|
||||
vpcs_device["properties"][name] = value
|
||||
|
||||
# add the ports
|
||||
if self._ports:
|
||||
ports = vpcs_device["ports"] = []
|
||||
for port in self._ports:
|
||||
ports.append(port.dump())
|
||||
|
||||
return vpcs_device
|
||||
|
||||
def load(self, node_info):
|
||||
@@ -249,6 +237,8 @@ class VPCSDevice(VM):
|
||||
:param node_info: representation of the node (dictionary)
|
||||
"""
|
||||
|
||||
super().load(node_info)
|
||||
|
||||
# for backward compatibility
|
||||
vm_id = node_info.get("vpcs_id")
|
||||
if not vm_id:
|
||||
@@ -263,35 +253,8 @@ class VPCSDevice(VM):
|
||||
|
||||
log.info("VPCS device {} is loading".format(name))
|
||||
self.setName(name)
|
||||
self._loading = True
|
||||
self._node_info = node_info
|
||||
self.loaded_signal.connect(self._updatePortSettings)
|
||||
self.setup(name, vm_id, vm_settings)
|
||||
|
||||
def _updatePortSettings(self):
|
||||
"""
|
||||
Updates port settings when loading a topology.
|
||||
"""
|
||||
|
||||
self.loaded_signal.disconnect(self._updatePortSettings)
|
||||
|
||||
# assign the correct names and IDs to the ports
|
||||
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():
|
||||
port.setName(topology_port["name"])
|
||||
port.setId(topology_port["id"])
|
||||
|
||||
# now we can set the node as initialized and trigger the created signal
|
||||
self.setInitialized(True)
|
||||
log.info("VPCS device {} has been loaded".format(self.name()))
|
||||
self.created_signal.emit(self.id())
|
||||
self._module.addNode(self)
|
||||
self._loading = False
|
||||
self._node_info = None
|
||||
|
||||
def exportConfig(self, config_export_path):
|
||||
"""
|
||||
Exports the script file.
|
||||
|
||||
@@ -26,9 +26,9 @@ import json
|
||||
from gns3.qt import QtGui, QtCore, QtWidgets
|
||||
from gns3.local_config import LocalConfig
|
||||
from ..ui.general_preferences_page_ui import Ui_GeneralPreferencesPageWidget
|
||||
from ..settings import GRAPHICS_VIEW_SETTINGS, GENERAL_SETTINGS, PRECONFIGURED_TELNET_CONSOLE_COMMANDS, \
|
||||
PRECONFIGURED_SERIAL_CONSOLE_COMMANDS, PRECONFIGURED_VNC_CONSOLE_COMMANDS, STYLES
|
||||
from gns3.servers import Servers
|
||||
from ..settings import GRAPHICS_VIEW_SETTINGS, GENERAL_SETTINGS, STYLES
|
||||
from ..dialogs.console_command_dialog import ConsoleCommandDialog
|
||||
|
||||
|
||||
class GeneralPreferencesPage(QtWidgets.QWidget, Ui_GeneralPreferencesPageWidget):
|
||||
@@ -44,14 +44,6 @@ class GeneralPreferencesPage(QtWidgets.QWidget, Ui_GeneralPreferencesPageWidget)
|
||||
self._remote_servers = {}
|
||||
self._preferences_dialog = parent
|
||||
|
||||
# Load the pre-configured console & VNC commands
|
||||
for name, cmd in sorted(PRECONFIGURED_TELNET_CONSOLE_COMMANDS.items()):
|
||||
self.uiTelnetConsolePreconfiguredCommandComboBox.addItem(name, cmd)
|
||||
for name, cmd in sorted(PRECONFIGURED_SERIAL_CONSOLE_COMMANDS.items()):
|
||||
self.uiSerialConsolePreconfiguredCommandComboBox.addItem(name, cmd)
|
||||
for name, cmd in sorted(PRECONFIGURED_VNC_CONSOLE_COMMANDS.items()):
|
||||
self.uiVNCConsolePreconfiguredCommandComboBox.addItem(name, cmd)
|
||||
|
||||
# Display the path of the config file
|
||||
config_file_path = LocalConfig.instance().configFilePath()
|
||||
self.uiConfigurationFileLabel.setText(config_file_path)
|
||||
@@ -136,30 +128,30 @@ class GeneralPreferencesPage(QtWidgets.QWidget, Ui_GeneralPreferencesPageWidget)
|
||||
Slot to set a chosen pre-configured Telnet console command.
|
||||
"""
|
||||
|
||||
self.uiTelnetConsoleCommandLineEdit.clear()
|
||||
command = self.uiTelnetConsolePreconfiguredCommandComboBox.itemData(self.uiTelnetConsolePreconfiguredCommandComboBox.currentIndex(), QtCore.Qt.UserRole)
|
||||
self.uiTelnetConsoleCommandLineEdit.setText(command)
|
||||
self.uiTelnetConsoleCommandLineEdit.setCursorPosition(0)
|
||||
cmd = self.uiTelnetConsoleCommandLineEdit.text()
|
||||
(ok, cmd) = ConsoleCommandDialog.getCommand(self, console_type="telnet", current=cmd)
|
||||
if ok:
|
||||
self.uiTelnetConsoleCommandLineEdit.setText(cmd)
|
||||
|
||||
def _serialConsolePreconfiguredCommandSlot(self):
|
||||
"""
|
||||
Slot to set a chosen pre-configured serial console command.
|
||||
"""
|
||||
|
||||
self.uiSerialConsoleCommandLineEdit.clear()
|
||||
command = self.uiSerialConsolePreconfiguredCommandComboBox.itemData(self.uiSerialConsolePreconfiguredCommandComboBox.currentIndex(), QtCore.Qt.UserRole)
|
||||
self.uiSerialConsoleCommandLineEdit.setText(command)
|
||||
self.uiSerialConsoleCommandLineEdit.setCursorPosition(0)
|
||||
cmd = self.uiSerialConsoleCommandLineEdit.text()
|
||||
(ok, cmd) = ConsoleCommandDialog.getCommand(self, console_type="serial", current=cmd)
|
||||
if ok:
|
||||
self.uiSerialConsoleCommandLineEdit.setText(cmd)
|
||||
|
||||
def _vncConsolePreconfiguredCommandSlot(self):
|
||||
"""
|
||||
Slot to set a chosen pre-configured VNC console command.
|
||||
"""
|
||||
|
||||
self.uiVNCConsoleCommandLineEdit.clear()
|
||||
command = self.uiVNCConsolePreconfiguredCommandComboBox.itemData(self.uiVNCConsolePreconfiguredCommandComboBox.currentIndex(), QtCore.Qt.UserRole)
|
||||
self.uiVNCConsoleCommandLineEdit.setText(command)
|
||||
self.uiVNCConsoleCommandLineEdit.setCursorPosition(0)
|
||||
cmd = self.uiVNCConsoleCommandLineEdit.text()
|
||||
(ok, cmd) = ConsoleCommandDialog.getCommand(self, console_type="vnc", current=cmd)
|
||||
if ok:
|
||||
self.uiVNCConsoleCommandLineEdit.setText(cmd)
|
||||
|
||||
def _importConfigurationFileSlot(self):
|
||||
"""
|
||||
@@ -262,23 +254,14 @@ class GeneralPreferencesPage(QtWidgets.QWidget, Ui_GeneralPreferencesPageWidget)
|
||||
index = self.uiStyleComboBox.findText(settings["style"])
|
||||
if index != -1:
|
||||
self.uiStyleComboBox.setCurrentIndex(index)
|
||||
index = self.uiTelnetConsolePreconfiguredCommandComboBox.findData(settings["telnet_console_command"])
|
||||
if index != -1:
|
||||
self.uiTelnetConsolePreconfiguredCommandComboBox.setCurrentIndex(index)
|
||||
self.uiSerialConsoleCommandLineEdit.setText(settings["serial_console_command"])
|
||||
self.uiSerialConsoleCommandLineEdit.setCursorPosition(0)
|
||||
index = self.uiSerialConsolePreconfiguredCommandComboBox.findData(settings["serial_console_command"])
|
||||
if index != -1:
|
||||
self.uiSerialConsolePreconfiguredCommandComboBox.setCurrentIndex(index)
|
||||
self.uiCloseConsoleWindowsOnDeleteCheckBox.setChecked(settings["auto_close_console"])
|
||||
self.uiBringConsoleWindowToFrontCheckBox.setChecked(settings["bring_console_to_front"])
|
||||
self.uiDelayConsoleAllSpinBox.setValue(settings["delay_console_all"])
|
||||
|
||||
self.uiVNCConsoleCommandLineEdit.setText(settings["vnc_console_command"])
|
||||
self.uiVNCConsoleCommandLineEdit.setCursorPosition(0)
|
||||
index = self.uiVNCConsolePreconfiguredCommandComboBox.findData(settings["vnc_console_command"])
|
||||
if index != -1:
|
||||
self.uiVNCConsolePreconfiguredCommandComboBox.setCurrentIndex(index)
|
||||
|
||||
def _populateGraphicsViewSettingWidgets(self, settings):
|
||||
"""
|
||||
|
||||
@@ -28,6 +28,7 @@ For PyQt4 and PyQt5 differences please see http://pyqt.sourceforge.net/Docs/PyQt
|
||||
import sys
|
||||
import sip
|
||||
import os
|
||||
import re
|
||||
import functools
|
||||
import inspect
|
||||
|
||||
@@ -105,23 +106,6 @@ class QFileDialog(OldFileDialog):
|
||||
QtWidgets.QFileDialog = QFileDialog
|
||||
|
||||
|
||||
class StatsQtWidgetsQDialog(QtWidgets.QDialog):
|
||||
"""
|
||||
Send stats from all the QWizard
|
||||
"""
|
||||
|
||||
def __init__(self, *args):
|
||||
super().__init__(*args)
|
||||
|
||||
import re
|
||||
from .utils.analytics import AnalyticsClient
|
||||
name = self.__class__.__name__
|
||||
name = re.sub(r"([A-Z])", r" \1", name).strip()
|
||||
AnalyticsClient.instance().sendScreenView(name)
|
||||
|
||||
QtWidgets.QDialog = StatsQtWidgetsQDialog
|
||||
|
||||
|
||||
class LogQMessageBox(QtWidgets.QMessageBox):
|
||||
"""
|
||||
Replace the standard message box for logging errors to console. And
|
||||
@@ -148,39 +132,6 @@ class LogQMessageBox(QtWidgets.QMessageBox):
|
||||
QtWidgets.QMessageBox = LogQMessageBox
|
||||
|
||||
|
||||
class StatsQtWidgetsQWizard(QtWidgets.QWizard):
|
||||
"""
|
||||
Send stats from all the QWizard
|
||||
"""
|
||||
|
||||
def __init__(self, *args):
|
||||
super().__init__(*args)
|
||||
|
||||
import re
|
||||
from .utils.analytics import AnalyticsClient
|
||||
name = self.__class__.__name__
|
||||
name = re.sub(r"([A-Z])", r" \1", name).strip()
|
||||
AnalyticsClient.instance().sendScreenView(name)
|
||||
|
||||
QtWidgets.QWizard = StatsQtWidgetsQWizard
|
||||
|
||||
|
||||
class StatsQtWidgetsQMainWindow(QtWidgets.QMainWindow):
|
||||
"""
|
||||
Send stats from all the QMainWindow
|
||||
"""
|
||||
|
||||
def __init__(self, *args):
|
||||
super().__init__(*args)
|
||||
|
||||
import re
|
||||
from .utils.analytics import AnalyticsClient
|
||||
name = self.__class__.__name__
|
||||
name = re.sub(r"([A-Z])", r" \1", name).strip()
|
||||
AnalyticsClient.instance().sendScreenView(name)
|
||||
|
||||
QtWidgets.QMainWindow = StatsQtWidgetsQMainWindow
|
||||
|
||||
# If we run from a test we replace the signal by a synchronous version
|
||||
if hasattr(sys, '_called_from_test'):
|
||||
class FakeQtSignal:
|
||||
@@ -212,6 +163,54 @@ if hasattr(sys, '_called_from_test'):
|
||||
QtCore.pyqtSignal = FakeQtSignal
|
||||
|
||||
|
||||
class StatsQtWidgetsQWizard(QtWidgets.QWizard):
|
||||
"""
|
||||
Send stats from all the QWizard
|
||||
"""
|
||||
|
||||
def __init__(self, *args):
|
||||
super().__init__(*args)
|
||||
|
||||
from ..utils.analytics import AnalyticsClient
|
||||
name = self.__class__.__name__
|
||||
name = re.sub(r"([A-Z])", r" \1", name).strip()
|
||||
AnalyticsClient.instance().sendScreenView(name)
|
||||
|
||||
QtWidgets.QWizard = StatsQtWidgetsQWizard
|
||||
|
||||
|
||||
class StatsQtWidgetsQMainWindow(QtWidgets.QMainWindow):
|
||||
"""
|
||||
Send stats from all the QMainWindow
|
||||
"""
|
||||
|
||||
def __init__(self, *args):
|
||||
super().__init__(*args)
|
||||
|
||||
from ..utils.analytics import AnalyticsClient
|
||||
name = self.__class__.__name__
|
||||
name = re.sub(r"([A-Z])", r" \1", name).strip()
|
||||
AnalyticsClient.instance().sendScreenView(name)
|
||||
|
||||
QtWidgets.QMainWindow = StatsQtWidgetsQMainWindow
|
||||
|
||||
|
||||
class StatsQtWidgetsQDialog(QtWidgets.QDialog):
|
||||
"""
|
||||
Send stats from all the QWizard
|
||||
"""
|
||||
|
||||
def __init__(self, *args):
|
||||
super().__init__(*args)
|
||||
|
||||
from ..utils.analytics import AnalyticsClient
|
||||
name = self.__class__.__name__
|
||||
name = re.sub(r"([A-Z])", r" \1", name).strip()
|
||||
AnalyticsClient.instance().sendScreenView(name)
|
||||
|
||||
QtWidgets.QDialog = StatsQtWidgetsQDialog
|
||||
|
||||
|
||||
def qpartial(func, *args, **kwargs):
|
||||
"""
|
||||
A functools partial that you can use on qobject. If the targeted qobject is
|
||||
@@ -230,3 +229,4 @@ def qpartial(func, *args, **kwargs):
|
||||
return functools.partial(partial, *args, **kwargs)
|
||||
|
||||
return functools.partial(func, *args, **kwargs)
|
||||
|
||||
@@ -291,6 +291,7 @@
|
||||
"x": { "type": "number" },
|
||||
"y": { "type": "number" },
|
||||
"z": { "type": "number" },
|
||||
"custom_console_command": { "$ref": "#/definitions/mandatory_string" },
|
||||
"properties": {
|
||||
"type": "object",
|
||||
"oneOf": [
|
||||
|
||||
@@ -28,10 +28,8 @@ from .main_window import MainWindow
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
# TODO: support more than just Vbox (Qemu maybe?)
|
||||
|
||||
|
||||
def serialConsole(vmname, pipe_path):
|
||||
def serialConsole(vmname, pipe_path, command):
|
||||
"""
|
||||
:param vmname: Virtual machine name.
|
||||
:param pipe_path: Virtual machine serial pipe path.
|
||||
@@ -39,10 +37,6 @@ def serialConsole(vmname, pipe_path):
|
||||
Start a Serial console program.
|
||||
"""
|
||||
|
||||
command = MainWindow.instance().serialConsoleCommand()
|
||||
if not command:
|
||||
return
|
||||
|
||||
# replace the place-holders by the actual values
|
||||
command = command.replace("%s", pipe_path)
|
||||
command = command.replace("%d", vmname)
|
||||
|
||||
@@ -93,6 +93,9 @@ class ServerSummaryView(QtWidgets.QTreeWidget):
|
||||
def __init__(self, parent):
|
||||
|
||||
super().__init__(parent)
|
||||
|
||||
self._servers = set()
|
||||
|
||||
Servers.instance().server_added_signal.connect(self._serverAddedSlot)
|
||||
for server in Servers.instance().servers():
|
||||
self._serverAddedSlot(server.url())
|
||||
@@ -103,6 +106,10 @@ class ServerSummaryView(QtWidgets.QTreeWidget):
|
||||
|
||||
:params url: URL of the server
|
||||
"""
|
||||
|
||||
if url in self._servers:
|
||||
return
|
||||
self._servers.add(url)
|
||||
server = Servers.instance().getServerFromString(url)
|
||||
ServerItem(self, server)
|
||||
|
||||
|
||||
@@ -322,3 +322,9 @@ PACKET_CAPTURE_SETTINGS = {
|
||||
"command_auto_start": True,
|
||||
"packet_capture_analyzer_command": DEFAULT_PACKET_CAPTURE_ANALYZER_COMMAND,
|
||||
}
|
||||
|
||||
CUSTOM_CONSOLE_COMMANDS_SETTINGS = {
|
||||
"telnet": {},
|
||||
"vnc": {},
|
||||
"serial": {}
|
||||
}
|
||||
|
||||
@@ -84,19 +84,16 @@ class ConsoleThread(QtCore.QThread):
|
||||
console_mutex.unlock()
|
||||
|
||||
|
||||
def nodeTelnetConsole(name, server, port):
|
||||
def nodeTelnetConsole(name, server, port, command):
|
||||
"""
|
||||
Start a Telnet console program for a topology node.
|
||||
|
||||
:param name: Name of the console
|
||||
:param port: Port number of the console on remote host
|
||||
:param server: Server where the console is running
|
||||
:param command: Console command
|
||||
"""
|
||||
|
||||
command = MainWindow.instance().telnetConsoleCommand()
|
||||
if not command:
|
||||
return
|
||||
|
||||
log.info('Starting telnet console in thread "{}"'.format(command))
|
||||
console_thread = ConsoleThread(MainWindow.instance(), command, name, server, port)
|
||||
console_thread.consoleError.connect(_consoleErrorSlot)
|
||||
@@ -117,7 +114,8 @@ def telnetConsole(name, host, port):
|
||||
:param server: Server where the console is running
|
||||
"""
|
||||
|
||||
command = MainWindow.instance().telnetConsoleCommand()
|
||||
general_settings = MainWindow.instance().settings()
|
||||
command = general_settings["telnet_console_command"]
|
||||
if not command:
|
||||
return
|
||||
|
||||
|
||||
137
gns3/ui/console_command_dialog.ui
Normal file
137
gns3/ui/console_command_dialog.ui
Normal file
@@ -0,0 +1,137 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>uiConsoleCommandDialog</class>
|
||||
<widget class="QDialog" name="uiConsoleCommandDialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>524</width>
|
||||
<height>350</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Command</string>
|
||||
</property>
|
||||
<property name="modal">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="sizeConstraint">
|
||||
<enum>QLayout::SetFixedSize</enum>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>Choose a predefined command:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QComboBox" name="uiCommandComboBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="uiRemovePushButton">
|
||||
<property name="text">
|
||||
<string>Remove</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="uiSavePushButton">
|
||||
<property name="text">
|
||||
<string>Save</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string><html><head/><body><p>Or customize the command in the next input field. <br/>The following variables are replaced by GNS3: </p><ul style="margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;"><li style=" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%h: console IP or hostname</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%p: console port</li><li style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%s: path of the serial connection</li><li style=" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">%d: title of the console</li></ul></body></html></string>
|
||||
</property>
|
||||
<property name="textFormat">
|
||||
<enum>Qt::RichText</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPlainTextEdit" name="uiCommandPlainTextEdit">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>500</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="uiButtonBox">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>uiButtonBox</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>uiConsoleCommandDialog</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>uiConsoleCommandDialog</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>
|
||||
71
gns3/ui/console_command_dialog_ui.py
Normal file
71
gns3/ui/console_command_dialog_ui.py
Normal file
@@ -0,0 +1,71 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Form implementation generated from reading ui file '/Users/noplay/code/gns3/gns3-gui/gns3/ui/console_command_dialog.ui'
|
||||
#
|
||||
# Created by: PyQt5 UI code generator 5.5.1
|
||||
#
|
||||
# WARNING! All changes made in this file will be lost!
|
||||
|
||||
from PyQt5 import QtCore, QtGui, QtWidgets
|
||||
|
||||
class Ui_uiConsoleCommandDialog(object):
|
||||
def setupUi(self, uiConsoleCommandDialog):
|
||||
uiConsoleCommandDialog.setObjectName("uiConsoleCommandDialog")
|
||||
uiConsoleCommandDialog.resize(524, 350)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(uiConsoleCommandDialog.sizePolicy().hasHeightForWidth())
|
||||
uiConsoleCommandDialog.setSizePolicy(sizePolicy)
|
||||
uiConsoleCommandDialog.setMinimumSize(QtCore.QSize(0, 0))
|
||||
uiConsoleCommandDialog.setModal(True)
|
||||
self.verticalLayout = QtWidgets.QVBoxLayout(uiConsoleCommandDialog)
|
||||
self.verticalLayout.setSizeConstraint(QtWidgets.QLayout.SetFixedSize)
|
||||
self.verticalLayout.setObjectName("verticalLayout")
|
||||
self.label_2 = QtWidgets.QLabel(uiConsoleCommandDialog)
|
||||
self.label_2.setObjectName("label_2")
|
||||
self.verticalLayout.addWidget(self.label_2)
|
||||
self.horizontalLayout = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName("horizontalLayout")
|
||||
self.uiCommandComboBox = QtWidgets.QComboBox(uiConsoleCommandDialog)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.uiCommandComboBox.sizePolicy().hasHeightForWidth())
|
||||
self.uiCommandComboBox.setSizePolicy(sizePolicy)
|
||||
self.uiCommandComboBox.setObjectName("uiCommandComboBox")
|
||||
self.horizontalLayout.addWidget(self.uiCommandComboBox)
|
||||
self.uiRemovePushButton = QtWidgets.QPushButton(uiConsoleCommandDialog)
|
||||
self.uiRemovePushButton.setObjectName("uiRemovePushButton")
|
||||
self.horizontalLayout.addWidget(self.uiRemovePushButton)
|
||||
self.uiSavePushButton = QtWidgets.QPushButton(uiConsoleCommandDialog)
|
||||
self.uiSavePushButton.setObjectName("uiSavePushButton")
|
||||
self.horizontalLayout.addWidget(self.uiSavePushButton)
|
||||
self.verticalLayout.addLayout(self.horizontalLayout)
|
||||
self.label = QtWidgets.QLabel(uiConsoleCommandDialog)
|
||||
self.label.setTextFormat(QtCore.Qt.RichText)
|
||||
self.label.setObjectName("label")
|
||||
self.verticalLayout.addWidget(self.label)
|
||||
self.uiCommandPlainTextEdit = QtWidgets.QPlainTextEdit(uiConsoleCommandDialog)
|
||||
self.uiCommandPlainTextEdit.setMinimumSize(QtCore.QSize(500, 0))
|
||||
self.uiCommandPlainTextEdit.setObjectName("uiCommandPlainTextEdit")
|
||||
self.verticalLayout.addWidget(self.uiCommandPlainTextEdit)
|
||||
self.uiButtonBox = QtWidgets.QDialogButtonBox(uiConsoleCommandDialog)
|
||||
self.uiButtonBox.setOrientation(QtCore.Qt.Horizontal)
|
||||
self.uiButtonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Ok)
|
||||
self.uiButtonBox.setObjectName("uiButtonBox")
|
||||
self.verticalLayout.addWidget(self.uiButtonBox)
|
||||
|
||||
self.retranslateUi(uiConsoleCommandDialog)
|
||||
self.uiButtonBox.accepted.connect(uiConsoleCommandDialog.accept)
|
||||
self.uiButtonBox.rejected.connect(uiConsoleCommandDialog.reject)
|
||||
QtCore.QMetaObject.connectSlotsByName(uiConsoleCommandDialog)
|
||||
|
||||
def retranslateUi(self, uiConsoleCommandDialog):
|
||||
_translate = QtCore.QCoreApplication.translate
|
||||
uiConsoleCommandDialog.setWindowTitle(_translate("uiConsoleCommandDialog", "Command"))
|
||||
self.label_2.setText(_translate("uiConsoleCommandDialog", "Choose a predefined command:"))
|
||||
self.uiRemovePushButton.setText(_translate("uiConsoleCommandDialog", "Remove"))
|
||||
self.uiSavePushButton.setText(_translate("uiConsoleCommandDialog", "Save"))
|
||||
self.label.setText(_translate("uiConsoleCommandDialog", "<html><head/><body><p>Or customize the command in the next input field. <br/>The following variables are replaced by GNS3: </p><ul style=\"margin-top: 0px; margin-bottom: 0px; margin-left: 0px; margin-right: 0px; -qt-list-indent: 1;\"><li style=\" margin-top:12px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%h: console IP or hostname</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%p: console port</li><li style=\" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%s: path of the serial connection</li><li style=\" margin-top:0px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;\">%d: title of the console</li></ul></body></html>"))
|
||||
|
||||
@@ -256,103 +256,88 @@
|
||||
<item>
|
||||
<widget class="QGroupBox" name="uiTelnetConsoleSettingsGroupBox">
|
||||
<property name="title">
|
||||
<string>Console settings for Telnet connections</string>
|
||||
<string>Console settings</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_4">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="uiTelnetConsolePreconfiguredCommandLabel">
|
||||
<property name="text">
|
||||
<string>Preconfigured commands:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QComboBox" name="uiTelnetConsolePreconfiguredCommandComboBox"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_9">
|
||||
<item>
|
||||
<widget class="QLabel" name="uiTelnetConsoleCommandLabel">
|
||||
<property name="text">
|
||||
<string>Console application command:</string>
|
||||
<string>Console application command for Telnet:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="QLineEdit" name="uiTelnetConsoleCommandLineEdit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Command line replacements:</p><p>%h = device server </p><p>%p = device port</p><p>%d = device hostname</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="uiTelnetConsoleCommandLineEdit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Command line replacements:</p><p>%h = device server </p><p>%p = device port</p><p>%d = device hostname</p></body></html></string>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="uiTelnetConsolePreconfiguredCommandPushButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Edit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="uiTelnetConsolePreconfiguredCommandPushButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Set</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="uiSerialConsoleSettingsGroupBox">
|
||||
<property name="title">
|
||||
<string>Console settings for local serial connections</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_5">
|
||||
<item row="3" column="0">
|
||||
<item>
|
||||
<widget class="QLabel" name="uiSerialConsoleCommandLabel">
|
||||
<property name="text">
|
||||
<string>Console application command:</string>
|
||||
<string>Console application command for Serial:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="uiSerialConsolePreconfiguredCommandLabel">
|
||||
<property name="text">
|
||||
<string>Preconfigured commands:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QComboBox" name="uiSerialConsolePreconfiguredCommandComboBox"/>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="QLineEdit" name="uiSerialConsoleCommandLineEdit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Command line replacements:</p><p>%d = device hostname</p><p>%s = device pipe file</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="uiSerialConsolePreconfiguredCommandPushButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Set</string>
|
||||
</property>
|
||||
</widget>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_10">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="uiSerialConsoleCommandLineEdit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Command line replacements:</p><p>%d = device hostname</p><p>%s = device pipe file</p></body></html></string>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="uiSerialConsolePreconfiguredCommandPushButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Edit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
@@ -428,49 +413,46 @@
|
||||
<property name="title">
|
||||
<string>Settings for VNC connections</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_6">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="uiVNCConsolePreconfiguredCommandLabel">
|
||||
<property name="text">
|
||||
<string>Preconfigured commands:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QComboBox" name="uiVNCConsolePreconfiguredCommandComboBox"/>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_8">
|
||||
<item>
|
||||
<widget class="QLabel" name="uiVNCConsoleCommandLabel">
|
||||
<property name="text">
|
||||
<string>Console application command:</string>
|
||||
<string>Console application command for VNC:</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<widget class="QLineEdit" name="uiVNCConsoleCommandLineEdit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Command line replacements:</p><p>%h = device server </p><p>%p = device port</p><p>%d = device hostname</p></body></html></string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="uiVNCConsolePreconfiguredCommandPushButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Set</string>
|
||||
</property>
|
||||
</widget>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<item>
|
||||
<widget class="QLineEdit" name="uiVNCConsoleCommandLineEdit">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string><html><head/><body><p>Command line replacements:</p><p>%h = device server </p><p>%p = device port</p><p>%d = device hostname</p></body></html></string>
|
||||
</property>
|
||||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="uiVNCConsolePreconfiguredCommandPushButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Edit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
||||
@@ -142,25 +142,22 @@ class Ui_GeneralPreferencesPageWidget(object):
|
||||
self.verticalLayout_3.setObjectName("verticalLayout_3")
|
||||
self.uiTelnetConsoleSettingsGroupBox = QtWidgets.QGroupBox(self.uiConsoleTab)
|
||||
self.uiTelnetConsoleSettingsGroupBox.setObjectName("uiTelnetConsoleSettingsGroupBox")
|
||||
self.gridLayout_4 = QtWidgets.QGridLayout(self.uiTelnetConsoleSettingsGroupBox)
|
||||
self.gridLayout_4.setObjectName("gridLayout_4")
|
||||
self.uiTelnetConsolePreconfiguredCommandLabel = QtWidgets.QLabel(self.uiTelnetConsoleSettingsGroupBox)
|
||||
self.uiTelnetConsolePreconfiguredCommandLabel.setObjectName("uiTelnetConsolePreconfiguredCommandLabel")
|
||||
self.gridLayout_4.addWidget(self.uiTelnetConsolePreconfiguredCommandLabel, 0, 0, 1, 1)
|
||||
self.uiTelnetConsolePreconfiguredCommandComboBox = QtWidgets.QComboBox(self.uiTelnetConsoleSettingsGroupBox)
|
||||
self.uiTelnetConsolePreconfiguredCommandComboBox.setObjectName("uiTelnetConsolePreconfiguredCommandComboBox")
|
||||
self.gridLayout_4.addWidget(self.uiTelnetConsolePreconfiguredCommandComboBox, 1, 0, 1, 1)
|
||||
self.verticalLayout_9 = QtWidgets.QVBoxLayout(self.uiTelnetConsoleSettingsGroupBox)
|
||||
self.verticalLayout_9.setObjectName("verticalLayout_9")
|
||||
self.uiTelnetConsoleCommandLabel = QtWidgets.QLabel(self.uiTelnetConsoleSettingsGroupBox)
|
||||
self.uiTelnetConsoleCommandLabel.setObjectName("uiTelnetConsoleCommandLabel")
|
||||
self.gridLayout_4.addWidget(self.uiTelnetConsoleCommandLabel, 3, 0, 1, 1)
|
||||
self.verticalLayout_9.addWidget(self.uiTelnetConsoleCommandLabel)
|
||||
self.horizontalLayout_9 = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout_9.setObjectName("horizontalLayout_9")
|
||||
self.uiTelnetConsoleCommandLineEdit = QtWidgets.QLineEdit(self.uiTelnetConsoleSettingsGroupBox)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.uiTelnetConsoleCommandLineEdit.sizePolicy().hasHeightForWidth())
|
||||
self.uiTelnetConsoleCommandLineEdit.setSizePolicy(sizePolicy)
|
||||
self.uiTelnetConsoleCommandLineEdit.setReadOnly(True)
|
||||
self.uiTelnetConsoleCommandLineEdit.setObjectName("uiTelnetConsoleCommandLineEdit")
|
||||
self.gridLayout_4.addWidget(self.uiTelnetConsoleCommandLineEdit, 4, 0, 1, 2)
|
||||
self.horizontalLayout_9.addWidget(self.uiTelnetConsoleCommandLineEdit)
|
||||
self.uiTelnetConsolePreconfiguredCommandPushButton = QtWidgets.QPushButton(self.uiTelnetConsoleSettingsGroupBox)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
@@ -168,38 +165,32 @@ class Ui_GeneralPreferencesPageWidget(object):
|
||||
sizePolicy.setHeightForWidth(self.uiTelnetConsolePreconfiguredCommandPushButton.sizePolicy().hasHeightForWidth())
|
||||
self.uiTelnetConsolePreconfiguredCommandPushButton.setSizePolicy(sizePolicy)
|
||||
self.uiTelnetConsolePreconfiguredCommandPushButton.setObjectName("uiTelnetConsolePreconfiguredCommandPushButton")
|
||||
self.gridLayout_4.addWidget(self.uiTelnetConsolePreconfiguredCommandPushButton, 1, 1, 1, 1)
|
||||
self.verticalLayout_3.addWidget(self.uiTelnetConsoleSettingsGroupBox)
|
||||
self.uiSerialConsoleSettingsGroupBox = QtWidgets.QGroupBox(self.uiConsoleTab)
|
||||
self.uiSerialConsoleSettingsGroupBox.setObjectName("uiSerialConsoleSettingsGroupBox")
|
||||
self.gridLayout_5 = QtWidgets.QGridLayout(self.uiSerialConsoleSettingsGroupBox)
|
||||
self.gridLayout_5.setObjectName("gridLayout_5")
|
||||
self.uiSerialConsoleCommandLabel = QtWidgets.QLabel(self.uiSerialConsoleSettingsGroupBox)
|
||||
self.horizontalLayout_9.addWidget(self.uiTelnetConsolePreconfiguredCommandPushButton)
|
||||
self.verticalLayout_9.addLayout(self.horizontalLayout_9)
|
||||
self.uiSerialConsoleCommandLabel = QtWidgets.QLabel(self.uiTelnetConsoleSettingsGroupBox)
|
||||
self.uiSerialConsoleCommandLabel.setObjectName("uiSerialConsoleCommandLabel")
|
||||
self.gridLayout_5.addWidget(self.uiSerialConsoleCommandLabel, 3, 0, 1, 1)
|
||||
self.uiSerialConsolePreconfiguredCommandLabel = QtWidgets.QLabel(self.uiSerialConsoleSettingsGroupBox)
|
||||
self.uiSerialConsolePreconfiguredCommandLabel.setObjectName("uiSerialConsolePreconfiguredCommandLabel")
|
||||
self.gridLayout_5.addWidget(self.uiSerialConsolePreconfiguredCommandLabel, 0, 0, 1, 1)
|
||||
self.uiSerialConsolePreconfiguredCommandComboBox = QtWidgets.QComboBox(self.uiSerialConsoleSettingsGroupBox)
|
||||
self.uiSerialConsolePreconfiguredCommandComboBox.setObjectName("uiSerialConsolePreconfiguredCommandComboBox")
|
||||
self.gridLayout_5.addWidget(self.uiSerialConsolePreconfiguredCommandComboBox, 1, 0, 1, 1)
|
||||
self.uiSerialConsoleCommandLineEdit = QtWidgets.QLineEdit(self.uiSerialConsoleSettingsGroupBox)
|
||||
self.verticalLayout_9.addWidget(self.uiSerialConsoleCommandLabel)
|
||||
self.horizontalLayout_10 = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout_10.setObjectName("horizontalLayout_10")
|
||||
self.uiSerialConsoleCommandLineEdit = QtWidgets.QLineEdit(self.uiTelnetConsoleSettingsGroupBox)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.uiSerialConsoleCommandLineEdit.sizePolicy().hasHeightForWidth())
|
||||
self.uiSerialConsoleCommandLineEdit.setSizePolicy(sizePolicy)
|
||||
self.uiSerialConsoleCommandLineEdit.setReadOnly(True)
|
||||
self.uiSerialConsoleCommandLineEdit.setObjectName("uiSerialConsoleCommandLineEdit")
|
||||
self.gridLayout_5.addWidget(self.uiSerialConsoleCommandLineEdit, 4, 0, 1, 2)
|
||||
self.uiSerialConsolePreconfiguredCommandPushButton = QtWidgets.QPushButton(self.uiSerialConsoleSettingsGroupBox)
|
||||
self.horizontalLayout_10.addWidget(self.uiSerialConsoleCommandLineEdit)
|
||||
self.uiSerialConsolePreconfiguredCommandPushButton = QtWidgets.QPushButton(self.uiTelnetConsoleSettingsGroupBox)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.uiSerialConsolePreconfiguredCommandPushButton.sizePolicy().hasHeightForWidth())
|
||||
self.uiSerialConsolePreconfiguredCommandPushButton.setSizePolicy(sizePolicy)
|
||||
self.uiSerialConsolePreconfiguredCommandPushButton.setObjectName("uiSerialConsolePreconfiguredCommandPushButton")
|
||||
self.gridLayout_5.addWidget(self.uiSerialConsolePreconfiguredCommandPushButton, 1, 1, 1, 1)
|
||||
self.verticalLayout_3.addWidget(self.uiSerialConsoleSettingsGroupBox)
|
||||
self.horizontalLayout_10.addWidget(self.uiSerialConsolePreconfiguredCommandPushButton)
|
||||
self.verticalLayout_9.addLayout(self.horizontalLayout_10)
|
||||
self.verticalLayout_3.addWidget(self.uiTelnetConsoleSettingsGroupBox)
|
||||
self.uiConsoleMiscGroupBox = QtWidgets.QGroupBox(self.uiConsoleTab)
|
||||
self.uiConsoleMiscGroupBox.setObjectName("uiConsoleMiscGroupBox")
|
||||
self.gridLayout_7 = QtWidgets.QGridLayout(self.uiConsoleMiscGroupBox)
|
||||
@@ -228,25 +219,22 @@ class Ui_GeneralPreferencesPageWidget(object):
|
||||
self.verticalLayout_6.setObjectName("verticalLayout_6")
|
||||
self.uiVNCConsoleSettingsGroupBox = QtWidgets.QGroupBox(self.uiVNCTab)
|
||||
self.uiVNCConsoleSettingsGroupBox.setObjectName("uiVNCConsoleSettingsGroupBox")
|
||||
self.gridLayout_6 = QtWidgets.QGridLayout(self.uiVNCConsoleSettingsGroupBox)
|
||||
self.gridLayout_6.setObjectName("gridLayout_6")
|
||||
self.uiVNCConsolePreconfiguredCommandLabel = QtWidgets.QLabel(self.uiVNCConsoleSettingsGroupBox)
|
||||
self.uiVNCConsolePreconfiguredCommandLabel.setObjectName("uiVNCConsolePreconfiguredCommandLabel")
|
||||
self.gridLayout_6.addWidget(self.uiVNCConsolePreconfiguredCommandLabel, 0, 0, 1, 1)
|
||||
self.uiVNCConsolePreconfiguredCommandComboBox = QtWidgets.QComboBox(self.uiVNCConsoleSettingsGroupBox)
|
||||
self.uiVNCConsolePreconfiguredCommandComboBox.setObjectName("uiVNCConsolePreconfiguredCommandComboBox")
|
||||
self.gridLayout_6.addWidget(self.uiVNCConsolePreconfiguredCommandComboBox, 1, 0, 1, 1)
|
||||
self.verticalLayout_8 = QtWidgets.QVBoxLayout(self.uiVNCConsoleSettingsGroupBox)
|
||||
self.verticalLayout_8.setObjectName("verticalLayout_8")
|
||||
self.uiVNCConsoleCommandLabel = QtWidgets.QLabel(self.uiVNCConsoleSettingsGroupBox)
|
||||
self.uiVNCConsoleCommandLabel.setObjectName("uiVNCConsoleCommandLabel")
|
||||
self.gridLayout_6.addWidget(self.uiVNCConsoleCommandLabel, 3, 0, 1, 1)
|
||||
self.verticalLayout_8.addWidget(self.uiVNCConsoleCommandLabel)
|
||||
self.horizontalLayout_8 = QtWidgets.QHBoxLayout()
|
||||
self.horizontalLayout_8.setObjectName("horizontalLayout_8")
|
||||
self.uiVNCConsoleCommandLineEdit = QtWidgets.QLineEdit(self.uiVNCConsoleSettingsGroupBox)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.MinimumExpanding, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.uiVNCConsoleCommandLineEdit.sizePolicy().hasHeightForWidth())
|
||||
self.uiVNCConsoleCommandLineEdit.setSizePolicy(sizePolicy)
|
||||
self.uiVNCConsoleCommandLineEdit.setReadOnly(True)
|
||||
self.uiVNCConsoleCommandLineEdit.setObjectName("uiVNCConsoleCommandLineEdit")
|
||||
self.gridLayout_6.addWidget(self.uiVNCConsoleCommandLineEdit, 4, 0, 1, 2)
|
||||
self.horizontalLayout_8.addWidget(self.uiVNCConsoleCommandLineEdit)
|
||||
self.uiVNCConsolePreconfiguredCommandPushButton = QtWidgets.QPushButton(self.uiVNCConsoleSettingsGroupBox)
|
||||
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
@@ -254,7 +242,8 @@ class Ui_GeneralPreferencesPageWidget(object):
|
||||
sizePolicy.setHeightForWidth(self.uiVNCConsolePreconfiguredCommandPushButton.sizePolicy().hasHeightForWidth())
|
||||
self.uiVNCConsolePreconfiguredCommandPushButton.setSizePolicy(sizePolicy)
|
||||
self.uiVNCConsolePreconfiguredCommandPushButton.setObjectName("uiVNCConsolePreconfiguredCommandPushButton")
|
||||
self.gridLayout_6.addWidget(self.uiVNCConsolePreconfiguredCommandPushButton, 1, 1, 1, 1)
|
||||
self.horizontalLayout_8.addWidget(self.uiVNCConsolePreconfiguredCommandPushButton)
|
||||
self.verticalLayout_8.addLayout(self.horizontalLayout_8)
|
||||
self.verticalLayout_6.addWidget(self.uiVNCConsoleSettingsGroupBox)
|
||||
spacerItem3 = QtWidgets.QSpacerItem(20, 294, QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Expanding)
|
||||
self.verticalLayout_6.addItem(spacerItem3)
|
||||
@@ -396,16 +385,13 @@ class Ui_GeneralPreferencesPageWidget(object):
|
||||
self.uiExportConfigurationFilePushButton.setText(_translate("GeneralPreferencesPageWidget", "&Export"))
|
||||
self.uiConfigurationFileLabel.setText(_translate("GeneralPreferencesPageWidget", "Unknown location"))
|
||||
self.uiMiscTabWidget.setTabText(self.uiMiscTabWidget.indexOf(self.uiGeneralTab), _translate("GeneralPreferencesPageWidget", "General"))
|
||||
self.uiTelnetConsoleSettingsGroupBox.setTitle(_translate("GeneralPreferencesPageWidget", "Console settings for Telnet connections"))
|
||||
self.uiTelnetConsolePreconfiguredCommandLabel.setText(_translate("GeneralPreferencesPageWidget", "Preconfigured commands:"))
|
||||
self.uiTelnetConsoleCommandLabel.setText(_translate("GeneralPreferencesPageWidget", "Console application command:"))
|
||||
self.uiTelnetConsoleSettingsGroupBox.setTitle(_translate("GeneralPreferencesPageWidget", "Console settings"))
|
||||
self.uiTelnetConsoleCommandLabel.setText(_translate("GeneralPreferencesPageWidget", "Console application command for Telnet:"))
|
||||
self.uiTelnetConsoleCommandLineEdit.setToolTip(_translate("GeneralPreferencesPageWidget", "<html><head/><body><p>Command line replacements:</p><p>%h = device server </p><p>%p = device port</p><p>%d = device hostname</p></body></html>"))
|
||||
self.uiTelnetConsolePreconfiguredCommandPushButton.setText(_translate("GeneralPreferencesPageWidget", "&Set"))
|
||||
self.uiSerialConsoleSettingsGroupBox.setTitle(_translate("GeneralPreferencesPageWidget", "Console settings for local serial connections"))
|
||||
self.uiSerialConsoleCommandLabel.setText(_translate("GeneralPreferencesPageWidget", "Console application command:"))
|
||||
self.uiSerialConsolePreconfiguredCommandLabel.setText(_translate("GeneralPreferencesPageWidget", "Preconfigured commands:"))
|
||||
self.uiTelnetConsolePreconfiguredCommandPushButton.setText(_translate("GeneralPreferencesPageWidget", "&Edit"))
|
||||
self.uiSerialConsoleCommandLabel.setText(_translate("GeneralPreferencesPageWidget", "Console application command for Serial:"))
|
||||
self.uiSerialConsoleCommandLineEdit.setToolTip(_translate("GeneralPreferencesPageWidget", "<html><head/><body><p>Command line replacements:</p><p>%d = device hostname</p><p>%s = device pipe file</p></body></html>"))
|
||||
self.uiSerialConsolePreconfiguredCommandPushButton.setText(_translate("GeneralPreferencesPageWidget", "&Set"))
|
||||
self.uiSerialConsolePreconfiguredCommandPushButton.setText(_translate("GeneralPreferencesPageWidget", "&Edit"))
|
||||
self.uiConsoleMiscGroupBox.setTitle(_translate("GeneralPreferencesPageWidget", "Miscellaneous"))
|
||||
self.uiCloseConsoleWindowsOnDeleteCheckBox.setText(_translate("GeneralPreferencesPageWidget", "Close any connected console window when deleting a node"))
|
||||
self.uiBringConsoleWindowToFrontCheckBox.setToolTip(_translate("GeneralPreferencesPageWidget", "<html>This option will attempt to bring existing opened console window to front, instead of opening a new window.<br>If no existing opened console window exists, it will start a new console window.</html>"))
|
||||
@@ -414,10 +400,9 @@ class Ui_GeneralPreferencesPageWidget(object):
|
||||
self.uiDelayConsoleAllSpinBox.setSuffix(_translate("GeneralPreferencesPageWidget", " ms"))
|
||||
self.uiMiscTabWidget.setTabText(self.uiMiscTabWidget.indexOf(self.uiConsoleTab), _translate("GeneralPreferencesPageWidget", "Console applications"))
|
||||
self.uiVNCConsoleSettingsGroupBox.setTitle(_translate("GeneralPreferencesPageWidget", "Settings for VNC connections"))
|
||||
self.uiVNCConsolePreconfiguredCommandLabel.setText(_translate("GeneralPreferencesPageWidget", "Preconfigured commands:"))
|
||||
self.uiVNCConsoleCommandLabel.setText(_translate("GeneralPreferencesPageWidget", "Console application command:"))
|
||||
self.uiVNCConsoleCommandLabel.setText(_translate("GeneralPreferencesPageWidget", "Console application command for VNC:"))
|
||||
self.uiVNCConsoleCommandLineEdit.setToolTip(_translate("GeneralPreferencesPageWidget", "<html><head/><body><p>Command line replacements:</p><p>%h = device server </p><p>%p = device port</p><p>%d = device hostname</p></body></html>"))
|
||||
self.uiVNCConsolePreconfiguredCommandPushButton.setText(_translate("GeneralPreferencesPageWidget", "&Set"))
|
||||
self.uiVNCConsolePreconfiguredCommandPushButton.setText(_translate("GeneralPreferencesPageWidget", "&Edit"))
|
||||
self.uiMiscTabWidget.setTabText(self.uiMiscTabWidget.indexOf(self.uiVNCTab), _translate("GeneralPreferencesPageWidget", "VNC"))
|
||||
self.uiSceneWidthLabel.setText(_translate("GeneralPreferencesPageWidget", "Default width:"))
|
||||
self.uiSceneHeightLabel.setText(_translate("GeneralPreferencesPageWidget", "Default height:"))
|
||||
|
||||
272134
gns3/ui/resources_rc.py
272134
gns3/ui/resources_rc.py
File diff suppressed because it is too large
Load Diff
148
gns3/vm.py
148
gns3/vm.py
@@ -38,6 +38,46 @@ class VM(Node):
|
||||
self._vm_id = None
|
||||
self._vm_directory = None
|
||||
self._command_line = None
|
||||
self._custom_console_command = None
|
||||
|
||||
def consoleCommand(self):
|
||||
"""
|
||||
:returns: The console command for this host
|
||||
"""
|
||||
if self._custom_console_command:
|
||||
return self._custom_console_command
|
||||
else:
|
||||
from .main_window import MainWindow
|
||||
general_settings = MainWindow.instance().settings()
|
||||
|
||||
console_type = self.consoleType()
|
||||
if console_type == "serial":
|
||||
return general_settings["serial_console_command"]
|
||||
elif console_type == "vnc":
|
||||
return general_settings["vnc_console_command"]
|
||||
return general_settings["telnet_console_command"]
|
||||
|
||||
def setCustomConsoleCommand(self, console_command):
|
||||
"""
|
||||
Set custom console command for this node
|
||||
"""
|
||||
|
||||
console_command = console_command.strip()
|
||||
if console_command == '':
|
||||
self._custom_console_command = None
|
||||
else:
|
||||
self._custom_console_command = console_command
|
||||
|
||||
def consoleType(self):
|
||||
"""
|
||||
Get the console type (serial, telnet or VNC)
|
||||
"""
|
||||
console_type = "telnet"
|
||||
if hasattr(self, "serialConsole") and self.serialConsole():
|
||||
return "serial"
|
||||
if "console_type" in self.settings():
|
||||
return self.settings()["console_type"]
|
||||
return console_type
|
||||
|
||||
def vm_id(self):
|
||||
"""
|
||||
@@ -122,7 +162,7 @@ class VM(Node):
|
||||
log.info("{} has started".format(self.name()))
|
||||
self.setStatus(Node.started)
|
||||
if result:
|
||||
self._setupCallback(result)
|
||||
self._updateCallback(result)
|
||||
|
||||
def _setupCallback(self, result, error=False, **kwargs):
|
||||
"""
|
||||
@@ -159,6 +199,24 @@ class VM(Node):
|
||||
self._settings[name] = value
|
||||
return True
|
||||
|
||||
def _updateCallback(self, result, error=False, **kwargs):
|
||||
"""
|
||||
Callback for update.
|
||||
|
||||
:param result: server response (dict)
|
||||
: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["message"])
|
||||
return False
|
||||
|
||||
if "command_line" in result:
|
||||
self._command_line = result["command_line"]
|
||||
|
||||
return True
|
||||
|
||||
def stop(self):
|
||||
"""
|
||||
Stops this VM instance.
|
||||
@@ -367,3 +425,91 @@ class VM(Node):
|
||||
self.server_error_signal.emit(self.id(), result["message"])
|
||||
else:
|
||||
PacketCapture.instance().stopCapture(self, context["port"])
|
||||
def dump(self):
|
||||
"""
|
||||
Returns a representation of this device.
|
||||
(to be saved in a topology file).
|
||||
|
||||
:returns: representation of the node (dictionary)
|
||||
"""
|
||||
|
||||
device = {
|
||||
"id": self.id(),
|
||||
"type": self.__class__.__name__,
|
||||
"description": str(self),
|
||||
"properties": {},
|
||||
"server_id": self._server.id()
|
||||
}
|
||||
if self._custom_console_command is not None:
|
||||
device["custom_console_command"] = self._custom_console_command
|
||||
|
||||
# add the ports
|
||||
if self._ports:
|
||||
ports = device["ports"] = []
|
||||
for port in self._ports:
|
||||
ports.append(port.dump())
|
||||
|
||||
return device
|
||||
|
||||
def load(self, node_info):
|
||||
"""
|
||||
Loads a device representation
|
||||
(from a topology file).
|
||||
|
||||
:param node_info: representation of the node (dictionary)
|
||||
"""
|
||||
|
||||
if "custom_console_command" in node_info:
|
||||
self._custom_console_command = node_info["custom_console_command"]
|
||||
self._loading = True
|
||||
self._node_info = node_info
|
||||
self.loaded_signal.connect(self._updatePortSettings)
|
||||
|
||||
def openConsole(self, aux):
|
||||
if hasattr(self, "serialConsole") and self.serialConsole():
|
||||
from .serial_console import serialConsole
|
||||
serialConsole(self.name(), self.serialPipe(), self.consoleCommand())
|
||||
|
||||
if aux:
|
||||
console_port = self.auxConsole()
|
||||
if console_port is None:
|
||||
raise ValueError("AUX console port not allocated for {}".format(self.name()))
|
||||
else:
|
||||
console_port = self.console()
|
||||
|
||||
console_type = "telnet"
|
||||
if "console_type" in self.settings():
|
||||
console_type = self.settings()["console_type"]
|
||||
if console_type == "telnet":
|
||||
from .telnet_console import nodeTelnetConsole
|
||||
nodeTelnetConsole(self.name(), self.server(), console_port, self.consoleCommand())
|
||||
elif console_type == "vnc":
|
||||
from .vnc_console import vncConsole
|
||||
vncConsole(self.server().host(), console_port, self.consoleCommand())
|
||||
|
||||
def _updatePortSettings(self):
|
||||
"""
|
||||
Updates port settings when loading a topology.
|
||||
"""
|
||||
|
||||
self.loaded_signal.disconnect(self._updatePortSettings)
|
||||
|
||||
# assign the correct names and IDs to the ports
|
||||
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():
|
||||
# If the adapter is missing we consider that adapter_number == port_number
|
||||
adapter_number = topology_port.get("adapter_number", topology_port["port_number"])
|
||||
if port.adapterNumber() is None or adapter_number == port.adapterNumber() or topology_port.get("slot_number", None) == port.adapterNumber():
|
||||
port.setName(topology_port["name"])
|
||||
port.setId(topology_port["id"])
|
||||
|
||||
# now we can set the node as initialized and trigger the created signal
|
||||
self.setInitialized(True)
|
||||
log.info("{} has been loaded".format(self.name()))
|
||||
self.created_signal.emit(self.id())
|
||||
self._module.addNode(self)
|
||||
self._loading = False
|
||||
self._node_info = None
|
||||
|
||||
@@ -29,7 +29,7 @@ import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def vncConsole(host, port):
|
||||
def vncConsole(host, port, command):
|
||||
"""
|
||||
Start a VNC console program.
|
||||
|
||||
@@ -37,10 +37,6 @@ def vncConsole(host, port):
|
||||
:param port: port number
|
||||
"""
|
||||
|
||||
command = MainWindow.instance().vncConsoleCommand()
|
||||
if not command:
|
||||
return
|
||||
|
||||
# replace the place-holders by the actual values
|
||||
command = command.replace("%h", host)
|
||||
command = command.replace("%p", str(port))
|
||||
|
||||
700
resources/icons/console_edit.svg
Normal file
700
resources/icons/console_edit.svg
Normal file
@@ -0,0 +1,700 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Created with Inkscape (http://www.inkscape.org/) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:xlink="http://www.w3.org/1999/xlink"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="48px"
|
||||
height="48px"
|
||||
id="svg1306"
|
||||
sodipodi:version="0.32"
|
||||
inkscape:version="0.91 r13725"
|
||||
sodipodi:docname="console_edit.svg"
|
||||
inkscape:export-filename="/home/andreas/projekt/bild/tango/terminal4.png"
|
||||
inkscape:export-xdpi="240.00000"
|
||||
inkscape:export-ydpi="240.00000"
|
||||
version="1.1">
|
||||
<defs
|
||||
id="defs1308">
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient5060"
|
||||
id="radialGradient5031"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(-2.774389,0,0,1.969706,112.7623,-872.8854)"
|
||||
cx="605.71429"
|
||||
cy="486.64789"
|
||||
fx="605.71429"
|
||||
fy="486.64789"
|
||||
r="117.14286" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient5060">
|
||||
<stop
|
||||
style="stop-color:black;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop5062" />
|
||||
<stop
|
||||
style="stop-color:black;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop5064" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient5060"
|
||||
id="radialGradient5029"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(2.774389,0,0,1.969706,-1891.633,-872.8854)"
|
||||
cx="605.71429"
|
||||
cy="486.64789"
|
||||
fx="605.71429"
|
||||
fy="486.64789"
|
||||
r="117.14286" />
|
||||
<linearGradient
|
||||
id="linearGradient5048">
|
||||
<stop
|
||||
style="stop-color:black;stop-opacity:0;"
|
||||
offset="0"
|
||||
id="stop5050" />
|
||||
<stop
|
||||
id="stop5056"
|
||||
offset="0.5"
|
||||
style="stop-color:black;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:black;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop5052" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient5048"
|
||||
id="linearGradient5027"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(2.774389,0,0,1.969706,-1892.179,-872.8854)"
|
||||
x1="302.85715"
|
||||
y1="366.64789"
|
||||
x2="302.85715"
|
||||
y2="609.50507" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient6447">
|
||||
<stop
|
||||
style="stop-color:#777973;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop6449" />
|
||||
<stop
|
||||
style="stop-color:#777973;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop6451" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient4254">
|
||||
<stop
|
||||
style="stop-color:#616161;stop-opacity:1.0000000;"
|
||||
offset="0.0000000"
|
||||
id="stop4256" />
|
||||
<stop
|
||||
style="stop-color:#a0a0a0;stop-opacity:1.0000000;"
|
||||
offset="1.0000000"
|
||||
id="stop4258" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient5176">
|
||||
<stop
|
||||
id="stop5178"
|
||||
offset="0.0000000"
|
||||
style="stop-color:#a2a59c;stop-opacity:1.0000000;" />
|
||||
<stop
|
||||
id="stop5180"
|
||||
offset="1.0000000"
|
||||
style="stop-color:#535750;stop-opacity:1.0000000;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient2667">
|
||||
<stop
|
||||
id="stop2669"
|
||||
offset="0.0000000"
|
||||
style="stop-color:#ffffff;stop-opacity:1.0000000;" />
|
||||
<stop
|
||||
id="stop2671"
|
||||
offset="1.0000000"
|
||||
style="stop-color:#fcfcff;stop-opacity:0.0000000;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
y2="26.729263"
|
||||
x2="17.199417"
|
||||
y1="1.6537577"
|
||||
x1="11.492236"
|
||||
gradientTransform="matrix(1.236157,0.000000,0.000000,0.896051,-1.081820,2.830699)"
|
||||
id="linearGradient2673"
|
||||
xlink:href="#linearGradient2667"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
id="linearGradient2238">
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop2240" />
|
||||
<stop
|
||||
style="stop-color:#ffffff;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop2242" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient2224">
|
||||
<stop
|
||||
style="stop-color:#32342f;stop-opacity:0.54639173;"
|
||||
offset="0.0000000"
|
||||
id="stop2226" />
|
||||
<stop
|
||||
style="stop-color:#32342f;stop-opacity:0;"
|
||||
offset="1"
|
||||
id="stop2228" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient2214">
|
||||
<stop
|
||||
style="stop-color:#a9aaa7;stop-opacity:1.0000000;"
|
||||
offset="0.0000000"
|
||||
id="stop2216" />
|
||||
<stop
|
||||
style="stop-color:#676964;stop-opacity:1.0000000;"
|
||||
offset="1.0000000"
|
||||
id="stop2218" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient2206">
|
||||
<stop
|
||||
style="stop-color:#777973;stop-opacity:1.0000000;"
|
||||
offset="0.0000000"
|
||||
id="stop2208" />
|
||||
<stop
|
||||
style="stop-color:#cbccca;stop-opacity:1.0000000;"
|
||||
offset="1.0000000"
|
||||
id="stop2210" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient2198">
|
||||
<stop
|
||||
style="stop-color:#748f48;stop-opacity:1.0000000;"
|
||||
offset="0.0000000"
|
||||
id="stop2200" />
|
||||
<stop
|
||||
style="stop-color:#1f2816;stop-opacity:1.0000000;"
|
||||
offset="1.0000000"
|
||||
id="stop2202" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient2198"
|
||||
id="linearGradient2204"
|
||||
x1="23.118565"
|
||||
y1="9.5830288"
|
||||
x2="22.440805"
|
||||
y2="34.225887"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.950085,0.000000,0.000000,0.965659,1.243978,0.255342)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient2206"
|
||||
id="linearGradient2212"
|
||||
x1="29.870447"
|
||||
y1="32.285740"
|
||||
x2="24.841814"
|
||||
y2="14.157946"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.957412,0.000000,0.000000,0.952331,1.022766,0.133307)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient5176"
|
||||
id="linearGradient2220"
|
||||
x1="8.6529236"
|
||||
y1="9.5865316"
|
||||
x2="21.305075"
|
||||
y2="32.497993"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.957412,0.000000,0.000000,0.952331,1.022766,0.133307)" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient2224"
|
||||
id="radialGradient2230"
|
||||
cx="24.041630"
|
||||
cy="42.242130"
|
||||
fx="24.041630"
|
||||
fy="42.242130"
|
||||
r="17.576654"
|
||||
gradientTransform="matrix(1.000000,0.000000,0.000000,0.304598,-1.841788e-16,29.37527)"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient2238"
|
||||
id="linearGradient2244"
|
||||
x1="20.338758"
|
||||
y1="19.636894"
|
||||
x2="48.845253"
|
||||
y2="49.730762"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.953506,0.000000,0.000000,0.947873,1.141528,1.205591)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient4254"
|
||||
id="linearGradient4260"
|
||||
x1="11.048059"
|
||||
y1="9.1463490"
|
||||
x2="26.178129"
|
||||
y2="30.343304"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(0.997583,0.000000,0.000000,0.989941,0.104141,7.028871e-2)" />
|
||||
<linearGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient2214"
|
||||
id="linearGradient5719"
|
||||
x1="40.253334"
|
||||
y1="42.318577"
|
||||
x2="36.451904"
|
||||
y2="37.999615"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.000000,0.000000,0.000000,0.744756,0.000000,9.569132)" />
|
||||
<radialGradient
|
||||
inkscape:collect="always"
|
||||
xlink:href="#linearGradient6447"
|
||||
id="radialGradient6453"
|
||||
cx="37.495606"
|
||||
cy="39.510023"
|
||||
fx="37.495606"
|
||||
fy="39.510023"
|
||||
r="2.5100370"
|
||||
gradientTransform="matrix(1.000000,0.000000,0.000000,0.737790,0.000000,9.844321)"
|
||||
gradientUnits="userSpaceOnUse" />
|
||||
<linearGradient
|
||||
id="linearGradient2994">
|
||||
<stop
|
||||
id="stop2996"
|
||||
offset="0"
|
||||
style="stop-color:#000000;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop2998"
|
||||
offset="1"
|
||||
style="stop-color:#c9c9c9;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient2984"
|
||||
inkscape:collect="always">
|
||||
<stop
|
||||
id="stop2986"
|
||||
offset="0"
|
||||
style="stop-color:#e7e2b8;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop2988"
|
||||
offset="1"
|
||||
style="stop-color:#e7e2b8;stop-opacity:0;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient2974">
|
||||
<stop
|
||||
id="stop2976"
|
||||
offset="0"
|
||||
style="stop-color:#c1c1c1;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop2978"
|
||||
offset="1"
|
||||
style="stop-color:#acacac;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient2966">
|
||||
<stop
|
||||
id="stop2968"
|
||||
offset="0"
|
||||
style="stop-color:#ffd1d1;stop-opacity:1;" />
|
||||
<stop
|
||||
style="stop-color:#ff1d1d;stop-opacity:1;"
|
||||
offset="0.5"
|
||||
id="stop3006" />
|
||||
<stop
|
||||
id="stop2970"
|
||||
offset="1"
|
||||
style="stop-color:#6f0000;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient2919">
|
||||
<stop
|
||||
id="stop2921"
|
||||
offset="0"
|
||||
style="stop-color:#a3a4a0;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop2923"
|
||||
offset="1"
|
||||
style="stop-color:#888a85;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient2873">
|
||||
<stop
|
||||
id="stop2875"
|
||||
offset="0"
|
||||
style="stop-color:#939393;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop2877"
|
||||
offset="1"
|
||||
style="stop-color:#424242;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<linearGradient
|
||||
id="linearGradient2855">
|
||||
<stop
|
||||
id="stop2857"
|
||||
offset="0"
|
||||
style="stop-color:#dfdfdf;stop-opacity:1;" />
|
||||
<stop
|
||||
id="stop2859"
|
||||
offset="1"
|
||||
style="stop-color:#ffffff;stop-opacity:1;" />
|
||||
</linearGradient>
|
||||
<radialGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(1.000000,0.000000,0.000000,0.348243,0.000000,26.35543)"
|
||||
r="19.5625"
|
||||
fy="40.4375"
|
||||
fx="23.5625"
|
||||
cy="40.4375"
|
||||
cx="23.5625"
|
||||
id="radialGradient2871"
|
||||
xlink:href="#linearGradient5060"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
gradientTransform="translate(-5.669292,0)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
y2="22.250591"
|
||||
x2="50.988335"
|
||||
y1="17.376184"
|
||||
x1="48.90625"
|
||||
id="linearGradient2972"
|
||||
xlink:href="#linearGradient2966"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
gradientTransform="translate(-5.669292,0)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
y2="22.625"
|
||||
x2="47.6875"
|
||||
y1="19.8125"
|
||||
x1="46"
|
||||
id="linearGradient2980"
|
||||
xlink:href="#linearGradient2974"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
gradientUnits="userSpaceOnUse"
|
||||
gradientTransform="matrix(2.923565,0,0,2.029717,-61.55532,-27.88417)"
|
||||
r="3.2408544"
|
||||
fy="27.640751"
|
||||
fx="29.053354"
|
||||
cy="27.640751"
|
||||
cx="29.053354"
|
||||
id="radialGradient2990"
|
||||
xlink:href="#linearGradient2984"
|
||||
inkscape:collect="always" />
|
||||
<linearGradient
|
||||
gradientTransform="translate(-5.825542,0.125)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
y2="30.703125"
|
||||
x2="25.514589"
|
||||
y1="31.046875"
|
||||
x1="25.71875"
|
||||
id="linearGradient3000"
|
||||
xlink:href="#linearGradient2994"
|
||||
inkscape:collect="always" />
|
||||
<radialGradient
|
||||
r="19.5625"
|
||||
fy="40.4375"
|
||||
fx="23.5625"
|
||||
cy="40.4375"
|
||||
cx="23.5625"
|
||||
gradientTransform="matrix(1,0,0,0.348243,0,26.35543)"
|
||||
gradientUnits="userSpaceOnUse"
|
||||
id="radialGradient3010"
|
||||
xlink:href="#linearGradient5060"
|
||||
inkscape:collect="always" />
|
||||
</defs>
|
||||
<sodipodi:namedview
|
||||
id="base"
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="0.19607843"
|
||||
inkscape:pageopacity="0.0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:zoom="3.3292944"
|
||||
inkscape:cx="24"
|
||||
inkscape:cy="-6.995453"
|
||||
inkscape:current-layer="layer1"
|
||||
showgrid="false"
|
||||
inkscape:grid-bbox="true"
|
||||
inkscape:document-units="px"
|
||||
inkscape:window-width="926"
|
||||
inkscape:window-height="975"
|
||||
inkscape:window-x="1769"
|
||||
inkscape:window-y="6"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
inkscape:showpageshadow="false"
|
||||
inkscape:window-maximized="0" />
|
||||
<metadata
|
||||
id="metadata1311">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title></dc:title>
|
||||
<dc:date>2005-10-15</dc:date>
|
||||
<dc:creator>
|
||||
<cc:Agent>
|
||||
<dc:title>Andreas Nilsson</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:creator>
|
||||
<dc:subject>
|
||||
<rdf:Bag>
|
||||
<rdf:li>terminal</rdf:li>
|
||||
<rdf:li>emulator</rdf:li>
|
||||
<rdf:li>term</rdf:li>
|
||||
<rdf:li>command line</rdf:li>
|
||||
</rdf:Bag>
|
||||
</dc:subject>
|
||||
<cc:license
|
||||
rdf:resource="http://creativecommons.org/licenses/by-sa/2.0/" />
|
||||
<dc:contributor>
|
||||
<cc:Agent>
|
||||
<dc:title>Jakub Steiner</dc:title>
|
||||
</cc:Agent>
|
||||
</dc:contributor>
|
||||
</cc:Work>
|
||||
<cc:License
|
||||
rdf:about="http://creativecommons.org/licenses/by-sa/2.0/">
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/Reproduction" />
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/Distribution" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/Notice" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/Attribution" />
|
||||
<cc:permits
|
||||
rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
|
||||
<cc:requires
|
||||
rdf:resource="http://web.resource.org/cc/ShareAlike" />
|
||||
</cc:License>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<g
|
||||
id="layer1"
|
||||
inkscape:label="Layer 1"
|
||||
inkscape:groupmode="layer">
|
||||
<g
|
||||
id="g5022"
|
||||
transform="matrix(2.454499e-2,0,0,2.086758e-2,46.14369,39.34109)">
|
||||
<rect
|
||||
y="-150.69685"
|
||||
x="-1559.2523"
|
||||
height="478.35718"
|
||||
width="1339.6335"
|
||||
id="rect4173"
|
||||
style="opacity:0.40206185;color:black;fill:url(#linearGradient5027);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccc"
|
||||
id="path5058"
|
||||
d="M -219.61876,-150.68038 C -219.61876,-150.68038 -219.61876,327.65041 -219.61876,327.65041 C -76.744594,328.55086 125.78146,220.48075 125.78138,88.454235 C 125.78138,-43.572302 -33.655436,-150.68036 -219.61876,-150.68038 z "
|
||||
style="opacity:0.40206185;color:black;fill:url(#radialGradient5029);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible" />
|
||||
<path
|
||||
style="opacity:0.40206185;color:black;fill:url(#radialGradient5031);fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:round;stroke-linejoin:miter;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
|
||||
d="M -1559.2523,-150.68038 C -1559.2523,-150.68038 -1559.2523,327.65041 -1559.2523,327.65041 C -1702.1265,328.55086 -1904.6525,220.48075 -1904.6525,88.454235 C -1904.6525,-43.572302 -1745.2157,-150.68036 -1559.2523,-150.68038 z "
|
||||
id="path5018"
|
||||
sodipodi:nodetypes="cccc" />
|
||||
</g>
|
||||
<rect
|
||||
style="opacity:1.0000000;fill:url(#linearGradient2212);fill-opacity:1.0000000;fill-rule:evenodd;stroke:url(#linearGradient2220);stroke-width:0.99999946;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-dasharray:none;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
|
||||
id="rect1316"
|
||||
width="44.996037"
|
||||
height="38.998734"
|
||||
x="1.5026338"
|
||||
y="3.5015533"
|
||||
rx="4.8517075"
|
||||
ry="4.8517079" />
|
||||
<rect
|
||||
style="opacity:1.0000000;fill:url(#linearGradient2204);fill-opacity:1.0000000;fill-rule:evenodd;stroke:url(#linearGradient4260);stroke-width:0.99495775;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-dasharray:none;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
|
||||
id="rect1314"
|
||||
width="37.088005"
|
||||
height="29.022322"
|
||||
x="5.4962788"
|
||||
y="7.4827089"
|
||||
rx="1.6452150"
|
||||
ry="1.6452144" />
|
||||
<g
|
||||
id="g2286"
|
||||
style="opacity:0.25568182">
|
||||
<path
|
||||
id="path1345"
|
||||
d="M 8.0152033,11.500361 L 39.994145,11.500361"
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#181f10;stroke-width:1.00072134;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#181f10;stroke-width:1.00072134;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 8.0152033,13.500361 L 39.994145,13.500361"
|
||||
id="path2264" />
|
||||
<path
|
||||
id="path2266"
|
||||
d="M 8.0152033,15.500361 L 39.994145,15.500361"
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#181f10;stroke-width:1.00072134;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#181f10;stroke-width:1.00072134;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 8.0152033,17.500361 L 39.994145,17.500361"
|
||||
id="path2268" />
|
||||
<path
|
||||
id="path2270"
|
||||
d="M 8.0152033,19.500361 L 39.994145,19.500361"
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#181f10;stroke-width:1.00072134;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#181f10;stroke-width:1.00072134;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 8.0152033,21.500361 L 39.994145,21.500361"
|
||||
id="path2272" />
|
||||
<path
|
||||
id="path2274"
|
||||
d="M 8.0152033,23.500361 L 39.994145,23.500361"
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#181f10;stroke-width:1.00072134;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#181f10;stroke-width:1.00072134;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 8.0152033,25.500361 L 39.994145,25.500361"
|
||||
id="path2276" />
|
||||
<path
|
||||
id="path2278"
|
||||
d="M 8.0152033,27.500361 L 39.994145,27.500361"
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#181f10;stroke-width:1.00072134;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#181f10;stroke-width:1.00072134;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 8.0152033,29.500361 L 39.994145,29.500361"
|
||||
id="path2280" />
|
||||
<path
|
||||
id="path2282"
|
||||
d="M 8.0152033,31.500361 L 39.994145,31.500361"
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#181f10;stroke-width:1.00072134;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" />
|
||||
<path
|
||||
style="fill:none;fill-opacity:0.75;fill-rule:evenodd;stroke:#181f10;stroke-width:1.00072134;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
d="M 8.0152033,33.500361 L 39.994145,33.500361"
|
||||
id="path2284" />
|
||||
</g>
|
||||
<rect
|
||||
style="opacity:0.76373626;fill:none;fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient2244);stroke-width:0.99999946;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect2232"
|
||||
width="42.945141"
|
||||
height="37.000587"
|
||||
x="2.5542557"
|
||||
y="4.5007114"
|
||||
rx="3.7910469"
|
||||
ry="3.7910469" />
|
||||
<path
|
||||
style="font-size:18.585011px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125.00000%;writing-mode:lr-tb;text-anchor:start;fill:#ffffff;fill-opacity:1.0000000;stroke:#6ed66e;stroke-width:1.0000000pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:0.27868852;font-family:Bitstream Vera Sans Mono"
|
||||
d="M 11.625000,20.679392 L 11.625000,17.625000 L 20.609828,21.685794 L 20.609828,23.541713 L 11.625000,27.629147 L 11.625000,24.583829 L 18.589396,22.729971 L 11.625000,20.679392 z M 30.517635,30.705752 L 30.517635,32.679948 L 19.614229,32.679948 L 19.614229,30.705752 L 30.517635,30.705752"
|
||||
id="text1340"
|
||||
sodipodi:nodetypes="ccccccccccccc" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccccccc"
|
||||
style="opacity:0.53142856;fill:url(#linearGradient2673);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.25pt;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
d="M 7.625388,8 C 7.102102,8 6.05153,8.190188 6.05153,9.0259761 L 6.16958,25.542519 C 23.841567,24.579133 20.294433,17.286426 42,13.633318 L 41.937264,9.2913791 C 41.859002,8.1662868 41.397947,8.0594548 40.327115,8.066071 L 7.625388,8 z "
|
||||
id="path2443" />
|
||||
<rect
|
||||
style="opacity:0.71428573;fill:none;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.9999992;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4.0000000;stroke-dasharray:none;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
|
||||
id="rect1340"
|
||||
width="34.026031"
|
||||
height="26.057468"
|
||||
x="6.9894562"
|
||||
y="8.9805145"
|
||||
rx="0.11773217"
|
||||
ry="0.11773217" />
|
||||
<rect
|
||||
style="opacity:1;fill:url(#radialGradient6453);fill-opacity:1;fill-rule:evenodd;stroke:url(#linearGradient5719);stroke-width:1.00000119;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect5025"
|
||||
width="4.0200734"
|
||||
height="2.9590063"
|
||||
x="35.485569"
|
||||
y="37.514935"
|
||||
rx="0.35819405"
|
||||
ry="0.56022596" />
|
||||
<rect
|
||||
style="opacity:1;fill:#93d94c;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:2;stroke-linecap:round;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1"
|
||||
id="rect6458"
|
||||
width="2"
|
||||
height="2"
|
||||
x="32"
|
||||
y="38"
|
||||
rx="0.56022543"
|
||||
ry="0.56022543" />
|
||||
<path
|
||||
sodipodi:type="arc"
|
||||
style="opacity:1;color:#000000;fill:#ffffff;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:round;marker:none;marker-start:none;marker-mid:none;marker-end:none;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;visibility:visible;display:inline;overflow:visible"
|
||||
id="path2300"
|
||||
sodipodi:cx="28.3125"
|
||||
sodipodi:cy="38.75"
|
||||
sodipodi:rx="0.5625"
|
||||
sodipodi:ry="0.5625"
|
||||
d="M 28.875 38.75 A 0.5625 0.5625 0 1 1 27.75,38.75 A 0.5625 0.5625 0 1 1 28.875 38.75 z"
|
||||
transform="translate(4.375000,-6.250000e-2)" />
|
||||
<g
|
||||
inkscape:label="Layer 1"
|
||||
id="layer1-3"
|
||||
transform="translate(-2.8179398,6.273626)">
|
||||
<ellipse
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:0.31578944;fill:url(#radialGradient3010);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
|
||||
id="path3008"
|
||||
transform="matrix(0.616613,0,0,0.440367,10.61425,13.94266)"
|
||||
cx="23.5625"
|
||||
cy="40.4375"
|
||||
rx="19.5625"
|
||||
ry="6.8125" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccccc"
|
||||
id="path2960"
|
||||
d="m 17.34116,32.5 5.625,-5.625 20.093749,-9.75 c 3.25,-1.25 5.1875,3.375 2.3125,5 L 25.34116,31.5 l -8,1 z"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#cb9022;fill-opacity:1;fill-rule:evenodd;stroke:#5c410c;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#linearGradient2972);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
|
||||
d="m 38.330708,20 c 0,0 1.4375,0.09375 2,1.34375 0.579493,1.287761 0,2.65625 0,2.65625 l 5.03125,-2.46875 c 0,0 1.452032,-0.881367 0.65625,-2.84375 -0.784912,-1.935577 -2.6875,-1.15625 -2.6875,-1.15625 l -5,2.46875 z"
|
||||
id="path2964"
|
||||
sodipodi:nodetypes="czcczcc"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
sodipodi:nodetypes="czcczcc"
|
||||
id="path2962"
|
||||
d="m 38.330708,20 c 0,0 1.4375,0.09375 2,1.34375 0.579493,1.287761 0,2.65625 0,2.65625 l 2,-1 c 0,0 0.827032,-1.318867 0.21875,-2.6875 C 41.924458,18.90625 40.330708,19 40.330708,19 l -2,1 z"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#linearGradient2980);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccc"
|
||||
id="path2982"
|
||||
d="m 18.768208,31.78125 4.5,-4.5 c 1.5,0.8125 2.28125,2.15625 1.875,3.71875 l -6.375,0.78125 z"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#radialGradient2990);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
sodipodi:nodetypes="cccc"
|
||||
id="path2992"
|
||||
d="m 20.111958,30.375 -1.625,1.59375 2.34375,-0.3125 c 0.21875,-0.71875 -0.1875,-1.0625 -0.71875,-1.28125 z"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:url(#linearGradient3000);fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccccc"
|
||||
id="path3002"
|
||||
d="m 23.268208,27.25 1.5625,1.25 15.38734,-7.31867 C 39.773616,20.325286 38.976281,20.096733 38.314669,20.019068 L 23.268208,27.25 Z"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#ffffff;fill-opacity:0.36363639;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
|
||||
inkscape:connector-curvature="0" />
|
||||
<path
|
||||
sodipodi:nodetypes="ccccc"
|
||||
id="path3004"
|
||||
d="m 25.143208,31.0625 0.1875,-0.75 15.23109,-7.1296 c 0,0 -0.11016,0.613627 -0.215879,0.74935 L 25.143208,31.0625 Z"
|
||||
style="color:#000000;display:inline;overflow:visible;visibility:visible;opacity:1;fill:#000000;fill-opacity:0.36363639;fill-rule:evenodd;stroke:none;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;marker:none;marker-start:none;marker-mid:none;marker-end:none"
|
||||
inkscape:connector-curvature="0" />
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 30 KiB |
@@ -48,6 +48,7 @@
|
||||
<file>icons/connection-new.svg</file>
|
||||
<file>icons/connection-new-hover.svg</file>
|
||||
<file>icons/console.svg</file>
|
||||
<file>icons/console_edit.svg</file>
|
||||
<file>icons/aux-console.svg</file>
|
||||
<file>icons/delete.svg</file>
|
||||
<file>icons/led_green.svg</file>
|
||||
|
||||
@@ -32,6 +32,49 @@ def test_vpcs_device_start(vpcs_device):
|
||||
assert args[0] == "/vpcs/vms/{vm_id}/start".format(vm_id=vpcs_device.vm_id())
|
||||
|
||||
|
||||
def test_vpcs_dump(vpcs_device):
|
||||
|
||||
dump = vpcs_device.dump()
|
||||
assert dump["id"] == vpcs_device.id()
|
||||
assert dump["type"] == "VPCSDevice"
|
||||
assert dump["description"] == "VPCS device"
|
||||
assert dump["properties"] == {"name": vpcs_device.name()}
|
||||
assert dump["server_id"] == vpcs_device._server.id()
|
||||
assert "custom_console_command" not in dump
|
||||
|
||||
|
||||
def test_vpcs_dump_custom_console(vpcs_device):
|
||||
|
||||
vpcs_device.setCustomConsoleCommand("/bin/fake")
|
||||
dump = vpcs_device.dump()
|
||||
assert dump["id"] == vpcs_device.id()
|
||||
assert dump["type"] == "VPCSDevice"
|
||||
assert dump["description"] == "VPCS device"
|
||||
assert dump["properties"] == {"name": vpcs_device.name()}
|
||||
assert dump["server_id"] == vpcs_device._server.id()
|
||||
assert dump["custom_console_command"] == "/bin/fake"
|
||||
|
||||
|
||||
def test_vpcs_dump_custom_console(vpcs_device):
|
||||
|
||||
vpcs_device.setCustomConsoleCommand("/bin/fake")
|
||||
dump = vpcs_device.dump()
|
||||
assert dump["id"] == vpcs_device.id()
|
||||
assert dump["type"] == "VPCSDevice"
|
||||
assert dump["description"] == "VPCS device"
|
||||
assert dump["properties"] == {"name": vpcs_device.name()}
|
||||
assert dump["server_id"] == vpcs_device._server.id()
|
||||
assert dump["custom_console_command"] == "/bin/fake"
|
||||
|
||||
|
||||
def test_vpcs_load(vpcs_device):
|
||||
|
||||
dump = vpcs_device.dump()
|
||||
dump["custom_console_command"] = "/bin/test"
|
||||
vpcs_device.load(dump)
|
||||
assert vpcs_device.consoleCommand() == "/bin/test"
|
||||
|
||||
|
||||
def test_vpcs_device_stop(vpcs_device):
|
||||
|
||||
with patch('gns3.node.Node.httpPost') as mock:
|
||||
|
||||
Reference in New Issue
Block a user