From e156d7afa3b4a0f6cda9a5cb03db3d3ab0846b9b Mon Sep 17 00:00:00 2001 From: Tamal Saha Date: Fri, 15 Mar 2024 07:03:54 -0700 Subject: [PATCH] Add ReplicationSlot support for Postgres (#1142) Signed-off-by: Tamal Saha Signed-off-by: souravbiswassanto Co-authored-by: souravbiswassanto --- apis/kubedb/v1alpha2/openapi_generated.go | 46 ++++++++++++++++++- apis/kubedb/v1alpha2/postgres_helpers.go | 36 +++++++++++++++ apis/kubedb/v1alpha2/postgres_types.go | 22 +++++++++ apis/kubedb/v1alpha2/zz_generated.deepcopy.go | 36 +++++++++++++++ crds/kubedb.com_postgreses.yaml | 16 +++++++ openapi/swagger.json | 27 +++++++++++ 6 files changed, 182 insertions(+), 1 deletion(-) diff --git a/apis/kubedb/v1alpha2/openapi_generated.go b/apis/kubedb/v1alpha2/openapi_generated.go index 019e568d5f..1cfc496c12 100644 --- a/apis/kubedb/v1alpha2/openapi_generated.go +++ b/apis/kubedb/v1alpha2/openapi_generated.go @@ -558,6 +558,7 @@ func GetOpenAPIDefinitions(ref common.ReferenceCallback) map[string]common.OpenA "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.Postgres": schema_apimachinery_apis_kubedb_v1alpha2_Postgres(ref), "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.PostgresList": schema_apimachinery_apis_kubedb_v1alpha2_PostgresList(ref), "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.PostgresRef": schema_apimachinery_apis_kubedb_v1alpha2_PostgresRef(ref), + "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.PostgresReplication": schema_apimachinery_apis_kubedb_v1alpha2_PostgresReplication(ref), "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.PostgresServiceRef": schema_apimachinery_apis_kubedb_v1alpha2_PostgresServiceRef(ref), "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.PostgresSpec": schema_apimachinery_apis_kubedb_v1alpha2_PostgresSpec(ref), "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.PostgresStatus": schema_apimachinery_apis_kubedb_v1alpha2_PostgresStatus(ref), @@ -28608,6 +28609,44 @@ func schema_apimachinery_apis_kubedb_v1alpha2_PostgresRef(ref common.ReferenceCa } } +func schema_apimachinery_apis_kubedb_v1alpha2_PostgresReplication(ref common.ReferenceCallback) common.OpenAPIDefinition { + return common.OpenAPIDefinition{ + Schema: spec.Schema{ + SchemaProps: spec.SchemaProps{ + Type: []string{"object"}, + Properties: map[string]spec.Schema{ + "walLimitPolicy": { + SchemaProps: spec.SchemaProps{ + Default: "", + Type: []string{"string"}, + Format: "", + }, + }, + "walKeepSize": { + SchemaProps: spec.SchemaProps{ + Type: []string{"integer"}, + Format: "int32", + }, + }, + "walKeepSegment": { + SchemaProps: spec.SchemaProps{ + Type: []string{"integer"}, + Format: "int32", + }, + }, + "maxSlotWALKeepSize": { + SchemaProps: spec.SchemaProps{ + Type: []string{"integer"}, + Format: "int32", + }, + }, + }, + Required: []string{"walLimitPolicy"}, + }, + }, + } +} + func schema_apimachinery_apis_kubedb_v1alpha2_PostgresServiceRef(ref common.ReferenceCallback) common.OpenAPIDefinition { return common.OpenAPIDefinition{ Schema: spec.Schema{ @@ -28830,12 +28869,17 @@ func schema_apimachinery_apis_kubedb_v1alpha2_PostgresSpec(ref common.ReferenceC Ref: ref("kubedb.dev/apimachinery/apis/kubedb/v1alpha2.ArbiterSpec"), }, }, + "replication": { + SchemaProps: spec.SchemaProps{ + Ref: ref("kubedb.dev/apimachinery/apis/kubedb/v1alpha2.PostgresReplication"), + }, + }, }, Required: []string{"version"}, }, }, Dependencies: []string{ - "k8s.io/api/core/v1.LocalObjectReference", "k8s.io/api/core/v1.PersistentVolumeClaimSpec", "kmodules.xyz/client-go/api/v1.HealthCheckSpec", "kmodules.xyz/client-go/api/v1.TLSConfig", "kmodules.xyz/monitoring-agent-api/api/v1.AgentSpec", "kmodules.xyz/offshoot-api/api/v1.PodTemplateSpec", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.AllowedConsumers", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.ArbiterSpec", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.Archiver", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.AutoOpsSpec", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.CoordinatorSpec", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.InitSpec", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.NamedServiceTemplateSpec", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.PostgreLeaderElectionConfig", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.RemoteReplicaSpec", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.SecretReference"}, + "k8s.io/api/core/v1.LocalObjectReference", "k8s.io/api/core/v1.PersistentVolumeClaimSpec", "kmodules.xyz/client-go/api/v1.HealthCheckSpec", "kmodules.xyz/client-go/api/v1.TLSConfig", "kmodules.xyz/monitoring-agent-api/api/v1.AgentSpec", "kmodules.xyz/offshoot-api/api/v1.PodTemplateSpec", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.AllowedConsumers", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.ArbiterSpec", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.Archiver", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.AutoOpsSpec", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.CoordinatorSpec", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.InitSpec", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.NamedServiceTemplateSpec", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.PostgreLeaderElectionConfig", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.PostgresReplication", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.RemoteReplicaSpec", "kubedb.dev/apimachinery/apis/kubedb/v1alpha2.SecretReference"}, } } diff --git a/apis/kubedb/v1alpha2/postgres_helpers.go b/apis/kubedb/v1alpha2/postgres_helpers.go index 00d193cc88..8fcbf433c7 100644 --- a/apis/kubedb/v1alpha2/postgres_helpers.go +++ b/apis/kubedb/v1alpha2/postgres_helpers.go @@ -26,6 +26,8 @@ import ( "kubedb.dev/apimachinery/apis/kubedb" "kubedb.dev/apimachinery/crds" + "github.com/Masterminds/semver/v3" + "github.com/pkg/errors" promapi "github.com/prometheus-operator/prometheus-operator/pkg/apis/monitoring/v1" "gomodules.xyz/pointer" core "k8s.io/api/core/v1" @@ -261,6 +263,7 @@ func (p *Postgres) SetDefaults(postgresVersion *catalog.PostgresVersion, topolog // So that /var/pv directory have the group permission for the RunAsGroup user GID. // Otherwise, We will get write permission denied. p.Spec.PodTemplate.Spec.SecurityContext.FSGroup = p.Spec.PodTemplate.Spec.ContainerSecurityContext.RunAsGroup + p.SetDefaultReplicationMode(postgresVersion) p.SetArbiterDefault() p.SetTLSDefaults() p.SetHealthCheckerDefaults() @@ -278,6 +281,39 @@ func (p *Postgres) SetDefaults(postgresVersion *catalog.PostgresVersion, topolog } } +func getMajorPgVersion(postgresVersion *catalog.PostgresVersion) (uint64, error) { + ver, err := semver.NewVersion(postgresVersion.Spec.Version) + if err != nil { + return 0, errors.Wrap(err, "Failed to get postgres major.") + } + return ver.Major(), nil +} + +// SetDefaultReplicationMode set the default replication mode. +// Replication slot will be prioritized if no WalLimitPolicy is mentioned +func (p *Postgres) SetDefaultReplicationMode(postgresVersion *catalog.PostgresVersion) { + majorVersion, _ := getMajorPgVersion(postgresVersion) + if p.Spec.Replication == nil { + p.Spec.Replication = &PostgresReplication{} + } + if p.Spec.Replication.WALLimitPolicy == "" { + if majorVersion <= uint64(12) { + p.Spec.Replication.WALLimitPolicy = WALKeepSegment + } else { + p.Spec.Replication.WALLimitPolicy = WALKeepSize + } + } + if p.Spec.Replication.WALLimitPolicy == WALKeepSegment && p.Spec.Replication.WalKeepSegment == nil { + p.Spec.Replication.WalKeepSegment = pointer.Int32P(64) + } + if p.Spec.Replication.WALLimitPolicy == WALKeepSize && p.Spec.Replication.WalKeepSizeInMegaBytes == nil { + p.Spec.Replication.WalKeepSizeInMegaBytes = pointer.Int32P(1024) + } + if p.Spec.Replication.WALLimitPolicy == ReplicationSlot && p.Spec.Replication.MaxSlotWALKeepSizeInMegaBytes == nil { + p.Spec.Replication.MaxSlotWALKeepSizeInMegaBytes = pointer.Int32P(-1) + } +} + func (p *Postgres) SetArbiterDefault() { if p.Spec.Arbiter == nil { p.Spec.Arbiter = &ArbiterSpec{ diff --git a/apis/kubedb/v1alpha2/postgres_types.go b/apis/kubedb/v1alpha2/postgres_types.go index 1b3f376153..67a9f1c518 100644 --- a/apis/kubedb/v1alpha2/postgres_types.go +++ b/apis/kubedb/v1alpha2/postgres_types.go @@ -164,6 +164,28 @@ type PostgresSpec struct { // Arbiter controls spec for arbiter pods // +optional Arbiter *ArbiterSpec `json:"arbiter,omitempty"` + + // +optional + Replication *PostgresReplication `json:"replication,omitempty"` +} + +type WALLimitPolicy string + +const ( + WALKeepSize WALLimitPolicy = "WALKeepSize" + ReplicationSlot WALLimitPolicy = "ReplicationSlot" + WALKeepSegment WALLimitPolicy = "WALKeepSegment" +) + +type PostgresReplication struct { + WALLimitPolicy WALLimitPolicy `json:"walLimitPolicy"` + + // +optional + WalKeepSizeInMegaBytes *int32 `json:"walKeepSize,omitempty"` + // +optional + WalKeepSegment *int32 `json:"walKeepSegment,omitempty"` + // +optional + MaxSlotWALKeepSizeInMegaBytes *int32 `json:"maxSlotWALKeepSize,omitempty"` } type ArbiterSpec struct { diff --git a/apis/kubedb/v1alpha2/zz_generated.deepcopy.go b/apis/kubedb/v1alpha2/zz_generated.deepcopy.go index 902842860a..3d2697dbad 100644 --- a/apis/kubedb/v1alpha2/zz_generated.deepcopy.go +++ b/apis/kubedb/v1alpha2/zz_generated.deepcopy.go @@ -3513,6 +3513,37 @@ func (in *PostgresRef) DeepCopy() *PostgresRef { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *PostgresReplication) DeepCopyInto(out *PostgresReplication) { + *out = *in + if in.WalKeepSizeInMegaBytes != nil { + in, out := &in.WalKeepSizeInMegaBytes, &out.WalKeepSizeInMegaBytes + *out = new(int32) + **out = **in + } + if in.WalKeepSegment != nil { + in, out := &in.WalKeepSegment, &out.WalKeepSegment + *out = new(int32) + **out = **in + } + if in.MaxSlotWALKeepSizeInMegaBytes != nil { + in, out := &in.MaxSlotWALKeepSizeInMegaBytes, &out.MaxSlotWALKeepSizeInMegaBytes + *out = new(int32) + **out = **in + } + return +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new PostgresReplication. +func (in *PostgresReplication) DeepCopy() *PostgresReplication { + if in == nil { + return nil + } + out := new(PostgresReplication) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *PostgresServiceRef) DeepCopyInto(out *PostgresServiceRef) { *out = *in @@ -3618,6 +3649,11 @@ func (in *PostgresSpec) DeepCopyInto(out *PostgresSpec) { *out = new(ArbiterSpec) (*in).DeepCopyInto(*out) } + if in.Replication != nil { + in, out := &in.Replication, &out.Replication + *out = new(PostgresReplication) + (*in).DeepCopyInto(*out) + } return } diff --git a/crds/kubedb.com_postgreses.yaml b/crds/kubedb.com_postgreses.yaml index 92c34845a7..54e9d33391 100644 --- a/crds/kubedb.com_postgreses.yaml +++ b/crds/kubedb.com_postgreses.yaml @@ -4027,6 +4027,22 @@ spec: replicas: format: int32 type: integer + replication: + properties: + maxSlotWALKeepSize: + format: int32 + type: integer + walKeepSegment: + format: int32 + type: integer + walKeepSize: + format: int32 + type: integer + walLimitPolicy: + type: string + required: + - walLimitPolicy + type: object serviceTemplates: items: properties: diff --git a/openapi/swagger.json b/openapi/swagger.json index 831dc1ede5..03aaff389b 100644 --- a/openapi/swagger.json +++ b/openapi/swagger.json @@ -25362,6 +25362,30 @@ } ] }, + "dev.kubedb.apimachinery.apis.kubedb.v1alpha2.PostgresReplication": { + "type": "object", + "required": [ + "walLimitPolicy" + ], + "properties": { + "maxSlotWALKeepSize": { + "type": "integer", + "format": "int32" + }, + "walKeepSegment": { + "type": "integer", + "format": "int32" + }, + "walKeepSize": { + "type": "integer", + "format": "int32" + }, + "walLimitPolicy": { + "type": "string", + "default": "" + } + } + }, "dev.kubedb.apimachinery.apis.kubedb.v1alpha2.PostgresSpec": { "type": "object", "required": [ @@ -25444,6 +25468,9 @@ "type": "integer", "format": "int32" }, + "replication": { + "$ref": "#/definitions/dev.kubedb.apimachinery.apis.kubedb.v1alpha2.PostgresReplication" + }, "serviceTemplates": { "description": "ServiceTemplates is an optional configuration for services used to expose database", "type": "array",