mirror of
https://github.com/GNS3/gns3-server
synced 2024-11-28 19:28:07 +00:00
Merge pull request #2086 from GNS3/iou-user-loader-libraries
Support user defined loader/libraries to run IOU
This commit is contained in:
commit
d08a052f94
@ -88,6 +88,8 @@ class IOUVM(BaseNode):
|
|||||||
self._started = False
|
self._started = False
|
||||||
self._nvram_watcher = None
|
self._nvram_watcher = None
|
||||||
self._path = self.manager.get_abs_image_path(path, project.path)
|
self._path = self.manager.get_abs_image_path(path, project.path)
|
||||||
|
self._lib_base = self.manager.get_images_directory()
|
||||||
|
self._loader = None
|
||||||
self._license_check = True
|
self._license_check = True
|
||||||
|
|
||||||
# IOU settings
|
# IOU settings
|
||||||
@ -147,6 +149,7 @@ class IOUVM(BaseNode):
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
self._path = self.manager.get_abs_image_path(path, self.project.path)
|
self._path = self.manager.get_abs_image_path(path, self.project.path)
|
||||||
|
self._loader = None
|
||||||
log.info(f'IOU "{self._name}" [{self._id}]: IOU image updated to "{self._path}"')
|
log.info(f'IOU "{self._name}" [{self._id}]: IOU image updated to "{self._path}"')
|
||||||
|
|
||||||
@property
|
@property
|
||||||
@ -178,9 +181,10 @@ class IOUVM(BaseNode):
|
|||||||
Finds the default RAM and NVRAM values for the IOU image.
|
Finds the default RAM and NVRAM values for the IOU image.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
await self._check_requirements()
|
||||||
try:
|
try:
|
||||||
output = await gns3server.utils.asyncio.subprocess_check_output(
|
output = await gns3server.utils.asyncio.subprocess_check_output(
|
||||||
self._path, "-h", cwd=self.working_dir, stderr=True
|
*self._loader, self._path, "-h", cwd=self.working_dir, stderr=True
|
||||||
)
|
)
|
||||||
match = re.search(r"-n <n>\s+Size of nvram in Kb \(default ([0-9]+)KB\)", output)
|
match = re.search(r"-n <n>\s+Size of nvram in Kb \(default ([0-9]+)KB\)", output)
|
||||||
if match:
|
if match:
|
||||||
@ -195,11 +199,13 @@ class IOUVM(BaseNode):
|
|||||||
|
|
||||||
await self.update_default_iou_values()
|
await self.update_default_iou_values()
|
||||||
|
|
||||||
def _check_requirements(self):
|
async def _check_requirements(self):
|
||||||
"""
|
"""
|
||||||
Checks the IOU image.
|
Checks the IOU image.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
if self._loader is not None:
|
||||||
|
return # image already checked
|
||||||
if not self._path:
|
if not self._path:
|
||||||
raise IOUError("IOU image is not configured")
|
raise IOUError("IOU image is not configured")
|
||||||
if not os.path.isfile(self._path) or not os.path.exists(self._path):
|
if not os.path.isfile(self._path) or not os.path.exists(self._path):
|
||||||
@ -223,6 +229,28 @@ class IOUVM(BaseNode):
|
|||||||
if not os.access(self._path, os.X_OK):
|
if not os.access(self._path, os.X_OK):
|
||||||
raise IOUError(f"IOU image '{self._path}' is not executable")
|
raise IOUError(f"IOU image '{self._path}' is not executable")
|
||||||
|
|
||||||
|
# set loader command
|
||||||
|
if elf_header_start[4] == 1:
|
||||||
|
# 32-bit loader
|
||||||
|
loader = os.path.join(self._lib_base, "lib", "ld-linux.so.2")
|
||||||
|
lib_path = (os.path.join(self._lib_base, "lib"),
|
||||||
|
os.path.join(self._lib_base, "lib", "i386-linux-gnu"))
|
||||||
|
else:
|
||||||
|
# 64-bit loader
|
||||||
|
loader = os.path.join(self._lib_base, "lib64", "ld-linux-x86-64.so.2")
|
||||||
|
lib_path = (os.path.join(self._lib_base, "lib64"),
|
||||||
|
os.path.join(self._lib_base, "lib", "x86_64-linux-gnu"))
|
||||||
|
self._loader = []
|
||||||
|
if os.path.isfile(loader):
|
||||||
|
try:
|
||||||
|
proc = await asyncio.create_subprocess_exec(loader, "--verify", self._path)
|
||||||
|
if await proc.wait() == 0:
|
||||||
|
self._loader = [loader, "--library-path", ":".join(lib_path)]
|
||||||
|
else:
|
||||||
|
log.warning(f"Loader {loader} incompatible with '{self._path}'")
|
||||||
|
except (OSError, subprocess.SubprocessError) as e:
|
||||||
|
log.warning(f"Could not use loader {loader}: {e}")
|
||||||
|
|
||||||
def asdict(self):
|
def asdict(self):
|
||||||
|
|
||||||
iou_vm_info = {
|
iou_vm_info = {
|
||||||
@ -391,8 +419,10 @@ class IOUVM(BaseNode):
|
|||||||
Checks for missing shared library dependencies in the IOU image.
|
Checks for missing shared library dependencies in the IOU image.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
env = os.environ.copy()
|
||||||
|
env["LD_TRACE_LOADED_OBJECTS"] = "1"
|
||||||
try:
|
try:
|
||||||
output = await gns3server.utils.asyncio.subprocess_check_output("ldd", self._path)
|
output = await gns3server.utils.asyncio.subprocess_check_output(*self._loader, self._path, env=env)
|
||||||
except (OSError, subprocess.SubprocessError) as e:
|
except (OSError, subprocess.SubprocessError) as e:
|
||||||
log.warning(f"Could not determine the shared library dependencies for {self._path}: {e}")
|
log.warning(f"Could not determine the shared library dependencies for {self._path}: {e}")
|
||||||
return
|
return
|
||||||
@ -519,7 +549,7 @@ class IOUVM(BaseNode):
|
|||||||
Starts the IOU process.
|
Starts the IOU process.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
self._check_requirements()
|
await self._check_requirements()
|
||||||
if not self.is_running():
|
if not self.is_running():
|
||||||
|
|
||||||
await self._library_check()
|
await self._library_check()
|
||||||
@ -566,10 +596,13 @@ class IOUVM(BaseNode):
|
|||||||
|
|
||||||
command = await self._build_command()
|
command = await self._build_command()
|
||||||
try:
|
try:
|
||||||
|
if self._loader:
|
||||||
|
log.info(f"Starting IOU: {command} with loader {self._loader}")
|
||||||
|
else:
|
||||||
log.info(f"Starting IOU: {command}")
|
log.info(f"Starting IOU: {command}")
|
||||||
self.command_line = " ".join(command)
|
self.command_line = " ".join(command)
|
||||||
self._iou_process = await asyncio.create_subprocess_exec(
|
self._iou_process = await asyncio.create_subprocess_exec(
|
||||||
*command,
|
*self._loader, *command,
|
||||||
stdout=asyncio.subprocess.PIPE,
|
stdout=asyncio.subprocess.PIPE,
|
||||||
stdin=asyncio.subprocess.PIPE,
|
stdin=asyncio.subprocess.PIPE,
|
||||||
stderr=subprocess.STDOUT,
|
stderr=subprocess.STDOUT,
|
||||||
@ -1131,7 +1164,7 @@ class IOUVM(BaseNode):
|
|||||||
env["IOURC"] = self.iourc_path
|
env["IOURC"] = self.iourc_path
|
||||||
try:
|
try:
|
||||||
output = await gns3server.utils.asyncio.subprocess_check_output(
|
output = await gns3server.utils.asyncio.subprocess_check_output(
|
||||||
self._path, "-h", cwd=self.working_dir, env=env, stderr=True
|
*self._loader, self._path, "-h", cwd=self.working_dir, env=env, stderr=True
|
||||||
)
|
)
|
||||||
if re.search(r"-l\s+Enable Layer 1 keepalive messages", output):
|
if re.search(r"-l\s+Enable Layer 1 keepalive messages", output):
|
||||||
command.extend(["-l"])
|
command.extend(["-l"])
|
||||||
|
@ -91,7 +91,8 @@ async def get_computes(app: FastAPI) -> List[dict]:
|
|||||||
def image_filter(change: Change, path: str) -> bool:
|
def image_filter(change: Change, path: str) -> bool:
|
||||||
|
|
||||||
if change == Change.added and os.path.isfile(path):
|
if change == Change.added and os.path.isfile(path):
|
||||||
if path.endswith(".tmp") or path.endswith(".md5sum") or path.startswith("."):
|
if path.endswith(".tmp") or path.endswith(".md5sum") or path.startswith(".") or \
|
||||||
|
"/lib/" in path or "/lib64/" in path:
|
||||||
return False
|
return False
|
||||||
header_magic_len = 7
|
header_magic_len = 7
|
||||||
with open(path, "rb") as f:
|
with open(path, "rb") as f:
|
||||||
|
@ -48,6 +48,7 @@ async def vm(compute_project, manager, config, tmpdir, fake_iou_bin, iourc_file)
|
|||||||
vm = IOUVM("test", str(uuid.uuid4()), compute_project, manager, application_id=1)
|
vm = IOUVM("test", str(uuid.uuid4()), compute_project, manager, application_id=1)
|
||||||
config.settings.IOU.iourc_path = iourc_file
|
config.settings.IOU.iourc_path = iourc_file
|
||||||
vm.path = "iou.bin"
|
vm.path = "iou.bin"
|
||||||
|
vm._loader = []
|
||||||
return vm
|
return vm
|
||||||
|
|
||||||
|
|
||||||
@ -228,7 +229,8 @@ def test_path_relative(vm, fake_iou_bin):
|
|||||||
assert vm.path == fake_iou_bin
|
assert vm.path == fake_iou_bin
|
||||||
|
|
||||||
|
|
||||||
def test_path_invalid_bin(vm, tmpdir, config):
|
@pytest.mark.asyncio
|
||||||
|
async def test_path_invalid_bin(vm, tmpdir, config):
|
||||||
|
|
||||||
config.settings.Server.images_path = str(tmpdir)
|
config.settings.Server.images_path = str(tmpdir)
|
||||||
path = str(tmpdir / "test.bin")
|
path = str(tmpdir / "test.bin")
|
||||||
@ -238,7 +240,7 @@ def test_path_invalid_bin(vm, tmpdir, config):
|
|||||||
|
|
||||||
with pytest.raises(IOUError):
|
with pytest.raises(IOUError):
|
||||||
vm.path = path
|
vm.path = path
|
||||||
vm._check_requirements()
|
await vm._check_requirements()
|
||||||
|
|
||||||
|
|
||||||
def test_create_netmap_config(vm):
|
def test_create_netmap_config(vm):
|
||||||
|
Loading…
Reference in New Issue
Block a user