@@ -27,6 +27,7 @@ import (
2727 "os/exec"
2828 "path"
2929 "path/filepath"
30+ "strconv"
3031 "strings"
3132 "time"
3233
@@ -36,6 +37,7 @@ import (
3637 "github.com/cloudnative-pg/machinery/pkg/fileutils"
3738 "github.com/cloudnative-pg/machinery/pkg/fileutils/compatibility"
3839 "github.com/cloudnative-pg/machinery/pkg/log"
40+ "github.com/cloudnative-pg/machinery/pkg/postgres/version"
3941 "github.com/spf13/cobra"
4042 "k8s.io/utils/ptr"
4143 ctrl "sigs.k8s.io/controller-runtime/pkg/client"
@@ -48,9 +50,10 @@ import (
4850 "github.com/cloudnative-pg/cloudnative-pg/pkg/management"
4951 "github.com/cloudnative-pg/cloudnative-pg/pkg/management/postgres"
5052 "github.com/cloudnative-pg/cloudnative-pg/pkg/management/postgres/constants"
51- "github.com/cloudnative-pg/cloudnative-pg/pkg/management/postgres/utils"
53+ postgresutils "github.com/cloudnative-pg/cloudnative-pg/pkg/management/postgres/utils"
5254 "github.com/cloudnative-pg/cloudnative-pg/pkg/management/postgres/webserver/metricserver"
5355 "github.com/cloudnative-pg/cloudnative-pg/pkg/specs"
56+ "github.com/cloudnative-pg/cloudnative-pg/pkg/utils"
5457)
5558
5659// NewCmd creates the cobra command
@@ -187,8 +190,19 @@ func upgradeSubCommand(
187190 }
188191 }
189192
193+ // Extract controldata information from the old data directory
194+ controlData , err := getControlData (oldBinDir , pgData )
195+ if err != nil {
196+ return fmt .Errorf ("error while getting old data directory control data: %w" , err )
197+ }
198+
199+ targetVersion , err := cluster .GetPostgresqlVersion ()
200+ if err != nil {
201+ return fmt .Errorf ("error while getting the target version from the cluster object: %w" , err )
202+ }
203+
190204 contextLogger .Info ("Creating data directory" , "directory" , newDataDir )
191- if err := runInitDB (newDataDir , newWalDir ); err != nil {
205+ if err := runInitDB (newDataDir , newWalDir , controlData , targetVersion ); err != nil {
192206 return fmt .Errorf ("error while creating the data directory: %w" , err )
193207 }
194208
@@ -199,12 +213,12 @@ func upgradeSubCommand(
199213
200214 contextLogger .Info ("Checking if we have anything to update" )
201215 // Read pg_version from both the old and new data directories
202- oldVersion , err := utils .GetPgdataVersion (pgData )
216+ oldVersion , err := postgresutils .GetPgdataVersion (pgData )
203217 if err != nil {
204218 return fmt .Errorf ("error while reading the old version: %w" , err )
205219 }
206220
207- newVersion , err := utils .GetPgdataVersion (newDataDir )
221+ newVersion , err := postgresutils .GetPgdataVersion (newDataDir )
208222 if err != nil {
209223 return fmt .Errorf ("error while reading the new version: %w" , err )
210224 }
@@ -262,7 +276,19 @@ func upgradeSubCommand(
262276 return nil
263277}
264278
265- func runInitDB (destDir string , walDir * string ) error {
279+ func getControlData (binDir , pgData string ) (map [string ]string , error ) {
280+ pgControlDataCmd := exec .Command (path .Join (binDir , "pg_controldata" )) // #nosec
281+ pgControlDataCmd .Env = append (os .Environ (), "PGDATA=" + pgData )
282+
283+ out , err := pgControlDataCmd .CombinedOutput ()
284+ if err != nil {
285+ return nil , fmt .Errorf ("while executing pg_controldata: %w" , err )
286+ }
287+
288+ return utils .ParsePgControldataOutput (string (out )), nil
289+ }
290+
291+ func runInitDB (destDir string , walDir * string , pgControlData map [string ]string , targetVersion version.Data ) error {
266292 // Invoke initdb to generate a data directory
267293 options := []string {
268294 "--username" ,
@@ -275,6 +301,17 @@ func runInitDB(destDir string, walDir *string) error {
275301 options = append (options , "--waldir" , * walDir )
276302 }
277303
304+ // Extract the WAL segment size from the pg_controldata output
305+ options , err := tryAddWalSegmentSize (pgControlData , options )
306+ if err != nil {
307+ return err
308+ }
309+
310+ options , err = tryAddDataChecksums (pgControlData , targetVersion , options )
311+ if err != nil {
312+ return err
313+ }
314+
278315 // Certain CSI drivers may add setgid permissions on newly created folders.
279316 // A default umask is set to attempt to avoid this, by revoking group/other
280317 // permission bits on the PGDATA
@@ -288,6 +325,46 @@ func runInitDB(destDir string, walDir *string) error {
288325 return nil
289326}
290327
328+ // TODO: refactor it should be a method of pgControlData
329+ func tryAddDataChecksums (
330+ pgControlData map [string ]string ,
331+ targetVersion version.Data ,
332+ options []string ,
333+ ) ([]string , error ) {
334+ dataPageChecksumVersion , ok := pgControlData [utils .PgControlDataDataPageChecksumVersion ]
335+ if ! ok {
336+ return nil , fmt .Errorf ("no '%s' section into pg_controldata output" , utils .PgControlDataDataPageChecksumVersion )
337+ }
338+
339+ if dataPageChecksumVersion != "1" {
340+ // In postgres 18 we will have to set "--no-data-checksums" if checksums are disabled (they are enabled by default)
341+ if targetVersion .Major () >= 18 {
342+ return append (options , "--no-data-checksums" ), nil
343+ }
344+ return options , nil
345+ }
346+
347+ return append (options , "--data-checksums" ), nil
348+ }
349+
350+ // TODO: refactor it should be a method of pgControlData
351+ func tryAddWalSegmentSize (pgControlData map [string ]string , options []string ) ([]string , error ) {
352+ walSegmentSizeString , ok := pgControlData [utils .PgControlDataBytesPerWALSegment ]
353+ if ! ok {
354+ return nil , fmt .Errorf ("no '%s' section into pg_controldata output" , utils .PgControlDataBytesPerWALSegment )
355+ }
356+
357+ walSegmentSize , err := strconv .Atoi (walSegmentSizeString )
358+ if err != nil {
359+ return nil , fmt .Errorf (
360+ "wrong '%s' pg_controldata value (not an integer): '%s' %w" ,
361+ utils .PgControlDataBytesPerWALSegment , walSegmentSizeString , err )
362+ }
363+
364+ param := "--wal-segsize=" + strconv .Itoa (walSegmentSize / (1024 * 1024 ))
365+ return append (options , param ), nil
366+ }
367+
291368func prepareConfigurationFiles (ctx context.Context , cluster apiv1.Cluster , destDir string ) error {
292369 // Always read the custom and override configuration files created by the operator
293370 _ , err := configfile .EnsureIncludes (path .Join (destDir , "postgresql.conf" ),
@@ -298,8 +375,20 @@ func prepareConfigurationFiles(ctx context.Context, cluster apiv1.Cluster, destD
298375 return fmt .Errorf ("appending inclusion directives to postgresql.conf file resulted in an error: %w" , err )
299376 }
300377
378+ // Set `max_slot_wal_keep_size` to the default value because any other value it is not supported in pg_upgrade
379+ tmpCluster := cluster .DeepCopy ()
380+ tmpCluster .Spec .PostgresConfiguration .Parameters ["max_slot_wal_keep_size" ] = "-1"
381+
382+ pgVersion , err := postgresutils .GetPgdataVersion (destDir )
383+ if err != nil {
384+ return fmt .Errorf ("error while reading the new data directory version: %w" , err )
385+ }
386+ if pgVersion .Major >= 18 {
387+ tmpCluster .Spec .PostgresConfiguration .Parameters ["idle_replication_slot_timeout" ] = "0"
388+ }
389+
301390 newInstance := postgres.Instance {PgData : destDir }
302- if _ , err := newInstance .RefreshConfigurationFilesFromCluster (ctx , & cluster , false ); err != nil {
391+ if _ , err := newInstance .RefreshConfigurationFilesFromCluster (ctx , tmpCluster , false ); err != nil {
303392 return fmt .Errorf ("error while creating the configuration files for new datadir %q: %w" , destDir , err )
304393 }
305394
0 commit comments