auto-generate configuration CRD (#3102)

* auto-generate configuration CRD
* make all subconfig optional
* remove field enable crd validation
* update field descriptions which use proxy types
This commit is contained in:
Felix Kunde 2026-06-22 10:44:46 +02:00 committed by GitHub
parent e4e686588e
commit a664816c09
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
20 changed files with 2664 additions and 2251 deletions

View File

@ -1,6 +1,6 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2025 Zalando SE Copyright (c) 2026 Zalando SE
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@ -66,15 +66,15 @@ $(GENERATED): go.mod $(CRD_SOURCES)
$(GENERATED_CRDS): $(GENERATED) $(GENERATED_CRDS): $(GENERATED)
go tool controller-gen crd:crdVersions=v1,allowDangerousTypes=true paths=./pkg/apis/acid.zalan.do/... output:crd:dir=manifests go tool controller-gen crd:crdVersions=v1,allowDangerousTypes=true paths=./pkg/apis/acid.zalan.do/... output:crd:dir=manifests
# only generate postgresteam.crd.yaml and postgresql.crd.yaml for now
@rm manifests/acid.zalan.do_operatorconfigurations.yaml
@mv manifests/acid.zalan.do_postgresqls.yaml manifests/postgresql.crd.yaml @mv manifests/acid.zalan.do_postgresqls.yaml manifests/postgresql.crd.yaml
@# hack to use lowercase kind and listKind @# hack to use lowercase kind and listKind
@sed -i -e 's/kind: Postgresql/kind: postgresql/' manifests/postgresql.crd.yaml @sed -i -e 's/kind: Postgresql/kind: postgresql/' manifests/postgresql.crd.yaml
@sed -i -e 's/listKind: PostgresqlList/listKind: postgresqlList/' manifests/postgresql.crd.yaml @sed -i -e 's/listKind: PostgresqlList/listKind: postgresqlList/' manifests/postgresql.crd.yaml
@hack/adjust_postgresql_crd.sh @hack/adjust_postgresql_crd.sh
@mv manifests/acid.zalan.do_operatorconfigurations.yaml manifests/operatorconfiguration.crd.yaml
@mv manifests/acid.zalan.do_postgresteams.yaml manifests/postgresteam.crd.yaml @mv manifests/acid.zalan.do_postgresteams.yaml manifests/postgresteam.crd.yaml
@cp manifests/postgresql.crd.yaml pkg/apis/acid.zalan.do/v1/postgresql.crd.yaml @cp manifests/postgresql.crd.yaml pkg/apis/acid.zalan.do/v1/postgresql.crd.yaml
@cp manifests/operatorconfiguration.crd.yaml pkg/apis/acid.zalan.do/v1/operatorconfiguration.crd.yaml
local: ${SOURCES} $(GENERATED_CRDS) local: ${SOURCES} $(GENERATED_CRDS)
CGO_ENABLED=${CGO_ENABLED} go build -o build/${BINARY} $(LOCAL_BUILD_FLAGS) -ldflags "$(LDFLAGS)" $(SOURCES) CGO_ENABLED=${CGO_ENABLED} go build -o build/${BINARY} $(LOCAL_BUILD_FLAGS) -ldflags "$(LDFLAGS)" $(SOURCES)

File diff suppressed because it is too large Load Diff

View File

@ -79,11 +79,6 @@ Those are top-level keys, containing both leaf keys and groups.
Instruct the operator to create/update the CRDs. If disabled the operator will rely on the CRDs being managed separately. Instruct the operator to create/update the CRDs. If disabled the operator will rely on the CRDs being managed separately.
The default is `true`. The default is `true`.
* **enable_crd_validation**
*deprecated*: toggles if the operator will create or update CRDs with
[OpenAPI v3 schema validation](https://kubernetes.io/docs/tasks/access-kubernetes-api/custom-resources/custom-resource-definitions/#validation)
The default is `true`. `false` will be ignored, since `apiextensions.io/v1` requires a structural schema definition.
* **crd_categories** * **crd_categories**
The operator will register CRDs in the `all` category by default so that they will be returned by a `kubectl get all` call. You are free to change categories or leave them empty. The operator will register CRDs in the `all` category by default so that they will be returned by a `kubectl get all` call. You are free to change categories or leave them empty.

View File

@ -38,7 +38,6 @@ data:
# downscaler_annotations: "deployment-time,downscaler/*" # downscaler_annotations: "deployment-time,downscaler/*"
enable_admin_role_for_users: "true" enable_admin_role_for_users: "true"
enable_crd_registration: "true" enable_crd_registration: "true"
enable_crd_validation: "true"
enable_cross_namespace_secret: "false" enable_cross_namespace_secret: "false"
enable_finalizers: "false" enable_finalizers: "false"
enable_database_access: "true" enable_database_access: "true"

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -13,11 +13,17 @@ import (
) )
// +genclient // +genclient
// +genclient:onlyVerbs=get
// +genclient:noStatus
// +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object // +k8s:deepcopy-gen:interfaces=k8s.io/apimachinery/pkg/runtime.Object
// OperatorConfiguration defines the specification for the OperatorConfiguration. // OperatorConfiguration defines the specification for the OperatorConfiguration.
// +k8s:deepcopy-gen=true
// +kubebuilder:resource:categories=all,shortName=opconfig,scope=Namespaced
// +kubebuilder:printcolumn:name="Image",type=string,JSONPath=`.configuration.docker_image`,description="Spilo image to be used for Pods"
// +kubebuilder:printcolumn:name="Cluster-Label",type=string,JSONPath=`.configuration.kubernetes.cluster_name_label`,description="Label for K8s resources created by operator"
// +kubebuilder:printcolumn:name="Service-Account",type=string,JSONPath=`.configuration.kubernetes.pod_service_account_name`,description="Name of service account to be used"
// +kubebuilder:printcolumn:name="Min-Instances",type=integer,JSONPath=`.configuration.min_instances`,description="Minimum number of instances per Postgres cluster"
// +kubebuilder:printcolumn:name="Age",type=date,JSONPath=`.metadata.creationTimestamp`,description="Age of the OperatorConfiguration resource"
// +kubebuilder:subresource:status
type OperatorConfiguration struct { type OperatorConfiguration struct {
metav1.TypeMeta `json:",inline"` metav1.TypeMeta `json:",inline"`
metav1.ObjectMeta `json:"metadata"` metav1.ObjectMeta `json:"metadata"`
@ -37,102 +43,170 @@ type OperatorConfigurationList struct {
// PostgresUsersConfiguration defines the system users of Postgres. // PostgresUsersConfiguration defines the system users of Postgres.
type PostgresUsersConfiguration struct { type PostgresUsersConfiguration struct {
SuperUsername string `json:"super_username,omitempty"` // +kubebuilder:default=postgres
ReplicationUsername string `json:"replication_username,omitempty"` SuperUsername string `json:"super_username,omitempty"`
AdditionalOwnerRoles []string `json:"additional_owner_roles,omitempty"` // +kubebuilder:default=standby
EnablePasswordRotation bool `json:"enable_password_rotation,omitempty"` ReplicationUsername string `json:"replication_username,omitempty"`
PasswordRotationInterval uint32 `json:"password_rotation_interval,omitempty"` AdditionalOwnerRoles []string `json:"additional_owner_roles,omitempty"`
PasswordRotationUserRetention uint32 `json:"password_rotation_user_retention,omitempty"` EnablePasswordRotation bool `json:"enable_password_rotation,omitempty"`
// +kubebuilder:default=90
PasswordRotationInterval uint32 `json:"password_rotation_interval,omitempty"`
// +kubebuilder:default=120
PasswordRotationUserRetention uint32 `json:"password_rotation_user_retention,omitempty"`
} }
// MajorVersionUpgradeConfiguration defines how to execute major version upgrades of Postgres. // MajorVersionUpgradeConfiguration defines how to execute major version upgrades of Postgres.
type MajorVersionUpgradeConfiguration struct { type MajorVersionUpgradeConfiguration struct {
MajorVersionUpgradeMode string `json:"major_version_upgrade_mode" default:"manual"` // off - no actions, manual - manifest triggers action, full - manifest and minimal version violation trigger upgrade // +kubebuilder:validation:Enum=off;manual;full
// +kubebuilder:default=manual
MajorVersionUpgradeMode string `json:"major_version_upgrade_mode,omitempty"` // off - no actions, manual - manifest triggers action, full - manifest and minimal version violation trigger upgrade
MajorVersionUpgradeTeamAllowList []string `json:"major_version_upgrade_team_allow_list,omitempty"` MajorVersionUpgradeTeamAllowList []string `json:"major_version_upgrade_team_allow_list,omitempty"`
MinimalMajorVersion string `json:"minimal_major_version" default:"14"` // +kubebuilder:default="14"
TargetMajorVersion string `json:"target_major_version" default:"18"` MinimalMajorVersion string `json:"minimal_major_version,omitempty"`
// +kubebuilder:default="18"
TargetMajorVersion string `json:"target_major_version,omitempty"`
} }
// KubernetesMetaConfiguration defines k8s conf required for all Postgres clusters and the operator itself // KubernetesMetaConfiguration defines k8s conf required for all Postgres clusters and the operator itself
type KubernetesMetaConfiguration struct { type KubernetesMetaConfiguration struct {
EnableOwnerReferences *bool `json:"enable_owner_references,omitempty"` EnableOwnerReferences *bool `json:"enable_owner_references,omitempty"`
// +kubebuilder:default=postgres-pod
PodServiceAccountName string `json:"pod_service_account_name,omitempty"` PodServiceAccountName string `json:"pod_service_account_name,omitempty"`
// TODO: change it to the proper json // TODO: change it to the proper json
PodServiceAccountDefinition string `json:"pod_service_account_definition,omitempty"` PodServiceAccountDefinition string `json:"pod_service_account_definition,omitempty"`
PodServiceAccountRoleBindingDefinition string `json:"pod_service_account_role_binding_definition,omitempty"` PodServiceAccountRoleBindingDefinition string `json:"pod_service_account_role_binding_definition,omitempty"`
PodTerminateGracePeriod Duration `json:"pod_terminate_grace_period,omitempty"` // +kubebuilder:default="5m"
LivenessProbe *v1.Probe `json:"liveness_probe"` // Postgres pods are terminated forcefully after this timeout
SpiloPrivileged bool `json:"spilo_privileged,omitempty"` PodTerminateGracePeriod Duration `json:"pod_terminate_grace_period,omitempty"`
SpiloAllowPrivilegeEscalation *bool `json:"spilo_allow_privilege_escalation,omitempty"` // +optional
SpiloRunAsUser *int64 `json:"spilo_runasuser,omitempty"` LivenessProbe *v1.Probe `json:"liveness_probe"`
SpiloRunAsGroup *int64 `json:"spilo_runasgroup,omitempty"` SpiloPrivileged bool `json:"spilo_privileged,omitempty"`
SpiloFSGroup *int64 `json:"spilo_fsgroup,omitempty"` // +kubebuilder:default=true
AdditionalPodCapabilities []string `json:"additional_pod_capabilities,omitempty"` SpiloAllowPrivilegeEscalation *bool `json:"spilo_allow_privilege_escalation,omitempty"`
WatchedNamespace string `json:"watched_namespace,omitempty"` SpiloRunAsUser *int64 `json:"spilo_runasuser,omitempty"`
PDBNameFormat config.StringTemplate `json:"pdb_name_format,omitempty"` SpiloRunAsGroup *int64 `json:"spilo_runasgroup,omitempty"`
PDBMasterLabelSelector *bool `json:"pdb_master_label_selector,omitempty"` SpiloFSGroup *int64 `json:"spilo_fsgroup,omitempty"`
EnablePodDisruptionBudget *bool `json:"enable_pod_disruption_budget,omitempty"` AdditionalPodCapabilities []string `json:"additional_pod_capabilities,omitempty"`
StorageResizeMode string `json:"storage_resize_mode,omitempty"` WatchedNamespace string `json:"watched_namespace,omitempty"`
EnableInitContainers *bool `json:"enable_init_containers,omitempty"` // +kubebuilder:default="postgres-{cluster}-pdb"
EnableSidecars *bool `json:"enable_sidecars,omitempty"` // defines the template for PDB names
SharePgSocketWithSidecars *bool `json:"share_pgsocket_with_sidecars,omitempty"` PDBNameFormat config.StringTemplate `json:"pdb_name_format,omitempty"`
SecretNameTemplate config.StringTemplate `json:"secret_name_template,omitempty"` // +kubebuilder:default=true
ClusterDomain string `json:"cluster_domain,omitempty"` PDBMasterLabelSelector *bool `json:"pdb_master_label_selector,omitempty"`
OAuthTokenSecretName spec.NamespacedName `json:"oauth_token_secret_name,omitempty"` // +kubebuilder:default=true
InfrastructureRolesSecretName spec.NamespacedName `json:"infrastructure_roles_secret_name,omitempty"` EnablePodDisruptionBudget *bool `json:"enable_pod_disruption_budget,omitempty"`
InfrastructureRolesDefs []*config.InfrastructureRole `json:"infrastructure_roles_secrets,omitempty"` // +kubebuilder:validation:Enum=ebs;mixed;pvc;off
PodRoleLabel string `json:"pod_role_label,omitempty"` // +kubebuilder:default=pvc
ClusterLabels map[string]string `json:"cluster_labels,omitempty"` StorageResizeMode string `json:"storage_resize_mode,omitempty"`
InheritedLabels []string `json:"inherited_labels,omitempty"` // +kubebuilder:default=true
InheritedAnnotations []string `json:"inherited_annotations,omitempty"` EnableInitContainers *bool `json:"enable_init_containers,omitempty"`
DownscalerAnnotations []string `json:"downscaler_annotations,omitempty"` // +kubebuilder:default=true
IgnoredAnnotations []string `json:"ignored_annotations,omitempty"` EnableSidecars *bool `json:"enable_sidecars,omitempty"`
ClusterNameLabel string `json:"cluster_name_label,omitempty"` SharePgSocketWithSidecars *bool `json:"share_pgsocket_with_sidecars,omitempty"`
DeleteAnnotationDateKey string `json:"delete_annotation_date_key,omitempty"` // +kubebuilder:default="{username}.{cluster}.credentials.{tprkind}.{tprgroup}"
DeleteAnnotationNameKey string `json:"delete_annotation_name_key,omitempty"` // template for database user secrets generated by the operator,
NodeReadinessLabel map[string]string `json:"node_readiness_label,omitempty"` // here username contains the namespace in the format namespace.username
NodeReadinessLabelMerge string `json:"node_readiness_label_merge,omitempty"` // if the user is in different namespace than cluster and cross namespace secrets
CustomPodAnnotations map[string]string `json:"custom_pod_annotations,omitempty"` // are enabled via `enable_cross_namespace_secret` flag in the configuration.
SecretNameTemplate config.StringTemplate `json:"secret_name_template,omitempty"`
// +kubebuilder:default="cluster.local"
ClusterDomain string `json:"cluster_domain,omitempty"`
// +kubebuilder:default=postgres-operator
// namespaced name of the secret containing the OAuth2 token to pass to the teams API
OAuthTokenSecretName spec.NamespacedName `json:"oauth_token_secret_name,omitempty"`
InfrastructureRolesSecretName spec.NamespacedName `json:"infrastructure_roles_secret_name,omitempty"`
// +kubebuilder:validation:Type=array
// namespaced name of the secret containing infrastructure roles names and passwords
InfrastructureRolesDefs []*config.InfrastructureRole `json:"infrastructure_roles_secrets,omitempty"`
// +kubebuilder:default=spilo-role
PodRoleLabel string `json:"pod_role_label,omitempty"`
// +kubebuilder:default={application: spilo}
ClusterLabels map[string]string `json:"cluster_labels,omitempty"`
InheritedLabels []string `json:"inherited_labels,omitempty"`
InheritedAnnotations []string `json:"inherited_annotations,omitempty"`
DownscalerAnnotations []string `json:"downscaler_annotations,omitempty"`
IgnoredAnnotations []string `json:"ignored_annotations,omitempty"`
// +kubebuilder:default=cluster-name
ClusterNameLabel string `json:"cluster_name_label,omitempty"`
DeleteAnnotationDateKey string `json:"delete_annotation_date_key,omitempty"`
DeleteAnnotationNameKey string `json:"delete_annotation_name_key,omitempty"`
NodeReadinessLabel map[string]string `json:"node_readiness_label,omitempty"`
// +kubebuilder:validation:Enum=AND;OR
NodeReadinessLabelMerge string `json:"node_readiness_label_merge,omitempty"`
CustomPodAnnotations map[string]string `json:"custom_pod_annotations,omitempty"`
// TODO: use a proper toleration structure? // TODO: use a proper toleration structure?
PodToleration map[string]string `json:"toleration,omitempty"` PodToleration map[string]string `json:"toleration,omitempty"`
PodEnvironmentConfigMap spec.NamespacedName `json:"pod_environment_configmap,omitempty"` // namespaced name of the ConfigMap with environment variables to populate on every pod
PodEnvironmentSecret string `json:"pod_environment_secret,omitempty"` PodEnvironmentConfigMap spec.NamespacedName `json:"pod_environment_configmap,omitempty"`
PodPriorityClassName string `json:"pod_priority_class_name,omitempty"` PodEnvironmentSecret string `json:"pod_environment_secret,omitempty"`
MasterPodMoveTimeout Duration `json:"master_pod_move_timeout,omitempty"` PodPriorityClassName string `json:"pod_priority_class_name,omitempty"`
EnablePodAntiAffinity bool `json:"enable_pod_antiaffinity,omitempty"` // +kubebuilder:default="20m"
PodAntiAffinityPreferredDuringScheduling bool `json:"pod_antiaffinity_preferred_during_scheduling,omitempty"` // timeout for successful migration of master pods from unschedulable node
PodAntiAffinityTopologyKey string `json:"pod_antiaffinity_topology_key,omitempty"` MasterPodMoveTimeout Duration `json:"master_pod_move_timeout,omitempty"`
PodManagementPolicy string `json:"pod_management_policy,omitempty"` EnablePodAntiAffinity bool `json:"enable_pod_antiaffinity,omitempty"`
PersistentVolumeClaimRetentionPolicy map[string]string `json:"persistent_volume_claim_retention_policy,omitempty"` PodAntiAffinityPreferredDuringScheduling bool `json:"pod_antiaffinity_preferred_during_scheduling,omitempty"`
EnableSecretsDeletion *bool `json:"enable_secrets_deletion,omitempty"` // +kubebuilder:default="kubernetes.io/hostname"
EnablePersistentVolumeClaimDeletion *bool `json:"enable_persistent_volume_claim_deletion,omitempty"` PodAntiAffinityTopologyKey string `json:"pod_antiaffinity_topology_key,omitempty"`
EnableReadinessProbe bool `json:"enable_readiness_probe,omitempty"` // +kubebuilder:validation:Enum=ordered_ready;parallel
EnableCrossNamespaceSecret bool `json:"enable_cross_namespace_secret,omitempty"` // +kubebuilder:default=ordered_ready
EnableFinalizers *bool `json:"enable_finalizers,omitempty"` PodManagementPolicy string `json:"pod_management_policy,omitempty"`
PersistentVolumeClaimRetentionPolicy map[string]string `json:"persistent_volume_claim_retention_policy,omitempty"`
// +kubebuilder:default=true
EnableSecretsDeletion *bool `json:"enable_secrets_deletion,omitempty"`
// +kubebuilder:default=true
EnablePersistentVolumeClaimDeletion *bool `json:"enable_persistent_volume_claim_deletion,omitempty"`
EnableReadinessProbe bool `json:"enable_readiness_probe,omitempty"`
EnableCrossNamespaceSecret bool `json:"enable_cross_namespace_secret,omitempty"`
EnableFinalizers *bool `json:"enable_finalizers,omitempty"`
} }
// PostgresPodResourcesDefaults defines the spec of default resources // PostgresPodResourcesDefaults defines the spec of default resources
type PostgresPodResourcesDefaults struct { type PostgresPodResourcesDefaults struct {
DefaultCPURequest string `json:"default_cpu_request,omitempty"` // +kubebuilder:validation:Pattern=`^(\d+m|\d+(\.\d{1,3})?)$`
DefaultCPURequest string `json:"default_cpu_request,omitempty"`
// +kubebuilder:validation:Pattern=`^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$`
DefaultMemoryRequest string `json:"default_memory_request,omitempty"` DefaultMemoryRequest string `json:"default_memory_request,omitempty"`
DefaultCPULimit string `json:"default_cpu_limit,omitempty"` // +kubebuilder:validation:Pattern=`^(\d+m|\d+(\.\d{1,3})?)$`
DefaultMemoryLimit string `json:"default_memory_limit,omitempty"` DefaultCPULimit string `json:"default_cpu_limit,omitempty"`
MinCPULimit string `json:"min_cpu_limit,omitempty"` // +kubebuilder:validation:Pattern=`^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$`
MinMemoryLimit string `json:"min_memory_limit,omitempty"` DefaultMemoryLimit string `json:"default_memory_limit,omitempty"`
MaxCPURequest string `json:"max_cpu_request,omitempty"` // +kubebuilder:validation:Pattern=`^(\d+m|\d+(\.\d{1,3})?)$`
MaxMemoryRequest string `json:"max_memory_request,omitempty"` MinCPULimit string `json:"min_cpu_limit,omitempty"`
// +kubebuilder:validation:Pattern=`^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$`
MinMemoryLimit string `json:"min_memory_limit,omitempty"`
// +kubebuilder:validation:Pattern=`^(\d+m|\d+(\.\d{1,3})?)$`
MaxCPURequest string `json:"max_cpu_request,omitempty"`
// +kubebuilder:validation:Pattern=`^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$`
MaxMemoryRequest string `json:"max_memory_request,omitempty"`
} }
// OperatorTimeouts defines the timeout of ResourceCheck, PodWait, ReadyWait // OperatorTimeouts defines the timeout of ResourceCheck, PodWait, ReadyWait
type OperatorTimeouts struct { type OperatorTimeouts struct {
ResourceCheckInterval Duration `json:"resource_check_interval,omitempty"` // +kubebuilder:default="3s"
ResourceCheckTimeout Duration `json:"resource_check_timeout,omitempty"` // interval to wait between consecutive attempts to check for some K8s resources
PodLabelWaitTimeout Duration `json:"pod_label_wait_timeout,omitempty"` ResourceCheckInterval Duration `json:"resource_check_interval,omitempty"`
PodDeletionWaitTimeout Duration `json:"pod_deletion_wait_timeout,omitempty"` // +kubebuilder:default="10m"
ReadyWaitInterval Duration `json:"ready_wait_interval,omitempty"` // timeout when waiting for the presence of a certain K8s resource
ReadyWaitTimeout Duration `json:"ready_wait_timeout,omitempty"` ResourceCheckTimeout Duration `json:"resource_check_timeout,omitempty"`
// +kubebuilder:default="10m"
// timeout when waiting for pod role and cluster labels
PodLabelWaitTimeout Duration `json:"pod_label_wait_timeout,omitempty"`
// +kubebuilder:default="10m"
// timeout when waiting for the Postgres pods to be deleted
PodDeletionWaitTimeout Duration `json:"pod_deletion_wait_timeout,omitempty"`
// +kubebuilder:default="4s"
// interval between consecutive attempts waiting for postgresql CRD to be created
ReadyWaitInterval Duration `json:"ready_wait_interval,omitempty"`
// +kubebuilder:default="30s"
// timeout for the complete postgres CRD creation
ReadyWaitTimeout Duration `json:"ready_wait_timeout,omitempty"`
// +kubebuilder:default="1s"
// interval between consecutive attempts of operator calling the Patroni API
PatroniAPICheckInterval Duration `json:"patroni_api_check_interval,omitempty"` PatroniAPICheckInterval Duration `json:"patroni_api_check_interval,omitempty"`
PatroniAPICheckTimeout Duration `json:"patroni_api_check_timeout,omitempty"` // +kubebuilder:default="5s"
// timeout when waiting for successful response from Patroni API
PatroniAPICheckTimeout Duration `json:"patroni_api_check_timeout,omitempty"`
} }
// LoadBalancerConfiguration defines the LB configuration // LoadBalancerConfiguration defines the LB configuration
@ -143,24 +217,36 @@ type LoadBalancerConfiguration struct {
EnableReplicaLoadBalancer bool `json:"enable_replica_load_balancer,omitempty"` EnableReplicaLoadBalancer bool `json:"enable_replica_load_balancer,omitempty"`
EnableReplicaPoolerLoadBalancer bool `json:"enable_replica_pooler_load_balancer,omitempty"` EnableReplicaPoolerLoadBalancer bool `json:"enable_replica_pooler_load_balancer,omitempty"`
// kept in LoadBalancerConfiguration because all the other parameters apply here too // NodePort flags kept in LoadBalancerConfiguration because all the other parameters apply here too
EnableMasterNodePort bool `json:"enable_master_node_port,omitempty"` EnableMasterNodePort bool `json:"enable_master_node_port,omitempty"`
EnableMasterPoolerNodePort bool `json:"enable_master_pooler_node_port,omitempty"` EnableMasterPoolerNodePort bool `json:"enable_master_pooler_node_port,omitempty"`
EnableReplicaNodePort bool `json:"enable_replica_node_port,omitempty"` EnableReplicaNodePort bool `json:"enable_replica_node_port,omitempty"`
EnableReplicaPoolerNodePort bool `json:"enable_replica_pooler_node_port,omitempty"` EnableReplicaPoolerNodePort bool `json:"enable_replica_pooler_node_port,omitempty"`
CustomServiceAnnotations map[string]string `json:"custom_service_annotations,omitempty"` CustomServiceAnnotations map[string]string `json:"custom_service_annotations,omitempty"`
MasterDNSNameFormat config.StringTemplate `json:"master_dns_name_format,omitempty"` // +kubebuilder:default="{cluster}.{namespace}.{hostedzone}"
MasterLegacyDNSNameFormat config.StringTemplate `json:"master_legacy_dns_name_format,omitempty"` // defines the DNS name string template for the master load balancer cluster
ReplicaDNSNameFormat config.StringTemplate `json:"replica_dns_name_format,omitempty"` MasterDNSNameFormat config.StringTemplate `json:"master_dns_name_format,omitempty"`
// +kubebuilder:default="{cluster}.{team}.{hostedzone}"
// deprecated DNS template for master load balancer using team name
MasterLegacyDNSNameFormat config.StringTemplate `json:"master_legacy_dns_name_format,omitempty"`
// +kubebuilder:default="{cluster}-repl.{namespace}.{hostedzone}"
// defines the DNS name string template for the replica load balancer cluster
ReplicaDNSNameFormat config.StringTemplate `json:"replica_dns_name_format,omitempty"`
// +kubebuilder:default="{cluster}-repl.{team}.{hostedzone}"
// deprecated DNS template for replica load balancer using team name
ReplicaLegacyDNSNameFormat config.StringTemplate `json:"replica_legacy_dns_name_format,omitempty"` ReplicaLegacyDNSNameFormat config.StringTemplate `json:"replica_legacy_dns_name_format,omitempty"`
ExternalTrafficPolicy string `json:"external_traffic_policy" default:"Cluster"` // +kubebuilder:validation:Enum=Cluster;Local
// +kubebuilder:default=Cluster
ExternalTrafficPolicy string `json:"external_traffic_policy,omitempty"`
} }
// AWSGCPConfiguration defines the configuration for AWS // AWSGCPConfiguration defines the configuration for AWS
// TODO complete Google Cloud Platform (GCP) configuration // TODO complete Google Cloud Platform (GCP) configuration
type AWSGCPConfiguration struct { type AWSGCPConfiguration struct {
WALES3Bucket string `json:"wal_s3_bucket,omitempty"` WALES3Bucket string `json:"wal_s3_bucket,omitempty"`
// +kubebuilder:default=eu-central-1
AWSRegion string `json:"aws_region,omitempty"` AWSRegion string `json:"aws_region,omitempty"`
WALGSBucket string `json:"wal_gs_bucket,omitempty"` WALGSBucket string `json:"wal_gs_bucket,omitempty"`
GCPCredentials string `json:"gcp_credentials,omitempty"` GCPCredentials string `json:"gcp_credentials,omitempty"`
@ -169,70 +255,109 @@ type AWSGCPConfiguration struct {
KubeIAMRole string `json:"kube_iam_role,omitempty"` KubeIAMRole string `json:"kube_iam_role,omitempty"`
AdditionalSecretMount string `json:"additional_secret_mount,omitempty"` AdditionalSecretMount string `json:"additional_secret_mount,omitempty"`
AdditionalSecretMountPath string `json:"additional_secret_mount_path,omitempty"` AdditionalSecretMountPath string `json:"additional_secret_mount_path,omitempty"`
EnableEBSGp3Migration bool `json:"enable_ebs_gp3_migration" default:"false"` EnableEBSGp3Migration bool `json:"enable_ebs_gp3_migration,omitempty"`
EnableEBSGp3MigrationMaxSize int64 `json:"enable_ebs_gp3_migration_max_size" default:"1000"` EnableEBSGp3MigrationMaxSize int64 `json:"enable_ebs_gp3_migration_max_size,omitempty"`
} }
// OperatorDebugConfiguration defines options for the debug mode // OperatorDebugConfiguration defines options for the debug mode
type OperatorDebugConfiguration struct { type OperatorDebugConfiguration struct {
DebugLogging *bool `json:"debug_logging,omitempty"` // +kubebuilder:default=true
DebugLogging *bool `json:"debug_logging,omitempty"`
// +kubebuilder:default=true
EnableDBAccess *bool `json:"enable_database_access,omitempty"` EnableDBAccess *bool `json:"enable_database_access,omitempty"`
} }
// TeamsAPIConfiguration defines the configuration of TeamsAPI // TeamsAPIConfiguration defines the configuration of TeamsAPI
type TeamsAPIConfiguration struct { type TeamsAPIConfiguration struct {
EnableTeamsAPI bool `json:"enable_teams_api,omitempty"` EnableTeamsAPI bool `json:"enable_teams_api,omitempty"`
TeamsAPIUrl string `json:"teams_api_url,omitempty"` // +kubebuilder:default="https://teams.example.com/api/"
TeamAPIRoleConfiguration map[string]string `json:"team_api_role_configuration,omitempty"` TeamsAPIUrl string `json:"teams_api_url,omitempty"`
EnableTeamSuperuser bool `json:"enable_team_superuser,omitempty"` // +kubebuilder:default={log_statement: all}
EnableAdminRoleForUsers bool `json:"enable_admin_role_for_users,omitempty"` TeamAPIRoleConfiguration map[string]string `json:"team_api_role_configuration,omitempty"`
TeamAdminRole string `json:"team_admin_role,omitempty"` EnableTeamSuperuser bool `json:"enable_team_superuser,omitempty"`
PamRoleName string `json:"pam_role_name,omitempty"` // +kubebuilder:default=true
PamConfiguration string `json:"pam_configuration,omitempty"` EnableAdminRoleForUsers bool `json:"enable_admin_role_for_users,omitempty"`
ProtectedRoles []string `json:"protected_role_names,omitempty"` // +kubebuilder:default=admin
PostgresSuperuserTeams []string `json:"postgres_superuser_teams,omitempty"` TeamAdminRole string `json:"team_admin_role,omitempty"`
EnablePostgresTeamCRD bool `json:"enable_postgres_team_crd,omitempty"` // +kubebuilder:default=zalandos
EnablePostgresTeamCRDSuperusers bool `json:"enable_postgres_team_crd_superusers,omitempty"` PamRoleName string `json:"pam_role_name,omitempty"`
EnableTeamMemberDeprecation bool `json:"enable_team_member_deprecation,omitempty"` // +kubebuilder:default="https://info.example.com/oauth2/tokeninfo?access_token= uid realm=/employees"
RoleDeletionSuffix string `json:"role_deletion_suffix,omitempty"` PamConfiguration string `json:"pam_configuration,omitempty"`
// +kubebuilder:default="[\"admin\", \"cron_admin\"]"
ProtectedRoles []string `json:"protected_role_names,omitempty"`
PostgresSuperuserTeams []string `json:"postgres_superuser_teams,omitempty"`
// +kubebuilder:default=true
EnablePostgresTeamCRD bool `json:"enable_postgres_team_crd,omitempty"`
EnablePostgresTeamCRDSuperusers bool `json:"enable_postgres_team_crd_superusers,omitempty"`
EnableTeamMemberDeprecation bool `json:"enable_team_member_deprecation,omitempty"`
// +kubebuilder:default=_deleted
RoleDeletionSuffix string `json:"role_deletion_suffix,omitempty"`
} }
// LoggingRESTAPIConfiguration defines Logging API conf // LoggingRESTAPIConfiguration defines Logging API conf
type LoggingRESTAPIConfiguration struct { type LoggingRESTAPIConfiguration struct {
APIPort int `json:"api_port,omitempty"` // +kubebuilder:default=8080
RingLogLines int `json:"ring_log_lines,omitempty"` APIPort int `json:"api_port,omitempty"`
// +kubebuilder:default=100
RingLogLines int `json:"ring_log_lines,omitempty"`
// +kubebuilder:default=1000
ClusterHistoryEntries int `json:"cluster_history_entries,omitempty"` ClusterHistoryEntries int `json:"cluster_history_entries,omitempty"`
} }
// ScalyrConfiguration defines the configuration for ScalyrAPI // ScalyrConfiguration defines the configuration for ScalyrAPI
type ScalyrConfiguration struct { type ScalyrConfiguration struct {
ScalyrAPIKey string `json:"scalyr_api_key,omitempty"` ScalyrAPIKey string `json:"scalyr_api_key,omitempty"`
ScalyrImage string `json:"scalyr_image,omitempty"` ScalyrImage string `json:"scalyr_image,omitempty"`
ScalyrServerURL string `json:"scalyr_server_url,omitempty"` // +kubebuilder:default="https://upload.eu.scalyr.com"
ScalyrCPURequest string `json:"scalyr_cpu_request,omitempty"` ScalyrServerURL string `json:"scalyr_server_url,omitempty"`
// +kubebuilder:validation:Pattern=`^(\d+m|\d+(\.\d{1,3})?)$`
// +kubebuilder:default="100m"
ScalyrCPURequest string `json:"scalyr_cpu_request,omitempty"`
// +kubebuilder:validation:Pattern=`^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$`
// +kubebuilder:default="50Mi"
ScalyrMemoryRequest string `json:"scalyr_memory_request,omitempty"` ScalyrMemoryRequest string `json:"scalyr_memory_request,omitempty"`
ScalyrCPULimit string `json:"scalyr_cpu_limit,omitempty"` // +kubebuilder:validation:Pattern=`^(\d+m|\d+(\.\d{1,3})?)$`
ScalyrMemoryLimit string `json:"scalyr_memory_limit,omitempty"` // +kubebuilder:default="1"
ScalyrCPULimit string `json:"scalyr_cpu_limit,omitempty"`
// +kubebuilder:validation:Pattern=`^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$`
// +kubebuilder:default="500Mi"
ScalyrMemoryLimit string `json:"scalyr_memory_limit,omitempty"`
} }
// ConnectionPoolerConfiguration defines default configuration for connection pooler // ConnectionPoolerConfiguration defines default configuration for connection pooler
type ConnectionPoolerConfiguration struct { type ConnectionPoolerConfiguration struct {
NumberOfInstances *int32 `json:"connection_pooler_number_of_instances,omitempty"` // +kubebuilder:validation:Minimum=1
Schema string `json:"connection_pooler_schema,omitempty"` // +kubebuilder:default=2
User string `json:"connection_pooler_user,omitempty"` NumberOfInstances *int32 `json:"connection_pooler_number_of_instances,omitempty"`
Image string `json:"connection_pooler_image,omitempty"` // +kubebuilder:default=pooler
Mode string `json:"connection_pooler_mode,omitempty"` Schema string `json:"connection_pooler_schema,omitempty"`
MaxDBConnections *int32 `json:"connection_pooler_max_db_connections,omitempty"` // +kubebuilder:default=pooler
DefaultCPURequest string `json:"connection_pooler_default_cpu_request,omitempty"` User string `json:"connection_pooler_user,omitempty"`
// +kubebuilder:default="ghcr.io/zalando/postgres-operator/pgbouncer:latest"
Image string `json:"connection_pooler_image,omitempty"`
// +kubebuilder:validation:Enum=session;transaction
// +kubebuilder:default=transaction
Mode string `json:"connection_pooler_mode,omitempty"`
MaxDBConnections *int32 `json:"connection_pooler_max_db_connections,omitempty"`
// +kubebuilder:validation:Pattern=`^(\d+m|\d+(\.\d{1,3})?)$`
DefaultCPURequest string `json:"connection_pooler_default_cpu_request,omitempty"`
// +kubebuilder:validation:Pattern=`^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$`
DefaultMemoryRequest string `json:"connection_pooler_default_memory_request,omitempty"` DefaultMemoryRequest string `json:"connection_pooler_default_memory_request,omitempty"`
DefaultCPULimit string `json:"connection_pooler_default_cpu_limit,omitempty"` // +kubebuilder:validation:Pattern=`^(\d+m|\d+(\.\d{1,3})?)$`
DefaultMemoryLimit string `json:"connection_pooler_default_memory_limit,omitempty"` DefaultCPULimit string `json:"connection_pooler_default_cpu_limit,omitempty"`
// +kubebuilder:validation:Pattern=`^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$`
DefaultMemoryLimit string `json:"connection_pooler_default_memory_limit,omitempty"`
} }
// OperatorLogicalBackupConfiguration defines configuration for logical backup // OperatorLogicalBackupConfiguration defines configuration for logical backup
type OperatorLogicalBackupConfiguration struct { type OperatorLogicalBackupConfiguration struct {
Schedule string `json:"logical_backup_schedule,omitempty"` // +kubebuilder:validation:Pattern=`^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$`
DockerImage string `json:"logical_backup_docker_image,omitempty"` // +kubebuilder:default="30 00 * * *"
Schedule string `json:"logical_backup_schedule,omitempty"`
// +kubebuilder:default="ghcr.io/zalando/postgres-operator/logical-backup:v1.15.1"
DockerImage string `json:"logical_backup_docker_image,omitempty"`
// +kubebuilder:validation:Enum=az;gcs;s3
// +kubebuilder:default=s3
BackupProvider string `json:"logical_backup_provider,omitempty"` BackupProvider string `json:"logical_backup_provider,omitempty"`
AzureStorageAccountName string `json:"logical_backup_azure_storage_account_name,omitempty"` AzureStorageAccountName string `json:"logical_backup_azure_storage_account_name,omitempty"`
AzureStorageContainer string `json:"logical_backup_azure_storage_container,omitempty"` AzureStorageContainer string `json:"logical_backup_azure_storage_container,omitempty"`
@ -246,15 +371,26 @@ type OperatorLogicalBackupConfiguration struct {
S3SSE string `json:"logical_backup_s3_sse,omitempty"` S3SSE string `json:"logical_backup_s3_sse,omitempty"`
RetentionTime string `json:"logical_backup_s3_retention_time,omitempty"` RetentionTime string `json:"logical_backup_s3_retention_time,omitempty"`
GoogleApplicationCredentials string `json:"logical_backup_google_application_credentials,omitempty"` GoogleApplicationCredentials string `json:"logical_backup_google_application_credentials,omitempty"`
JobPrefix string `json:"logical_backup_job_prefix,omitempty"` // +kubebuilder:default=logical-backup-
CronjobEnvironmentSecret string `json:"logical_backup_cronjob_environment_secret,omitempty"` JobPrefix string `json:"logical_backup_job_prefix,omitempty"`
CPURequest string `json:"logical_backup_cpu_request,omitempty"` CronjobEnvironmentSecret string `json:"logical_backup_cronjob_environment_secret,omitempty"`
MemoryRequest string `json:"logical_backup_memory_request,omitempty"` // +kubebuilder:validation:Pattern=`^(\d+m|\d+(\.\d{1,3})?)$`
CPULimit string `json:"logical_backup_cpu_limit,omitempty"` CPURequest string `json:"logical_backup_cpu_request,omitempty"`
MemoryLimit string `json:"logical_backup_memory_limit,omitempty"` // +kubebuilder:validation:Pattern=`^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$`
SuccessfulJobsHistoryLimit *int32 `json:"logical_backup_successful_jobs_history_limit,omitempty"` MemoryRequest string `json:"logical_backup_memory_request,omitempty"`
FailedJobsHistoryLimit *int32 `json:"logical_backup_failed_jobs_history_limit,omitempty"` // +kubebuilder:validation:Pattern=`^(\d+m|\d+(\.\d{1,3})?)$`
TTLSecondsAfterFinished *int32 `json:"logical_backup_ttl_seconds_after_finished,omitempty"` CPULimit string `json:"logical_backup_cpu_limit,omitempty"`
// +kubebuilder:validation:Pattern=`^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$`
MemoryLimit string `json:"logical_backup_memory_limit,omitempty"`
// +kubebuilder:validation:Minimum=0
// +kubebuilder:default=3
SuccessfulJobsHistoryLimit *int32 `json:"logical_backup_successful_jobs_history_limit,omitempty"`
// +kubebuilder:validation:Minimum=0
// +kubebuilder:default=3
FailedJobsHistoryLimit *int32 `json:"logical_backup_failed_jobs_history_limit,omitempty"`
// +kubebuilder:validation:Minimum=0
// +kubebuilder:default=86400
TTLSecondsAfterFinished *int32 `json:"logical_backup_ttl_seconds_after_finished,omitempty"`
} }
// PatroniConfiguration defines configuration for Patroni // PatroniConfiguration defines configuration for Patroni
@ -264,42 +400,80 @@ type PatroniConfiguration struct {
// OperatorConfigurationData defines the operation config // OperatorConfigurationData defines the operation config
type OperatorConfigurationData struct { type OperatorConfigurationData struct {
EnableCRDRegistration *bool `json:"enable_crd_registration,omitempty"` // +kubebuilder:default=true
EnableCRDValidation *bool `json:"enable_crd_validation,omitempty"` EnableCRDRegistration *bool `json:"enable_crd_registration,omitempty"`
CRDCategories []string `json:"crd_categories,omitempty"` CRDCategories []string `json:"crd_categories,omitempty"`
EnableLazySpiloUpgrade bool `json:"enable_lazy_spilo_upgrade,omitempty"` EnableLazySpiloUpgrade bool `json:"enable_lazy_spilo_upgrade,omitempty"`
EnablePgVersionEnvVar bool `json:"enable_pgversion_env_var,omitempty"` // +kubebuilder:default=true
EnableSpiloWalPathCompat bool `json:"enable_spilo_wal_path_compat,omitempty"` EnablePgVersionEnvVar bool `json:"enable_pgversion_env_var,omitempty"`
EnableTeamIdClusternamePrefix bool `json:"enable_team_id_clustername_prefix,omitempty"` EnableSpiloWalPathCompat bool `json:"enable_spilo_wal_path_compat,omitempty"`
EtcdHost string `json:"etcd_host,omitempty"` EnableTeamIdClusternamePrefix bool `json:"enable_team_id_clustername_prefix,omitempty"`
KubernetesUseConfigMaps bool `json:"kubernetes_use_configmaps,omitempty"` // +kubebuilder:default=""
DockerImage string `json:"docker_image,omitempty"` EtcdHost string `json:"etcd_host,omitempty"`
Workers uint32 `json:"workers,omitempty"` // +kubebuilder:default=true
ResyncPeriod Duration `json:"resync_period,omitempty"` KubernetesUseConfigMaps bool `json:"kubernetes_use_configmaps,omitempty"`
RepairPeriod Duration `json:"repair_period,omitempty"` // +kubebuilder:default="ghcr.io/zalando/spilo-18:4.1-p1"
EnableMaintenanceWindows *bool `json:"enable_maintenance_windows,omitempty"` DockerImage string `json:"docker_image,omitempty"`
MaintenanceWindows []MaintenanceWindow `json:"maintenance_windows,omitempty"` // +kubebuilder:validation:Minimum=1
SetMemoryRequestToLimit bool `json:"set_memory_request_to_limit,omitempty"` // +kubebuilder:default=8
ShmVolume *bool `json:"enable_shm_volume,omitempty"` Workers uint32 `json:"workers,omitempty"`
SidecarImages map[string]string `json:"sidecar_docker_images,omitempty"` // deprecated in favour of SidecarContainers // +kubebuilder:default="30m"
SidecarContainers []v1.Container `json:"sidecars,omitempty"` // period between consecutive sync requests
PostgresUsersConfiguration PostgresUsersConfiguration `json:"users"` ResyncPeriod Duration `json:"resync_period,omitempty"`
MajorVersionUpgrade MajorVersionUpgradeConfiguration `json:"major_version_upgrade"` // +kubebuilder:default="5m"
Kubernetes KubernetesMetaConfiguration `json:"kubernetes"` // period between consecutive repair requests
PostgresPodResources PostgresPodResourcesDefaults `json:"postgres_pod_resources"` RepairPeriod Duration `json:"repair_period,omitempty"`
Timeouts OperatorTimeouts `json:"timeouts"` // +kubebuilder:default=true
LoadBalancer LoadBalancerConfiguration `json:"load_balancer"` EnableMaintenanceWindows *bool `json:"enable_maintenance_windows,omitempty"`
AWSGCP AWSGCPConfiguration `json:"aws_or_gcp"` // +kubebuilder:validation:Schemaless
OperatorDebug OperatorDebugConfiguration `json:"debug"` // +kubebuilder:validation:Type=array
TeamsAPI TeamsAPIConfiguration `json:"teams_api"` MaintenanceWindows []MaintenanceWindow `json:"maintenance_windows,omitempty"`
LoggingRESTAPI LoggingRESTAPIConfiguration `json:"logging_rest_api"` SetMemoryRequestToLimit bool `json:"set_memory_request_to_limit,omitempty"`
Scalyr ScalyrConfiguration `json:"scalyr"` // +kubebuilder:default=true
LogicalBackup OperatorLogicalBackupConfiguration `json:"logical_backup"` ShmVolume *bool `json:"enable_shm_volume,omitempty"`
ConnectionPooler ConnectionPoolerConfiguration `json:"connection_pooler"` SidecarImages map[string]string `json:"sidecar_docker_images,omitempty"` // deprecated in favour of SidecarContainers
Patroni PatroniConfiguration `json:"patroni"` // +kubebuilder:validation:XPreserveUnknownFields
// +kubebuilder:validation:Type=object
// +kubebuilder:validation:Schemaless
SidecarContainers []v1.Container `json:"sidecars,omitempty"`
// +optional
PostgresUsersConfiguration PostgresUsersConfiguration `json:"users"`
// +optional
MajorVersionUpgrade MajorVersionUpgradeConfiguration `json:"major_version_upgrade"`
// +optional
Kubernetes KubernetesMetaConfiguration `json:"kubernetes"`
// +optional
PostgresPodResources PostgresPodResourcesDefaults `json:"postgres_pod_resources"`
// +optional
Timeouts OperatorTimeouts `json:"timeouts"`
// +optional
LoadBalancer LoadBalancerConfiguration `json:"load_balancer"`
// +optional
AWSGCP AWSGCPConfiguration `json:"aws_or_gcp"`
// +optional
OperatorDebug OperatorDebugConfiguration `json:"debug"`
// +optional
TeamsAPI TeamsAPIConfiguration `json:"teams_api"`
// +optional
LoggingRESTAPI LoggingRESTAPIConfiguration `json:"logging_rest_api"`
// +optional
Scalyr ScalyrConfiguration `json:"scalyr"`
// +optional
LogicalBackup OperatorLogicalBackupConfiguration `json:"logical_backup"`
// +optional
ConnectionPooler ConnectionPoolerConfiguration `json:"connection_pooler"`
// +optional
Patroni PatroniConfiguration `json:"patroni"`
// +kubebuilder:validation:Minimum=-1
// +kubebuilder:default=-1
// -1 = disabled
MinInstances int32 `json:"min_instances,omitempty"`
// +kubebuilder:validation:Minimum=-1
// +kubebuilder:default=-1
// -1 = disabled
MaxInstances int32 `json:"max_instances,omitempty"`
MinInstances int32 `json:"min_instances,omitempty"`
MaxInstances int32 `json:"max_instances,omitempty"`
IgnoreInstanceLimitsAnnotationKey string `json:"ignore_instance_limits_annotation_key,omitempty"` IgnoreInstanceLimitsAnnotationKey string `json:"ignore_instance_limits_annotation_key,omitempty"`
IgnoreResourcesLimitsAnnotationKey string `json:"ignore_resources_limits_annotation_key,omitempty"` IgnoreResourcesLimitsAnnotationKey string `json:"ignore_resources_limits_annotation_key,omitempty"`
} }

View File

@ -0,0 +1,971 @@
---
apiVersion: apiextensions.k8s.io/v1
kind: CustomResourceDefinition
metadata:
annotations:
controller-gen.kubebuilder.io/version: v0.17.3
name: operatorconfigurations.acid.zalan.do
spec:
group: acid.zalan.do
names:
categories:
- all
kind: OperatorConfiguration
listKind: OperatorConfigurationList
plural: operatorconfigurations
shortNames:
- opconfig
singular: operatorconfiguration
scope: Namespaced
versions:
- additionalPrinterColumns:
- description: Spilo image to be used for Pods
jsonPath: .configuration.docker_image
name: Image
type: string
- description: Label for K8s resources created by operator
jsonPath: .configuration.kubernetes.cluster_name_label
name: Cluster-Label
type: string
- description: Name of service account to be used
jsonPath: .configuration.kubernetes.pod_service_account_name
name: Service-Account
type: string
- description: Minimum number of instances per Postgres cluster
jsonPath: .configuration.min_instances
name: Min-Instances
type: integer
- description: Age of the OperatorConfiguration resource
jsonPath: .metadata.creationTimestamp
name: Age
type: date
name: v1
schema:
openAPIV3Schema:
description: OperatorConfiguration defines the specification for the OperatorConfiguration.
properties:
apiVersion:
description: |-
APIVersion defines the versioned schema of this representation of an object.
Servers should convert recognized schemas to the latest internal value, and
may reject unrecognized values.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#resources
type: string
configuration:
description: OperatorConfigurationData defines the operation config
properties:
aws_or_gcp:
description: AWSGCPConfiguration defines the configuration for AWS
properties:
additional_secret_mount:
type: string
additional_secret_mount_path:
type: string
aws_region:
default: eu-central-1
type: string
enable_ebs_gp3_migration:
type: boolean
enable_ebs_gp3_migration_max_size:
format: int64
type: integer
gcp_credentials:
type: string
kube_iam_role:
type: string
log_s3_bucket:
type: string
wal_az_storage_account:
type: string
wal_gs_bucket:
type: string
wal_s3_bucket:
type: string
type: object
connection_pooler:
description: ConnectionPoolerConfiguration defines default configuration
for connection pooler
properties:
connection_pooler_default_cpu_limit:
pattern: ^(\d+m|\d+(\.\d{1,3})?)$
type: string
connection_pooler_default_cpu_request:
pattern: ^(\d+m|\d+(\.\d{1,3})?)$
type: string
connection_pooler_default_memory_limit:
pattern: ^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$
type: string
connection_pooler_default_memory_request:
pattern: ^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$
type: string
connection_pooler_image:
default: ghcr.io/zalando/postgres-operator/pgbouncer:latest
type: string
connection_pooler_max_db_connections:
format: int32
type: integer
connection_pooler_mode:
default: transaction
enum:
- session
- transaction
type: string
connection_pooler_number_of_instances:
default: 2
format: int32
minimum: 1
type: integer
connection_pooler_schema:
default: pooler
type: string
connection_pooler_user:
default: pooler
type: string
type: object
crd_categories:
items:
type: string
type: array
debug:
description: OperatorDebugConfiguration defines options for the debug
mode
properties:
debug_logging:
default: true
type: boolean
enable_database_access:
default: true
type: boolean
type: object
docker_image:
default: ghcr.io/zalando/spilo-18:4.1-p1
type: string
enable_crd_registration:
default: true
type: boolean
enable_lazy_spilo_upgrade:
type: boolean
enable_maintenance_windows:
default: true
type: boolean
enable_pgversion_env_var:
default: true
type: boolean
enable_shm_volume:
default: true
type: boolean
enable_spilo_wal_path_compat:
type: boolean
enable_team_id_clustername_prefix:
type: boolean
etcd_host:
default: ""
type: string
ignore_instance_limits_annotation_key:
type: string
ignore_resources_limits_annotation_key:
type: string
kubernetes:
description: KubernetesMetaConfiguration defines k8s conf required
for all Postgres clusters and the operator itself
properties:
additional_pod_capabilities:
items:
type: string
type: array
cluster_domain:
default: cluster.local
type: string
cluster_labels:
additionalProperties:
type: string
default:
application: spilo
type: object
cluster_name_label:
default: cluster-name
type: string
custom_pod_annotations:
additionalProperties:
type: string
type: object
delete_annotation_date_key:
type: string
delete_annotation_name_key:
type: string
downscaler_annotations:
items:
type: string
type: array
enable_cross_namespace_secret:
type: boolean
enable_finalizers:
type: boolean
enable_init_containers:
default: true
type: boolean
enable_owner_references:
type: boolean
enable_persistent_volume_claim_deletion:
default: true
type: boolean
enable_pod_antiaffinity:
type: boolean
enable_pod_disruption_budget:
default: true
type: boolean
enable_readiness_probe:
type: boolean
enable_secrets_deletion:
default: true
type: boolean
enable_sidecars:
default: true
type: boolean
ignored_annotations:
items:
type: string
type: array
infrastructure_roles_secret_name:
description: |-
NamespacedName comprises a resource name, with a mandatory namespace,
rendered as "<namespace>/<name>". Being a type captures intent and
helps make sure that UIDs, namespaced names and non-namespaced names
do not get conflated in code. For most use cases, namespace and name
will already have been format validated at the API entry point, so we
don't do that here. Where that's not the case (e.g. in testing),
consider using NamespacedNameOrDie() in testing.go in this package.
from: https://github.com/kubernetes/apimachinery/blob/master/pkg/types/namespacedname.go
properties:
name:
type: string
namespace:
type: string
required:
- name
type: object
infrastructure_roles_secrets:
description: namespaced name of the secret containing infrastructure
roles names and passwords
items:
properties:
defaultrolevalue:
type: string
defaultuservalue:
type: string
details:
description: This field point out the detailed yaml definition
of the role, if exists
type: string
passwordkey:
type: string
rolekey:
type: string
secretname:
description: |-
Name of a secret which describes the role, and optionally name of a
configmap with an extra information
properties:
name:
type: string
namespace:
type: string
required:
- name
type: object
template:
type: boolean
userkey:
type: string
type: object
type: array
inherited_annotations:
items:
type: string
type: array
inherited_labels:
items:
type: string
type: array
liveness_probe:
description: |-
Probe describes a health check to be performed against a container to determine whether it is
alive or ready to receive traffic.
properties:
exec:
description: Exec specifies a command to execute in the container.
properties:
command:
description: |-
Command is the command line to execute inside the container, the working directory for the
command is root ('/') in the container's filesystem. The command is simply exec'd, it is
not run inside a shell, so traditional shell instructions ('|', etc) won't work. To use
a shell, you need to explicitly call out to that shell.
Exit status of 0 is treated as live/healthy and non-zero is unhealthy.
items:
type: string
type: array
x-kubernetes-list-type: atomic
type: object
failureThreshold:
description: |-
Minimum consecutive failures for the probe to be considered failed after having succeeded.
Defaults to 3. Minimum value is 1.
format: int32
type: integer
grpc:
description: GRPC specifies a GRPC HealthCheckRequest.
properties:
port:
description: Port number of the gRPC service. Number must
be in the range 1 to 65535.
format: int32
type: integer
service:
default: ""
description: |-
Service is the name of the service to place in the gRPC HealthCheckRequest
(see https://github.com/grpc/grpc/blob/master/doc/health-checking.md).
If this is not specified, the default behavior is defined by gRPC.
type: string
required:
- port
type: object
httpGet:
description: HTTPGet specifies an HTTP GET request to perform.
properties:
host:
description: |-
Host name to connect to, defaults to the pod IP. You probably want to set
"Host" in httpHeaders instead.
type: string
httpHeaders:
description: Custom headers to set in the request. HTTP
allows repeated headers.
items:
description: HTTPHeader describes a custom header to
be used in HTTP probes
properties:
name:
description: |-
The header field name.
This will be canonicalized upon output, so case-variant names will be understood as the same header.
type: string
value:
description: The header field value
type: string
required:
- name
- value
type: object
type: array
x-kubernetes-list-type: atomic
path:
description: Path to access on the HTTP server.
type: string
port:
anyOf:
- type: integer
- type: string
description: |-
Name or number of the port to access on the container.
Number must be in the range 1 to 65535.
Name must be an IANA_SVC_NAME.
x-kubernetes-int-or-string: true
scheme:
description: |-
Scheme to use for connecting to the host.
Defaults to HTTP.
type: string
required:
- port
type: object
initialDelaySeconds:
description: |-
Number of seconds after the container has started before liveness probes are initiated.
More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes
format: int32
type: integer
periodSeconds:
description: |-
How often (in seconds) to perform the probe.
Default to 10 seconds. Minimum value is 1.
format: int32
type: integer
successThreshold:
description: |-
Minimum consecutive successes for the probe to be considered successful after having failed.
Defaults to 1. Must be 1 for liveness and startup. Minimum value is 1.
format: int32
type: integer
tcpSocket:
description: TCPSocket specifies a connection to a TCP port.
properties:
host:
description: 'Optional: Host name to connect to, defaults
to the pod IP.'
type: string
port:
anyOf:
- type: integer
- type: string
description: |-
Number or name of the port to access on the container.
Number must be in the range 1 to 65535.
Name must be an IANA_SVC_NAME.
x-kubernetes-int-or-string: true
required:
- port
type: object
terminationGracePeriodSeconds:
description: |-
Optional duration in seconds the pod needs to terminate gracefully upon probe failure.
The grace period is the duration in seconds after the processes running in the pod are sent
a termination signal and the time when the processes are forcibly halted with a kill signal.
Set this value longer than the expected cleanup time for your process.
If this value is nil, the pod's terminationGracePeriodSeconds will be used. Otherwise, this
value overrides the value provided by the pod spec.
Value must be non-negative integer. The value zero indicates stop immediately via
the kill signal (no opportunity to shut down).
This is a beta field and requires enabling ProbeTerminationGracePeriod feature gate.
Minimum value is 1. spec.terminationGracePeriodSeconds is used if unset.
format: int64
type: integer
timeoutSeconds:
description: |-
Number of seconds after which the probe times out.
Defaults to 1 second. Minimum value is 1.
More info: https://kubernetes.io/docs/concepts/workloads/pods/pod-lifecycle#container-probes
format: int32
type: integer
type: object
master_pod_move_timeout:
default: 20m
description: timeout for successful migration of master pods from
unschedulable node
format: int64
type: integer
node_readiness_label:
additionalProperties:
type: string
type: object
node_readiness_label_merge:
enum:
- AND
- OR
type: string
oauth_token_secret_name:
default: postgres-operator
description: namespaced name of the secret containing the OAuth2
token to pass to the teams API
properties:
name:
type: string
namespace:
type: string
required:
- name
type: object
pdb_master_label_selector:
default: true
type: boolean
pdb_name_format:
default: postgres-{cluster}-pdb
description: defines the template for PDB names
type: string
persistent_volume_claim_retention_policy:
additionalProperties:
type: string
type: object
pod_antiaffinity_preferred_during_scheduling:
type: boolean
pod_antiaffinity_topology_key:
default: kubernetes.io/hostname
type: string
pod_environment_configmap:
description: namespaced name of the ConfigMap with environment
variables to populate on every pod
properties:
name:
type: string
namespace:
type: string
required:
- name
type: object
pod_environment_secret:
type: string
pod_management_policy:
default: ordered_ready
enum:
- ordered_ready
- parallel
type: string
pod_priority_class_name:
type: string
pod_role_label:
default: spilo-role
type: string
pod_service_account_definition:
type: string
pod_service_account_name:
default: postgres-pod
type: string
pod_service_account_role_binding_definition:
type: string
pod_terminate_grace_period:
default: 5m
description: Postgres pods are terminated forcefully after this
timeout
format: int64
type: integer
secret_name_template:
default: '{username}.{cluster}.credentials.{tprkind}.{tprgroup}'
description: |-
template for database user secrets generated by the operator,
here username contains the namespace in the format namespace.username
if the user is in different namespace than cluster and cross namespace secrets
are enabled via `enable_cross_namespace_secret` flag in the configuration.
type: string
share_pgsocket_with_sidecars:
type: boolean
spilo_allow_privilege_escalation:
default: true
type: boolean
spilo_fsgroup:
format: int64
type: integer
spilo_privileged:
type: boolean
spilo_runasgroup:
format: int64
type: integer
spilo_runasuser:
format: int64
type: integer
storage_resize_mode:
default: pvc
enum:
- ebs
- mixed
- pvc
- "off"
type: string
toleration:
additionalProperties:
type: string
type: object
watched_namespace:
type: string
type: object
kubernetes_use_configmaps:
default: true
type: boolean
load_balancer:
description: LoadBalancerConfiguration defines the LB configuration
properties:
custom_service_annotations:
additionalProperties:
type: string
type: object
db_hosted_zone:
type: string
enable_master_load_balancer:
type: boolean
enable_master_node_port:
type: boolean
enable_master_pooler_load_balancer:
type: boolean
enable_master_pooler_node_port:
type: boolean
enable_replica_load_balancer:
type: boolean
enable_replica_node_port:
type: boolean
enable_replica_pooler_load_balancer:
type: boolean
enable_replica_pooler_node_port:
type: boolean
external_traffic_policy:
default: Cluster
enum:
- Cluster
- Local
type: string
master_dns_name_format:
default: '{cluster}.{namespace}.{hostedzone}'
description: defines the DNS name string template for the master
load balancer cluster
type: string
master_legacy_dns_name_format:
default: '{cluster}.{team}.{hostedzone}'
description: deprecated DNS template for master load balancer
using team name
type: string
replica_dns_name_format:
default: '{cluster}-repl.{namespace}.{hostedzone}'
description: defines the DNS name string template for the replica
load balancer cluster
type: string
replica_legacy_dns_name_format:
default: '{cluster}-repl.{team}.{hostedzone}'
description: deprecated DNS template for replica load balancer
using team name
type: string
type: object
logging_rest_api:
description: LoggingRESTAPIConfiguration defines Logging API conf
properties:
api_port:
default: 8080
type: integer
cluster_history_entries:
default: 1000
type: integer
ring_log_lines:
default: 100
type: integer
type: object
logical_backup:
description: OperatorLogicalBackupConfiguration defines configuration
for logical backup
properties:
logical_backup_azure_storage_account_key:
type: string
logical_backup_azure_storage_account_name:
type: string
logical_backup_azure_storage_container:
type: string
logical_backup_cpu_limit:
pattern: ^(\d+m|\d+(\.\d{1,3})?)$
type: string
logical_backup_cpu_request:
pattern: ^(\d+m|\d+(\.\d{1,3})?)$
type: string
logical_backup_cronjob_environment_secret:
type: string
logical_backup_docker_image:
default: ghcr.io/zalando/postgres-operator/logical-backup:v1.15.1
type: string
logical_backup_failed_jobs_history_limit:
default: 3
format: int32
minimum: 0
type: integer
logical_backup_google_application_credentials:
type: string
logical_backup_job_prefix:
default: logical-backup-
type: string
logical_backup_memory_limit:
pattern: ^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$
type: string
logical_backup_memory_request:
pattern: ^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$
type: string
logical_backup_provider:
default: s3
enum:
- az
- gcs
- s3
type: string
logical_backup_s3_access_key_id:
type: string
logical_backup_s3_bucket:
type: string
logical_backup_s3_bucket_prefix:
type: string
logical_backup_s3_endpoint:
type: string
logical_backup_s3_region:
type: string
logical_backup_s3_retention_time:
type: string
logical_backup_s3_secret_access_key:
type: string
logical_backup_s3_sse:
type: string
logical_backup_schedule:
default: 30 00 * * *
pattern: ^(\d+|\*)(/\d+)?(\s+(\d+|\*)(/\d+)?){4}$
type: string
logical_backup_successful_jobs_history_limit:
default: 3
format: int32
minimum: 0
type: integer
logical_backup_ttl_seconds_after_finished:
default: 86400
format: int32
minimum: 0
type: integer
type: object
maintenance_windows:
type: array
major_version_upgrade:
description: MajorVersionUpgradeConfiguration defines how to execute
major version upgrades of Postgres.
properties:
major_version_upgrade_mode:
default: manual
enum:
- "off"
- manual
- full
type: string
major_version_upgrade_team_allow_list:
items:
type: string
type: array
minimal_major_version:
default: "14"
type: string
target_major_version:
default: "18"
type: string
type: object
max_instances:
default: -1
description: -1 = disabled
format: int32
minimum: -1
type: integer
min_instances:
default: -1
description: -1 = disabled
format: int32
minimum: -1
type: integer
patroni:
description: PatroniConfiguration defines configuration for Patroni
properties:
enable_patroni_failsafe_mode:
type: boolean
type: object
postgres_pod_resources:
description: PostgresPodResourcesDefaults defines the spec of default
resources
properties:
default_cpu_limit:
pattern: ^(\d+m|\d+(\.\d{1,3})?)$
type: string
default_cpu_request:
pattern: ^(\d+m|\d+(\.\d{1,3})?)$
type: string
default_memory_limit:
pattern: ^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$
type: string
default_memory_request:
pattern: ^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$
type: string
max_cpu_request:
pattern: ^(\d+m|\d+(\.\d{1,3})?)$
type: string
max_memory_request:
pattern: ^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$
type: string
min_cpu_limit:
pattern: ^(\d+m|\d+(\.\d{1,3})?)$
type: string
min_memory_limit:
pattern: ^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$
type: string
type: object
repair_period:
default: 5m
description: period between consecutive repair requests
format: int64
type: integer
resync_period:
default: 30m
description: period between consecutive sync requests
format: int64
type: integer
scalyr:
description: ScalyrConfiguration defines the configuration for ScalyrAPI
properties:
scalyr_api_key:
type: string
scalyr_cpu_limit:
default: "1"
pattern: ^(\d+m|\d+(\.\d{1,3})?)$
type: string
scalyr_cpu_request:
default: 100m
pattern: ^(\d+m|\d+(\.\d{1,3})?)$
type: string
scalyr_image:
type: string
scalyr_memory_limit:
default: 500Mi
pattern: ^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$
type: string
scalyr_memory_request:
default: 50Mi
pattern: ^(\d+(e\d+)?|\d+(\.\d+)?(e\d+)?[EPTGMK]i?)$
type: string
scalyr_server_url:
default: https://upload.eu.scalyr.com
type: string
type: object
set_memory_request_to_limit:
type: boolean
sidecar_docker_images:
additionalProperties:
type: string
type: object
sidecars:
type: object
x-kubernetes-preserve-unknown-fields: true
teams_api:
description: TeamsAPIConfiguration defines the configuration of TeamsAPI
properties:
enable_admin_role_for_users:
default: true
type: boolean
enable_postgres_team_crd:
default: true
type: boolean
enable_postgres_team_crd_superusers:
type: boolean
enable_team_member_deprecation:
type: boolean
enable_team_superuser:
type: boolean
enable_teams_api:
type: boolean
pam_configuration:
default: https://info.example.com/oauth2/tokeninfo?access_token=
uid realm=/employees
type: string
pam_role_name:
default: zalandos
type: string
postgres_superuser_teams:
items:
type: string
type: array
protected_role_names:
default: '["admin", "cron_admin"]'
items:
type: string
type: array
role_deletion_suffix:
default: _deleted
type: string
team_admin_role:
default: admin
type: string
team_api_role_configuration:
additionalProperties:
type: string
default:
log_statement: all
type: object
teams_api_url:
default: https://teams.example.com/api/
type: string
type: object
timeouts:
description: OperatorTimeouts defines the timeout of ResourceCheck,
PodWait, ReadyWait
properties:
patroni_api_check_interval:
default: 1s
description: interval between consecutive attempts of operator
calling the Patroni API
format: int64
type: integer
patroni_api_check_timeout:
default: 5s
description: timeout when waiting for successful response from
Patroni API
format: int64
type: integer
pod_deletion_wait_timeout:
default: 10m
description: timeout when waiting for the Postgres pods to be
deleted
format: int64
type: integer
pod_label_wait_timeout:
default: 10m
description: timeout when waiting for pod role and cluster labels
format: int64
type: integer
ready_wait_interval:
default: 4s
description: interval between consecutive attempts waiting for
postgresql CRD to be created
format: int64
type: integer
ready_wait_timeout:
default: 30s
description: timeout for the complete postgres CRD creation
format: int64
type: integer
resource_check_interval:
default: 3s
description: interval to wait between consecutive attempts to
check for some K8s resources
format: int64
type: integer
resource_check_timeout:
default: 10m
description: timeout when waiting for the presence of a certain
K8s resource
format: int64
type: integer
type: object
users:
description: PostgresUsersConfiguration defines the system users of
Postgres.
properties:
additional_owner_roles:
items:
type: string
type: array
enable_password_rotation:
type: boolean
password_rotation_interval:
default: 90
format: int32
type: integer
password_rotation_user_retention:
default: 120
format: int32
type: integer
replication_username:
default: standby
type: string
super_username:
default: postgres
type: string
type: object
workers:
default: 8
format: int32
minimum: 1
type: integer
type: object
kind:
description: |-
Kind is a string value representing the REST resource this object represents.
Servers may infer this from the endpoint the client submits requests to.
Cannot be updated.
In CamelCase.
More info: https://git.k8s.io/community/contributors/devel/sig-architecture/api-conventions.md#types-kinds
type: string
metadata:
type: object
required:
- configuration
- metadata
type: object
served: true
storage: true
subresources:
status: {}

View File

@ -428,11 +428,6 @@ func (in *OperatorConfigurationData) DeepCopyInto(out *OperatorConfigurationData
*out = new(bool) *out = new(bool)
**out = **in **out = **in
} }
if in.EnableCRDValidation != nil {
in, out := &in.EnableCRDValidation, &out.EnableCRDValidation
*out = new(bool)
**out = **in
}
if in.CRDCategories != nil { if in.CRDCategories != nil {
in, out := &in.CRDCategories, &out.CRDCategories in, out := &in.CRDCategories, &out.CRDCategories
*out = make([]string, len(*in)) *out = make([]string, len(*in))

View File

@ -31,7 +31,6 @@ func (c *Controller) importConfigurationFromCRD(fromCRD *acidv1.OperatorConfigur
// general config // general config
result.EnableCRDRegistration = util.CoalesceBool(fromCRD.EnableCRDRegistration, util.True()) result.EnableCRDRegistration = util.CoalesceBool(fromCRD.EnableCRDRegistration, util.True())
result.EnableCRDValidation = util.CoalesceBool(fromCRD.EnableCRDValidation, util.True())
result.CRDCategories = util.CoalesceStrArr(fromCRD.CRDCategories, []string{"all"}) result.CRDCategories = util.CoalesceStrArr(fromCRD.CRDCategories, []string{"all"})
result.EnableLazySpiloUpgrade = fromCRD.EnableLazySpiloUpgrade result.EnableLazySpiloUpgrade = fromCRD.EnableLazySpiloUpgrade
result.EnablePgVersionEnvVar = fromCRD.EnablePgVersionEnvVar result.EnablePgVersionEnvVar = fromCRD.EnablePgVersionEnvVar

View File

@ -103,7 +103,11 @@ func (c *Controller) createPostgresCRD() error {
} }
func (c *Controller) createConfigurationCRD() error { func (c *Controller) createConfigurationCRD() error {
return c.createOperatorCRD(acidv1.ConfigurationCRD(c.opConfig.CRDCategories)) crd, err := acidv1.OperatorConfigurationCRD(c.opConfig.CRDCategories)
if err != nil {
return fmt.Errorf("could not create OperatorConfiguration CRD object: %v", err)
}
return c.createOperatorCRD(crd)
} }
func readDecodedRole(s string) (*spec.PgUser, error) { func readDecodedRole(s string) (*spec.PgUser, error) {

View File

@ -32,18 +32,26 @@ import (
// fakeOperatorConfigurations implements OperatorConfigurationInterface // fakeOperatorConfigurations implements OperatorConfigurationInterface
type fakeOperatorConfigurations struct { type fakeOperatorConfigurations struct {
*gentype.FakeClient[*v1.OperatorConfiguration] *gentype.FakeClientWithList[*v1.OperatorConfiguration, *v1.OperatorConfigurationList]
Fake *FakeAcidV1 Fake *FakeAcidV1
} }
func newFakeOperatorConfigurations(fake *FakeAcidV1, namespace string) acidzalandov1.OperatorConfigurationInterface { func newFakeOperatorConfigurations(fake *FakeAcidV1, namespace string) acidzalandov1.OperatorConfigurationInterface {
return &fakeOperatorConfigurations{ return &fakeOperatorConfigurations{
gentype.NewFakeClient[*v1.OperatorConfiguration]( gentype.NewFakeClientWithList[*v1.OperatorConfiguration, *v1.OperatorConfigurationList](
fake.Fake, fake.Fake,
namespace, namespace,
v1.SchemeGroupVersion.WithResource("operatorconfigurations"), v1.SchemeGroupVersion.WithResource("operatorconfigurations"),
v1.SchemeGroupVersion.WithKind("OperatorConfiguration"), v1.SchemeGroupVersion.WithKind("OperatorConfiguration"),
func() *v1.OperatorConfiguration { return &v1.OperatorConfiguration{} }, func() *v1.OperatorConfiguration { return &v1.OperatorConfiguration{} },
func() *v1.OperatorConfigurationList { return &v1.OperatorConfigurationList{} },
func(dst, src *v1.OperatorConfigurationList) { dst.ListMeta = src.ListMeta },
func(list *v1.OperatorConfigurationList) []*v1.OperatorConfiguration {
return gentype.ToPointerSlice(list.Items)
},
func(list *v1.OperatorConfigurationList, items []*v1.OperatorConfiguration) {
list.Items = gentype.FromPointerSlice(items)
},
), ),
fake, fake,
} }

View File

@ -30,6 +30,8 @@ import (
acidzalandov1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1" acidzalandov1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
scheme "github.com/zalando/postgres-operator/pkg/generated/clientset/versioned/scheme" scheme "github.com/zalando/postgres-operator/pkg/generated/clientset/versioned/scheme"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
types "k8s.io/apimachinery/pkg/types"
watch "k8s.io/apimachinery/pkg/watch"
gentype "k8s.io/client-go/gentype" gentype "k8s.io/client-go/gentype"
) )
@ -41,24 +43,32 @@ type OperatorConfigurationsGetter interface {
// OperatorConfigurationInterface has methods to work with OperatorConfiguration resources. // OperatorConfigurationInterface has methods to work with OperatorConfiguration resources.
type OperatorConfigurationInterface interface { type OperatorConfigurationInterface interface {
Create(ctx context.Context, operatorConfiguration *acidzalandov1.OperatorConfiguration, opts metav1.CreateOptions) (*acidzalandov1.OperatorConfiguration, error)
Update(ctx context.Context, operatorConfiguration *acidzalandov1.OperatorConfiguration, opts metav1.UpdateOptions) (*acidzalandov1.OperatorConfiguration, error)
Delete(ctx context.Context, name string, opts metav1.DeleteOptions) error
DeleteCollection(ctx context.Context, opts metav1.DeleteOptions, listOpts metav1.ListOptions) error
Get(ctx context.Context, name string, opts metav1.GetOptions) (*acidzalandov1.OperatorConfiguration, error) Get(ctx context.Context, name string, opts metav1.GetOptions) (*acidzalandov1.OperatorConfiguration, error)
List(ctx context.Context, opts metav1.ListOptions) (*acidzalandov1.OperatorConfigurationList, error)
Watch(ctx context.Context, opts metav1.ListOptions) (watch.Interface, error)
Patch(ctx context.Context, name string, pt types.PatchType, data []byte, opts metav1.PatchOptions, subresources ...string) (result *acidzalandov1.OperatorConfiguration, err error)
OperatorConfigurationExpansion OperatorConfigurationExpansion
} }
// operatorConfigurations implements OperatorConfigurationInterface // operatorConfigurations implements OperatorConfigurationInterface
type operatorConfigurations struct { type operatorConfigurations struct {
*gentype.Client[*acidzalandov1.OperatorConfiguration] *gentype.ClientWithList[*acidzalandov1.OperatorConfiguration, *acidzalandov1.OperatorConfigurationList]
} }
// newOperatorConfigurations returns a OperatorConfigurations // newOperatorConfigurations returns a OperatorConfigurations
func newOperatorConfigurations(c *AcidV1Client, namespace string) *operatorConfigurations { func newOperatorConfigurations(c *AcidV1Client, namespace string) *operatorConfigurations {
return &operatorConfigurations{ return &operatorConfigurations{
gentype.NewClient[*acidzalandov1.OperatorConfiguration]( gentype.NewClientWithList[*acidzalandov1.OperatorConfiguration, *acidzalandov1.OperatorConfigurationList](
"operatorconfigurations", "operatorconfigurations",
c.RESTClient(), c.RESTClient(),
scheme.ParameterCodec, scheme.ParameterCodec,
namespace, namespace,
func() *acidzalandov1.OperatorConfiguration { return &acidzalandov1.OperatorConfiguration{} }, func() *acidzalandov1.OperatorConfiguration { return &acidzalandov1.OperatorConfiguration{} },
func() *acidzalandov1.OperatorConfigurationList { return &acidzalandov1.OperatorConfigurationList{} },
), ),
} }
} }

View File

@ -30,6 +30,8 @@ import (
// Interface provides access to all the informers in this group version. // Interface provides access to all the informers in this group version.
type Interface interface { type Interface interface {
// OperatorConfigurations returns a OperatorConfigurationInformer.
OperatorConfigurations() OperatorConfigurationInformer
// PostgresTeams returns a PostgresTeamInformer. // PostgresTeams returns a PostgresTeamInformer.
PostgresTeams() PostgresTeamInformer PostgresTeams() PostgresTeamInformer
// Postgresqls returns a PostgresqlInformer. // Postgresqls returns a PostgresqlInformer.
@ -47,6 +49,11 @@ func New(f internalinterfaces.SharedInformerFactory, namespace string, tweakList
return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions} return &version{factory: f, namespace: namespace, tweakListOptions: tweakListOptions}
} }
// OperatorConfigurations returns a OperatorConfigurationInformer.
func (v *version) OperatorConfigurations() OperatorConfigurationInformer {
return &operatorConfigurationInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}
}
// PostgresTeams returns a PostgresTeamInformer. // PostgresTeams returns a PostgresTeamInformer.
func (v *version) PostgresTeams() PostgresTeamInformer { func (v *version) PostgresTeams() PostgresTeamInformer {
return &postgresTeamInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions} return &postgresTeamInformer{factory: v.factory, namespace: v.namespace, tweakListOptions: v.tweakListOptions}

View File

@ -0,0 +1,96 @@
/*
Copyright 2026 Compose, Zalando SE
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
// Code generated by informer-gen. DO NOT EDIT.
package v1
import (
context "context"
time "time"
apisacidzalandov1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
versioned "github.com/zalando/postgres-operator/pkg/generated/clientset/versioned"
internalinterfaces "github.com/zalando/postgres-operator/pkg/generated/informers/externalversions/internalinterfaces"
acidzalandov1 "github.com/zalando/postgres-operator/pkg/generated/listers/acid.zalan.do/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
runtime "k8s.io/apimachinery/pkg/runtime"
watch "k8s.io/apimachinery/pkg/watch"
cache "k8s.io/client-go/tools/cache"
)
// OperatorConfigurationInformer provides access to a shared informer and lister for
// OperatorConfigurations.
type OperatorConfigurationInformer interface {
Informer() cache.SharedIndexInformer
Lister() acidzalandov1.OperatorConfigurationLister
}
type operatorConfigurationInformer struct {
factory internalinterfaces.SharedInformerFactory
tweakListOptions internalinterfaces.TweakListOptionsFunc
namespace string
}
// NewOperatorConfigurationInformer constructs a new informer for OperatorConfiguration type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewOperatorConfigurationInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers) cache.SharedIndexInformer {
return NewFilteredOperatorConfigurationInformer(client, namespace, resyncPeriod, indexers, nil)
}
// NewFilteredOperatorConfigurationInformer constructs a new informer for OperatorConfiguration type.
// Always prefer using an informer factory to get a shared informer instead of getting an independent
// one. This reduces memory footprint and number of connections to the server.
func NewFilteredOperatorConfigurationInformer(client versioned.Interface, namespace string, resyncPeriod time.Duration, indexers cache.Indexers, tweakListOptions internalinterfaces.TweakListOptionsFunc) cache.SharedIndexInformer {
return cache.NewSharedIndexInformer(
&cache.ListWatch{
ListFunc: func(options metav1.ListOptions) (runtime.Object, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.AcidV1().OperatorConfigurations(namespace).List(context.TODO(), options)
},
WatchFunc: func(options metav1.ListOptions) (watch.Interface, error) {
if tweakListOptions != nil {
tweakListOptions(&options)
}
return client.AcidV1().OperatorConfigurations(namespace).Watch(context.TODO(), options)
},
},
&apisacidzalandov1.OperatorConfiguration{},
resyncPeriod,
indexers,
)
}
func (f *operatorConfigurationInformer) defaultInformer(client versioned.Interface, resyncPeriod time.Duration) cache.SharedIndexInformer {
return NewFilteredOperatorConfigurationInformer(client, f.namespace, resyncPeriod, cache.Indexers{cache.NamespaceIndex: cache.MetaNamespaceIndexFunc}, f.tweakListOptions)
}
func (f *operatorConfigurationInformer) Informer() cache.SharedIndexInformer {
return f.factory.InformerFor(&apisacidzalandov1.OperatorConfiguration{}, f.defaultInformer)
}
func (f *operatorConfigurationInformer) Lister() acidzalandov1.OperatorConfigurationLister {
return acidzalandov1.NewOperatorConfigurationLister(f.Informer().GetIndexer())
}

View File

@ -60,6 +60,8 @@ func (f *genericInformer) Lister() cache.GenericLister {
func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) { func (f *sharedInformerFactory) ForResource(resource schema.GroupVersionResource) (GenericInformer, error) {
switch resource { switch resource {
// Group=acid.zalan.do, Version=v1 // Group=acid.zalan.do, Version=v1
case v1.SchemeGroupVersion.WithResource("operatorconfigurations"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Acid().V1().OperatorConfigurations().Informer()}, nil
case v1.SchemeGroupVersion.WithResource("postgresteams"): case v1.SchemeGroupVersion.WithResource("postgresteams"):
return &genericInformer{resource: resource.GroupResource(), informer: f.Acid().V1().PostgresTeams().Informer()}, nil return &genericInformer{resource: resource.GroupResource(), informer: f.Acid().V1().PostgresTeams().Informer()}, nil
case v1.SchemeGroupVersion.WithResource("postgresqls"): case v1.SchemeGroupVersion.WithResource("postgresqls"):

View File

@ -24,6 +24,14 @@ SOFTWARE.
package v1 package v1
// OperatorConfigurationListerExpansion allows custom methods to be added to
// OperatorConfigurationLister.
type OperatorConfigurationListerExpansion interface{}
// OperatorConfigurationNamespaceListerExpansion allows custom methods to be added to
// OperatorConfigurationNamespaceLister.
type OperatorConfigurationNamespaceListerExpansion interface{}
// PostgresTeamListerExpansion allows custom methods to be added to // PostgresTeamListerExpansion allows custom methods to be added to
// PostgresTeamLister. // PostgresTeamLister.
type PostgresTeamListerExpansion interface{} type PostgresTeamListerExpansion interface{}

View File

@ -0,0 +1,76 @@
/*
Copyright 2026 Compose, Zalando SE
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/
// Code generated by lister-gen. DO NOT EDIT.
package v1
import (
acidzalandov1 "github.com/zalando/postgres-operator/pkg/apis/acid.zalan.do/v1"
labels "k8s.io/apimachinery/pkg/labels"
listers "k8s.io/client-go/listers"
cache "k8s.io/client-go/tools/cache"
)
// OperatorConfigurationLister helps list OperatorConfigurations.
// All objects returned here must be treated as read-only.
type OperatorConfigurationLister interface {
// List lists all OperatorConfigurations in the indexer.
// Objects returned here must be treated as read-only.
List(selector labels.Selector) (ret []*acidzalandov1.OperatorConfiguration, err error)
// OperatorConfigurations returns an object that can list and get OperatorConfigurations.
OperatorConfigurations(namespace string) OperatorConfigurationNamespaceLister
OperatorConfigurationListerExpansion
}
// operatorConfigurationLister implements the OperatorConfigurationLister interface.
type operatorConfigurationLister struct {
listers.ResourceIndexer[*acidzalandov1.OperatorConfiguration]
}
// NewOperatorConfigurationLister returns a new OperatorConfigurationLister.
func NewOperatorConfigurationLister(indexer cache.Indexer) OperatorConfigurationLister {
return &operatorConfigurationLister{listers.New[*acidzalandov1.OperatorConfiguration](indexer, acidzalandov1.Resource("operatorconfiguration"))}
}
// OperatorConfigurations returns an object that can list and get OperatorConfigurations.
func (s *operatorConfigurationLister) OperatorConfigurations(namespace string) OperatorConfigurationNamespaceLister {
return operatorConfigurationNamespaceLister{listers.NewNamespaced[*acidzalandov1.OperatorConfiguration](s.ResourceIndexer, namespace)}
}
// OperatorConfigurationNamespaceLister helps list and get OperatorConfigurations.
// All objects returned here must be treated as read-only.
type OperatorConfigurationNamespaceLister interface {
// List lists all OperatorConfigurations in the indexer for a given namespace.
// Objects returned here must be treated as read-only.
List(selector labels.Selector) (ret []*acidzalandov1.OperatorConfiguration, err error)
// Get retrieves the OperatorConfiguration from the indexer for a given namespace and name.
// Objects returned here must be treated as read-only.
Get(name string) (*acidzalandov1.OperatorConfiguration, error)
OperatorConfigurationNamespaceListerExpansion
}
// operatorConfigurationNamespaceLister implements the OperatorConfigurationNamespaceLister
// interface.
type operatorConfigurationNamespaceLister struct {
listers.ResourceIndexer[*acidzalandov1.OperatorConfiguration]
}

View File

@ -19,7 +19,6 @@ type CRD struct {
ResyncPeriod time.Duration `name:"resync_period" default:"30m"` ResyncPeriod time.Duration `name:"resync_period" default:"30m"`
RepairPeriod time.Duration `name:"repair_period" default:"5m"` RepairPeriod time.Duration `name:"repair_period" default:"5m"`
EnableCRDRegistration *bool `name:"enable_crd_registration" default:"true"` EnableCRDRegistration *bool `name:"enable_crd_registration" default:"true"`
EnableCRDValidation *bool `name:"enable_crd_validation" default:"true"`
CRDCategories []string `name:"crd_categories" default:"all"` CRDCategories []string `name:"crd_categories" default:"all"`
} }