Skip to content

Commit

Permalink
Merge pull request #1132 from sosy-lab/use-podman-container-when-gett…
Browse files Browse the repository at this point in the history
…ing-version

Add feature to use podman container when determining version for vcloud-benchmark
  • Loading branch information
dbeyer authored Dec 12, 2024
2 parents d8deb6a + 195dada commit f28d99c
Show file tree
Hide file tree
Showing 5 changed files with 308 additions and 17 deletions.
23 changes: 13 additions & 10 deletions benchexec/containerized_tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@
util,
)


tool: tooladapter.CURRENT_BASETOOL = None


Expand Down Expand Up @@ -55,19 +54,23 @@ def __init__(self, tool_module, config):
# We use multiprocessing.Pool as an easy way for RPC with another process.
self._pool = multiprocessing.Pool(1, _init_worker_process)

# Call function that loads tool module and returns its doc
try:
self._setup_container(tool_module, config)
except BaseException as e:
self._pool.terminate()
raise e

def _setup_container(self, tool_module, config):
container_options = containerexecutor.handle_basic_container_args(config)
temp_dir = tempfile.mkdtemp(prefix="Benchexec_tool_info_container_")

# Call function that loads tool module and returns its doc
try:
self.__doc__ = self._pool.apply(
self.__doc__, _ = self._pool.apply(
_init_container_and_load_tool,
[tool_module, temp_dir],
[_init_container, tool_module, temp_dir],
container_options,
)
except BaseException as e:
self._pool.terminate()
raise e
finally:
# Outside the container, the temp_dir is just an empty directory, because
# the tmpfs mount is only visible inside. We can remove it immediately.
Expand Down Expand Up @@ -125,15 +128,15 @@ def _init_worker_process():
signal.signal(signal.SIGINT, signal.SIG_IGN)


def _init_container_and_load_tool(tool_module, *args, **kwargs):
def _init_container_and_load_tool(initializer, tool_module, *args, **kwargs):
"""Initialize container for the current process and load given tool-info module."""
try:
_init_container(*args, **kwargs)
initializer_ret = initializer(*args, **kwargs)
except OSError as e:
if container.check_apparmor_userns_restriction(e):
raise BenchExecException(container._ERROR_MSG_USER_NS_RESTRICTION)
raise BenchExecException(f"Failed to configure container: {e}")
return _load_tool(tool_module)
return _load_tool(tool_module), initializer_ret


def _init_container(
Expand Down
4 changes: 4 additions & 0 deletions benchexec/libc.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ def _check_errno(result, func, arguments):
unshare.argtypes = [c_int]
unshare.errcheck = _check_errno

setns = _libc.setns
"""Set the current process namespace(s)."""
setns.argtypes = [c_int, c_int]
setns.errcheck = _check_errno

mmap = _libc.mmap
"""Map file into memory."""
Expand Down
54 changes: 51 additions & 3 deletions contrib/vcloud-benchmark.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,25 +9,29 @@

import logging
import os
import subprocess
import sys
import tempfile
import urllib.request
import subprocess

sys.dont_write_bytecode = True # prevent creation of .pyc files
sys.path.insert(0, os.path.join(os.path.dirname(__file__), ".."))

from vcloud.vcloudbenchmarkbase import VcloudBenchmarkBase # noqa E402
from vcloud import vcloudutil # noqa E402
from benchexec import __version__ # noqa E402
from vcloud.vcloudbenchmarkbase import VcloudBenchmarkBase # noqa E402

import benchexec.benchexec # noqa E402
import benchexec.model # noqa E402
import benchexec.tools # noqa E402
from benchexec import BenchExecException, __version__ # noqa E402

_ROOT_DIR = os.path.abspath(os.path.join(os.path.dirname(__file__), "vcloud"))
IVY_JAR_NAME = "ivy-2.5.0.jar"
IVY_PATH = os.path.join(_ROOT_DIR, "lib", IVY_JAR_NAME)
IVY_DOWNLOAD_URL = "https://www.sosy-lab.org/ivy/org.apache.ivy/ivy/" + IVY_JAR_NAME

original_load_tool_info = benchexec.model.load_tool_info


def download_required_jars(config):
# download ivy if needed
Expand Down Expand Up @@ -71,6 +75,50 @@ def download_required_jars(config):
temp_dir.cleanup()


def hook_load_tool_info(tool_name, config):
"""
Load the tool-info class.
@param tool_name: The name of the tool-info module.
Either a full Python package name or a name within the benchexec.tools package.
@return: A tuple of the full name of the used tool-info module and an instance of the tool-info class.
"""
if not config.containerImage:
return original_load_tool_info(tool_name, config)

if not config.tool_directory:
raise BenchExecException(
"Using a container image is currently only supported "
"if the tool directory is explicitly provided. Please set it "
"using the --tool-directory option."
)

tool_module = tool_name if "." in tool_name else f"benchexec.tools.{tool_name}"

try:
import vcloud.podman_containerized_tool as pod

tool = pod.PodmanContainerizedTool(tool_module, config, config.containerImage)

except ImportError as ie:
logging.debug(
"Did not find module '%s'. "
"Python probably looked for it in one of the following paths:\n %s",
tool_module,
"\n ".join(path or "." for path in sys.path),
)
sys.exit(f'Unsupported tool "{tool_name}" specified. ImportError: {ie}')
except AttributeError as ae:
sys.exit(
f'Unsupported tool "{tool_name}" specified, class "Tool" is missing: {ae}'
)
except TypeError as te:
sys.exit(f'Unsupported tool "{tool_name}" specified. TypeError: {te}')
return tool_module, tool


benchexec.model.load_tool_info = hook_load_tool_info


class VcloudBenchmark(VcloudBenchmarkBase):
"""
Benchmark class that defines the load_executor function.
Expand Down
56 changes: 52 additions & 4 deletions contrib/vcloud/benchmarkclient_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,11 @@
import shutil
import subprocess
import sys
from pathlib import Path

import benchexec.tooladapter
import benchexec.util
from benchexec import BenchExecException
from benchexec.tooladapter import CURRENT_BASETOOL, create_tool_locator

from . import vcloudutil

Expand All @@ -38,9 +40,55 @@ def set_vcloud_jar_path(p):
def init(config, benchmark):
global _JustReprocessResults
_JustReprocessResults = config.reprocessResults
tool_locator = benchexec.tooladapter.create_tool_locator(config)
benchmark.executable = benchmark.tool.executable(tool_locator)
benchmark.tool_version = benchmark.tool.version(benchmark.executable)

if config.containerImage:
from vcloud.podman_containerized_tool import TOOL_DIRECTORY_MOUNT_POINT

tool_locator = CURRENT_BASETOOL.ToolLocator(
tool_directory=TOOL_DIRECTORY_MOUNT_POINT
)
executable_for_version = benchmark.tool.executable(tool_locator)
benchmark.tool_version = benchmark.tool.version(executable_for_version)

executable_for_version = Path(executable_for_version)

# ensure executable_for_version is relative
if executable_for_version.is_absolute():
try:
executable_for_version = executable_for_version.relative_to(
TOOL_DIRECTORY_MOUNT_POINT
)
except ValueError as e:
raise BenchExecException(
f"Executable path {executable_for_version} is not relative"
" and is not containing the expected mount point in the container"
" {TOOL_DIRECTORY_MOUNT_POINT}."
) from e

# ensure that executable_for_version is not pointing to a directory
# outside of the tool directory

executable_for_cloud = Path(config.tool_directory) / executable_for_version

# Paths must be resolved to properly detect when the executable would
# escape the tool dir with '..'
if not executable_for_cloud.resolve().is_relative_to(
Path(config.tool_directory).resolve()
):
raise BenchExecException(
f"Executable path {executable_for_cloud} is not within the tool directory"
f" {config.tool_directory}."
)

# The vcloud uses the tool location later to determine which files need to be uploaded
# So this needs to point to the actual path where the executable is on the host
benchmark.executable = str(executable_for_cloud)

else:
tool_locator = create_tool_locator(config)
benchmark.executable = benchmark.tool.executable(tool_locator)
benchmark.tool_version = benchmark.tool.version(benchmark.executable)

environment = benchmark.environment()
if environment.get("keepEnv", None) or environment.get("additionalEnv", None):
sys.exit(
Expand Down
Loading

0 comments on commit f28d99c

Please sign in to comment.