From f02789c74a24c99a53445aaa4522731330436f4b Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Sat, 30 Oct 2021 14:53:24 +0200 Subject: [PATCH] Fix bug where db file is posible moved outside of docker volume (#496) #494 introduced a bug, where a migration function can remove the sqlite3 file outside of the mounted docker volume. that would result in a data lose after a container recreate. this fix it by only rename the file if in same folder else just use the old path as fallback and put warnings into the log Co-authored-by: Anbraten --- cmd/server/setup.go | 96 ++++++++++++++++++++++++++++++++++----------- 1 file changed, 73 insertions(+), 23 deletions(-) diff --git a/cmd/server/setup.go b/cmd/server/setup.go index 1a90bc458..794a33165 100644 --- a/cmd/server/setup.go +++ b/cmd/server/setup.go @@ -17,6 +17,7 @@ package main import ( "fmt" "os" + "strings" "time" "github.com/gin-gonic/gin" @@ -46,41 +47,90 @@ import ( ) func setupStore(c *cli.Context) (store.Store, error) { - if err := migrateSqlFile(c); err != nil { - log.Fatal().Err(err).Msg("could not migrate legacy sqlite file") + datasource := c.String("datasource") + driver := c.String("driver") + + if strings.ToLower(driver) == "sqlite3" { + if new, err := fallbackSqlite3File(datasource); err != nil { + log.Fatal().Err(err).Msg("fallback to old sqlite3 file failed") + } else { + datasource = new + } } opts := &datastore.Opts{ - Driver: c.String("driver"), - Config: c.String("datasource"), + Driver: driver, + Config: datasource, } log.Trace().Msgf("setup datastore: %#v", opts) return datastore.New(opts) } -// TODO Remove this once we are sure users aren't attempting to migrate from Drone to Woodpecker (possibly never) -func migrateSqlFile(c *cli.Context) error { - // default config for docker containers - if c.String("datasource") == "/var/lib/woodpecker/woodpecker.sqlite" { - _, err := os.Stat("/var/lib/drone/drone.sqlite") - if err == nil { - return os.Rename("/var/lib/drone/drone.sqlite", "/var/lib/woodpecker/woodpecker.sqlite") - } else if !os.IsNotExist(err) { - return err - } +// TODO: convert it to a check and fail hard only function in v0.16.0 to be able to remove it in v0.17.0 +// TODO: add it to the "how to migrate from drone docs" +func fallbackSqlite3File(path string) (string, error) { + const dockerDefaultPath = "/var/lib/woodpecker/woodpecker.sqlite" + const dockerDefaultDir = "/var/lib/woodpecker/drone.sqlite" + const dockerOldPath = "/var/lib/drone/drone.sqlite" + const standaloneDefault = "woodpecker.sqlite" + const standaloneOld = "drone.sqlite" + + // custom location was set, use that one + if path != dockerDefaultPath && path != standaloneDefault { + return path, nil } - // default config for standalone installations - if c.String("datasource") == "woodpecker.sqlite" { - _, err := os.Stat("drone.sqlite") - if err == nil { - return os.Rename("drone.sqlite", "woodpecker.sqlite") - } else if err != nil && !os.IsNotExist(err) { - return err - } + // file is at new default("/var/lib/woodpecker/woodpecker.sqlite") + _, err := os.Stat(dockerDefaultPath) + if err != nil && !os.IsNotExist(err) { + return "", err + } + if err == nil { + return dockerDefaultPath, nil } - return nil + // file is at new default("woodpecker.sqlite") + _, err = os.Stat(standaloneDefault) + if err != nil && !os.IsNotExist(err) { + return "", err + } + if err == nil { + return standaloneDefault, nil + } + + // woodpecker run in standalone mode, file is in same folder but not renamed + _, err = os.Stat(standaloneOld) + if err != nil && !os.IsNotExist(err) { + return "", err + } + if err == nil { + // rename in same folder should be fine as it should be same docker volume + log.Warn().Msgf("found sqlite3 file at '%s' and moved to '%s'", standaloneOld, standaloneDefault) + return standaloneDefault, os.Rename(standaloneOld, standaloneDefault) + } + + // file is in new folder but not renamed + _, err = os.Stat(dockerDefaultDir) + if err != nil && !os.IsNotExist(err) { + return "", err + } + if err == nil { + // rename in same folder should be fine as it should be same docker volume + log.Warn().Msgf("found sqlite3 file at '%s' and moved to '%s'", dockerDefaultDir, dockerDefaultPath) + return dockerDefaultPath, os.Rename(dockerDefaultDir, dockerDefaultPath) + } + + // file is still at old location + _, err = os.Stat(dockerOldPath) + if err == nil { + // TODO: use log.Fatal()... in next version + log.Error().Msgf("found sqlite3 file at deprecated path '%s', please move it to '%s' and update your volume path if necessary", dockerOldPath, dockerDefaultPath) + return dockerOldPath, nil + } + + // file does not exist at all + log.Warn().Msgf("no sqlite3 file found, will create one at '%s'", path) + return path, nil } func setupQueue(c *cli.Context, s store.Store) queue.Queue {