mirror of
https://github.com/GNS3/gns3-server.git
synced 2026-11-13 18:35:15 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
43d7e8a437 | ||
|
|
833b5a9ea8 | ||
|
|
05dda0117f | ||
|
|
6f0dfecc3d | ||
|
|
2414b7a968 | ||
|
|
7b20314edb | ||
|
|
193f470eaf | ||
|
|
4335fd7ce0 | ||
|
|
ef2cf277c1 | ||
|
|
66db267e27 | ||
|
|
27fbe37375 | ||
|
|
7b3fd4450e | ||
|
|
58d1e8f0c5 | ||
|
|
8ce690ce78 | ||
|
|
c676a5bf82 |
No files matched your search
@@ -18,11 +18,7 @@ jobs:
|
||||
strategy:
|
||||
matrix:
|
||||
os: ["ubuntu-latest"]
|
||||
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
|
||||
#include:
|
||||
# only test with Python 3.10 on Windows
|
||||
# - os: windows-latest
|
||||
# python-version: "3.10"
|
||||
python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"]
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
@@ -1,5 +1,16 @@
|
||||
# Change Log
|
||||
|
||||
## 2.2.56.1 28/01/2026
|
||||
|
||||
* Fix telnet keepalive options on macOS
|
||||
* Upgrade dependencies
|
||||
* Drop Python 3.8 support
|
||||
|
||||
## 2.2.56 21/01/2026
|
||||
|
||||
* Set default location of udhcpc in "/etc/network/udhcpc". Fixes #2582
|
||||
* Upgrade pywin32 to v311
|
||||
|
||||
## 2.2.55 19/11/2025
|
||||
|
||||
* Docker API version requirements and process to handle older daemons
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
-rrequirements.txt
|
||||
|
||||
pytest==8.3.3
|
||||
flake8==7.1.0
|
||||
pytest-timeout==2.3.1
|
||||
pytest-aiohttp==1.0.5
|
||||
pytest==8.4.2 # version 8.4.2 is the last one supporting Python 3.9
|
||||
flake8==7.3.0
|
||||
pytest-timeout==2.4.0
|
||||
pytest-aiohttp==1.1.0
|
||||
@@ -0,0 +1,32 @@
|
||||
{
|
||||
"name": "Asterfusion AsterNOS-VPP",
|
||||
"category": "router",
|
||||
"description": "AsterNOS-VPP leverages SONiC’s robust routing features and management capability with VPP’s high-performance data forwarding. It supports L3 routing, NAT, PPPoE, and VPN services. Minimum requirements: 4 vCPUs and 4GB RAM.",
|
||||
"vendor_name": "Asterfusion",
|
||||
"vendor_url": "https://cloudswit.ch/product/sonic-enterprise-distribution/#vAsterNOS",
|
||||
"documentation_url": "https://docs.asternos.com/routing",
|
||||
"product_name": "AsterNOS-VPP",
|
||||
"registry_version": 6,
|
||||
"status": "stable",
|
||||
"maintainer": "Asterfusion Product Team",
|
||||
"maintainer_email": "bd@cloudswit.ch",
|
||||
"images": [
|
||||
{
|
||||
"filename": "AsterNOS-VPP_V6.1-R0101P02_x86.img.gz",
|
||||
"version": "V6.1",
|
||||
"md5sum": "55834c3e8849ab226144d79ef76acf81",
|
||||
"filesize": 1318201015,
|
||||
"download_url": "https://asternos.dev/api/file/b2c9fd83-a9d3-46f3-9676-6b49dd481d6c",
|
||||
"comments": "Registration is required to download the image."
|
||||
}
|
||||
],
|
||||
"qemu": {
|
||||
"adapter_type": "virtio-net-pci",
|
||||
"adapters": 4,
|
||||
"ram": 4096,
|
||||
"cpus": 4,
|
||||
"arch": "x86_64",
|
||||
"console_type": "telnet",
|
||||
"kvm": "require"
|
||||
}
|
||||
}
|
||||
@@ -104,9 +104,23 @@
|
||||
"md5sum": "781d0fce9fbf789f6ea6ff10dc104afb",
|
||||
"version": "25.10.0",
|
||||
"direct_download_url": "https://github.com/kernelkit/infix/releases/download/v25.10.0/infix-x86_64-disk-25.10.0.qcow2"
|
||||
},
|
||||
{
|
||||
"filename": "infix-x86_64-disk-25.11.0.qcow2",
|
||||
"filesize": 288930816,
|
||||
"md5sum": "e2eb1a4fff9d56815f37c2e82a6279fb",
|
||||
"version": "25.11.0",
|
||||
"direct_download_url": "https://github.com/kernelkit/infix/releases/download/v25.11.0/infix-x86_64-disk-25.11.0.qcow2"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "25.11.0",
|
||||
"images": {
|
||||
"bios_image": "OVMF-edk2-stable202305.fd",
|
||||
"hda_disk_image": "infix-x86_64-disk-25.11.0.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "25.10.0",
|
||||
"images": {
|
||||
|
||||
@@ -11,237 +11,34 @@
|
||||
"status": "stable",
|
||||
"maintainer": "GNS3 Team",
|
||||
"maintainer_email": "developers@gns3.net",
|
||||
"usage": "Default password is toor\nEnable persistence by selecting boot option 'Live USB Persistence'",
|
||||
"usage": "Default username is kali and the default password is kali",
|
||||
"port_name_format": "eth{0}",
|
||||
"qemu": {
|
||||
"adapter_type": "e1000",
|
||||
"adapters": 8,
|
||||
"ram": 1024,
|
||||
"ram": 2048,
|
||||
"cpus": 2,
|
||||
"hda_disk_interface": "ide",
|
||||
"arch": "x86_64",
|
||||
"console_type": "vnc",
|
||||
"boot_priority": "d",
|
||||
"kvm": "require"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "kali-linux-2021.1-live-amd64.iso",
|
||||
"version": "2021.1",
|
||||
"md5sum": "3a3716fef866e5c29a1c1ccfc94264b5",
|
||||
"filesize": 3591385088,
|
||||
"download_url": "http://cdimage.kali.org/kali-2021.1/",
|
||||
"direct_download_url": "http://cdimage.kali.org/kali-2021.1/kali-linux-2021.1-live-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "kali-linux-2019.3-amd64.iso",
|
||||
"version": "2019.3",
|
||||
"md5sum": "9c6fb00558f78ed06992d89f745ef975",
|
||||
"filesize": 3037736960,
|
||||
"download_url": "http://old.kali.org/kali-images/kali-2019.3",
|
||||
"direct_download_url": "http://old.kali.org/kali-images/kali-2019.3/kali-linux-2019.3-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "kali-linux-2019.2-amd64.iso",
|
||||
"version": "2019.2",
|
||||
"md5sum": "0f89b6225d7ea9c18682f7cc541c1179",
|
||||
"filesize": 3353227264,
|
||||
"download_url": "http://old.kali.org/kali-images/kali-2019.2",
|
||||
"direct_download_url": "http://old.kali.org/kali-images/kali-2019.2/kali-linux-2019.2-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "kali-linux-mate-2019.2-amd64.iso",
|
||||
"version": "2019.2 (MATE)",
|
||||
"md5sum": "fec8dd7009f932c51a74323df965a709",
|
||||
"filesize": 3313217536,
|
||||
"download_url": "http://old.kali.org/kali-images/kali-2019.2",
|
||||
"direct_download_url": "http://old.kali.org/kali-images/kali-2019.2/kali-linux-mate-2019.2-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "kali-linux-2019.1a-amd64.iso",
|
||||
"version": "2019.1a",
|
||||
"md5sum": "58c6111ed0be1919ea87267e7e65ab0f",
|
||||
"filesize": 3483873280,
|
||||
"download_url": "http://old.kali.org/kali-images/kali-2019.1a",
|
||||
"direct_download_url": "http://old.kali.org/kali-images/kali-2019.1a/kali-linux-2019.1a-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "kali-linux-2018.4-amd64.iso",
|
||||
"version": "2018.4",
|
||||
"md5sum": "1b2d598bb8d2003e6207c119c0ba42fe",
|
||||
"filesize": 3139436544,
|
||||
"download_url": "http://old.kali.org/kali-images/kali-2018.4",
|
||||
"direct_download_url": "http://old.kali.org/kali-images/kali-2018.4/kali-linux-2018.4-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "kali-linux-2018.3a-amd64.iso",
|
||||
"version": "2018.3a",
|
||||
"md5sum": "2da675d016bd690c05e180e33aa98b94",
|
||||
"filesize": 3192651776,
|
||||
"download_url": "http://old.kali.org/kali-images/kali-2018.3a",
|
||||
"direct_download_url": "http://old.kali.org/kali-images/kali-2018.3a/kali-linux-2018.3a-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "kali-linux-2018.1-amd64.iso",
|
||||
"version": "2018.1",
|
||||
"md5sum": "a3feb90df5b71b3c7f4a02bdddf221d7",
|
||||
"filesize": 3028500480,
|
||||
"download_url": "http://old.kali.org/kali-images/kali-2018.1",
|
||||
"direct_download_url": "http://old.kali.org/kali-images/kali-2018.1/kali-linux-2018.1-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "kali-linux-2017.3-amd64.iso",
|
||||
"version": "2017.3",
|
||||
"md5sum": "b465580c897e94675ac1daf031fa66b9",
|
||||
"filesize": 2886402048,
|
||||
"download_url": "http://old.kali.org/kali-images/kali-2017.3/",
|
||||
"direct_download_url": "http://old.kali.org/kali-images/kali-2017.3/kali-linux-2017.3-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "kali-linux-2017.2-amd64.iso",
|
||||
"version": "2017.2",
|
||||
"md5sum": "541654f8f818450dc0db866a0a0f6eec",
|
||||
"filesize": 3020619776,
|
||||
"download_url": "http://old.kali.org/kali-images/kali-2017.2/",
|
||||
"direct_download_url": "http://old.kali.org/kali-images/kali-2017.2/kali-linux-2017.2-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "kali-linux-2017.1-amd64.iso",
|
||||
"version": "2017.1",
|
||||
"md5sum": "c8e742283929d7a12dbe7c58e398ff08",
|
||||
"filesize": 2794307584,
|
||||
"download_url": "http://old.kali.org/kali-images/kali-2017.1/",
|
||||
"direct_download_url": "http://old.kali.org/kali-images/kali-2017.1/kali-linux-2017.1-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "kali-linux-2016.2-amd64.iso",
|
||||
"version": "2016.2",
|
||||
"md5sum": "3d163746bc5148e61ad689d94bc263f9",
|
||||
"filesize": 3076767744,
|
||||
"download_url": "http://old.kali.org/kali-images/kali-2016.2/",
|
||||
"direct_download_url": "http://old.kali.org/kali-images/kali-2016.2/kali-linux-2016.2-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "kali-linux-2016.1-amd64.iso",
|
||||
"version": "2016.1",
|
||||
"md5sum": "2e1230dc14036935b3279dfe3e49ad39",
|
||||
"filesize": 2945482752,
|
||||
"download_url": "http://old.kali.org/kali-images/kali-2016.1/",
|
||||
"direct_download_url": "http://old.kali.org/kali-images/kali-2016.1/kali-linux-2016.1-amd64.iso"
|
||||
},
|
||||
{
|
||||
"filename": "kali-linux-2.0-amd64.iso",
|
||||
"version": "2.0",
|
||||
"md5sum": "ef192433017c5d99a156eaef51fd389d",
|
||||
"filesize": 3320512512,
|
||||
"download_url": "https://www.offensive-security.com/kali-linux-vmware-arm-image-download/",
|
||||
"direct_download_url": "http://images.kali.org/Kali-Linux-2.0.0-vm-amd64.7z"
|
||||
},
|
||||
{
|
||||
"filename": "kali-linux-persistence-1gb.qcow2",
|
||||
"version": "1.0",
|
||||
"md5sum": "14e9c92f3ba5a0bd1128c1ea26a129ea",
|
||||
"filesize": 34734080,
|
||||
"download_url": "https://sourceforge.net/projects/gns-3/files/Qemu%20Appliances/",
|
||||
"direct_download_url": "https://sourceforge.net/projects/gns-3/files/Qemu%20Appliances/kali-linux-persistence-1gb.qcow2/download"
|
||||
{
|
||||
"filename": "kali-linux-2025.4-qemu-amd64.qcow2",
|
||||
"version": "2025.4",
|
||||
"md5sum": "a4be43351b5deb5b2823cb38a73b2095",
|
||||
"filesize": 15719268352,
|
||||
"download_url": "https://cdimage.kali.org/kali-2025.4/",
|
||||
"direct_download_url": "https://cdimage.kali.org/kali-2025.4/kali-linux-2025.4-qemu-amd64.7z",
|
||||
"compression": "7z"
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "2021.1",
|
||||
"name": "2025.4",
|
||||
"images": {
|
||||
"hda_disk_image": "kali-linux-persistence-1gb.qcow2",
|
||||
"cdrom_image": "kali-linux-2021.1-live-amd64.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "2019.3",
|
||||
"images": {
|
||||
"hda_disk_image": "kali-linux-persistence-1gb.qcow2",
|
||||
"cdrom_image": "kali-linux-2019.3-amd64.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "2019.2",
|
||||
"images": {
|
||||
"hda_disk_image": "kali-linux-persistence-1gb.qcow2",
|
||||
"cdrom_image": "kali-linux-2019.2-amd64.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "2019.2 (MATE)",
|
||||
"images": {
|
||||
"hda_disk_image": "kali-linux-persistence-1gb.qcow2",
|
||||
"cdrom_image": "kali-linux-mate-2019.2-amd64.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "2019.1a",
|
||||
"images": {
|
||||
"hda_disk_image": "kali-linux-persistence-1gb.qcow2",
|
||||
"cdrom_image": "kali-linux-2019.1a-amd64.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "2018.4",
|
||||
"images": {
|
||||
"hda_disk_image": "kali-linux-persistence-1gb.qcow2",
|
||||
"cdrom_image": "kali-linux-2018.4-amd64.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "2018.3a",
|
||||
"images": {
|
||||
"hda_disk_image": "kali-linux-persistence-1gb.qcow2",
|
||||
"cdrom_image": "kali-linux-2018.3a-amd64.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "2018.1",
|
||||
"images": {
|
||||
"hda_disk_image": "kali-linux-persistence-1gb.qcow2",
|
||||
"cdrom_image": "kali-linux-2018.1-amd64.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "2017.3",
|
||||
"images": {
|
||||
"hda_disk_image": "kali-linux-persistence-1gb.qcow2",
|
||||
"cdrom_image": "kali-linux-2017.3-amd64.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "2017.2",
|
||||
"images": {
|
||||
"hda_disk_image": "kali-linux-persistence-1gb.qcow2",
|
||||
"cdrom_image": "kali-linux-2017.2-amd64.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "2017.1",
|
||||
"images": {
|
||||
"hda_disk_image": "kali-linux-persistence-1gb.qcow2",
|
||||
"cdrom_image": "kali-linux-2017.1-amd64.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "2016.2",
|
||||
"images": {
|
||||
"hda_disk_image": "kali-linux-persistence-1gb.qcow2",
|
||||
"cdrom_image": "kali-linux-2016.2-amd64.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "2016.1",
|
||||
"images": {
|
||||
"hda_disk_image": "kali-linux-persistence-1gb.qcow2",
|
||||
"cdrom_image": "kali-linux-2016.1-amd64.iso"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "2.0",
|
||||
"images": {
|
||||
"hda_disk_image": "kali-linux-persistence-1gb.qcow2",
|
||||
"cdrom_image": "kali-linux-2.0-amd64.iso"
|
||||
"hda_disk_image": "kali-linux-2025.4-qemu-amd64.qcow2"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
{
|
||||
"appliance_id": "1174e46d-4a29-4554-a1e8-71ed90682295",
|
||||
"name": "MikroTik WinBox 2026",
|
||||
"category": "guest",
|
||||
"description": "Mikrotik's WinBox router management software for GNS3 2026",
|
||||
"vendor_name": "MikroTik",
|
||||
"vendor_url": "https://mikrotik.com",
|
||||
"documentation_url": "https://mikrotik.com/winbox",
|
||||
"product_name": "MikroTik WinBox",
|
||||
"product_url": "https://mikrotik.com/winbox",
|
||||
"registry_version": 4,
|
||||
"status": "stable",
|
||||
"availability": "free",
|
||||
"maintainer": "h3ck13r",
|
||||
"maintainer_email": "pisdushko1886@gmail.com",
|
||||
"usage": "Connect WinBox to a MikroTik CHR port and start them both. Open WinBox console and wait until MikroTik appear in neighbors tab, provide credentials and connect.",
|
||||
"docker": {
|
||||
"adapters": 1,
|
||||
"image": "snatao808/winbox-mikrotik-2026",
|
||||
"console_type": "vnc"
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,13 @@
|
||||
"on_close": "shutdown_signal"
|
||||
},
|
||||
"images": [
|
||||
{
|
||||
"filename": "vyos-1.4.4-kvm-amd64.qcow2",
|
||||
"version": "1.4.4",
|
||||
"md5sum": "942dae45d63924b58b65d069890765d4",
|
||||
"filesize": 518782976,
|
||||
"download_url": "https://support.vyos.io/"
|
||||
},
|
||||
{
|
||||
"filename": "vyos-1.4.3-kvm-amd64.qcow2",
|
||||
"version": "1.4.3",
|
||||
@@ -130,6 +137,12 @@
|
||||
}
|
||||
],
|
||||
"versions": [
|
||||
{
|
||||
"name": "1.4.4",
|
||||
"images": {
|
||||
"hda_disk_image": "vyos-1.4.4-kvm-amd64.qcow2"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "1.4.3",
|
||||
"images": {
|
||||
|
||||
@@ -3,7 +3,12 @@
|
||||
# script for udhcpc
|
||||
# Copyright (c) 2008 Natanael Copa <natanael.copa@gmail.com>
|
||||
|
||||
UDHCPC="/gns3/etc/udhcpc"
|
||||
if [ -d /etc/network ]; then
|
||||
UDHCPC="/etc/network/udhcpc"
|
||||
else
|
||||
UDHCPC="/gns3/etc/udhcpc"
|
||||
fi
|
||||
|
||||
UDHCPC_CONF="$UDHCPC/udhcpc.conf"
|
||||
|
||||
RESOLV_CONF="/etc/resolv.conf"
|
||||
|
||||
@@ -57,7 +57,7 @@ class CrashReport:
|
||||
Report crash to a third party service
|
||||
"""
|
||||
|
||||
DSN = "https://9721facaf4cb1e0a93e126300ea56901@o19455.ingest.us.sentry.io/38482"
|
||||
DSN = "https://5bfcec70239c428d44aafef68f3eea79@o19455.ingest.us.sentry.io/38482"
|
||||
_instance = None
|
||||
|
||||
def __init__(self):
|
||||
|
||||
+3
-3
@@ -235,9 +235,9 @@ def run():
|
||||
return
|
||||
log.info("HTTP authentication is enabled with username '{}'".format(user))
|
||||
|
||||
# we only support Python 3 version >= 3.8
|
||||
if sys.version_info < (3, 8, 0):
|
||||
raise SystemExit("Python 3.8 or higher is required")
|
||||
# we only support Python 3 version >= 3.9
|
||||
if sys.version_info < (3, 9, 0):
|
||||
raise SystemExit("Python 3.9 or higher is required")
|
||||
|
||||
user_log.info("Running with Python {major}.{minor}.{micro} and has PID {pid}".format(major=sys.version_info[0], minor=sys.version_info[1],
|
||||
micro=sys.version_info[2], pid=os.getpid()))
|
||||
|
||||
@@ -91,25 +91,16 @@ async def wait_for_process_termination(process, timeout=10):
|
||||
In theory this can be implemented by just:
|
||||
await asyncio.wait_for(self._iou_process.wait(), timeout=100)
|
||||
|
||||
But it's broken before Python 3.4:
|
||||
http://bugs.python.org/issue23140
|
||||
|
||||
:param process: An asyncio subprocess
|
||||
:param timeout: Timeout in seconds
|
||||
"""
|
||||
|
||||
if sys.version_info >= (3, 5):
|
||||
try:
|
||||
await asyncio.wait_for(process.wait(), timeout=timeout)
|
||||
except ProcessLookupError:
|
||||
while timeout > 0:
|
||||
if process.returncode is not None:
|
||||
return
|
||||
else:
|
||||
while timeout > 0:
|
||||
if process.returncode is not None:
|
||||
return
|
||||
await asyncio.sleep(0.1)
|
||||
timeout -= 0.1
|
||||
raise asyncio.TimeoutError()
|
||||
await asyncio.sleep(0.1)
|
||||
timeout -= 0.1
|
||||
raise asyncio.TimeoutError()
|
||||
|
||||
|
||||
async def _check_process(process, termination_callback):
|
||||
|
||||
@@ -40,10 +40,7 @@ class Pool():
|
||||
while len(self._tasks) > 0 or len(pending) > 0:
|
||||
while len(self._tasks) > 0 and len(pending) < self._concurrency:
|
||||
task, args, kwargs = self._tasks.pop(0)
|
||||
if sys.version_info >= (3, 7):
|
||||
t = asyncio.create_task(task(*args, **kwargs))
|
||||
else:
|
||||
t = asyncio.get_event_loop().create_task(task(*args, **kwargs))
|
||||
t = asyncio.create_task(task(*args, **kwargs))
|
||||
pending.add(t)
|
||||
(done, pending) = await asyncio.wait(pending, return_when=asyncio.FIRST_COMPLETED)
|
||||
for task in done:
|
||||
|
||||
@@ -186,15 +186,25 @@ class AsyncioTelnetServer:
|
||||
await writer.drain()
|
||||
|
||||
async def run(self, network_reader, network_writer):
|
||||
|
||||
sock = network_writer.get_extra_info("socket")
|
||||
sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
|
||||
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
|
||||
# 60 sec keep alives, close tcp session after 4 missed
|
||||
# Will keep a firewall from aging out telnet console.
|
||||
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 60)
|
||||
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 10)
|
||||
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 4)
|
||||
try:
|
||||
# Keepalive options are platform dependent: Linux uses TCP_KEEPIDLE,
|
||||
# while macOS exposes TCP_KEEPALIVE (in Python >= 3.10).
|
||||
if hasattr(socket, "TCP_KEEPIDLE"):
|
||||
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 60)
|
||||
elif hasattr(socket, "TCP_KEEPALIVE"):
|
||||
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPALIVE, 60)
|
||||
else:
|
||||
raise AttributeError("module 'socket' has no attribute 'TCP_KEEPIDLE' or 'TCP_KEEPALIVE'")
|
||||
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 10)
|
||||
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 4)
|
||||
except (AttributeError, OSError):
|
||||
log.debug("Failed to tune TCP keepalive for telnet client; using OS defaults", exc_info=True)
|
||||
|
||||
#log.debug("New connection from {}".format(sock.getpeername()))
|
||||
|
||||
# Keep track of connected clients
|
||||
|
||||
@@ -23,8 +23,9 @@
|
||||
# or negative for a release candidate or beta (after the base version
|
||||
# number has been incremented)
|
||||
|
||||
__version__ = "2.2.55"
|
||||
__version_info__ = (2, 2, 55, 0)
|
||||
__version__ = "2.2.56.1"
|
||||
__version_info__ = (2, 2, 56, 0)
|
||||
|
||||
if "dev" in __version__:
|
||||
try:
|
||||
import os
|
||||
|
||||
+8
-9
@@ -1,13 +1,12 @@
|
||||
jsonschema>=4.23,<4.24
|
||||
aiohttp>=3.10.11,<3.11 # version 3.10.11 is the last compatible version with Python 3.8
|
||||
aiohttp-cors>=0.7.0,<0.8
|
||||
aiofiles>=24.1.0,<25.0
|
||||
jsonschema>=4.25.1,<4.26 # version 4.25.1 is the last to support Python 3.9
|
||||
aiohttp>=3.13.3,<3.14
|
||||
aiohttp-cors>=0.8.1,<0.9
|
||||
aiofiles>=25.1.0,<26.0
|
||||
Jinja2>=3.1.6,<3.2
|
||||
sentry-sdk>=2.44.0,<2.45 # optional dependency
|
||||
psutil>=7.1.3
|
||||
async-timeout>=5.0.1,<5.1
|
||||
sentry-sdk>=2.50.0,<3 # optional dependency
|
||||
psutil>=7.2.1
|
||||
async-timeout>=5.0.1,<5.1 # this library has effectively been upstreamed into Python 3.11+
|
||||
distro>=1.9.0
|
||||
py-cpuinfo>=9.0.0,<10.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'
|
||||
truststore>=0.10.4; python_version >= '3.10'
|
||||
@@ -1,238 +0,0 @@
|
||||
#!/usr/bin/env python
|
||||
#
|
||||
# Copyright (C) 2016 GNS3 Technologies Inc.
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
"""
|
||||
This script connect to the local GNS3 server and will create a random topology
|
||||
"""
|
||||
|
||||
import sys
|
||||
import json
|
||||
import math
|
||||
import aiohttp
|
||||
import aiohttp.web
|
||||
import asyncio
|
||||
import random
|
||||
|
||||
import coloredlogs
|
||||
import logging
|
||||
|
||||
coloredlogs.install(fmt=" %(asctime)s %(levelname)s %(message)s")
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
PROJECT_ID = "9e26e37d-4962-4921-8c0e-136d3b04ba9c"
|
||||
HOST = "192.168.84.151:3080"
|
||||
|
||||
# Use for node names uniqueness
|
||||
node_i = 1
|
||||
|
||||
|
||||
def die(*args):
|
||||
log.error(*args)
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
class HTTPError(Exception):
|
||||
|
||||
def __init__(self, method, path, response):
|
||||
self._method = method
|
||||
self._path = path
|
||||
self._response = response
|
||||
|
||||
@property
|
||||
def response(self):
|
||||
return self._response
|
||||
|
||||
@property
|
||||
def path(self):
|
||||
return self._path
|
||||
|
||||
@property
|
||||
def method(self):
|
||||
return self._method
|
||||
|
||||
|
||||
class HTTPConflict(HTTPError):
|
||||
pass
|
||||
|
||||
|
||||
class HTTPNotFound(HTTPError):
|
||||
pass
|
||||
|
||||
|
||||
async def query(method, path, body=None, **kwargs):
|
||||
global session
|
||||
|
||||
if body:
|
||||
kwargs["data"] = json.dumps(body)
|
||||
|
||||
async with session.request(method, "http://" + HOST + "/v2" + path, **kwargs) as response:
|
||||
if response.status == 409:
|
||||
raise HTTPConflict(method, path, response)
|
||||
elif response.status == 404:
|
||||
raise HTTPNotFound(method, path, response)
|
||||
elif response.status >= 300:
|
||||
raise HTTPError(method, path, response)
|
||||
log.info("%s %s %d", method, path, response.status)
|
||||
if response.headers["content-type"] == "application/json":
|
||||
return await response.json()
|
||||
else:
|
||||
return "{}"
|
||||
|
||||
|
||||
async def post(path, **kwargs):
|
||||
return await query("POST", path, **kwargs)
|
||||
|
||||
|
||||
async def get(path, **kwargs):
|
||||
return await query("GET", path, **kwargs)
|
||||
|
||||
|
||||
async def delete(path, **kwargs):
|
||||
return await query("DELETE", path, **kwargs)
|
||||
|
||||
|
||||
async def create_project():
|
||||
# Delete project if already exists
|
||||
response = await get("/projects")
|
||||
project_exists = False
|
||||
for project in response:
|
||||
if project["name"] == "random" and project["project_id"] != PROJECT_ID:
|
||||
await delete("/projects/" + project["project_id"])
|
||||
elif project["project_id"] == PROJECT_ID:
|
||||
project_exists = True
|
||||
tasks = []
|
||||
for node in await get("/projects/" + PROJECT_ID + "/nodes"):
|
||||
tasks.append(delete_node(project, node))
|
||||
await asyncio.gather(*tasks)
|
||||
if project_exists:
|
||||
response = await post("/projects/" + PROJECT_ID + "/open")
|
||||
else:
|
||||
response = await post("/projects", body={"name": "random", "project_id": PROJECT_ID, "auto_close": False})
|
||||
return response
|
||||
|
||||
|
||||
async def create_node(project):
|
||||
global node_i
|
||||
|
||||
r = random.randint(0, 1)
|
||||
|
||||
if r == 0:
|
||||
node_type = "ethernet_switch"
|
||||
symbol = ":/symbols/ethernet_switch.svg"
|
||||
elif r == 1:
|
||||
node_type = "vpcs"
|
||||
symbol = ":/symbols/vpcs_guest.svg"
|
||||
response = await post("/projects/{}/nodes".format(project["project_id"]), body={
|
||||
"node_type": node_type,
|
||||
"compute_id": "local",
|
||||
"symbol": symbol,
|
||||
"name": "Node{}".format(node_i),
|
||||
"x": (math.floor((node_i - 1) % 12.0) * 100) - 500,
|
||||
"y": (math.ceil((node_i) / 12.0) * 100) - 300
|
||||
})
|
||||
node_i += 1
|
||||
return response
|
||||
|
||||
|
||||
async def delete_node(project, node):
|
||||
await delete("/projects/{}/nodes/{}".format(project["project_id"], node["node_id"]))
|
||||
|
||||
|
||||
async def create_link(project, nodes):
|
||||
"""
|
||||
Create all possible link of a node
|
||||
"""
|
||||
node1 = random.choice(list(nodes.values()))
|
||||
|
||||
for port in range(0, 8):
|
||||
node2 = random.choice(list(nodes.values()))
|
||||
|
||||
if node1 == node2:
|
||||
continue
|
||||
|
||||
data = {"nodes":
|
||||
[
|
||||
{
|
||||
"adapter_number": 0,
|
||||
"node_id": node1["node_id"],
|
||||
"port_number": port
|
||||
},
|
||||
{
|
||||
"adapter_number": 0,
|
||||
"node_id": node2["node_id"],
|
||||
"port_number": port
|
||||
}
|
||||
]
|
||||
}
|
||||
try:
|
||||
await post("/projects/{}/links".format(project["project_id"]), body=data)
|
||||
except (HTTPConflict, HTTPNotFound):
|
||||
pass
|
||||
|
||||
|
||||
async def build_topology():
|
||||
global node_i
|
||||
|
||||
nodes = {}
|
||||
project = await create_project()
|
||||
while True:
|
||||
rand = random.randint(0, 1000)
|
||||
if rand < 500: # chance to create a new node
|
||||
if len(nodes.keys()) < 255: # Limit of VPCS:
|
||||
node = await create_node(project)
|
||||
nodes[node["node_id"]] = node
|
||||
elif rand < 600: # start all nodes
|
||||
await post("/projects/{}/nodes/start".format(project["project_id"]))
|
||||
elif rand < 700: # stop all nodes
|
||||
await post("/projects/{}/nodes/stop".format(project["project_id"]))
|
||||
elif rand < 950: # create a link
|
||||
if len(nodes.keys()) >= 2:
|
||||
await create_link(project, nodes)
|
||||
elif rand < 999: # chance to delete a node
|
||||
continue
|
||||
if len(nodes.keys()) > 0:
|
||||
node = random.choice(list(nodes.values()))
|
||||
await delete_node(project, node)
|
||||
del nodes[node["node_id"]]
|
||||
elif len(nodes.keys()) > 0: # % chance to delete all nodes
|
||||
continue
|
||||
node_i = 1
|
||||
tasks = []
|
||||
for node in nodes.values():
|
||||
tasks.append(delete_node(project, node))
|
||||
await asyncio.gather(*tasks)
|
||||
nodes = {}
|
||||
await asyncio.sleep(0.2)
|
||||
|
||||
async def main(loop):
|
||||
global session
|
||||
async with aiohttp.ClientSession() as session:
|
||||
try:
|
||||
await build_topology()
|
||||
except HTTPError as error:
|
||||
try:
|
||||
j = await error.response.json()
|
||||
die("%s %s invalid status %d:\n%s", error.method, error.path, error.response.status, json.dumps(j, indent=4))
|
||||
except (ValueError, aiohttp.ServerDisconnectedError):
|
||||
die("%s %s invalid status %d", error.method, error.path, error.response.status)
|
||||
|
||||
|
||||
loop = asyncio.get_event_loop()
|
||||
loop.run_until_complete(main(loop))
|
||||
|
||||
if session:
|
||||
session.close()
|
||||
@@ -21,8 +21,8 @@ from setuptools import setup, find_packages
|
||||
from setuptools.command.test import test as TestCommand
|
||||
|
||||
# we only support Python 3 version >= 3.8
|
||||
if len(sys.argv) >= 2 and sys.argv[1] == "install" and sys.version_info < (3, 8):
|
||||
raise SystemExit("Python 3.8 or higher is required")
|
||||
if len(sys.argv) >= 2 and sys.argv[1] == "install" and sys.version_info < (3, 9):
|
||||
raise SystemExit("Python 3.9 or higher is required")
|
||||
|
||||
|
||||
class PyTest(TestCommand):
|
||||
@@ -78,7 +78,6 @@ setup(
|
||||
"Operating System :: Microsoft :: Windows",
|
||||
"Programming Language :: Python",
|
||||
"Programming Language :: Python :: 3 :: Only",
|
||||
"Programming Language :: Python :: 3.8",
|
||||
"Programming Language :: Python :: 3.9",
|
||||
"Programming Language :: Python :: 3.10",
|
||||
"Programming Language :: Python :: 3.11",
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
-rrequirements.txt
|
||||
|
||||
pywin32==306
|
||||
pywin32==311
|
||||
wmi==1.5.1
|
||||
Reference in new issue
Block a user