Files
EdgeAdmin/internal/web/actions/default/setup/install.go
2021-07-20 17:15:17 +08:00

289 lines
8.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

package setup
import (
"bytes"
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/configs"
"github.com/TeaOSLab/EdgeAdmin/internal/nodes"
"github.com/TeaOSLab/EdgeAdmin/internal/rpc"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
"github.com/go-yaml/yaml"
"github.com/iwind/TeaGo/Tea"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/dbs"
"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
}) {
// API节点配置
apiNodeMap := maps.Map{}
err := json.Unmarshal(params.ApiNodeJSON, &apiNodeMap)
if err != nil {
this.Fail("API节点配置数据解析错误请刷新页面后重新尝试安装错误信息" + err.Error())
}
// 数据库
dbMap := maps.Map{}
err = json.Unmarshal(params.DbJSON, &dbMap)
if err != nil {
this.Fail("数据库配置数据解析错误,请刷新页面后重新尝试安装,错误信息:" + err.Error())
}
// 管理员
adminMap := maps.Map{}
err = json.Unmarshal(params.AdminJSON, &adminMap)
if err != nil {
this.Fail("管理员数据解析错误,请刷新页面后重新尝试安装,错误信息:" + err.Error())
}
// 安装API节点
mode := apiNodeMap.GetString("mode")
if mode == "new" {
// 整个系统目录结构为:
// 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) {
this.Fail("在当前目录(" + Tea.Root + ")下找不到" + dir + "目录,请将" + dir + "目录上传或者重新下载解压")
}
this.Fail("无法检查" + dir + "目录,发生错误:" + err.Error())
}
}
// 保存数据库配置
dsn := dbMap.GetString("username") + ":" + dbMap.GetString("password") + "@tcp(" + configutils.QuoteIP(dbMap.GetString("host")) + ":" + dbMap.GetString("port") + ")/" + dbMap.GetString("database") + "?charset=utf8mb4&timeout=30s"
dbConfig := &dbs.Config{
DBs: map[string]*dbs.DBConfig{
"prod": {
Driver: "mysql",
Dsn: dsn,
Prefix: "edge",
}},
}
dbConfig.Default.DB = "prod"
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)
}
}
}
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)
}
}
}
// 开始安装
var resultMap = maps.Map{}
{
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"))
}
}
// 启动API节点
{
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(2 * time.Second)
}
// 写入API节点配置完成安装
apiConfig := &configs.APIConfig{
RPC: struct {
Endpoints []string `yaml:"endpoints"`
}{
Endpoints: []string{"http://" + configutils.QuoteIP(apiNodeMap.GetString("newHost")) + ":" + apiNodeMap.GetString("newPort")},
},
NodeId: resultMap.GetString("adminNodeId"),
Secret: resultMap.GetString("adminNodeSecret"),
}
// 设置管理员
client, err := rpc.NewRPCClient(apiConfig)
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"),
})
// 这里我们尝试多次是为了等待API节点启动完毕
if err != nil {
time.Sleep(1 * time.Second)
}
}
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
}
}
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"`
}{
Endpoints: []string{apiNodeMap.GetString("oldProtocol") + "://" + configutils.QuoteIP(apiNodeMap.GetString("oldHost")) + ":" + apiNodeMap.GetString("oldPort")},
},
NodeId: apiNodeMap.GetString("oldNodeId"),
Secret: apiNodeMap.GetString("oldNodeSecret"),
}
client, err := rpc.NewRPCClient(apiConfig)
if err != nil {
this.FailField("oldHost", "测试API节点时出错请检查配置错误信息"+err.Error())
}
// 设置管理员
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
}
}
// 写入API节点配置完成安装
err = apiConfig.WriteFile(Tea.ConfigFile("api.yaml"))
if err != nil {
this.Fail("保存配置失败,原因:" + err.Error())
}
// 成功
this.Success()
} else {
this.Fail("错误的API节点模式'" + mode + "'")
}
}