Support user defined loader/libraries to run IOU

This commit is contained in:
grossmj 2022-07-16 11:38:51 +02:00
parent 5b478fc331
commit f5e1956dfa
2 changed files with 44 additions and 9 deletions

View File

@ -84,6 +84,8 @@ class IOUVM(BaseNode):
self._started = False
self._nvram_watcher = None
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
# IOU settings
@ -143,6 +145,7 @@ class IOUVM(BaseNode):
"""
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}"')
@property
@ -174,9 +177,10 @@ class IOUVM(BaseNode):
Finds the default RAM and NVRAM values for the IOU image.
"""
await self._check_requirements()
try:
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)
if match:
@ -191,11 +195,13 @@ class IOUVM(BaseNode):
await self.update_default_iou_values()
def _check_requirements(self):
async def _check_requirements(self):
"""
Checks the IOU image.
"""
if self._loader is not None:
return # image already checked
if not self._path:
raise IOUError("IOU image is not configured")
if not os.path.isfile(self._path) or not os.path.exists(self._path):
@ -219,6 +225,28 @@ class IOUVM(BaseNode):
if not os.access(self._path, os.X_OK):
raise IOUError(f"IOU image '{self._path}' is not executable")
# set loader command
if elf_header_start[4] == b"\x01":
# 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):
iou_vm_info = {
@ -385,8 +413,10 @@ class IOUVM(BaseNode):
Checks for missing shared library dependencies in the IOU image.
"""
env = os.environ.copy()
env["LD_TRACE_LOADED_OBJECTS"] = "1"
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:
log.warning(f"Could not determine the shared library dependencies for {self._path}: {e}")
return
@ -513,7 +543,7 @@ class IOUVM(BaseNode):
Starts the IOU process.
"""
self._check_requirements()
await self._check_requirements()
if not self.is_running():
await self._library_check()
@ -560,10 +590,13 @@ class IOUVM(BaseNode):
command = await self._build_command()
try:
log.info(f"Starting IOU: {command}")
if self._loader:
log.info(f"Starting IOU: {command} with loader {self._loader}")
else:
log.info(f"Starting IOU: {command}")
self.command_line = " ".join(command)
self._iou_process = await asyncio.create_subprocess_exec(
*command,
*self._loader, *command,
stdout=asyncio.subprocess.PIPE,
stdin=asyncio.subprocess.PIPE,
stderr=subprocess.STDOUT,
@ -1125,7 +1158,7 @@ class IOUVM(BaseNode):
env["IOURC"] = self.iourc_path
try:
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):
command.extend(["-l"])

View File

@ -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)
config.settings.IOU.iourc_path = iourc_file
vm.path = "iou.bin"
vm._loader = []
return vm
@ -228,7 +229,8 @@ def test_path_relative(vm, 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)
path = str(tmpdir / "test.bin")
@ -238,7 +240,7 @@ def test_path_invalid_bin(vm, tmpdir, config):
with pytest.raises(IOUError):
vm.path = path
vm._check_requirements()
await vm._check_requirements()
def test_create_netmap_config(vm):