mirror of
https://github.com/GNS3/gns3-gui.git
synced 2026-05-17 00:46:01 +03:00
@@ -15,37 +15,100 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from .qt import QtCore
|
||||
from .controller import Controller
|
||||
|
||||
from .utils.server_select import server_select
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class ApplianceManager:
|
||||
class ApplianceManager(QtCore.QObject):
|
||||
|
||||
appliances_changed_signal = QtCore.Signal()
|
||||
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self._appliance_templates = []
|
||||
self._appliances = []
|
||||
self._controller = Controller.instance()
|
||||
self._controller.connected_signal.connect(self._controllerConnectedSlot)
|
||||
self._controller.connected_signal.connect(self.refresh)
|
||||
self._controller.disconnected_signal.connect(self._controllerDisconnectedSlot)
|
||||
self._controllerConnectedSlot()
|
||||
self.refresh()
|
||||
|
||||
def _controllerConnectedSlot(self):
|
||||
def refresh(self):
|
||||
if self._controller.connected():
|
||||
self._controller.get("/appliances/templates", self._listApplianceTemplateCallback)
|
||||
self._controller.get("/appliances", self._listAppliancesCallback)
|
||||
|
||||
def _controllerDisconnectedSlot(self):
|
||||
self._appliance_templates = []
|
||||
self._appliances = []
|
||||
self.appliances_changed_signal.emit()
|
||||
|
||||
def appliance_templates(self):
|
||||
return self._appliance_templates
|
||||
|
||||
def appliances(self):
|
||||
return self._appliances
|
||||
|
||||
def getAppliance(self, appliance_id):
|
||||
"""
|
||||
Look for an appliance by appliance ID
|
||||
"""
|
||||
for appliance in self._appliances:
|
||||
if appliance["appliance_id"] == appliance_id:
|
||||
return appliance
|
||||
return None
|
||||
|
||||
def _listAppliancesCallback(self, result, error=False, **kwargs):
|
||||
if error is True:
|
||||
log.error("Error while getting appliances list: {}".format(result["message"]))
|
||||
return
|
||||
self._appliances = result
|
||||
self.appliances_changed_signal.emit()
|
||||
|
||||
def _listApplianceTemplateCallback(self, result, error=False, **kwargs):
|
||||
if error is True:
|
||||
log.error("Error while getting appliance templates list: {}".format(result["message"]))
|
||||
return
|
||||
self._appliance_templates = result
|
||||
self.appliances_changed_signal.emit()
|
||||
|
||||
def createNodeFromApplianceId(self, project, appliance_id, x, y):
|
||||
for appliance in self._appliances:
|
||||
if appliance["appliance_id"] == appliance_id:
|
||||
break
|
||||
if appliance.get("compute_id") is None:
|
||||
server = server_select(None, node_type=appliance["node_type"])
|
||||
self._controller.post("/projects/" + project.id() + "/appliances/" + appliance_id, self._createNodeFromApplianceCallback, {
|
||||
"compute_id": server.id(),
|
||||
"x": int(x),
|
||||
"y": int(y)
|
||||
})
|
||||
else:
|
||||
self._controller.post("/projects/" + project.id() + "/appliances/" + appliance_id, self._createNodeFromApplianceCallback, {
|
||||
"x": int(x),
|
||||
"y": int(y)
|
||||
})
|
||||
|
||||
def _createNodeFromApplianceCallback(self, result, error=False, **kwargs):
|
||||
if error:
|
||||
if "message" in result:
|
||||
log.error("Error while creating node: {}".format(result["message"]))
|
||||
return
|
||||
|
||||
def _controllerDisconnectedSlot(self):
|
||||
self._appliances = []
|
||||
|
||||
def appliances(self):
|
||||
return self._appliances
|
||||
|
||||
def _listAppliancesCallback(self, result, error=False, **kwargs):
|
||||
if error is True:
|
||||
log.error("Error while getting appliance list: {}".format(result["message"]))
|
||||
return
|
||||
self._appliance_templates = result
|
||||
self._appliances = result
|
||||
|
||||
@staticmethod
|
||||
def instance():
|
||||
|
||||
@@ -24,17 +24,16 @@ import os
|
||||
import sip
|
||||
import pickle
|
||||
|
||||
from .qt import QtCore, QtGui, QtSvg, QtNetwork, QtWidgets, qpartial, qslot
|
||||
from .qt import QtCore, QtGui, QtNetwork, QtWidgets, qpartial, qslot
|
||||
from .items.node_item import NodeItem
|
||||
from .dialogs.node_properties_dialog import NodePropertiesDialog
|
||||
from .link import Link
|
||||
from .node import Node
|
||||
from .modules import MODULES
|
||||
from .modules.builtin.cloud import Cloud
|
||||
from .modules.module_error import ModuleError
|
||||
from .settings import GRAPHICS_VIEW_SETTINGS
|
||||
from .topology import Topology
|
||||
from .ports.port import Port
|
||||
from .appliance_manager import ApplianceManager
|
||||
from .dialogs.style_editor_dialog import StyleEditorDialog
|
||||
from .dialogs.text_editor_dialog import TextEditorDialog
|
||||
from .dialogs.symbol_selection_dialog import SymbolSelectionDialog
|
||||
@@ -44,7 +43,6 @@ from .dialogs.file_editor_dialog import FileEditorDialog
|
||||
from .local_config import LocalConfig
|
||||
from .progress import Progress
|
||||
from .utils.server_select import server_select
|
||||
from .utils.normalize_filename import normalize_filename
|
||||
from .compute_manager import ComputeManager
|
||||
|
||||
# link items
|
||||
@@ -613,7 +611,8 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
"""
|
||||
|
||||
# check if what is dragged is handled by this view
|
||||
if event.mimeData().hasFormat("application/x-gns3-node") or event.mimeData().hasFormat("text/uri-list"):
|
||||
if event.mimeData().hasFormat("text/uri-list") \
|
||||
or event.mimeData().hasFormat("application/x-gns3-appliance"):
|
||||
event.acceptProposedAction()
|
||||
event.accept()
|
||||
else:
|
||||
@@ -627,10 +626,8 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
"""
|
||||
|
||||
# check if what has been dropped is handled by this view
|
||||
if event.mimeData().hasFormat("application/x-gns3-node"):
|
||||
data = event.mimeData().data("application/x-gns3-node")
|
||||
# load the pickled node data
|
||||
node_data = pickle.loads(data)
|
||||
if event.mimeData().hasFormat("application/x-gns3-appliance"):
|
||||
appliance_id = event.mimeData().data("application/x-gns3-appliance").data().decode()
|
||||
event.setDropAction(QtCore.Qt.CopyAction)
|
||||
event.accept()
|
||||
if event.keyboardModifiers() == QtCore.Qt.ShiftModifier:
|
||||
@@ -641,12 +638,9 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
for node_number in range(integer):
|
||||
x = event.pos().x() - (150 / 2) + (node_number % max_nodes_per_line) * offset
|
||||
y = event.pos().y() - (70 / 2) + (node_number // max_nodes_per_line) * offset
|
||||
node_item = self.createNode(node_data, QtCore.QPoint(x, y))
|
||||
if node_item is None:
|
||||
# stop if there is any error
|
||||
break
|
||||
self.createNodeFromApplianceId(appliance_id, QtCore.QPoint(x, y))
|
||||
else:
|
||||
self.createNode(node_data, event.pos())
|
||||
self.createNodeFromApplianceId(appliance_id, event.pos())
|
||||
elif event.mimeData().hasFormat("text/uri-list") and event.mimeData().hasUrls():
|
||||
# This should not arrive but we received bug report with it...
|
||||
if len(event.mimeData().urls()) == 0:
|
||||
@@ -1434,38 +1428,12 @@ class GraphicsView(QtWidgets.QGraphicsView):
|
||||
raise ModuleError("Please select a server")
|
||||
return server
|
||||
|
||||
def createNode(self, node_data, pos):
|
||||
def createNodeFromApplianceId(self, appliance_id, pos):
|
||||
"""
|
||||
Creates a new node on the scene.
|
||||
|
||||
:param node_data: node data to create a new node
|
||||
:param pos: position of the drop event
|
||||
|
||||
:returns: NodeItem instance
|
||||
Ask the server to create a node using this appliance
|
||||
"""
|
||||
try:
|
||||
node_module = None
|
||||
for module in MODULES:
|
||||
instance = module.instance()
|
||||
node_class = module.getNodeClass(node_data["class"])
|
||||
if node_class in instance.classes():
|
||||
node_module = instance
|
||||
break
|
||||
|
||||
if not node_module:
|
||||
raise ModuleError("Could not find any module for {}".format(node_class))
|
||||
|
||||
node = node_module.instantiateNode(node_class, self.allocateCompute(node_data, instance), self._topology.project())
|
||||
# If no server is available a ValueError is raised
|
||||
except (ModuleError, ValueError) as e:
|
||||
QtWidgets.QMessageBox.critical(self, "Node creation", "{}".format(e))
|
||||
return
|
||||
|
||||
pos = self.mapToScene(pos)
|
||||
node_item = self.createNodeItem(node, node_data["symbol"], pos.x(), pos.y())
|
||||
node.setGraphics(node_item)
|
||||
node_module.createNode(node, node_data["name"])
|
||||
return node_item
|
||||
ApplianceManager().instance().createNodeFromApplianceId(self._topology.project(), appliance_id, pos.x(), pos.y())
|
||||
|
||||
def createNodeItem(self, node, symbol, x, y):
|
||||
node.setSymbol(symbol)
|
||||
|
||||
@@ -33,7 +33,6 @@ from .atm_switch import ATMSwitch
|
||||
from .settings import (
|
||||
BUILTIN_SETTINGS,
|
||||
CLOUD_SETTINGS,
|
||||
NAT_SETTINGS,
|
||||
ETHERNET_HUB_SETTINGS,
|
||||
ETHERNET_SWITCH_SETTINGS
|
||||
)
|
||||
@@ -227,40 +226,6 @@ class Builtin(Module):
|
||||
# create an instance of the node class
|
||||
return node_class(self, server, project)
|
||||
|
||||
def createNode(self, node, node_name):
|
||||
"""
|
||||
Creates a node.
|
||||
|
||||
:param node: Node instance
|
||||
:param node_name: Node name
|
||||
"""
|
||||
|
||||
if isinstance(node, Cloud):
|
||||
for key, info in self._cloud_nodes.items():
|
||||
if node_name == info["name"]:
|
||||
default_name_format = info["default_name_format"].replace('{name}', node_name)
|
||||
node.create(ports=info["ports_mapping"], default_name_format=default_name_format)
|
||||
return
|
||||
elif isinstance(node, Nat):
|
||||
for key, info in self._nat_nodes.items():
|
||||
if node_name == info["name"]:
|
||||
default_name_format = info["default_name_format"].replace('{name}', node_name)
|
||||
node.create(default_name_format=default_name_format)
|
||||
return
|
||||
elif isinstance(node, EthernetHub):
|
||||
for key, info in self._ethernet_hubs.items():
|
||||
if node_name == info["name"]:
|
||||
default_name_format = info["default_name_format"].replace('{name}', node_name)
|
||||
node.create(ports=info["ports_mapping"], default_name_format=default_name_format)
|
||||
return
|
||||
elif isinstance(node, EthernetSwitch):
|
||||
for key, info in self._ethernet_switches.items():
|
||||
if node_name == info["name"]:
|
||||
default_name_format = info["default_name_format"].replace('{name}', node_name)
|
||||
node.create(ports=info["ports_mapping"], default_name_format=default_name_format)
|
||||
return
|
||||
node.create()
|
||||
|
||||
@staticmethod
|
||||
def findAlternativeInterface(node, missing_interface):
|
||||
|
||||
@@ -328,17 +293,6 @@ class Builtin(Module):
|
||||
"""
|
||||
|
||||
nodes = []
|
||||
for node_class in Builtin.classes():
|
||||
nodes.append(
|
||||
{"class": node_class.__name__,
|
||||
"name": node_class.symbolName(),
|
||||
"categories": node_class.categories(),
|
||||
"symbol": node_class.defaultSymbol(),
|
||||
"builtin": True,
|
||||
"node_type": node_class.URL_PREFIX
|
||||
}
|
||||
)
|
||||
|
||||
# add custom cloud node templates
|
||||
for cloud_node in self._cloud_nodes.values():
|
||||
nodes.append(
|
||||
@@ -369,9 +323,8 @@ class Builtin(Module):
|
||||
"server": switch["server"],
|
||||
"symbol": switch["symbol"],
|
||||
"categories": [switch["category"]]
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
return nodes
|
||||
|
||||
@staticmethod
|
||||
|
||||
@@ -140,55 +140,6 @@ class Docker(Module):
|
||||
# create an instance of the node class
|
||||
return node_class(self, server, project)
|
||||
|
||||
def createNode(self, node, node_name):
|
||||
"""
|
||||
Creates a node.
|
||||
|
||||
:param node: Node instance
|
||||
:param node_name: Node name
|
||||
"""
|
||||
|
||||
image = None
|
||||
if node_name:
|
||||
for image_key, info in self._docker_containers.items():
|
||||
if node_name == info["name"]:
|
||||
image = image_key
|
||||
if not image:
|
||||
selected_images = []
|
||||
for image, info in self._docker_containers.items():
|
||||
if info["server"] == node.compute().id():
|
||||
selected_images.append(image)
|
||||
|
||||
if not selected_images:
|
||||
raise ModuleError("No Docker VM on server {}".format(
|
||||
node.server().url()))
|
||||
elif len(selected_images) > 1:
|
||||
from gns3.main_window import MainWindow
|
||||
mainwindow = MainWindow.instance()
|
||||
|
||||
(selection, ok) = QtWidgets.QInputDialog.getItem(
|
||||
mainwindow, "Docker Image", "Please choose an image",
|
||||
selected_images, 0, False)
|
||||
if ok:
|
||||
image = selection
|
||||
else:
|
||||
raise ModuleError("Please select a Docker Image")
|
||||
else:
|
||||
image = selected_images[0]
|
||||
|
||||
image_settings = {}
|
||||
for setting_name, value in self._docker_containers[image].items():
|
||||
if setting_name in node.settings() and value != "" and value is not None:
|
||||
if setting_name not in ['name', 'image']:
|
||||
image_settings[setting_name] = value
|
||||
|
||||
default_name_format = DOCKER_CONTAINER_SETTINGS["default_name_format"]
|
||||
if self._docker_containers[image]["default_name_format"]:
|
||||
default_name_format = self._docker_containers[image]["default_name_format"]
|
||||
|
||||
image = self._docker_containers[image]["image"]
|
||||
node.create(image, base_name=node_name, additional_settings=image_settings, default_name_format=default_name_format)
|
||||
|
||||
def reset(self):
|
||||
"""Resets the servers."""
|
||||
self._nodes.clear()
|
||||
|
||||
@@ -248,50 +248,6 @@ class Dynamips(Module):
|
||||
# create an instance of the node class
|
||||
return node_class(self, server, project)
|
||||
|
||||
def createNode(self, node, node_name):
|
||||
"""
|
||||
Creates a node.
|
||||
|
||||
:param node: Node instance
|
||||
:param node_name: Node name
|
||||
"""
|
||||
|
||||
if isinstance(node, Router):
|
||||
ios_router = None
|
||||
if node_name:
|
||||
for ios_key, info in self._ios_routers.items():
|
||||
if node_name == info["name"]:
|
||||
ios_router = self._ios_routers[ios_key]
|
||||
break
|
||||
|
||||
if not ios_router:
|
||||
raise ModuleError("No IOS router for platform {}".format(node.settings()["platform"]))
|
||||
|
||||
vm_settings = {}
|
||||
for setting_name, value in ios_router.items():
|
||||
if setting_name in node.settings() and setting_name != "name" and value != "" and value is not None:
|
||||
vm_settings[setting_name] = value
|
||||
|
||||
default_name_format = IOS_ROUTER_SETTINGS["default_name_format"]
|
||||
if ios_router["default_name_format"]:
|
||||
default_name_format = ios_router["default_name_format"]
|
||||
|
||||
# Older GNS3 versions may have the following invalid settings in the VM template
|
||||
if "console" in vm_settings:
|
||||
del vm_settings["console"]
|
||||
if "sensors" in vm_settings:
|
||||
del vm_settings["sensors"]
|
||||
if "power_supplies" in vm_settings:
|
||||
del vm_settings["power_supplies"]
|
||||
|
||||
ram = vm_settings.pop("ram")
|
||||
image = vm_settings.pop("image", None)
|
||||
if image is None:
|
||||
raise ModuleError("No IOS image has been associated with this IOS router")
|
||||
node.create(image, ram, additional_settings=vm_settings, default_name_format=default_name_format)
|
||||
else:
|
||||
node.create()
|
||||
|
||||
def updateImageIdlepc(self, image_path, idlepc):
|
||||
"""
|
||||
Updates the Idle-PC for an IOS image.
|
||||
|
||||
@@ -177,62 +177,6 @@ class IOU(Module):
|
||||
# create an instance of the node class
|
||||
return node_class(self, server, project)
|
||||
|
||||
def createNode(self, node, node_name):
|
||||
"""
|
||||
Creates a node.
|
||||
|
||||
:param node: Node instance
|
||||
:param node_name: Node name
|
||||
"""
|
||||
|
||||
iouimage = None
|
||||
if node_name:
|
||||
for iou_key, info in self._iou_devices.items():
|
||||
if node_name == info["name"]:
|
||||
iouimage = iou_key
|
||||
|
||||
if not iouimage:
|
||||
selected_images = []
|
||||
for image, info in self._iou_devices.items():
|
||||
if info["server"] == node.compute().id():
|
||||
selected_images.append(image)
|
||||
|
||||
if not selected_images:
|
||||
raise ModuleError("No IOU image found for this device")
|
||||
elif len(selected_images) > 1:
|
||||
|
||||
from gns3.main_window import MainWindow
|
||||
mainwindow = MainWindow.instance()
|
||||
|
||||
(selection, ok) = QtWidgets.QInputDialog.getItem(mainwindow, "IOU image", "Please choose an image", selected_images, 0, False)
|
||||
if ok:
|
||||
iouimage = selection
|
||||
else:
|
||||
raise ModuleError("Please select an IOU image")
|
||||
|
||||
else:
|
||||
iouimage = selected_images[0]
|
||||
|
||||
vm_settings = {}
|
||||
for setting_name, value in self._iou_devices[iouimage].items():
|
||||
if setting_name in node.settings() and setting_name != "name" and value != "" and value is not None:
|
||||
vm_settings[setting_name] = value
|
||||
|
||||
default_name_format = IOU_DEVICE_SETTINGS["default_name_format"]
|
||||
if self._iou_devices[iouimage]["default_name_format"]:
|
||||
default_name_format = self._iou_devices[iouimage]["default_name_format"]
|
||||
|
||||
if vm_settings["use_default_iou_values"]:
|
||||
del vm_settings["ram"]
|
||||
del vm_settings["nvram"]
|
||||
|
||||
if "console" in vm_settings:
|
||||
# Older GNS3 versions may have a console setting in the VM template
|
||||
del vm_settings["console"]
|
||||
|
||||
iou_path = vm_settings.pop("path")
|
||||
node.create(iou_path, additional_settings=vm_settings, default_name_format=default_name_format)
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Resets the servers.
|
||||
|
||||
@@ -61,19 +61,6 @@ class IOUDevice(Node):
|
||||
|
||||
self.settings().update(iou_device_settings)
|
||||
|
||||
def create(self, iou_path, name=None, node_id=None, additional_settings={}, default_name_format="IOU{0}"):
|
||||
"""
|
||||
Creates this IOU device.
|
||||
|
||||
:param iou_path: path to an IOU image
|
||||
:param name: optional name
|
||||
:param console: optional TCP console port
|
||||
"""
|
||||
|
||||
params = {"path": iou_path}
|
||||
params.update(additional_settings)
|
||||
self._create(name, node_id, params, default_name_format)
|
||||
|
||||
def _createCallback(self, result):
|
||||
"""
|
||||
Callback for create.
|
||||
|
||||
@@ -177,67 +177,6 @@ class Qemu(Module):
|
||||
# create an instance of the node class
|
||||
return node_class(self, server, project)
|
||||
|
||||
def createNode(self, node, node_name):
|
||||
"""
|
||||
Creates a node.
|
||||
|
||||
:param node: Node instance
|
||||
:param node_name: Node name
|
||||
"""
|
||||
|
||||
vm = None
|
||||
if node_name:
|
||||
for vm_key, info in self._qemu_vms.items():
|
||||
if node_name == info["name"]:
|
||||
vm = vm_key
|
||||
|
||||
if not vm:
|
||||
selected_vms = []
|
||||
for vm, info in self._qemu_vms.items():
|
||||
if info["server"] == node.compute().id():
|
||||
selected_vms.append(vm)
|
||||
|
||||
if not selected_vms:
|
||||
raise ModuleError("No QEMU VM on server {}".format(node.server().host()))
|
||||
elif len(selected_vms) > 1:
|
||||
|
||||
from gns3.main_window import MainWindow
|
||||
mainwindow = MainWindow.instance()
|
||||
|
||||
(selection, ok) = QtWidgets.QInputDialog.getItem(mainwindow, "QEMU VM", "Please choose a VM", selected_vms, 0, False)
|
||||
if ok:
|
||||
vm = selection
|
||||
else:
|
||||
raise ModuleError("Please select a QEMU VM")
|
||||
else:
|
||||
vm = selected_vms[0]
|
||||
|
||||
vm_settings = {}
|
||||
for setting_name, value in self._qemu_vms[vm].items():
|
||||
if setting_name in node.settings() and value != "" and value is not None:
|
||||
vm_settings[setting_name] = value
|
||||
|
||||
qemu_path = vm_settings.pop("qemu_path")
|
||||
name = vm_settings.pop("name")
|
||||
port_name_format = self._qemu_vms[vm]["port_name_format"]
|
||||
port_segment_size = self._qemu_vms[vm]["port_segment_size"]
|
||||
first_port_name = self._qemu_vms[vm]["first_port_name"]
|
||||
|
||||
default_name_format = QEMU_VM_SETTINGS["default_name_format"]
|
||||
if self._qemu_vms[vm]["default_name_format"]:
|
||||
default_name_format = self._qemu_vms[vm]["default_name_format"]
|
||||
if self._qemu_vms[vm]["linked_base"]:
|
||||
name = default_name_format.replace('{name}', name)
|
||||
|
||||
node.create(qemu_path,
|
||||
name=name,
|
||||
port_name_format=port_name_format,
|
||||
port_segment_size=port_segment_size,
|
||||
first_port_name=first_port_name,
|
||||
linked_clone=self._qemu_vms[vm]["linked_base"],
|
||||
additional_settings=vm_settings,
|
||||
default_name_format=default_name_format)
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Resets the servers.
|
||||
|
||||
@@ -219,68 +219,6 @@ class VirtualBox(Module):
|
||||
# create an instance of the node class
|
||||
return node_class(self, server, project)
|
||||
|
||||
def createNode(self, node, node_name):
|
||||
"""
|
||||
Creates a node.
|
||||
|
||||
:param node: Node instance
|
||||
:param node_name: Node name
|
||||
"""
|
||||
|
||||
vm = None
|
||||
if node_name:
|
||||
for vm_key, info in self._virtualbox_vms.items():
|
||||
if node_name == info["name"]:
|
||||
vm = vm_key
|
||||
|
||||
if not vm:
|
||||
selected_vms = []
|
||||
for vm, info in self._virtualbox_vms.items():
|
||||
if info["server"] == node.compute().id():
|
||||
selected_vms.append(vm)
|
||||
|
||||
if not selected_vms:
|
||||
raise ModuleError("No VirtualBox VM on server {}".format(node.server().url()))
|
||||
elif len(selected_vms) > 1:
|
||||
|
||||
from gns3.main_window import MainWindow
|
||||
mainwindow = MainWindow.instance()
|
||||
|
||||
(selection, ok) = QtWidgets.QInputDialog.getItem(mainwindow, "VirtualBox VM", "Please choose a VM", selected_vms, 0, False)
|
||||
if ok:
|
||||
vm = selection
|
||||
else:
|
||||
raise ModuleError("Please select a VirtualBox VM")
|
||||
|
||||
else:
|
||||
vm = selected_vms[0]
|
||||
|
||||
vm_settings = {}
|
||||
for setting_name, value in self._virtualbox_vms[vm].items():
|
||||
if setting_name != "name" and setting_name in node.settings() and value != "" and value is not None:
|
||||
vm_settings[setting_name] = value
|
||||
|
||||
name = self._virtualbox_vms[vm]["name"]
|
||||
vmname = self._virtualbox_vms[vm]["vmname"]
|
||||
port_name_format = self._virtualbox_vms[vm]["port_name_format"]
|
||||
port_segment_size = self._virtualbox_vms[vm]["port_segment_size"]
|
||||
first_port_name = self._virtualbox_vms[vm]["first_port_name"]
|
||||
|
||||
default_name_format = VBOX_VM_SETTINGS["default_name_format"]
|
||||
if self._virtualbox_vms[vm]["default_name_format"]:
|
||||
default_name_format = self._virtualbox_vms[vm]["default_name_format"]
|
||||
if self._virtualbox_vms[vm]["linked_base"]:
|
||||
name = default_name_format.replace('{name}', name)
|
||||
|
||||
node.create(vmname,
|
||||
name=name,
|
||||
port_name_format=port_name_format,
|
||||
port_segment_size=port_segment_size,
|
||||
first_port_name=first_port_name,
|
||||
linked_clone=self._virtualbox_vms[vm]["linked_base"],
|
||||
additional_settings=vm_settings,
|
||||
default_name_format=default_name_format)
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Resets the module.
|
||||
|
||||
@@ -286,68 +286,6 @@ class VMware(Module):
|
||||
# create an instance of the node class
|
||||
return node_class(self, server, project)
|
||||
|
||||
def createNode(self, node, node_name):
|
||||
"""
|
||||
Creates a node.
|
||||
|
||||
:param node: Node instance
|
||||
:param node_name: Node name
|
||||
"""
|
||||
|
||||
vm = None
|
||||
if node_name:
|
||||
for vm_key, info in self._vmware_vms.items():
|
||||
if node_name == info["name"]:
|
||||
vm = vm_key
|
||||
|
||||
if not vm:
|
||||
selected_vms = []
|
||||
for vm, info in self._vmware_vms.items():
|
||||
if info["server"] == node.compute().id():
|
||||
selected_vms.append(vm)
|
||||
|
||||
if not selected_vms:
|
||||
raise ModuleError("No VMware VM on server {}".format(node.server().url()))
|
||||
elif len(selected_vms) > 1:
|
||||
|
||||
from gns3.main_window import MainWindow
|
||||
mainwindow = MainWindow.instance()
|
||||
|
||||
(selection, ok) = QtWidgets.QInputDialog.getItem(mainwindow, "VMware VM", "Please choose a VM", selected_vms, 0, False)
|
||||
if ok:
|
||||
vm = selection
|
||||
else:
|
||||
raise ModuleError("Please select a VMware VM")
|
||||
else:
|
||||
vm = selected_vms[0]
|
||||
|
||||
linked_base = self._vmware_vms[vm]["linked_base"]
|
||||
vm_settings = {}
|
||||
for setting_name, value in self._vmware_vms[vm].items():
|
||||
if setting_name in node.settings():
|
||||
vm_settings[setting_name] = value
|
||||
|
||||
vmx_path = vm_settings.pop("vmx_path")
|
||||
name = vm_settings.pop("name")
|
||||
port_name_format = self._vmware_vms[vm]["port_name_format"]
|
||||
port_segment_size = self._vmware_vms[vm]["port_segment_size"]
|
||||
first_port_name = self._vmware_vms[vm]["first_port_name"]
|
||||
|
||||
default_name_format = VMWARE_VM_SETTINGS["default_name_format"]
|
||||
if self._vmware_vms[vm]["default_name_format"]:
|
||||
default_name_format = self._vmware_vms[vm]["default_name_format"]
|
||||
if linked_base:
|
||||
name = default_name_format.replace('{name}', name)
|
||||
|
||||
node.create(vmx_path,
|
||||
name=name,
|
||||
port_name_format=port_name_format,
|
||||
port_segment_size=port_segment_size,
|
||||
first_port_name=first_port_name,
|
||||
linked_clone=linked_base,
|
||||
additional_settings=vm_settings,
|
||||
default_name_format=default_name_format)
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Resets the module.
|
||||
|
||||
@@ -160,33 +160,6 @@ class VPCS(Module):
|
||||
# create an instance of the node class
|
||||
return node_class(self, server, project)
|
||||
|
||||
def createNode(self, node, node_name):
|
||||
"""
|
||||
Creates a node.
|
||||
|
||||
:param node: Node instance
|
||||
:param node_name: Node name
|
||||
"""
|
||||
|
||||
log.info("creating node {}".format(node))
|
||||
|
||||
vm_settings = {
|
||||
"base_script_file": "vpcs_base_config.txt"
|
||||
}
|
||||
if node_name:
|
||||
for node_key, info in self._vpcs_nodes.items():
|
||||
if node_name == info["name"]:
|
||||
|
||||
for setting_name, value in self._vpcs_nodes[node_key].items():
|
||||
|
||||
if setting_name in node.settings() and setting_name != "name" and value != "" and value is not None:
|
||||
vm_settings[setting_name] = value
|
||||
|
||||
node.create(default_name_format=info["default_name_format"], additional_settings=vm_settings)
|
||||
return
|
||||
|
||||
node.create(additional_settings=vm_settings)
|
||||
|
||||
def reset(self):
|
||||
"""
|
||||
Resets the module.
|
||||
@@ -194,18 +167,6 @@ class VPCS(Module):
|
||||
|
||||
self._nodes.clear()
|
||||
|
||||
@staticmethod
|
||||
def getNodeClass(name):
|
||||
"""
|
||||
Returns the object with the corresponding name.
|
||||
|
||||
:param name: object name
|
||||
"""
|
||||
|
||||
if name in globals():
|
||||
return globals()[name]
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def getNodeType(name, platform=None):
|
||||
if name == "vpcs":
|
||||
@@ -262,16 +223,6 @@ class VPCS(Module):
|
||||
"builtin": True
|
||||
}
|
||||
)
|
||||
|
||||
for node in self._vpcs_nodes.values():
|
||||
nodes.append(
|
||||
{"class": VPCSNode.__name__,
|
||||
"name": node["name"],
|
||||
"server": node["server"],
|
||||
"symbol": node["symbol"],
|
||||
"categories": [node["category"]]
|
||||
}
|
||||
)
|
||||
return nodes
|
||||
|
||||
@staticmethod
|
||||
|
||||
95
gns3/node.py
95
gns3/node.py
@@ -69,9 +69,6 @@ class Node(BaseNode):
|
||||
with open(context["path"], "wb+") as f:
|
||||
f.write(raw_body)
|
||||
|
||||
def creator(self):
|
||||
return self._creator
|
||||
|
||||
def settings(self):
|
||||
return self._settings
|
||||
|
||||
@@ -220,66 +217,6 @@ class Node(BaseNode):
|
||||
|
||||
return body
|
||||
|
||||
def _create(self, name=None, node_id=None, params=None, default_name_format="Node{0}", timeout=120):
|
||||
"""
|
||||
Create the node on the controller
|
||||
"""
|
||||
|
||||
self._creator = True
|
||||
if params is None:
|
||||
params = {}
|
||||
|
||||
if "symbol" in self._settings:
|
||||
params["symbol"] = self._settings["symbol"]
|
||||
params["x"] = self._settings["x"]
|
||||
params["y"] = self._settings["y"]
|
||||
if "label" in self._settings:
|
||||
params["label"] = self._settings["label"]
|
||||
|
||||
if not name:
|
||||
# use the default name format if no name is provided
|
||||
name = default_name_format
|
||||
|
||||
params["name"] = name
|
||||
if node_id is not None:
|
||||
self._node_id = node_id
|
||||
|
||||
body = self._prepareBody(params)
|
||||
self.controllerHttpPost("/nodes", self.createNodeCallback, body=body, timeout=timeout)
|
||||
|
||||
def createNodeCallback(self, result, error=False, **kwargs):
|
||||
"""
|
||||
Callback for create.
|
||||
|
||||
:param result: server response
|
||||
:param error: indicates an error (boolean)
|
||||
:returns: Boolean success or not
|
||||
"""
|
||||
if error:
|
||||
self.server_error_signal.emit(self.id(), "Error while setting up node: {}".format(result["message"]))
|
||||
self.deleted_signal.emit()
|
||||
self._module.removeNode(self)
|
||||
return False
|
||||
|
||||
result = self._parseResponse(result)
|
||||
self._created = True
|
||||
self._createCallback(result)
|
||||
|
||||
if self._loading:
|
||||
self.loaded_signal.emit()
|
||||
else:
|
||||
self.setInitialized(True)
|
||||
log.info("Node instance {} has been created".format(self.name()))
|
||||
self.created_signal.emit(self.id())
|
||||
self._module.addNode(self)
|
||||
|
||||
def _createCallback(self, result):
|
||||
"""
|
||||
Create callback compatible with the compute api.
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
def _update(self, params, timeout=60):
|
||||
"""
|
||||
Update the node on the controller
|
||||
@@ -380,6 +317,38 @@ class Node(BaseNode):
|
||||
new_port.setStatus(self.status())
|
||||
self._ports.append(new_port)
|
||||
|
||||
def createNodeCallback(self, result, error=False, **kwargs):
|
||||
"""
|
||||
Callback for create.
|
||||
|
||||
:param result: server response
|
||||
:param error: indicates an error (boolean)
|
||||
:returns: Boolean success or not
|
||||
"""
|
||||
if error:
|
||||
self.server_error_signal.emit(self.id(), "Error while setting up node: {}".format(result["message"]))
|
||||
self.deleted_signal.emit()
|
||||
self._module.removeNode(self)
|
||||
return False
|
||||
|
||||
result = self._parseResponse(result)
|
||||
self._created = True
|
||||
self._createCallback(result)
|
||||
|
||||
if self._loading:
|
||||
self.loaded_signal.emit()
|
||||
else:
|
||||
self.setInitialized(True)
|
||||
log.info("Node instance {} has been created".format(self.name()))
|
||||
self.created_signal.emit(self.id())
|
||||
self._module.addNode(self)
|
||||
|
||||
def _createCallback(self, result):
|
||||
"""
|
||||
Create callback compatible with the compute api.
|
||||
"""
|
||||
pass
|
||||
|
||||
def _updateCallback(self, result):
|
||||
"""
|
||||
Update callback compatible with the compute api.
|
||||
|
||||
@@ -21,9 +21,9 @@ on the QGraphics scene.
|
||||
"""
|
||||
|
||||
import tempfile
|
||||
import pickle
|
||||
import json
|
||||
import sip
|
||||
import os
|
||||
|
||||
from .qt import QtCore, QtGui, QtWidgets, qpartial
|
||||
from .modules import MODULES
|
||||
@@ -34,6 +34,14 @@ from .dialogs.configuration_dialog import ConfigurationDialog
|
||||
from .local_config import LocalConfig
|
||||
|
||||
|
||||
CATEGORY_TO_ID = {
|
||||
"firewall": 3,
|
||||
"guest": 2,
|
||||
"switch": 1,
|
||||
"multilayer_switch": 1,
|
||||
"router": 0
|
||||
}
|
||||
|
||||
CATEGORY_TO_ID = {
|
||||
"firewall": 3,
|
||||
"guest": 2,
|
||||
@@ -62,7 +70,7 @@ class NodesView(QtWidgets.QTreeWidget):
|
||||
# enables the possibility to drag items.
|
||||
self.setDragEnabled(True)
|
||||
|
||||
Controller.instance().connected_signal.connect(self.refresh)
|
||||
ApplianceManager.instance().appliances_changed_signal.connect(self.refresh)
|
||||
|
||||
def setCurrentSearch(self, search):
|
||||
self._current_search = search
|
||||
@@ -94,27 +102,40 @@ class NodesView(QtWidgets.QTreeWidget):
|
||||
|
||||
display_appliances = set()
|
||||
|
||||
if self._show_installed_appliances:
|
||||
for module in MODULES:
|
||||
for node in module.instance().nodes():
|
||||
if category is not None and category not in node["categories"]:
|
||||
continue
|
||||
if search != "" and search not in node["name"].lower():
|
||||
continue
|
||||
for appliance in ApplianceManager.instance().appliances():
|
||||
if category is not None and category != CATEGORY_TO_ID[appliance["category"]]:
|
||||
continue
|
||||
if search != "" and search.lower() not in appliance["name"].lower():
|
||||
continue
|
||||
display_appliances.add(appliance["name"])
|
||||
item = QtWidgets.QTreeWidgetItem(self)
|
||||
item.setText(0, appliance["name"])
|
||||
item.setData(0, QtCore.Qt.UserRole, appliance)
|
||||
item.setData(1, QtCore.Qt.UserRole, "node")
|
||||
item.setSizeHint(0, QtCore.QSize(32, 32))
|
||||
Controller.instance().getSymbolIcon(appliance["symbol"], qpartial(self._setItemIcon, item))
|
||||
|
||||
display_appliances.add(node["name"])
|
||||
item = QtWidgets.QTreeWidgetItem(self)
|
||||
item.setText(0, node["name"])
|
||||
item.setData(0, QtCore.Qt.UserRole, node)
|
||||
item.setData(1, QtCore.Qt.UserRole, "node")
|
||||
item.setSizeHint(0, QtCore.QSize(32, 32))
|
||||
Controller.instance().getSymbolIcon(node["symbol"], qpartial(self._setItemIcon, item))
|
||||
if self._show_installed_appliances:
|
||||
for appliance in ApplianceManager.instance().appliances():
|
||||
if category is not None and category != CATEGORY_TO_ID[appliance["category"]]:
|
||||
continue
|
||||
if search != "" and search.lower() not in appliance["name"].lower():
|
||||
continue
|
||||
if appliance["name"] in display_appliances:
|
||||
continue
|
||||
|
||||
item = QtWidgets.QTreeWidgetItem(self)
|
||||
item.setText(0, appliance["name"])
|
||||
item.setData(0, QtCore.Qt.UserRole, appliance["appliance_id"])
|
||||
item.setData(1, QtCore.Qt.UserRole, "appliance")
|
||||
item.setSizeHint(0, QtCore.QSize(32, 32))
|
||||
Controller.instance().getSymbolIcon(appliance.get("symbol"), qpartial(self._setItemIcon, item), fallback=":/symbols/" + appliance["category"] + ".svg")
|
||||
|
||||
if self._show_available_appliances:
|
||||
for appliance in ApplianceManager.instance().appliance_templates():
|
||||
if category is not None and category != CATEGORY_TO_ID[appliance["category"]]:
|
||||
continue
|
||||
if search != "" and search not in appliance["name"].lower():
|
||||
if search != "" and search.lower() not in appliance["name"].lower():
|
||||
continue
|
||||
if appliance["name"] in display_appliances:
|
||||
continue
|
||||
@@ -123,7 +144,7 @@ class NodesView(QtWidgets.QTreeWidget):
|
||||
item.setForeground(0, QtGui.QBrush(QtGui.QColor("gray")))
|
||||
item.setText(0, appliance["name"])
|
||||
item.setData(0, QtCore.Qt.UserRole, appliance)
|
||||
item.setData(1, QtCore.Qt.UserRole, "appliance")
|
||||
item.setData(1, QtCore.Qt.UserRole, "appliance_template")
|
||||
item.setSizeHint(0, QtCore.QSize(32, 32))
|
||||
Controller.instance().getSymbolIcon(appliance.get("symbol"), qpartial(self._setItemIcon, item), fallback=":/symbols/" + appliance["category"] + ".svg")
|
||||
|
||||
@@ -160,7 +181,7 @@ class NodesView(QtWidgets.QTreeWidget):
|
||||
item = self.currentItem()
|
||||
|
||||
# retrieve the node class from the item data
|
||||
if item.data(1, QtCore.Qt.UserRole) == "appliance":
|
||||
if item.data(1, QtCore.Qt.UserRole) == "appliance_template":
|
||||
f = tempfile.NamedTemporaryFile(mode="w+", suffix=".gns3a", delete=False)
|
||||
json.dump(item.data(0, QtCore.Qt.UserRole), f)
|
||||
f.close()
|
||||
@@ -168,13 +189,12 @@ class NodesView(QtWidgets.QTreeWidget):
|
||||
return
|
||||
|
||||
icon = item.icon(0)
|
||||
node = item.data(0, QtCore.Qt.UserRole)
|
||||
mimedata = QtCore.QMimeData()
|
||||
|
||||
# pickle the node class, set the Mime type and data
|
||||
# and start dragging the item.
|
||||
data = pickle.dumps(node)
|
||||
mimedata.setData("application/x-gns3-node", data)
|
||||
if item.data(1, QtCore.Qt.UserRole) == "appliance":
|
||||
appliance_id = item.data(0, QtCore.Qt.UserRole)
|
||||
mimedata.setData("application/x-gns3-appliance", appliance_id.encode())
|
||||
|
||||
drag = QtGui.QDrag(self)
|
||||
drag.setMimeData(mimedata)
|
||||
drag.setPixmap(icon.pixmap(self.iconSize()))
|
||||
@@ -184,17 +204,17 @@ class NodesView(QtWidgets.QTreeWidget):
|
||||
|
||||
def _showContextualMenu(self):
|
||||
item = self.currentItem()
|
||||
node = item.data(0, QtCore.Qt.UserRole)
|
||||
if "class" not in node:
|
||||
node = ApplianceManager.instance().getAppliance(item.data(0, QtCore.Qt.UserRole))
|
||||
if not node:
|
||||
return
|
||||
for module in MODULES:
|
||||
node_class = module.getNodeClass(node["class"])
|
||||
node_class = module.getNodeType(node["node_type"])
|
||||
if node_class:
|
||||
break
|
||||
|
||||
# We can not edit stuff like EthernetSwitch
|
||||
# or without config template like VPCS
|
||||
if "builtin" not in node and hasattr(module, "vmConfigurationPage"):
|
||||
if not node["builtin"] and hasattr(module, "vmConfigurationPage"):
|
||||
for vm_key, vm in module.instance().VMs().items():
|
||||
if vm["name"] == node["name"]:
|
||||
break
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import os
|
||||
import sys
|
||||
import traceback
|
||||
from .qt import QtCore, qpartial, QtWidgets, QtNetwork
|
||||
|
||||
from gns3.controller import Controller
|
||||
@@ -25,7 +23,7 @@ from gns3.compute_manager import ComputeManager
|
||||
from gns3.topology import Topology
|
||||
from gns3.local_config import LocalConfig
|
||||
from gns3.settings import GRAPHICS_VIEW_SETTINGS
|
||||
|
||||
from gns3.appliance_manager import ApplianceManager
|
||||
|
||||
import logging
|
||||
log = logging.getLogger(__name__)
|
||||
@@ -516,5 +514,6 @@ class Project(QtCore.QObject):
|
||||
cm.computeDataReceivedCallback(result["event"])
|
||||
elif result["action"] == "settings.updated":
|
||||
LocalConfig.instance().refreshConfigFromController()
|
||||
ApplianceManager.instance().refresh()
|
||||
elif result["action"] == "ping":
|
||||
pass
|
||||
|
||||
@@ -26,27 +26,6 @@ def test_docker_vm_init(local_server, project):
|
||||
vm = DockerVM(Docker(), local_server, project)
|
||||
|
||||
|
||||
def test_docker_vm_create(project, local_server):
|
||||
|
||||
docker_vm = DockerVM(Docker(), local_server, project)
|
||||
with patch('gns3.project.Project.post') as mock:
|
||||
docker_vm.create("ubuntu", base_name="ubuntu")
|
||||
mock.assert_called_with("/nodes",
|
||||
docker_vm.createNodeCallback,
|
||||
body={
|
||||
"node_id": docker_vm._node_id,
|
||||
"compute_id": "local",
|
||||
"node_type": "docker",
|
||||
"properties": {
|
||||
"adapters": 1,
|
||||
"image": "ubuntu",
|
||||
},
|
||||
"name": "ubuntu-{0}"
|
||||
},
|
||||
context={},
|
||||
timeout=None)
|
||||
|
||||
|
||||
def test_createCallback(project, local_server):
|
||||
docker_vm = DockerVM(Docker(), local_server, project)
|
||||
|
||||
|
||||
@@ -40,72 +40,6 @@ def test_iou_device_init(local_server, project):
|
||||
iou_device = IOUDevice(None, local_server, project)
|
||||
|
||||
|
||||
def test_iou_device_create(iou_device, project):
|
||||
|
||||
with patch('gns3.project.Project.post') as mock:
|
||||
iou_device.create("/tmp/iou.bin", name="PC 1")
|
||||
mock.assert_called_with("/nodes",
|
||||
iou_device.createNodeCallback,
|
||||
body={
|
||||
'node_id': iou_device._node_id,
|
||||
'name': 'PC 1',
|
||||
'properties': {
|
||||
'path': '/tmp/iou.bin',
|
||||
},
|
||||
'node_type': 'iou',
|
||||
'compute_id': 'local'
|
||||
},
|
||||
context={},
|
||||
timeout=120)
|
||||
|
||||
# Callback
|
||||
params = {
|
||||
"console": 2000,
|
||||
"name": "PC1",
|
||||
"project_id": "f91bd115-3b5c-402e-b411-e5919723cf4b",
|
||||
"node_id": "aec7a00c-e71c-45a6-8c04-29e40732883c",
|
||||
"path": "iou.bin",
|
||||
"md5sum": "0cc175b9c0f1b6a831c399e269772661"
|
||||
}
|
||||
iou_device.createNodeCallback(params)
|
||||
|
||||
assert iou_device.node_id() == "aec7a00c-e71c-45a6-8c04-29e40732883c"
|
||||
|
||||
|
||||
def test_iou_device_setup_with_uuid(iou_device, project):
|
||||
"""
|
||||
If we have an ID that mean the VM already exits and we should not send startup_script
|
||||
"""
|
||||
|
||||
with patch('gns3.project.Project.post') as mock:
|
||||
iou_device.create("/tmp/iou.bin", name="PC 1", node_id="aec7a00c-e71c-45a6-8c04-29e40732883c")
|
||||
mock.assert_called_with("/nodes",
|
||||
iou_device.createNodeCallback,
|
||||
body={'name': 'PC 1',
|
||||
'properties': {
|
||||
'path': '/tmp/iou.bin',
|
||||
},
|
||||
'node_type': 'iou',
|
||||
'node_id': 'aec7a00c-e71c-45a6-8c04-29e40732883c',
|
||||
'compute_id': 'local'
|
||||
},
|
||||
context={},
|
||||
timeout=120)
|
||||
|
||||
# Callback
|
||||
params = {
|
||||
"console": 2000,
|
||||
"name": "PC1",
|
||||
"project_id": "f91bd115-3b5c-402e-b411-e5919723cf4b",
|
||||
"node_id": "aec7a00c-e71c-45a6-8c04-29e40732883c",
|
||||
"path": "iou.bin",
|
||||
"md5sum": "0cc175b9c0f1b6a831c399e269772661"
|
||||
}
|
||||
iou_device.createNodeCallback(params)
|
||||
|
||||
assert iou_device.node_id() == "aec7a00c-e71c-45a6-8c04-29e40732883c"
|
||||
|
||||
|
||||
def test_update(iou_device):
|
||||
|
||||
new_settings = {
|
||||
|
||||
@@ -27,79 +27,6 @@ def test_qemu_vm_init(local_server, project):
|
||||
vm = QemuVM(None, local_server, project)
|
||||
|
||||
|
||||
def test_qemu_vm_create(qemu_vm, project):
|
||||
|
||||
with patch('gns3.project.Project.post') as mock:
|
||||
qemu_vm.create("/bin/fake", name="VMNAME")
|
||||
mock.assert_called_with("/nodes",
|
||||
qemu_vm.createNodeCallback,
|
||||
body={
|
||||
'node_id': qemu_vm._node_id,
|
||||
'name': 'VMNAME',
|
||||
'properties': {
|
||||
'linked_clone': True,
|
||||
'qemu_path': '/bin/fake'
|
||||
},
|
||||
'port_name_format': 'Ethernet{0}',
|
||||
'first_port_name': '',
|
||||
'port_segment_size': 0,
|
||||
'compute_id': 'local',
|
||||
'node_type': 'qemu'
|
||||
},
|
||||
context={},
|
||||
timeout=120)
|
||||
|
||||
# Callback
|
||||
params = {
|
||||
"name": "QEMU1",
|
||||
"vmname": "VMNAME",
|
||||
"project_id": "f91bd115-3b5c-402e-b411-e5919723cf4b",
|
||||
"node_id": "aec7a00c-e71c-45a6-8c04-29e40732883c",
|
||||
"node_directory": "/tmp/test",
|
||||
"hda_disk_image": "0cc175b9c0f1b6a831c399e269772661"
|
||||
}
|
||||
qemu_vm.createNodeCallback(params)
|
||||
assert qemu_vm.node_id() == "aec7a00c-e71c-45a6-8c04-29e40732883c"
|
||||
assert qemu_vm.nodeDir() == "/tmp/test"
|
||||
|
||||
|
||||
def test_qemu_vm_setup_command_line(qemu_vm, project):
|
||||
|
||||
with patch('gns3.project.Project.post') as mock:
|
||||
qemu_vm.create("/bin/fake", name="VMNAME")
|
||||
mock.assert_called_with("/nodes",
|
||||
qemu_vm.createNodeCallback,
|
||||
body={
|
||||
'node_id': qemu_vm._node_id,
|
||||
'name': 'VMNAME',
|
||||
'properties': {
|
||||
'linked_clone': True,
|
||||
'qemu_path': '/bin/fake'
|
||||
},
|
||||
'port_name_format': 'Ethernet{0}',
|
||||
'first_port_name': '',
|
||||
'port_segment_size': 0,
|
||||
'compute_id': 'local',
|
||||
'node_type': 'qemu'
|
||||
},
|
||||
context={},
|
||||
timeout=120)
|
||||
|
||||
# Callback
|
||||
params = {
|
||||
"name": "QEMU1",
|
||||
"vmname": "VMNAME",
|
||||
"project_id": "f91bd115-3b5c-402e-b411-e5919723cf4b",
|
||||
"node_id": "aec7a00c-e71c-45a6-8c04-29e40732883c",
|
||||
"vm_directory": "/tmp/test",
|
||||
"hda_disk_image": "0cc175b9c0f1b6a831c399e269772661",
|
||||
"command_line": "/bin/fake"
|
||||
}
|
||||
qemu_vm.createNodeCallback(params)
|
||||
assert qemu_vm.node_id() == "aec7a00c-e71c-45a6-8c04-29e40732883c"
|
||||
assert qemu_vm.commandLine() == "/bin/fake"
|
||||
|
||||
|
||||
def test_update(qemu_vm):
|
||||
|
||||
new_settings = {
|
||||
|
||||
@@ -27,41 +27,6 @@ def test_virtualbox_vm_init(local_server, project):
|
||||
vm = VirtualBoxVM(None, local_server, project)
|
||||
|
||||
|
||||
def test_virtualbox_vm_create(virtualbox_vm, project):
|
||||
|
||||
with patch('gns3.project.Project.post') as mock:
|
||||
virtualbox_vm.create("VMNAME")
|
||||
mock.assert_called_with("/nodes",
|
||||
virtualbox_vm.createNodeCallback,
|
||||
body={
|
||||
'node_id': virtualbox_vm._node_id,
|
||||
'name': 'VMNAME',
|
||||
'compute_id': 'local',
|
||||
'node_type': 'virtualbox',
|
||||
'properties': {
|
||||
'linked_clone': False,
|
||||
'vmname': 'VMNAME'
|
||||
},
|
||||
'port_name_format': 'Ethernet{0}',
|
||||
'port_segment_size': 0,
|
||||
'first_port_name': ''
|
||||
},
|
||||
context={},
|
||||
timeout=120)
|
||||
|
||||
# Callback
|
||||
params = {
|
||||
"name": "VBOX1",
|
||||
"vmname": "VMNAME",
|
||||
"linked_clone": False,
|
||||
"adapters": 0,
|
||||
"project_id": "f91bd115-3b5c-402e-b411-e5919723cf4b",
|
||||
"node_id": "aec7a00c-e71c-45a6-8c04-29e40732883c"
|
||||
}
|
||||
virtualbox_vm.createNodeCallback(params)
|
||||
assert virtualbox_vm.node_id() == "aec7a00c-e71c-45a6-8c04-29e40732883c"
|
||||
|
||||
|
||||
def test_update(virtualbox_vm):
|
||||
|
||||
new_settings = {
|
||||
|
||||
@@ -29,68 +29,6 @@ def test_vpcs_device_init(local_server, project):
|
||||
vpcs_device = VPCSNode(None, local_server, project)
|
||||
|
||||
|
||||
def test_vpcs_device_create(vpcs_device, project, local_server):
|
||||
|
||||
with patch('gns3.base_node.BaseNode.controllerHttpPost') as mock:
|
||||
vpcs_device.create(name="PC 1", additional_settings={})
|
||||
assert mock.called
|
||||
args, kwargs = mock.call_args
|
||||
assert args[0] == "/nodes"
|
||||
assert kwargs["body"] == {
|
||||
"node_id": vpcs_device._node_id,
|
||||
"name": "PC 1",
|
||||
"compute_id": local_server.id(),
|
||||
"node_type": "vpcs",
|
||||
"properties": {
|
||||
}
|
||||
}
|
||||
|
||||
# Callback
|
||||
params = {
|
||||
"console": 2000,
|
||||
"name": "PC1",
|
||||
"node_id": "aec7a00c-e71c-45a6-8c04-29e40732883c",
|
||||
"project_id": "f91bd115-3b5c-402e-b411-e5919723cf4b",
|
||||
"properties": {
|
||||
}
|
||||
}
|
||||
vpcs_device.createNodeCallback(params)
|
||||
|
||||
assert vpcs_device.node_id() == "aec7a00c-e71c-45a6-8c04-29e40732883c"
|
||||
|
||||
|
||||
def test_vpcs_device_setup_with_uuid(vpcs_device, project, local_server):
|
||||
"""
|
||||
If we have an ID that mean the VM already exits and we should not send startup_script
|
||||
"""
|
||||
|
||||
with patch('gns3.base_node.BaseNode.controllerHttpPost') as mock:
|
||||
vpcs_device.create(name="PC 1", node_id="aec7a00c-e71c-45a6-8c04-29e40732883c", additional_settings={})
|
||||
assert mock.called
|
||||
args, kwargs = mock.call_args
|
||||
assert args[0] == "/nodes"
|
||||
assert kwargs["body"] == {
|
||||
"node_id": "aec7a00c-e71c-45a6-8c04-29e40732883c",
|
||||
"name": "PC 1",
|
||||
"compute_id": local_server.id(),
|
||||
"node_type": "vpcs",
|
||||
"properties": {}
|
||||
}
|
||||
|
||||
# Callback
|
||||
params = {
|
||||
"console": 2000,
|
||||
"name": "PC1",
|
||||
"project_id": "f91bd115-3b5c-402e-b411-e5919723cf4b",
|
||||
"node_id": "aec7a00c-e71c-45a6-8c04-29e40732883c",
|
||||
"properties": {
|
||||
}
|
||||
}
|
||||
vpcs_device.createNodeCallback(params)
|
||||
|
||||
assert vpcs_device.node_id() == "aec7a00c-e71c-45a6-8c04-29e40732883c"
|
||||
|
||||
|
||||
def test_update(vpcs_device):
|
||||
|
||||
new_settings = {
|
||||
|
||||
@@ -26,23 +26,6 @@ from gns3.ports.ethernet_port import EthernetPort
|
||||
from gns3.ports.serial_port import SerialPort
|
||||
|
||||
|
||||
def test_create(vpcs_device, local_server):
|
||||
with patch('gns3.base_node.BaseNode.controllerHttpPost') as mock:
|
||||
vpcs_device._create(name="PC 1", params={"startup_script": "echo TEST"})
|
||||
assert mock.called
|
||||
args, kwargs = mock.call_args
|
||||
assert args[0] == "/nodes"
|
||||
assert kwargs["body"] == {
|
||||
"name": "PC 1",
|
||||
"node_id": vpcs_device._node_id,
|
||||
"compute_id": local_server.id(),
|
||||
"node_type": "vpcs",
|
||||
"properties": {
|
||||
"startup_script": "echo TEST"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
def test_setupVMCallback(vpcs_device):
|
||||
node_id = str(uuid.uuid4())
|
||||
vpcs_device._createCallback = MagicMock()
|
||||
|
||||
Reference in New Issue
Block a user