render.py 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. import copy
  2. try:
  3. from .client import Client
  4. from .configs import Configs
  5. from .container import Container
  6. from .deps import Deps
  7. from .error import RenderError
  8. from .functions import Functions
  9. from .notes import Notes
  10. from .portals import Portals
  11. from .volumes import Volumes
  12. except ImportError:
  13. from client import Client
  14. from configs import Configs
  15. from container import Container
  16. from deps import Deps
  17. from error import RenderError
  18. from functions import Functions
  19. from notes import Notes
  20. from portals import Portals
  21. from volumes import Volumes
  22. class Render(object):
  23. def __init__(self, values):
  24. self._containers: dict[str, Container] = {}
  25. self.values = values
  26. self._add_images_internal_use()
  27. # Make a copy after we inject the images
  28. self._original_values: dict = copy.deepcopy(self.values)
  29. self.deps: Deps = Deps(self)
  30. self.client: Client = Client(render_instance=self)
  31. self.configs = Configs(render_instance=self)
  32. self.funcs = Functions(render_instance=self).func_map()
  33. self.portals: Portals = Portals(render_instance=self)
  34. self.notes: Notes = Notes(render_instance=self)
  35. self.volumes = Volumes(render_instance=self)
  36. def _add_images_internal_use(self):
  37. if not self.values.get("images"):
  38. self.values["images"] = {}
  39. if "python_permissions_image" not in self.values["images"]:
  40. self.values["images"]["python_permissions_image"] = {"repository": "python", "tag": "3.13.0-slim-bookworm"}
  41. if "postgres_upgrade_image" not in self.values["images"]:
  42. self.values["images"]["postgres_upgrade_image"] = {
  43. "repository": "ixsystems/postgres-upgrade",
  44. "tag": "1.0.1",
  45. }
  46. def container_names(self):
  47. return list(self._containers.keys())
  48. def add_container(self, name: str, image: str):
  49. name = name.strip()
  50. if not name:
  51. raise RenderError("Container name cannot be empty")
  52. container = Container(self, name, image)
  53. if name in self._containers:
  54. raise RenderError(f"Container {name} already exists.")
  55. self._containers[name] = container
  56. return container
  57. def render(self):
  58. if self.values != self._original_values:
  59. raise RenderError("Values have been modified since the renderer was created.")
  60. if not self._containers:
  61. raise RenderError("No containers added.")
  62. result: dict = {
  63. "x-notes": self.notes.render(),
  64. "x-portals": self.portals.render(),
  65. "services": {c._name: c.render() for c in self._containers.values()},
  66. }
  67. # Make sure that after services are rendered
  68. # there are no labels that target a non-existent container
  69. # This is to prevent typos
  70. for label in self.values.get("labels", []):
  71. for c in label.get("containers", []):
  72. if c not in self.container_names():
  73. raise RenderError(f"Label [{label['key']}] references container [{c}] which does not exist")
  74. if self.volumes.has_volumes():
  75. result["volumes"] = self.volumes.render()
  76. if self.configs.has_configs():
  77. result["configs"] = self.configs.render()
  78. # if self.networks:
  79. # result["networks"] = {...}
  80. return result