{{/* Per-instance fully-qualified name. Used as the prefix for every K8s object in the chart so instances in the same namespace can't collide. */}} {{- define "instance.fullname" -}} {{- .Values.instance.code | trunc 40 | trimSuffix "-" -}} {{- end -}} {{/* Standard labels applied to every K8s object. Keeps `kubectl get -l` queries by-instance trivial. */}} {{- define "instance.labels" -}} app.kubernetes.io/name: odoo app.kubernetes.io/instance: {{ .Values.instance.code | quote }} app.kubernetes.io/managed-by: {{ .Release.Service }} app.kubernetes.io/version: {{ include "instance.odooTag" . | quote }} odoosky.io/component: instance {{- end -}} {{/* Resolved Odoo image tag. If `.Values.odoo.tag` matches a key in `.Values.odoo.pinnedTags`, the chart treats `odoo.tag` as a MAJOR reference (e.g. "18.0") and resolves it to the pinned date-stamped nightly the platform has tested (e.g. "18.0-20260421"). Otherwise it's used verbatim — that's the escape hatch for per-instance overrides during testing. This is what closes the GitOps loop: per-instance overlays carry `odoo.tag: "18.0"` (a major), the chart resolves to the exact pinned nightly. Bumping the platform's pinned image becomes a one-line edit to `pinnedTags` in values.yaml, propagated to every instance on next pod restart without touching any per-instance overlay. Source of truth for which nightly each major maps to: https://git.odoosky.org/odoo-tower/odoosky-odoo (versions.yaml) The `pinnedTags` map in values.yaml MUST stay in sync with that file. */}} {{- define "instance.odooTag" -}} {{- $tag := .Values.odoo.tag -}} {{- $resolved := index .Values.odoo.pinnedTags $tag -}} {{- if $resolved }}{{ $resolved }}{{ else }}{{ $tag }}{{ end -}} {{- end -}} {{/* Resolved full Odoo image reference (registry mirror + image + resolved tag). Used by every Odoo container + initContainer in the chart so a single edit to `pinnedTags` sweeps through every spot. */}} {{- define "instance.odooImage" -}} {{- $tag := include "instance.odooTag" . -}} {{- if .Values.imageMirror.registry -}} {{ .Values.imageMirror.registry }}/{{ .Values.odoo.image }}:{{ $tag }} {{- else -}} {{ .Values.odoo.image }}:{{ $tag }} {{- end -}} {{- end -}} {{/* Resources for a given role (`odoo` | `postgres`), looked up against the `sizes` table by `instance.size`. Falls back to "small" if the operator picked a name that doesn't exist (defensive: a typo shouldn't blow up the rendered chart). */}} {{- define "instance.resources" -}} {{- $size := .Values.instance.size | default "small" -}} {{- $cfg := index .Values.sizes $size | default (index .Values.sizes "small") -}} {{- toYaml (index $cfg .role) -}} {{- end -}} {{/* Args list for the Odoo container. Hard baseline (-d / --db-filter / --addons-path / --proxy-mode) encodes invariants the v3 deployment relies on (Traefik termination, single-DB mode); operators cannot drop these. Runtime knobs come from .Values.odoo.* and only render when set — null leaves Odoo's internal default in place. Overlays without the extended odoo block render byte-identical to the pre-runtime-knob chart, so B-1 doesn't disturb any live instance. Schema: see values.yaml `odoo:` block + docs/PLAN_INSTANCE_CONFIG_AND_DBTOOLS.md. */}} {{- define "instance.odooArgs" -}} - "-d" - {{ .Values.instance.code | quote }} {{- if .Values.odoo.dbFilter }} - {{ printf "--db-filter=%s" .Values.odoo.dbFilter | quote }} {{- else }} - {{ printf "--db-filter=^%s$" .Values.instance.code | quote }} {{- end }} - {{ printf "--addons-path=/usr/lib/python3/dist-packages/odoo/addons,%s" .Values.addonsMountPath | quote }} - "--proxy-mode" {{- with .Values.odoo.workers }} - {{ printf "--workers=%d" (int64 .) | quote }} {{- end }} {{- with .Values.odoo.maxCronThreads }} - {{ printf "--max-cron-threads=%d" (int64 .) | quote }} {{- end }} {{- with .Values.odoo.limitTimeCpu }} - {{ printf "--limit-time-cpu=%d" (int64 .) | quote }} {{- end }} {{- with .Values.odoo.limitTimeReal }} - {{ printf "--limit-time-real=%d" (int64 .) | quote }} {{- end }} {{- with .Values.odoo.limitTimeRealCron }} - {{ printf "--limit-time-real-cron=%d" (int64 .) | quote }} {{- end }} {{- with .Values.odoo.limitMemorySoft }} - {{ printf "--limit-memory-soft=%d" (int64 .) | quote }} {{- end }} {{- with .Values.odoo.limitMemoryHard }} - {{ printf "--limit-memory-hard=%d" (int64 .) | quote }} {{- end }} {{- with .Values.odoo.serverWideModules }} - {{ printf "--load=%s" (join "," .) | quote }} {{- end }} {{- range .Values.odoo.extraArgs }} - {{ . | quote }} {{- end }} {{- end -}} {{/* Storage size for a given layer (`filestore` | `database`). Resolution order, most-specific first: 1. instance.{layer}Storage in the tenant overlay (operator override) 2. sizes[size].storage.{layer} (per-tier default) 3. legacy chart-level fallback (.Values.odoo.filestoreSize / .Values.postgres.storage) This lets operators decouple storage from CPU/RAM tiers — a Small instance with lots of attachments can have 50 GB filestore without upgrading to Medium for capacity it doesn't need. */}} {{- define "instance.storage" -}} {{- $size := .Values.instance.size | default "small" -}} {{- $tier := index .Values.sizes $size | default (index .Values.sizes "small") -}} {{- if eq .layer "filestore" -}} {{- if .Values.instance.filestoreStorage -}}{{ .Values.instance.filestoreStorage }}{{- else if and $tier.storage $tier.storage.filestore -}}{{ $tier.storage.filestore }}{{- else -}}{{ .Values.odoo.filestoreSize | default "10Gi" }}{{- end -}} {{- else if eq .layer "database" -}} {{- if .Values.instance.dbStorage -}}{{ .Values.instance.dbStorage }}{{- else if and $tier.storage $tier.storage.database -}}{{ $tier.storage.database }}{{- else -}}{{ .Values.postgres.storage | default "10Gi" }}{{- end -}} {{- end -}} {{- end -}}