1
0
mirror of https://github.com/GNS3/gns3-server synced 2024-11-24 17:28:08 +00:00

Merge pull request #2219 from GNS3/install-qemu-empty-disks

Install empty Qemu disks
This commit is contained in:
Jeremy Grossmann 2023-05-08 16:58:26 +08:00 committed by GitHub
commit 9868c28bc6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
16 changed files with 89 additions and 40 deletions

View File

@ -30,6 +30,7 @@ except ImportError:
from ..config import Config from ..config import Config
from ..utils import parse_version from ..utils import parse_version
from ..utils.images import default_images_directory
from .project import Project from .project import Project
from .template import Template from .template import Template
@ -72,6 +73,7 @@ class Controller:
log.info("Controller is starting") log.info("Controller is starting")
self._install_base_configs() self._install_base_configs()
self._install_builtin_disks()
server_config = Config.instance().get_section_config("Server") server_config = Config.instance().get_section_config("Server")
Config.instance().listen_for_config_changes(self._update_config) Config.instance().listen_for_config_changes(self._update_config)
host = server_config.get("host", "localhost") host = server_config.get("host", "localhost")
@ -279,29 +281,50 @@ class Controller:
except OSError as e: except OSError as e:
log.error(str(e)) log.error(str(e))
@staticmethod
def install_resource_files(dst_path, resource_name):
"""
Install files from resources to user's file system
"""
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):
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(f'gns3server.{resource_name}').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 {resource_name} resource file "{entry.name}" to "{full_path}"')
shutil.copy(str(entry), os.path.join(dst_path, entry.name))
def _install_base_configs(self): def _install_base_configs(self):
""" """
At startup we copy base file to the user location to allow At startup we copy base configs to the user location to allow
them to customize it them to customize it
""" """
dst_path = self.configs_path() dst_path = self.configs_path()
log.info(f"Installing base configs in '{dst_path}'") log.info(f"Installing base configs in '{dst_path}'")
try: try:
if hasattr(sys, "frozen") and sys.platform.startswith("win"): Controller.install_resource_files(dst_path, "configs")
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: except OSError as e:
log.error(f"Could not install base config files to {dst_path}: {e}") log.error(f"Could not install base config files to {dst_path}: {e}")
def _install_builtin_disks(self):
"""
At startup we copy built-in Qemu disks to the user location to allow
them to use with appliances
"""
dst_path = self.disks_path()
log.info(f"Installing built-in disks in '{dst_path}'")
try:
Controller.install_resource_files(dst_path, "disks")
except OSError as e:
log.error(f"Could not install disk files to {dst_path}: {e}")
def images_path(self): def images_path(self):
""" """
Get the image storage directory Get the image storage directory
@ -322,6 +345,15 @@ class Controller:
os.makedirs(configs_path, exist_ok=True) os.makedirs(configs_path, exist_ok=True)
return configs_path return configs_path
def disks_path(self, emulator_type="qemu"):
"""
Get the disks storage directory
"""
disks_path = default_images_directory(emulator_type)
os.makedirs(disks_path, exist_ok=True)
return disks_path
async def add_compute(self, compute_id=None, name=None, force=False, connect=True, **kwargs): async def add_compute(self, compute_id=None, name=None, force=False, connect=True, **kwargs):
""" """
Add a server to the dictionary of computes controlled by this controller Add a server to the dictionary of computes controlled by this controller

View File

@ -100,17 +100,9 @@ class ApplianceManager:
dst_path = self._builtin_appliances_path(delete_first=True) dst_path = self._builtin_appliances_path(delete_first=True)
log.info(f"Installing built-in appliances in '{dst_path}'") log.info(f"Installing built-in appliances in '{dst_path}'")
from . import Controller
try: try:
if hasattr(sys, "frozen") and sys.platform.startswith("win"): Controller.instance().install_resource_files(dst_path, "appliances")
resource_path = os.path.normpath(os.path.join(os.path.dirname(sys.executable), "appliances"))
for filename in os.listdir(resource_path):
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():
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: except OSError as e:
log.error(f"Could not install built-in appliance files to {dst_path}: {e}") log.error(f"Could not install built-in appliance files to {dst_path}: {e}")

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
gns3server/disks/empty8G.qcow2 Executable file

Binary file not shown.

View File

@ -26,11 +26,11 @@ import logging
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
def list_images(type): def list_images(emulator_type):
""" """
Scan directories for available image for a type Scan directories for available image for a given emulator type
:param type: emulator type (dynamips, qemu, iou) :param emulator_type: emulator type (dynamips, qemu, iou)
""" """
files = set() files = set()
images = [] images = []
@ -38,10 +38,10 @@ def list_images(type):
server_config = Config.instance().get_section_config("Server") server_config = Config.instance().get_section_config("Server")
general_images_directory = os.path.expanduser(server_config.get("images_path", "~/GNS3/images")) general_images_directory = os.path.expanduser(server_config.get("images_path", "~/GNS3/images"))
# Subfolder of the general_images_directory specific to this VM type # Subfolder of the general_images_directory specific to this emulator type
default_directory = default_images_directory(type) default_directory = default_images_directory(emulator_type)
for directory in images_directories(type): for directory in images_directories(emulator_type):
# We limit recursion to path outside the default images directory # We limit recursion to path outside the default images directory
# the reason is in the default directory manage file organization and # the reason is in the default directory manage file organization and
@ -57,9 +57,9 @@ def list_images(type):
if filename not in files: if filename not in files:
if filename.endswith(".md5sum") or filename.startswith("."): if filename.endswith(".md5sum") or filename.startswith("."):
continue continue
elif ((filename.endswith(".image") or filename.endswith(".bin")) and type == "dynamips") \ elif ((filename.endswith(".image") or filename.endswith(".bin")) and emulator_type == "dynamips") \
or ((filename.endswith(".bin") or filename.startswith("i86bi")) and type == "iou") \ or ((filename.endswith(".bin") or filename.startswith("i86bi")) and emulator_type == "iou") \
or (not filename.endswith(".bin") and not filename.endswith(".image") and type == "qemu"): or (not filename.endswith(".bin") and not filename.endswith(".image") and emulator_type == "qemu"):
files.add(filename) files.add(filename)
# It the image is located in the standard directory the path is relative # It the image is located in the standard directory the path is relative
@ -69,7 +69,7 @@ def list_images(type):
path = os.path.relpath(os.path.join(root, filename), default_directory) path = os.path.relpath(os.path.join(root, filename), default_directory)
try: try:
if type in ["dynamips", "iou"]: if emulator_type in ["dynamips", "iou"]:
with open(os.path.join(root, filename), "rb") as f: with open(os.path.join(root, filename), "rb") as f:
# read the first 7 bytes of the file. # read the first 7 bytes of the file.
elf_header_start = f.read(7) elf_header_start = f.read(7)
@ -102,34 +102,34 @@ def _os_walk(directory, recurse=True, **kwargs):
yield directory, [], files yield directory, [], files
def default_images_directory(type): def default_images_directory(emulator_type):
""" """
:returns: Return the default directory for a node type :returns: Return the default directory for a node type
""" """
server_config = Config.instance().get_section_config("Server") server_config = Config.instance().get_section_config("Server")
img_dir = os.path.expanduser(server_config.get("images_path", "~/GNS3/images")) img_dir = os.path.expanduser(server_config.get("images_path", "~/GNS3/images"))
if type == "qemu": if emulator_type == "qemu":
return os.path.join(img_dir, "QEMU") return os.path.join(img_dir, "QEMU")
elif type == "iou": elif emulator_type == "iou":
return os.path.join(img_dir, "IOU") return os.path.join(img_dir, "IOU")
elif type == "dynamips": elif emulator_type == "dynamips":
return os.path.join(img_dir, "IOS") return os.path.join(img_dir, "IOS")
else: else:
raise NotImplementedError("%s node type is not supported", type) raise NotImplementedError("%s node type is not supported", emulator_type)
def images_directories(type): def images_directories(emulator_type):
""" """
Return all directories where we will look for images Return all directories where we will look for images
by priority by priority
:param type: Type of emulator :param emulator_type: Type of emulator
""" """
server_config = Config.instance().get_section_config("Server") server_config = Config.instance().get_section_config("Server")
paths = [] paths = []
img_dir = os.path.expanduser(server_config.get("images_path", "~/GNS3/images")) img_dir = os.path.expanduser(server_config.get("images_path", "~/GNS3/images"))
type_img_directory = default_images_directory(type) type_img_directory = default_images_directory(emulator_type)
try: try:
os.makedirs(type_img_directory, exist_ok=True) os.makedirs(type_img_directory, exist_ok=True)
paths.append(type_img_directory) paths.append(type_img_directory)

View File

@ -395,6 +395,31 @@ async def test_install_base_configs(controller, config, tmpdir):
assert f.read() == 'test' assert f.read() == 'test'
@pytest.mark.parametrize(
"builtin_disk",
[
"empty8G.qcow2",
"empty10G.qcow2",
"empty20G.qcow2",
"empty30G.qcow2",
"empty40G.qcow2",
"empty50G.qcow2",
"empty100G.qcow2",
"empty150G.qcow2",
"empty200G.qcow2",
"empty250G.qcow2",
"empty500G.qcow2",
"empty1T.qcow2"
]
)
async def test_install_builtin_disks(controller, config, tmpdir, builtin_disk):
config.set_section_config("Server", {"images_path": str(tmpdir)})
controller._install_builtin_disks()
# we only install Qemu empty disks at this time
assert os.path.exists(str(tmpdir / "QEMU" / builtin_disk))
def test_appliances(controller, tmpdir): def test_appliances(controller, tmpdir):
my_appliance = { my_appliance = {