mirror of
https://github.com/GNS3/gns3-gui.git
synced 2026-05-17 00:46:01 +03:00
Basic support to create new template from appliance.
This commit is contained in:
@@ -17,10 +17,14 @@
|
||||
|
||||
import os
|
||||
import sip
|
||||
import urllib
|
||||
import shutil
|
||||
from ssl import CertificateError
|
||||
|
||||
from ..qt import QtWidgets, QtCore, QtGui, qpartial, qslot
|
||||
from ..ui.appliance_wizard_ui import Ui_ApplianceWizard
|
||||
from ..template_manager import TemplateManager
|
||||
from ..template import Template
|
||||
from ..modules import Qemu
|
||||
from ..registry.appliance import Appliance, ApplianceError
|
||||
from ..registry.registry import Registry
|
||||
@@ -525,12 +529,6 @@ class ApplianceWizard(QtWidgets.QWizard, Ui_ApplianceWizard):
|
||||
:params version: appliance version name
|
||||
"""
|
||||
|
||||
try:
|
||||
config = Config()
|
||||
except (OSError, ValueError) as e:
|
||||
QtWidgets.QMessageBox.critical(self.parent(), "Add appliance", str(e))
|
||||
return False
|
||||
|
||||
if version is None:
|
||||
appliance_configuration = self._appliance.copy()
|
||||
if not "docker" in appliance_configuration:
|
||||
@@ -543,9 +541,10 @@ class ApplianceWizard(QtWidgets.QWizard, Ui_ApplianceWizard):
|
||||
QtWidgets.QMessageBox.critical(self.parent(), "Add appliance", str(e))
|
||||
return False
|
||||
|
||||
while len(appliance_configuration["name"]) == 0 or not config.is_name_available(appliance_configuration["name"]):
|
||||
QtWidgets.QMessageBox.warning(self.parent(), "Add appliance", "The name \"{}\" is already used by another appliance".format(appliance_configuration["name"]))
|
||||
appliance_configuration["name"], ok = QtWidgets.QInputDialog.getText(self.parent(), "Add appliance", "New name:", QtWidgets.QLineEdit.Normal, appliance_configuration["name"])
|
||||
template_manager = TemplateManager().instance()
|
||||
while len(appliance_configuration["name"]) == 0 or not template_manager.is_name_available(appliance_configuration["name"]):
|
||||
QtWidgets.QMessageBox.warning(self.parent(), "Add template", "The name \"{}\" is already used by another template".format(appliance_configuration["name"]))
|
||||
appliance_configuration["name"], ok = QtWidgets.QInputDialog.getText(self.parent(), "Add template", "New name:", QtWidgets.QLineEdit.Normal, appliance_configuration["name"])
|
||||
if not ok:
|
||||
return False
|
||||
appliance_configuration["name"] = appliance_configuration["name"].strip()
|
||||
@@ -553,18 +552,194 @@ class ApplianceWizard(QtWidgets.QWizard, Ui_ApplianceWizard):
|
||||
if "qemu" in appliance_configuration:
|
||||
appliance_configuration["qemu"]["path"] = self.uiQemuListComboBox.currentData()
|
||||
|
||||
worker = WaitForLambdaWorker(lambda: config.add_appliance(appliance_configuration, self._compute_id, self._symbols), allowed_exceptions=[ConfigException, OSError])
|
||||
progress_dialog = ProgressDialog(worker, "Add appliance", "Install the appliance...", None, busy=True, parent=self)
|
||||
progress_dialog.show()
|
||||
if not progress_dialog.exec_():
|
||||
return False
|
||||
self._create_template(appliance_configuration, self._compute_id)
|
||||
return True
|
||||
|
||||
worker = WaitForLambdaWorker(lambda: config.save(), allowed_exceptions=[ConfigException, OSError])
|
||||
progress_dialog = ProgressDialog(worker, "Add appliance", "Install the appliance...", None, busy=True, parent=self)
|
||||
progress_dialog.show()
|
||||
if progress_dialog.exec_():
|
||||
QtWidgets.QMessageBox.information(self.parent(), "Add appliance", "{} installed!".format(appliance_configuration["name"]))
|
||||
return True
|
||||
#worker = WaitForLambdaWorker(lambda: self._create_template(appliance_configuration, self._compute_id), allowed_exceptions=[ConfigException, OSError])
|
||||
#progress_dialog = ProgressDialog(worker, "Add template", "Installing a new template...", None, busy=True, parent=self)
|
||||
#progress_dialog.show()
|
||||
#if progress_dialog.exec_():
|
||||
# QtWidgets.QMessageBox.information(self.parent(), "Add template", "{} template has been installed!".format(appliance_configuration["name"]))
|
||||
# return True
|
||||
#return False
|
||||
|
||||
# worker = WaitForLambdaWorker(lambda: config.save(), allowed_exceptions=[ConfigException, OSError])
|
||||
# progress_dialog = ProgressDialog(worker, "Add appliance", "Install the appliance...", None, busy=True, parent=self)
|
||||
# progress_dialog.show()
|
||||
# if progress_dialog.exec_():
|
||||
# QtWidgets.QMessageBox.information(self.parent(), "Add appliance", "{} installed!".format(appliance_configuration["name"]))
|
||||
# return True
|
||||
|
||||
def _create_template(self, appliance_config, server):
|
||||
"""
|
||||
Creates a new template from an appliance.
|
||||
|
||||
:param appliance_config: Dictionary with appliance configuration
|
||||
:param server
|
||||
"""
|
||||
|
||||
new_template = {
|
||||
"compute_id": server,
|
||||
"name": appliance_config["name"]
|
||||
}
|
||||
|
||||
if "usage" in appliance_config:
|
||||
new_template["usage"] = appliance_config["usage"]
|
||||
|
||||
if appliance_config["category"] == "multilayer_switch":
|
||||
new_template["category"] = "switch"
|
||||
else:
|
||||
new_template["category"] = appliance_config["category"]
|
||||
|
||||
if "symbol" in appliance_config:
|
||||
new_template["symbol"] = self._set_symbol(appliance_config["symbol"], self._symbols)
|
||||
|
||||
if new_template.get("symbol") is None:
|
||||
if appliance_config["category"] == "guest":
|
||||
if "docker" in appliance_config:
|
||||
new_template["symbol"] = ":/symbols/docker_guest.svg"
|
||||
else:
|
||||
new_template["symbol"] = ":/symbols/qemu_guest.svg"
|
||||
elif appliance_config["category"] == "router":
|
||||
new_template["symbol"] = ":/symbols/router.svg"
|
||||
elif appliance_config["category"] == "switch":
|
||||
new_template["symbol"] = ":/symbols/ethernet_switch.svg"
|
||||
elif appliance_config["category"] == "multilayer_switch":
|
||||
new_template["symbol"] = ":/symbols/multilayer_switch.svg"
|
||||
elif appliance_config["category"] == "firewall":
|
||||
new_template["symbol"] = ":/symbols/firewall.svg"
|
||||
|
||||
if "qemu" in appliance_config:
|
||||
new_template["template_type"] = "qemu"
|
||||
self._add_qemu_config(new_template, appliance_config)
|
||||
elif "iou" in appliance_config:
|
||||
new_template["template_type"] = "iou"
|
||||
self._add_iou_config(new_template, appliance_config)
|
||||
elif "dynamips" in appliance_config:
|
||||
new_template["template_type"] = "dynamips"
|
||||
self._add_dynamips_config(new_template, appliance_config)
|
||||
elif "docker" in appliance_config:
|
||||
new_template["template_type"] = "docker"
|
||||
self._add_docker_config(new_template, appliance_config)
|
||||
else:
|
||||
raise ConfigException("{} no configuration found for known emulators".format(new_template["name"]))
|
||||
|
||||
TemplateManager.instance().createTemplate(Template(new_template))
|
||||
|
||||
def _add_qemu_config(self, new_config, appliance_config):
|
||||
|
||||
new_config.update(appliance_config["qemu"])
|
||||
|
||||
# the following properties are not valid for a template
|
||||
new_config.pop("kvm")
|
||||
new_config.pop("path")
|
||||
new_config.pop("arch")
|
||||
|
||||
options = appliance_config["qemu"].get("options", "")
|
||||
if "-nographic" not in options:
|
||||
options += " -nographic"
|
||||
if appliance_config["qemu"].get("kvm", "allow") == "disable" and "-no-kvm" not in options:
|
||||
options += " -no-kvm"
|
||||
new_config["options"] = options.strip()
|
||||
|
||||
for image in appliance_config["images"]:
|
||||
if image.get("path"):
|
||||
new_config[image["type"]] = self._relative_image_path("QEMU", image["path"])
|
||||
|
||||
if "path" in appliance_config["qemu"]:
|
||||
new_config["qemu_path"] = appliance_config["qemu"]["path"]
|
||||
else:
|
||||
new_config["qemu_path"] = "qemu-system-{}".format(appliance_config["qemu"]["arch"])
|
||||
|
||||
if "first_port_name" in appliance_config:
|
||||
new_config["first_port_name"] = appliance_config["first_port_name"]
|
||||
|
||||
if "port_name_format" in appliance_config:
|
||||
new_config["port_name_format"] = appliance_config["port_name_format"]
|
||||
|
||||
if "port_segment_size" in appliance_config:
|
||||
new_config["port_segment_size"] = appliance_config["port_segment_size"]
|
||||
|
||||
if "custom_adapters" in appliance_config:
|
||||
new_config["custom_adapters"] = appliance_config["custom_adapters"]
|
||||
|
||||
if "linked_clone" in appliance_config:
|
||||
new_config["linked_clone"] = appliance_config["linked_clone"]
|
||||
|
||||
def _add_docker_config(self, new_config, appliance_config):
|
||||
|
||||
new_config.update(appliance_config["docker"])
|
||||
|
||||
if "custom_adapters" in appliance_config:
|
||||
new_config["custom_adapters"] = appliance_config["custom_adapters"]
|
||||
|
||||
def _add_dynamips_config(self, new_config, appliance_config):
|
||||
|
||||
new_config.update(appliance_config["dynamips"])
|
||||
|
||||
for image in appliance_config["images"]:
|
||||
new_config[image["type"]] = self._relative_image_path("IOS", image["path"])
|
||||
new_config["idlepc"] = image.get("idlepc", "")
|
||||
|
||||
def _add_iou_config(self, new_config, appliance_config):
|
||||
|
||||
new_config.update(appliance_config["iou"])
|
||||
for image in appliance_config["images"]:
|
||||
if "path" not in image:
|
||||
raise ConfigException("Disk image is missing")
|
||||
new_config[image["type"]] = self._relative_image_path("IOU", image["path"])
|
||||
new_config["path"] = new_config["image"]
|
||||
|
||||
def _relative_image_path(self, image_dir_type, path):
|
||||
"""
|
||||
|
||||
:param image_dir_type: Type of image directory
|
||||
:param filename: Filename at the end of the process
|
||||
:param path: Full path to the file
|
||||
:returns: Path relative to image directory.
|
||||
Copy the image to the directory if not already in the directory
|
||||
"""
|
||||
|
||||
images_dir = os.path.join(Config().images_dir, image_dir_type)
|
||||
path = os.path.abspath(path)
|
||||
if os.path.commonprefix([images_dir, path]) == images_dir:
|
||||
return path.replace(images_dir, '').strip('/\\')
|
||||
|
||||
return os.path.basename(path)
|
||||
|
||||
def _set_symbol(self, symbol, controller_symbols):
|
||||
"""
|
||||
Check if exists on controller or download symbol from the web if needed
|
||||
"""
|
||||
|
||||
# GNS3 builtin symbol
|
||||
if symbol.startswith(":/symbols/"):
|
||||
return symbol
|
||||
|
||||
path = os.path.join(self.symbols_dir, symbol)
|
||||
if os.path.exists(path):
|
||||
return os.path.basename(path)
|
||||
|
||||
is_symbol_on_controller = len([s for s in controller_symbols
|
||||
if s['symbol_id'] == symbol]) > 0
|
||||
|
||||
if is_symbol_on_controller:
|
||||
cached = Controller.instance().getStaticCachedPath(symbol)
|
||||
if os.path.exists(cached):
|
||||
try:
|
||||
shutil.copy(cached, path)
|
||||
except IOError as e:
|
||||
log.warning("Cannot copy cached symbol from `{}` to `{}` due `{}`".format(
|
||||
cached, path, str(e)
|
||||
))
|
||||
return symbol
|
||||
|
||||
url = "https://raw.githubusercontent.com/GNS3/gns3-registry/master/symbols/{}".format(symbol)
|
||||
try:
|
||||
urllib.request.urlretrieve(url, path)
|
||||
return os.path.basename(path)
|
||||
except (OSError, CertificateError):
|
||||
return None
|
||||
|
||||
def _uploadImages(self, version):
|
||||
"""
|
||||
@@ -711,8 +886,7 @@ class ApplianceWizard(QtWidgets.QWizard, Ui_ApplianceWizard):
|
||||
reply = QtWidgets.QMessageBox.question(self, "Custom files",
|
||||
"This option allows files with different MD5 checksums. This feature is only for advanced users and can lead "
|
||||
"to unexpected problems. Are you sure you would like to enable it?",
|
||||
QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No
|
||||
)
|
||||
QtWidgets.QMessageBox.Yes, QtWidgets.QMessageBox.No)
|
||||
|
||||
if reply == QtWidgets.QMessageBox.No:
|
||||
self.allowCustomFiles.setChecked(False)
|
||||
|
||||
@@ -52,7 +52,6 @@ class NewTemplateWizard(QtWidgets.QWizard, Ui_NewTemplateWizard):
|
||||
self.setOption(QtWidgets.QWizard.HaveCustomButton1, True)
|
||||
self.customButtonClicked.connect(self._downloadAppliancesSlot)
|
||||
self.button(QtWidgets.QWizard.CustomButton1).hide()
|
||||
|
||||
self.uiFilterLineEdit.textChanged.connect(self._filterTextChangedSlot)
|
||||
ApplianceManager.instance().appliances_changed_signal.connect(self._appliancesChangedSlot)
|
||||
|
||||
@@ -81,11 +80,10 @@ class NewTemplateWizard(QtWidgets.QWizard, Ui_NewTemplateWizard):
|
||||
QtWidgets.QMessageBox.information(self, "Appliances", "Appliances are up-to-date!")
|
||||
|
||||
def _filterTextChangedSlot(self, text):
|
||||
|
||||
self._get_appliances_from_server(appliance_filter=text)
|
||||
|
||||
def _setItemIcon(self, item, icon):
|
||||
item.setIcon(0, icon)
|
||||
item.setIcon(0, icon)
|
||||
|
||||
def _get_tooltip_text(self, appliance):
|
||||
"""
|
||||
@@ -188,13 +186,14 @@ class NewTemplateWizard(QtWidgets.QWizard, Ui_NewTemplateWizard):
|
||||
|
||||
item.setText(3, appliance["vendor_name"])
|
||||
item.setData(0, QtCore.Qt.UserRole, appliance)
|
||||
item.setSizeHint(0, QtCore.QSize(32, 32))
|
||||
|
||||
#item.setSizeHint(0, QtCore.QSize(32, 32))
|
||||
item.setToolTip(0, self._get_tooltip_text(appliance))
|
||||
Controller.instance().getSymbolIcon(appliance.get("symbol"), qpartial(self._setItemIcon, item),
|
||||
fallback=":/symbols/" + appliance["category"] + ".svg")
|
||||
|
||||
self.uiAppliancesTreeWidget.resizeColumnToContents(0)
|
||||
self.uiAppliancesTreeWidget.sortByColumn(0, QtCore.Qt.AscendingOrder)
|
||||
self.uiAppliancesTreeWidget.resizeColumnToContents(0)
|
||||
|
||||
def initializePage(self, page_id):
|
||||
"""
|
||||
|
||||
@@ -18,12 +18,7 @@
|
||||
|
||||
|
||||
import json
|
||||
import os
|
||||
import urllib
|
||||
import shutil
|
||||
from ssl import CertificateError
|
||||
|
||||
from gns3.controller import Controller
|
||||
from ..local_config import LocalConfig
|
||||
from ..local_server_config import LocalServerConfig
|
||||
from ..settings import LOCAL_SERVER_SETTINGS
|
||||
@@ -93,265 +88,6 @@ class Config:
|
||||
servers.append(server["url"])
|
||||
return servers
|
||||
|
||||
def is_name_available(self, name):
|
||||
"""
|
||||
:param name: Appliance name
|
||||
:returns: True if name is not already used
|
||||
"""
|
||||
|
||||
appliance_names = []
|
||||
if "Qemu" in self._config:
|
||||
appliance_names.extend(self._config["Qemu"].get("vms", []))
|
||||
if "IOU" in self._config:
|
||||
appliance_names.extend(self._config["IOU"].get("devices", []))
|
||||
if "Dynamips" in self._config:
|
||||
appliance_names.extend(self._config["Dynamips"].get("routers", []))
|
||||
if "Docker" in self._config:
|
||||
appliance_names.extend(self._config["Docker"].get("containers", []))
|
||||
for item in appliance_names:
|
||||
if item["name"] == name:
|
||||
return False
|
||||
return True
|
||||
|
||||
def add_appliance(self, appliance_config, server, controller_symbols=None):
|
||||
"""
|
||||
Add appliance to the user configuration
|
||||
|
||||
:param appliance_config: Dictionary with appliance configuration
|
||||
:param server
|
||||
:param controller_symbols: Symbols located on controller
|
||||
"""
|
||||
|
||||
if controller_symbols is None:
|
||||
controller_symbols = []
|
||||
|
||||
new_config = {
|
||||
"compute_id": server,
|
||||
"name": appliance_config["name"]
|
||||
}
|
||||
|
||||
if "usage" in appliance_config:
|
||||
new_config["usage"] = appliance_config["usage"]
|
||||
|
||||
if appliance_config["category"] == "guest":
|
||||
new_config["category"] = 2
|
||||
elif appliance_config["category"] == "router":
|
||||
new_config["category"] = 0
|
||||
elif appliance_config["category"] == "firewall":
|
||||
new_config["category"] = 3
|
||||
elif appliance_config["category"] == "switch":
|
||||
new_config["category"] = 1
|
||||
elif appliance_config["category"] == "multilayer_switch":
|
||||
new_config["category"] = 1
|
||||
|
||||
if "symbol" in appliance_config:
|
||||
new_config["symbol"] = self._set_symbol(appliance_config["symbol"], controller_symbols)
|
||||
|
||||
if new_config.get("symbol") is None:
|
||||
if appliance_config["category"] == "guest":
|
||||
if "docker" in appliance_config:
|
||||
new_config["symbol"] = ":/symbols/docker_guest.svg"
|
||||
else:
|
||||
new_config["symbol"] = ":/symbols/qemu_guest.svg"
|
||||
elif appliance_config["category"] == "router":
|
||||
new_config["symbol"] = ":/symbols/router.svg"
|
||||
elif appliance_config["category"] == "switch":
|
||||
new_config["symbol"] = ":/symbols/ethernet_switch.svg"
|
||||
elif appliance_config["category"] == "multilayer_switch":
|
||||
new_config["symbol"] = ":/symbols/multilayer_switch.svg"
|
||||
elif appliance_config["category"] == "firewall":
|
||||
new_config["symbol"] = ":/symbols/firewall.svg"
|
||||
|
||||
# Raise error if VM already exists
|
||||
if not self.is_name_available(new_config["name"]):
|
||||
raise ConfigException("{} already exists".format(new_config["name"]))
|
||||
|
||||
if "qemu" in appliance_config:
|
||||
self._add_qemu_config(new_config, appliance_config)
|
||||
return
|
||||
if "iou" in appliance_config:
|
||||
self._add_iou_config(new_config, appliance_config)
|
||||
return
|
||||
if "dynamips" in appliance_config:
|
||||
self._add_dynamips_config(new_config, appliance_config)
|
||||
return
|
||||
if "docker" in appliance_config:
|
||||
self._add_docker_config(new_config, appliance_config)
|
||||
return
|
||||
raise ConfigException("{} no configuration found for known emulators".format(new_config["name"]))
|
||||
|
||||
def _add_docker_config(self, new_config, appliance_config):
|
||||
new_config["adapters"] = appliance_config["docker"]["adapters"]
|
||||
new_config["image"] = appliance_config["docker"]["image"]
|
||||
new_config["environment"] = appliance_config["docker"].get("environment", "")
|
||||
new_config["start_command"] = appliance_config["docker"].get("start_command", "")
|
||||
new_config["console_type"] = appliance_config["docker"].get("console_type", "telnet")
|
||||
new_config["console_http_port"] = appliance_config["docker"].get("console_http_port", 80)
|
||||
new_config["console_http_path"] = appliance_config["docker"].get("console_http_path", "/")
|
||||
new_config["extra_hosts"] = appliance_config["docker"].get("extra_hosts", "")
|
||||
self._config["Docker"]["containers"].append(new_config)
|
||||
|
||||
def _add_dynamips_config(self, new_config, appliance_config):
|
||||
new_config["auto_delete_disks"] = True
|
||||
new_config["disk0"] = 0
|
||||
new_config["disk1"] = 0
|
||||
new_config["exec_area"] = 64
|
||||
new_config["idlemax"] = 500
|
||||
new_config["idlesleep"] = 30
|
||||
new_config["system_id"] = "FTX0945W0MY"
|
||||
new_config["sparsemem"] = True
|
||||
new_config["private_config"] = ""
|
||||
new_config["mac_addr"] = ""
|
||||
new_config["iomem"] = 5
|
||||
new_config["mmap"] = True
|
||||
|
||||
for key, value in appliance_config["dynamips"].items():
|
||||
new_config[key] = value
|
||||
|
||||
for image in appliance_config["images"]:
|
||||
new_config[image["type"]] = self._relative_image_path("IOS", image["path"])
|
||||
new_config["idlepc"] = image.get("idlepc", "")
|
||||
|
||||
log.debug("Add appliance Dynamips: %s", str(new_config))
|
||||
self._config["Dynamips"].setdefault("routers", [])
|
||||
self._config["Dynamips"]["routers"].append(new_config)
|
||||
|
||||
def _add_iou_config(self, new_config, appliance_config):
|
||||
new_config["ethernet_adapters"] = appliance_config["iou"]["ethernet_adapters"]
|
||||
new_config["serial_adapters"] = appliance_config["iou"]["serial_adapters"]
|
||||
new_config["startup_config"] = appliance_config["iou"]["startup_config"]
|
||||
new_config["private_config"] = ""
|
||||
new_config["l1_keepalives"] = False
|
||||
new_config["use_default_iou_values"] = True
|
||||
new_config["nvram"] = appliance_config["iou"]["nvram"]
|
||||
new_config["ram"] = appliance_config["iou"]["ram"]
|
||||
new_config["console_type"] = appliance_config["iou"].get("console_type", "telnet")
|
||||
|
||||
for image in appliance_config["images"]:
|
||||
if "path" not in image:
|
||||
raise ConfigException("Disk image is missing")
|
||||
new_config[image["type"]] = self._relative_image_path("IOU", image["path"])
|
||||
new_config["path"] = new_config["image"]
|
||||
|
||||
log.debug("Add appliance IOU: %s", str(new_config))
|
||||
self._config["IOU"].setdefault("devices", [])
|
||||
self._config["IOU"]["devices"].append(new_config)
|
||||
|
||||
def _add_qemu_config(self, new_config, appliance_config):
|
||||
|
||||
new_config["adapter_type"] = appliance_config["qemu"]["adapter_type"]
|
||||
new_config["adapters"] = appliance_config["qemu"]["adapters"]
|
||||
new_config["cpu_throttling"] = appliance_config["qemu"].get("cpu_throttling", 0)
|
||||
new_config["cpus"] = appliance_config["qemu"].get("cpus", 1)
|
||||
new_config["ram"] = appliance_config["qemu"]["ram"]
|
||||
new_config["console_type"] = appliance_config["qemu"]["console_type"]
|
||||
new_config["legacy_networking"] = False
|
||||
new_config["process_priority"] = appliance_config["qemu"].get("process_priority", "normal")
|
||||
|
||||
options = appliance_config["qemu"].get("options", "")
|
||||
if "-nographic" not in options:
|
||||
options += " -nographic"
|
||||
if appliance_config["qemu"].get("kvm", "allow") == "disable" and "-no-kvm" not in options:
|
||||
options += " -no-kvm"
|
||||
new_config["options"] = options.strip()
|
||||
|
||||
for image in appliance_config["images"]:
|
||||
if image.get("path"):
|
||||
new_config[image["type"]] = self._relative_image_path("QEMU", image["path"])
|
||||
|
||||
new_config.setdefault("hda_disk_image", "")
|
||||
new_config.setdefault("hdb_disk_image", "")
|
||||
new_config.setdefault("hdc_disk_image", "")
|
||||
new_config.setdefault("hdd_disk_image", "")
|
||||
new_config.setdefault("cdrom_image", "")
|
||||
new_config.setdefault("bios_image", "")
|
||||
new_config.setdefault("initrd", "")
|
||||
new_config.setdefault("kernel_image", "")
|
||||
|
||||
new_config["hda_disk_interface"] = appliance_config["qemu"].get("hda_disk_interface", "ide")
|
||||
new_config["hdb_disk_interface"] = appliance_config["qemu"].get("hdb_disk_interface", "ide")
|
||||
new_config["hdc_disk_interface"] = appliance_config["qemu"].get("hdc_disk_interface", "ide")
|
||||
new_config["hdd_disk_interface"] = appliance_config["qemu"].get("hdd_disk_interface", "ide")
|
||||
|
||||
new_config["kernel_command_line"] = appliance_config["qemu"].get("kernel_command_line", "")
|
||||
|
||||
if "path" in appliance_config["qemu"]:
|
||||
new_config["qemu_path"] = appliance_config["qemu"]["path"]
|
||||
else:
|
||||
new_config["qemu_path"] = "qemu-system-{}".format(appliance_config["qemu"]["arch"])
|
||||
|
||||
if "boot_priority" in appliance_config["qemu"]:
|
||||
new_config["boot_priority"] = appliance_config["qemu"]["boot_priority"]
|
||||
|
||||
if "first_port_name" in appliance_config:
|
||||
new_config["first_port_name"] = appliance_config["first_port_name"]
|
||||
|
||||
if "port_name_format" in appliance_config:
|
||||
new_config["port_name_format"] = appliance_config["port_name_format"]
|
||||
|
||||
if "port_segment_size" in appliance_config:
|
||||
new_config["port_segment_size"] = appliance_config["port_segment_size"]
|
||||
|
||||
if "custom_adapters" in appliance_config:
|
||||
new_config["custom_adapters"] = appliance_config["custom_adapters"]
|
||||
|
||||
if "linked_clone" in appliance_config:
|
||||
new_config["linked_clone"] = appliance_config["linked_clone"]
|
||||
|
||||
log.debug("Add appliance QEMU: %s", str(new_config))
|
||||
self._config["Qemu"].setdefault("vms", [])
|
||||
self._config["Qemu"]["vms"].append(new_config)
|
||||
|
||||
def _set_symbol(self, symbol, controller_symbols):
|
||||
"""
|
||||
Check if exists on controller or download symbol from the web if needed
|
||||
"""
|
||||
|
||||
# GNS3 builtin symbol
|
||||
if symbol.startswith(":/symbols/"):
|
||||
return symbol
|
||||
|
||||
path = os.path.join(self.symbols_dir, symbol)
|
||||
if os.path.exists(path):
|
||||
return os.path.basename(path)
|
||||
|
||||
is_symbol_on_controller = len([s for s in controller_symbols
|
||||
if s['symbol_id'] == symbol]) > 0
|
||||
|
||||
if is_symbol_on_controller:
|
||||
cached = Controller.instance().getStaticCachedPath(symbol)
|
||||
if os.path.exists(cached):
|
||||
try:
|
||||
shutil.copy(cached, path)
|
||||
except IOError as e:
|
||||
log.warning("Cannot copy cached symbol from `{}` to `{}` due `{}`".format(
|
||||
cached, path, str(e)
|
||||
))
|
||||
return symbol
|
||||
|
||||
url = "https://raw.githubusercontent.com/GNS3/gns3-registry/master/symbols/{}".format(symbol)
|
||||
try:
|
||||
urllib.request.urlretrieve(url, path)
|
||||
return os.path.basename(path)
|
||||
except (OSError, CertificateError):
|
||||
return None
|
||||
|
||||
def _relative_image_path(self, image_dir_type, path):
|
||||
"""
|
||||
:param image_dir_type: Type of image directory
|
||||
:param filename: Filename at the end of the processus
|
||||
:param path: Full path to the file
|
||||
:returns: Path relative to image directory.
|
||||
Copy the image to the directory if not already in the directory
|
||||
"""
|
||||
|
||||
images_dir = os.path.join(self.images_dir, image_dir_type)
|
||||
path = os.path.abspath(path)
|
||||
if os.path.commonprefix([images_dir, path]) == images_dir:
|
||||
return path.replace(images_dir, '').strip('/\\')
|
||||
|
||||
return os.path.basename(path)
|
||||
|
||||
def save(self):
|
||||
"""
|
||||
Save the configuration file
|
||||
|
||||
@@ -60,6 +60,16 @@ class TemplateManager(QtCore.QObject):
|
||||
self._templates = {}
|
||||
self.templates_changed_signal.emit()
|
||||
|
||||
def createTemplate(self, template):
|
||||
"""
|
||||
Creates a template on the controller.
|
||||
|
||||
:param template: template object.
|
||||
"""
|
||||
|
||||
log.debug("Create template '{}' (ID={})".format(template.name(), template.id()))
|
||||
self._controller.post("/templates", self.templateDataReceivedCallback, body=template.__json__())
|
||||
|
||||
def deleteTemplate(self, template_id):
|
||||
"""
|
||||
Deletes a template on the controller.
|
||||
@@ -114,8 +124,7 @@ class TemplateManager(QtCore.QObject):
|
||||
# Create the new templates
|
||||
for template in templates:
|
||||
if template.id() not in self._templates:
|
||||
log.debug("Create template '{}' (ID={})".format(template.name(), template.id()))
|
||||
self._controller.post("/templates", self.templateDataReceivedCallback, body=template.__json__())
|
||||
self.createTemplate(template)
|
||||
|
||||
def templateDataReceivedCallback(self, result, error=False, **kwargs):
|
||||
"""
|
||||
@@ -215,6 +224,17 @@ class TemplateManager(QtCore.QObject):
|
||||
log.error("Error while creating node from template: {}".format(result["message"]))
|
||||
return
|
||||
|
||||
def is_name_available(self, name):
|
||||
"""
|
||||
:param name: Template name
|
||||
:returns: True if name is not already used
|
||||
"""
|
||||
|
||||
for template in self._templates.values():
|
||||
if template.name() == name:
|
||||
return False
|
||||
return True
|
||||
|
||||
@staticmethod
|
||||
def instance():
|
||||
"""
|
||||
|
||||
@@ -79,6 +79,9 @@
|
||||
<property name="sortingEnabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<attribute name="headerShowSortIndicator" stdset="0">
|
||||
<bool>true</bool>
|
||||
</attribute>
|
||||
<column>
|
||||
<property name="text">
|
||||
<string>Appliance name</string>
|
||||
|
||||
@@ -40,6 +40,7 @@ class Ui_NewTemplateWizard(object):
|
||||
self.uiAppliancesTreeWidget.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
|
||||
self.uiAppliancesTreeWidget.setRootIsDecorated(False)
|
||||
self.uiAppliancesTreeWidget.setObjectName("uiAppliancesTreeWidget")
|
||||
self.uiAppliancesTreeWidget.header().setSortIndicatorShown(True)
|
||||
self.verticalLayout_2.addWidget(self.uiAppliancesTreeWidget)
|
||||
NewTemplateWizard.addPage(self.uiApplianceFromServerWizardPage)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user