@@ -7,6 +7,7 @@ package physical
7
7
8
8
import (
9
9
"bufio"
10
+ "bytes"
10
11
"context"
11
12
"fmt"
12
13
"io"
@@ -45,6 +46,11 @@ const (
45
46
defaultPgConfigsDir = "default"
46
47
)
47
48
49
+ var (
50
+ // List of original parameters to synchronize on restore.
51
+ originalParamsToRestore = []string {"max_connections" }
52
+ )
53
+
48
54
// RestoreJob describes a job for physical restoring.
49
55
type RestoreJob struct {
50
56
name string
@@ -131,7 +137,9 @@ func (r *RestoreJob) Run(ctx context.Context) (err error) {
131
137
}
132
138
}()
133
139
134
- isEmpty , err := tools .IsEmptyDirectory (r .globalCfg .DataDir ())
140
+ dataDir := r .globalCfg .DataDir ()
141
+
142
+ isEmpty , err := tools .IsEmptyDirectory (dataDir )
135
143
if err != nil {
136
144
return errors .Wrap (err , "failed to explore the data directory" )
137
145
}
@@ -175,7 +183,7 @@ func (r *RestoreJob) Run(ctx context.Context) (err error) {
175
183
log .Err ("Failed to mark database data: " , err )
176
184
}
177
185
178
- pgVersion , err := tools .DetectPGVersion (r . globalCfg . DataDir () )
186
+ pgVersion , err := tools .DetectPGVersion (dataDir )
179
187
if err != nil {
180
188
return errors .Wrap (err , "failed to detect the Postgres version" )
181
189
}
@@ -186,27 +194,33 @@ func (r *RestoreJob) Run(ctx context.Context) (err error) {
186
194
return errors .Wrap (err , "cannot get path to default configs" )
187
195
}
188
196
189
- if err := fs .CopyDirectoryContent (sourceConfigDir , r . globalCfg . DataDir () ); err != nil {
197
+ if err := fs .CopyDirectoryContent (sourceConfigDir , dataDir ); err != nil {
190
198
return errors .Wrap (err , "failed to set default configuration files" )
191
199
}
192
200
193
- if err := configuration .Run (r . globalCfg . DataDir () ); err != nil {
201
+ if err := configuration .Run (dataDir ); err != nil {
194
202
return errors .Wrap (err , "failed to configure" )
195
203
}
196
204
197
- if err := r .adjustRecoveryConfiguration (pgVersion , r . globalCfg . DataDir () ); err != nil {
205
+ if err := r .adjustRecoveryConfiguration (pgVersion , dataDir ); err != nil {
198
206
return err
199
207
}
200
208
201
209
// Set permissions.
202
210
if err := tools .ExecCommand (ctx , r .dockerClient , contID , types.ExecConfig {
203
- Cmd : []string {"chown" , "-R" , "postgres" , r . globalCfg . DataDir () },
211
+ Cmd : []string {"chown" , "-R" , "postgres" , dataDir },
204
212
}); err != nil {
205
213
return errors .Wrap (err , "failed to set permissions" )
206
214
}
207
215
216
+ // Apply important initial configs.
217
+ if err := r .applyInitParams (ctx , contID , pgVersion , dataDir ); err != nil {
218
+ return errors .Wrap (err , "failed to adjust by init parameters" )
219
+ }
220
+
208
221
// Start PostgreSQL instance.
209
- startCommand , err := r .dockerClient .ContainerExecCreate (ctx , contID , startingPostgresConfig (r .globalCfg .DataDir (), pgVersion ))
222
+ startCommand , err := r .dockerClient .ContainerExecCreate (ctx , contID ,
223
+ pgCommandConfig ("postgres" , dataDir , pgVersion ))
210
224
211
225
if err != nil {
212
226
return errors .Wrap (err , "failed to create an exec command" )
@@ -263,8 +277,8 @@ func (r *RestoreJob) startContainer(ctx context.Context, containerName, containe
263
277
return syncInstance .ID , nil
264
278
}
265
279
266
- func startingPostgresConfig ( pgDataDir , pgVersion string ) types.ExecConfig {
267
- command := fmt .Sprintf ("/usr/lib/postgresql/%s/bin/postgres " , pgVersion )
280
+ func pgCommandConfig ( cmd , pgDataDir , pgVersion string ) types.ExecConfig {
281
+ command := fmt .Sprintf ("/usr/lib/postgresql/%s/bin/%s " , pgVersion , cmd )
268
282
269
283
return types.ExecConfig {
270
284
AttachStdout : true ,
@@ -350,7 +364,8 @@ func (r *RestoreJob) runSyncInstance(ctx context.Context) error {
350
364
return err
351
365
}
352
366
353
- startSyncCommand , err := r .dockerClient .ContainerExecCreate (ctx , syncInstanceID , startingPostgresConfig (r .globalCfg .DataDir (), pgVersion ))
367
+ startSyncCommand , err := r .dockerClient .ContainerExecCreate (ctx , syncInstanceID ,
368
+ pgCommandConfig ("postgres" , r .globalCfg .DataDir (), pgVersion ))
354
369
if err != nil {
355
370
return errors .Wrap (err , "failed to create exec command" )
356
371
}
@@ -446,14 +461,90 @@ func (r *RestoreJob) adjustRecoveryConfiguration(pgVersion, pgDataDir string) er
446
461
recoveryFilename = "recovery.conf"
447
462
}
448
463
449
- recoveryFile , err := os .OpenFile (path .Join (pgDataDir , recoveryFilename ), os .O_APPEND | os .O_CREATE | os .O_WRONLY , 0644 )
464
+ return r .appendConfigFile (path .Join (pgDataDir , recoveryFilename ), r .restorer .GetRecoveryConfig ())
465
+ }
466
+
467
+ func (r * RestoreJob ) applyInitParams (ctx context.Context , contID , pgVersion , dataDir string ) error {
468
+ initConfCmd , err := r .dockerClient .ContainerExecCreate (ctx , contID ,
469
+ pgCommandConfig ("pg_controldata" , dataDir , pgVersion ))
470
+
471
+ if err != nil {
472
+ return errors .Wrap (err , "failed to create an exec command" )
473
+ }
474
+
475
+ log .Msg ("Check initial configs" )
476
+
477
+ attachResponse , err := r .dockerClient .ContainerExecAttach (ctx , initConfCmd .ID , types.ExecStartCheck {})
478
+ if err != nil {
479
+ return errors .Wrap (err , "failed to attach to the exec command" )
480
+ }
481
+
482
+ defer attachResponse .Close ()
483
+
484
+ initParams , err := r .extractInitParams (ctx , attachResponse .Reader )
485
+ if err != nil {
486
+ return err
487
+ }
488
+
489
+ return r .appendInitConfigs (initParams , dataDir )
490
+ }
491
+
492
+ func (r * RestoreJob ) extractInitParams (ctx context.Context , read io.Reader ) (map [string ]string , error ) {
493
+ extractedConfigs := make (map [string ]string )
494
+ scanner := bufio .NewScanner (read )
495
+
496
+ const settingSuffix = " setting:"
497
+
498
+ for scanner .Scan () {
499
+ if ctx .Err () != nil {
500
+ return extractedConfigs , ctx .Err ()
501
+ }
502
+
503
+ responseLine := scanner .Text ()
504
+
505
+ for _ , param := range originalParamsToRestore {
506
+ extractedName := param + settingSuffix
507
+
508
+ if ! strings .HasPrefix (responseLine , extractedName ) {
509
+ continue
510
+ }
511
+
512
+ value := strings .TrimSpace (strings .TrimPrefix (responseLine , extractedName ))
513
+
514
+ extractedConfigs [param ] = value
515
+ }
516
+
517
+ if len (originalParamsToRestore ) == len (extractedConfigs ) {
518
+ break
519
+ }
520
+ }
521
+
522
+ return extractedConfigs , nil
523
+ }
524
+
525
+ func (r * RestoreJob ) appendInitConfigs (initConfiguration map [string ]string , pgDataDir string ) error {
526
+ if len (initConfiguration ) == 0 {
527
+ return nil
528
+ }
529
+
530
+ buffer := bytes .NewBuffer ([]byte ("\n " ))
531
+
532
+ for key , value := range initConfiguration {
533
+ buffer .WriteString (fmt .Sprintf ("%s = '%s'\n " , key , value ))
534
+ }
535
+
536
+ return r .appendConfigFile (path .Join (pgDataDir , "postgresql.conf" ), buffer .Bytes ())
537
+ }
538
+
539
+ func (r * RestoreJob ) appendConfigFile (file string , data []byte ) error {
540
+ configFile , err := os .OpenFile (file , os .O_APPEND | os .O_CREATE | os .O_WRONLY , 0644 )
450
541
if err != nil {
451
542
return err
452
543
}
453
544
454
- defer func () { _ = recoveryFile .Close () }()
545
+ defer func () { _ = configFile .Close () }()
455
546
456
- if _ , err := recoveryFile .Write (r . restorer . GetRecoveryConfig () ); err != nil {
547
+ if _ , err := configFile .Write (data ); err != nil {
457
548
return err
458
549
}
459
550
0 commit comments