helm: gate the bucket hook Job and its policy on one helper

Both were deriving the same condition from the same values, kept in step by
a comment. seaweedfs.bucketHookEnabled makes it one definition, so adding an
S3 mode cannot leave the Job running without its policy - which under
default-deny means the hook hangs. CI pins the pairing across the eleven
modes that decide it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sebastian Preisner
2026-07-29 12:02:23 +02:00
co-authored by Claude Opus 5
parent 2d41fb255f
commit 839845d726
4 changed files with 60 additions and 17 deletions
+40
View File
@@ -942,6 +942,46 @@ jobs:
if not failed:
print("every workload has a policy covering all of its containerPorts")
# The bucket hook Job and its policy are gated on one shared helper, and
# this pins that down: a Job without its policy hangs under default-deny,
# a policy without its Job is noise. The combinations cover the modes that
# decide it, including the ones where a bucket list is ignored.
hook_cases = {
"nothing": {},
"s3 without buckets": {"s3.enabled": "true"},
"s3 with buckets": {"s3.enabled": "true", "s3.createBuckets[0].name": "b"},
"filer.s3 without buckets": {"filer.s3.enabled": "true"},
"filer.s3 with buckets": {"filer.s3.enabled": "true",
"filer.s3.createBuckets[0].name": "b"},
"s3 gateway, buckets on filer.s3": {"s3.enabled": "true",
"filer.s3.createBuckets[0].name": "b"},
"allInOne without buckets": {"allInOne.enabled": "true",
"allInOne.s3.enabled": "true"},
"allInOne with buckets": {"allInOne.enabled": "true",
"allInOne.s3.enabled": "true",
"allInOne.s3.createBuckets[0].name": "b"},
# allInOne reads only its own bucket list, so s3.createBuckets is
# not enough to produce the Job.
"allInOne, buckets on s3": {"allInOne.enabled": "true",
"allInOne.s3.enabled": "true",
"s3.createBuckets[0].name": "b"},
"master off": {"master.enabled": "false", "s3.enabled": "true",
"s3.createBuckets[0].name": "b"},
"buckets but no S3 endpoint": {"s3.createBuckets[0].name": "b"},
}
for label, values in hook_cases.items():
out = render(dict(values, **{"networkPolicy.enabled": "true"}))
job = any(d.get("kind") == "Job"
and d["metadata"]["name"].endswith("-bucket-hook")
for d in docs(out))
policy = "bucket-hook" in policies(out)
if job != policy:
failed.append(f"{label}: bucket hook Job={job} but its policy={policy}; "
"the two are gated on seaweedfs.bucketHookEnabled and "
"have to appear together")
if not failed:
print(f"bucket hook Job and policy agree across {len(hook_cases)} modes")
# Egress is its own opt-in: with it off the policies must not constrain
# outbound traffic at all, or enabling networkPolicy alone would cut the filer
# off from its store.
@@ -344,6 +344,22 @@ true
{{- end -}}
{{- end -}}
{{/* True when the post-install bucket hook Job renders: an S3 endpoint, plus
buckets to create on it. Read by the Job itself and by its NetworkPolicy,
which has to appear exactly when the Job does - a Job without its policy
hangs in a default-deny namespace. */}}
{{- define "seaweedfs.bucketHookEnabled" -}}
{{- if .Values.allInOne.enabled -}}
{{- if and .Values.allInOne.s3.enabled .Values.allInOne.s3.createBuckets -}}
true
{{- end -}}
{{- else if .Values.master.enabled -}}
{{- if and (or .Values.filer.s3.enabled .Values.s3.enabled) (or .Values.s3.createBuckets .Values.filer.s3.createBuckets) -}}
true
{{- end -}}
{{- end -}}
{{- end -}}
{{/* S3 TLS cert/key arguments, using custom secret if s3.tlsSecret is set */}}
{{- define "seaweedfs.s3.tlsArgs" -}}
{{- $prefix := .prefix -}}
@@ -112,17 +112,7 @@
then. The resize hook is pre-install weight 0, which runs before the
manifest is applied at all, so its policy has to be a pre-install hook
itself, at a weight below the Job's. */}}
{{- /* Same condition as the Job in post-install-bucket-hook.yaml: an S3
endpoint plus buckets to create. Keep the two in step. */}}
{{- $bucketHook := false }}
{{- if .Values.allInOne.enabled }}
{{- $bucketHook = and .Values.allInOne.s3.enabled .Values.allInOne.s3.createBuckets }}
{{- else if .Values.master.enabled }}
{{- if or .Values.filer.s3.enabled .Values.s3.enabled }}
{{- $bucketHook = or .Values.s3.createBuckets .Values.filer.s3.createBuckets }}
{{- end }}
{{- end }}
{{- if $bucketHook }}
{{- if include "seaweedfs.bucketHookEnabled" . }}
{{- $targets = append $targets (dict "component" "bucket-hook" "ports" (list)) }}
{{- end }}
{{- /* Whether the resize hook Job materialises depends on a cluster lookup, so
@@ -1,7 +1,6 @@
{{- include "seaweedfs.compat" . -}}
{{- /* Support bucket creation for both standalone filer.s3 and allInOne modes */}}
{{- $createBuckets := list }}
{{- $s3Enabled := false }}
{{- $enableAuth := false }}
{{- $existingConfigSecret := "" }}
{{- $bucketsFolder := "/buckets" }}
@@ -17,7 +16,6 @@
{{- /* Check allInOne mode first */}}
{{- if .Values.allInOne.enabled }}
{{- if .Values.allInOne.s3.enabled }}
{{- $s3Enabled = true }}
{{- if .Values.allInOne.s3.createBuckets }}
{{- $createBuckets = .Values.allInOne.s3.createBuckets }}
{{- end }}
@@ -27,7 +25,6 @@
{{- else if .Values.master.enabled }}
{{- /* Check if embedded (in filer) or standalone S3 gateway is enabled */}}
{{- if or .Values.filer.s3.enabled .Values.s3.enabled }}
{{- $s3Enabled = true }}
{{- if .Values.s3.createBuckets }}
{{- $createBuckets = .Values.s3.createBuckets }}
{{- $enableAuth = .Values.s3.enableAuth }}
@@ -40,9 +37,9 @@
{{- end }}
{{- end }}
{{- /* networkpolicy.yaml decides whether to render this Job's policy off the
same condition. Keep the two in step. */}}
{{- if and $s3Enabled $createBuckets }}
{{- /* Shared with networkpolicy.yaml, which renders this Job's policy exactly
when the Job itself renders. */}}
{{- if include "seaweedfs.bucketHookEnabled" . }}
---
apiVersion: batch/v1
kind: Job