deps_redis.py 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. import urllib.parse
  2. from typing import TYPE_CHECKING, TypedDict, NotRequired
  3. if TYPE_CHECKING:
  4. from render import Render
  5. from storage import IxStorage
  6. try:
  7. from .error import RenderError
  8. from .deps_perms import PermsContainer
  9. from .validations import valid_port_or_raise, valid_redis_password_or_raise
  10. except ImportError:
  11. from error import RenderError
  12. from deps_perms import PermsContainer
  13. from validations import valid_port_or_raise, valid_redis_password_or_raise
  14. class RedisConfig(TypedDict):
  15. password: str
  16. port: NotRequired[int]
  17. volume: "IxStorage"
  18. class RedisContainer:
  19. def __init__(
  20. self, render_instance: "Render", name: str, image: str, config: RedisConfig, perms_instance: PermsContainer
  21. ):
  22. self._render_instance = render_instance
  23. self._name = name
  24. self._config = config
  25. for key in ("password", "volume"):
  26. if key not in config:
  27. raise RenderError(f"Expected [{key}] to be set for redis")
  28. valid_redis_password_or_raise(config["password"])
  29. port = valid_port_or_raise(self.get_port())
  30. self._get_repo(image, ("redis", "valkey/valkey"))
  31. user, group = 568, 568
  32. run_as = self._render_instance.values.get("run_as")
  33. if run_as:
  34. user = run_as["user"] or user # Avoids running as root
  35. group = run_as["group"] or group # Avoids running as root
  36. c = self._render_instance.add_container(name, image)
  37. c.set_user(user, group)
  38. c.remove_devices()
  39. c.healthcheck.set_test("redis", {"password": config["password"]})
  40. cmd = []
  41. cmd.extend(["--port", str(port)])
  42. cmd.extend(["--requirepass", config["password"]])
  43. c.environment.add_env("REDIS_PASSWORD", config["password"])
  44. c.set_command(cmd)
  45. c.add_storage("/data", config["volume"])
  46. perms_instance.add_or_skip_action(
  47. f"{self._name}_redis_data", config["volume"], {"uid": user, "gid": group, "mode": "check"}
  48. )
  49. # Store container for further configuration
  50. # For example: c.depends.add_dependency("other_container", "service_started")
  51. self._container = c
  52. def _get_repo(self, image, supported_repos):
  53. images = self._render_instance.values["images"]
  54. if image not in images:
  55. raise RenderError(f"Image [{image}] not found in values. Available images: [{', '.join(images.keys())}]")
  56. repo = images[image].get("repository")
  57. if not repo:
  58. raise RenderError("Could not determine repo")
  59. if repo not in supported_repos:
  60. raise RenderError(f"Unsupported repo [{repo}] for redis. Supported repos: {', '.join(supported_repos)}")
  61. return repo
  62. def get_port(self):
  63. return self._config.get("port") or 6379
  64. def get_url(self, variant: str):
  65. addr = f"{self._name}:{self.get_port()}"
  66. password = urllib.parse.quote_plus(self._config["password"])
  67. match variant:
  68. case "redis":
  69. return f"redis://default:{password}@{addr}"
  70. @property
  71. def container(self):
  72. return self._container