Cloudreve/models/migration.go

216 lines
5.4 KiB
Go
Raw Normal View History

2019-11-06 22:35:31 +08:00
package model
2019-11-07 15:56:05 +08:00
import (
"context"
"github.com/cloudreve/Cloudreve/v3/models/scripts/invoker"
"github.com/cloudreve/Cloudreve/v3/pkg/cache"
"github.com/cloudreve/Cloudreve/v3/pkg/conf"
"github.com/cloudreve/Cloudreve/v3/pkg/util"
2020-03-09 16:53:01 +08:00
"github.com/fatih/color"
"github.com/hashicorp/go-version"
2019-11-07 15:56:05 +08:00
"github.com/jinzhu/gorm"
"sort"
"strings"
2019-11-07 15:56:05 +08:00
)
2019-11-06 22:35:31 +08:00
// 是否需要迁移
func needMigration() bool {
var setting Setting
return DB.Where("name = ?", "db_version_"+conf.RequiredDBVersion).First(&setting).Error != nil
}
2019-11-07 15:56:05 +08:00
//执行数据迁移
2019-11-06 22:35:31 +08:00
func migration() {
// 确认是否需要执行迁移
if !needMigration() {
2022-09-29 17:40:22 +08:00
util.Log().Info("Database version fulfilled, skip schema migration.")
return
}
2022-09-29 17:40:22 +08:00
util.Log().Info("Start initializing database schema...")
2020-02-26 15:11:06 +08:00
// 清除所有缓存
if instance, ok := cache.Store.(*cache.RedisStore); ok {
instance.DeleteAll()
}
2019-11-06 22:35:31 +08:00
// 自动迁移模式
2019-11-16 16:49:03 +08:00
if conf.DatabaseConfig.Type == "mysql" {
DB = DB.Set("gorm:table_options", "ENGINE=InnoDB")
}
Feat: aria2 download and transfer in slave node (#1040) * Feat: retrieve nodes from data table * Feat: master node ping slave node in REST API * Feat: master send scheduled ping request * Feat: inactive nodes recover loop * Modify: remove database operations from aria2 RPC caller implementation * Feat: init aria2 client in master node * Feat: Round Robin load balancer * Feat: create and monitor aria2 task in master node * Feat: salve receive and handle heartbeat * Fix: Node ID will be 0 in download record generated in older version * Feat: sign request headers with all `X-` prefix * Feat: API call to slave node will carry meta data in headers * Feat: call slave aria2 rpc method from master * Feat: get slave aria2 task status Feat: encode slave response data using gob * Feat: aria2 callback to master node / cancel or select task to slave node * Fix: use dummy aria2 client when caller initialize failed in master node * Feat: slave aria2 status event callback / salve RPC auth * Feat: prototype for slave driven filesystem * Feat: retry for init aria2 client in master node * Feat: init request client with global options * Feat: slave receive async task from master * Fix: competition write in request header * Refactor: dependency initialize order * Feat: generic message queue implementation * Feat: message queue implementation * Feat: master waiting slave transfer result * Feat: slave transfer file in stateless policy * Feat: slave transfer file in slave policy * Feat: slave transfer file in local policy * Feat: slave transfer file in OneDrive policy * Fix: failed to initialize update checker http client * Feat: list slave nodes for dashboard * Feat: test aria2 rpc connection in slave * Feat: add and save node * Feat: add and delete node in node pool * Fix: temp file cannot be removed when aria2 task fails * Fix: delete node in admin panel * Feat: edit node and get node info * Modify: delete unused settings
2021-10-31 09:41:56 +08:00
2020-03-11 15:22:21 +08:00
DB.AutoMigrate(&User{}, &Setting{}, &Group{}, &Policy{}, &Folder{}, &File{}, &Share{},
Feat: aria2 download and transfer in slave node (#1040) * Feat: retrieve nodes from data table * Feat: master node ping slave node in REST API * Feat: master send scheduled ping request * Feat: inactive nodes recover loop * Modify: remove database operations from aria2 RPC caller implementation * Feat: init aria2 client in master node * Feat: Round Robin load balancer * Feat: create and monitor aria2 task in master node * Feat: salve receive and handle heartbeat * Fix: Node ID will be 0 in download record generated in older version * Feat: sign request headers with all `X-` prefix * Feat: API call to slave node will carry meta data in headers * Feat: call slave aria2 rpc method from master * Feat: get slave aria2 task status Feat: encode slave response data using gob * Feat: aria2 callback to master node / cancel or select task to slave node * Fix: use dummy aria2 client when caller initialize failed in master node * Feat: slave aria2 status event callback / salve RPC auth * Feat: prototype for slave driven filesystem * Feat: retry for init aria2 client in master node * Feat: init request client with global options * Feat: slave receive async task from master * Fix: competition write in request header * Refactor: dependency initialize order * Feat: generic message queue implementation * Feat: message queue implementation * Feat: master waiting slave transfer result * Feat: slave transfer file in stateless policy * Feat: slave transfer file in slave policy * Feat: slave transfer file in local policy * Feat: slave transfer file in OneDrive policy * Fix: failed to initialize update checker http client * Feat: list slave nodes for dashboard * Feat: test aria2 rpc connection in slave * Feat: add and save node * Feat: add and delete node in node pool * Fix: temp file cannot be removed when aria2 task fails * Fix: delete node in admin panel * Feat: edit node and get node info * Modify: delete unused settings
2021-10-31 09:41:56 +08:00
&Task{}, &Download{}, &Tag{}, &Webdav{}, &Node{})
2019-11-14 14:18:10 +08:00
// 创建初始存储策略
addDefaultPolicy()
2019-11-13 16:28:14 +08:00
// 创建初始用户组
addDefaultGroups()
2019-11-07 15:56:05 +08:00
// 创建初始管理员账户
addDefaultUser()
// 创建初始节点
addDefaultNode()
// 向设置数据表添加初始设置
addDefaultSettings()
// 执行数据库升级脚本
execUpgradeScripts()
2022-09-29 17:40:22 +08:00
util.Log().Info("Finish initializing database schema.")
2019-11-23 15:09:46 +08:00
}
2019-11-14 14:18:10 +08:00
func addDefaultPolicy() {
2019-11-30 15:09:56 +08:00
_, err := GetPolicyByID(uint(1))
2019-11-14 14:18:10 +08:00
// 未找到初始存储策略时,则创建
if gorm.IsRecordNotFoundError(err) {
defaultPolicy := Policy{
2022-09-29 17:40:22 +08:00
Name: "Default storage policy",
2019-11-14 14:18:10 +08:00
Type: "local",
2020-02-26 15:11:06 +08:00
MaxSize: 0,
2019-11-14 14:18:10 +08:00
AutoRename: true,
2019-11-30 15:09:56 +08:00
DirNameRule: "uploads/{uid}/{path}",
2019-11-14 14:18:10 +08:00
FileNameRule: "{uid}_{randomkey8}_{originname}",
IsOriginLinkEnable: false,
OptionsSerialized: PolicyOption{
ChunkSize: 25 << 20, // 25MB
},
2019-11-14 14:18:10 +08:00
}
if err := DB.Create(&defaultPolicy).Error; err != nil {
2022-09-29 17:40:22 +08:00
util.Log().Panic("Failed to create default storage policy: %s", err)
2019-11-14 14:18:10 +08:00
}
}
}
func addDefaultSettings() {
for _, value := range defaultSettings {
DB.Where(Setting{Name: value.Name}).Create(&value)
}
}
2019-11-13 16:28:14 +08:00
func addDefaultGroups() {
_, err := GetGroupByID(1)
// 未找到初始管理组时,则创建
if gorm.IsRecordNotFoundError(err) {
defaultAdminGroup := Group{
2022-09-29 17:40:22 +08:00
Name: "Admin",
2019-11-14 14:18:10 +08:00
PolicyList: []uint{1},
MaxStorage: 1 * 1024 * 1024 * 1024,
ShareEnabled: true,
WebDAVEnabled: true,
OptionsSerialized: GroupOption{
2020-02-02 14:40:07 +08:00
ArchiveDownload: true,
ArchiveTask: true,
ShareDownload: true,
2020-02-22 16:22:04 +08:00
Aria2: true,
2022-04-29 19:59:25 +08:00
SourceBatchSize: 1000,
Aria2BatchSize: 50,
},
2019-11-13 16:28:14 +08:00
}
if err := DB.Create(&defaultAdminGroup).Error; err != nil {
2022-09-29 17:40:22 +08:00
util.Log().Panic("Failed to create admin user group: %s", err)
2019-11-13 16:28:14 +08:00
}
}
err = nil
_, err = GetGroupByID(2)
// 未找到初始注册会员时,则创建
if gorm.IsRecordNotFoundError(err) {
defaultAdminGroup := Group{
2022-09-29 17:40:22 +08:00
Name: "User",
2019-11-14 14:18:10 +08:00
PolicyList: []uint{1},
MaxStorage: 1 * 1024 * 1024 * 1024,
ShareEnabled: true,
WebDAVEnabled: true,
2020-03-07 13:00:51 +08:00
OptionsSerialized: GroupOption{
2022-04-29 19:59:25 +08:00
ShareDownload: true,
SourceBatchSize: 10,
Aria2BatchSize: 1,
2020-03-07 13:00:51 +08:00
},
2019-11-13 16:28:14 +08:00
}
if err := DB.Create(&defaultAdminGroup).Error; err != nil {
2022-09-29 17:40:22 +08:00
util.Log().Panic("Failed to create initial user group: %s", err)
2019-11-13 16:28:14 +08:00
}
}
err = nil
_, err = GetGroupByID(3)
// 未找到初始游客用户组时,则创建
if gorm.IsRecordNotFoundError(err) {
defaultAdminGroup := Group{
2022-09-29 17:40:22 +08:00
Name: "Anonymous",
2020-03-07 13:00:51 +08:00
PolicyList: []uint{},
Policies: "[]",
OptionsSerialized: GroupOption{
ShareDownload: true,
},
}
if err := DB.Create(&defaultAdminGroup).Error; err != nil {
2022-09-29 17:40:22 +08:00
util.Log().Panic("Failed to create anonymous user group: %s", err)
}
}
2019-11-13 16:28:14 +08:00
}
func addDefaultUser() {
2019-11-11 19:13:17 +08:00
_, err := GetUserByID(1)
2020-03-09 16:53:01 +08:00
password := util.RandStringRunes(8)
// 未找到初始用户时,则创建
2019-11-07 15:56:05 +08:00
if gorm.IsRecordNotFoundError(err) {
defaultUser := NewUser()
defaultUser.Email = "admin@cloudreve.org"
defaultUser.Nick = "admin"
defaultUser.Status = Active
2019-11-13 16:28:14 +08:00
defaultUser.GroupID = 1
2020-03-09 16:53:01 +08:00
err := defaultUser.SetPassword(password)
2019-11-07 15:56:05 +08:00
if err != nil {
2022-09-29 17:40:22 +08:00
util.Log().Panic("Failed to create password: %s", err)
2019-11-07 15:56:05 +08:00
}
if err := DB.Create(&defaultUser).Error; err != nil {
2022-09-29 17:40:22 +08:00
util.Log().Panic("Failed to create initial root user: %s", err)
2019-11-07 15:56:05 +08:00
}
2020-03-09 16:53:01 +08:00
c := color.New(color.FgWhite).Add(color.BgBlack).Add(color.Bold)
2022-09-29 17:40:22 +08:00
util.Log().Info("Admin user name: " + c.Sprint("admin@cloudreve.org"))
util.Log().Info("Admin password: " + c.Sprint(password))
2019-11-07 15:56:05 +08:00
}
2019-11-06 22:35:31 +08:00
}
func addDefaultNode() {
_, err := GetNodeByID(1)
if gorm.IsRecordNotFoundError(err) {
defaultAdminGroup := Node{
2022-09-29 17:40:22 +08:00
Name: "Master (Local machine)",
Status: NodeActive,
Type: MasterNodeType,
Aria2OptionsSerialized: Aria2Option{
Interval: 10,
Timeout: 10,
},
}
if err := DB.Create(&defaultAdminGroup).Error; err != nil {
2022-09-29 17:40:22 +08:00
util.Log().Panic("Failed to create initial node: %s", err)
}
}
}
func execUpgradeScripts() {
s := invoker.ListPrefix("UpgradeTo")
versions := make([]*version.Version, len(s))
for i, raw := range s {
v, _ := version.NewVersion(strings.TrimPrefix(raw, "UpgradeTo"))
versions[i] = v
}
sort.Sort(version.Collection(versions))
for i := 0; i < len(versions); i++ {
invoker.RunDBScript("UpgradeTo"+versions[i].String(), context.Background())
}
}