8064876cb1
CI / test (push) Successful in 1m46s
paths, self-registration bootstrap)
Replaces the bring-your-own-only Stage 1 (commit 1be7cf2) wholesale, per
the redesign in the previous two commits: the operator creates every
server it manages, so self-registration (DESIGN.md §6) is the only
bootstrap path, and Deployment/Service/database management builds
together with it (ROADMAP.md Stage 1) rather than behind a separate
later stage.
Grounded in terdut-server's actual chart (charts/terdut-server/templates/
deployment.yaml, values.yaml), not reconstructed from DESIGN.md's
illustrative YAML alone -- env var names, the password-via-PGPASSWORD
convention, the Recreate deployment strategy, /healthz probes, and the
TERDUT_OPERATOR_MODE=true decision (always on here, unlike the chart's
default-off: every write this operator's own future controllers make
goes through a service account already) all match that source exactly.
- api/v1alpha1: full TerdutServerSpec (image, replicas, networking,
database, sweeper, deadman, notify, oidc, passwordLogin, allowedTeams).
spec.database is a oneOf (dsn xor postgresClusterRef) via CEL
XValidation. No spec.credentialsSecretRef -- removed entirely in the
prior redesign commit, not carried forward.
- internal/controller:
- terdutserver_deployment.go: Deployment + Service via CreateOrUpdate,
owned (OwnerReference), env built field-for-field against the chart.
- terdutserver_database.go: both §8 paths. The Zalando path resolves
the postgresql.acid.zalan.do CR by convention (database/role both
"terdut", matching every DESIGN.md example) and only ever confirms
its generated credentials Secret exists -- never reads the value,
same "wire a secretKeyRef, don't read it" posture the DSN path takes.
classifyClusterGetError is its own function specifically so the
CRD-not-installed case (meta.IsNoMatchError) is unit-testable without
a real client.
- terdutserver_bootstrap.go: self-registration, checkpointed against
both real crash windows (DESIGN.md §6 point 1) -- an admin-key
checkpoint Secret, and adopt-via-GET+mint-new-key on a 409 from
creating the service account. BootstrapStateLost is its own error
type so Reconcile can route it to a condition instead of an infinite
retry.
- terdutserver_controller.go: ties it together -- finalizer add, DB
resolution, Deployment/Service reconcile, wait for a ready replica,
bootstrap, Ready/Bootstrapped/DatabaseReady conditions. Finalizer on
delete only removes the generated Secrets: terdut-server's API can't
delete a user or service account, only revoke keys, so there's
nothing server-side to undo.
- internal/tdclient: added Bootstrap, CreateInstanceServiceAccount,
GetServiceAccountByName, CreateServiceAccountKey, matching
terdut-server's real handlers' request/response shapes (internal/api/
users.go, service_accounts.go in that repo) field-for-field.
- Tests: envtest suite covering the full DSN-path lifecycle end to end
(finalizer -> Deployment/Service -> simulated readiness -> real
bootstrap against an httptest.Server fake), the adopt-on-409 recovery
path, BootstrapStateLost, both Zalando outcomes (cluster not found;
cluster + Secret found -> real DSN -> Ready), and deletion. A minimal
test-only stub of the Zalando CRD (internal/controller/testdata) lets
envtest create fixture objects without a real postgres-operator
installed. 74.0%/44.7% coverage, 0 lint issues.
- Two things scoped down from §8's full ambition, called out in code and
ROADMAP.md rather than silently dropped: no live watch on the
Zalando-generated Secret for rotation (periodic resync notices
eventually, not immediately), no Gateway API HTTPRoute creation from
spec.networking (would add a new dependency; nothing about proving
bootstrap works depends on external ingress existing). Both are
near-term follow-ups.
Verified locally: make fmt lint test build all clean.
316 lines
8.9 KiB
Go
316 lines
8.9 KiB
Go
//go:build !ignore_autogenerated
|
|
|
|
// Code generated by controller-gen. DO NOT EDIT.
|
|
|
|
package v1alpha1
|
|
|
|
import (
|
|
"k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
"k8s.io/apimachinery/pkg/runtime"
|
|
)
|
|
|
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
func (in *AllowedTeams) DeepCopyInto(out *AllowedTeams) {
|
|
*out = *in
|
|
in.Namespaces.DeepCopyInto(&out.Namespaces)
|
|
}
|
|
|
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AllowedTeams.
|
|
func (in *AllowedTeams) DeepCopy() *AllowedTeams {
|
|
if in == nil {
|
|
return nil
|
|
}
|
|
out := new(AllowedTeams)
|
|
in.DeepCopyInto(out)
|
|
return out
|
|
}
|
|
|
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
func (in *AllowedTeamsNamespaces) DeepCopyInto(out *AllowedTeamsNamespaces) {
|
|
*out = *in
|
|
if in.Selector != nil {
|
|
in, out := &in.Selector, &out.Selector
|
|
*out = new(v1.LabelSelector)
|
|
(*in).DeepCopyInto(*out)
|
|
}
|
|
}
|
|
|
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new AllowedTeamsNamespaces.
|
|
func (in *AllowedTeamsNamespaces) DeepCopy() *AllowedTeamsNamespaces {
|
|
if in == nil {
|
|
return nil
|
|
}
|
|
out := new(AllowedTeamsNamespaces)
|
|
in.DeepCopyInto(out)
|
|
return out
|
|
}
|
|
|
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
func (in *DatabaseSpec) DeepCopyInto(out *DatabaseSpec) {
|
|
*out = *in
|
|
if in.PasswordSecretRef != nil {
|
|
in, out := &in.PasswordSecretRef, &out.PasswordSecretRef
|
|
*out = new(SecretKeyRef)
|
|
**out = **in
|
|
}
|
|
if in.PostgresClusterRef != nil {
|
|
in, out := &in.PostgresClusterRef, &out.PostgresClusterRef
|
|
*out = new(PostgresClusterRef)
|
|
**out = **in
|
|
}
|
|
}
|
|
|
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DatabaseSpec.
|
|
func (in *DatabaseSpec) DeepCopy() *DatabaseSpec {
|
|
if in == nil {
|
|
return nil
|
|
}
|
|
out := new(DatabaseSpec)
|
|
in.DeepCopyInto(out)
|
|
return out
|
|
}
|
|
|
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
func (in *DeadmanSpec) DeepCopyInto(out *DeadmanSpec) {
|
|
*out = *in
|
|
}
|
|
|
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DeadmanSpec.
|
|
func (in *DeadmanSpec) DeepCopy() *DeadmanSpec {
|
|
if in == nil {
|
|
return nil
|
|
}
|
|
out := new(DeadmanSpec)
|
|
in.DeepCopyInto(out)
|
|
return out
|
|
}
|
|
|
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
func (in *ImageSpec) DeepCopyInto(out *ImageSpec) {
|
|
*out = *in
|
|
}
|
|
|
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ImageSpec.
|
|
func (in *ImageSpec) DeepCopy() *ImageSpec {
|
|
if in == nil {
|
|
return nil
|
|
}
|
|
out := new(ImageSpec)
|
|
in.DeepCopyInto(out)
|
|
return out
|
|
}
|
|
|
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
func (in *NetworkingSpec) DeepCopyInto(out *NetworkingSpec) {
|
|
*out = *in
|
|
}
|
|
|
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NetworkingSpec.
|
|
func (in *NetworkingSpec) DeepCopy() *NetworkingSpec {
|
|
if in == nil {
|
|
return nil
|
|
}
|
|
out := new(NetworkingSpec)
|
|
in.DeepCopyInto(out)
|
|
return out
|
|
}
|
|
|
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
func (in *NotifySpec) DeepCopyInto(out *NotifySpec) {
|
|
*out = *in
|
|
if in.TokenSecretRef != nil {
|
|
in, out := &in.TokenSecretRef, &out.TokenSecretRef
|
|
*out = new(SecretKeyRef)
|
|
**out = **in
|
|
}
|
|
}
|
|
|
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new NotifySpec.
|
|
func (in *NotifySpec) DeepCopy() *NotifySpec {
|
|
if in == nil {
|
|
return nil
|
|
}
|
|
out := new(NotifySpec)
|
|
in.DeepCopyInto(out)
|
|
return out
|
|
}
|
|
|
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
func (in *OIDCSpec) DeepCopyInto(out *OIDCSpec) {
|
|
*out = *in
|
|
if in.ClientSecretRef != nil {
|
|
in, out := &in.ClientSecretRef, &out.ClientSecretRef
|
|
*out = new(SecretKeyRef)
|
|
**out = **in
|
|
}
|
|
if in.AllowedGroups != nil {
|
|
in, out := &in.AllowedGroups, &out.AllowedGroups
|
|
*out = make([]string, len(*in))
|
|
copy(*out, *in)
|
|
}
|
|
}
|
|
|
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new OIDCSpec.
|
|
func (in *OIDCSpec) DeepCopy() *OIDCSpec {
|
|
if in == nil {
|
|
return nil
|
|
}
|
|
out := new(OIDCSpec)
|
|
in.DeepCopyInto(out)
|
|
return out
|
|
}
|
|
|
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
func (in *PostgresClusterRef) DeepCopyInto(out *PostgresClusterRef) {
|
|
*out = *in
|
|
}
|
|
|
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PostgresClusterRef.
|
|
func (in *PostgresClusterRef) DeepCopy() *PostgresClusterRef {
|
|
if in == nil {
|
|
return nil
|
|
}
|
|
out := new(PostgresClusterRef)
|
|
in.DeepCopyInto(out)
|
|
return out
|
|
}
|
|
|
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
func (in *SecretKeyRef) DeepCopyInto(out *SecretKeyRef) {
|
|
*out = *in
|
|
}
|
|
|
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SecretKeyRef.
|
|
func (in *SecretKeyRef) DeepCopy() *SecretKeyRef {
|
|
if in == nil {
|
|
return nil
|
|
}
|
|
out := new(SecretKeyRef)
|
|
in.DeepCopyInto(out)
|
|
return out
|
|
}
|
|
|
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
func (in *SweeperSpec) DeepCopyInto(out *SweeperSpec) {
|
|
*out = *in
|
|
}
|
|
|
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new SweeperSpec.
|
|
func (in *SweeperSpec) DeepCopy() *SweeperSpec {
|
|
if in == nil {
|
|
return nil
|
|
}
|
|
out := new(SweeperSpec)
|
|
in.DeepCopyInto(out)
|
|
return out
|
|
}
|
|
|
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
func (in *TerdutServer) DeepCopyInto(out *TerdutServer) {
|
|
*out = *in
|
|
out.TypeMeta = in.TypeMeta
|
|
in.ObjectMeta.DeepCopyInto(&out.ObjectMeta)
|
|
in.Spec.DeepCopyInto(&out.Spec)
|
|
in.Status.DeepCopyInto(&out.Status)
|
|
}
|
|
|
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TerdutServer.
|
|
func (in *TerdutServer) DeepCopy() *TerdutServer {
|
|
if in == nil {
|
|
return nil
|
|
}
|
|
out := new(TerdutServer)
|
|
in.DeepCopyInto(out)
|
|
return out
|
|
}
|
|
|
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
|
func (in *TerdutServer) DeepCopyObject() runtime.Object {
|
|
if c := in.DeepCopy(); c != nil {
|
|
return c
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
func (in *TerdutServerList) DeepCopyInto(out *TerdutServerList) {
|
|
*out = *in
|
|
out.TypeMeta = in.TypeMeta
|
|
in.ListMeta.DeepCopyInto(&out.ListMeta)
|
|
if in.Items != nil {
|
|
in, out := &in.Items, &out.Items
|
|
*out = make([]TerdutServer, len(*in))
|
|
for i := range *in {
|
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
|
}
|
|
}
|
|
}
|
|
|
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TerdutServerList.
|
|
func (in *TerdutServerList) DeepCopy() *TerdutServerList {
|
|
if in == nil {
|
|
return nil
|
|
}
|
|
out := new(TerdutServerList)
|
|
in.DeepCopyInto(out)
|
|
return out
|
|
}
|
|
|
|
// DeepCopyObject is an autogenerated deepcopy function, copying the receiver, creating a new runtime.Object.
|
|
func (in *TerdutServerList) DeepCopyObject() runtime.Object {
|
|
if c := in.DeepCopy(); c != nil {
|
|
return c
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
func (in *TerdutServerSpec) DeepCopyInto(out *TerdutServerSpec) {
|
|
*out = *in
|
|
out.Image = in.Image
|
|
out.Networking = in.Networking
|
|
in.Database.DeepCopyInto(&out.Database)
|
|
out.Sweeper = in.Sweeper
|
|
out.Deadman = in.Deadman
|
|
in.Notify.DeepCopyInto(&out.Notify)
|
|
in.OIDC.DeepCopyInto(&out.OIDC)
|
|
in.AllowedTeams.DeepCopyInto(&out.AllowedTeams)
|
|
}
|
|
|
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TerdutServerSpec.
|
|
func (in *TerdutServerSpec) DeepCopy() *TerdutServerSpec {
|
|
if in == nil {
|
|
return nil
|
|
}
|
|
out := new(TerdutServerSpec)
|
|
in.DeepCopyInto(out)
|
|
return out
|
|
}
|
|
|
|
// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil.
|
|
func (in *TerdutServerStatus) DeepCopyInto(out *TerdutServerStatus) {
|
|
*out = *in
|
|
if in.Conditions != nil {
|
|
in, out := &in.Conditions, &out.Conditions
|
|
*out = make([]v1.Condition, len(*in))
|
|
for i := range *in {
|
|
(*in)[i].DeepCopyInto(&(*out)[i])
|
|
}
|
|
}
|
|
if in.CredentialsSecretRef != nil {
|
|
in, out := &in.CredentialsSecretRef, &out.CredentialsSecretRef
|
|
*out = new(SecretKeyRef)
|
|
**out = **in
|
|
}
|
|
}
|
|
|
|
// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TerdutServerStatus.
|
|
func (in *TerdutServerStatus) DeepCopy() *TerdutServerStatus {
|
|
if in == nil {
|
|
return nil
|
|
}
|
|
out := new(TerdutServerStatus)
|
|
in.DeepCopyInto(out)
|
|
return out
|
|
}
|