Merge branch '2.2' into 3.0

# Conflicts:
#	.github/workflows/testing.yml
#	CHANGELOG
#	appveyor.yml
#	dev-requirements.txt
#	gns3server/compute/base_node.py
#	gns3server/controller/__init__.py
#	gns3server/controller/appliance_manager.py
#	gns3server/crash_report.py
#	gns3server/static/web-ui/index.html
#	gns3server/utils/get_resource.py
#	gns3server/version.py
#	gns3server/web/route.py
#	requirements.txt
#	tests/handlers/api/compute/test_qemu.py
#	win-requirements.txt
This commit is contained in:
grossmj committed 2022-11-09 20:30:28 +08:00
commit 263febecbc
25 files changed
+328 -92

No files matched your search

+17 -9
View File
@@ -22,6 +22,7 @@ import socket
import shutil
import asyncio
import random
import importlib_resources
from ..config import Config
from .project import Project
@@ -32,7 +33,6 @@ from .notification import Notification
from .symbols import Symbols
from .topology import load_topology
from .gns3vm import GNS3VM
from ..utils.get_resource import get_resource
from .gns3vm.gns3_vm_error import GNS3VMError
from .controller_error import ControllerError, ControllerNotFoundError
@@ -62,7 +62,7 @@ class Controller:
async def start(self, computes=None):
log.info("Controller is starting")
self.load_base_files()
self._load_base_files()
server_config = Config.instance().settings.Server
Config.instance().listen_for_config_changes(self._update_config)
host = server_config.host
@@ -281,6 +281,7 @@ class Controller:
except OSError as e:
log.error(f"Cannot read Etag appliance file '{etag_appliances_path}': {e}")
self._appliance_manager.install_builtin_appliances()
self._appliance_manager.load_appliances()
self._config_loaded = True
@@ -305,20 +306,27 @@ class Controller:
except OSError as e:
log.error(str(e))
def load_base_files(self):
def _load_base_files(self):
"""
At startup we copy base file to the user location to allow
them to customize it
"""
dst_path = self.configs_path()
src_path = get_resource("configs")
try:
for file in os.listdir(src_path):
if not os.path.exists(os.path.join(dst_path, file)):
shutil.copy(os.path.join(src_path, file), os.path.join(dst_path, file))
except OSError:
pass
if hasattr(sys, "frozen") and sys.platform.startswith("win"):
resource_path = os.path.normpath(os.path.join(os.path.dirname(sys.executable), "configs"))
for filename in os.listdir(resource_path):
if not os.path.exists(os.path.join(dst_path, filename)):
shutil.copy(os.path.join(resource_path, filename), os.path.join(dst_path, filename))
else:
for entry in importlib_resources.files('gns3server.configs').iterdir():
full_path = os.path.join(dst_path, entry.name)
if entry.is_file() and not os.path.exists(full_path):
log.debug(f"Installing base config file {entry.name} to {full_path}")
shutil.copy(str(entry), os.path.join(dst_path, entry.name))
except OSError as e:
log.error(f"Could not install base config files to {dst_path}: {e}")
def images_path(self):
"""
+40 -6
View File
@@ -15,10 +15,13 @@
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
import sys
import os
import json
import asyncio
import aiofiles
import importlib_resources
import shutil
from typing import Tuple, List
from aiohttp.client_exceptions import ClientError
@@ -29,7 +32,6 @@ from pydantic import ValidationError
from .appliance import Appliance
from ..config import Config
from ..utils.asyncio import locking
from ..utils.get_resource import get_resource
from ..utils.http_client import HTTPClient
from .controller_error import ControllerBadRequestError, ControllerNotFoundError, ControllerError
from .appliance_to_template import ApplianceToTemplate
@@ -82,9 +84,9 @@ class ApplianceManager:
return self._appliances
def appliances_path(self) -> str:
def _custom_appliances_path(self) -> str:
"""
Get the image storage directory
Get the custom appliance storage directory
"""
server_config = Config.instance().settings.Server
@@ -92,6 +94,38 @@ class ApplianceManager:
os.makedirs(appliances_path, exist_ok=True)
return appliances_path
def _builtin_appliances_path(self):
"""
Get the built-in appliance storage directory
"""
config = Config.instance()
appliances_dir = os.path.join(config.config_dir, "appliances")
os.makedirs(appliances_dir, exist_ok=True)
return appliances_dir
def install_builtin_appliances(self):
"""
At startup we copy the built-in appliances files.
"""
dst_path = self._builtin_appliances_path()
try:
if hasattr(sys, "frozen") and sys.platform.startswith("win"):
resource_path = os.path.normpath(os.path.join(os.path.dirname(sys.executable), "appliances"))
for filename in os.listdir(resource_path):
if not os.path.exists(os.path.join(dst_path, filename)):
shutil.copy(os.path.join(resource_path, filename), os.path.join(dst_path, filename))
else:
for entry in importlib_resources.files('gns3server.appliances').iterdir():
full_path = os.path.join(dst_path, entry.name)
if entry.is_file() and not os.path.exists(full_path):
log.debug(f"Installing built-in appliance file {entry.name} to {full_path}")
shutil.copy(str(entry), os.path.join(dst_path, entry.name))
except OSError as e:
log.error(f"Could not install built-in appliance files to {dst_path}: {e}")
def _find_appliances_from_image_checksum(self, image_checksum: str) -> List[Tuple[Appliance, str]]:
"""
Find appliances that matches an image checksum.
@@ -289,11 +323,11 @@ class ApplianceManager:
self._appliances = {}
for directory, builtin in (
(
get_resource("appliances"),
self._builtin_appliances_path(),
True,
),
(
self.appliances_path(),
self._custom_appliances_path(),
False,
),
):
@@ -407,7 +441,7 @@ class ApplianceManager:
Controller.instance().save()
json_data = await response.json()
appliances_dir = get_resource("appliances")
appliances_dir = self._builtin_appliances_path()
downloaded_appliance_files = []
for appliance in json_data:
if appliance["type"] == "file":