feat(bp-harbor): vendor-agnostic Object Storage backend (closes #383) (#437)
Reworks bp-harbor to write blobs DIRECTLY to the cloud-provider's
native S3 endpoint (Hetzner Object Storage on Hetzner Sovereigns)
per ADR-0001 §13. Mirrors the post-#425 vendor-agnostic seam shipped
in bp-velero:1.2.0 (PR #435 / SHA 0172b9a8) 1:1.
Canonical seam used (per anti-duplication rule + docs/omantel-
handover-wbs.md §3a):
- Sealed Secret name: flux-system/object-storage (NOT hetzner-prefixed)
- Chart values block: .Values.objectStorage.s3.{enabled,credentialsSecretName,s3.{accessKey,secretKey}}
- Template filename: templates/objectstorage-credentials.yaml
- Reference impl: platform/velero/chart/ (PR #435)
Chart changes (platform/harbor/chart/):
- Chart.yaml: 1.0.0 → 1.1.0; description rewritten to emphasise
cloud-direct architecture + remove SeaweedFS hard-dep claim.
- values.yaml: REMOVED hardcoded SeaweedFS endpoint
(http://seaweedfs-s3.seaweedfs.svc.cluster.local:8333) from
persistence.imageChartStorage.s3.regionendpoint. Default
type flipped to `filesystem` so contabo/dev render is clean.
Added vendor-agnostic objectStorage block:
objectStorage:
enabled: false
useExistingSecret: false
credentialsSecretName: ""
s3: { accessKey: "", secretKey: "" }
- templates/objectstorage-credentials.yaml (NEW): synthesises a
harbor-namespace Secret with REGISTRY_STORAGE_S3_ACCESSKEY +
REGISTRY_STORAGE_S3_SECRETKEY keys (the upstream chart's
persistence.imageChartStorage.s3.existingSecret consumption
shape — envFrom on the registry pod). Skip-render branch
when objectStorage.enabled=false (default).
- templates/_helpers.tpl: added bp-harbor.objectStorageCredentialsSecretName
helper.
- templates/networkpolicy.yaml: egress rule retargeted from
SeaweedFS service-namespace selector → external HTTPS:443
(works for any cloud-native S3 endpoint without vendor coupling).
Gated on `.Values.objectStorage.enabled`. Removed
seaweedfsNamespace + seaweedfsS3Port overlay keys.
Per-Sovereign overlays (clusters/{_template,omantel,otech}/bootstrap-
kit/19-harbor.yaml):
- Chart version reference bumped 1.0.0 → 1.1.0.
- dependsOn: bp-seaweedfs REMOVED. New dependsOn = bp-cnpg + bp-cert-manager.
- Added valuesFrom block mapping the 5 keys of flux-system/object-
storage Secret:
s3-bucket → harbor.persistence.imageChartStorage.s3.bucket
s3-region → harbor.persistence.imageChartStorage.s3.region
s3-endpoint → harbor.persistence.imageChartStorage.s3.regionendpoint
s3-access-key → objectStorage.s3.accessKey
s3-secret-key → objectStorage.s3.secretKey
- Inline values flip objectStorage.enabled=true,
harbor.persistence.imageChartStorage.type=s3, and
harbor.persistence.imageChartStorage.s3.existingSecret=harbor-
objectstorage-credentials.
UI catalog (products/catalyst/bootstrap/ui/src/shared/constants/components.ts):
- Harbor's `dependencies` array drops `seaweedfs`. Now ['cnpg', 'valkey'].
Validation:
helm template default render →
1448 lines, 5 Secrets (Harbor internal: core/jobservice/registry/
registry-htpasswd/database — NO objectstorage-credentials),
type=filesystem, 0 SeaweedFS references.
helm template overlay render with objectStorage.enabled=true +
type=s3 + bucket=omantel-harbor + region=fsn1 +
regionendpoint=https://fsn1.your-objectstorage.com +
existingSecret=harbor-objectstorage-credentials →
1452 lines, 6 Secrets (5 internal + 1 objectstorage-credentials),
type=s3 with Hetzner endpoint, registry pod envFrom wired to the
new Secret, 0 SeaweedFS references.
scripts/check-vendor-coupling.sh → exit 0 (no violations across
platform/, clusters/, products/catalyst/bootstrap/{api,ui}/).
helm lint → 0 failures.
WBS:
§2 row 18 → 🟢 chart-released (#383).
§9 #383 row → 🟢 chart-released narrative.
§6 DAG: T383 moved from `class blocked` → `class done`.
Hetzner-S3 E2E deferred to Phase 8 (first omantel run).
Co-authored-by: hatiyildiz <hatiyildiz@noreply.github.com>