Skip to content

Commit 3b7fc81

Browse files
committed
K8SPG-574: add pg_repack to .spec.extensions.builtin`
https://perconadev.atlassian.net/browse/K8SPG-574
1 parent 94252cc commit 3b7fc81

File tree

14 files changed

+149
-7
lines changed

14 files changed

+149
-7
lines changed

build/crd/crunchy/generated/postgres-operator.crunchydata.com_postgresclusters.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -8352,6 +8352,8 @@ spec:
83528352
properties:
83538353
pgAudit:
83548354
type: boolean
8355+
pgRepack:
8356+
type: boolean
83558357
pgStatMonitor:
83568358
type: boolean
83578359
pgStatStatements:

build/crd/percona/generated/pgv2.percona.com_perconapgclusters.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -8066,6 +8066,8 @@ spec:
80668066
properties:
80678067
pg_audit:
80688068
type: boolean
8069+
pg_repack:
8070+
type: boolean
80698071
pg_stat_monitor:
80708072
type: boolean
80718073
pgvector:

config/crd/bases/pgv2.percona.com_perconapgclusters.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -8471,6 +8471,8 @@ spec:
84718471
properties:
84728472
pg_audit:
84738473
type: boolean
8474+
pg_repack:
8475+
type: boolean
84748476
pg_stat_monitor:
84758477
type: boolean
84768478
pgvector:

config/crd/bases/postgres-operator.crunchydata.com_postgresclusters.yaml

+2
Original file line numberDiff line numberDiff line change
@@ -8312,6 +8312,8 @@ spec:
83128312
properties:
83138313
pgAudit:
83148314
type: boolean
8315+
pgRepack:
8316+
type: boolean
83158317
pgStatMonitor:
83168318
type: boolean
83178319
pgStatStatements:

deploy/bundle.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -8764,6 +8764,8 @@ spec:
87648764
properties:
87658765
pg_audit:
87668766
type: boolean
8767+
pg_repack:
8768+
type: boolean
87678769
pg_stat_monitor:
87688770
type: boolean
87698771
pgvector:
@@ -33992,6 +33994,8 @@ spec:
3399233994
properties:
3399333995
pgAudit:
3399433996
type: boolean
33997+
pgRepack:
33998+
type: boolean
3399533999
pgStatMonitor:
3399634000
type: boolean
3399734001
pgStatStatements:

deploy/cr.yaml

+1
Original file line numberDiff line numberDiff line change
@@ -502,6 +502,7 @@ spec:
502502
# pg_stat_monitor: true
503503
# pg_audit: true
504504
# pgvector: false
505+
# pg_repack: false
505506
# custom:
506507
# - name: pg_cron
507508
# version: 1.6.1

deploy/crd.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -8764,6 +8764,8 @@ spec:
87648764
properties:
87658765
pg_audit:
87668766
type: boolean
8767+
pg_repack:
8768+
type: boolean
87678769
pg_stat_monitor:
87688770
type: boolean
87698771
pgvector:
@@ -33992,6 +33994,8 @@ spec:
3399233994
properties:
3399333995
pgAudit:
3399433996
type: boolean
33997+
pgRepack:
33998+
type: boolean
3399533999
pgStatMonitor:
3399634000
type: boolean
3399734001
pgStatStatements:

deploy/cw-bundle.yaml

+4
Original file line numberDiff line numberDiff line change
@@ -8764,6 +8764,8 @@ spec:
87648764
properties:
87658765
pg_audit:
87668766
type: boolean
8767+
pg_repack:
8768+
type: boolean
87678769
pg_stat_monitor:
87688770
type: boolean
87698771
pgvector:
@@ -33992,6 +33994,8 @@ spec:
3399233994
properties:
3399333995
pgAudit:
3399433996
type: boolean
33997+
pgRepack:
33998+
type: boolean
3399533999
pgStatMonitor:
3399634000
type: boolean
3399734001
pgStatStatements:

internal/controller/postgrescluster/postgres.go

+20-7
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ import (
3030
"github.com/percona/percona-postgresql-operator/internal/logging"
3131
"github.com/percona/percona-postgresql-operator/internal/naming"
3232
"github.com/percona/percona-postgresql-operator/internal/pgaudit"
33+
"github.com/percona/percona-postgresql-operator/internal/pgrepack"
3334
"github.com/percona/percona-postgresql-operator/internal/pgstatmonitor"
3435
"github.com/percona/percona-postgresql-operator/internal/pgstatstatements"
3536
"github.com/percona/percona-postgresql-operator/internal/pgvector"
@@ -245,7 +246,7 @@ func (r *Reconciler) reconcilePostgresDatabases(
245246

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

323+
// K8SPG-574
324+
if cluster.Spec.Extensions.PGRepack {
325+
if pgRepackOK = pgrepack.EnableInPostgreSQL(ctx, exec) == nil; !pgRepackOK {
326+
r.Recorder.Event(cluster, corev1.EventTypeWarning, "pgRepackDisabled",
327+
"Unable to install pg_repack")
328+
}
329+
} else {
330+
if pgRepackOK = pgrepack.DisableInPostgreSQL(ctx, exec) == nil; !pgRepackOK {
331+
r.Recorder.Event(cluster, corev1.EventTypeWarning, "pgRepackEnabled",
332+
"Unable to disable pg_repack")
333+
}
334+
}
335+
322336
// Enabling PostGIS extensions is a one-way operation
323337
// e.g., you can take a PostgresCluster and turn it into a PostGISCluster,
324338
// but you cannot reverse the process, as that would potentially remove an extension
@@ -364,7 +378,7 @@ func (r *Reconciler) reconcilePostgresDatabases(
364378
err = errors.WithStack(create(logging.NewContext(ctx, log), podExecutor))
365379
}
366380
// K8SPG-472
367-
if err == nil && pgStatMonitorOK && pgAuditOK && pgvectorOK && postgisInstallOK {
381+
if err == nil && pgStatMonitorOK && pgAuditOK && pgvectorOK && postgisInstallOK && pgRepackOK {
368382
cluster.Status.DatabaseRevision = revision
369383
}
370384

@@ -659,7 +673,6 @@ func (r *Reconciler) reconcilePostgresDataVolume(
659673
instanceSpec *v1beta1.PostgresInstanceSetSpec, instance *appsv1.StatefulSet,
660674
clusterVolumes []corev1.PersistentVolumeClaim, sourceCluster *v1beta1.PostgresCluster,
661675
) (*corev1.PersistentVolumeClaim, error) {
662-
663676
labelMap := map[string]string{
664677
naming.LabelCluster: cluster.Name,
665678
naming.LabelInstanceSet: instanceSpec.Name,
@@ -743,7 +756,8 @@ func (r *Reconciler) reconcilePostgresDataVolume(
743756
// setVolumeSize compares the potential sizes from the instance spec, status
744757
// and limit and sets the appropriate current value.
745758
func (r *Reconciler) setVolumeSize(ctx context.Context, cluster *v1beta1.PostgresCluster,
746-
pvc *corev1.PersistentVolumeClaim, instanceSpecName string) {
759+
pvc *corev1.PersistentVolumeClaim, instanceSpecName string,
760+
) {
747761
log := logging.FromContext(ctx)
748762

749763
// Store the limit for this instance set. This value will not change below.
@@ -818,7 +832,6 @@ func (r *Reconciler) reconcileTablespaceVolumes(
818832
instanceSpec *v1beta1.PostgresInstanceSetSpec, instance *appsv1.StatefulSet,
819833
clusterVolumes []corev1.PersistentVolumeClaim,
820834
) (tablespaceVolumes []*corev1.PersistentVolumeClaim, err error) {
821-
822835
if !feature.Enabled(ctx, feature.TablespaceVolumes) {
823836
return
824837
}
@@ -893,7 +906,6 @@ func (r *Reconciler) reconcilePostgresWALVolume(
893906
instanceSpec *v1beta1.PostgresInstanceSetSpec, instance *appsv1.StatefulSet,
894907
observed *Instance, clusterVolumes []corev1.PersistentVolumeClaim,
895908
) (*corev1.PersistentVolumeClaim, error) {
896-
897909
labelMap := map[string]string{
898910
naming.LabelCluster: cluster.Name,
899911
naming.LabelInstanceSet: instanceSpec.Name,
@@ -992,7 +1004,8 @@ func (r *Reconciler) reconcilePostgresWALVolume(
9921004
// DatabaseInitSQL is defined, the function will find the primary pod and run
9931005
// SQL from the defined ConfigMap
9941006
func (r *Reconciler) reconcileDatabaseInitSQL(ctx context.Context,
995-
cluster *v1beta1.PostgresCluster, instances *observedInstances) error {
1007+
cluster *v1beta1.PostgresCluster, instances *observedInstances,
1008+
) error {
9961009
log := logging.FromContext(ctx)
9971010

9981011
// Spec is not defined, unset status and return

internal/pgrepack/postgres.go

+39
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package pgrepack
2+
3+
import (
4+
"context"
5+
6+
"github.com/percona/percona-postgresql-operator/internal/logging"
7+
"github.com/percona/percona-postgresql-operator/internal/postgres"
8+
)
9+
10+
// EnableInPostgreSQL installs pg_repack triggers into every database.
11+
func EnableInPostgreSQL(ctx context.Context, exec postgres.Executor) error {
12+
log := logging.FromContext(ctx)
13+
14+
stdout, stderr, err := exec.ExecInAllDatabases(ctx,
15+
`SET client_min_messages = WARNING; CREATE EXTENSION IF NOT EXISTS pg_repack; ALTER EXTENSION pg_repack UPDATE;`,
16+
map[string]string{
17+
"ON_ERROR_STOP": "on", // Abort when any one command fails.
18+
"QUIET": "on", // Do not print successful commands to stdout.
19+
})
20+
21+
log.V(1).Info("enabled pg_repack", "stdout", stdout, "stderr", stderr)
22+
23+
return err
24+
}
25+
26+
func DisableInPostgreSQL(ctx context.Context, exec postgres.Executor) error {
27+
log := logging.FromContext(ctx)
28+
29+
stdout, stderr, err := exec.ExecInAllDatabases(ctx,
30+
`SET client_min_messages = WARNING; DROP EXTENSION IF EXISTS pg_repack;`,
31+
map[string]string{
32+
"ON_ERROR_STOP": "on", // Abort when any one command fails.
33+
"QUIET": "on", // Do not print successful commands to stdout.
34+
})
35+
36+
log.V(1).Info("disabled pg_repack", "stdout", stdout, "stderr", stderr)
37+
38+
return err
39+
}

internal/pgrepack/postgres_test.go

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package pgrepack
2+
3+
import (
4+
"context"
5+
"errors"
6+
"io"
7+
"strings"
8+
"testing"
9+
10+
"gotest.tools/v3/assert"
11+
)
12+
13+
func TestEnableInPostgreSQL(t *testing.T) {
14+
expected := errors.New("whoops")
15+
exec := func(
16+
_ context.Context, stdin io.Reader, stdout, stderr io.Writer, command ...string,
17+
) error {
18+
assert.Assert(t, stdout != nil, "should capture stdout")
19+
assert.Assert(t, stderr != nil, "should capture stderr")
20+
21+
assert.Assert(t, strings.Contains(strings.Join(command, "\n"),
22+
`SELECT datname FROM pg_catalog.pg_database`,
23+
), "expected all databases and templates")
24+
25+
b, err := io.ReadAll(stdin)
26+
assert.NilError(t, err)
27+
assert.Equal(t, string(b), strings.Trim(`
28+
SET client_min_messages = WARNING; CREATE EXTENSION IF NOT EXISTS pg_repack; ALTER EXTENSION pg_repack UPDATE;
29+
`, "\t\n"))
30+
31+
return expected
32+
}
33+
34+
ctx := context.Background()
35+
assert.Equal(t, expected, EnableInPostgreSQL(ctx, exec))
36+
}
37+
38+
func TestDisableInPostgreSQL(t *testing.T) {
39+
expected := errors.New("whoops")
40+
exec := func(
41+
_ context.Context, stdin io.Reader, stdout, stderr io.Writer, command ...string,
42+
) error {
43+
assert.Assert(t, stdout != nil, "should capture stdout")
44+
assert.Assert(t, stderr != nil, "should capture stderr")
45+
46+
assert.Assert(t, strings.Contains(strings.Join(command, "\n"),
47+
`SELECT datname FROM pg_catalog.pg_database`,
48+
), "expected all databases and templates")
49+
50+
b, err := io.ReadAll(stdin)
51+
assert.NilError(t, err)
52+
assert.Equal(t, string(b), strings.Trim(`
53+
SET client_min_messages = WARNING; DROP EXTENSION IF EXISTS pg_repack;
54+
`, "\t\n"))
55+
56+
return expected
57+
}
58+
59+
ctx := context.Background()
60+
assert.Equal(t, expected, DisableInPostgreSQL(ctx, exec))
61+
}

pkg/apis/pgv2.percona.com/v2/perconapgcluster_types.go

+2
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ func (cr *PerconaPGCluster) ToCrunchy(ctx context.Context, postgresCluster *crun
357357
postgresCluster.Spec.Extensions.PGStatMonitor = *cr.Spec.Extensions.BuiltIn.PGStatMonitor
358358
postgresCluster.Spec.Extensions.PGAudit = *cr.Spec.Extensions.BuiltIn.PGAudit
359359
postgresCluster.Spec.Extensions.PGVector = *cr.Spec.Extensions.BuiltIn.PGVector
360+
postgresCluster.Spec.Extensions.PGRepack = *cr.Spec.Extensions.BuiltIn.PGRepack
360361

361362
postgresCluster.Spec.TLSOnly = cr.Spec.TLSOnly
362363

@@ -595,6 +596,7 @@ type BuiltInExtensionsSpec struct {
595596
PGStatMonitor *bool `json:"pg_stat_monitor,omitempty"`
596597
PGAudit *bool `json:"pg_audit,omitempty"`
597598
PGVector *bool `json:"pgvector,omitempty"`
599+
PGRepack *bool `json:"pg_repack,omitempty"`
598600
}
599601

600602
type ExtensionsSpec struct {

pkg/apis/pgv2.percona.com/v2/zz_generated.deepcopy.go

+5
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/apis/postgres-operator.crunchydata.com/v1beta1/postgrescluster_types.go

+1
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,7 @@ type ExtensionsSpec struct {
194194
PGAudit bool `json:"pgAudit,omitempty"`
195195
PGStatStatements bool `json:"pgStatStatements,omitempty"`
196196
PGVector bool `json:"pgvector,omitempty"`
197+
PGRepack bool `json:"pgRepack,omitempty"`
197198
}
198199

199200
// DataSource defines data sources for a new PostgresCluster.

0 commit comments

Comments
 (0)