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
+109
View File
@@ -0,0 +1,109 @@
# jsonutils
`jsonutils` exposes a few tools to work with JSON:
- a fast, simple `Concat` to concatenate (not merge) JSON objects and arrays
- `FromDynamicJSON` to convert a data structure into a "dynamic JSON" data structure
- `ReadJSON` and `WriteJSON` behave like `json.Unmarshal` and `json.Marshal`,
with the ability to use another underlying serialization library through an `Adapter`
configured at runtime
- a `JSONMapSlice` structure that may be used to store JSON objects with the order of keys maintained
## Dynamic JSON
We call "dynamic JSON" the go data structure that results from unmarshaling JSON like this:
```go
var value any
jsonBytes := `{"a": 1, ... }`
_ = json.Unmarshal(jsonBytes, &value)
```
In this configuration, the standard library mappings are as follows:
| JSON | go |
|-----------|------------------|
| `number` | `float64` |
| `string` | `string` |
| `boolean` | `bool` |
| `null` | `nil` |
| `object` | `map[string]any` |
| `array` | `[]any` |
## Map slices
When using `JSONMapSlice`, the ordering of keys is ensured by replacing
mappings to `map[string]any` by a `JSONMapSlice` which is an (ordered)
slice of `JSONMapItem`s.
Notice that a similar feature is available for YAML (see [`yamlutils`](../yamlutils)),
with a `YAMLMapSlice` type based on the `JSONMapSlice`.
`JSONMapSlice` is similar to an ordered map, but the keys are not retrieved
in constant time.
Another difference with the the above standard mappings is that numbers don't always map
to a `float64`: if the value is a JSON integer, it unmarshals to `int64`.
See also [some examples](https://pkg.go.dev/github.com/go-openapi/swag/jsonutils#pkg-examples)
## Adapters
`ReadJSON`, `WriteJSON` and `FromDynamicJSON` (which is a combination of the latter two)
are wrappers on top of `json.Unmarshal` and `json.Marshal`.
By default, the adapter merely wraps the standard library.
The adapter may be used to register other JSON serialization libraries,
possibly several ones at the same time.
If the value passed is identified as an "ordered map" (i.e. implements `ifaces.Ordered`
or `ifaces.SetOrdered`, the adapter favors the "ordered" JSON behavior and tries to
find a registered implementation that support ordered keys in objects.
Our standard library implementation supports this.
As of `v0.25.0`, we support through such an adapter the popular `mailru/easyjson`
library, which kicks in when the passed values support the `easyjson.Unmarshaler`
or `easyjson.Marshaler` interfaces.
In the future, we plan to add more similar libraries that compete on the go JSON
serializers scene.
## Registering an adapter
In package `github.com/go-openapi/swag/easyjson/adapters`, several adapters are available.
Each adapter is an independent go module. Hence you'll pick its dependencies only if you import it.
At this moment we provide:
- `stdlib`: JSON adapter based on the standard library
- `easyjson`: JSON adapter based on the `github.com/mailru/easyjson`
The adapters provide the basic `Marshal` and `Unmarshal` capabilities, plus an implementation
of the `MapSlice` pattern.
You may also build your own adapter based on your specific use-case. An adapter is not required to implement
all capabilities.
Every adapter comes with a `Register` function, possibly with some options, to register the adapter
to a global registry.
For example, to enable `easyjson` to be used in `ReadJSON` and `WriteJSON`, you would write something like:
```go
import (
"github.com/go-openapi/swag/jsonutils/adapters"
easyjson "github.com/go-openapi/swag/jsonutils/adapters/easyjson/json"
)
func init() {
easyjson.Register(adapters.Registry)
}
```
You may register several adapters. In this case, capability matching is evaluated from the last registered
adapters (LIFO).
## [Benchmarks](./adapters/testintegration/benchmarks/README.md)