mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-07 15:43:43 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8014da10b | ||
|
|
f6080013e3 | ||
|
|
fc54c6e496 | ||
|
|
04cd107651 | ||
|
|
19cabdfde6 | ||
|
|
af7fbe6bb4 | ||
|
|
3d58b437b4 | ||
|
|
83921a45df | ||
|
|
11c9802268 | ||
|
|
a60e0d424d | ||
|
|
db1fb29c63 | ||
|
|
a5f0dba5cf |
No files matched your search
@@ -1,5 +1,14 @@
|
||||
# Change Log
|
||||
|
||||
## 2.2.52 02/12/2024
|
||||
|
||||
* Bundle web-ui v2.2.52
|
||||
* Sync appliances
|
||||
* Remove restrictions based on file extension when listing images and fix ELF header checks
|
||||
* Fix use project name instead of ID for fast duplication when running local server. Fixes #2446
|
||||
* Overwrite user resources when the originals have changed.
|
||||
* Relax setuptools requirement to allow for easier Debian packaging on Ubuntu Focal & Jammy
|
||||
|
||||
## 2.2.51 07/11/2024
|
||||
|
||||
* Catch error when cannot resize Docker container TTY.
|
||||
|
||||
@@ -33,11 +33,23 @@
|
||||
"md5sum": "cbbbea66a253f1dac0fcf81274dc778d",
|
||||
"filesize": 87756936
|
||||
},
|
||||
{
|
||||
"filename": "c7200-adventerprisek9-mz.152-4.M11.image",
|
||||
"version": "152-4.M11",
|
||||
"md5sum": "9a2005ad09ce1ec6fe7cf9af1e9b099e",
|
||||
"filesize": 128487680
|
||||
},
|
||||
{
|
||||
"filename": "c7200-adventerprisek9-mz.124-24.T5.image",
|
||||
"version": "124-24.T5",
|
||||
"md5sum": "6b89d0d804e1f2bb5b8bda66b5692047",
|
||||
"filesize": 102345240
|
||||
},
|
||||
{
|
||||
"filename": "c7200-a3jk9s-mz.124-25g.image",
|
||||
"version": "124-25G",
|
||||
"md5sum": "9c7cc9b3f3b3571411a7f62faaa2c036",
|
||||
"filesize": 71528984
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
@@ -55,12 +67,26 @@
|
||||
"image": "c7200-advipservicesk9-mz.152-4.S5.image"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "152-4.M11",
|
||||
"idlepc": "0x6062e5c0",
|
||||
"images": {
|
||||
"image": "c7200-adventerprisek9-mz.152-4.M11.image"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "124-24.T5",
|
||||
"idlepc": "0x606df838",
|
||||
"images": {
|
||||
"image": "c7200-adventerprisek9-mz.124-24.T5.image"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "124-25G",
|
||||
"idlepc": "0x6066a998",
|
||||
"images": {
|
||||
"image": "c7200-a3jk9s-mz.124-25g.image"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -12,7 +12,7 @@
|
||||
"status": "stable",
|
||||
"maintainer": "GNS3 Team",
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"usage": "There is no default password and enable password. A default configuration is present. ASAv goes through a double-boot before becoming active. This is normal and expected.",
|
||||
"usage": "There is no default password and enable password. A default configuration is present. ASAv goes through a double-boot before becoming active. This is normal and expected. Switch to the Telnet console type after the first boot.",
|
||||
"symbol": ":/symbols/asa.svg",
|
||||
"first_port_name": "Management0/0",
|
||||
"port_name_format": "Gi0/{0}",
|
||||
@@ -26,6 +26,13 @@
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "asav9-22-1-1.qcow2",
|
||||
"version": "9.22.1.1 CML",
|
||||
"md5sum": "250a924cdc2370208eaac9d1dc8dc9e3",
|
||||
"filesize": 379518976,
|
||||
"download_url": "https://learningnetworkstore.cisco.com/cisco-modeling-labs-personal/cisco-modeling-labs-personal/CML-PERSONAL.html"
|
||||
},
|
||||
{
|
||||
"filename": "asav9-18-2.qcow2",
|
||||
"version": "9.18.2 CML",
|
||||
@@ -126,6 +133,12 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "9.22.1.1 CML",
|
||||
"images": {
|
||||
"hda_disk_image": "asav9-22-1-1.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "9.18.2 CML",
|
||||
"images": {
|
||||
|
||||
@@ -24,12 +24,26 @@
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "csr1000v-universalk9.17.03.08a-serial.qcow2",
|
||||
"version": "17.03.08a",
|
||||
"md5sum": "6abece87d6db99d9fd6917203e253f91",
|
||||
"filesize": 1421410304,
|
||||
"download_url": "https://software.cisco.com/download/home/286323714/type/282046477/release/Amsterdam-17.3.8a"
|
||||
},
|
||||
{
|
||||
"filename": "csr1000v-universalk9.17.03.06-serial.qcow2",
|
||||
"version": "17.03.06",
|
||||
"md5sum": "086ab9bef6e66de847af0da3910c60e8",
|
||||
"filesize": 1422000128,
|
||||
"download_url": "https://software.cisco.com/download/home/284364978/type/282046477/release/Gibraltar-16.12.3"
|
||||
"download_url": "https://software.cisco.com/download/home/286323714/type/282046477/release/Amsterdam-17.3.6"
|
||||
},
|
||||
{
|
||||
"filename": "csr1000v-ucmk9.16.12.5-serial.qcow2",
|
||||
"version": "16.12.05",
|
||||
"md5sum": "5c0cc217f0f0648407b34b11a1dd5b8e",
|
||||
"filesize": 844103680,
|
||||
"download_url": "https://software.cisco.com/download/home/286323714/type/286321980/release/16.12.5"
|
||||
},
|
||||
{
|
||||
"filename": "csr1000v-universalk9.16.12.03-serial.qcow2",
|
||||
@@ -166,13 +180,25 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "17.03.08a",
|
||||
"images": {
|
||||
"hda_disk_image": "csr1000v-universalk9.17.03.08a-serial.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "17.03.06",
|
||||
"images": {
|
||||
"hda_disk_image": "csr1000v-universalk9.17.03.06-serial.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
{
|
||||
"name": "16.12.05",
|
||||
"images": {
|
||||
"hda_disk_image": "csr1000v-ucmk9.16.12.5-serial.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "16.12.3",
|
||||
"images": {
|
||||
"hda_disk_image": "csr1000v-universalk9.16.12.03-serial.qcow2"
|
||||
|
||||
@@ -13,11 +13,17 @@
|
||||
"iou": {
|
||||
"ethernet_adapters": 4,
|
||||
"serial_adapters": 0,
|
||||
"nvram": 128,
|
||||
"ram": 256,
|
||||
"nvram": 512,
|
||||
"ram": 512,
|
||||
"startup_config": "iou_l2_base_startup-config.txt"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "x86_64_crb_linux_l2-adventerprisek9-ms.iol",
|
||||
"version": "17.15.1",
|
||||
"md5sum": "6c587cdfd5056078e70b3f6c26800d66",
|
||||
"filesize": 243251976
|
||||
},
|
||||
{
|
||||
"filename": "x86_64_crb_linux_l2-adventerprisek9-ms.bin",
|
||||
"version": "17.12.1",
|
||||
@@ -44,6 +50,12 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "17.15.1",
|
||||
"images": {
|
||||
"image": "x86_64_crb_linux_l2-adventerprisek9-ms.iol"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "17.12.1",
|
||||
"images": {
|
||||
|
||||
@@ -13,11 +13,17 @@
|
||||
"iou": {
|
||||
"ethernet_adapters": 2,
|
||||
"serial_adapters": 2,
|
||||
"nvram": 128,
|
||||
"ram": 256,
|
||||
"nvram": 512,
|
||||
"ram": 512,
|
||||
"startup_config": "iou_l3_base_startup-config.txt"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "x86_64_crb_linux-adventerprisek9-ms.iol",
|
||||
"version": "17.15.1",
|
||||
"md5sum": "5d584f6cfbeaadc87d55f613da1049ed",
|
||||
"filesize": 292001512
|
||||
},
|
||||
{
|
||||
"filename": "x86_64_crb_linux-adventerprisek9-ms.bin",
|
||||
"version": "17.12.1",
|
||||
@@ -44,6 +50,12 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "17.15.1",
|
||||
"images": {
|
||||
"image": "x86_64_crb_linux-adventerprisek9-ms.iol"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "17.12.1",
|
||||
"images": {
|
||||
|
||||
@@ -28,7 +28,21 @@
|
||||
"options": ""
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
{
|
||||
"filename": "MFG_CTVM_8_10_196_0.iso",
|
||||
"version": "8.10.196.0",
|
||||
"md5sum": "6093aca44dcf45c999f83e62dc9aeea2",
|
||||
"filesize": 650809344,
|
||||
"download_url": "https://software.cisco.com/download/release.html?mdfid=284464214&flowid=&softwareid=280926587&release=8.10.196.0"
|
||||
},
|
||||
{
|
||||
"filename": "MFG_CTVM_8_5_182_0.iso",
|
||||
"version": "8.5.182.0",
|
||||
"md5sum": "1cf3c57c2b123e739ab4662ea0abbc34",
|
||||
"filesize": 388579328,
|
||||
"download_url": "https://software.cisco.com/download/home/284464214/type/280926587/release/8.5.182.0"
|
||||
},
|
||||
{
|
||||
"filename": "MFG_CTVM_8_3_102_0.iso",
|
||||
"version": "8.3.102.0",
|
||||
"md5sum": "7f6b7968b5bed04b5ecc119b6ba4e41c",
|
||||
@@ -73,6 +87,20 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "8.10.196.0",
|
||||
"images": {
|
||||
"hda_disk_image": "empty8G.qcow2",
|
||||
"cdrom_image": "MFG_CTVM_8_10_196_0.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "8.5.182.0",
|
||||
"images": {
|
||||
"hda_disk_image": "empty8G.qcow2",
|
||||
"cdrom_image": "MFG_CTVM_8_5_182_0.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "8.3.102.0",
|
||||
"images": {
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
"product_url": "http://www.cisco.com/",
|
||||
"registry_version": 4,
|
||||
"status": "experimental",
|
||||
"maintainer": "Laurent LEVIER",
|
||||
"maintainer_email": "laurent.levier@orange.com",
|
||||
"maintainer": "Christopher Uhrig",
|
||||
"maintainer_email": "christopher.uhrig@telekom.de",
|
||||
"usage": "Initial username is admin, password is admin as well.",
|
||||
"first_port_name": "Management0/0",
|
||||
"port_name_format": "Ge0/{0}",
|
||||
@@ -39,6 +39,20 @@
|
||||
"md5sum": "4aa487101d4cdc390f53a6e8b6f45ca7",
|
||||
"filesize": 328400896,
|
||||
"download_url": "http://www.cisco.com/"
|
||||
},
|
||||
{
|
||||
"filename": "viptela-edge-20.9.5.1-genericx86-64.qcow2",
|
||||
"version": "20.9.5.1",
|
||||
"md5sum": "41d9e981908fd83695de78d6ca5794bd",
|
||||
"filesize": 409468928,
|
||||
"download_url": "https://software.cisco.com/download/home/286320995/type/286321047/release/20.9.5.1"
|
||||
},
|
||||
{
|
||||
"filename": "viptela-edge-20.12.4-genericx86-64.qcow2",
|
||||
"version": "20.12.4",
|
||||
"md5sum": "9f1aedada5e632c7bc29a51c004f4486",
|
||||
"filesize": 411762688,
|
||||
"download_url": "https://software.cisco.com/download/home/286320995/type/286321047/release/20.12.4"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
@@ -53,6 +67,18 @@
|
||||
"images": {
|
||||
"hda_disk_image": "viptela-edge-genericx86-64.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "20.9.5.1",
|
||||
"images": {
|
||||
"hda_disk_image": "viptela-edge-20.9.5.1-genericx86-64.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "20.12.4",
|
||||
"images": {
|
||||
"hda_disk_image": "viptela-edge-20.12.4-genericx86-64.qcow2"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -24,6 +24,20 @@
|
||||
"options": "-smp 2,maxcpus=2 -cpu host"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "viptela-smart-20.12.4-genericx86-64.qcow2",
|
||||
"version": "20.12.4",
|
||||
"md5sum": "0e7b6468498a89195ab815260bc4cfb6",
|
||||
"filesize": 411762688,
|
||||
"download_url": "https://software.cisco.com/download/home/286320995/type/286321043/release/20.12.4"
|
||||
},
|
||||
{
|
||||
"filename": "viptela-smart-20.9.5.1-genericx86-64.qcow2",
|
||||
"version": "20.9.5.1",
|
||||
"md5sum": "08e105778bb68f8f24f323dfd263a91a",
|
||||
"filesize": 409468928,
|
||||
"download_url": "https://software.cisco.com/download/home/286320995/type/286321043/release/20.9.5.1"
|
||||
},
|
||||
{
|
||||
"filename": "viptela-smart-19.2.0-genericx86-64.qcow2",
|
||||
"version": "19.2.0",
|
||||
@@ -31,7 +45,7 @@
|
||||
"filesize": 328400896,
|
||||
"download_url": "http://www.cisco.com/"
|
||||
},
|
||||
{
|
||||
{
|
||||
"filename": "viptela-smart-genericx86-64-disk1.vmdk",
|
||||
"version": "18.3.7",
|
||||
"md5sum": "ab9b06c212319336810a4b336ec3dd96",
|
||||
@@ -51,6 +65,18 @@
|
||||
"images": {
|
||||
"hda_disk_image": "viptela-smart-19.2.0-genericx86-64.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "20.9.5.1",
|
||||
"images": {
|
||||
"hda_disk_image": "viptela-smart-20.9.5.1-genericx86-64.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "20.12.4",
|
||||
"images": {
|
||||
"hda_disk_image": "viptela-smart-20.12.4-genericx86-64.qcow2"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -10,8 +10,8 @@
|
||||
"product_url": "http://www.cisco.com/",
|
||||
"registry_version": 4,
|
||||
"status": "experimental",
|
||||
"maintainer": "Laurent LEVIER",
|
||||
"maintainer_email": "laurent.levier@orange.com",
|
||||
"maintainer": "Christopher Uhrig",
|
||||
"maintainer_email": "christopher.uhrig@telekom.de",
|
||||
"usage": "Initial username is admin, password is admin as well.",
|
||||
"qemu": {
|
||||
"adapter_type": "vmxnet3",
|
||||
@@ -25,14 +25,28 @@
|
||||
"options": "-cpu host -smp 2,maxcpus=2"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
{
|
||||
"filename": "viptela-vmanage-20.12.4-genericx86-64.qcow2",
|
||||
"version": "20.12.4",
|
||||
"md5sum": "4e0d4c379623c495a0bb671a76a12f9f",
|
||||
"filesize": 4951375872,
|
||||
"download_url": "https://software.cisco.com/download/home/286320995/type/286321039/release/20.12.4"
|
||||
},
|
||||
{
|
||||
"filename": "viptela-vmanage-20.9.5.2-genericx86-64.qcow2",
|
||||
"version": "20.9.5.2",
|
||||
"md5sum": "a8a4ebee0274541200f4fe94a739d454",
|
||||
"filesize": 3133865984,
|
||||
"download_url": "https://software.cisco.com/download/home/286320995/type/286321039/release/20.9.5.2"
|
||||
},
|
||||
{
|
||||
"filename": "viptela-vmanage-19.2.0-genericx86-64.qcow2",
|
||||
"version": "19.2.0",
|
||||
"md5sum": "27ef126f178c6c929a36ad2cf6ed8db7",
|
||||
"filesize": 1185349632,
|
||||
"download_url": "http://www.cisco.com/"
|
||||
},
|
||||
{
|
||||
{
|
||||
"filename": "viptela-vmanage-genericx86-64-disk1.vmdk",
|
||||
"version": "18.3.7",
|
||||
"md5sum": "2290c6467c907d9ca9c65793fe898716",
|
||||
@@ -55,6 +69,20 @@
|
||||
"hda_disk_image": "viptela-vmanage-19.2.0-genericx86-64.qcow2",
|
||||
"hdb_disk_image": "empty30G.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "20.12.4",
|
||||
"images": {
|
||||
"hda_disk_image": "viptela-vmanage-20.12.4-genericx86-64.qcow2",
|
||||
"hdb_disk_image": "empty30G.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "20.9.5.2",
|
||||
"images": {
|
||||
"hda_disk_image": "viptela-vmanage-20.9.5.2-genericx86-64.qcow2",
|
||||
"hdb_disk_image": "empty30G.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "18.3.7",
|
||||
|
||||
@@ -29,7 +29,7 @@ except ImportError:
|
||||
from importlib import resources as importlib_resources
|
||||
|
||||
from ..config import Config
|
||||
from ..utils import parse_version
|
||||
from ..utils import parse_version, md5sum
|
||||
from ..utils.images import default_images_directory
|
||||
|
||||
from .project import Project
|
||||
@@ -289,12 +289,21 @@ class Controller:
|
||||
except OSError as e:
|
||||
log.error(str(e))
|
||||
|
||||
|
||||
@staticmethod
|
||||
def install_resource_files(dst_path, resource_name):
|
||||
def install_resource_files(dst_path, resource_name, upgrade_resources=True):
|
||||
"""
|
||||
Install files from resources to user's file system
|
||||
"""
|
||||
|
||||
def should_copy(src, dst, upgrade_resources):
|
||||
if not os.path.exists(dst):
|
||||
return True
|
||||
if upgrade_resources is False:
|
||||
return False
|
||||
# copy the resource if it is different
|
||||
return md5sum(src) != md5sum(dst)
|
||||
|
||||
if hasattr(sys, "frozen") and sys.platform.startswith("win"):
|
||||
resource_path = os.path.normpath(os.path.join(os.path.dirname(sys.executable), resource_name))
|
||||
for filename in os.listdir(resource_path):
|
||||
@@ -303,7 +312,7 @@ class Controller:
|
||||
else:
|
||||
for entry in importlib_resources.files('gns3server').joinpath(resource_name).iterdir():
|
||||
full_path = os.path.join(dst_path, entry.name)
|
||||
if entry.is_file() and not os.path.exists(full_path):
|
||||
if entry.is_file() and should_copy(str(entry), full_path, upgrade_resources):
|
||||
log.debug(f'Installing {resource_name} resource file "{entry.name}" to "{full_path}"')
|
||||
shutil.copy(str(entry), os.path.join(dst_path, entry.name))
|
||||
elif entry.is_dir():
|
||||
@@ -319,7 +328,7 @@ class Controller:
|
||||
dst_path = self.configs_path()
|
||||
log.info(f"Installing base configs in '{dst_path}'")
|
||||
try:
|
||||
Controller.install_resource_files(dst_path, "configs")
|
||||
Controller.install_resource_files(dst_path, "configs", upgrade_resources=False)
|
||||
except OSError as e:
|
||||
log.error(f"Could not install base config files to {dst_path}: {e}")
|
||||
|
||||
@@ -332,7 +341,7 @@ class Controller:
|
||||
dst_path = self.disks_path()
|
||||
log.info(f"Installing built-in disks in '{dst_path}'")
|
||||
try:
|
||||
Controller.install_resource_files(dst_path, "disks")
|
||||
Controller.install_resource_files(dst_path, "disks", upgrade_resources=False)
|
||||
except OSError as e:
|
||||
log.error(f"Could not install disk files to {dst_path}: {e}")
|
||||
|
||||
|
||||
@@ -82,7 +82,7 @@ class ApplianceManager:
|
||||
os.makedirs(appliances_path, exist_ok=True)
|
||||
return appliances_path
|
||||
|
||||
def builtin_appliances_path(self, delete_first=False):
|
||||
def builtin_appliances_path(self):
|
||||
"""
|
||||
Get the built-in appliance storage directory
|
||||
"""
|
||||
@@ -91,8 +91,6 @@ class ApplianceManager:
|
||||
appname = vendor = "GNS3"
|
||||
resources_path = os.path.expanduser(server_config.get("resources_path", platformdirs.user_data_dir(appname, vendor, roaming=True)))
|
||||
appliances_dir = os.path.join(resources_path, "appliances")
|
||||
if delete_first:
|
||||
shutil.rmtree(appliances_dir, ignore_errors=True)
|
||||
os.makedirs(appliances_dir, exist_ok=True)
|
||||
return appliances_dir
|
||||
|
||||
@@ -101,7 +99,7 @@ class ApplianceManager:
|
||||
At startup we copy the built-in appliances files.
|
||||
"""
|
||||
|
||||
dst_path = self.builtin_appliances_path(delete_first=True)
|
||||
dst_path = self.builtin_appliances_path()
|
||||
log.info(f"Installing built-in appliances in '{dst_path}'")
|
||||
from . import Controller
|
||||
try:
|
||||
|
||||
@@ -588,7 +588,7 @@ class Project:
|
||||
|
||||
if node_type == "iou":
|
||||
async with self._iou_id_lock:
|
||||
# wait for a IOU node to be completely created before adding a new one
|
||||
# wait for an IOU node to be completely created before adding a new one
|
||||
# this is important otherwise we allocate the same application ID (used
|
||||
# to generate MAC addresses) when creating multiple IOU node at the same time
|
||||
if "properties" in kwargs.keys():
|
||||
@@ -1275,7 +1275,10 @@ class Project:
|
||||
p_work = pathlib.Path(location or self.path).parent.absolute()
|
||||
t0 = time.time()
|
||||
new_project_id = str(uuid.uuid4())
|
||||
new_project_path = p_work.joinpath(new_project_id)
|
||||
if location:
|
||||
new_project_path = p_work.joinpath(location)
|
||||
else:
|
||||
new_project_path = p_work.joinpath(new_project_id)
|
||||
# copy dir
|
||||
await wait_run_in_executor(shutil.copytree, self.path, new_project_path.as_posix(), symlinks=True, ignore_dangling_symlinks=True)
|
||||
log.info("Project content copied from '{}' to '{}' in {}s".format(self.path, new_project_path, time.time() - t0))
|
||||
|
||||
@@ -57,7 +57,7 @@ class CrashReport:
|
||||
Report crash to a third party service
|
||||
"""
|
||||
|
||||
DSN = "https://088679fcf3aa35f775356982a80fe37c@o19455.ingest.us.sentry.io/38482"
|
||||
DSN = "https://b2ea85d65646be3f56aebf2458337918@o19455.ingest.us.sentry.io/38482"
|
||||
_instance = None
|
||||
|
||||
def __init__(self):
|
||||
|
||||
@@ -46,6 +46,6 @@
|
||||
|
||||
gtag('config', 'G-0BT7QQV1W1');
|
||||
</script>
|
||||
<script src="runtime.415291667f70565cd8ef.js" defer></script><script src="polyfills-es5.865074f5cd9a121111a2.js" nomodule defer></script><script src="polyfills.2f91a039d848e57ff02e.js" defer></script><script src="main.df8c319a3da6fb0e3629.js" defer></script>
|
||||
<script src="runtime.415291667f70565cd8ef.js" defer></script><script src="polyfills-es5.865074f5cd9a121111a2.js" nomodule defer></script><script src="polyfills.2f91a039d848e57ff02e.js" defer></script><script src="main.9297104511b6616fc55c.js" defer></script>
|
||||
|
||||
</body></html>
|
||||
+1
-1
@@ -1 +1 @@
|
||||
(self.webpackChunkgns3_web_ui=self.webpackChunkgns3_web_ui||[]).push([[179],{98255:function(ue){function q(f){return Promise.resolve().then(function(){var B=new Error("Cannot find module '"+f+"'");throw B.code="MODULE_NOT_FOUND",B})}q.keys=function(){return[]},q.resolve=q,q.id=98255,ue.exports=q},82908:function(ue){ue.exports=function(f,B){(null==B||B>f.length)&&(B=f.length);for(var U=0,V=new Array(B);U<B;U++)V[U]=f[U];return V},ue.exports.default=ue.exports,ue.exports.__esModule=!0},36457:function(ue){ue.exports=function(f){if(Array.isArray(f))return f},ue.exports.default=ue.exports,ue.exports.__esModule=!0},35036:function(ue){ue.exports=function(f,B){var U=null==f?null:"undefined"!=typeof Symbol&&f[Symbol.iterator]||f["@@iterator"];if(null!=U){var N,b,V=[],Z=!0,w=!1;try{for(U=U.call(f);!(Z=(N=U.next()).done)&&(V.push(N.value),!B||V.length!==B);Z=!0);}catch(_){w=!0,b=_}finally{try{!Z&&null!=U.return&&U.return()}finally{if(w)throw b}}return V}},ue.exports.default=ue.exports,ue.exports.__esModule=!0},13969:function(ue){ue.exports=function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")},ue.exports.default=ue.exports,ue.exports.__esModule=!0},6326:function(ue,q,f){var B=f(36457),U=f(35036),V=f(54850),Z=f(13969);ue.exports=function(N,b){return B(N)||U(N,b)||V(N,b)||Z()},ue.exports.default=ue.exports,ue.exports.__esModule=!0},54850:function(ue,q,f){var B=f(82908);ue.exports=function(V,Z){if(V){if("string"==typeof V)return B(V,Z);var w=Object.prototype.toString.call(V).slice(8,-1);if("Object"===w&&V.constructor&&(w=V.constructor.name),"Map"===w||"Set"===w)return Array.from(V);if("Arguments"===w||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(w))return B(V,Z)}},ue.exports.default=ue.exports,ue.exports.__esModule=!0},26552:function(ue,q,f){ue.exports=f(55590)},61855:function(ue,q,f){"use strict";f.d(q,{ZT:function(){return U},mG:function(){return _},Jh:function(){return I},ev:function(){return R}});var B=function($,ae){return(B=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(se,ce){se.__proto__=ce}||function(se,ce){for(var le in ce)Object.prototype.hasOwnProperty.call(ce,le)&&(se[le]=ce[le])})($,ae)};function U($,ae){if("function"!=typeof ae&&null!==ae)throw new TypeError("Class extends value "+String(ae)+" is not a constructor or null");function se(){this.constructor=$}B($,ae),$.prototype=null===ae?Object.create(ae):(se.prototype=ae.prototype,new se)}function _($,ae,se,ce){return new(se||(se=Promise))(function(oe,Ae){function be(_t){try{qe(ce.next(_t))}catch(yt){Ae(yt)}}function it(_t){try{qe(ce.throw(_t))}catch(yt){Ae(yt)}}function qe(_t){_t.done?oe(_t.value):function(oe){return oe instanceof se?oe:new se(function(Ae){Ae(oe)})}(_t.value).then(be,it)}qe((ce=ce.apply($,ae||[])).next())})}function I($,ae){var ce,le,oe,Ae,se={label:0,sent:function(){if(1&oe[0])throw oe[1];return oe[1]},trys:[],ops:[]};return Ae={next:be(0),throw:be(1),return:be(2)},"function"==typeof Symbol&&(Ae[Symbol.iterator]=function(){return this}),Ae;function be(qe){return function(_t){return function(qe){if(ce)throw new TypeError("Generator is already executing.");for(;se;)try{if(ce=1,le&&(oe=2&qe[0]?le.return:qe[0]?le.throw||((oe=le.return)&&oe.call(le),0):le.next)&&!(oe=oe.call(le,qe[1])).done)return oe;switch(le=0,oe&&(qe=[2&qe[0],oe.value]),qe[0]){case 0:case 1:oe=qe;break;case 4:return se.label++,{value:qe[1],done:!1};case 5:se.label++,le=qe[1],qe=[0];continue;case 7:qe=se.ops.pop(),se.trys.pop();continue;default:if(!(oe=(oe=se.trys).length>0&&oe[oe.length-1])&&(6===qe[0]||2===qe[0])){se=0;continue}if(3===qe[0]&&(!oe||qe[1]>oe[0]&&qe[1]<oe[3])){se.label=qe[1];break}if(6===qe[0]&&se.label<oe[1]){se.label=oe[1],oe=qe;break}if(oe&&se.label<oe[2]){se.label=oe[2],se.ops.push(qe);break}oe[2]&&se.ops.pop(),se.trys.pop();continue}qe=ae.call($,se)}catch(_t){qe=[6,_t],le=0}finally{ce=oe=0}if(5&qe[0])throw qe[1];return{value:qe[0]?qe[1]:void 0,done:!0}}([qe,_t])}}}function R($,ae,se){if(se||2===arguments.length)for(var oe,ce=0,le=ae.length;ce<le;ce++)(oe||!(ce in ae))&&(oe||(oe=Array.prototype.slice.call(ae,0,ce)),oe[ce]=ae[ce]);return $.concat(oe||Array.prototype.slice.call(ae))}},739:function(ue,q,f){"use strict";f.d(q,{l3:function(){return w},_j:function(){return V},LC:function(){return Z},ZN:function(){return O},jt:function(){return b},pV:function(){return T},F4:function(){return S},IO:function(){return k},vP:function(){return I},SB:function(){return A},oB:function(){return D},eR:function(){return v},X$:function(){return N},ZE:function(){return F},k1:function(){return z}});var B=f(14105),U=f(18967),V=function K(){(0,U.Z)(this,K)},Z=function K(){(0,U.Z)(this,K)},w="*";function N(K,j){return{type:7,name:K,definitions:j,options:{}}}function b(K){var j=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;return{type:4,styles:j,timings:K}}function I(K){var j=arguments.length>1&&void 0!==arguments[1]?arguments[1]Line truncated
|
||||
(self.webpackChunkgns3_web_ui=self.webpackChunkgns3_web_ui||[]).push([[179],{98255:function(ue){function q(f){return Promise.resolve().then(function(){var B=new Error("Cannot find module '"+f+"'");throw B.code="MODULE_NOT_FOUND",B})}q.keys=function(){return[]},q.resolve=q,q.id=98255,ue.exports=q},82908:function(ue){ue.exports=function(f,B){(null==B||B>f.length)&&(B=f.length);for(var U=0,V=new Array(B);U<B;U++)V[U]=f[U];return V},ue.exports.default=ue.exports,ue.exports.__esModule=!0},36457:function(ue){ue.exports=function(f){if(Array.isArray(f))return f},ue.exports.default=ue.exports,ue.exports.__esModule=!0},35036:function(ue){ue.exports=function(f,B){var U=null==f?null:"undefined"!=typeof Symbol&&f[Symbol.iterator]||f["@@iterator"];if(null!=U){var N,b,V=[],Z=!0,w=!1;try{for(U=U.call(f);!(Z=(N=U.next()).done)&&(V.push(N.value),!B||V.length!==B);Z=!0);}catch(_){w=!0,b=_}finally{try{!Z&&null!=U.return&&U.return()}finally{if(w)throw b}}return V}},ue.exports.default=ue.exports,ue.exports.__esModule=!0},13969:function(ue){ue.exports=function(){throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method.")},ue.exports.default=ue.exports,ue.exports.__esModule=!0},6326:function(ue,q,f){var B=f(36457),U=f(35036),V=f(54850),Z=f(13969);ue.exports=function(N,b){return B(N)||U(N,b)||V(N,b)||Z()},ue.exports.default=ue.exports,ue.exports.__esModule=!0},54850:function(ue,q,f){var B=f(82908);ue.exports=function(V,Z){if(V){if("string"==typeof V)return B(V,Z);var w=Object.prototype.toString.call(V).slice(8,-1);if("Object"===w&&V.constructor&&(w=V.constructor.name),"Map"===w||"Set"===w)return Array.from(V);if("Arguments"===w||/^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(w))return B(V,Z)}},ue.exports.default=ue.exports,ue.exports.__esModule=!0},26552:function(ue,q,f){ue.exports=f(55590)},61855:function(ue,q,f){"use strict";f.d(q,{ZT:function(){return U},mG:function(){return _},Jh:function(){return I},ev:function(){return R}});var B=function($,ae){return(B=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(se,ce){se.__proto__=ce}||function(se,ce){for(var le in ce)Object.prototype.hasOwnProperty.call(ce,le)&&(se[le]=ce[le])})($,ae)};function U($,ae){if("function"!=typeof ae&&null!==ae)throw new TypeError("Class extends value "+String(ae)+" is not a constructor or null");function se(){this.constructor=$}B($,ae),$.prototype=null===ae?Object.create(ae):(se.prototype=ae.prototype,new se)}function _($,ae,se,ce){return new(se||(se=Promise))(function(oe,Ae){function be(_t){try{qe(ce.next(_t))}catch(yt){Ae(yt)}}function it(_t){try{qe(ce.throw(_t))}catch(yt){Ae(yt)}}function qe(_t){_t.done?oe(_t.value):function(oe){return oe instanceof se?oe:new se(function(Ae){Ae(oe)})}(_t.value).then(be,it)}qe((ce=ce.apply($,ae||[])).next())})}function I($,ae){var ce,le,oe,Ae,se={label:0,sent:function(){if(1&oe[0])throw oe[1];return oe[1]},trys:[],ops:[]};return Ae={next:be(0),throw:be(1),return:be(2)},"function"==typeof Symbol&&(Ae[Symbol.iterator]=function(){return this}),Ae;function be(qe){return function(_t){return function(qe){if(ce)throw new TypeError("Generator is already executing.");for(;se;)try{if(ce=1,le&&(oe=2&qe[0]?le.return:qe[0]?le.throw||((oe=le.return)&&oe.call(le),0):le.next)&&!(oe=oe.call(le,qe[1])).done)return oe;switch(le=0,oe&&(qe=[2&qe[0],oe.value]),qe[0]){case 0:case 1:oe=qe;break;case 4:return se.label++,{value:qe[1],done:!1};case 5:se.label++,le=qe[1],qe=[0];continue;case 7:qe=se.ops.pop(),se.trys.pop();continue;default:if(!(oe=(oe=se.trys).length>0&&oe[oe.length-1])&&(6===qe[0]||2===qe[0])){se=0;continue}if(3===qe[0]&&(!oe||qe[1]>oe[0]&&qe[1]<oe[3])){se.label=qe[1];break}if(6===qe[0]&&se.label<oe[1]){se.label=oe[1],oe=qe;break}if(oe&&se.label<oe[2]){se.label=oe[2],se.ops.push(qe);break}oe[2]&&se.ops.pop(),se.trys.pop();continue}qe=ae.call($,se)}catch(_t){qe=[6,_t],le=0}finally{ce=oe=0}if(5&qe[0])throw qe[1];return{value:qe[0]?qe[1]:void 0,done:!0}}([qe,_t])}}}function R($,ae,se){if(se||2===arguments.length)for(var oe,ce=0,le=ae.length;ce<le;ce++)(oe||!(ce in ae))&&(oe||(oe=Array.prototype.slice.call(ae,0,ce)),oe[ce]=ae[ce]);return $.concat(oe||Array.prototype.slice.call(ae))}},739:function(ue,q,f){"use strict";f.d(q,{l3:function(){return w},_j:function(){return V},LC:function(){return Z},ZN:function(){return O},jt:function(){return b},pV:function(){return T},F4:function(){return S},IO:function(){return k},vP:function(){return I},SB:function(){return A},oB:function(){return D},eR:function(){return v},X$:function(){return N},ZE:function(){return F},k1:function(){return z}});var B=f(14105),U=f(18967),V=function K(){(0,U.Z)(this,K)},Z=function K(){(0,U.Z)(this,K)},w="*";function N(K,j){return{type:7,name:K,definitions:j,options:{}}}function b(K){var j=arguments.length>1&&void 0!==arguments[1]?arguments[1]:null;return{type:4,styles:j,timings:K}}function I(K){var j=arguments.length>1&&void 0!==arguments[1]?arguments[1]Line truncated
|
||||
@@ -23,6 +23,7 @@ import textwrap
|
||||
import posixpath
|
||||
import socket
|
||||
import errno
|
||||
import hashlib
|
||||
|
||||
|
||||
def force_unix_path(path):
|
||||
@@ -120,3 +121,14 @@ def is_ipv6_enabled() -> bool:
|
||||
if e.errno == errno.EADDRINUSE:
|
||||
return True
|
||||
raise
|
||||
|
||||
def md5sum(filename):
|
||||
"""
|
||||
Calculate the MD5 checksum of a file.
|
||||
"""
|
||||
|
||||
hash_md5 = hashlib.md5()
|
||||
with open(filename, "rb") as f:
|
||||
for chunk in iter(lambda: f.read(4096), b""):
|
||||
hash_md5.update(chunk)
|
||||
return hash_md5.hexdigest()
|
||||
+44
-28
@@ -45,7 +45,7 @@ def list_images(emulator_type):
|
||||
|
||||
# We limit recursion to path outside the default images directory
|
||||
# the reason is in the default directory manage file organization and
|
||||
# it should be flatten to keep things simple
|
||||
# it should be flat to keep things simple
|
||||
recurse = True
|
||||
if os.path.commonprefix([directory, general_images_directory]) == general_images_directory:
|
||||
recurse = False
|
||||
@@ -53,37 +53,53 @@ def list_images(emulator_type):
|
||||
directory = os.path.normpath(directory)
|
||||
for root, _, filenames in _os_walk(directory, recurse=recurse):
|
||||
for filename in filenames:
|
||||
if filename not in files:
|
||||
if filename.endswith(".md5sum") or filename.startswith("."):
|
||||
if filename in files:
|
||||
log.debug("File {} has already been found, skipping...".format(filename))
|
||||
continue
|
||||
if filename.endswith(".md5sum") or filename.startswith("."):
|
||||
continue
|
||||
|
||||
files.add(filename)
|
||||
|
||||
filesize = os.stat(os.path.join(root, filename)).st_size
|
||||
if filesize < 7:
|
||||
log.debug("File {} is too small to be an image, skipping...".format(filename))
|
||||
continue
|
||||
|
||||
try:
|
||||
with open(os.path.join(root, filename), "rb") as f:
|
||||
# read the first 7 bytes of the file.
|
||||
elf_header_start = f.read(7)
|
||||
if emulator_type == "dynamips" and elf_header_start != b'\x7fELF\x01\x02\x01':
|
||||
# IOS images must start with the ELF magic number, be 32-bit, big endian and have an ELF version of 1
|
||||
log.warning("IOS image {} does not start with a valid ELF magic number, skipping...".format(filename))
|
||||
continue
|
||||
elif emulator_type == "iou" and elf_header_start != b'\x7fELF\x02\x01\x01' and elf_header_start != b'\x7fELF\x01\x01\x01':
|
||||
# IOU images must start with the ELF magic number, be 32-bit or 64-bit, little endian and have an ELF version of 1
|
||||
log.warning("IOU image {} does not start with a valid ELF magic number, skipping...".format(filename))
|
||||
continue
|
||||
elif emulator_type == "qemu" and elf_header_start[:4] == b'\x7fELF':
|
||||
# QEMU images should not start with an ELF magic number
|
||||
log.warning("QEMU image {} starts with an ELF magic number, skipping...".format(filename))
|
||||
continue
|
||||
elif ((filename.endswith(".image") or filename.endswith(".bin")) and emulator_type == "dynamips") \
|
||||
or ((filename.endswith(".bin") or filename.startswith("i86bi")) and emulator_type == "iou") \
|
||||
or (not filename.endswith(".bin") and not filename.endswith(".image") and emulator_type == "qemu"):
|
||||
files.add(filename)
|
||||
|
||||
# It the image is located in the standard directory the path is relative
|
||||
if os.path.commonprefix([root, default_directory]) != default_directory:
|
||||
path = os.path.join(root, filename)
|
||||
else:
|
||||
path = os.path.relpath(os.path.join(root, filename), default_directory)
|
||||
# It the image is located in the standard directory the path is relative
|
||||
if os.path.commonprefix([root, default_directory]) != default_directory:
|
||||
path = os.path.join(root, filename)
|
||||
else:
|
||||
path = os.path.relpath(os.path.join(root, filename), default_directory)
|
||||
|
||||
try:
|
||||
if emulator_type in ["dynamips", "iou"]:
|
||||
with open(os.path.join(root, filename), "rb") as f:
|
||||
# read the first 7 bytes of the file.
|
||||
elf_header_start = f.read(7)
|
||||
# valid IOU or IOS images must start with the ELF magic number, be 32-bit or 64-bit,
|
||||
# little endian and have an ELF version of 1
|
||||
if elf_header_start != b'\x7fELF\x02\x01\x01' and elf_header_start != b'\x7fELF\x01\x01\x01':
|
||||
continue
|
||||
images.append(
|
||||
{
|
||||
"filename": filename,
|
||||
"path": force_unix_path(path),
|
||||
"md5sum": md5sum(os.path.join(root, filename)),
|
||||
"filesize": filesize
|
||||
}
|
||||
)
|
||||
|
||||
images.append({
|
||||
"filename": filename,
|
||||
"path": force_unix_path(path),
|
||||
"md5sum": md5sum(os.path.join(root, filename)),
|
||||
"filesize": os.stat(os.path.join(root, filename)).st_size})
|
||||
except OSError as e:
|
||||
log.warning("Can't add image {}: {}".format(path, str(e)))
|
||||
except OSError as e:
|
||||
log.warning("Can't add image {}: {}".format(path, str(e)))
|
||||
return images
|
||||
|
||||
|
||||
|
||||
@@ -23,8 +23,8 @@
|
||||
# or negative for a release candidate or beta (after the base version
|
||||
# number has been incremented)
|
||||
|
||||
__version__ = "2.2.51"
|
||||
__version_info__ = (2, 2, 51, 0)
|
||||
__version__ = "2.2.52"
|
||||
__version_info__ = (2, 2, 52, 0)
|
||||
|
||||
if "dev" in __version__:
|
||||
try:
|
||||
|
||||
+1
-1
@@ -8,6 +8,6 @@ psutil>=6.1.0
|
||||
async-timeout>=4.0.3,<4.1
|
||||
distro>=1.9.0
|
||||
py-cpuinfo>=9.0.0,<10.0
|
||||
platformdirs>=2.4.0
|
||||
platformdirs>=2.4.0,<3 # platformdirs >=3 conflicts when building Debian packages
|
||||
importlib-resources>=1.3; python_version < '3.9'
|
||||
truststore>=0.10.0; python_version >= '3.10'
|
||||
@@ -65,7 +65,7 @@ setup(
|
||||
zip_safe=False,
|
||||
platforms="any",
|
||||
python_requires=">=3.8",
|
||||
setup_requires=["setuptools>=61.0"],
|
||||
setup_requires=["setuptools>=45.2"],
|
||||
classifiers=[
|
||||
"Development Status :: 5 - Production/Stable",
|
||||
"Environment :: Console",
|
||||
|
||||
@@ -239,12 +239,12 @@ async def test_list_images(qemu, tmpdir):
|
||||
os.makedirs(tmp_images_dir, exist_ok=True)
|
||||
for image in fake_images:
|
||||
with open(os.path.join(tmp_images_dir, image), "w+") as f:
|
||||
f.write("1")
|
||||
f.write("1234567")
|
||||
|
||||
with patch("gns3server.utils.images.default_images_directory", return_value=str(tmp_images_dir)):
|
||||
assert sorted(await qemu.list_images(), key=lambda k: k['filename']) == [
|
||||
{"filename": "a.qcow2", "path": "a.qcow2", "md5sum": "c4ca4238a0b923820dcc509a6f75849b", "filesize": 1},
|
||||
{"filename": "b.qcow2", "path": "b.qcow2", "md5sum": "c4ca4238a0b923820dcc509a6f75849b", "filesize": 1}
|
||||
{"filename": "a.qcow2", "path": "a.qcow2", "md5sum": "fcea920f7412b5da7be0cf42b8c93759", "filesize": 7},
|
||||
{"filename": "b.qcow2", "path": "b.qcow2", "md5sum": "fcea920f7412b5da7be0cf42b8c93759", "filesize": 7}
|
||||
]
|
||||
|
||||
|
||||
@@ -255,19 +255,19 @@ async def test_list_images_recursives(qemu, tmpdir):
|
||||
fake_images = ["a.qcow2", "b.qcow2", ".blu.qcow2", "a.qcow2.md5sum"]
|
||||
for image in fake_images:
|
||||
with open(os.path.join(tmp_images_dir, image), "w+") as f:
|
||||
f.write("1")
|
||||
f.write("1234567")
|
||||
os.makedirs(os.path.join(tmp_images_dir, "c"))
|
||||
fake_images = ["c.qcow2", "c.qcow2.md5sum"]
|
||||
for image in fake_images:
|
||||
with open(os.path.join(tmp_images_dir, "c", image), "w+") as f:
|
||||
f.write("1")
|
||||
f.write("1234567")
|
||||
|
||||
with patch("gns3server.utils.images.default_images_directory", return_value=str(tmp_images_dir)):
|
||||
|
||||
assert sorted(await qemu.list_images(), key=lambda k: k['filename']) == [
|
||||
{"filename": "a.qcow2", "path": "a.qcow2", "md5sum": "c4ca4238a0b923820dcc509a6f75849b", "filesize": 1},
|
||||
{"filename": "b.qcow2", "path": "b.qcow2", "md5sum": "c4ca4238a0b923820dcc509a6f75849b", "filesize": 1},
|
||||
{"filename": "c.qcow2", "path": force_unix_path(os.path.sep.join(["c", "c.qcow2"])), "md5sum": "c4ca4238a0b923820dcc509a6f75849b", "filesize": 1}
|
||||
{"filename": "a.qcow2", "path": "a.qcow2", "md5sum": "fcea920f7412b5da7be0cf42b8c93759", "filesize": 7},
|
||||
{"filename": "b.qcow2", "path": "b.qcow2", "md5sum": "fcea920f7412b5da7be0cf42b8c93759", "filesize": 7},
|
||||
{"filename": "c.qcow2", "path": force_unix_path(os.path.sep.join(["c", "c.qcow2"])), "md5sum": "fcea920f7412b5da7be0cf42b8c93759", "filesize": 7}
|
||||
]
|
||||
|
||||
|
||||
|
||||
@@ -144,7 +144,7 @@ def fake_image(tmpdir):
|
||||
|
||||
path = str(tmpdir / "7200.bin")
|
||||
with open(path, "wb+") as f:
|
||||
f.write(b'\x7fELF\x01\x01\x01')
|
||||
f.write(b'\x7fELF\x01\x02\x01')
|
||||
os.chmod(path, stat.S_IREAD)
|
||||
return path
|
||||
|
||||
@@ -168,7 +168,7 @@ async def test_images(compute_api, tmpdir, fake_image, fake_file):
|
||||
assert response.json == [{"filename": "7200.bin",
|
||||
"path": "7200.bin",
|
||||
"filesize": 7,
|
||||
"md5sum": "e573e8f5c93c6c00783f20c7a170aa6c"
|
||||
"md5sum": "b0d5aa897d937aced5a6b1046e8f7e2e"
|
||||
}]
|
||||
|
||||
|
||||
|
||||
@@ -45,7 +45,7 @@ def fake_qemu_vm(images_dir):
|
||||
img_dir = os.path.join(images_dir, "QEMU")
|
||||
bin_path = os.path.join(img_dir, "linux载.img")
|
||||
with open(bin_path, "w+") as f:
|
||||
f.write("1")
|
||||
f.write("1234567")
|
||||
os.chmod(bin_path, stat.S_IRUSR | stat.S_IWUSR | stat.S_IXUSR)
|
||||
return bin_path
|
||||
|
||||
@@ -101,7 +101,7 @@ async def test_qemu_create_with_params(compute_api, compute_project, base_params
|
||||
assert response.json["project_id"] == compute_project.id
|
||||
assert response.json["ram"] == 1024
|
||||
assert response.json["hda_disk_image"] == "linux载.img"
|
||||
assert response.json["hda_disk_image_md5sum"] == "c4ca4238a0b923820dcc509a6f75849b"
|
||||
assert response.json["hda_disk_image_md5sum"] == "fcea920f7412b5da7be0cf42b8c93759"
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Not supported on Windows")
|
||||
@@ -279,7 +279,7 @@ async def test_images(compute_api, fake_qemu_vm):
|
||||
|
||||
response = await compute_api.get("/qemu/images")
|
||||
assert response.status == 200
|
||||
assert {"filename": "linux载.img", "path": "linux载.img", "md5sum": "c4ca4238a0b923820dcc509a6f75849b", "filesize": 1} in response.json
|
||||
assert {"filename": "linux载.img", "path": "linux载.img", "md5sum": "fcea920f7412b5da7be0cf42b8c93759", "filesize": 7} in response.json
|
||||
|
||||
|
||||
@pytest.mark.skipif(sys.platform.startswith("win"), reason="Does not work on Windows")
|
||||
|
||||
+55
-30
@@ -114,30 +114,49 @@ def test_remove_checksum(tmpdir):
|
||||
|
||||
def test_list_images(tmpdir):
|
||||
|
||||
path1 = tmpdir / "images1" / "IOS" / "test1.image"
|
||||
path1.write(b'\x7fELF\x01\x01\x01', ensure=True)
|
||||
path1 = force_unix_path(str(path1))
|
||||
# IOS image in the images directory
|
||||
ios_image_1 = tmpdir / "images1" / "IOS" / "ios_image_1.image"
|
||||
ios_image_1.write(b'\x7fELF\x01\x02\x01', ensure=True)
|
||||
ios_image_1 = force_unix_path(str(ios_image_1))
|
||||
|
||||
path2 = tmpdir / "images2" / "test2.image"
|
||||
path2.write(b'\x7fELF\x01\x01\x01', ensure=True)
|
||||
path2 = force_unix_path(str(path2))
|
||||
# IOS image in an additional images path
|
||||
ios_image_2 = tmpdir / "images2" / "ios_image_2.image"
|
||||
ios_image_2.write(b'\x7fELF\x01\x02\x01', ensure=True)
|
||||
ios_image_2 = force_unix_path(str(ios_image_2))
|
||||
|
||||
# Invalid image because not a valid elf file
|
||||
path = tmpdir / "images2" / "test_invalid.image"
|
||||
path.write(b'NOTANELF', ensure=True)
|
||||
# Not a valid elf file
|
||||
not_elf_file = tmpdir / "images1" / "IOS" / "not_elf.image"
|
||||
not_elf_file.write(b'NOTANELF', ensure=True)
|
||||
not_elf_file = force_unix_path(str(not_elf_file))
|
||||
|
||||
# Invalid image because it is very small
|
||||
small_file = tmpdir / "images1" / "too_small.image"
|
||||
small_file.write(b'1', ensure=True)
|
||||
|
||||
if sys.platform.startswith("linux"):
|
||||
path3 = tmpdir / "images1" / "IOU" / "test3.bin"
|
||||
path3.write(b'\x7fELF\x02\x01\x01', ensure=True)
|
||||
path3 = force_unix_path(str(path3))
|
||||
# 64-bit IOU image
|
||||
iou_image_1 = tmpdir / "images1" / "IOU" / "iou64.bin"
|
||||
iou_image_1.write(b'\x7fELF\x02\x01\x01', ensure=True)
|
||||
iou_image_1 = force_unix_path(str(iou_image_1))
|
||||
# 32-bit IOU image
|
||||
iou_image_2 = tmpdir / "images1" / "IOU" / "iou32.bin"
|
||||
iou_image_2.write(b'\x7fELF\x01\x01\x01', ensure=True) # 32-bit IOU image
|
||||
iou_image_2 = force_unix_path(str(iou_image_2))
|
||||
|
||||
path4 = tmpdir / "images1" / "QEMU" / "test4.qcow2"
|
||||
path4.write("1", ensure=True)
|
||||
path4 = force_unix_path(str(path4))
|
||||
|
||||
path5 = tmpdir / "images1" / "QEMU" / "test4.qcow2.md5sum"
|
||||
path5.write("1", ensure=True)
|
||||
path5 = force_unix_path(str(path5))
|
||||
# Qemu image
|
||||
qemu_image_1 = tmpdir / "images1" / "QEMU" / "qemu_image.qcow2"
|
||||
qemu_image_1.write("1234567", ensure=True)
|
||||
qemu_image_1 = force_unix_path(str(qemu_image_1))
|
||||
|
||||
# ELF file inside the Qemu
|
||||
elf_file = tmpdir / "images1" / "QEMU" / "elf_file.bin"
|
||||
elf_file.write(b'\x7fELF\x02\x01\x01', ensure=True) # ELF file
|
||||
elf_file = force_unix_path(str(elf_file))
|
||||
|
||||
md5sum_file = tmpdir / "images1" / "QEMU" / "image.qcow2.md5sum"
|
||||
md5sum_file.write("1", ensure=True)
|
||||
md5sum_file = force_unix_path(str(md5sum_file))
|
||||
|
||||
with patch("gns3server.config.Config.get_section_config", return_value={
|
||||
"images_path": str(tmpdir / "images1"),
|
||||
@@ -146,34 +165,40 @@ def test_list_images(tmpdir):
|
||||
|
||||
assert list_images("dynamips") == [
|
||||
{
|
||||
'filename': 'test1.image',
|
||||
'filename': 'ios_image_1.image',
|
||||
'filesize': 7,
|
||||
'md5sum': 'e573e8f5c93c6c00783f20c7a170aa6c',
|
||||
'path': 'test1.image'
|
||||
'md5sum': 'b0d5aa897d937aced5a6b1046e8f7e2e',
|
||||
'path': 'ios_image_1.image'
|
||||
},
|
||||
{
|
||||
'filename': 'test2.image',
|
||||
'filename': 'ios_image_2.image',
|
||||
'filesize': 7,
|
||||
'md5sum': 'e573e8f5c93c6c00783f20c7a170aa6c',
|
||||
'path': str(path2)
|
||||
'md5sum': 'b0d5aa897d937aced5a6b1046e8f7e2e',
|
||||
'path': str(ios_image_2)
|
||||
}
|
||||
]
|
||||
|
||||
if sys.platform.startswith("linux"):
|
||||
assert list_images("iou") == [
|
||||
{
|
||||
'filename': 'test3.bin',
|
||||
'filename': 'iou64.bin',
|
||||
'filesize': 7,
|
||||
'md5sum': 'c73626d23469519894d58bc98bee9655',
|
||||
'path': 'test3.bin'
|
||||
'path': 'iou64.bin'
|
||||
},
|
||||
{
|
||||
'filename': 'iou32.bin',
|
||||
'filesize': 7,
|
||||
'md5sum': 'e573e8f5c93c6c00783f20c7a170aa6c',
|
||||
'path': 'iou32.bin'
|
||||
}
|
||||
]
|
||||
|
||||
assert list_images("qemu") == [
|
||||
{
|
||||
'filename': 'test4.qcow2',
|
||||
'filesize': 1,
|
||||
'md5sum': 'c4ca4238a0b923820dcc509a6f75849b',
|
||||
'path': 'test4.qcow2'
|
||||
'filename': 'qemu_image.qcow2',
|
||||
'filesize': 7,
|
||||
'md5sum': 'fcea920f7412b5da7be0cf42b8c93759',
|
||||
'path': 'qemu_image.qcow2'
|
||||
}
|
||||
]
|
||||
Reference in new issue
Block a user