mirror of https://github.com/portainer/portainer
parent
5dad419f60
commit
0fce4c98a0
|
@ -49,7 +49,7 @@ func (*Service) ParseFlags(version string) (*portainer.CLIFlags, error) {
|
||||||
SSL: kingpin.Flag("ssl", "Secure Portainer instance using SSL (deprecated)").Default(defaultSSL).Bool(),
|
SSL: kingpin.Flag("ssl", "Secure Portainer instance using SSL (deprecated)").Default(defaultSSL).Bool(),
|
||||||
SSLCert: kingpin.Flag("sslcert", "Path to the SSL certificate used to secure the Portainer instance").String(),
|
SSLCert: kingpin.Flag("sslcert", "Path to the SSL certificate used to secure the Portainer instance").String(),
|
||||||
SSLKey: kingpin.Flag("sslkey", "Path to the SSL key used to secure the Portainer instance").String(),
|
SSLKey: kingpin.Flag("sslkey", "Path to the SSL key used to secure the Portainer instance").String(),
|
||||||
Rollback: kingpin.Flag("rollback", "Rollback the database store to the previous version").Bool(),
|
Rollback: kingpin.Flag("rollback", "Rollback the database to the previous backup").Bool(),
|
||||||
SnapshotInterval: kingpin.Flag("snapshot-interval", "Duration between each environment snapshot job").String(),
|
SnapshotInterval: kingpin.Flag("snapshot-interval", "Duration between each environment snapshot job").String(),
|
||||||
AdminPassword: kingpin.Flag("admin-password", "Set admin password with provided hash").String(),
|
AdminPassword: kingpin.Flag("admin-password", "Set admin password with provided hash").String(),
|
||||||
AdminPasswordFile: kingpin.Flag("admin-password-file", "Path to the file containing the password for the admin user").String(),
|
AdminPasswordFile: kingpin.Flag("admin-password-file", "Path to the file containing the password for the admin user").String(),
|
||||||
|
|
|
@ -65,7 +65,7 @@ type BackupOptions struct {
|
||||||
// - db rollback
|
// - db rollback
|
||||||
func getBackupRestoreOptions(backupDir string) *BackupOptions {
|
func getBackupRestoreOptions(backupDir string) *BackupOptions {
|
||||||
return &BackupOptions{
|
return &BackupOptions{
|
||||||
BackupDir: backupDir, //connection.commonBackupDir(),
|
BackupDir: backupDir,
|
||||||
BackupFileName: beforePortainerVersionUpgradeBackup,
|
BackupFileName: beforePortainerVersionUpgradeBackup,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,12 +76,12 @@ func (store *Store) Backup(version *models.Version) (string, error) {
|
||||||
return store.backupWithOptions(nil)
|
return store.backupWithOptions(nil)
|
||||||
}
|
}
|
||||||
|
|
||||||
return store.backupWithOptions(&BackupOptions{
|
backupOptions := getBackupRestoreOptions(store.commonBackupDir())
|
||||||
Version: version.SchemaVersion,
|
backupOptions.Version = version.SchemaVersion
|
||||||
})
|
return store.backupWithOptions(backupOptions)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (store *Store) setupOptions(options *BackupOptions) *BackupOptions {
|
func (store *Store) setDefaultBackupOptions(options *BackupOptions) *BackupOptions {
|
||||||
if options == nil {
|
if options == nil {
|
||||||
options = &BackupOptions{}
|
options = &BackupOptions{}
|
||||||
}
|
}
|
||||||
|
@ -110,7 +110,7 @@ func (store *Store) backupWithOptions(options *BackupOptions) (string, error) {
|
||||||
|
|
||||||
store.createBackupFolders()
|
store.createBackupFolders()
|
||||||
|
|
||||||
options = store.setupOptions(options)
|
options = store.setDefaultBackupOptions(options)
|
||||||
dbPath := store.databasePath()
|
dbPath := store.databasePath()
|
||||||
|
|
||||||
if err := store.Close(); err != nil {
|
if err := store.Close(); err != nil {
|
||||||
|
@ -139,20 +139,18 @@ func (store *Store) backupWithOptions(options *BackupOptions) (string, error) {
|
||||||
// - default: restore latest from current edition
|
// - default: restore latest from current edition
|
||||||
// - restore a specific
|
// - restore a specific
|
||||||
func (store *Store) restoreWithOptions(options *BackupOptions) error {
|
func (store *Store) restoreWithOptions(options *BackupOptions) error {
|
||||||
options = store.setupOptions(options)
|
options = store.setDefaultBackupOptions(options)
|
||||||
|
|
||||||
// Check if backup file exist before restoring
|
// Check if backup file exist before restoring
|
||||||
_, err := os.Stat(options.BackupPath)
|
_, err := os.Stat(options.BackupPath)
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
log.Error().Str("path", options.BackupPath).Err(err).Msg("backup file to restore does not exist %s")
|
log.Error().Str("path", options.BackupPath).Err(err).Msg("backup file to restore does not exist")
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
err = store.Close()
|
err = store.Close()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Error().Err(err).Msg("error while closing store before restore")
|
log.Error().Err(err).Msg("error while closing store before restore")
|
||||||
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -170,7 +168,7 @@ func (store *Store) restoreWithOptions(options *BackupOptions) error {
|
||||||
func (store *Store) removeWithOptions(options *BackupOptions) error {
|
func (store *Store) removeWithOptions(options *BackupOptions) error {
|
||||||
log.Info().Msg("removing DB backup")
|
log.Info().Msg("removing DB backup")
|
||||||
|
|
||||||
options = store.setupOptions(options)
|
options = store.setDefaultBackupOptions(options)
|
||||||
_, err := os.Stat(options.BackupPath)
|
_, err := os.Stat(options.BackupPath)
|
||||||
|
|
||||||
if os.IsNotExist(err) {
|
if os.IsNotExist(err) {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package datastore
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
"runtime/debug"
|
"runtime/debug"
|
||||||
|
|
||||||
portainer "github.com/portainer/portainer/api"
|
portainer "github.com/portainer/portainer/api"
|
||||||
|
@ -117,6 +118,11 @@ func (store *Store) FailSafeMigrate(migrator *migrator.Migrator, version *models
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Special test code to simulate a failure (used by migrate_data_test.go). Do not remove...
|
||||||
|
if os.Getenv("PORTAINER_TEST_MIGRATE_FAIL") == "FAIL" {
|
||||||
|
panic("test migration failure")
|
||||||
|
}
|
||||||
|
|
||||||
err = store.VersionService.StoreIsUpdating(false)
|
err = store.VersionService.StoreIsUpdating(false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return errors.Wrap(err, "failed to update the store")
|
return errors.Wrap(err, "failed to update the store")
|
||||||
|
|
|
@ -10,6 +10,7 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
portainer "github.com/portainer/portainer/api"
|
||||||
"github.com/portainer/portainer/api/database/boltdb"
|
"github.com/portainer/portainer/api/database/boltdb"
|
||||||
|
|
||||||
"github.com/google/go-cmp/cmp"
|
"github.com/google/go-cmp/cmp"
|
||||||
|
@ -55,111 +56,108 @@ func TestMigrateData(t *testing.T) {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// t.Run("MigrateData for New Store & Re-Open Check", func(t *testing.T) {
|
t.Run("MigrateData for New Store & Re-Open Check", func(t *testing.T) {
|
||||||
// newStore, store, teardown := MustNewTestStore(t, true, false)
|
newStore, store := MustNewTestStore(t, true, false)
|
||||||
// defer teardown()
|
|
||||||
|
|
||||||
// if !newStore {
|
if !newStore {
|
||||||
// t.Error("Expect a new DB")
|
t.Error("Expect a new DB")
|
||||||
// }
|
}
|
||||||
|
|
||||||
// testVersion(store, portainer.APIVersion, t)
|
testVersion(store, portainer.APIVersion, t)
|
||||||
// store.Close()
|
store.Close()
|
||||||
|
|
||||||
// newStore, _ = store.Open()
|
newStore, _ = store.Open()
|
||||||
// if newStore {
|
if newStore {
|
||||||
// t.Error("Expect store to NOT be new DB")
|
t.Error("Expect store to NOT be new DB")
|
||||||
// }
|
}
|
||||||
// })
|
})
|
||||||
|
|
||||||
// tests := []struct {
|
tests := []struct {
|
||||||
// version string
|
version string
|
||||||
// expectedVersion string
|
expectedVersion string
|
||||||
// }{
|
}{
|
||||||
// {version: "1.24.1", expectedVersion: portainer.APIVersion},
|
{version: "1.24.1", expectedVersion: portainer.APIVersion},
|
||||||
// {version: "2.0.0", expectedVersion: portainer.APIVersion},
|
{version: "2.0.0", expectedVersion: portainer.APIVersion},
|
||||||
// }
|
}
|
||||||
// for _, tc := range tests {
|
for _, tc := range tests {
|
||||||
// _, store, teardown := MustNewTestStore(t, true, true)
|
_, store := MustNewTestStore(t, true, true)
|
||||||
// defer teardown()
|
|
||||||
|
|
||||||
// // Setup data
|
// Setup data
|
||||||
// v := models.Version{SchemaVersion: tc.version}
|
v := models.Version{SchemaVersion: tc.version, Edition: int(portainer.PortainerCE)}
|
||||||
// store.VersionService.UpdateVersion(&v)
|
store.VersionService.UpdateVersion(&v)
|
||||||
|
|
||||||
// // Required roles by migrations 22.2
|
// Required roles by migrations 22.2
|
||||||
// store.RoleService.Create(&portainer.Role{ID: 1})
|
store.RoleService.Create(&portainer.Role{ID: 1})
|
||||||
// store.RoleService.Create(&portainer.Role{ID: 2})
|
store.RoleService.Create(&portainer.Role{ID: 2})
|
||||||
// store.RoleService.Create(&portainer.Role{ID: 3})
|
store.RoleService.Create(&portainer.Role{ID: 3})
|
||||||
// store.RoleService.Create(&portainer.Role{ID: 4})
|
store.RoleService.Create(&portainer.Role{ID: 4})
|
||||||
|
|
||||||
// t.Run(fmt.Sprintf("MigrateData for version %s", tc.version), func(t *testing.T) {
|
t.Run(fmt.Sprintf("MigrateData for version %s", tc.version), func(t *testing.T) {
|
||||||
// store.MigrateData()
|
store.MigrateData()
|
||||||
// testVersion(store, tc.expectedVersion, t)
|
testVersion(store, tc.expectedVersion, t)
|
||||||
// })
|
})
|
||||||
|
|
||||||
// t.Run(fmt.Sprintf("Restoring DB after migrateData for version %s", tc.version), func(t *testing.T) {
|
t.Run(fmt.Sprintf("Restoring DB after migrateData for version %s", tc.version), func(t *testing.T) {
|
||||||
// store.Rollback(true)
|
store.Rollback(true)
|
||||||
// store.Open()
|
store.Open()
|
||||||
// testVersion(store, tc.version, t)
|
testVersion(store, tc.version, t)
|
||||||
// })
|
})
|
||||||
// }
|
}
|
||||||
|
|
||||||
// t.Run("Error in MigrateData should restore backup before MigrateData", func(t *testing.T) {
|
t.Run("Error in MigrateData should restore backup before MigrateData", func(t *testing.T) {
|
||||||
// _, store, teardown := MustNewTestStore(t, false, true)
|
_, store := MustNewTestStore(t, false, false)
|
||||||
// defer teardown()
|
|
||||||
|
|
||||||
// v := models.Version{SchemaVersion: "1.24.1"}
|
v := models.Version{SchemaVersion: "1.24.1", Edition: int(portainer.PortainerCE)}
|
||||||
// store.VersionService.UpdateVersion(&v)
|
store.VersionService.UpdateVersion(&v)
|
||||||
|
|
||||||
// store.MigrateData()
|
store.MigrateData()
|
||||||
|
|
||||||
// testVersion(store, v.SchemaVersion, t)
|
testVersion(store, v.SchemaVersion, t)
|
||||||
// })
|
})
|
||||||
|
|
||||||
// t.Run("MigrateData should create backup file upon update", func(t *testing.T) {
|
t.Run("MigrateData should create backup file upon update", func(t *testing.T) {
|
||||||
// _, store, teardown := MustNewTestStore(t, false, true)
|
_, store := MustNewTestStore(t, false, false)
|
||||||
// defer teardown()
|
|
||||||
|
|
||||||
// v := models.Version{SchemaVersion: "0.0.0"}
|
v := models.Version{SchemaVersion: "0.0.0", Edition: int(portainer.PortainerCE)}
|
||||||
// store.VersionService.UpdateVersion(&v)
|
store.VersionService.UpdateVersion(&v)
|
||||||
|
|
||||||
// store.MigrateData()
|
store.MigrateData()
|
||||||
|
|
||||||
// options := store.setupOptions(getBackupRestoreOptions(store.commonBackupDir()))
|
options := store.setDefaultBackupOptions(getBackupRestoreOptions(store.commonBackupDir()))
|
||||||
|
|
||||||
// if !isFileExist(options.BackupPath) {
|
if !isFileExist(options.BackupPath) {
|
||||||
// t.Errorf("Backup file should exist; file=%s", options.BackupPath)
|
t.Errorf("Backup file should exist; file=%s", options.BackupPath)
|
||||||
// }
|
}
|
||||||
// })
|
})
|
||||||
|
|
||||||
// t.Run("MigrateData should fail to create backup if database file is set to updating", func(t *testing.T) {
|
t.Run("MigrateData should fail to create backup if database file is set to updating", func(t *testing.T) {
|
||||||
// _, store, teardown := MustNewTestStore(t, false, true)
|
_, store := MustNewTestStore(t, false, false)
|
||||||
// defer teardown()
|
|
||||||
|
|
||||||
// store.VersionService.StoreIsUpdating(true)
|
store.VersionService.StoreIsUpdating(true)
|
||||||
|
|
||||||
// store.MigrateData()
|
store.MigrateData()
|
||||||
|
|
||||||
// options := store.setupOptions(getBackupRestoreOptions(store.commonBackupDir()))
|
options := store.setDefaultBackupOptions(getBackupRestoreOptions(store.commonBackupDir()))
|
||||||
|
|
||||||
// if isFileExist(options.BackupPath) {
|
if isFileExist(options.BackupPath) {
|
||||||
// t.Errorf("Backup file should not exist for dirty database; file=%s", options.BackupPath)
|
t.Errorf("Backup file should not exist for dirty database; file=%s", options.BackupPath)
|
||||||
// }
|
}
|
||||||
// })
|
})
|
||||||
|
|
||||||
// t.Run("MigrateData should not create backup on startup if portainer version matches db", func(t *testing.T) {
|
t.Run("MigrateData should recover and restore backup during migration critical failure", func(t *testing.T) {
|
||||||
// _, store, teardown := MustNewTestStore(t, false, true)
|
os.Setenv("PORTAINER_TEST_MIGRATE_FAIL", "FAIL")
|
||||||
// defer teardown()
|
|
||||||
|
|
||||||
// store.MigrateData()
|
version := "2.15"
|
||||||
|
_, store := MustNewTestStore(t, true, false)
|
||||||
|
store.VersionService.UpdateVersion(&models.Version{SchemaVersion: version, Edition: int(portainer.PortainerCE)})
|
||||||
|
err := store.MigrateData()
|
||||||
|
if err == nil {
|
||||||
|
t.Errorf("Expect migration to fail")
|
||||||
|
}
|
||||||
|
|
||||||
// options := store.setupOptions(getBackupRestoreOptions(store.commonBackupDir()))
|
store.Open()
|
||||||
|
testVersion(store, version, t)
|
||||||
// if isFileExist(options.BackupPath) {
|
})
|
||||||
// t.Errorf("Backup file should not exist for dirty database; file=%s", options.BackupPath)
|
|
||||||
// }
|
|
||||||
// })
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Test_getBackupRestoreOptions(t *testing.T) {
|
func Test_getBackupRestoreOptions(t *testing.T) {
|
||||||
|
|
Loading…
Reference in New Issue