library: add meili dep (#2945)

* add meili dep support

* small fix

* let default
This commit is contained in:
Stavros Kois
2025-08-13 13:14:52 +03:00
committed by GitHub
parent 288b80df1d
commit 25518b9ae7
68 changed files with 171 additions and 6 deletions

View File

@@ -4,17 +4,19 @@ if TYPE_CHECKING:
from render import Render
try:
from .deps_postgres import PostgresContainer, PostgresConfig
from .deps_redis import RedisContainer, RedisConfig
from .deps_mariadb import MariadbContainer, MariadbConfig
from .deps_meilisearch import MeilisearchContainer, MeiliConfig
from .deps_mongodb import MongoDBContainer, MongoDBConfig
from .deps_perms import PermsContainer
from .deps_postgres import PostgresContainer, PostgresConfig
from .deps_redis import RedisContainer, RedisConfig
except ImportError:
from deps_postgres import PostgresContainer, PostgresConfig
from deps_redis import RedisContainer, RedisConfig
from deps_mariadb import MariadbContainer, MariadbConfig
from deps_meilisearch import MeilisearchContainer, MeiliConfig
from deps_mongodb import MongoDBContainer, MongoDBConfig
from deps_perms import PermsContainer
from deps_postgres import PostgresContainer, PostgresConfig
from deps_redis import RedisContainer, RedisConfig
class Deps:
@@ -35,3 +37,6 @@ class Deps:
def mongodb(self, name: str, image: str, config: MongoDBConfig, perms_instance: PermsContainer):
return MongoDBContainer(self._render_instance, name, image, config, perms_instance)
def meilisearch(self, name: str, image: str, config: MeiliConfig, perms_instance: PermsContainer):
return MeilisearchContainer(self._render_instance, name, image, config, perms_instance)

View File

@@ -0,0 +1,85 @@
from typing import TYPE_CHECKING, TypedDict, NotRequired
if TYPE_CHECKING:
from render import Render
from storage import IxStorage
try:
from .error import RenderError
from .deps_perms import PermsContainer
except ImportError:
from error import RenderError
from deps_perms import PermsContainer
class MeiliConfig(TypedDict):
master_key: str
port: NotRequired[int]
volume: "IxStorage"
class MeilisearchContainer:
def __init__(
self, render_instance: "Render", name: str, image: str, config: MeiliConfig, perms_instance: PermsContainer
):
self._render_instance = render_instance
self._name = name
self._config = config
self._data_dir = "/meili_data"
for key in ("master_key", "volume"):
if key not in config:
raise RenderError(f"Expected [{key}] to be set for meilisearch")
c = self._render_instance.add_container(name, image)
user, group = 568, 568
run_as = self._render_instance.values.get("run_as")
if run_as:
user = run_as["user"] or user # Avoids running as root
group = run_as["group"] or group # Avoids running as root
c.set_user(user, group)
c.healthcheck.set_test("curl", {"port": self._get_port(), "path": "/health"})
c.remove_devices()
c.add_storage(self._data_dir, config["volume"])
c.environment.add_env("MEILI_HTTP_ADDR", f"0.0.0.0:{self._get_port()}")
c.environment.add_env("MEILI_NO_ANALYTICS", True)
c.environment.add_env("MEILI_EXPERIMENTAL_DUMPLESS_UPGRADE", True)
c.environment.add_env("MEILI_MASTER_KEY", config["master_key"])
perms_instance.add_or_skip_action(
f"{self._name}_meili_data", config["volume"], {"uid": user, "gid": group, "mode": "check"}
)
self._get_repo(image, ("getmeili/meilisearch",))
# Store container for further configuration
# For example: c.depends.add_dependency("other_container", "service_started")
self._container = c
@property
def container(self):
return self._container
def _get_port(self):
return self._config.get("port") or 7700
def _get_repo(self, image, supported_repos):
images = self._render_instance.values["images"]
if image not in images:
raise RenderError(f"Image [{image}] not found in values. Available images: [{', '.join(images.keys())}]")
repo = images[image].get("repository")
if not repo:
raise RenderError("Could not determine repo")
if repo not in supported_repos:
raise RenderError(
f"Unsupported repo [{repo}] for meilisearch. Supported repos: {', '.join(supported_repos)}"
)
return repo
def get_url(self):
return f"http://{self._name}:{self._get_port()}"

View File

@@ -39,7 +39,7 @@ class RedisContainer:
self._get_repo(image, ("redis", "valkey/valkey"))
user, group = 568, 568
run_as = render_instance.values.get("run_as")
run_as = self._render_instance.values.get("run_as")
if run_as:
user = run_as["user"] or user # Avoids running as root
group = run_as["group"] or group # Avoids running as root

View File

@@ -615,3 +615,78 @@ def test_add_mongodb_unsupported_repo(mock_values):
},
perms_container,
)
def test_add_meilisearch(mock_values):
mock_values["images"]["meili_image"] = {"repository": "getmeili/meilisearch", "tag": "v1.17.0"}
render = Render(mock_values)
c1 = render.add_container("test_container", "test_image")
c1.healthcheck.disable()
perms_container = render.deps.perms("perms_container")
m = render.deps.meilisearch(
"meili_container",
"meili_image",
{
"master_key": "test_master_key",
"volume": {"type": "volume", "volume_config": {"volume_name": "test_volume", "auto_permissions": True}},
},
perms_container,
)
if perms_container.has_actions():
perms_container.activate()
m.container.depends.add_dependency("perms_container", "service_completed_successfully")
output = render.render()
assert "devices" not in output["services"]["meili_container"]
assert "reservations" not in output["services"]["meili_container"]["deploy"]["resources"]
assert output["services"]["meili_container"]["image"] == "getmeili/meilisearch:v1.17.0"
assert output["services"]["meili_container"]["user"] == "568:568"
assert output["services"]["meili_container"]["deploy"]["resources"]["limits"]["cpus"] == "2.0"
assert output["services"]["meili_container"]["deploy"]["resources"]["limits"]["memory"] == "4096M"
assert output["services"]["meili_container"]["healthcheck"] == {
"test": "curl --request GET --silent --output /dev/null --show-error --fail http://127.0.0.1:7700/health",
"interval": "30s",
"timeout": "5s",
"retries": 5,
"start_period": "15s",
"start_interval": "2s",
}
assert output["services"]["meili_container"]["volumes"] == [
{
"type": "volume",
"source": "test_volume",
"target": "/meili_data",
"read_only": False,
"volume": {"nocopy": False},
}
]
assert output["services"]["meili_container"]["environment"] == {
"TZ": "Etc/UTC",
"UMASK": "002",
"UMASK_SET": "002",
"NVIDIA_VISIBLE_DEVICES": "void",
"MEILI_MASTER_KEY": "test_master_key",
"MEILI_HTTP_ADDR": "0.0.0.0:7700",
"MEILI_NO_ANALYTICS": "true",
"MEILI_EXPERIMENTAL_DUMPLESS_UPGRADE": "true",
}
assert output["services"]["meili_container"]["depends_on"] == {
"perms_container": {"condition": "service_completed_successfully"}
}
def test_add_meilisearch_unsupported_repo(mock_values):
mock_values["images"]["meili_image"] = {"repository": "unsupported_repo", "tag": "7"}
render = Render(mock_values)
c1 = render.add_container("test_container", "test_image")
c1.healthcheck.disable()
perms_container = render.deps.perms("perms_container")
with pytest.raises(Exception):
render.deps.meilisearch(
"meili_container",
"meili_image",
{
"master_key": "test_master_key",
"volume": {"type": "volume", "volume_config": {"volume_name": "test_volume", "auto_permissions": True}},
},
perms_container,
)

View File

@@ -1,2 +1,2 @@
0.0.1: f074617a82a86d2a6cc78a4c8a4296fc9d168e456f12713e50c696557b302133
2.1.45: 2b78b1918738cd8bbb292da9a3f5060f5122e085fa34559c5ae748ead981cff4
2.1.46: 464cacce9ffec31b1819cd064a4d1099af6d232cb3d870da847a885e00ed12ce