diff --git a/build/configs/.gitignore b/build/configs/.gitignore index 8d069de8..96c2fc58 100644 --- a/build/configs/.gitignore +++ b/build/configs/.gitignore @@ -1,4 +1,4 @@ server.yaml api_db.yaml -api.yaml +api-123.yaml *.pem \ No newline at end of file diff --git a/build/configs/api.yaml b/build/configs/api.yaml new file mode 100644 index 00000000..6cc8a803 --- /dev/null +++ b/build/configs/api.yaml @@ -0,0 +1,6 @@ +rpc: + endpoints: + - http://192.168.2.40:8003 +nodeId: H6sjDf779jimnVPnBFSgZxvr6Ca0wQ0z +secret: hMHjmEng0SIcT3yiA3HIoUjogwAC9cur + diff --git a/internal/configs/api_config.go b/internal/configs/api_config.go index 63f8ec88..199c29ac 100644 --- a/internal/configs/api_config.go +++ b/internal/configs/api_config.go @@ -1,9 +1,12 @@ package configs import ( + teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const" "github.com/go-yaml/yaml" "github.com/iwind/TeaGo/Tea" "io/ioutil" + "os" + "path/filepath" ) // API配置 @@ -17,7 +20,26 @@ type APIConfig struct { // 加载API配置 func LoadAPIConfig() (*APIConfig, error) { - data, err := ioutil.ReadFile(Tea.ConfigFile("api.yaml")) + // 候选文件 + localFile := Tea.ConfigFile("api.yaml") + isFromLocal := false + paths := []string{localFile} + homeDir, err := os.UserHomeDir() + if err == nil { + paths = append(paths, homeDir+"/."+teaconst.ProcessName+"/api.yaml") + } + paths = append(paths, "/etc/"+teaconst.ProcessName+"/api.yaml") + + var data []byte + for _, path := range paths { + data, err = ioutil.ReadFile(path) + if err == nil { + if path == localFile { + isFromLocal = true + } + break + } + } if err != nil { return nil, err } @@ -28,6 +50,11 @@ func LoadAPIConfig() (*APIConfig, error) { return nil, err } + if !isFromLocal { + // 恢复文件 + _ = ioutil.WriteFile(localFile, data, 0666) + } + return config, nil } @@ -37,5 +64,38 @@ func (this *APIConfig) WriteFile(path string) error { if err != nil { return err } - return ioutil.WriteFile(path, data, 0666) + err = ioutil.WriteFile(path, data, 0666) + + // 写入 ~/ 和 /etc/ 目录,因为是备份需要,所以不需要提示错误信息 + // 写入 ~/.edge-admin/ + filename := filepath.Base(path) + homeDir, err := os.UserHomeDir() + if err == nil { + dir := homeDir + "/." + teaconst.ProcessName + stat, err := os.Stat(dir) + if err == nil && stat.IsDir() { + _ = ioutil.WriteFile(dir+"/"+filename, data, 0666) + } else if err != nil && os.IsNotExist(err) { + err = os.Mkdir(dir, 0777) + if err == nil { + _ = ioutil.WriteFile(dir+"/"+filename, data, 0666) + } + } + } + + // 写入 /etc/.edge-admin + { + dir := "/etc/" + teaconst.ProcessName + stat, err := os.Stat(dir) + if err == nil && stat.IsDir() { + _ = ioutil.WriteFile(dir+"/"+filename, data, 0666) + } else if err != nil && os.IsNotExist(err) { + err = os.Mkdir(dir, 0777) + if err == nil { + _ = ioutil.WriteFile(dir+"/"+filename, data, 0666) + } + } + } + + return err } diff --git a/internal/configs/api_config_test.go b/internal/configs/api_config_test.go index 03f5b9d4..f5dd4c63 100644 --- a/internal/configs/api_config_test.go +++ b/internal/configs/api_config_test.go @@ -12,3 +12,18 @@ func TestLoadAPIConfig(t *testing.T) { } t.Log(config) } + +func TestAPIConfig_WriteFile(t *testing.T) { + config := &APIConfig{ + RPC: struct { + Endpoints []string `yaml:"endpoints"` + }{}, + NodeId: "1", + Secret: "2", + } + err := config.WriteFile("/tmp/api_config.yaml") + if err != nil { + t.Fatal(err) + } + t.Log("ok") +} diff --git a/internal/nodes/admin_node.go b/internal/nodes/admin_node.go index 58e7c0f2..37d27698 100644 --- a/internal/nodes/admin_node.go +++ b/internal/nodes/admin_node.go @@ -22,6 +22,8 @@ import ( "time" ) +var SharedAdminNode *AdminNode = nil + type AdminNode struct { subPIDs []int } @@ -31,6 +33,8 @@ func NewAdminNode() *AdminNode { } func (this *AdminNode) Run() { + SharedAdminNode = this + // 启动管理界面 secret := this.genSecret() configs.Secret = secret @@ -145,6 +149,11 @@ func (this *AdminNode) InstallSystemService() error { return nil } +// 添加子PID +func (this *AdminNode) AddSubPID(pid int) { + this.subPIDs = append(this.subPIDs, pid) +} + // 检查Server配置 func (this *AdminNode) checkServer() error { configFile := Tea.ConfigFile("server.yaml") @@ -192,8 +201,61 @@ https: // 启动API节点 func (this *AdminNode) startAPINode() { - _, err := os.Stat(Tea.Root + "/edge-api/configs/api.yaml") + configPath := Tea.Root + "/edge-api/configs/api.yaml" + _, err := os.Stat(configPath) + canStart := false if err == nil { + canStart = true + } else if err != nil && os.IsNotExist(err) { + // 尝试恢复api.yaml + homeDir, _ := os.UserHomeDir() + paths := []string{} + if len(homeDir) > 0 { + paths = append(paths, homeDir+"/.edge-api/api.yaml") + } + paths = append(paths, "/etc/edge-api/api.yaml") + for _, path := range paths { + _, err = os.Stat(path) + if err == nil { + data, err := ioutil.ReadFile(path) + if err == nil { + err = ioutil.WriteFile(configPath, data, 0666) + if err == nil { + logs.Println("[NODE]recover 'edge-api/configs/api.yaml' from '" + path + "'") + canStart = true + break + } + } + } + } + } + + dbPath := Tea.Root + "/edge-api/configs/db.yaml" + _, err = os.Stat(dbPath) + if err != nil && os.IsNotExist(err) { + // 尝试恢复db.yaml + homeDir, _ := os.UserHomeDir() + paths := []string{} + if len(homeDir) > 0 { + paths = append(paths, homeDir+"/.edge-api/db.yaml") + } + paths = append(paths, "/etc/edge-api/db.yaml") + for _, path := range paths { + _, err = os.Stat(path) + if err == nil { + data, err := ioutil.ReadFile(path) + if err == nil { + err = ioutil.WriteFile(dbPath, data, 0666) + if err == nil { + logs.Println("[NODE]recover 'edge-api/configs/db.yaml' from '" + path + "'") + break + } + } + } + } + } + + if canStart { logs.Println("start edge-api") cmd := exec.Command(Tea.Root + "/edge-api/bin/edge-api") err = cmd.Start() diff --git a/internal/web/actions/default/setup/install.go b/internal/web/actions/default/setup/install.go index 1d366886..1a8335fe 100644 --- a/internal/web/actions/default/setup/install.go +++ b/internal/web/actions/default/setup/install.go @@ -4,6 +4,7 @@ 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/rpc/pb" @@ -91,11 +92,46 @@ func (this *InstallAction) RunPost(params struct { 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{} { @@ -125,6 +161,9 @@ func (this *InstallAction) RunPost(params struct { this.Fail("API节点启动失败:" + err.Error()) } + // 记录子PID方便退出的时候一起退出 + nodes.SharedAdminNode.AddSubPID(cmd.Process.Pid) + // 等待API节点初始化完成 time.Sleep(2 * time.Second) }