diff --git a/.github/workflows/publish-api-documentation.yml b/.github/workflows/publish-api-documentation.yml index 782e76fe..30beb62f 100644 --- a/.github/workflows/publish-api-documentation.yml +++ b/.github/workflows/publish-api-documentation.yml @@ -12,11 +12,11 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: fetch-depth: 0 ref: "gh-pages" - - uses: actions/setup-python@v2 + - uses: actions/setup-python@v3 with: python-version: 3.7 - name: Merge changes from 3.0 branch @@ -24,13 +24,10 @@ jobs: git config user.name github-actions git config user.email github-actions@github.com git merge origin/3.0 -X theirs - - name: Install dependencies + - name: Install GNS3 server and dependencies run: | python -m pip install --upgrade pip - if [ -f requirements.txt ]; then pip install -r requirements.txt; fi - - name: Install GNS3 server - run: | - python setup.py install + python -m pip install . - name: Generate the API documentation run: | cd scripts diff --git a/CHANGELOG b/CHANGELOG index 571c5931..b8c55692 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,5 +1,15 @@ # Change Log +## 2.2.43 19/09/2023 + +* Force English output for VBoxManage. Fixes #2266 +* Automatically add vboxnet and DHCP server if not present for VirtualBox GNS3 VM. Ref #2266 +* Fix issue with controller config saved before checking current version with previous one +* Prevent X11 socket file to be modified by Docker container +* Use the user data dir to store built-in appliances +* Catch ConnectionResetError exception when client disconnects +* Upgrade to PyQt 5.15.9 and pywin32 + ## 2.2.42 09/08/2023 * Bundle web-ui v2.2.42 diff --git a/gns3server/appliances/open-media-vault.gns3a b/gns3server/appliances/open-media-vault.gns3a index 262a8db0..9b634b93 100644 --- a/gns3server/appliances/open-media-vault.gns3a +++ b/gns3server/appliances/open-media-vault.gns3a @@ -26,6 +26,14 @@ "kvm": "require" }, "images": [ + { + "filename": "openmediavault_6.5.0-amd64.iso", + "version": "6.5.0", + "md5sum": "aa40e5ca50748b139cba2f4ac704a72d", + "filesize": 941621248, + "download_url": "https://www.openmediavault.org/download.html", + "direct_download_url": "https://sourceforge.net/projects/openmediavault/files/6.5.0/openmediavault_6.5.0-amd64.iso" + }, { "filename": "openmediavault_6.0.24-amd64.iso", "version": "6.0.24", @@ -60,6 +68,14 @@ } ], "versions": [ + { + "name": "6.5.0", + "images": { + "hda_disk_image": "empty30G.qcow2", + "hdb_disk_image": "empty30G.qcow2", + "cdrom_image": "openmediavault_6.5.0-amd64.iso" + } + }, { "name": "6.0.24", "images": { diff --git a/gns3server/appliances/openwrt.gns3a b/gns3server/appliances/openwrt.gns3a index e6428658..b4a7a697 100644 --- a/gns3server/appliances/openwrt.gns3a +++ b/gns3server/appliances/openwrt.gns3a @@ -170,7 +170,7 @@ { "filename": "openwrt-18.06.5-x86-64-combined-ext4.img", "version": "18.06.5", - "md5sum": "6fce24c15f0bc75af16c133b839aea30", + "md5sum": "a0f72f4e75e15bef06396fa31eb1bc82", "filesize": 285736960, "download_url": "https://downloads.openwrt.org/releases/18.06.5/targets/x86/64/", "direct_download_url": "https://downloads.openwrt.org/releases/18.06.5/targets/x86/64/openwrt-18.06.5-x86-64-combined-ext4.img.gz", @@ -179,7 +179,7 @@ { "filename": "openwrt-18.06.2-x86-64-combined-ext4.img", "version": "18.06.2", - "md5sum": "d112cd432bf51e2ddadbf9513f272fd9", + "md5sum": "9996a3c070b3e2ea582d28293bd78055", "filesize": 285736960, "download_url": "https://downloads.openwrt.org/releases/18.06.2/targets/x86/64/", "direct_download_url": "https://downloads.openwrt.org/releases/18.06.2/targets/x86/64/openwrt-18.06.2-x86-64-combined-ext4.img.gz", diff --git a/gns3server/appliances/vyos.gns3a b/gns3server/appliances/vyos.gns3a index fd6f97f1..31a78deb 100644 --- a/gns3server/appliances/vyos.gns3a +++ b/gns3server/appliances/vyos.gns3a @@ -59,32 +59,28 @@ "version": "1.2.9-S1", "md5sum": "3fece6363f9766f862e26d292d0ed5a3", "filesize": 430964736, - "download_url": "https://support.vyos.io/en/downloads/files/vyos-1-2-9-s1-generic-iso-image", - "direct_download_url": "https://s3-us.vyos.io/1.2.9-S1/vyos-1.2.9-S1-amd64.iso" + "download_url": "https://support.vyos.io/en/downloads/files/vyos-1-2-9-s1-generic-iso-image" }, { "filename": "vyos-1.2.9-S1-10G-qemu.qcow2", "version": "1.2.9-S1-KVM", "md5sum": "0a70d78b80a3716d42487c02ef44f41f", "filesize": 426967040, - "download_url": "https://support.vyos.io/en/downloads/files/vyos-1-2-9-s1-for-kvm", - "direct_download_url": "https://s3-us.vyos.io/1.2.9-S1/vyos-1.2.9-S1-10G-qemu.qcow2" + "download_url": "https://support.vyos.io/en/downloads/files/vyos-1-2-9-s1-for-kvm" }, { "filename": "vyos-1.2.9-amd64.iso", "version": "1.2.9", "md5sum": "586be23b6256173e174c82d8f1f699a1", "filesize": 430964736, - "download_url": "https://support.vyos.io/en/downloads/files/vyos-1-2-9-generic-iso-image", - "direct_download_url": "https://s3-us.vyos.io/1.2.9/vyos-1.2.9-amd64.iso" + "download_url": "https://support.vyos.io/en/downloads/files/vyos-1-2-9-generic-iso-image" }, { "filename": "vyos-1.2.9-10G-qemu.qcow2", "version": "1.2.9-KVM", "md5sum": "76871c7b248c32f75177c419128257ac", "filesize": 427360256, - "download_url": "https://support.vyos.io/en/downloads/files/vyos-1-2-9-10g-qemu-qcow2", - "direct_download_url": "https://s3-us.vyos.io/1.2.9/vyos-1.2.9-10G-qemu.qcow2" + "download_url": "https://support.vyos.io/en/downloads/files/vyos-1-2-9-10g-qemu-qcow2" }, { "filename": "vyos-1.2.8-amd64.iso", @@ -93,13 +89,6 @@ "filesize": 429916160, "download_url": "https://support.vyos.io/en/downloads/files/vyos-1-2-8-generic-iso-image" }, - { - "filename": "vyos-1.1.8-amd64.iso", - "version": "1.1.8", - "md5sum": "95a141d4b592b81c803cdf7e9b11d8ea", - "filesize": 241172480, - "direct_download_url": "https://s3-us.vyos.io/vyos-1.1.8-amd64.iso" - }, { "filename": "empty8G.qcow2", "version": "1.0", @@ -170,13 +159,6 @@ "hda_disk_image": "empty8G.qcow2", "cdrom_image": "vyos-1.2.8-amd64.iso" } - }, - { - "name": "1.1.8", - "images": { - "hda_disk_image": "empty8G.qcow2", - "cdrom_image": "vyos-1.1.8-amd64.iso" - } } ] } diff --git a/gns3server/appliances/windows-11-dev-env.gns3a b/gns3server/appliances/windows-11-dev-env.gns3a index b0888e46..b9b453e8 100644 --- a/gns3server/appliances/windows-11-dev-env.gns3a +++ b/gns3server/appliances/windows-11-dev-env.gns3a @@ -29,6 +29,14 @@ "kvm": "require" }, "images": [ + { + "filename": "WinDev2308Eval-disk1.vmdk", + "version": "2308", + "md5sum": "6a9b4ed6d7481f7bbf8a054c797b1eee", + "filesize": 24945341952, + "download_url": "https://download.microsoft.com/download/7/1/3/7135f2ab-8528-49fc-9252-8d5d94c697ef/WinDev2308Eval.VMWare.zip", + "compression": "zip" + }, { "filename": "WinDev2212Eval-disk1.vmdk", "version": "2212", @@ -48,6 +56,13 @@ } ], "versions": [ + { + "name": "2308", + "images": { + "bios_image": "OVMF-edk2-stable202305.fd", + "hda_disk_image": "WinDev2308Eval-disk1.vmdk" + } + }, { "name": "2212", "images": { diff --git a/gns3server/compute/virtualbox/__init__.py b/gns3server/compute/virtualbox/__init__.py index 628a24c2..5627fb5e 100644 --- a/gns3server/compute/virtualbox/__init__.py +++ b/gns3server/compute/virtualbox/__init__.py @@ -100,9 +100,14 @@ class VirtualBox(BaseManager): command.extend(args) command_string = " ".join(command) log.info(f"Executing VBoxManage with command: {command_string}") + env = os.environ.copy() + env["LANG"] = "en" # force english output because we rely on it to parse the output try: process = await asyncio.create_subprocess_exec( - *command, stdout=asyncio.subprocess.PIPE, stderr=asyncio.subprocess.PIPE + *command, + stdout=asyncio.subprocess.PIPE, + stderr=asyncio.subprocess.PIPE, + env=env ) except (OSError, subprocess.SubprocessError) as e: raise VirtualBoxError(f"Could not execute VBoxManage: {e}") diff --git a/gns3server/controller/gns3vm/virtualbox_gns3_vm.py b/gns3server/controller/gns3vm/virtualbox_gns3_vm.py index 06ca5370..79d97d94 100644 --- a/gns3server/controller/gns3vm/virtualbox_gns3_vm.py +++ b/gns3server/controller/gns3vm/virtualbox_gns3_vm.py @@ -15,11 +15,13 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . +import re import sys import aiohttp import logging import asyncio import socket +import ipaddress from .base_gns3_vm import BaseGNS3VM from .gns3_vm_error import GNS3VMError @@ -77,9 +79,6 @@ class VirtualBoxGNS3VM(BaseGNS3VM): except ValueError: continue self._system_properties[name.strip()] = value.strip() - if "API Version" in self._system_properties: - # API version is not consistent between VirtualBox versions, the key is named "API Version" in VirtualBox 7 - self._system_properties["API version"] = self._system_properties.pop("API Version") async def _check_requirements(self): """ @@ -164,6 +163,44 @@ class VirtualBoxGNS3VM(BaseGNS3VM): return True return False + async def _add_dhcp_server(self, vboxnet): + """ + Add a DHCP server for vboxnet. + + :param vboxnet: vboxnet name + """ + + hostonlyifs = await self._execute("list", ["hostonlyifs"]) + pattern = r"IPAddress:\s+(\d+\.\d+\.\d+\.\d+)\nNetworkMask:\s+(\d+\.\d+\.\d+\.\d+)" + match = re.search(pattern, hostonlyifs) + + if match: + ip_address = match.group(1) + netmask = match.group(2) + else: + raise GNS3VMError("Could not find IP address and netmask for vboxnet {}".format(vboxnet)) + + try: + interface = ipaddress.IPv4Interface(f"{ip_address}/{netmask}") + subnet = ipaddress.IPv4Network(str(interface.network)) + dhcp_server_ip = str(interface.ip + 1) + netmask = str(subnet.netmask) + lower_ip = str(interface.ip + 2) + upper_ip = str(subnet.network_address + subnet.num_addresses - 2) + except ValueError: + raise GNS3VMError("Invalid IP address and netmask for vboxnet {}: {}/{}".format(vboxnet, ip_address, netmask)) + + dhcp_server_args = [ + "add", + "--network=HostInterfaceNetworking-{}".format(vboxnet), + "--server-ip={}".format(dhcp_server_ip), + "--netmask={}".format(netmask), + "--lower-ip={}".format(lower_ip), + "--upper-ip={}".format(upper_ip), + "--enable" + ] + await self._execute("dhcpserver", dhcp_server_args) + async def _check_vboxnet_exists(self, vboxnet, vboxnet_type): """ Check if the vboxnet interface exists @@ -266,12 +303,20 @@ class VirtualBoxGNS3VM(BaseGNS3VM): await self.set_hostonly_network(interface_number, first_available_vboxnet) vboxnet = first_available_vboxnet else: - raise GNS3VMError('VirtualBox host-only network "{}" does not exist, please make the sure the network adapter {} configuration is valid for "{}"'.format(vboxnet, - interface_number, - self._vmname)) + try: + await self._execute("hostonlyif", ["create"]) + except GNS3VMError: + raise GNS3VMError('VirtualBox host-only network "{}" does not exist and could not be automatically created, please make the sure the network adapter {} configuration is valid for "{}"'.format( + vboxnet, + interface_number, + self._vmname + )) if backend_type == "hostonlyadapter" and not (await self._check_dhcp_server(vboxnet)): - raise GNS3VMError('DHCP must be enabled on VirtualBox host-only network "{}"'.format(vboxnet)) + try: + await self._add_dhcp_server(vboxnet) + except GNS3VMError as e: + raise GNS3VMError("Could not add DHCP server for vboxnet {}: {}, please configure manually".format(vboxnet, e)) vm_state = await self._get_state() log.info(f'"{self._vmname}" state is {vm_state}') diff --git a/requirements.txt b/requirements.txt index 321af4f5..a0693b37 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,7 +6,7 @@ aiohttp>=3.8.5,<3.9 async-timeout==4.0.3 aiofiles==23.2.1 Jinja2>=3.1.2,<3.2 -sentry-sdk==1.30.0,<1.31 +sentry-sdk==1.31.0,<1.32 psutil==5.9.5 distro>=1.8.0 py-cpuinfo==9.0.0 @@ -19,4 +19,5 @@ email-validator==2.0.0.post2 watchfiles==0.20.0 zstandard==0.21.0 platformdirs==3.10.0 -importlib_resources>=1.3 +importlib-resources>=1.3; python_version <= '3.9' +truststore>=0.8.0; python_version >= '3.10' \ No newline at end of file