portainer/api/datastore/migrator/migrate_ce.go

126 lines
3.7 KiB
Go
Raw Normal View History

package migrator
import (
"reflect"
"runtime"
"github.com/pkg/errors"
portainer "github.com/portainer/portainer/api"
"github.com/Masterminds/semver"
"github.com/rs/zerolog/log"
)
func migrationError(err error, context string) error {
return errors.Wrap(err, "failed in "+context)
}
func GetFunctionName(i interface{}) string {
return runtime.FuncForPC(reflect.ValueOf(i).Pointer()).Name()
}
// Migrate checks the database version and migrate the existing data to the most recent data model.
func (m *Migrator) Migrate() error {
version, err := m.versionService.Version()
if err != nil {
return migrationError(err, "get version service")
}
schemaVersion, err := semver.NewVersion(version.SchemaVersion)
if err != nil {
return migrationError(err, "invalid db schema version")
}
newMigratorCount := 0
apiVersion := semver.MustParse(portainer.APIVersion)
if schemaVersion.Equal(apiVersion) {
// detect and run migrations when the versions are the same.
// e.g. development builds
latestMigrations := m.LatestMigrations()
if latestMigrations.Version.Equal(schemaVersion) &&
version.MigratorCount != len(latestMigrations.MigrationFuncs) {
err := runMigrations(latestMigrations.MigrationFuncs)
if err != nil {
return err
}
newMigratorCount = len(latestMigrations.MigrationFuncs)
}
} else {
// regular path when major/minor/patch versions differ
for _, migration := range m.migrations {
if schemaVersion.LessThan(migration.Version) {
log.Info().Msgf("migrating data to %s", migration.Version.String())
err := runMigrations(migration.MigrationFuncs)
if err != nil {
return err
}
}
if apiVersion.Equal(migration.Version) {
newMigratorCount = len(migration.MigrationFuncs)
}
}
}
feat(internal-auth): ability to set minimum password length [EE-3175] (#6942) * feat(internal-auth): ability to set minimum password length [EE-3175] * pass props to react component * fixes + WIP slider * fix slider updating + add styles * remove nested ternary * fix slider updating + add remind me later button * add length to settings + value & onchange method * finish my account view * fix slider updating * slider styles * update style * move slider in * update size of slider * allow admin to browse to authentication view * use feather icons instead of font awesome * feat(settings): add colors to password rules * clean up tooltip styles * more style changes * styles * fixes + use requiredLength in password field for icon logic * simplify logic * simplify slider logic and remove debug code * use required length for logic to display pwd length warning * fix slider styles * use requiredPasswordLength to determine if password is valid * style tooltip based on theme * reset skips when password is changed * misc cleanup * reset skips when required length is changed * fix formatting * fix issues * implement some suggestions * simplify logic * update broken test * pick min password length from DB * fix suggestions * set up min password length in the DB * fix test after migration * fix formatting issue * fix bug with icon * refactored migration * fix typo * fixes * fix logic * set skips per user * reset skips for all users on length change Co-authored-by: Chaim Lev-Ari <chiptus@gmail.com> Co-authored-by: Dmitry Salakhov <to@dimasalakhov.com>
2022-06-03 04:00:13 +00:00
err = m.Always()
if err != nil {
return migrationError(err, "Always migrations returned error")
}
version.SchemaVersion = portainer.APIVersion
version.MigratorCount = newMigratorCount
err = m.versionService.UpdateVersion(version)
if err != nil {
return migrationError(err, "StoreDBVersion")
}
log.Info().Msgf("db migrated to %s", portainer.APIVersion)
return nil
}
func runMigrations(migrationFuncs []func() error) error {
for _, migrationFunc := range migrationFuncs {
err := migrationFunc()
if err != nil {
return migrationError(err, GetFunctionName(migrationFunc))
}
}
return nil
}
func (m *Migrator) NeedsMigration() bool {
// we need to migrate if anything changes with the version in the DB vs what our software version is.
// If the version matches, then it's all down to the number of migration funcs we have for the current version
// i.e. the MigratorCount
// In this particular instance we should log a fatal error
if m.CurrentDBEdition() != portainer.PortainerCE {
log.Fatal().Msg("the Portainer database is set for Portainer Business Edition, please follow the instructions in our documentation to downgrade it: https://documentation.portainer.io/v2.0-be/downgrade/be-to-ce/")
return false
}
if m.CurrentSemanticDBVersion().LessThan(semver.MustParse(portainer.APIVersion)) {
return true
}
// Check if we have any migrations for the current version
latestMigrations := m.LatestMigrations()
if latestMigrations.Version.Equal(semver.MustParse(portainer.APIVersion)) {
if m.currentDBVersion.MigratorCount != len(latestMigrations.MigrationFuncs) {
return true
}
} else {
// One remaining possibility if we get here. If our migrator count > 0 and we have no migration funcs
// for the current version (i.e. they were deleted during development). Then we we need to migrate.
// This is to reset the migrator count back to 0
if m.currentDBVersion.MigratorCount > 0 {
return true
}
}
return false
}