2020-03-22 21:07:15 +00:00
package api
import (
"fmt"
"html/template"
"net/http"
2020-04-22 01:22:14 +00:00
"os"
2020-03-22 21:07:15 +00:00
"github.com/stashapp/stash/pkg/database"
2020-04-22 01:22:14 +00:00
"github.com/stashapp/stash/pkg/logger"
2020-08-06 01:21:14 +00:00
"github.com/stashapp/stash/pkg/manager"
2020-03-22 21:07:15 +00:00
)
type migrateData struct {
ExistingVersion uint
MigrateVersion uint
BackupPath string
}
func getMigrateData ( ) migrateData {
return migrateData {
ExistingVersion : database . Version ( ) ,
MigrateVersion : database . AppSchemaVersion ( ) ,
BackupPath : database . DatabaseBackupPath ( ) ,
}
}
func getMigrateHandler ( w http . ResponseWriter , r * http . Request ) {
if ! database . NeedsMigration ( ) {
http . Redirect ( w , r , "/" , 301 )
return
}
data , _ := setupUIBox . Find ( "migrate.html" )
templ , err := template . New ( "Migrate" ) . Parse ( string ( data ) )
if err != nil {
http . Error ( w , fmt . Sprintf ( "error: %s" , err ) , 500 )
return
}
err = templ . Execute ( w , getMigrateData ( ) )
if err != nil {
http . Error ( w , fmt . Sprintf ( "error: %s" , err ) , 500 )
}
}
func doMigrateHandler ( w http . ResponseWriter , r * http . Request ) {
err := r . ParseForm ( )
if err != nil {
http . Error ( w , fmt . Sprintf ( "error: %s" , err ) , 500 )
}
2020-04-22 01:22:14 +00:00
formBackupPath := r . Form . Get ( "backuppath" )
// always backup so that we can roll back to the previous version if
// migration fails
backupPath := formBackupPath
if formBackupPath == "" {
backupPath = database . DatabaseBackupPath ( )
}
2020-03-22 21:07:15 +00:00
// perform database backup
2020-04-22 01:22:14 +00:00
if err = database . Backup ( backupPath ) ; err != nil {
http . Error ( w , fmt . Sprintf ( "error backing up database: %s" , err ) , 500 )
return
2020-03-22 21:07:15 +00:00
}
err = database . RunMigrations ( )
if err != nil {
2020-04-22 01:22:14 +00:00
errStr := fmt . Sprintf ( "error performing migration: %s" , err )
// roll back to the backed up version
restoreErr := database . RestoreFromBackup ( backupPath )
if restoreErr != nil {
errStr = fmt . Sprintf ( "ERROR: unable to restore database from backup after migration failure: %s\n%s" , restoreErr . Error ( ) , errStr )
} else {
errStr = "An error occurred migrating the database to the latest schema version. The backup database file was automatically renamed to restore the database.\n" + errStr
}
http . Error ( w , errStr , 500 )
2020-03-22 21:07:15 +00:00
return
}
2020-04-22 01:22:14 +00:00
2020-08-06 01:21:14 +00:00
// perform post-migration operations
manager . GetInstance ( ) . PostMigrate ( )
2020-04-22 01:22:14 +00:00
// if no backup path was provided, then delete the created backup
if formBackupPath == "" {
err = os . Remove ( backupPath )
if err != nil {
logger . Warnf ( "error removing unwanted database backup (%s): %s" , backupPath , err . Error ( ) )
}
}
2020-03-22 21:07:15 +00:00
http . Redirect ( w , r , "/" , 301 )
}