-
Notifications
You must be signed in to change notification settings - Fork 32
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Adding support (and docs) of running LNST controller in podman/docker container.
- Loading branch information
Showing
6 changed files
with
284 additions
and
6 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
# syntax=docker/dockerfile:1 | ||
FROM fedora:41 | ||
|
||
RUN dnf install -y initscripts \ | ||
iputils \ | ||
python3.9 \ | ||
python-pip \ | ||
gcc \ | ||
python-devel \ | ||
libxml2-devel \ | ||
libxslt-devel \ | ||
libnl3 \ | ||
lksctp-tools-devel \ | ||
git \ | ||
libnl3-devel && \ | ||
curl -sSL https://install.python-poetry.org | \ | ||
python3 - --version 1.8.3 | ||
|
||
RUN mkdir -p /root/.lnst | ||
COPY . /lnst | ||
COPY container_files/controller/pool /root/.lnst/pool | ||
|
||
RUN cd /lnst && \ | ||
/root/.local/bin/poetry config virtualenvs.path /root/lnst_venv && \ | ||
/root/.local/bin/poetry config virtualenvs.in-project false && \ | ||
/root/.local/bin/poetry install | ||
# setting in-project to false to prevent poetry from | ||
# using in-project .venv which might be present if | ||
# user has mounted host-machine's lnst dir to /lnst | ||
|
||
WORKDIR /lnst | ||
CMD ["/lnst/container_files/controller/entrypoint.sh"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
import os | ||
import sys | ||
import traceback | ||
from typing import Any, Type, Optional | ||
|
||
from lnst.Recipes.ENRT import * | ||
from lnst.Controller.Recipe import BaseRecipe | ||
from lnst.Controller.Controller import Controller | ||
from lnst.Controller.RecipeResults import ResultLevel, ResultType | ||
from lnst.Controller.MachineMapper import ContainerMapper | ||
from lnst.Controller.ContainerPoolManager import ContainerPoolManager | ||
|
||
from lnst.Controller.RunSummaryFormatters import * | ||
from lnst.Controller.RunSummaryFormatters.RunSummaryFormatter import RunSummaryFormatter | ||
|
||
|
||
class ContainerRunner: | ||
"""This class is responsible for running the LNST controller in a container. | ||
Environment variables: | ||
* DEBUG: Set to 1 to enable debug mode | ||
* RECIPE: Name of the recipe class to run | ||
* RECIPE_PARAMS: Parameters to pass to the recipe class | ||
* FORMATTERS: List of formatters to use | ||
* MULTIMATCH: Set to 1 to enable multimatch mode | ||
Agents in containers-specific environment variables: | ||
* PODMAN_URI: URI of the Podman socket | ||
* IMAGE_NAME: Name of the container image | ||
""" | ||
|
||
def __init__(self) -> None: | ||
self._controller = Controller(**self._parse_controller_params()) | ||
self._recipe_params: dict[str, Any] = self._parse_recipe_params() | ||
|
||
if not os.getenv("RECIPE"): | ||
raise ValueError("RECIPE environment variable is not set") | ||
self._recipe_cls: Type[BaseRecipe] = eval(os.getenv("RECIPE", "")) | ||
self._recipe: Optional[BaseRecipe] = None | ||
|
||
self._formatters: list[Type[RunSummaryFormatter]] = self._parse_formatters() | ||
|
||
def _parse_controller_params(self) -> dict: | ||
params = { | ||
"debug": bool(os.getenv("DEBUG", 0)), | ||
} | ||
|
||
if "PODMAN_URI" in os.environ: | ||
return params | { | ||
"podman_uri": os.getenv("PODMAN_URI"), | ||
"image": os.getenv("IMAGE_NAME", "lnst"), | ||
"network_plugin": "cni", | ||
"poolMgr": ContainerPoolManager, | ||
"mapper": ContainerMapper, | ||
} | ||
|
||
return params | ||
|
||
def _parse_recipe_params(self) -> dict[str, Any]: | ||
params = {} | ||
for param in os.getenv("RECIPE_PARAMS", "").split(";"): | ||
if not param: | ||
continue | ||
key, value = param.split("=") | ||
params[key] = eval(value) | ||
|
||
return params | ||
|
||
def _parse_formatters(self) -> list[Type[RunSummaryFormatter]]: | ||
return [ | ||
eval(formatter) | ||
for formatter in os.getenv("FORMATTERS", "").split(";") | ||
if formatter | ||
] | ||
|
||
def run(self) -> ResultType: | ||
"""Initialize recipe class with parameters provided in `RECIPE_PARAMS` | ||
and execute. Function returns overall result. | ||
""" | ||
overall_result = ResultType.PASS | ||
|
||
try: | ||
self._recipe = self._recipe_cls(**self._recipe_params) | ||
self._controller.run( | ||
self._recipe, multimatch=bool(os.getenv("MULTIMATCH", False)) | ||
) | ||
except Exception: | ||
print("LNST Controller crashed with an exception:", file=sys.stderr) | ||
traceback.print_exc(file=sys.stderr) | ||
exit(ResultType.FAIL) | ||
|
||
for formatter in self._formatters: | ||
fmt = formatter(level=ResultLevel.IMPORTANT) | ||
for run in self._recipe.runs: | ||
print(fmt.format_run(run)) | ||
overall_result = ResultType.max_severity( | ||
overall_result, run.overall_result | ||
) | ||
|
||
return overall_result | ||
|
||
|
||
if __name__ == "__main__": | ||
runner = ContainerRunner() | ||
exit_code = 0 if runner.run() == ResultType.PASS else 1 | ||
exit(exit_code) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
#!/bin/sh | ||
PYTHON_PATH=$(/root/.local/bin/poetry env info -p)/bin/python | ||
exec "$PYTHON_PATH" /lnst/container_files/controller/container_runner.py |
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters