Implement autobackup-operator controllers, tests, CI and packaging

PVCs and CloudNativePG Clusters need S3 buckets and backup schedules
provisioned consistently. This operator watches the
backups.unkin.net/{schedule,destination} annotations on those objects and
provisions everything needed to back them up, with no new CRDs.

- Add a PVC controller that provisions cephrgw ObjectStoreUser/Bucket/BucketAccess,
  auto-generates a restic repo-password Secret and creates a k8up Schedule scoped
  to the PVC via spec.backup.volumes[].persistentVolumeClaim.claimName.
- Add a CNPG Cluster controller that provisions the same bucket stack, idempotently
  patches spec.backup.barmanObjectStore (leaving a user-set destinationPath alone
  with a Warning event) and creates a ScheduledBackup.
- Resolve destinations through a ConfigMap lookup table; requeue until the
  BucketAccess is Ready before creating schedule resources; own-reference created
  resources and retain bucket data by default.
- Add schedule-mapping helpers (k8up 5-field/shortcut pass-through, CNPG 6-field
  seconds-first) and deterministic, length-bounded name derivation.
- Add unit tests (schedule mapping, name derivation, destination resolution) and
  envtest controller tests for both paths, wiring the external CRDs into envtest.
- Add kubebuilder-generated RBAC, a Dockerfile (distroless/nonroot), Woodpecker
  lint/test/build pipelines and a tag-triggered image push to the artifactapi
  docker-internal registry, plus a version-bump Makefile and deploy manifests.
This commit is contained in:
2026-08-14 00:08:37 +10:00
parent 3d63975b24
commit 9da206dc7c
4631 changed files with 1334852 additions and 1 deletions
+5
View File
@@ -0,0 +1,5 @@
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
// SPDX-License-Identifier: Apache-2.0
// Package ifaces exposes all interfaces to work with adapters.
package ifaces
+84
View File
@@ -0,0 +1,84 @@
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
// SPDX-License-Identifier: Apache-2.0
package ifaces
import (
_ "encoding/json" // for documentation purpose
"iter"
)
// Ordered knows how to iterate over the (key,value) pairs of a JSON object.
type Ordered interface {
OrderedItems() iter.Seq2[string, any]
}
// SetOrdered knows how to append or update the keys of a JSON object,
// given an iterator over (key,value) pairs.
//
// If the provided iterator is nil then the receiver should be set to nil.
type SetOrdered interface {
SetOrderedItems(iter.Seq2[string, any])
}
// OrderedMap represent a JSON object (i.e. like a map[string,any]),
// and knows how to serialize and deserialize JSON with the order of keys maintained.
type OrderedMap interface {
Ordered
SetOrdered
OrderedMarshalJSON() ([]byte, error)
OrderedUnmarshalJSON([]byte) error
}
// MarshalAdapter behaves likes the standard library [json.Marshal].
type MarshalAdapter interface {
Poolable
Marshal(any) ([]byte, error)
}
// OrderedMarshalAdapter behaves likes the standard library [json.Marshal], preserving the order of keys in objects.
type OrderedMarshalAdapter interface {
Poolable
OrderedMarshal(Ordered) ([]byte, error)
}
// UnmarshalAdapter behaves likes the standard library [json.Unmarshal].
type UnmarshalAdapter interface {
Poolable
Unmarshal([]byte, any) error
}
// OrderedUnmarshalAdapter behaves likes the standard library [json.Unmarshal], preserving the order of keys in objects.
type OrderedUnmarshalAdapter interface {
Poolable
OrderedUnmarshal([]byte, SetOrdered) error
}
// Adapter exposes an interface like the standard [json] library.
type Adapter interface {
MarshalAdapter
UnmarshalAdapter
OrderedAdapter
}
// OrderedAdapter exposes interfaces to process JSON and keep the order of object keys.
type OrderedAdapter interface {
OrderedMarshalAdapter
OrderedUnmarshalAdapter
NewOrderedMap(capacity int) OrderedMap
}
type Poolable interface {
// Self-redeem: for [Adapter] s that are allocated from a pool.
// The [Adapter] must not be used after calling [Redeem].
Redeem()
// Reset the state of the [Adapter], if any.
Reset()
}
@@ -0,0 +1,91 @@
// SPDX-FileCopyrightText: Copyright 2015-2025 go-swagger maintainers
// SPDX-License-Identifier: Apache-2.0
package ifaces
import (
"strings"
)
// Capability indicates what a JSON adapter is capable of.
type Capability uint8
const (
CapabilityMarshalJSON Capability = 1 << iota
CapabilityUnmarshalJSON
CapabilityOrderedMarshalJSON
CapabilityOrderedUnmarshalJSON
CapabilityOrderedMap
)
func (c Capability) String() string {
switch c {
case CapabilityMarshalJSON:
return "MarshalJSON"
case CapabilityUnmarshalJSON:
return "UnmarshalJSON"
case CapabilityOrderedMarshalJSON:
return "OrderedMarshalJSON"
case CapabilityOrderedUnmarshalJSON:
return "OrderedUnmarshalJSON"
case CapabilityOrderedMap:
return "OrderedMap"
default:
return "<unknown>"
}
}
// Capabilities holds several unitary capability flags
type Capabilities uint8
// Has some capability flag enabled.
func (c Capabilities) Has(capability Capability) bool {
return Capability(c)&capability > 0
}
func (c Capabilities) String() string {
var w strings.Builder
first := true
for _, capability := range []Capability{
CapabilityMarshalJSON,
CapabilityUnmarshalJSON,
CapabilityOrderedMarshalJSON,
CapabilityOrderedUnmarshalJSON,
CapabilityOrderedMap,
} {
if c.Has(capability) {
if !first {
w.WriteByte('|')
} else {
first = false
}
w.WriteString(capability.String())
}
}
return w.String()
}
const (
AllCapabilities Capabilities = Capabilities(uint8(CapabilityMarshalJSON) |
uint8(CapabilityUnmarshalJSON) |
uint8(CapabilityOrderedMarshalJSON) |
uint8(CapabilityOrderedUnmarshalJSON) |
uint8(CapabilityOrderedMap))
AllUnorderedCapabilities Capabilities = Capabilities(uint8(CapabilityMarshalJSON) | uint8(CapabilityUnmarshalJSON))
)
// RegistryEntry describes how any given adapter registers its capabilities to the [Registrar].
type RegistryEntry struct {
Who string
What Capabilities
Constructor func() Adapter
Support func(what Capability, value any) bool
}
// Registrar is a type that knows how to keep registration calls from adapters.
type Registrar interface {
RegisterFor(RegistryEntry)
}