简化API节点的数据库配置(db.yaml)

This commit is contained in:
GoEdgeLab
2024-05-06 17:29:11 +08:00
parent d8e9268dab
commit a573eb5608
8 changed files with 223 additions and 91 deletions

View 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
}

View File

@@ -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 {

View File

@@ -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,

View File

@@ -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()
}

View File

@@ -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 {

View File

@@ -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") {

View File

@@ -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 {

View File

@@ -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">