From bad53c4636da3a1dd3eb6f2b4444c2b564a49fc7 Mon Sep 17 00:00:00 2001 From: Tower Deploy Date: Mon, 27 Apr 2026 00:59:51 +0300 Subject: [PATCH] Addon initContainer materialization: per-addon image runs as initContainer + copies content into shared emptyDir mounted at /mnt/extra-addons --- templates/odoo-deployment.yaml | 47 ++++++++++++++++++++++++++++++++++ values.yaml | 25 ++++++++++++++++++ 2 files changed, 72 insertions(+) diff --git a/templates/odoo-deployment.yaml b/templates/odoo-deployment.yaml index 086c227..2cc57fd 100644 --- a/templates/odoo-deployment.yaml +++ b/templates/odoo-deployment.yaml @@ -20,11 +20,44 @@ spec: labels: {{- include "instance.labels" . | nindent 8 }} odoosky.io/role: odoo + annotations: + # Bumping this hash whenever the addons list changes forces + # Helm/ArgoCD to roll the Deployment, which re-runs the init + # containers and re-materializes the shared volume from the + # current image set. Without this, changing only `addons:` in + # values.yaml would leave the existing pod alone. + odoosky.io/addons-hash: {{ .Values.addons | toJson | sha256sum | trunc 16 }} spec: + {{- if .Values.addons }} + # One initContainer per selected addon. Each addon image's + # ENTRYPOINT/CMD copies its bundled content into /target/, + # which is the shared volume the Odoo container reads from. + # Init containers run in order, but each writes to its own + # subdir, so order doesn't matter. + initContainers: + {{- range $i, $a := .Values.addons }} + - name: addon-{{ $a.code | replace "_" "-" | lower }} + image: {{ $a.image }}:{{ $a.version }} + imagePullPolicy: IfNotPresent + volumeMounts: + - name: addons + mountPath: /target + {{- end }} + {{- end }} containers: - name: odoo image: "{{ .Values.odoo.image }}:{{ .Values.odoo.tag }}" imagePullPolicy: IfNotPresent + {{- if .Values.addons }} + # Pass --addons-path explicitly so the official Odoo image's + # entrypoint appends our extra-addons dir to the default + # addons_path. Args after the entrypoint that start with -- + # are passed through to `odoo` directly. We list our path + # AFTER the default so built-in modules still take priority + # on name collisions. + args: + - "--addons-path=/usr/lib/python3/dist-packages/odoo/addons,{{ .Values.addonsMountPath }}" + {{- end }} ports: - name: http containerPort: 8069 @@ -46,6 +79,11 @@ spec: volumeMounts: - name: filestore mountPath: /var/lib/odoo + {{- if .Values.addons }} + - name: addons + mountPath: {{ .Values.addonsMountPath }} + readOnly: true + {{- end }} resources: {{- include "instance.resources" (dict "Values" .Values "role" "odoo") | nindent 12 }} # /web/login is the most stable health endpoint across Odoo @@ -67,3 +105,12 @@ spec: - name: filestore persistentVolumeClaim: claimName: {{ include "instance.fullname" . }}-odoo + {{- if .Values.addons }} + # Shared scratch volume that init containers populate with + # addon content. emptyDir is fine — the source of truth is + # the registry's images; if the volume is wiped (pod + # recreate) the init containers re-materialize from the + # cached images. + - name: addons + emptyDir: {} + {{- end }} diff --git a/values.yaml b/values.yaml index 07cdccb..9ed1925 100644 --- a/values.yaml +++ b/values.yaml @@ -63,6 +63,31 @@ odoo: # Filestore PVC size (Odoo's /var/lib/odoo). filestoreSize: 10Gi +# Addons selected for this instance. Each entry is a tagged image in +# the cluster-local registry (deployed by cluster-platform-v3 chart). +# The chart renders one initContainer per entry that copies the +# addon's content into a shared volume; the Odoo container reads from +# /mnt/extra-addons/. +# +# Tower owns this list — it commits new entries to the tenant overlay +# AFTER ensuring the corresponding image exists in the destination +# cluster's registry (spawning a build Job from Gitea source if not). +# +# Schema: +# addons: +# - code: odoosky_demo +# version: "18.0.1.0.0" +# source: platform # platform | tenant +# image: registry.odoosky-system.svc.cluster.local:5000/addons/odoosky_demo +# +# Empty list = no extra addons; only Odoo's built-in modules. +addons: [] + +# Path inside the Odoo container where addons are materialized. +# Odoo's addons_path includes this dir; one folder per addon code. +# Override only if you need a non-standard layout. +addonsMountPath: /mnt/extra-addons + postgres: image: postgres tag: "16-alpine"