diff --git a/gns3registry/config.py b/gns3registry/config.py index 8446e90..9d1cc30 100644 --- a/gns3registry/config.py +++ b/gns3registry/config.py @@ -23,6 +23,10 @@ import os from gns3registry.image import Image +class ConfigException(Exception): + pass + + class Config: """ GNS3 config file @@ -66,9 +70,9 @@ class Config: home = os.path.expanduser("~") return os.path.join(home, ".config", appname, filename) - def add_image(self, device_config): + def add_images(self, device_config): """ - Add an image to the user configuration + Add images to the user configuration """ new_config = { "server": "local", @@ -76,6 +80,9 @@ class Config: } if device_config["category"] == "guest": new_config["category"] = 2 + elif device_config["category"] == "router": + new_config["category"] = 0 + if "qemu" in device_config: self._add_qemu_config(new_config, device_config) @@ -99,19 +106,32 @@ class Config: #TODO: Manage Windows if device_config["qemu"]["processor"] == "i386": new_config["qemu_path"] = "qemu-system-i386" + elif device_config["qemu"]["processor"] == "x64": + new_config["qemu_path"] = "qemu-system-x86_64" if device_config["category"] == "guest": new_config["default_symbol"] = ":/symbols/qemu_guest.normal.svg" new_config["hover_symbol"] = ":/symbols/qemu_guest.selected.svg" + elif device_config["category"] == "router": + new_config["default_symbol"] = ":/symbols/router.normal.svg" + new_config["hover_symbol"] = ":/symbols/router.selected.svg" - if isinstance(device_config["images"]["hda_disk_image"], Image): - new_config["name"] += " {}".format(device_config["images"]["hda_disk_image"].version) - new_config["hda_disk_image"] = device_config["images"]["hda_disk_image"].path + disks = ["hda_disk_image", "hdb_disk_image", "hdc_disk_image", "hdd_disk_image"] + for disk in disks: + if disk in device_config["images"]: + if isinstance(device_config["images"][disk], list): + require_images = "" + for image in device_config["images"][disk]: + require_images += "* {}\n".format(image["filename"]) + raise ConfigException("Missing image for {} you should provide one of the following images:\n{}".format(disk, require_images)) + else: + new_config["name"] += " {}".format(device_config["images"][disk].version) + new_config[disk] = device_config["images"][disk].path # Remove VM with the same Name self._config["Qemu"]["vms"] = [item for item in self._config["Qemu"]["vms"] if item["name"] != new_config["name"]] - self._config["Qemu"]["vms"] .append(new_config) + self._config["Qemu"]["vms"].append(new_config) def save(self): """ diff --git a/gns3registry/main.py b/gns3registry/main.py index dacd4f3..fdf5f4a 100644 --- a/gns3registry/main.py +++ b/gns3registry/main.py @@ -24,7 +24,7 @@ from distutils.util import strtobool sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))) from gns3registry.registry import Registry -from gns3registry.config import Config +from gns3registry.config import Config, ConfigException registry = Registry() config = Config() @@ -37,25 +37,29 @@ def yes_no(message): except ValueError: pass -def add_image(image): +def add_images(images): print("WARNING WARNING WARNING") print("It's experimental") print("Please close the GUI before using it") print("") - confs = registry.detect_image(image) + confs = registry.detect_images(images) if len(confs) > 0: print("Found: {} devices configuration".format(len(confs))) for conf in confs: if yes_no("Add {}?".format(conf["name"])): - config.add_image(conf) + try: + config.add_images(conf) + except ConfigException as e: + print(e, file=sys.stderr) + sys.exit(1) config.save() if __name__ == "__main__": parser = argparse.ArgumentParser(description="Manage GNS3 registry") - parser.add_argument("--add", dest="add_image", action="store", - help="Add an image to GNS3") + parser.add_argument("--add", dest="add_images", action="store", nargs='+', + help="Add images to GNS3") parser.add_argument("--search", dest="search", action="store", help="Search an image for GNS3") parser.add_argument("--install", dest="install", action="store", @@ -68,8 +72,8 @@ if __name__ == "__main__": if args.test: sys.exit(0) - if args.add_image: - add_image(args.add_image) + if args.add_images: + add_images(args.add_images) elif args.search: print("Available images\n") for res in registry.search_device(args.search): @@ -81,7 +85,7 @@ if __name__ == "__main__": elif args.install: image = registry.download_image(args.install, config.images_dir) if image: - add_image(image) + add_images([image]) else: parser.print_help() sys.exit(1) diff --git a/gns3registry/registry.py b/gns3registry/registry.py index 6ce661b..e3b5ef1 100644 --- a/gns3registry/registry.py +++ b/gns3registry/registry.py @@ -25,21 +25,31 @@ import urllib.request from gns3registry.image import Image + class Registry: def __init__(self): pass - def detect_image(self, image_path): + def detect_images(self, images_path): """ :returns: Array of configuration corresponding to the image """ - image = Image(image_path) + images = [] + + for path in images_path: + images.append(Image(path)) + configurations = [] #TODO: Manage open error for config in self._all_configs(): - if self._image_match(image, config): + + matched = False + for image in images: + if self._image_match(image, config): + matched = True + if matched: configurations.append(config) return configurations @@ -85,11 +95,16 @@ class Registry: :returns: True if image is present in configuration """ for image_type in config.get("images", {}): - for file in config["images"].get(image_type, []): - if file.get("sha1sum", None) == image.sha1sum: - image.version = file["version"] - config["images"][image_type] = image - return True + images = config["images"].get(image_type, []) + # If it's not a list it's mean we have already detect the image + if not isinstance(images, list): + continue + for file in images: + if isinstance(file, dict): + if file.get("sha1sum", None) == image.sha1sum: + image.version = file["version"] + config["images"][image_type] = image + return True return False def _get_devices_path(self): @@ -98,5 +113,3 @@ class Registry: """ path = os.path.abspath(os.path.dirname(__file__)) return os.path.join(path, "..", "devices") - - diff --git a/test/test_config.py b/test/test_config.py index a53ef4f..9b975b9 100644 --- a/test/test_config.py +++ b/test/test_config.py @@ -19,12 +19,13 @@ import pytest import json +from unittest.mock import MagicMock -from gns3registry.config import Config +from gns3registry.config import Config, ConfigException from gns3registry.image import Image -@pytest.fixture +@pytest.fixture(scope="function") def empty_config(tmpdir): config = { "LocalServer": { @@ -75,13 +76,13 @@ def empty_config(tmpdir): return Config(path) -def test_add_image(empty_config, linux_microcore_img): +def test_add_images_guest(empty_config, linux_microcore_img): with open("devices/qemu/microcore-linux.json") as f: config = json.load(f) image = Image(linux_microcore_img) image.version = "3.4.1" config["images"]["hda_disk_image"] = image - empty_config.add_image(config) + empty_config.add_images(config) assert empty_config._config["Qemu"]["vms"][0] == { "adapter_type": "e1000", "adapters": 1, @@ -106,23 +107,88 @@ def test_add_image(empty_config, linux_microcore_img): } -def test_add_image_uniq(empty_config, linux_microcore_img): +def test_add_images_router_two_disk(empty_config): + with open("devices/qemu/arista-veos.json") as f: + config = json.load(f) + + image = MagicMock() + image.version = "2.1.0" + image.sha1sum = "ea9dc1989764fc6db1d388b061340743016214a7" + image.path = "/a" + config["images"]["hda_disk_image"] = image + + image = MagicMock() + image.version = "4.13.8M" + image.sha1sum = "ff50656fe817c420e9f7fbb0c0ee41f1ca52fee2" + image.path = "/b" + config["images"]["hdb_disk_image"] = image + + empty_config.add_images(config) + assert empty_config._config["Qemu"]["vms"][0]["name"] == "Arista vEOS 2.1.0 4.13.8M" + + assert empty_config._config["Qemu"]["vms"][0] == { + "adapter_type": "e1000", + "adapters": 8, + "category": 0, + "cpu_throttling": 0, + "default_symbol": ":/symbols/router.normal.svg", + "hda_disk_image": "/a", + "hdb_disk_image": "/b", + "hdc_disk_image": "", + "hdd_disk_image": "", + "hover_symbol": ":/symbols/router.selected.svg", + "initrd": "", + "kernel_command_line": "", + "kernel_image": "", + "legacy_networking": False, + "name": "Arista vEOS 2.1.0 4.13.8M", + "options": "", + "process_priority": "normal", + "qemu_path": "qemu-system-x86_64", + "ram": 2048, + "server": "local" + } + + +def test_add_images_uniq(empty_config, linux_microcore_img): with open("devices/qemu/microcore-linux.json") as f: config = json.load(f) + image = Image(linux_microcore_img) image.version = "3.4.1" - config["hda_disk_image"] = image - empty_config.add_image(config) - config["adapters"] = 2 - empty_config.add_image(config) + config["images"]["hda_disk_image"] = image + + empty_config.add_images(config) + config["qemu"]["adapters"] = 2 + empty_config.add_images(config) assert len(empty_config._config["Qemu"]["vms"]) == 1 + assert empty_config._config["Qemu"]["vms"][0]["adapters"] == 2 + + +def test_add_images_two_disk_one_missing(empty_config): + with open("devices/qemu/arista-veos.json") as f: + config = json.load(f) + + image = MagicMock() + image.version = "2.1.0" + image.sha1sum = "ea9dc1989764fc6db1d388b061340743016214a7" + config["images"]["hda_disk_image"] = image + + with pytest.raises(ConfigException): + empty_config.add_images(config) + assert len(empty_config._config["Qemu"]["vms"]) == 0 def test_save(empty_config, linux_microcore_img): with open("devices/qemu/microcore-linux.json") as f: config = json.load(f) - empty_config.add_image(config) + + image = Image(linux_microcore_img) + image.version = "3.4.1" + config["images"]["hda_disk_image"] = image + + empty_config.add_images(config) empty_config.save() with open(empty_config.path) as f: assert "Micro Core" in f.read() diff --git a/test/test_repository.py b/test/test_registry.py similarity index 73% rename from test/test_repository.py rename to test/test_registry.py index ce77cd7..2fb93c6 100644 --- a/test/test_repository.py +++ b/test/test_registry.py @@ -29,14 +29,25 @@ def test_detect_image(linux_microcore_img): config = json.load(f) registry = Registry() - detected = registry.detect_image(linux_microcore_img) + detected = registry.detect_images([linux_microcore_img]) + assert detected[0]["name"] == "Micro Core Linux" + assert detected[0]["images"]["hda_disk_image"].version == "3.4.1" + + +def test_detect_two_image(linux_microcore_img): + + with open("devices/qemu/microcore-linux.json") as f: + config = json.load(f) + + registry = Registry() + detected = registry.detect_images([linux_microcore_img]) assert detected[0]["name"] == "Micro Core Linux" assert detected[0]["images"]["hda_disk_image"].version == "3.4.1" def test_detect_unknow_image(empty_file): registry = Registry() - assert registry.detect_image(empty_file) == [] + assert registry.detect_images([empty_file]) == [] def test_search_device():