bump version and cleanup migration tool for previous version (#19)

This commit is contained in:
Tiger Wang
2022-11-02 11:05:42 -04:00
committed by GitHub
parent 7da057088c
commit e2d9ecf229
7 changed files with 33 additions and 616 deletions
+5 -8
View File
@@ -8,7 +8,6 @@ import (
interfaces "github.com/IceWhaleTech/CasaOS-Common"
"github.com/IceWhaleTech/CasaOS-Common/utils/systemctl"
"github.com/IceWhaleTech/CasaOS-Common/utils/version"
"github.com/IceWhaleTech/CasaOS-UserService/common"
)
@@ -20,12 +19,11 @@ const (
)
//go:embedded ../../build/sysroot/etc/casaos/user-service.conf.sample
var _userServiceConfigFileSample string
//var _userServiceConfigFileSample string
var (
_logger *Logger
_status *version.GlobalMigrationStatus
)
var _logger *Logger
// var _status *version.GlobalMigrationStatus
func main() {
versionFlag := flag.Bool("v", false, "version")
@@ -63,8 +61,7 @@ func main() {
}
migrationTools := []interfaces.MigrationTool{
NewMigrationToolFor032AndOlder(),
NewMigrationToolFor033_034_035(),
NewMigrationDummy(),
}
var selectedMigrationTool interfaces.MigrationTool
@@ -1,262 +0,0 @@
package main
import (
"database/sql"
"os"
"path/filepath"
"strconv"
"strings"
"time"
interfaces "github.com/IceWhaleTech/CasaOS-Common"
"github.com/IceWhaleTech/CasaOS-Common/utils/version"
"github.com/IceWhaleTech/CasaOS-UserService/common"
"github.com/IceWhaleTech/CasaOS-UserService/pkg/config"
"github.com/IceWhaleTech/CasaOS-UserService/pkg/sqlite"
"github.com/IceWhaleTech/CasaOS-UserService/pkg/utils/encryption"
"github.com/IceWhaleTech/CasaOS-UserService/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS-UserService/service"
"github.com/IceWhaleTech/CasaOS-UserService/service/model"
"gopkg.in/ini.v1"
)
type migrationTool1 struct{}
func (u *migrationTool1) IsMigrationNeeded() (bool, error) {
if status, err := version.GetGlobalMigrationStatus(userServiceNameShort); err == nil {
_status = status
if status.LastMigratedVersion != "" {
_logger.Info("Last migrated version: %s", status.LastMigratedVersion)
if r, err := version.Compare(status.LastMigratedVersion, common.Version); err == nil {
return r < 0, nil
}
}
}
if _, err := os.Stat(version.LegacyCasaOSConfigFilePath); err != nil {
_logger.Info("`%s` not found, migration is not needed.", version.LegacyCasaOSConfigFilePath)
return false, nil
}
majorVersion, minorVersion, patchVersion, err := version.DetectLegacyVersion()
if err != nil {
if err == version.ErrLegacyVersionNotFound {
return false, nil
}
return false, err
}
if majorVersion != 0 {
return false, nil
}
if minorVersion == 2 {
_logger.Info("Migration is needed for a CasaOS version 0.2.x...")
return true, nil
}
if minorVersion == 3 && patchVersion < 2 {
_logger.Info("Migration is needed for a CasaOS version between 0.3.0 and 0.3.2...")
return true, nil
}
return false, nil
}
func (u *migrationTool1) PreMigrate() error {
if _, err := os.Stat(userServiceConfigDirPath); os.IsNotExist(err) {
_logger.Info("Creating %s since it doesn't exists...", userServiceConfigDirPath)
if err := os.Mkdir(userServiceConfigDirPath, 0o755); err != nil {
return err
}
}
if _, err := os.Stat(userServiceConfigFilePath); os.IsNotExist(err) {
_logger.Info("Creating %s since it doesn't exist...", userServiceConfigFilePath)
f, err := os.Create(userServiceConfigFilePath)
if err != nil {
return err
}
defer f.Close()
if _, err := f.WriteString(_userServiceConfigFileSample); err != nil {
return err
}
}
extension := "." + time.Now().Format("20060102") + ".bak"
_logger.Info("Creating a backup %s if it doesn't exist...", version.LegacyCasaOSConfigFilePath+extension)
return file.CopySingleFile(version.LegacyCasaOSConfigFilePath, version.LegacyCasaOSConfigFilePath+extension, "skip")
}
func (u *migrationTool1) Migrate() error {
_logger.Info("Loading legacy %s...", version.LegacyCasaOSConfigFilePath)
legacyConfigFile, err := ini.Load(version.LegacyCasaOSConfigFilePath)
if err != nil {
return err
}
migrateConfigurationFile1(legacyConfigFile)
return migrateUser1(legacyConfigFile)
}
func (u *migrationTool1) PostMigrate() error {
defer _status.Done(common.Version)
legacyConfigFile, err := ini.Load(version.LegacyCasaOSConfigFilePath)
if err != nil {
return err
}
_logger.Info("Deleting legacy `user` section in %s...", version.LegacyCasaOSConfigFilePath)
legacyConfigFile.DeleteSection("user")
if err := legacyConfigFile.SaveTo(version.LegacyCasaOSConfigFilePath); err != nil {
return err
}
dbPath := legacyConfigFile.Section("app").Key("DBPath").String()
dbFile := filepath.Join(dbPath, "db", "casaOS.db")
if _, err := os.Stat(dbFile); err != nil {
dbFile = filepath.Join(defaultDBPath, "db", "casaOS.db")
if _, err := os.Stat(dbFile); err != nil {
return nil
}
}
legacyDB, err := sql.Open("sqlite3", dbFile)
if err != nil {
return err
}
defer legacyDB.Close()
for _, tableName := range []string{"o_users", "o_user"} {
tableExists, err := isTableExist(legacyDB, tableName)
if err != nil {
return err
}
if !tableExists {
continue
}
_logger.Info("Dropping `%s` table in legacy database...", tableName)
if _, err = legacyDB.Exec("DROP TABLE " + tableName); err != nil {
_logger.Error("Failed to drop `%s` table in legacy database: %s", tableName, err)
}
}
return nil
}
func NewMigrationToolFor032AndOlder() interfaces.MigrationTool {
return &migrationTool1{}
}
func migrateConfigurationFile1(legacyConfigFile *ini.File) {
_logger.Info("Updating %s with settings from legacy configuration...", config.UserServiceConfigFilePath)
config.InitSetup(config.UserServiceConfigFilePath)
// LogPath
if logPath, err := legacyConfigFile.Section("app").GetKey("LogPath"); err == nil {
_logger.Info("[app] LogPath = %s", logPath.Value())
config.AppInfo.LogPath = logPath.Value()
}
if logPath, err := legacyConfigFile.Section("app").GetKey("LogSavePath"); err == nil {
_logger.Info("[app] LogSavePath = %s", logPath.Value())
config.AppInfo.LogPath = logPath.Value()
}
// LogFileExt
if logFileExt, err := legacyConfigFile.Section("app").GetKey("LogFileExt"); err == nil {
_logger.Info("[app] LogFileExt = %s", logFileExt.Value())
config.AppInfo.LogFileExt = logFileExt.Value()
}
// UserDataPath
if userDataPath, err := legacyConfigFile.Section("app").GetKey("UserDataPath"); err == nil {
_logger.Info("[app] UserDataPath = %s", userDataPath.Value())
config.AppInfo.UserDataPath = userDataPath.Value()
}
_logger.Info("Saving %s...", config.UserServiceConfigFilePath)
config.SaveSetup(config.UserServiceConfigFilePath)
}
func migrateUser1(legacyConfigFile *ini.File) error {
_logger.Info("Migrating user from configuration file to database...")
user := model.UserDBModel{Role: "admin"}
// UserName
if userName, err := legacyConfigFile.Section("user").GetKey("UserName"); err == nil {
_logger.Info("[user] UserName = %s", userName.Value())
user.Username = userName.Value()
}
// Email
if userEmail, err := legacyConfigFile.Section("user").GetKey("Email"); err == nil {
_logger.Info("[user] Email = %s", userEmail.Value())
user.Email = userEmail.Value()
}
// NickName
if userNickName, err := legacyConfigFile.Section("user").GetKey("NickName"); err == nil {
_logger.Info("[user] NickName = %s", userNickName.Value())
user.Nickname = userNickName.Value()
}
// Password
if userPassword, err := legacyConfigFile.Section("user").GetKey("PWD"); err == nil {
_logger.Info("[user] Password = %s", strings.Repeat("*", len(userPassword.Value())))
user.Password = encryption.GetMD5ByStr(userPassword.Value())
}
newDB := sqlite.GetDb(config.AppInfo.DBPath)
userService := service.NewUserService(newDB)
if len(user.Username) == 0 {
_logger.Info("No user found in legacy configuration file. Skipping...")
return nil
}
if userService.GetUserInfoByUserName(user.Username).Id > 0 {
_logger.Info("User `%s` already exists in user database at %s. Skipping...", user.Username, config.AppInfo.DBPath)
return nil
}
_logger.Info("Creating user %s in database at %s...", user.Username, config.AppInfo.DBPath)
user = userService.CreateUser(user)
if user.Id > 0 {
userPath := config.AppInfo.UserDataPath + "/" + strconv.Itoa(user.Id)
_logger.Info("Creating user data path: %s", userPath)
if err := file.MkDir(userPath); err != nil {
return err
}
if legacyProjectPath, err := legacyConfigFile.Section("app").GetKey("ProjectPath"); err == nil {
appOrderJSONFile := filepath.Join(legacyProjectPath.Value(), "app_order.json")
if _, err := os.Stat(appOrderJSONFile); err == nil {
_logger.Info("Moving %s to %s...", appOrderJSONFile, userPath)
if err := os.Rename(appOrderJSONFile, filepath.Join(userPath, "app_order.json")); err != nil {
return err
}
}
}
}
return nil
}
-309
View File
@@ -1,309 +0,0 @@
package main
import (
"database/sql"
"os"
"path/filepath"
"time"
interfaces "github.com/IceWhaleTech/CasaOS-Common"
"github.com/IceWhaleTech/CasaOS-Common/utils/version"
"github.com/IceWhaleTech/CasaOS-UserService/common"
"github.com/IceWhaleTech/CasaOS-UserService/pkg/config"
"github.com/IceWhaleTech/CasaOS-UserService/pkg/sqlite"
"github.com/IceWhaleTech/CasaOS-UserService/pkg/utils/file"
"github.com/IceWhaleTech/CasaOS-UserService/service"
"github.com/IceWhaleTech/CasaOS-UserService/service/model"
"gopkg.in/ini.v1"
)
type migrationTool2 struct{}
const defaultDBPath = "/var/lib/casaos"
func (u *migrationTool2) IsMigrationNeeded() (bool, error) {
if status, err := version.GetGlobalMigrationStatus(userServiceNameShort); err == nil {
_status = status
if status.LastMigratedVersion != "" {
_logger.Info("Last migrated version: %s", status.LastMigratedVersion)
if r, err := version.Compare(status.LastMigratedVersion, common.Version); err == nil {
return r < 0, nil
}
}
}
if _, err := os.Stat(version.LegacyCasaOSConfigFilePath); err != nil {
_logger.Info("`%s` not found, migration is not needed.", version.LegacyCasaOSConfigFilePath)
return false, nil
}
majorVersion, minorVersion, patchVersion, err := version.DetectLegacyVersion()
if err != nil {
if err == version.ErrLegacyVersionNotFound {
return false, nil
}
return false, err
}
if majorVersion != 0 {
return false, nil
}
if minorVersion != 3 {
return false, nil
}
if patchVersion < 3 || patchVersion > 5 {
return false, nil
}
// legacy version has to be between 0.3.3 and 0.3.5
_logger.Info("Migration is needed for a CasaOS version between 0.3.3 and 0.3.5...")
return true, nil
}
func (u *migrationTool2) PreMigrate() error {
if _, err := os.Stat(userServiceConfigDirPath); os.IsNotExist(err) {
_logger.Info("Creating %s since it doesn't exists...", userServiceConfigDirPath)
if err := os.Mkdir(userServiceConfigDirPath, 0o755); err != nil {
return err
}
}
if _, err := os.Stat(userServiceConfigFilePath); os.IsNotExist(err) {
_logger.Info("Creating %s since it doesn't exist...", userServiceConfigFilePath)
f, err := os.Create(userServiceConfigFilePath)
if err != nil {
return err
}
defer f.Close()
if _, err := f.WriteString(_userServiceConfigFileSample); err != nil {
return err
}
}
extension := "." + time.Now().Format("20060102") + ".bak"
_logger.Info("Creating a backup %s if it doesn't exist...", version.LegacyCasaOSConfigFilePath+extension)
if err := file.CopySingleFile(version.LegacyCasaOSConfigFilePath, version.LegacyCasaOSConfigFilePath+extension, "skip"); err != nil {
return err
}
legacyConfigFile, err := ini.Load(version.LegacyCasaOSConfigFilePath)
if err != nil {
return err
}
dbPath := legacyConfigFile.Section("app").Key("DBPath").String()
dbFile := filepath.Join(dbPath, "db", "casaOS.db")
if _, err := os.Stat(dbFile); err != nil {
dbFile = filepath.Join(defaultDBPath, "db", "casaOS.db")
if _, err := os.Stat(dbFile); err != nil {
return err
}
}
_logger.Info("Creating a backup %s if it doesn't exist...", dbFile+extension)
if err := file.CopySingleFile(dbFile, dbFile+extension, "skip"); err != nil {
return err
}
return nil
}
func (u *migrationTool2) Migrate() error {
_logger.Info("Loading legacy %s...", version.LegacyCasaOSConfigFilePath)
legacyConfigFile, err := ini.Load(version.LegacyCasaOSConfigFilePath)
if err != nil {
return err
}
migrateConfigurationFile2(legacyConfigFile)
return migrateUser2(legacyConfigFile)
}
func (u *migrationTool2) PostMigrate() error {
defer _status.Done(common.Version)
legacyConfigFile, err := ini.Load(version.LegacyCasaOSConfigFilePath)
if err != nil {
return err
}
_logger.Info("Deleting legacy `user` section in %s...", version.LegacyCasaOSConfigFilePath)
legacyConfigFile.DeleteSection("user")
if err := legacyConfigFile.SaveTo(version.LegacyCasaOSConfigFilePath); err != nil {
return err
}
dbPath := legacyConfigFile.Section("app").Key("DBPath").String()
dbFile := filepath.Join(dbPath, "db", "casaOS.db")
if _, err := os.Stat(dbFile); err != nil {
dbFile = filepath.Join(defaultDBPath, "db", "casaOS.db")
if _, err := os.Stat(dbFile); err != nil {
return nil
}
}
legacyDB, err := sql.Open("sqlite3", dbFile)
if err != nil {
return err
}
defer legacyDB.Close()
for _, tableName := range []string{"o_users", "o_user"} {
tableExists, err := isTableExist(legacyDB, tableName)
if err != nil {
return err
}
if !tableExists {
continue
}
_logger.Info("Dropping `%s` table in legacy database...", tableName)
if _, err = legacyDB.Exec("DROP TABLE " + tableName); err != nil {
_logger.Error("Failed to drop `%s` table in legacy database: %s", tableName, err)
}
}
return nil
}
func NewMigrationToolFor033_034_035() interfaces.MigrationTool {
return &migrationTool2{}
}
func migrateConfigurationFile2(legacyConfigFile *ini.File) {
_logger.Info("Updating %s with settings from legacy configuration...", config.UserServiceConfigFilePath)
config.InitSetup(config.UserServiceConfigFilePath)
// LogPath
if logPath, err := legacyConfigFile.Section("app").GetKey("LogPath"); err == nil {
_logger.Info("[app] LogPath = %s", logPath.Value())
config.AppInfo.LogPath = logPath.Value()
}
// LogFileExt
if logFileExt, err := legacyConfigFile.Section("app").GetKey("LogFileExt"); err == nil {
_logger.Info("[app] LogFileExt = %s", logFileExt.Value())
config.AppInfo.LogFileExt = logFileExt.Value()
}
// DBPath
if dbPath, err := legacyConfigFile.Section("app").GetKey("DBPath"); err == nil {
_logger.Info("[app] DBPath = %s", dbPath.Value())
config.AppInfo.DBPath = dbPath.Value() + "/db"
}
// UserDataPath
if userDataPath, err := legacyConfigFile.Section("app").GetKey("UserDataPath"); err == nil {
_logger.Info("[app] UserDataPath = %s", userDataPath.Value())
config.AppInfo.UserDataPath = userDataPath.Value()
}
_logger.Info("Saving %s...", config.UserServiceConfigFilePath)
config.SaveSetup(config.UserServiceConfigFilePath)
}
func migrateUser2(legacyConfigFile *ini.File) error {
_logger.Info("Migrating user from legacy database to user database...")
user := model.UserDBModel{Role: "admin"}
dbPath := legacyConfigFile.Section("app").Key("DBPath").String()
dbFile := filepath.Join(dbPath, "db", "casaOS.db")
if _, err := os.Stat(dbFile); err != nil {
dbFile = filepath.Join(defaultDBPath, "db", "casaOS.db")
if _, err := os.Stat(dbFile); err != nil {
return err
}
}
legacyDB, err := sql.Open("sqlite3", dbFile)
if err != nil {
return err
}
defer legacyDB.Close()
newDB := sqlite.GetDb(config.AppInfo.DBPath)
userService := service.NewUserService(newDB)
// create an inline map from string to string
sqlTableStatementMap := make(map[string]string)
sqlTableStatementMap["o_users"] = "SELECT id, username, password, role, email, nickname, avatar, description, created_at FROM o_users ORDER BY id ASC"
sqlTableStatementMap["o_user"] = "SELECT id, user_name, password, role, email, nick_name, avatar, description, created_at FROM o_user ORDER BY id ASC"
// historically there were two names for user table: o_users and users
for tableName, sqlStatement := range sqlTableStatementMap {
tableExists, err := isTableExist(legacyDB, tableName)
if err != nil {
return err
}
if !tableExists {
continue
}
rows, err := legacyDB.Query(sqlStatement)
if err != nil {
return err
}
defer rows.Close()
for rows.Next() {
if err := rows.Scan(
&user.Id,
&user.Username,
&user.Password,
&user.Role,
&user.Email,
&user.Nickname,
&user.Avatar,
&user.Description,
&user.CreatedAt,
); err != nil {
return err
}
if userService.GetUserAllInfoByName(user.Username).Id > 0 {
_logger.Info("User %s already exists in user database at %s, skipping...", user.Username, config.AppInfo.DBPath)
continue
}
_logger.Info("Creating user %s in user database...", user.Username)
user = userService.CreateUser(user)
}
}
return nil
}
func isTableExist(legacyDB *sql.DB, tableName string) (bool, error) {
rows, err := legacyDB.Query("SELECT name FROM sqlite_master WHERE type='table' AND name= ?", tableName)
if err != nil {
return false, err
}
defer rows.Close()
return rows.Next(), nil
}
+27
View File
@@ -0,0 +1,27 @@
package main
import (
interfaces "github.com/IceWhaleTech/CasaOS-Common"
)
type migrationTool struct{}
func (u *migrationTool) IsMigrationNeeded() (bool, error) {
return false, nil
}
func (u *migrationTool) PreMigrate() error {
return nil
}
func (u *migrationTool) Migrate() error {
return nil
}
func (u *migrationTool) PostMigrate() error {
return nil
}
func NewMigrationDummy() interfaces.MigrationTool {
return &migrationTool{}
}