Skip to content

Commit

Permalink
Allow upgrading Postgres with timescaleDB extension.
Browse files Browse the repository at this point in the history
  • Loading branch information
Gerrit91 committed Jan 29, 2024
1 parent 67ce41f commit d276b85
Show file tree
Hide file tree
Showing 4 changed files with 128 additions and 2 deletions.
2 changes: 2 additions & 0 deletions cmd/internal/database/postgres/postgres.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import (
"github.com/metal-stack/backup-restore-sidecar/cmd/internal/utils"
"github.com/metal-stack/backup-restore-sidecar/pkg/constants"
"go.uber.org/zap"

_ "github.com/lib/pq"
)

const (
Expand Down
33 changes: 33 additions & 0 deletions cmd/internal/database/postgres/upgrade.go
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,23 @@ func (db *Postgres) Upgrade(ctx context.Context) error {
"--new-bindir", newPostgresBinDir,
"--link",
}

runsTimescaleDB, err := db.runningTimescaleDB(ctx, postgresConfigCmd)
if err != nil {
return err
}

if runsTimescaleDB {
db.log.Infow("running timescaledb, applying custom options for upgrade command")

// timescaledb libraries in this container are only compatible with the current postgres version
// do not load them anymore with the old postgresql server
pgUpgradeArgs = append(pgUpgradeArgs,
"--old-options", "-c shared_preload_libraries=''",
"--new-options", "-c timescaledb.restoring=on -c shared_preload_libraries=timescaledb",
)
}

cmd = exec.CommandContext(ctx, postgresUpgradeCmd, pgUpgradeArgs...) //nolint:gosec
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stderr
Expand Down Expand Up @@ -255,6 +272,22 @@ func (db *Postgres) getBinDir(ctx context.Context, pgConfigCmd string) (string,
return strings.TrimSpace(string(out)), nil
}

func (db *Postgres) runningTimescaleDB(ctx context.Context, pgConfigCmd string) (bool, error) {
cmd := exec.CommandContext(ctx, pgConfigCmd, "--pkglibdir")
out, err := cmd.CombinedOutput()
if err != nil {
return false, err
}

libDir := strings.TrimSpace(string(out))

if _, err := os.Stat(path.Join(libDir, "timescaledb.so")); err == nil {
return true, nil
}

return false, nil
}

// copyPostgresBinaries is needed to save old postgres binaries for a later major upgrade
func (db *Postgres) copyPostgresBinaries(ctx context.Context, override bool) error {
binDir, err := db.getBinDir(ctx, postgresConfigCmd)
Expand Down
30 changes: 28 additions & 2 deletions cmd/internal/utils/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"os"
"os/exec"
"strings"
"time"

"go.uber.org/zap"
)
Expand Down Expand Up @@ -52,7 +53,7 @@ func (c *CmdExecutor) ExecWithStreamingOutput(ctx context.Context, command strin

parts := strings.Fields(command)

cmd := exec.CommandContext(ctx, parts[0], parts[1:]...) // nolint:gosec
cmd := exec.Command(parts[0], parts[1:]...) // nolint:gosec

c.log.Debugw("running command", "command", cmd.Path, "args", cmd.Args)

Expand All @@ -61,5 +62,30 @@ func (c *CmdExecutor) ExecWithStreamingOutput(ctx context.Context, command strin
cmd.Stdout = os.Stdout
cmd.Stderr = os.Stdout

return cmd.Run()
err := cmd.Start()
if err != nil {
return err
}

go func() {
<-ctx.Done()

go func() {
time.Sleep(10 * time.Second)

c.log.Infow("force killing post-exec command now")
if err := cmd.Process.Signal(os.Kill); err != nil {
panic(err)
}
}()

c.log.Infow("sending sigint to post-exec command process")

err := cmd.Process.Signal(os.Interrupt)
if err != nil {
c.log.Errorw("unable to send interrupt to post-exec command", "error", err)
}
}()

return cmd.Wait()
}
65 changes: 65 additions & 0 deletions integration/postgres_timescaledb_upgrade_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
//go:build integration

package integration_test

import (
"testing"

"github.com/metal-stack/backup-restore-sidecar/pkg/generate/examples/examples"
"github.com/stretchr/testify/require"
corev1 "k8s.io/api/core/v1"
"sigs.k8s.io/controller-runtime/pkg/client"

_ "github.com/lib/pq"
)

func Test_Postgres_TimescaleDB_Upgrade(t *testing.T) {
backingResources := examples.PostgresBackingResources(namespaceName(t))

modified := false

for _, r := range backingResources {
cm, ok := r.(*corev1.ConfigMap)
if !ok {
continue
}

if cm.Name != "backup-restore-sidecar-config-postgres" {
continue
}

cm.Data = map[string]string{
"config.yaml": `---
bind-addr: 0.0.0.0
db: postgres
db-data-directory: /data/postgres/
backup-provider: local
backup-cron-schedule: "*/1 * * * *"
object-prefix: postgres-test
compression-method: tar
post-exec-cmds:
- docker-entrypoint.sh postgres -c shared_preload_libraries=timescaledb
`}

modified = true
break
}

require.True(t, modified)

upgradeFlow(t, &upgradeFlowSpec{
flowSpec: flowSpec{
databaseType: examples.Postgres,
sts: examples.PostgresSts,
backingResources: func(namespace string) []client.Object {
return backingResources
},
addTestData: addPostgresTestData,
verifyTestData: verifyPostgresTestData,
},
databaseImages: []string{
"timescale/timescaledb:2.11.2-pg12",
"timescale/timescaledb:2.11.2-pg15",
},
})
}

0 comments on commit d276b85

Please sign in to comment.