Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

K8SPG-574: add pg_repack to .spec.extensions.builtin #1102

Merged
merged 5 commits into from
Apr 2, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -8352,6 +8352,8 @@ spec:
properties:
pgAudit:
type: boolean
pgRepack:
type: boolean
pgStatMonitor:
type: boolean
pgStatStatements:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8066,6 +8066,8 @@ spec:
properties:
pg_audit:
type: boolean
pg_repack:
type: boolean
pg_stat_monitor:
type: boolean
pgvector:
Expand Down
2 changes: 2 additions & 0 deletions config/crd/bases/pgv2.percona.com_perconapgclusters.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8471,6 +8471,8 @@ spec:
properties:
pg_audit:
type: boolean
pg_repack:
type: boolean
pg_stat_monitor:
type: boolean
pgvector:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8312,6 +8312,8 @@ spec:
properties:
pgAudit:
type: boolean
pgRepack:
type: boolean
pgStatMonitor:
type: boolean
pgStatStatements:
Expand Down
4 changes: 4 additions & 0 deletions deploy/bundle.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8768,6 +8768,8 @@ spec:
properties:
pg_audit:
type: boolean
pg_repack:
type: boolean
pg_stat_monitor:
type: boolean
pgvector:
Expand Down Expand Up @@ -34002,6 +34004,8 @@ spec:
properties:
pgAudit:
type: boolean
pgRepack:
type: boolean
pgStatMonitor:
type: boolean
pgStatStatements:
Expand Down
1 change: 1 addition & 0 deletions deploy/cr.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,7 @@ spec:
# pg_stat_monitor: true
# pg_audit: true
# pgvector: false
# pg_repack: false
# custom:
# - name: pg_cron
# version: 1.6.1
4 changes: 4 additions & 0 deletions deploy/crd.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8768,6 +8768,8 @@ spec:
properties:
pg_audit:
type: boolean
pg_repack:
type: boolean
pg_stat_monitor:
type: boolean
pgvector:
Expand Down Expand Up @@ -34002,6 +34004,8 @@ spec:
properties:
pgAudit:
type: boolean
pgRepack:
type: boolean
pgStatMonitor:
type: boolean
pgStatStatements:
Expand Down
4 changes: 4 additions & 0 deletions deploy/cw-bundle.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8768,6 +8768,8 @@ spec:
properties:
pg_audit:
type: boolean
pg_repack:
type: boolean
pg_stat_monitor:
type: boolean
pgvector:
Expand Down Expand Up @@ -34002,6 +34004,8 @@ spec:
properties:
pgAudit:
type: boolean
pgRepack:
type: boolean
pgStatMonitor:
type: boolean
pgStatStatements:
Expand Down
27 changes: 20 additions & 7 deletions internal/controller/postgrescluster/postgres.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
"github.com/percona/percona-postgresql-operator/internal/logging"
"github.com/percona/percona-postgresql-operator/internal/naming"
"github.com/percona/percona-postgresql-operator/internal/pgaudit"
"github.com/percona/percona-postgresql-operator/internal/pgrepack"
"github.com/percona/percona-postgresql-operator/internal/pgstatmonitor"
"github.com/percona/percona-postgresql-operator/internal/pgstatstatements"
"github.com/percona/percona-postgresql-operator/internal/pgvector"
Expand Down Expand Up @@ -245,7 +246,7 @@ func (r *Reconciler) reconcilePostgresDatabases(

// Calculate a hash of the SQL that should be executed in PostgreSQL.
// K8SPG-375, K8SPG-577, K8SPG-699
var pgAuditOK, pgStatMonitorOK, pgStatStatementsOK, pgvectorOK, postgisInstallOK bool
var pgAuditOK, pgStatMonitorOK, pgStatStatementsOK, pgvectorOK, pgRepackOK, postgisInstallOK bool
create := func(ctx context.Context, exec postgres.Executor) error {
// validate version string before running it in database
_, err := gover.NewVersion(cluster.Labels[naming.LabelVersion])
Expand Down Expand Up @@ -319,6 +320,19 @@ func (r *Reconciler) reconcilePostgresDatabases(
}
}

// K8SPG-574
if cluster.Spec.Extensions.PGRepack {
if pgRepackOK = pgrepack.EnableInPostgreSQL(ctx, exec) == nil; !pgRepackOK {
r.Recorder.Event(cluster, corev1.EventTypeWarning, "pgRepackDisabled",
"Unable to install pg_repack")
}
} else {
if pgRepackOK = pgrepack.DisableInPostgreSQL(ctx, exec) == nil; !pgRepackOK {
r.Recorder.Event(cluster, corev1.EventTypeWarning, "pgRepackEnabled",
"Unable to disable pg_repack")
}
}

// Enabling PostGIS extensions is a one-way operation
// e.g., you can take a PostgresCluster and turn it into a PostGISCluster,
// but you cannot reverse the process, as that would potentially remove an extension
Expand Down Expand Up @@ -364,7 +378,7 @@ func (r *Reconciler) reconcilePostgresDatabases(
err = errors.WithStack(create(logging.NewContext(ctx, log), podExecutor))
}
// K8SPG-472
if err == nil && pgStatMonitorOK && pgAuditOK && pgvectorOK && postgisInstallOK {
if err == nil && pgStatMonitorOK && pgAuditOK && pgvectorOK && postgisInstallOK && pgRepackOK {
cluster.Status.DatabaseRevision = revision
}

Expand Down Expand Up @@ -659,7 +673,6 @@ func (r *Reconciler) reconcilePostgresDataVolume(
instanceSpec *v1beta1.PostgresInstanceSetSpec, instance *appsv1.StatefulSet,
clusterVolumes []corev1.PersistentVolumeClaim, sourceCluster *v1beta1.PostgresCluster,
) (*corev1.PersistentVolumeClaim, error) {

labelMap := map[string]string{
naming.LabelCluster: cluster.Name,
naming.LabelInstanceSet: instanceSpec.Name,
Expand Down Expand Up @@ -743,7 +756,8 @@ func (r *Reconciler) reconcilePostgresDataVolume(
// setVolumeSize compares the potential sizes from the instance spec, status
// and limit and sets the appropriate current value.
func (r *Reconciler) setVolumeSize(ctx context.Context, cluster *v1beta1.PostgresCluster,
pvc *corev1.PersistentVolumeClaim, instanceSpecName string) {
pvc *corev1.PersistentVolumeClaim, instanceSpecName string,
) {
log := logging.FromContext(ctx)

// Store the limit for this instance set. This value will not change below.
Expand Down Expand Up @@ -818,7 +832,6 @@ func (r *Reconciler) reconcileTablespaceVolumes(
instanceSpec *v1beta1.PostgresInstanceSetSpec, instance *appsv1.StatefulSet,
clusterVolumes []corev1.PersistentVolumeClaim,
) (tablespaceVolumes []*corev1.PersistentVolumeClaim, err error) {

if !feature.Enabled(ctx, feature.TablespaceVolumes) {
return
}
Expand Down Expand Up @@ -893,7 +906,6 @@ func (r *Reconciler) reconcilePostgresWALVolume(
instanceSpec *v1beta1.PostgresInstanceSetSpec, instance *appsv1.StatefulSet,
observed *Instance, clusterVolumes []corev1.PersistentVolumeClaim,
) (*corev1.PersistentVolumeClaim, error) {

labelMap := map[string]string{
naming.LabelCluster: cluster.Name,
naming.LabelInstanceSet: instanceSpec.Name,
Expand Down Expand Up @@ -992,7 +1004,8 @@ func (r *Reconciler) reconcilePostgresWALVolume(
// DatabaseInitSQL is defined, the function will find the primary pod and run
// SQL from the defined ConfigMap
func (r *Reconciler) reconcileDatabaseInitSQL(ctx context.Context,
cluster *v1beta1.PostgresCluster, instances *observedInstances) error {
cluster *v1beta1.PostgresCluster, instances *observedInstances,
) error {
log := logging.FromContext(ctx)

// Spec is not defined, unset status and return
Expand Down
39 changes: 39 additions & 0 deletions internal/pgrepack/postgres.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package pgrepack

import (
"context"

"github.com/percona/percona-postgresql-operator/internal/logging"
"github.com/percona/percona-postgresql-operator/internal/postgres"
)

// EnableInPostgreSQL installs pg_repack triggers into every database.
func EnableInPostgreSQL(ctx context.Context, exec postgres.Executor) error {
log := logging.FromContext(ctx)

stdout, stderr, err := exec.ExecInAllDatabases(ctx,
`SET client_min_messages = WARNING; CREATE EXTENSION IF NOT EXISTS pg_repack; ALTER EXTENSION pg_repack UPDATE;`,
map[string]string{
"ON_ERROR_STOP": "on", // Abort when any one command fails.
"QUIET": "on", // Do not print successful commands to stdout.
})

log.V(1).Info("enabled pg_repack", "stdout", stdout, "stderr", stderr)

return err
}

func DisableInPostgreSQL(ctx context.Context, exec postgres.Executor) error {
log := logging.FromContext(ctx)

stdout, stderr, err := exec.ExecInAllDatabases(ctx,
`SET client_min_messages = WARNING; DROP EXTENSION IF EXISTS pg_repack;`,
map[string]string{
"ON_ERROR_STOP": "on", // Abort when any one command fails.
"QUIET": "on", // Do not print successful commands to stdout.
})

log.V(1).Info("disabled pg_repack", "stdout", stdout, "stderr", stderr)

return err
}
61 changes: 61 additions & 0 deletions internal/pgrepack/postgres_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
package pgrepack

import (
"context"
"errors"
"io"
"strings"
"testing"

"gotest.tools/v3/assert"
)

func TestEnableInPostgreSQL(t *testing.T) {
expected := errors.New("whoops")
exec := func(
_ context.Context, stdin io.Reader, stdout, stderr io.Writer, command ...string,
) error {
assert.Assert(t, stdout != nil, "should capture stdout")
assert.Assert(t, stderr != nil, "should capture stderr")

assert.Assert(t, strings.Contains(strings.Join(command, "\n"),
`SELECT datname FROM pg_catalog.pg_database`,
), "expected all databases and templates")

b, err := io.ReadAll(stdin)
assert.NilError(t, err)
assert.Equal(t, string(b), strings.Trim(`
SET client_min_messages = WARNING; CREATE EXTENSION IF NOT EXISTS pg_repack; ALTER EXTENSION pg_repack UPDATE;
`, "\t\n"))

return expected
}

ctx := context.Background()
assert.Equal(t, expected, EnableInPostgreSQL(ctx, exec))
}

func TestDisableInPostgreSQL(t *testing.T) {
expected := errors.New("whoops")
exec := func(
_ context.Context, stdin io.Reader, stdout, stderr io.Writer, command ...string,
) error {
assert.Assert(t, stdout != nil, "should capture stdout")
assert.Assert(t, stderr != nil, "should capture stderr")

assert.Assert(t, strings.Contains(strings.Join(command, "\n"),
`SELECT datname FROM pg_catalog.pg_database`,
), "expected all databases and templates")

b, err := io.ReadAll(stdin)
assert.NilError(t, err)
assert.Equal(t, string(b), strings.Trim(`
SET client_min_messages = WARNING; DROP EXTENSION IF EXISTS pg_repack;
`, "\t\n"))

return expected
}

ctx := context.Background()
assert.Equal(t, expected, DisableInPostgreSQL(ctx, exec))
}
5 changes: 5 additions & 0 deletions pkg/apis/pgv2.percona.com/v2/perconapgcluster_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,9 @@ func (cr *PerconaPGCluster) Default() {
if cr.Spec.Extensions.BuiltIn.PGVector == nil {
cr.Spec.Extensions.BuiltIn.PGVector = &f
}
if cr.Spec.Extensions.BuiltIn.PGRepack == nil {
cr.Spec.Extensions.BuiltIn.PGRepack = &f
}

if cr.CompareVersion("2.6.0") >= 0 && cr.Spec.AutoCreateUserSchema == nil {
cr.Spec.AutoCreateUserSchema = &t
Expand Down Expand Up @@ -352,6 +355,7 @@ func (cr *PerconaPGCluster) ToCrunchy(ctx context.Context, postgresCluster *crun
postgresCluster.Spec.Extensions.PGStatMonitor = *cr.Spec.Extensions.BuiltIn.PGStatMonitor
postgresCluster.Spec.Extensions.PGAudit = *cr.Spec.Extensions.BuiltIn.PGAudit
postgresCluster.Spec.Extensions.PGVector = *cr.Spec.Extensions.BuiltIn.PGVector
postgresCluster.Spec.Extensions.PGRepack = *cr.Spec.Extensions.BuiltIn.PGRepack

postgresCluster.Spec.TLSOnly = cr.Spec.TLSOnly

Expand Down Expand Up @@ -596,6 +600,7 @@ type BuiltInExtensionsSpec struct {
PGStatMonitor *bool `json:"pg_stat_monitor,omitempty"`
PGAudit *bool `json:"pg_audit,omitempty"`
PGVector *bool `json:"pgvector,omitempty"`
PGRepack *bool `json:"pg_repack,omitempty"`
}

type ExtensionsSpec struct {
Expand Down
5 changes: 5 additions & 0 deletions pkg/apis/pgv2.percona.com/v2/zz_generated.deepcopy.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ type ExtensionsSpec struct {
PGAudit bool `json:"pgAudit,omitempty"`
PGStatStatements bool `json:"pgStatStatements,omitempty"`
PGVector bool `json:"pgvector,omitempty"`
PGRepack bool `json:"pgRepack,omitempty"`
}

// DataSource defines data sources for a new PostgresCluster.
Expand Down
Loading