Files
EdgeAdmin/internal/web/actions/default/setup/install.go

317 lines
9.6 KiB
Go
Raw Normal View History

2020-10-13 20:05:29 +08:00
package setup
import (
"bytes"
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/configs"
"github.com/TeaOSLab/EdgeAdmin/internal/nodes"
2020-10-13 20:05:29 +08:00
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
2021-07-20 17:15:17 +08:00
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
2020-10-13 20:05:29 +08:00
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
2020-10-13 20:05:29 +08:00
"github.com/go-yaml/yaml"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/dbs"
2021-11-01 21:09:52 +08:00
"github.com/iwind/TeaGo/logs"
2020-10-13 20:05:29 +08:00
"github.com/iwind/TeaGo/maps"
"io/ioutil"
"os"
"os/exec"
"time"
)
type InstallAction struct {
actionutils.ParentAction
}
func (this *InstallAction) RunPost(params struct {
ApiNodeJSON []byte
DbJSON []byte
AdminJSON []byte
Must *actions.Must
}) {
2021-11-01 21:09:52 +08:00
currentStatusText = ""
defer func() {
currentStatusText = ""
}()
2020-10-13 20:05:29 +08:00
// API节点配置
2021-11-01 21:09:52 +08:00
currentStatusText = "正在检查API节点配置"
2020-10-13 20:05:29 +08:00
apiNodeMap := maps.Map{}
err := json.Unmarshal(params.ApiNodeJSON, &apiNodeMap)
if err != nil {
this.Fail("API节点配置数据解析错误请刷新页面后重新尝试安装错误信息" + err.Error())
}
// 数据库
2021-11-01 21:09:52 +08:00
currentStatusText = "正在检查数据库配置"
2020-10-13 20:05:29 +08:00
dbMap := maps.Map{}
err = json.Unmarshal(params.DbJSON, &dbMap)
if err != nil {
this.Fail("数据库配置数据解析错误,请刷新页面后重新尝试安装,错误信息:" + err.Error())
}
// 管理员
2021-11-01 21:09:52 +08:00
currentStatusText = "正在检查管理员配置"
2020-10-13 20:05:29 +08:00
adminMap := maps.Map{}
err = json.Unmarshal(params.AdminJSON, &adminMap)
if err != nil {
this.Fail("管理员数据解析错误,请刷新页面后重新尝试安装,错误信息:" + err.Error())
}
// 安装API节点
mode := apiNodeMap.GetString("mode")
if mode == "new" {
2021-11-01 21:09:52 +08:00
currentStatusText = "准备启动新API节点"
2020-10-13 20:05:29 +08:00
// 整个系统目录结构为:
// edge-admin/
// edge-api/
// bin/
// ...
// 检查环境
apiNodeDir := Tea.Root + "/edge-api"
for _, dir := range []string{"edge-api", "edge-api/configs", "edge-api/bin"} {
apiNodeDir := Tea.Root + "/" + dir
_, err = os.Stat(apiNodeDir)
if err != nil {
if os.IsNotExist(err) {
2021-07-20 17:15:17 +08:00
this.Fail("在当前目录(" + Tea.Root + ")下找不到" + dir + "目录,请将" + dir + "目录上传或者重新下载解压")
2020-10-13 20:05:29 +08:00
}
this.Fail("无法检查" + dir + "目录,发生错误:" + err.Error())
}
}
// 保存数据库配置
2021-07-20 17:15:17 +08:00
dsn := dbMap.GetString("username") + ":" + dbMap.GetString("password") + "@tcp(" + configutils.QuoteIP(dbMap.GetString("host")) + ":" + dbMap.GetString("port") + ")/" + dbMap.GetString("database") + "?charset=utf8mb4&timeout=30s"
2020-10-13 20:05:29 +08:00
dbConfig := &dbs.Config{
DBs: map[string]*dbs.DBConfig{
"prod": {
Driver: "mysql",
Dsn: dsn,
Prefix: "edge",
}},
}
dbConfig.Default.DB = "prod"
2020-10-13 20:05:29 +08:00
dbConfigData, err := yaml.Marshal(dbConfig)
if err != nil {
this.Fail("生成数据库配置失败:" + err.Error())
}
err = ioutil.WriteFile(apiNodeDir+"/configs/db.yaml", dbConfigData, 0666)
if err != nil {
this.Fail("保存数据库配置失败:" + err.Error())
}
// 生成备份文件
homeDir, _ := os.UserHomeDir()
backupDirs := []string{"/etc/edge-api"}
if len(homeDir) > 0 {
backupDirs = append(backupDirs, homeDir+"/.edge-api")
}
for _, backupDir := range backupDirs {
stat, err := os.Stat(backupDir)
if err == nil && stat.IsDir() {
_ = ioutil.WriteFile(backupDir+"/db.yaml", dbConfigData, 0666)
} else if err != nil && os.IsNotExist(err) {
err = os.Mkdir(backupDir, 0777)
if err == nil {
_ = ioutil.WriteFile(backupDir+"/db.yaml", dbConfigData, 0666)
}
}
}
2020-10-13 20:05:29 +08:00
err = ioutil.WriteFile(Tea.ConfigFile("/api_db.yaml"), dbConfigData, 0666)
if err != nil {
this.Fail("保存数据库配置失败:" + err.Error())
}
// 生成备份文件
backupDirs = []string{"/etc/edge-admin"}
if len(homeDir) > 0 {
backupDirs = append(backupDirs, homeDir+"/.edge-admin")
}
for _, backupDir := range backupDirs {
stat, err := os.Stat(backupDir)
if err == nil && stat.IsDir() {
_ = ioutil.WriteFile(backupDir+"/api_db.yaml", dbConfigData, 0666)
} else if err != nil && os.IsNotExist(err) {
err = os.Mkdir(backupDir, 0777)
if err == nil {
_ = ioutil.WriteFile(backupDir+"/api_db.yaml", dbConfigData, 0666)
}
}
}
2020-10-13 20:05:29 +08:00
// 开始安装
2021-11-01 21:09:52 +08:00
currentStatusText = "正在安装数据库表结构并写入数据"
2020-10-13 20:05:29 +08:00
var resultMap = maps.Map{}
2021-11-01 21:09:52 +08:00
logs.Println("[INSTALL]setup edge-api")
2020-10-13 20:05:29 +08:00
{
cmd := exec.Command(apiNodeDir+"/bin/edge-api", "setup", "-api-node-protocol=http", "-api-node-host=\""+apiNodeMap.GetString("newHost")+"\"", "-api-node-port=\""+apiNodeMap.GetString("newPort")+"\"")
output := bytes.NewBuffer([]byte{})
cmd.Stdout = output
err = cmd.Run()
if err != nil {
this.Fail("安装失败:" + err.Error())
}
resultData := output.Bytes()
err = json.Unmarshal(resultData, &resultMap)
if err != nil {
this.Fail("安装节点时返回数据错误:" + err.Error() + "(" + string(resultData) + ")")
}
if !resultMap.GetBool("isOk") {
this.Fail("节点安装错误:" + resultMap.GetString("error"))
}
}
2021-11-01 21:09:52 +08:00
// 关闭正在运行的API节点防止冲突
logs.Println("[INSTALL]stop edge-api")
{
cmd := exec.Command(apiNodeDir+"/bin/edge-api", "stop")
_ = cmd.Run()
}
2020-10-13 20:05:29 +08:00
// 启动API节点
2021-11-01 21:09:52 +08:00
currentStatusText = "正在启动API节点"
logs.Println("[INSTALL]start edge-api")
2020-10-13 20:05:29 +08:00
{
cmd := exec.Command(apiNodeDir + "/bin/edge-api")
err = cmd.Start()
if err != nil {
this.Fail("API节点启动失败" + err.Error())
}
// 记录子PID方便退出的时候一起退出
nodes.SharedAdminNode.AddSubPID(cmd.Process.Pid)
// 等待API节点初始化完成
time.Sleep(5 * time.Second)
2020-10-13 20:05:29 +08:00
}
// 写入API节点配置完成安装
apiConfig := &configs.APIConfig{
RPC: struct {
Endpoints []string `yaml:"endpoints"`
}{
2021-07-20 17:15:17 +08:00
Endpoints: []string{"http://" + configutils.QuoteIP(apiNodeMap.GetString("newHost")) + ":" + apiNodeMap.GetString("newPort")},
2020-10-13 20:05:29 +08:00
},
NodeId: resultMap.GetString("adminNodeId"),
Secret: resultMap.GetString("adminNodeSecret"),
}
// 设置管理员
2021-11-01 21:09:52 +08:00
currentStatusText = "正在设置管理员"
2021-11-10 22:22:27 +08:00
client, err := rpc.NewRPCClient(apiConfig, false)
2020-10-13 20:05:29 +08:00
if err != nil {
this.FailField("oldHost", "测试API节点时出错请检查配置错误信息"+err.Error())
}
ctx := client.Context(0)
for i := 0; i < 3; i++ {
_, err = client.AdminRPC().CreateOrUpdateAdmin(ctx, &pb.CreateOrUpdateAdminRequest{
Username: adminMap.GetString("username"),
Password: adminMap.GetString("password"),
})
2021-06-17 21:17:43 +08:00
// 这里我们尝试多次是为了等待API节点启动完毕
2020-10-13 20:05:29 +08:00
if err != nil {
time.Sleep(1 * time.Second)
}
}
if err != nil {
this.Fail("设置管理员账号出错:" + err.Error())
}
// 设置访问日志保留天数
2021-11-01 21:09:52 +08:00
currentStatusText = "正在配置访问日志保留天数"
var accessLogKeepDays = dbMap.GetInt("accessLogKeepDays")
if accessLogKeepDays > 0 {
var config = &systemconfigs.DatabaseConfig{}
config.ServerAccessLog.Clean.Days = accessLogKeepDays
configJSON, err := json.Marshal(config)
if err != nil {
this.Fail("配置设置访问日志保留天数出错:" + err.Error())
return
}
_, err = client.SysSettingRPC().UpdateSysSetting(ctx, &pb.UpdateSysSettingRequest{
Code: systemconfigs.SettingCodeDatabaseConfigSetting,
ValueJSON: configJSON,
})
if err != nil {
this.Fail("配置设置访问日志保留天数出错:" + err.Error())
return
}
}
2020-10-13 20:05:29 +08:00
err = apiConfig.WriteFile(Tea.ConfigFile("api.yaml"))
if err != nil {
this.Fail("保存配置失败,原因:" + err.Error())
}
this.Success()
} else if mode == "old" {
// 构造RPC
apiConfig := &configs.APIConfig{
RPC: struct {
Endpoints []string `yaml:"endpoints"`
}{
2021-07-20 17:15:17 +08:00
Endpoints: []string{apiNodeMap.GetString("oldProtocol") + "://" + configutils.QuoteIP(apiNodeMap.GetString("oldHost")) + ":" + apiNodeMap.GetString("oldPort")},
2020-10-13 20:05:29 +08:00
},
NodeId: apiNodeMap.GetString("oldNodeId"),
Secret: apiNodeMap.GetString("oldNodeSecret"),
}
2021-11-10 22:22:27 +08:00
client, err := rpc.NewRPCClient(apiConfig, false)
2020-10-13 20:05:29 +08:00
if err != nil {
this.FailField("oldHost", "测试API节点时出错请检查配置错误信息"+err.Error())
}
2021-11-10 22:22:27 +08:00
defer func() {
_ = client.Close()
}()
2020-10-13 20:05:29 +08:00
// 设置管理员
ctx := client.APIContext(0)
_, err = client.AdminRPC().CreateOrUpdateAdmin(ctx, &pb.CreateOrUpdateAdminRequest{
Username: adminMap.GetString("username"),
Password: adminMap.GetString("password"),
})
if err != nil {
this.Fail("设置管理员账号出错:" + err.Error())
}
// 设置访问日志保留天数
var accessLogKeepDays = dbMap.GetInt("accessLogKeepDays")
if accessLogKeepDays > 0 {
var config = &systemconfigs.DatabaseConfig{}
config.ServerAccessLog.Clean.Days = accessLogKeepDays
configJSON, err := json.Marshal(config)
if err != nil {
this.Fail("配置设置访问日志保留天数出错:" + err.Error())
return
}
_, err = client.SysSettingRPC().UpdateSysSetting(ctx, &pb.UpdateSysSettingRequest{
Code: systemconfigs.SettingCodeDatabaseConfigSetting,
ValueJSON: configJSON,
})
if err != nil {
this.Fail("配置设置访问日志保留天数出错:" + err.Error())
return
}
}
2020-10-13 20:05:29 +08:00
// 写入API节点配置完成安装
err = apiConfig.WriteFile(Tea.ConfigFile("api.yaml"))
if err != nil {
this.Fail("保存配置失败,原因:" + err.Error())
}
// 成功
this.Success()
} else {
this.Fail("错误的API节点模式'" + mode + "'")
}
}