@@ -6,12 +6,16 @@ package restore
66import (
77 "context"
88 "fmt"
9+ "sort"
10+ "time"
911
1012 cnpgv1 "github.com/cloudnative-pg/cloudnative-pg/api/v1"
1113 "github.com/cloudnative-pg/cloudnative-pg/pkg/postgres"
1214 restore "github.com/cloudnative-pg/cnpg-i/pkg/restore/job"
15+ "github.com/cloudnative-pg/machinery/pkg/types"
1316 "github.com/dalibo/cnpg-i-pgbackrest/internal/operator"
1417 "github.com/dalibo/cnpg-i-pgbackrest/internal/pgbackrest"
18+ pgbackrestapi "github.com/dalibo/cnpg-i-pgbackrest/internal/pgbackrest/api"
1519 "sigs.k8s.io/controller-runtime/pkg/client"
1620 "sigs.k8s.io/controller-runtime/pkg/log"
1721)
@@ -111,6 +115,20 @@ func (impl JobHookImpl) Restore(
111115 }
112116 env = append (env , recovEnv ... )
113117 pgb := pgbackrest .NewPgBackrest (env )
118+ backupInfo , err := pgb .GetBackupInfo ()
119+ if err != nil {
120+ return nil , err
121+ }
122+ choosenBackup , err := selectBestBackup (backupInfo , recovOption )
123+ if err != nil {
124+ return nil , err
125+ }
126+ env = append (
127+ env ,
128+ fmt .Sprintf ("PGBACKREST_REPO=%d" , choosenBackup .Database .RepoKey ),
129+ fmt .Sprintf ("PGBACKREST_SET=%s" , choosenBackup .Label ),
130+ )
131+ pgb = pgbackrest .NewPgBackrest (env )
114132 errCh := pgb .Restore (ctx )
115133 if err := <- errCh ; err != nil {
116134 return nil , err
@@ -128,3 +146,65 @@ func (impl JobHookImpl) Restore(
128146 Envs : nil ,
129147 }, nil
130148}
149+
150+ func selectBestBackup (
151+ backups []pgbackrestapi.BackupInfo ,
152+ opts pgbackrest.RestoreOptions ,
153+ ) (* pgbackrestapi.BackupInfo , error ) {
154+ if len (backups ) == 0 {
155+ return nil , fmt .Errorf ("no backups available" )
156+ }
157+
158+ // First sort backups from newest to oldest, that way we will
159+ // always match the newest backup
160+ sort .Slice (backups , func (i , j int ) bool {
161+ return backups [i ].Timestamp .Stop > backups [j ].Timestamp .Stop
162+ })
163+
164+ switch opts .Type {
165+ // then try to find the most appropriate backup for the type of target
166+ case "name" :
167+ for _ , b := range backups {
168+ if b .Label == opts .Target {
169+ return & b , nil
170+ }
171+ }
172+ return nil , fmt .Errorf ("backup with label %q not found" , opts .Target )
173+
174+ case "time" :
175+ targetTime , err := time .Parse (time .RFC3339 , opts .Target )
176+ if err != nil {
177+ return nil , fmt .Errorf ("invalid target time %q: %w" , opts .Target , err )
178+ }
179+ targetTS := targetTime .Unix ()
180+
181+ for _ , b := range backups {
182+ if b .Timestamp .Stop <= targetTS {
183+ return & b , nil
184+ }
185+ }
186+ return nil , fmt .Errorf ("no backup found before target time %s" , opts .Target )
187+
188+ case "lsn" :
189+ targetLSN := types .LSN (opts .Target )
190+
191+ for _ , b := range backups {
192+ stopLSN := types .LSN (b .Lsn .Stop )
193+ if stopLSN .Less (targetLSN ) || stopLSN == targetLSN {
194+ return & b , nil
195+ }
196+ }
197+ return nil , fmt .Errorf (
198+ "no backup found before target LSN %s" ,
199+ opts .Target ,
200+ )
201+
202+ // decide what to do here
203+ // case "xid":
204+ // return nil, nil
205+ // by default, fallback to the latest backup, may be we should return nothing and
206+ // let pgbackrest do the job by itself
207+ default :
208+ return pgbackrest .LatestBackup (backups ), nil
209+ }
210+ }
0 commit comments