RestoreBackup restores the backup with the specified name and restarts the current running application process. NB! This feature is experimental and currently is expected to work only on UNIX based systems. To safely perform the restore it is recommended to have free disk space for at least 2x the
(ctx context.Context, name string)
| 153 | // it is possible the restore to fail during the `os.Rename` operations |
| 154 | // (see https://github.com/pocketbase/pocketbase/issues/4647). |
| 155 | func (app *BaseApp) RestoreBackup(ctx context.Context, name string) error { |
| 156 | if app.Store().Has(StoreKeyActiveBackup) { |
| 157 | return errors.New("try again later - another backup/restore operation has already been started") |
| 158 | } |
| 159 | |
| 160 | app.Store().Set(StoreKeyActiveBackup, name) |
| 161 | defer app.Store().Remove(StoreKeyActiveBackup) |
| 162 | |
| 163 | event := new(BackupEvent) |
| 164 | event.App = app |
| 165 | event.Context = ctx |
| 166 | event.Name = name |
| 167 | // default root dir entries to exclude from the backup restore |
| 168 | event.Exclude = []string{LocalBackupsDirName, LocalTempDirName, LocalAutocertCacheDirName, lostFoundDirName} |
| 169 | |
| 170 | return app.OnBackupRestore().Trigger(event, func(e *BackupEvent) error { |
| 171 | if runtime.GOOS == "windows" { |
| 172 | return errors.New("restore is not supported on Windows") |
| 173 | } |
| 174 | |
| 175 | // make sure that the special temp directory exists |
| 176 | // note: it needs to be inside the current pb_data to avoid "cross-device link" errors |
| 177 | localTempDir := filepath.Join(e.App.DataDir(), LocalTempDirName) |
| 178 | if err := os.MkdirAll(localTempDir, os.ModePerm); err != nil { |
| 179 | return fmt.Errorf("failed to create a temp dir: %w", err) |
| 180 | } |
| 181 | |
| 182 | fsys, err := e.App.NewBackupsFilesystem() |
| 183 | if err != nil { |
| 184 | return err |
| 185 | } |
| 186 | defer fsys.Close() |
| 187 | |
| 188 | fsys.SetContext(e.Context) |
| 189 | |
| 190 | if ok, _ := fsys.Exists(name); !ok { |
| 191 | return fmt.Errorf("missing or invalid backup file %q to restore", name) |
| 192 | } |
| 193 | |
| 194 | extractedDataDir := filepath.Join(localTempDir, "pb_restore_"+security.PseudorandomString(8)) |
| 195 | defer os.RemoveAll(extractedDataDir) |
| 196 | |
| 197 | // extract the zip |
| 198 | if e.App.Settings().Backups.S3.Enabled { |
| 199 | br, err := fsys.GetReader(name) |
| 200 | if err != nil { |
| 201 | return err |
| 202 | } |
| 203 | defer br.Close() |
| 204 | |
| 205 | // create a temp zip file from the blob.Reader and try to extract it |
| 206 | tempZip, err := os.CreateTemp(localTempDir, "pb_restore_zip") |
| 207 | if err != nil { |
| 208 | return err |
| 209 | } |
| 210 | defer os.Remove(tempZip.Name()) |
| 211 | defer tempZip.Close() // note: this technically shouldn't be necessary but it is here to workaround platforms discrepancies |
| 212 |
nothing calls this directly
no test coverage detected