diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 00000000000..9eec1933b60 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1,4 @@ +# CODEOWNERS +# Last-match-wins: put broader patterns above more specific ones. +# Docs: https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-code-owners +/.github/CODEOWNERS @flamingo-stack/devops-engineers diff --git a/charts/fleet/templates/configmap.yaml b/charts/fleet/templates/configmap.yaml index 5291fb9144d..9c4e0a21a42 100644 --- a/charts/fleet/templates/configmap.yaml +++ b/charts/fleet/templates/configmap.yaml @@ -14,6 +14,12 @@ apiVersion: v1 kind: ConfigMap metadata: name: fleet-database + # >>> OPENFRAME(helm): annotations so the migration Job's ConfigMap can join an Argo PreSync phase — openframe/docs/helm-chart.md + {{- with .Values.database.configMapAnnotations }} + annotations: + {{- toYaml . | trim | nindent 4 }} + {{- end }} + # <<< OPENFRAME(helm) labels: {{- include "fleet.labels" . | nindent 4 }} data: diff --git a/charts/fleet/templates/sa.yaml b/charts/fleet/templates/sa.yaml index b4b19bd2642..1d5b265c9ba 100644 --- a/charts/fleet/templates/sa.yaml +++ b/charts/fleet/templates/sa.yaml @@ -4,7 +4,7 @@ metadata: {{- if or .Values.serviceAccountAnnotations .Values.gke.workloadIdentityEmail }} annotations: {{- with .Values.serviceAccountAnnotations}} - {{ toYaml . | trim | indent 2}} + {{- toYaml . | trim | nindent 4 }} {{- end }} {{- if ne .Values.gke.workloadIdentityEmail "" }} iam.gke.io/gcp-service-account: {{ .Values.gke.workloadIdentityEmail }} diff --git a/charts/fleet/templates/secret.yaml b/charts/fleet/templates/secret.yaml index 526052395b3..09cca4ddfa5 100644 --- a/charts/fleet/templates/secret.yaml +++ b/charts/fleet/templates/secret.yaml @@ -3,6 +3,12 @@ apiVersion: v1 kind: Secret metadata: name: fleet-database + # >>> OPENFRAME(helm): annotations so the migration Job's Secret can join an Argo PreSync phase — openframe/docs/helm-chart.md + {{- with .Values.database.secretAnnotations }} + annotations: + {{- toYaml . | trim | nindent 4 }} + {{- end }} + # <<< OPENFRAME(helm) labels: {{- include "fleet.labels" . | nindent 4 }} type: Opaque diff --git a/charts/fleet/values.yaml b/charts/fleet/values.yaml index 661684fccc2..e6a360341ef 100644 --- a/charts/fleet/values.yaml +++ b/charts/fleet/values.yaml @@ -292,12 +292,16 @@ database: # >>> OPENFRAME(helm): fork-externalized DB connection config (ConfigMap/Secret refs) — openframe/docs/helm-chart.md # To read connection details from a ConfigMap instead of using static values below: existingConfigMap: "" # Name of a K8s ConfigMap. If set, host/port/database/username values are ignored. + configMapAnnotations: {} # Annotations for the chart-managed fleet-database ConfigMap. Argo CD users making + # the migration Job a PreSync hook must put the ConfigMap in the same phase: + # argocd.argoproj.io/hook: PreSync + hook-delete-policy: HookFailed hostKey: "FLEET_MYSQL_HOST" portKey: "FLEET_MYSQL_PORT" databaseKey: "MYSQL_DATABASE" usernameKey: "MYSQL_USER" # To read password from a Secret instead of the chart-created one: existingSecret: "" # Name of a K8s Secret. If set, secretName is ignored for password. + secretAnnotations: {} # Annotations for the chart-managed fleet-database Secret. Same PreSync note as above. secretKey: "MYSQL_PASSWORD" host: 127.0.0.1 port: "3306" diff --git a/openframe/docs/helm-chart.md b/openframe/docs/helm-chart.md index 9dfbe489f1f..24de587ec52 100644 --- a/openframe/docs/helm-chart.md +++ b/openframe/docs/helm-chart.md @@ -162,6 +162,32 @@ This walk-back depends on the [migration idempotency](migrations.md) work: becau re-running `prepare db` is a no-op, the job no longer needs hook-managed exactly-once semantics. +### Making it an Argo CD PreSync hook + +Argo CD hooks are not Helm hooks — an operator opts in with +`fleet.migrationJobAnnotations: {argocd.argoproj.io/hook: PreSync}`. The trap is that +PreSync runs *before* the Sync phase, so every Sync-phase resource is unreachable +from the hook. The Job hardcodes `serviceAccountName: fleet` and resolves the +database ConfigMap and Secret at pod-create time, so all three must be pulled into +the same phase or the sync deadlocks: the Job cannot start, so the Sync phase never +runs, so the resources it waits on are never created. + +| Dependency | Knob | Rendered by | +|------------|------|-------------| +| ServiceAccount `fleet` | `serviceAccountAnnotations` | [sa.yaml](../../charts/fleet/templates/sa.yaml) | +| ConfigMap `fleet-database` (host/port/db/user) | `database.configMapAnnotations` | [configmap.yaml](../../charts/fleet/templates/configmap.yaml) | +| Secret `fleet-database` (password) | `database.secretAnnotations` | [secret.yaml](../../charts/fleet/templates/secret.yaml) | + +When `database.existingConfigMap` / `database.existingSecret` point at externally +managed objects, the operator annotates those instead — the knobs above only reach +the chart-managed ones. + +Give the three dependencies `argocd.argoproj.io/hook-delete-policy: HookFailed`, not +the `BeforeHookCreation` default: the Deployment reads the same ConfigMap and Secret, +and BeforeHookCreation deletes and recreates them on every sync. Put the Job a wave +behind them (`argocd.argoproj.io/sync-wave: "1"`) so ordering does not rely on Argo's +intra-wave kind ordering. + ## Other fork additions | Feature | values.yaml | Notes |