feat: use settings file to predefine nodes #169

This commit is contained in:
Jacky 2024-05-07 19:45:24 +08:00
parent b429c15893
commit a689608bdb
No known key found for this signature in database
GPG key ID: 215C21B10DF38B4D
7 changed files with 191 additions and 48 deletions

View file

@ -1,45 +1,46 @@
; suppress inspection "DuplicateKeyInSection" for whole file
[server]
HttpPort = 9000
RunMode = debug
JwtSecret =
Email =
JwtSecret =
Email =
HTTPChallengePort = 9180
StartCmd = bash
Database = database
CADir =
GithubProxy =
NodeSecret =
CADir =
GithubProxy =
NodeSecret =
Demo = false
PageSize = 10
HttpHost = 0.0.0.0
CertRenewalInterval = 7
RecursiveNameservers =
RecursiveNameservers =
SkipInstallation = false
Name =
Name =
[nginx]
AccessLogPath = /var/log/nginx/access.log
ErrorLogPath = /var/log/nginx/error.log
ConfigDir =
PIDPath =
TestConfigCmd =
ReloadCmd =
RestartCmd =
ConfigDir =
PIDPath =
TestConfigCmd =
ReloadCmd =
RestartCmd =
[openai]
Model =
BaseUrl =
Proxy =
Token =
Model =
BaseUrl =
Proxy =
Token =
[casdoor]
Endpoint =
ClientId =
ClientSecret =
Certificate =
Organization =
Application =
RedirectUri =
Endpoint =
ClientId =
ClientSecret =
Certificate =
Organization =
Application =
RedirectUri =
[logrotate]
Enabled = false
@ -47,4 +48,6 @@ CMD = logrotate /etc/logrotate.d/nginx
Interval = 1440
[cluster]
Node =
Node = http://10.0.0.1:9000?name=node1&node_secret=my-node-secret&enabled=true
Node = http://10.0.0.2:9000?name=node2&node_secret=my-node-secret&enabled=true
Node = http://10.0.0.3?name=node3&node_secret=my-node-secret&enabled=true

View file

@ -44,6 +44,7 @@ func InitAfterDatabase() {
registerPredefinedUser,
cert.InitRegister,
InitCronJobs,
registerPredefinedClusterNodes,
analytic.RetrieveNodesStatus,
}

View file

@ -0,0 +1,71 @@
package kernal
import (
"github.com/0xJacky/Nginx-UI/internal/logger"
"github.com/0xJacky/Nginx-UI/model"
"github.com/0xJacky/Nginx-UI/query"
"github.com/0xJacky/Nginx-UI/settings"
"gorm.io/gen/field"
"net/url"
"strings"
)
func registerPredefinedClusterNodes() {
if len(settings.ClusterSettings.Node) == 0 {
return
}
q := query.Environment
for _, nodeUrl := range settings.ClusterSettings.Node {
func() {
node, err := parseNodeUrl(nodeUrl)
if err != nil {
logger.Error(nodeUrl, err)
return
}
if node.Name == "" {
logger.Error(nodeUrl, "Node name is required")
return
}
if node.URL == "" {
logger.Error(nodeUrl, "Node URL is required")
return
}
if node.Token == "" {
logger.Error(nodeUrl, "Node Token is required")
return
}
_, err = q.Where(q.URL.Eq(node.URL)).
Attrs(field.Attrs(node)).
FirstOrCreate()
if err != nil {
logger.Error(node.URL, err)
}
}()
}
}
func parseNodeUrl(nodeUrl string) (env *model.Environment, err error) {
u, err := url.Parse(nodeUrl)
if err != nil {
return
}
var sb strings.Builder
sb.WriteString(u.Scheme)
sb.WriteString("://")
sb.WriteString(u.Host)
sb.WriteString(u.Path)
env = &model.Environment{
Name: u.Query().Get("name"),
URL: sb.String(),
Token: u.Query().Get("node_secret"),
Enabled: u.Query().Get("enabled") == "true",
}
return
}

View file

@ -0,0 +1,47 @@
package kernal
import (
"github.com/0xJacky/Nginx-UI/settings"
"github.com/stretchr/testify/assert"
"testing"
)
func Test_parseNodeUrl(t *testing.T) {
settings.Init("../../app.example.ini")
t.Log(settings.ClusterSettings.Node)
node := settings.ClusterSettings.Node[0]
env, err := parseNodeUrl(node)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "node1", env.Name)
assert.Equal(t, "http://10.0.0.1:9000", env.URL)
assert.Equal(t, "my-node-secret", env.Token)
assert.Equal(t, true, env.Enabled)
node = settings.ClusterSettings.Node[1]
env, err = parseNodeUrl(node)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "node2", env.Name)
assert.Equal(t, "http://10.0.0.2:9000", env.URL)
assert.Equal(t, "my-node-secret", env.Token)
assert.Equal(t, true, env.Enabled)
node = settings.ClusterSettings.Node[2]
env, err = parseNodeUrl(node)
if err != nil {
t.Fatal(err)
}
assert.Equal(t, "node3", env.Name)
assert.Equal(t, "http://10.0.0.3", env.URL)
assert.Equal(t, "my-node-secret", env.Token)
assert.Equal(t, true, env.Enabled)
}

View file

@ -3,3 +3,7 @@ package settings
type Cluster struct {
Node []string `ini:",,allowshadow"`
}
var ClusterSettings = Cluster{
Node: []string{},
}

15
settings/cluster_test.go Normal file
View file

@ -0,0 +1,15 @@
package settings
import (
"github.com/stretchr/testify/assert"
"testing"
)
func TestCluster(t *testing.T) {
Init("../app.example.ini")
assert.Equal(t, []string{
"http://10.0.0.1:9000?name=node1&node_secret=my-node-secret&enabled=true",
"http://10.0.0.2:9000?name=node2&node_secret=my-node-secret&enabled=true",
}, ClusterSettings.Node)
}

View file

@ -6,8 +6,8 @@ import (
"gopkg.in/ini.v1"
"log"
"os"
"reflect"
"strings"
"reflect"
"strings"
"time"
)
@ -26,6 +26,7 @@ var sections = map[string]interface{}{
"openai": &OpenAISettings,
"casdoor": &CasdoorSettings,
"logrotate": &LogrotateSettings,
"cluster": &ClusterSettings,
}
func init() {
@ -40,10 +41,15 @@ func Init(confPath string) {
func Setup() {
var err error
Conf, err = ini.LooseLoad(ConfPath)
Conf, err = ini.LoadSources(ini.LoadOptions{
Loose: true,
AllowShadows: true,
}, ConfPath)
if err != nil {
log.Fatalf("settings.Setup: %v\n", err)
}
MapTo()
parseEnv(&ServerSettings, "SERVER_")
@ -70,8 +76,6 @@ func MapTo() {
}
}
func Save() (err error) {
for k, v := range sections {
reflectFrom(k, v)
@ -85,30 +89,30 @@ func Save() (err error) {
}
func ProtectedFill(targetSettings interface{}, newSettings interface{}) {
s := reflect.TypeOf(targetSettings).Elem()
vt := reflect.ValueOf(targetSettings).Elem()
vn := reflect.ValueOf(newSettings).Elem()
s := reflect.TypeOf(targetSettings).Elem()
vt := reflect.ValueOf(targetSettings).Elem()
vn := reflect.ValueOf(newSettings).Elem()
// copy the values from new to target settings if it is not protected
for i := 0; i < s.NumField(); i++ {
if s.Field(i).Tag.Get("protected") != "true" {
vt.Field(i).Set(vn.Field(i))
}
}
// copy the values from new to target settings if it is not protected
for i := 0; i < s.NumField(); i++ {
if s.Field(i).Tag.Get("protected") != "true" {
vt.Field(i).Set(vn.Field(i))
}
}
}
func mapTo(section string, v interface{}) {
err := Conf.Section(section).MapTo(v)
if err != nil {
log.Fatalf("Cfg.MapTo %s err: %v", section, err)
}
err := Conf.Section(section).MapTo(v)
if err != nil {
log.Fatalf("Cfg.MapTo %s err: %v", section, err)
}
}
func reflectFrom(section string, v interface{}) {
err := Conf.Section(section).ReflectFrom(v)
if err != nil {
log.Fatalf("Cfg.ReflectFrom %s err: %v", section, err)
}
err := Conf.Section(section).ReflectFrom(v)
if err != nil {
log.Fatalf("Cfg.ReflectFrom %s err: %v", section, err)
}
}
func parseEnv(ptr interface{}, prefix string) {
@ -121,5 +125,3 @@ func parseEnv(ptr interface{}, prefix string) {
log.Fatalf("settings.parseEnv: %v\n", err)
}
}