mirror of
https://github.com/GNS3/gns3-server.git
synced 2024-12-18 20:37:57 +00:00
commit
e94b55e3bf
@ -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>
|
File diff suppressed because one or more lines are too long
@ -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()
|
||||
|
@ -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:
|
||||
|
@ -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'
|
||||
|
2
setup.py
2
setup.py
@ -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")
|
||||
|
@ -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'
|
||||
}
|
||||
]
|
||||
|
Loading…
Reference in New Issue
Block a user