mirror of
https://github.com/TeaOSLab/EdgeAdmin.git
synced 2025-11-02 03:40:27 +08:00
简化API节点的数据库配置(db.yaml)
This commit is contained in:
51
internal/configs/simple_db_config.go
Normal file
51
internal/configs/simple_db_config.go
Normal file
@@ -0,0 +1,51 @@
|
||||
// Copyright 2024 GoEdge CDN goedge.cdn@gmail.com. All rights reserved. Official site: https://goedge.cn .
|
||||
|
||||
package configs
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"gopkg.in/yaml.v3"
|
||||
"net/url"
|
||||
"os"
|
||||
)
|
||||
|
||||
type SimpleDBConfig struct {
|
||||
User string `yaml:"user"`
|
||||
Password string `yaml:"password"`
|
||||
Database string `yaml:"database"`
|
||||
Host string `yaml:"host"`
|
||||
BoolFields []string `yaml:"boolFields,omitempty"`
|
||||
}
|
||||
|
||||
func (this *SimpleDBConfig) GenerateOldConfig(targetFile string) error {
|
||||
var dbConfig = &dbs.DBConfig{
|
||||
Driver: "mysql",
|
||||
Dsn: url.QueryEscape(this.User) + ":" + url.QueryEscape(this.Password) + "@tcp(" + this.Host + ")/" + url.PathEscape(this.Database) + "?charset=utf8mb4&timeout=30s&multiStatements=true",
|
||||
Prefix: "edge",
|
||||
}
|
||||
dbConfig.Models.Package = "internal/db/models"
|
||||
|
||||
var config = &dbs.Config{
|
||||
DBs: map[string]*dbs.DBConfig{
|
||||
Tea.Env: dbConfig,
|
||||
},
|
||||
}
|
||||
config.Default.DB = Tea.Env
|
||||
config.Fields = map[string][]string{
|
||||
"bool": this.BoolFields,
|
||||
}
|
||||
|
||||
oldConfigYAML, encodeErr := yaml.Marshal(config)
|
||||
if encodeErr != nil {
|
||||
return encodeErr
|
||||
}
|
||||
|
||||
err := os.WriteFile(targetFile, oldConfigYAML, 0666)
|
||||
if err != nil {
|
||||
return fmt.Errorf("create database config file failed: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -25,7 +25,7 @@ func (this *InstallAction) RunGet(params struct {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
node := nodeResp.ApiNode
|
||||
var node = nodeResp.ApiNode
|
||||
if node == nil {
|
||||
this.NotFound("apiNode", params.NodeId)
|
||||
return
|
||||
@@ -39,12 +39,12 @@ func (this *InstallAction) RunGet(params struct {
|
||||
}
|
||||
|
||||
// 数据库配置
|
||||
dbConfigMap := maps.Map{
|
||||
var dbConfigMap = maps.Map{
|
||||
"config": "",
|
||||
"error": "",
|
||||
"isNotFound": false,
|
||||
}
|
||||
dbConfigFile := Tea.ConfigFile("api_db.yaml")
|
||||
var dbConfigFile = Tea.ConfigFile("api_db.yaml")
|
||||
data, err := os.ReadFile(dbConfigFile)
|
||||
dbConfigMap["config"] = string(data)
|
||||
if err != nil {
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configs"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/go-sql-driver/mysql"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"gopkg.in/yaml.v3"
|
||||
"net"
|
||||
"os"
|
||||
"strings"
|
||||
)
|
||||
@@ -22,7 +24,7 @@ func (this *IndexAction) Init() {
|
||||
func (this *IndexAction) RunGet(params struct{}) {
|
||||
this.Data["error"] = ""
|
||||
|
||||
configFile := Tea.ConfigFile("api_db.yaml")
|
||||
var configFile = Tea.ConfigFile("api_db.yaml")
|
||||
data, err := os.ReadFile(configFile)
|
||||
if err != nil {
|
||||
this.Data["error"] = "read config file failed: api_db.yaml: " + err.Error()
|
||||
@@ -30,8 +32,33 @@ func (this *IndexAction) RunGet(params struct{}) {
|
||||
return
|
||||
}
|
||||
|
||||
config := &dbs.Config{}
|
||||
// new config
|
||||
var config = &configs.SimpleDBConfig{}
|
||||
err = yaml.Unmarshal(data, config)
|
||||
if err == nil && len(config.Host) > 0 {
|
||||
host, port, splitErr := net.SplitHostPort(config.Host)
|
||||
if splitErr != nil {
|
||||
port = "3306"
|
||||
}
|
||||
|
||||
this.Data["dbConfig"] = maps.Map{
|
||||
"host": host,
|
||||
"port": port,
|
||||
"username": config.User,
|
||||
"password": config.Password,
|
||||
"database": config.Database,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
return
|
||||
}
|
||||
|
||||
this.parseOldConfig(data)
|
||||
}
|
||||
|
||||
func (this *IndexAction) parseOldConfig(data []byte) {
|
||||
var config = &dbs.Config{}
|
||||
err := yaml.Unmarshal(data, config)
|
||||
if err != nil {
|
||||
this.Data["error"] = "parse config file failed: api_db.yaml: " + err.Error()
|
||||
this.Show()
|
||||
@@ -49,7 +76,12 @@ func (this *IndexAction) RunGet(params struct{}) {
|
||||
dbConfig = db
|
||||
break
|
||||
}
|
||||
dsn := dbConfig.Dsn
|
||||
if dbConfig == nil {
|
||||
this.Data["error"] = "no database configured in config file: api_db.yaml"
|
||||
this.Show()
|
||||
return
|
||||
}
|
||||
var dsn = dbConfig.Dsn
|
||||
cfg, err := mysql.ParseDSN(dsn)
|
||||
if err != nil {
|
||||
this.Data["error"] = "parse dsn error: " + err.Error()
|
||||
@@ -57,18 +89,19 @@ func (this *IndexAction) RunGet(params struct{}) {
|
||||
return
|
||||
}
|
||||
|
||||
host := cfg.Addr
|
||||
port := "3306"
|
||||
index := strings.LastIndex(host, ":")
|
||||
var host = cfg.Addr
|
||||
var port = "3306"
|
||||
var index = strings.LastIndex(host, ":")
|
||||
if index > 0 {
|
||||
port = host[index+1:]
|
||||
host = host[:index]
|
||||
}
|
||||
|
||||
password := cfg.Passwd
|
||||
var password = cfg.Passwd
|
||||
if len(password) > 0 {
|
||||
password = strings.Repeat("*", len(password))
|
||||
}
|
||||
|
||||
this.Data["dbConfig"] = maps.Map{
|
||||
"host": host,
|
||||
"port": port,
|
||||
|
||||
@@ -2,6 +2,7 @@ package database
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/configs"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
|
||||
@@ -40,55 +41,28 @@ func (this *UpdateAction) RunGet(params struct{}) {
|
||||
return
|
||||
}
|
||||
|
||||
config := &dbs.Config{}
|
||||
// new config
|
||||
var config = &configs.SimpleDBConfig{}
|
||||
err = yaml.Unmarshal(data, config)
|
||||
if err != nil {
|
||||
this.Show()
|
||||
return
|
||||
}
|
||||
|
||||
if config.DBs == nil {
|
||||
this.Show()
|
||||
return
|
||||
}
|
||||
|
||||
var dbConfig *dbs.DBConfig
|
||||
for _, db := range config.DBs {
|
||||
dbConfig = db
|
||||
break
|
||||
}
|
||||
|
||||
dsn := dbConfig.Dsn
|
||||
cfg, err := mysql.ParseDSN(dsn)
|
||||
if err != nil {
|
||||
this.Data["dbConfig"] = maps.Map{
|
||||
"host": "",
|
||||
"port": "",
|
||||
"username": "",
|
||||
"password": "",
|
||||
"database": "",
|
||||
if err == nil && len(config.Host) > 0 {
|
||||
host, port, splitErr := net.SplitHostPort(config.Host)
|
||||
if splitErr != nil {
|
||||
port = "3306"
|
||||
}
|
||||
|
||||
this.Data["dbConfig"] = maps.Map{
|
||||
"host": host,
|
||||
"port": port,
|
||||
"username": config.User,
|
||||
"password": config.Password,
|
||||
"database": config.Database,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
return
|
||||
}
|
||||
|
||||
host := cfg.Addr
|
||||
port := "3306"
|
||||
index := strings.LastIndex(cfg.Addr, ":")
|
||||
if index > 0 {
|
||||
host = cfg.Addr[:index]
|
||||
port = cfg.Addr[index+1:]
|
||||
}
|
||||
|
||||
this.Data["dbConfig"] = maps.Map{
|
||||
"host": host,
|
||||
"port": port,
|
||||
"username": cfg.User,
|
||||
"password": cfg.Passwd,
|
||||
"database": cfg.DBName,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
this.parseOldConfig(data)
|
||||
}
|
||||
|
||||
func (this *UpdateAction) RunPost(params struct {
|
||||
@@ -129,28 +103,91 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
Require("请输入连接数据库的用户名").
|
||||
Match(`^[\w\.-]+$`, "用户名中不能包含特殊字符")
|
||||
|
||||
// 保存
|
||||
dsn := params.Username + ":" + params.Password + "@tcp(" + configutils.QuoteIP(params.Host) + ":" + fmt.Sprintf("%d", params.Port) + ")/" + params.Database
|
||||
|
||||
configFile := Tea.ConfigFile("api_db.yaml")
|
||||
template := `default:
|
||||
db: "prod"
|
||||
prefix: ""
|
||||
|
||||
dbs:
|
||||
prod:
|
||||
driver: "mysql"
|
||||
dsn: "` + dsn + `?charset=utf8mb4&timeout=30s"
|
||||
prefix: "edge"
|
||||
models:
|
||||
package: internal/web/models
|
||||
`
|
||||
err := os.WriteFile(configFile, []byte(template), 0666)
|
||||
var config = &configs.SimpleDBConfig{
|
||||
User: params.Username,
|
||||
Password: params.Password,
|
||||
Database: params.Database,
|
||||
Host: configutils.QuoteIP(params.Host) + ":" + fmt.Sprintf("%d", params.Port),
|
||||
}
|
||||
configYAML, err := yaml.Marshal(config)
|
||||
if err != nil {
|
||||
this.Fail("保存配置失败:" + err.Error())
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
|
||||
// TODO 让本地的节点生效
|
||||
// 保存
|
||||
|
||||
var configFile = Tea.ConfigFile("api_db.yaml")
|
||||
err = os.WriteFile(configFile, configYAML, 0666)
|
||||
if err != nil {
|
||||
this.Fail("保存配置失败:" + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// TODO 思考是否让本地的API节点生效
|
||||
|
||||
this.Success()
|
||||
}
|
||||
|
||||
func (this *UpdateAction) parseOldConfig(data []byte) {
|
||||
var config = &dbs.Config{}
|
||||
err := yaml.Unmarshal(data, config)
|
||||
if err != nil {
|
||||
this.Show()
|
||||
return
|
||||
}
|
||||
|
||||
if config.DBs == nil {
|
||||
this.Show()
|
||||
return
|
||||
}
|
||||
|
||||
var dbConfig *dbs.DBConfig
|
||||
for _, db := range config.DBs {
|
||||
dbConfig = db
|
||||
break
|
||||
}
|
||||
if dbConfig == nil {
|
||||
this.Data["dbConfig"] = maps.Map{
|
||||
"host": "",
|
||||
"port": "",
|
||||
"username": "",
|
||||
"password": "",
|
||||
"database": "",
|
||||
}
|
||||
this.Show()
|
||||
return
|
||||
}
|
||||
|
||||
var dsn = dbConfig.Dsn
|
||||
cfg, err := mysql.ParseDSN(dsn)
|
||||
if err != nil {
|
||||
this.Data["dbConfig"] = maps.Map{
|
||||
"host": "",
|
||||
"port": "",
|
||||
"username": "",
|
||||
"password": "",
|
||||
"database": "",
|
||||
}
|
||||
this.Show()
|
||||
return
|
||||
}
|
||||
|
||||
var host = cfg.Addr
|
||||
var port = "3306"
|
||||
var index = strings.LastIndex(cfg.Addr, ":")
|
||||
if index > 0 {
|
||||
host = cfg.Addr[:index]
|
||||
port = cfg.Addr[index+1:]
|
||||
}
|
||||
|
||||
this.Data["dbConfig"] = maps.Map{
|
||||
"host": host,
|
||||
"port": port,
|
||||
"username": cfg.User,
|
||||
"password": cfg.Passwd,
|
||||
"database": cfg.DBName,
|
||||
}
|
||||
|
||||
this.Show()
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"runtime"
|
||||
"strings"
|
||||
@@ -48,7 +49,7 @@ func (this *DetectDBAction) RunPost(params struct{}) {
|
||||
for _, pass := range passwords {
|
||||
db, err := dbs.NewInstanceFromConfig(&dbs.DBConfig{
|
||||
Driver: "mysql",
|
||||
Dsn: username + ":" + pass + "@tcp(" + configutils.QuoteIP(localHost) + ":" + localPort + ")/edges",
|
||||
Dsn: url.QueryEscape(username) + ":" + url.QueryEscape(pass) + "@tcp(" + configutils.QuoteIP(localHost) + ":" + localPort + ")/edges",
|
||||
Prefix: "",
|
||||
})
|
||||
if err == nil {
|
||||
|
||||
@@ -12,7 +12,6 @@ import (
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
|
||||
"github.com/iwind/TeaGo/Tea"
|
||||
"github.com/iwind/TeaGo/actions"
|
||||
"github.com/iwind/TeaGo/dbs"
|
||||
"github.com/iwind/TeaGo/logs"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
"github.com/iwind/gosock/pkg/gosock"
|
||||
@@ -80,34 +79,39 @@ func (this *InstallAction) RunPost(params struct {
|
||||
// 检查环境
|
||||
var 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)
|
||||
var searchDir = Tea.Root + "/" + dir
|
||||
_, err = os.Stat(searchDir)
|
||||
if err != nil {
|
||||
if os.IsNotExist(err) {
|
||||
this.Fail("在当前目录(" + Tea.Root + ")下找不到" + dir + "目录,请将" + dir + "目录上传或者重新下载解压")
|
||||
}
|
||||
this.Fail("无法检查" + dir + "目录,发生错误:" + err.Error())
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 保存数据库配置
|
||||
var 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",
|
||||
}},
|
||||
var dbConfig = &configs.SimpleDBConfig{
|
||||
User: dbMap.GetString("username"),
|
||||
Password: dbMap.GetString("password"),
|
||||
Database: dbMap.GetString("database"),
|
||||
Host: configutils.QuoteIP(dbMap.GetString("host")) + ":" + dbMap.GetString("port"),
|
||||
}
|
||||
dbConfig.Default.DB = "prod"
|
||||
dbConfigData, err := yaml.Marshal(dbConfig)
|
||||
if err != nil {
|
||||
this.Fail("生成数据库配置失败:" + err.Error())
|
||||
return
|
||||
}
|
||||
err = os.WriteFile(apiNodeDir+"/configs/db.yaml", dbConfigData, 0666)
|
||||
if err != nil {
|
||||
this.Fail("保存数据库配置失败:" + err.Error())
|
||||
this.Fail("保存数据库配置失败(db.yaml):" + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
err = dbConfig.GenerateOldConfig(apiNodeDir + "/configs/.db.yaml")
|
||||
if err != nil {
|
||||
this.Fail("保存数据库配置失败(.db.yaml):" + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 生成备份文件
|
||||
@@ -130,7 +134,8 @@ func (this *InstallAction) RunPost(params struct {
|
||||
|
||||
err = os.WriteFile(Tea.ConfigFile("/api_db.yaml"), dbConfigData, 0666)
|
||||
if err != nil {
|
||||
this.Fail("保存数据库配置失败:" + err.Error())
|
||||
this.Fail("保存数据库配置失败(api_db.yaml):" + err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
// 生成备份文件
|
||||
@@ -157,21 +162,25 @@ func (this *InstallAction) RunPost(params struct {
|
||||
{
|
||||
this.apiSetupFinished = false
|
||||
var cmd = exec.Command(apiNodeDir+"/bin/edge-api", "setup", "-api-node-protocol=http", "-api-node-host=\""+apiNodeMap.GetString("newHost")+"\"", "-api-node-port=\""+apiNodeMap.GetString("newPort")+"\"")
|
||||
var output = bytes.NewBuffer([]byte{})
|
||||
var output = bytes.NewBuffer(nil)
|
||||
cmd.Stdout = output
|
||||
|
||||
var stderr = bytes.NewBuffer(nil)
|
||||
cmd.Stderr = stderr
|
||||
|
||||
// 试图读取执行日志
|
||||
go this.startReadingAPIInstallLog()
|
||||
|
||||
err = cmd.Run()
|
||||
this.apiSetupFinished = true
|
||||
if err != nil {
|
||||
this.Fail("安装失败:" + err.Error())
|
||||
this.Fail("安装失败:" + err.Error() + ": " + string(append(output.Bytes(), stderr.Bytes()...)))
|
||||
}
|
||||
|
||||
var resultData = output.Bytes()
|
||||
err = json.Unmarshal(resultData, &resultMap)
|
||||
if err != nil {
|
||||
|
||||
this.Fail("安装节点时返回数据错误:" + err.Error() + "(" + string(resultData) + ")")
|
||||
}
|
||||
if !resultMap.GetBool("isOk") {
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
stringutil "github.com/iwind/TeaGo/utils/string"
|
||||
"net"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
)
|
||||
@@ -57,7 +58,7 @@ func (this *ValidateDbAction) RunPost(params struct {
|
||||
// 测试连接
|
||||
db, err := dbs.NewInstanceFromConfig(&dbs.DBConfig{
|
||||
Driver: "mysql",
|
||||
Dsn: params.Username + ":" + params.Password + "@tcp(" + configutils.QuoteIP(params.Host) + ":" + params.Port + ")/" + params.Database,
|
||||
Dsn: url.QueryEscape(params.Username) + ":" + url.QueryEscape(params.Password) + "@tcp(" + configutils.QuoteIP(params.Host) + ":" + params.Port + ")/" + params.Database,
|
||||
Prefix: "",
|
||||
})
|
||||
if err != nil {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
{$template "menu"}
|
||||
|
||||
<div class="ui message small warning">
|
||||
<p>这里只能修改配置模板文件里的配置信息,并不能直接修改数据库的用户名、密码等信息。</p>
|
||||
<p>这里只能修改配置模板文件里的配置信息,并不能直接修改数据库自身的用户名、密码等信息。</p>
|
||||
</div>
|
||||
|
||||
<form method="post" class="ui form" data-tea-action="$" data-tea-success="success">
|
||||
|
||||
Reference in New Issue
Block a user