换成单集群模式

This commit is contained in:
robin
2026-03-02 20:07:53 +08:00
parent 5d0b7c7e91
commit 2a76d1773d
432 changed files with 5681 additions and 5095 deletions

View File

@@ -1,15 +1,14 @@
package apps
import (
"encoding/json"
"strconv"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/httpdnsutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
)
type AppSettingsAction struct {
@@ -60,55 +59,70 @@ func (this *AppSettingsAction) RunGet(params struct {
return
}
clusters := make([]maps.Map, 0, len(clusterResp.GetClusters()))
clusterDomainMap := map[int64]string{}
clusterApiAddressMap := map[int64]string{}
clusterNameMap := map[int64]string{}
defaultPrimaryClusterId := int64(0)
for _, cluster := range clusterResp.GetClusters() {
clusterId := cluster.GetId()
clusterName := cluster.GetName()
port := "443"
if rawTLS := cluster.GetTlsPolicyJSON(); len(rawTLS) > 0 {
var tlsConfig map[string]interface{}
if err := json.Unmarshal(rawTLS, &tlsConfig); err == nil {
if listenRaw, ok := tlsConfig["listen"]; ok && listenRaw != nil {
if data, err := json.Marshal(listenRaw); err == nil {
var listenAddresses []map[string]interface{}
if err := json.Unmarshal(data, &listenAddresses); err == nil {
if len(listenAddresses) > 0 {
if portRange, ok := listenAddresses[0]["portRange"].(string); ok && len(portRange) > 0 {
port = portRange
}
}
}
}
}
}
}
apiAddress := "https://" + cluster.GetServiceDomain() + ":" + port
clusters = append(clusters, maps.Map{
"id": clusterId,
"name": clusterName,
"serviceDomain": cluster.GetServiceDomain(),
"isDefault": cluster.GetIsDefault(),
"id": clusterId,
"name": clusterName,
})
clusterDomainMap[clusterId] = cluster.GetServiceDomain()
clusterApiAddressMap[clusterId] = apiAddress
clusterNameMap[clusterId] = clusterName
if defaultPrimaryClusterId <= 0 && cluster.GetIsDefault() {
defaultPrimaryClusterId = clusterId
}
// 读取应用绑定的集群列表,取第一个作为当前选中。
var selectedClusterId int64
if raw := app.Get("clusterIds"); raw != nil {
if ids, ok := raw.([]int64); ok && len(ids) > 0 {
selectedClusterId = ids[0]
}
}
defaultBackupClusterId := int64(0)
defaultBackupResp, err := this.RPC().SysSettingRPC().ReadSysSetting(this.AdminContext(), &pb.ReadSysSettingRequest{
Code: string(systemconfigs.SettingCodeHTTPDNSDefaultBackupClusterId),
})
if err != nil {
this.ErrorPage(err)
return
// 构建服务地址列表。
serviceAddresses := make([]maps.Map, 0)
if selectedClusterId > 0 {
addr := clusterApiAddressMap[selectedClusterId]
name := clusterNameMap[selectedClusterId]
if len(addr) > 0 {
serviceAddresses = append(serviceAddresses, maps.Map{
"address": addr,
"clusterName": name,
})
}
}
if defaultBackupResp != nil && len(defaultBackupResp.GetValueJSON()) > 0 {
defaultBackupClusterId = types.Int64(string(defaultBackupResp.GetValueJSON()))
}
primaryClusterId := app.GetInt64("primaryClusterId")
backupClusterId := app.GetInt64("backupClusterId")
settings := maps.Map{
"appId": app.GetString("appId"),
"appStatus": app.GetBool("isOn"),
"primaryClusterId": primaryClusterId,
"backupClusterId": backupClusterId,
"defaultPrimaryClusterId": defaultPrimaryClusterId,
"defaultPrimaryClusterName": clusterNameMap[defaultPrimaryClusterId],
"defaultBackupClusterId": defaultBackupClusterId,
"defaultBackupClusterName": clusterNameMap[defaultBackupClusterId],
"primaryServiceDomain": clusterDomainMap[primaryClusterId],
"backupServiceDomain": clusterDomainMap[backupClusterId],
"signEnabled": app.GetBool("signEnabled"),
"signSecretPlain": app.GetString("signSecretPlain"),
"signSecretMasked": app.GetString("signSecretMasked"),
"signSecretUpdatedAt": app.GetString("signSecretUpdated"),
"appId": app.GetString("appId"),
"appStatus": app.GetBool("isOn"),
"selectedClusterId": selectedClusterId,
"serviceAddresses": serviceAddresses,
"signEnabled": app.GetBool("signEnabled"),
"signSecretPlain": app.GetString("signSecretPlain"),
"signSecretMasked": app.GetString("signSecretMasked"),
"signSecretUpdatedAt": app.GetString("signSecretUpdated"),
}
this.Data["app"] = app
this.Data["settings"] = settings
@@ -119,18 +133,13 @@ func (this *AppSettingsAction) RunGet(params struct {
func (this *AppSettingsAction) RunPost(params struct {
AppId int64
AppStatus bool
PrimaryClusterId int64
BackupClusterId int64
AppStatus bool
ClusterId int64
Must *actions.Must
CSRF *actionutils.CSRF
}) {
params.Must.Field("appId", params.AppId).Gt(0, "请选择应用")
if params.PrimaryClusterId > 0 && params.BackupClusterId > 0 && params.PrimaryClusterId == params.BackupClusterId {
this.FailField("backupClusterId", "备用集群不能与主集群相同")
return
}
appResp, err := this.RPC().HTTPDNSAppRPC().FindHTTPDNSApp(this.AdminContext(), &pb.FindHTTPDNSAppRequest{
AppDbId: params.AppId,
@@ -144,13 +153,18 @@ func (this *AppSettingsAction) RunPost(params struct {
return
}
var clusterIds []int64
if params.ClusterId > 0 {
clusterIds = []int64{params.ClusterId}
}
clusterIdsJSON, _ := json.Marshal(clusterIds)
_, err = this.RPC().HTTPDNSAppRPC().UpdateHTTPDNSApp(this.AdminContext(), &pb.UpdateHTTPDNSAppRequest{
AppDbId: params.AppId,
Name: appResp.GetApp().GetName(),
PrimaryClusterId: params.PrimaryClusterId,
BackupClusterId: params.BackupClusterId,
IsOn: params.AppStatus,
UserId: appResp.GetApp().GetUserId(),
AppDbId: params.AppId,
Name: appResp.GetApp().GetName(),
ClusterIdsJSON: clusterIdsJSON,
IsOn: params.AppStatus,
UserId: appResp.GetApp().GetUserId(),
})
if err != nil {
this.ErrorPage(err)

View File

@@ -1,6 +1,7 @@
package apps
import (
"encoding/json"
"strconv"
"time"
@@ -33,28 +34,6 @@ func (this *CreateAction) RunGet(params struct{}) {
}
this.Data["clusters"] = clusters
defaultPrimaryClusterId := int64(0)
for _, cluster := range clusterResp.GetClusters() {
if cluster.GetIsDefault() {
defaultPrimaryClusterId = cluster.GetId()
break
}
}
if defaultPrimaryClusterId <= 0 && len(clusters) > 0 {
defaultPrimaryClusterId = clusters[0].GetInt64("id")
}
this.Data["defaultPrimaryClusterId"] = defaultPrimaryClusterId
defaultBackupClusterId := int64(0)
for _, cluster := range clusters {
clusterId := cluster.GetInt64("id")
if clusterId > 0 && clusterId != defaultPrimaryClusterId {
defaultBackupClusterId = clusterId
break
}
}
this.Data["defaultBackupClusterId"] = defaultBackupClusterId
usersResp, err := this.RPC().UserRPC().ListEnabledUsers(this.AdminContext(), &pb.ListEnabledUsersRequest{
Offset: 0,
Size: 10_000,
@@ -77,28 +56,28 @@ func (this *CreateAction) RunGet(params struct{}) {
}
func (this *CreateAction) RunPost(params struct {
Name string
PrimaryClusterId int64
BackupClusterId int64
UserId int64
Name string
ClusterId int64
UserId int64
Must *actions.Must
CSRF *actionutils.CSRF
}) {
params.Must.Field("name", params.Name).Require("请输入应用名称")
params.Must.Field("primaryClusterId", params.PrimaryClusterId).Gt(0, "请输入主服务集群")
if params.BackupClusterId > 0 && params.BackupClusterId == params.PrimaryClusterId {
this.FailField("backupClusterId", "备用服务集群必须和主服务集群不一致")
if params.ClusterId <= 0 {
this.FailField("clusterId", "请选择集群")
return
}
clusterIdsJSON, _ := json.Marshal([]int64{params.ClusterId})
createResp, err := this.RPC().HTTPDNSAppRPC().CreateHTTPDNSApp(this.AdminContext(), &pb.CreateHTTPDNSAppRequest{
Name: params.Name,
AppId: "app" + strconv.FormatInt(time.Now().UnixNano()%1_000_000_000_000, 36),
PrimaryClusterId: params.PrimaryClusterId,
BackupClusterId: params.BackupClusterId,
IsOn: true,
SignEnabled: true,
UserId: params.UserId,
Name: params.Name,
AppId: "app" + strconv.FormatInt(time.Now().UnixNano()%1_000_000_000_000, 36),
ClusterIdsJSON: clusterIdsJSON,
IsOn: true,
SignEnabled: true,
UserId: params.UserId,
})
if err != nil {
this.ErrorPage(err)

View File

@@ -24,5 +24,6 @@ func (this *IndexAction) RunGet(params struct {
return
}
this.Data["apps"] = apps
this.Data["page"] = ""
this.Show()
}

View File

@@ -1,6 +1,7 @@
package apps
import (
"encoding/json"
"strconv"
"strings"
"time"
@@ -87,15 +88,14 @@ func findAppMap(parent *actionutils.ParentAction, appDbId int64) (maps.Map, erro
return apps[0], nil
}
func createApp(parent *actionutils.ParentAction, name string, primaryClusterId int64, backupClusterId int64) (int64, error) {
func createApp(parent *actionutils.ParentAction, name string, clusterIdsJSON []byte) (int64, error) {
newAppId := "app" + strconv.FormatInt(time.Now().UnixNano()%1_000_000_000_000, 36)
resp, err := parent.RPC().HTTPDNSAppRPC().CreateHTTPDNSApp(parent.AdminContext(), &pb.CreateHTTPDNSAppRequest{
Name: strings.TrimSpace(name),
AppId: newAppId,
PrimaryClusterId: primaryClusterId,
BackupClusterId: backupClusterId,
IsOn: true,
SignEnabled: true,
Name: strings.TrimSpace(name),
AppId: newAppId,
ClusterIdsJSON: clusterIdsJSON,
IsOn: true,
SignEnabled: true,
})
if err != nil {
return 0, err
@@ -110,14 +110,13 @@ func deleteAppByID(parent *actionutils.ParentAction, appDbId int64) error {
return err
}
func updateAppSettings(parent *actionutils.ParentAction, appDbId int64, name string, primaryClusterId int64, backupClusterId int64, isOn bool, userId int64) error {
func updateAppSettings(parent *actionutils.ParentAction, appDbId int64, name string, clusterIdsJSON []byte, isOn bool, userId int64) error {
_, err := parent.RPC().HTTPDNSAppRPC().UpdateHTTPDNSApp(parent.AdminContext(), &pb.UpdateHTTPDNSAppRequest{
AppDbId: appDbId,
Name: strings.TrimSpace(name),
PrimaryClusterId: primaryClusterId,
BackupClusterId: backupClusterId,
IsOn: isOn,
UserId: userId,
AppDbId: appDbId,
Name: strings.TrimSpace(name),
ClusterIdsJSON: clusterIdsJSON,
IsOn: isOn,
UserId: userId,
})
return err
}
@@ -277,13 +276,24 @@ func toggleCustomRule(parent *actionutils.ParentAction, ruleId int64, isOn bool)
return err
}
func appPBToMap(app *pb.HTTPDNSApp, domainCount int64, clusterNameMap map[int64]string, userMapByID map[int64]maps.Map) maps.Map {
func appPBToMap(app *pb.HTTPDNSApp, domainCount int64, clusterMapByID map[int64]maps.Map, userMapByID map[int64]maps.Map) maps.Map {
signSecret := app.GetSignSecret()
primaryClusterID := app.GetPrimaryClusterId()
backupClusterID := app.GetBackupClusterId()
primaryClusterMap := maps.Map{"id": primaryClusterID, "name": clusterNameMap[primaryClusterID]}
backupClusterMap := maps.Map{"id": backupClusterID, "name": clusterNameMap[backupClusterID]}
// 读取集群 ID 列表
var clusterIds []int64
if len(app.GetClusterIdsJSON()) > 0 {
_ = json.Unmarshal(app.GetClusterIdsJSON(), &clusterIds)
}
// 构建集群映射列表
var clusterMaps []maps.Map
for _, cid := range clusterIds {
cm := clusterMapByID[cid]
if cm == nil {
cm = maps.Map{"id": cid, "name": "", "apiAddress": ""}
}
clusterMaps = append(clusterMaps, cm)
}
var userMap maps.Map
if app.GetUserId() > 0 {
@@ -301,11 +311,8 @@ func appPBToMap(app *pb.HTTPDNSApp, domainCount int64, clusterNameMap map[int64]
"id": app.GetId(),
"name": app.GetName(),
"appId": app.GetAppId(),
"clusterId": primaryClusterID,
"primaryClusterId": primaryClusterID,
"backupClusterId": backupClusterID,
"primaryCluster": primaryClusterMap,
"backupCluster": backupClusterMap,
"clusterIds": clusterIds,
"clusters": clusterMaps,
"userId": app.GetUserId(),
"user": userMap,
"isOn": app.GetIsOn(),
@@ -318,15 +325,37 @@ func appPBToMap(app *pb.HTTPDNSApp, domainCount int64, clusterNameMap map[int64]
}
}
func loadHTTPDNSClusterNameMap(parent *actionutils.ParentAction) (map[int64]string, error) {
func loadHTTPDNSClusterNameMap(parent *actionutils.ParentAction) (map[int64]maps.Map, error) {
resp, err := parent.RPC().HTTPDNSClusterRPC().FindAllHTTPDNSClusters(parent.AdminContext(), &pb.FindAllHTTPDNSClustersRequest{})
if err != nil {
return nil, err
}
result := map[int64]string{}
result := map[int64]maps.Map{}
for _, cluster := range resp.GetClusters() {
result[cluster.GetId()] = cluster.GetName()
port := "443"
if rawTLS := cluster.GetTlsPolicyJSON(); len(rawTLS) > 0 {
tlsConfig := maps.Map{}
if err := json.Unmarshal(rawTLS, &tlsConfig); err == nil {
if listenRaw := tlsConfig.Get("listen"); listenRaw != nil {
var listenAddresses []maps.Map
if data, err := json.Marshal(listenRaw); err == nil {
if err := json.Unmarshal(data, &listenAddresses); err == nil {
if len(listenAddresses) > 0 && len(listenAddresses[0].GetString("portRange")) > 0 {
port = listenAddresses[0].GetString("portRange")
}
}
}
}
}
}
apiAddress := "https://" + cluster.GetServiceDomain() + ":" + port
result[cluster.GetId()] = maps.Map{
"id": cluster.GetId(),
"name": cluster.GetName(),
"apiAddress": apiAddress,
}
}
return result, nil
}

View File

@@ -2,11 +2,14 @@ package node
import (
"encoding/json"
"fmt"
"strings"
"time"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeCommon/pkg/configutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/maps"
)
type InstallAction struct {
@@ -55,7 +58,22 @@ func (this *InstallAction) RunGet(params struct {
apiEndpoints = []string{"http://127.0.0.1:7788"}
}
this.Data["apiEndpoints"] = "\"" + strings.Join(apiEndpoints, "\", \"") + "\""
// 从 NodeLogin 中提取 SSH 地址
this.Data["sshAddr"] = ""
loginMap, _ := node.Get("login").(maps.Map)
if loginMap != nil {
paramsMap, _ := loginMap.Get("params").(maps.Map)
if paramsMap != nil {
host := paramsMap.GetString("host")
if len(host) > 0 {
port := paramsMap.GetInt("port")
if port <= 0 {
port = 22
}
this.Data["sshAddr"] = fmt.Sprintf("%s:%d", configutils.QuoteIP(host), port)
}
}
}
this.Show()
}

View File

@@ -57,7 +57,21 @@ func findHTTPDNSNodeMap(parent *actionutils.ParentAction, nodeID int64) (maps.Ma
if installStatusMap.Has("ipAddresses") {
for _, addr := range installStatusMap.GetSlice("ipAddresses") {
if addrMap, ok := addr.(map[string]interface{}); ok {
ipAddresses = append(ipAddresses, maps.Map(addrMap))
m := maps.Map(addrMap)
// 确保必要字段存在,防止前端组件报错
if !m.Has("name") {
m["name"] = ""
}
if !m.Has("canAccess") {
m["canAccess"] = true
}
if !m.Has("isOn") {
m["isOn"] = true
}
if !m.Has("isUp") {
m["isUp"] = true
}
ipAddresses = append(ipAddresses, m)
}
}
} else {
@@ -87,11 +101,16 @@ func findHTTPDNSNodeMap(parent *actionutils.ParentAction, nodeID int64) (maps.Ma
return nil, err
}
// 构造 node.login 用于 index.html 展示 SSH 信息
// 构造 node.login 用于 index.html 展示 SSH 信息(从 NodeLogin 读取)
var loginMap maps.Map = nil
sshInfo := installStatusMap.GetMap("ssh")
if sshInfo != nil {
grantId := sshInfo.GetInt64("grantId")
if node.GetNodeLogin() != nil {
nodeLogin := node.GetNodeLogin()
sshLoginParams := maps.Map{}
if len(nodeLogin.Params) > 0 {
_ = json.Unmarshal(nodeLogin.Params, &sshLoginParams)
}
grantId := sshLoginParams.GetInt64("grantId")
var grantMap maps.Map = nil
if grantId > 0 {
grantResp, grantErr := parent.RPC().NodeGrantRPC().FindEnabledNodeGrant(parent.AdminContext(), &pb.FindEnabledNodeGrantRequest{
@@ -110,8 +129,8 @@ func findHTTPDNSNodeMap(parent *actionutils.ParentAction, nodeID int64) (maps.Ma
loginMap = maps.Map{
"params": maps.Map{
"host": sshInfo.GetString("host"),
"port": sshInfo.GetInt("port"),
"host": sshLoginParams.GetString("host"),
"port": sshLoginParams.GetInt("port"),
},
"grant": grantMap,
}
@@ -169,8 +188,8 @@ func decodeNodeStatus(raw []byte) maps.Map {
func decodeInstallStatus(raw []byte) maps.Map {
result := maps.Map{
"isRunning": false,
"isFinished": true,
"isOk": true,
"isFinished": false,
"isOk": false,
"error": "",
"errorCode": "",
}

View File

@@ -47,39 +47,62 @@ func (this *UpdateAction) RunGet(params struct {
sshPort := 22
ipAddresses := []maps.Map{}
var grantId int64
var loginId int64
this.Data["grant"] = nil
resp, err := this.RPC().HTTPDNSNodeRPC().FindHTTPDNSNode(this.AdminContext(), &pb.FindHTTPDNSNodeRequest{
NodeId: params.NodeId,
})
if err == nil && resp.GetNode() != nil {
// 从 NodeLogin 读取 SSH 信息
if resp.GetNode().GetNodeLogin() != nil {
nodeLogin := resp.GetNode().GetNodeLogin()
loginId = nodeLogin.Id
if len(nodeLogin.Params) > 0 {
sshLoginParams := maps.Map{}
_ = json.Unmarshal(nodeLogin.Params, &sshLoginParams)
if h := strings.TrimSpace(sshLoginParams.GetString("host")); len(h) > 0 {
sshHost = h
}
if p := sshLoginParams.GetInt("port"); p > 0 {
sshPort = p
}
grantId = sshLoginParams.GetInt64("grantId")
}
}
// IP 地址仍从 installStatus 读取
if len(resp.GetNode().GetInstallStatusJSON()) > 0 {
installStatus := maps.Map{}
_ = json.Unmarshal(resp.GetNode().GetInstallStatusJSON(), &installStatus)
sshInfo := installStatus.GetMap("ssh")
if sshInfo != nil {
if h := strings.TrimSpace(sshInfo.GetString("host")); len(h) > 0 {
sshHost = h
}
if p := sshInfo.GetInt("port"); p > 0 {
sshPort = p
}
grantId = sshInfo.GetInt64("grantId")
}
if installStatus.Has("ipAddresses") {
for _, addr := range installStatus.GetSlice("ipAddresses") {
if addrMap, ok := addr.(map[string]interface{}); ok {
ipAddresses = append(ipAddresses, maps.Map(addrMap))
m := maps.Map(addrMap)
// 确保必要字段存在,防止前端组件报错
if !m.Has("name") {
m["name"] = ""
}
if !m.Has("canAccess") {
m["canAccess"] = true
}
if !m.Has("isOn") {
m["isOn"] = true
}
if !m.Has("isUp") {
m["isUp"] = true
}
ipAddresses = append(ipAddresses, m)
}
}
} else if ip := strings.TrimSpace(installStatus.GetString("ipAddr")); len(ip) > 0 {
ipAddresses = append(ipAddresses, maps.Map{
"ip": ip,
"name": "",
"ip": ip,
"name": "",
"canAccess": true,
"isOn": true,
"isUp": true,
"isOn": true,
"isUp": true,
})
}
}
@@ -87,6 +110,7 @@ func (this *UpdateAction) RunGet(params struct {
this.Data["sshHost"] = sshHost
this.Data["sshPort"] = sshPort
this.Data["loginId"] = loginId
this.Data["ipAddresses"] = ipAddresses
if grantId > 0 {
@@ -107,11 +131,12 @@ func (this *UpdateAction) RunGet(params struct {
}
func (this *UpdateAction) RunPost(params struct {
NodeId int64
Name string
ClusterId int64
IsOn bool
SshHost string
NodeId int64
Name string
ClusterId int64
IsOn bool
LoginId int64
SshHost string
SshPort int
GrantId int64
IpAddressesJSON []byte
@@ -155,8 +180,6 @@ func (this *UpdateAction) RunPost(params struct {
}
}
needUpdateInstallStatus := hasSSHUpdate || len(ipAddresses) > 0
resp, err := this.RPC().HTTPDNSNodeRPC().FindHTTPDNSNode(this.AdminContext(), &pb.FindHTTPDNSNodeRequest{
NodeId: params.NodeId,
})
@@ -186,7 +209,31 @@ func (this *UpdateAction) RunPost(params struct {
return
}
if needUpdateInstallStatus {
// SSH 保存到 NodeLogin
if hasSSHUpdate {
login := &pb.NodeLogin{
Id: params.LoginId,
Name: "SSH",
Type: "ssh",
Params: maps.Map{
"grantId": params.GrantId,
"host": params.SshHost,
"port": params.SshPort,
}.AsJSON(),
}
_, err = this.RPC().HTTPDNSNodeRPC().UpdateHTTPDNSNodeLogin(this.AdminContext(), &pb.UpdateHTTPDNSNodeLoginRequest{
NodeId: params.NodeId,
NodeLogin: login,
})
if err != nil {
this.ErrorPage(err)
return
}
}
// IP 地址仍保存在 installStatus 中
if len(ipAddresses) > 0 {
installStatus := maps.Map{
"isRunning": false,
"isFinished": true,
@@ -197,19 +244,10 @@ func (this *UpdateAction) RunPost(params struct {
if len(node.GetInstallStatusJSON()) > 0 {
_ = json.Unmarshal(node.GetInstallStatusJSON(), &installStatus)
}
if hasSSHUpdate {
installStatus["ssh"] = maps.Map{
"host": params.SshHost,
"port": params.SshPort,
"grantId": params.GrantId,
}
}
if len(ipAddresses) > 0 {
installStatus["ipAddresses"] = ipAddresses
} else {
delete(installStatus, "ipAddresses")
delete(installStatus, "ipAddr") // Cleanup legacy
}
installStatus["ipAddresses"] = ipAddresses
// 清理旧的 ssh 字段
delete(installStatus, "ssh")
delete(installStatus, "ipAddr")
installStatusJSON, _ := json.Marshal(installStatus)
_, err = this.RPC().HTTPDNSNodeRPC().UpdateHTTPDNSNodeStatus(this.AdminContext(), &pb.UpdateHTTPDNSNodeStatusRequest{

View File

@@ -34,7 +34,7 @@ func (this *UpdateInstallStatusAction) RunPost(params struct {
_ = json.Unmarshal(node.GetInstallStatusJSON(), &installStatus)
}
installStatus["isRunning"] = false
installStatus["isFinished"] = true
installStatus["isFinished"] = params.IsInstalled // 标记为未安装时重置为"未开始"状态
installStatus["isOk"] = params.IsInstalled
installStatus["error"] = ""
installStatus["errorCode"] = ""

View File

@@ -10,10 +10,8 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/serverconfigs/sslconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
"github.com/iwind/TeaGo/types"
)
type ClusterSettingsAction struct {
@@ -49,11 +47,9 @@ func (this *ClusterSettingsAction) RunGet(params struct {
"fallbackTimeout": cluster.GetInt("fallbackTimeout"),
"installDir": cluster.GetString("installDir"),
"isOn": cluster.GetBool("isOn"),
"isDefaultCluster": cluster.GetBool("isDefault"),
"isDefaultBackupCluster": false,
}
if settings.GetInt("cacheTtl") <= 0 {
settings["cacheTtl"] = 30
settings["cacheTtl"] = 60
}
if settings.GetInt("fallbackTimeout") <= 0 {
settings["fallbackTimeout"] = 300
@@ -62,22 +58,9 @@ func (this *ClusterSettingsAction) RunGet(params struct {
settings["installDir"] = "/opt/edge-httpdns"
}
defaultBackupResp, err := this.RPC().SysSettingRPC().ReadSysSetting(this.AdminContext(), &pb.ReadSysSettingRequest{
Code: string(systemconfigs.SettingCodeHTTPDNSDefaultBackupClusterId),
})
if err != nil {
this.ErrorPage(err)
return
}
defaultBackupClusterId := int64(0)
if defaultBackupResp != nil && len(defaultBackupResp.GetValueJSON()) > 0 {
defaultBackupClusterId = types.Int64(string(defaultBackupResp.GetValueJSON()))
}
settings["isDefaultBackupCluster"] = defaultBackupClusterId == params.ClusterId
listenAddresses := []*serverconfigs.NetworkAddressConfig{
{
Protocol: serverconfigs.ProtocolHTTPS,
Protocol: serverconfigs.ProtocolTLS,
Host: "",
PortRange: "443",
},
@@ -126,9 +109,7 @@ func (this *ClusterSettingsAction) RunPost(params struct {
CacheTtl int32
FallbackTimeout int32
InstallDir string
IsOn bool
IsDefaultCluster bool
IsDefaultBackupCluster bool
IsOn bool
Addresses []byte
SslPolicyJSON []byte
@@ -145,7 +126,7 @@ func (this *ClusterSettingsAction) RunPost(params struct {
params.Must.Field("gatewayDomain", params.GatewayDomain).Require("请输入服务域名")
if params.CacheTtl <= 0 {
params.CacheTtl = 30
params.CacheTtl = 60
}
if params.FallbackTimeout <= 0 {
params.FallbackTimeout = 300
@@ -153,18 +134,6 @@ func (this *ClusterSettingsAction) RunPost(params struct {
if len(params.InstallDir) == 0 {
params.InstallDir = "/opt/edge-httpdns"
}
if params.IsDefaultCluster && !params.IsOn {
this.Fail("默认主集群必须保持启用状态")
return
}
if params.IsDefaultBackupCluster && !params.IsOn {
this.Fail("默认备用集群必须保持启用状态")
return
}
if params.IsDefaultCluster && params.IsDefaultBackupCluster {
this.Fail("默认主集群和默认备用集群不能是同一个集群")
return
}
cluster, err := findClusterMap(this.Parent(), params.ClusterId)
if err != nil {
@@ -213,35 +182,7 @@ func (this *ClusterSettingsAction) RunPost(params struct {
InstallDir: params.InstallDir,
TlsPolicyJSON: tlsPolicyJSON,
IsOn: params.IsOn,
IsDefault: params.IsDefaultCluster,
})
if err != nil {
this.ErrorPage(err)
return
}
backupClusterValue := int64(0)
if params.IsDefaultBackupCluster {
backupClusterValue = params.ClusterId
} else {
readResp, err := this.RPC().SysSettingRPC().ReadSysSetting(this.AdminContext(), &pb.ReadSysSettingRequest{
Code: string(systemconfigs.SettingCodeHTTPDNSDefaultBackupClusterId),
})
if err != nil {
this.ErrorPage(err)
return
}
if readResp != nil && len(readResp.GetValueJSON()) > 0 {
oldBackupClusterId := types.Int64(string(readResp.GetValueJSON()))
if oldBackupClusterId != params.ClusterId {
backupClusterValue = oldBackupClusterId
}
}
}
_, err = this.RPC().SysSettingRPC().UpdateSysSetting(this.AdminContext(), &pb.UpdateSysSettingRequest{
Code: string(systemconfigs.SettingCodeHTTPDNSDefaultBackupClusterId),
ValueJSON: []byte(strconv.FormatInt(backupClusterValue, 10)),
IsDefault: false,
})
if err != nil {
this.ErrorPage(err)

View File

@@ -1,13 +1,11 @@
package clusters
import (
"strconv"
"strings"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/httpdnsutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
"github.com/iwind/TeaGo/actions"
)
@@ -25,14 +23,12 @@ func (this *CreateAction) RunGet(params struct{}) {
}
func (this *CreateAction) RunPost(params struct {
Name string
GatewayDomain string
CacheTtl int32
FallbackTimeout int32
InstallDir string
IsOn bool
IsDefaultPrimary bool
IsDefaultBackup bool
Name string
GatewayDomain string
CacheTtl int32
FallbackTimeout int32
InstallDir string
IsOn bool
Must *actions.Must
}) {
@@ -43,7 +39,7 @@ func (this *CreateAction) RunPost(params struct {
params.InstallDir = "/opt/edge-httpdns"
}
if params.CacheTtl <= 0 {
params.CacheTtl = 30
params.CacheTtl = 60
}
if params.FallbackTimeout <= 0 {
params.FallbackTimeout = 300
@@ -52,19 +48,6 @@ func (this *CreateAction) RunPost(params struct {
params.Must.Field("name", params.Name).Require("请输入集群名称")
params.Must.Field("gatewayDomain", params.GatewayDomain).Require("请输入服务域名")
if params.IsDefaultPrimary && !params.IsOn {
this.Fail("默认主集群必须保持启用状态")
return
}
if params.IsDefaultBackup && !params.IsOn {
this.Fail("默认备用集群必须保持启用状态")
return
}
if params.IsDefaultPrimary && params.IsDefaultBackup {
this.Fail("默认主集群和默认备用集群不能是同一个集群")
return
}
resp, err := this.RPC().HTTPDNSClusterRPC().CreateHTTPDNSCluster(this.AdminContext(), &pb.CreateHTTPDNSClusterRequest{
Name: params.Name,
ServiceDomain: params.GatewayDomain,
@@ -72,24 +55,13 @@ func (this *CreateAction) RunPost(params struct {
FallbackTimeoutMs: params.FallbackTimeout,
InstallDir: params.InstallDir,
IsOn: params.IsOn,
IsDefault: params.IsDefaultPrimary,
IsDefault: false,
})
if err != nil {
this.ErrorPage(err)
return
}
if params.IsDefaultBackup {
_, err = this.RPC().SysSettingRPC().UpdateSysSetting(this.AdminContext(), &pb.UpdateSysSettingRequest{
Code: string(systemconfigs.SettingCodeHTTPDNSDefaultBackupClusterId),
ValueJSON: []byte(strconv.FormatInt(resp.GetClusterId(), 10)),
})
if err != nil {
this.ErrorPage(err)
return
}
}
this.Data["clusterId"] = resp.GetClusterId()
this.Success()
}

View File

@@ -37,10 +37,29 @@ func listClusterMaps(parent *actionutils.ParentAction, keyword string) ([]maps.M
}
}
port := "443"
if rawTLS := cluster.GetTlsPolicyJSON(); len(rawTLS) > 0 {
tlsConfig := maps.Map{}
if err := json.Unmarshal(rawTLS, &tlsConfig); err == nil {
if listenRaw := tlsConfig.Get("listen"); listenRaw != nil {
var listenAddresses []maps.Map
if data, err := json.Marshal(listenRaw); err == nil {
if err := json.Unmarshal(data, &listenAddresses); err == nil {
if len(listenAddresses) > 0 && len(listenAddresses[0].GetString("portRange")) > 0 {
port = listenAddresses[0].GetString("portRange")
}
}
}
}
}
}
apiAddress := "https://" + cluster.GetServiceDomain() + ":" + port
result = append(result, maps.Map{
"id": cluster.GetId(),
"name": cluster.GetName(),
"gatewayDomain": cluster.GetServiceDomain(),
"apiAddress": apiAddress,
"defaultTTL": cluster.GetDefaultTTL(),
"fallbackTimeout": cluster.GetFallbackTimeoutMs(),
"installDir": cluster.GetInstallDir(),
@@ -86,7 +105,7 @@ func findClusterMap(parent *actionutils.ParentAction, clusterID int64) (maps.Map
"id": int64(0),
"name": "",
"gatewayDomain": "",
"defaultTTL": 30,
"defaultTTL": 60,
"fallbackTimeout": 300,
"installDir": "/opt/edge-httpdns",
}, nil

View File

@@ -7,8 +7,8 @@ import (
"strings"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/iwind/TeaGo/actions"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/maps"
)
@@ -47,25 +47,36 @@ func (this *UpdateNodeSSHAction) RunGet(params struct {
}
this.Data["loginId"] = 0
if resp.GetNode() != nil && len(resp.GetNode().GetInstallStatusJSON()) > 0 {
installStatus := maps.Map{}
_ = json.Unmarshal(resp.GetNode().GetInstallStatusJSON(), &installStatus)
sshInfo := installStatus.GetMap("ssh")
if sshInfo != nil {
if host := strings.TrimSpace(sshInfo.GetString("host")); len(host) > 0 {
loginParams["host"] = host
}
if port := sshInfo.GetInt("port"); port > 0 {
loginParams["port"] = port
}
if grantID := sshInfo.GetInt64("grantId"); grantID > 0 {
loginParams["grantId"] = grantID
}
// 从 NodeLogin 读取 SSH 信息
if resp.GetNode() != nil && resp.GetNode().GetNodeLogin() != nil {
nodeLogin := resp.GetNode().GetNodeLogin()
this.Data["loginId"] = nodeLogin.Id
if len(nodeLogin.Params) > 0 {
_ = json.Unmarshal(nodeLogin.Params, &loginParams)
}
}
this.Data["params"] = loginParams
this.Data["grant"] = nil
// 认证信息
grantId := loginParams.GetInt64("grantId")
var grantMap maps.Map = nil
if grantId > 0 {
grantResp, grantErr := this.RPC().NodeGrantRPC().FindEnabledNodeGrant(this.AdminContext(), &pb.FindEnabledNodeGrantRequest{
NodeGrantId: grantId,
})
if grantErr == nil && grantResp.GetNodeGrant() != nil {
g := grantResp.GetNodeGrant()
grantMap = maps.Map{
"id": g.Id,
"name": g.Name,
"method": g.Method,
"methodName": g.Method,
}
}
}
this.Data["grant"] = grantMap
this.Show()
}
@@ -93,46 +104,23 @@ func (this *UpdateNodeSSHAction) RunPost(params struct {
this.Fail("SSH 主机地址 IP 格式错误")
}
resp, err := this.RPC().HTTPDNSNodeRPC().FindHTTPDNSNode(this.AdminContext(), &pb.FindHTTPDNSNodeRequest{
NodeId: params.NodeId,
})
if err != nil {
this.ErrorPage(err)
return
}
node := resp.GetNode()
if node == nil {
this.Fail("节点不存在")
return
login := &pb.NodeLogin{
Id: params.LoginId,
Name: "SSH",
Type: "ssh",
Params: maps.Map{
"grantId": params.GrantId,
"host": params.SshHost,
"port": params.SshPort,
}.AsJSON(),
}
installStatus := maps.Map{
"isRunning": false,
"isFinished": true,
"isOk": node.GetIsInstalled(),
"error": "",
"errorCode": "",
}
if len(node.GetInstallStatusJSON()) > 0 {
_ = json.Unmarshal(node.GetInstallStatusJSON(), &installStatus)
}
installStatus["ssh"] = maps.Map{
"host": params.SshHost,
"port": params.SshPort,
"grantId": params.GrantId,
}
installStatusJSON, _ := json.Marshal(installStatus)
_, err = this.RPC().HTTPDNSNodeRPC().UpdateHTTPDNSNodeStatus(this.AdminContext(), &pb.UpdateHTTPDNSNodeStatusRequest{
NodeId: params.NodeId,
IsUp: node.GetIsUp(),
IsInstalled: node.GetIsInstalled(),
IsActive: node.GetIsActive(),
StatusJSON: node.GetStatusJSON(),
InstallStatusJSON: installStatusJSON,
_, err := this.RPC().HTTPDNSNodeRPC().UpdateHTTPDNSNodeLogin(this.AdminContext(), &pb.UpdateHTTPDNSNodeLoginRequest{
NodeId: params.NodeId,
NodeLogin: login,
})
if err != nil {
this.ErrorPage(err)
this.Fail("保存SSH登录信息失败: " + err.Error())
return
}

View File

@@ -1,15 +0,0 @@
package guide
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("httpdns", "app", "")
}
func (this *IndexAction) RunGet(params struct{}) {
this.RedirectURL("/httpdns/apps")
}

View File

@@ -1,19 +0,0 @@
package guide
import (
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
"github.com/iwind/TeaGo"
)
func init() {
TeaGo.BeforeStart(func(server *TeaGo.Server) {
server.
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeHttpDNS)).
Data("teaMenu", "httpdns").
Data("teaSubMenu", "guide").
Prefix("/httpdns/guide").
Get("", new(IndexAction)).
EndAll()
})
}

View File

@@ -1,19 +0,0 @@
package policies
import "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
type IndexAction struct {
actionutils.ParentAction
}
func (this *IndexAction) Init() {
this.Nav("httpdns", "policy", "")
}
func (this *IndexAction) RunGet(params struct{}) {
this.RedirectURL("/httpdns/clusters")
}
func (this *IndexAction) RunPost(params struct{}) {
this.Success()
}

View File

@@ -1,19 +0,0 @@
package policies
import (
"github.com/TeaOSLab/EdgeAdmin/internal/configloaders"
"github.com/TeaOSLab/EdgeAdmin/internal/web/helpers"
"github.com/iwind/TeaGo"
)
func init() {
TeaGo.BeforeStart(func(server *TeaGo.Server) {
server.
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeHttpDNS)).
Data("teaMenu", "httpdns").
Data("teaSubMenu", "policy").
Prefix("/httpdns/policies").
GetPost("", new(IndexAction)).
EndAll()
})
}

View File

@@ -1,6 +1,9 @@
package sandbox
import (
"encoding/json"
"strings"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/httpdns/httpdnsutils"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
@@ -25,9 +28,37 @@ func (this *IndexAction) RunGet(params struct{}) {
}
clusters := make([]maps.Map, 0, len(clusterResp.GetClusters()))
for _, cluster := range clusterResp.GetClusters() {
serviceDomain := strings.TrimSpace(cluster.GetServiceDomain())
port := "443"
if rawTLS := cluster.GetTlsPolicyJSON(); len(rawTLS) > 0 {
var tlsConfig map[string]interface{}
if err := json.Unmarshal(rawTLS, &tlsConfig); err == nil {
if listenRaw, ok := tlsConfig["listen"]; ok && listenRaw != nil {
if data, err := json.Marshal(listenRaw); err == nil {
var listenAddresses []map[string]interface{}
if err := json.Unmarshal(data, &listenAddresses); err == nil {
if len(listenAddresses) > 0 {
if portRange, ok := listenAddresses[0]["portRange"].(string); ok && len(portRange) > 0 {
port = portRange
}
}
}
}
}
}
}
apiAddress := "https://" + serviceDomain + ":" + port
displayName := apiAddress
if len(serviceDomain) == 0 {
displayName = cluster.GetName()
}
clusters = append(clusters, maps.Map{
"id": cluster.GetId(),
"name": cluster.GetName(),
"id": cluster.GetId(),
"name": cluster.GetName(),
"serviceDomain": serviceDomain,
"displayName": displayName,
})
}
this.Data["clusters"] = clusters
@@ -50,14 +81,18 @@ func (this *IndexAction) RunGet(params struct{}) {
for _, domain := range domainResp.GetDomains() {
domains = append(domains, domain.GetDomain())
}
// 解析集群ID列表
var clusterIds []int64
if len(app.GetClusterIdsJSON()) > 0 {
_ = json.Unmarshal(app.GetClusterIdsJSON(), &clusterIds)
}
apps = append(apps, maps.Map{
"id": app.GetId(),
"name": app.GetName(),
"appId": app.GetAppId(),
"clusterId": app.GetPrimaryClusterId(),
"primaryClusterId": app.GetPrimaryClusterId(),
"backupClusterId": app.GetBackupClusterId(),
"domains": domains,
"id": app.GetId(),
"name": app.GetName(),
"appId": app.GetAppId(),
"clusterIds": clusterIds,
"domains": domains,
})
}
this.Data["apps"] = apps

View File

@@ -4,6 +4,7 @@ import (
"crypto/hmac"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"net/url"
"strconv"
"strings"
@@ -52,12 +53,30 @@ func (this *TestAction) RunPost(params struct {
}
clusterDomain := ""
port := "443"
if params.ClusterId > 0 {
clusterResp, findErr := this.RPC().HTTPDNSClusterRPC().FindHTTPDNSCluster(this.AdminContext(), &pb.FindHTTPDNSClusterRequest{
ClusterId: params.ClusterId,
})
if findErr == nil && clusterResp.GetCluster() != nil {
clusterDomain = strings.TrimSpace(clusterResp.GetCluster().GetServiceDomain())
if rawTLS := clusterResp.GetCluster().GetTlsPolicyJSON(); len(rawTLS) > 0 {
var tlsConfig map[string]interface{}
if err := json.Unmarshal(rawTLS, &tlsConfig); err == nil {
if listenRaw, ok := tlsConfig["listen"]; ok && listenRaw != nil {
if data, err := json.Marshal(listenRaw); err == nil {
var listenAddresses []map[string]interface{}
if err := json.Unmarshal(data, &listenAddresses); err == nil {
if len(listenAddresses) > 0 {
if portRange, ok := listenAddresses[0]["portRange"].(string); ok && len(portRange) > 0 {
port = portRange
}
}
}
}
}
}
}
}
}
if len(clusterDomain) == 0 {
@@ -80,7 +99,7 @@ func (this *TestAction) RunPost(params struct {
query.Set("nonce", nonce)
query.Set("sign", sign)
}
requestURL := "https://" + clusterDomain + "/resolve?" + query.Encode()
requestURL := "https://" + clusterDomain + ":" + port + "/resolve?" + query.Encode()
resultCode := 1
if strings.EqualFold(resp.GetCode(), "SUCCESS") {

View File

@@ -10,6 +10,7 @@ import (
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
"github.com/iwind/TeaGo/actions"
"github.com/iwind/TeaGo/lists"
"github.com/iwind/TeaGo/maps"
"github.com/xlzd/gotp"
)
@@ -23,6 +24,38 @@ func (this *CreatePopupAction) Init() {
}
func (this *CreatePopupAction) RunGet(params struct{}) {
// 检查是否启用了 HTTPDNS 功能(全局用户注册设置中)
var hasHTTPDNSFeature = false
var defaultHttpdnsClusterId int64 = 0
resp, err := this.RPC().SysSettingRPC().ReadSysSetting(this.AdminContext(), &pb.ReadSysSettingRequest{Code: systemconfigs.SettingCodeUserRegisterConfig})
if err == nil && len(resp.ValueJSON) > 0 {
var config = userconfigs.DefaultUserRegisterConfig()
if json.Unmarshal(resp.ValueJSON, config) == nil {
hasHTTPDNSFeature = config.HTTPDNSIsOn
if len(config.HTTPDNSDefaultClusterIds) > 0 {
defaultHttpdnsClusterId = config.HTTPDNSDefaultClusterIds[0]
}
}
}
this.Data["hasHTTPDNSFeature"] = hasHTTPDNSFeature
this.Data["httpdnsClusterId"] = defaultHttpdnsClusterId
// 加载所有 HTTPDNS 集群
var httpdnsClusters = []maps.Map{}
if hasHTTPDNSFeature {
httpdnsClusterResp, err := this.RPC().HTTPDNSClusterRPC().FindAllHTTPDNSClusters(this.AdminContext(), &pb.FindAllHTTPDNSClustersRequest{})
if err == nil {
for _, c := range httpdnsClusterResp.GetClusters() {
httpdnsClusters = append(httpdnsClusters, maps.Map{
"id": c.GetId(),
"name": c.GetName(),
})
}
}
}
this.Data["httpdnsClusters"] = httpdnsClusters
this.Show()
}
@@ -35,8 +68,9 @@ func (this *CreatePopupAction) RunPost(params struct {
Tel string
Email string
Remark string
ClusterId int64
FeaturesType string
ClusterId int64
HttpdnsClusterId int64
FeaturesType string
// OTP
OtpOn bool
@@ -111,6 +145,28 @@ func (this *CreatePopupAction) RunPost(params struct {
userId = createResp.UserId
// 如果表单选择了 HTTPDNS 关联集群,在这里予以保存
if params.HttpdnsClusterId > 0 {
httpdnsJSON, _ := json.Marshal([]int64{params.HttpdnsClusterId})
_, err = this.RPC().UserRPC().UpdateUser(this.AdminContext(), &pb.UpdateUserRequest{
UserId: userId,
Username: params.Username,
Password: params.Pass1,
Fullname: params.Fullname,
Mobile: params.Mobile,
Tel: params.Tel,
Email: params.Email,
Remark: params.Remark,
IsOn: true,
NodeClusterId: params.ClusterId,
HttpdnsClusterIdsJSON: httpdnsJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
}
// 功能
if teaconst.IsPlus {
if params.FeaturesType == "default" {
@@ -127,14 +183,41 @@ func (this *CreatePopupAction) RunPost(params struct {
this.ErrorPage(err)
return
}
var featureCodes = config.Features
if config.HTTPDNSIsOn && !lists.ContainsString(featureCodes, userconfigs.UserFeatureCodeHTTPDNS) {
featureCodes = append(featureCodes, userconfigs.UserFeatureCodeHTTPDNS)
}
_, err = this.RPC().UserRPC().UpdateUserFeatures(this.AdminContext(), &pb.UpdateUserFeaturesRequest{
UserId: userId,
FeatureCodes: config.Features,
FeatureCodes: featureCodes,
})
if err != nil {
this.ErrorPage(err)
return
}
// 自动关联默认 HTTPDNS 集群 (如果没有在表单中选择的话)
if config.HTTPDNSIsOn && params.HttpdnsClusterId <= 0 && len(config.HTTPDNSDefaultClusterIds) > 0 {
httpdnsJSON, _ := json.Marshal(config.HTTPDNSDefaultClusterIds)
_, err = this.RPC().UserRPC().UpdateUser(this.AdminContext(), &pb.UpdateUserRequest{
UserId: userId,
Username: params.Username,
Password: params.Pass1,
Fullname: params.Fullname,
Mobile: params.Mobile,
Tel: params.Tel,
Email: params.Email,
Remark: params.Remark,
IsOn: true,
NodeClusterId: params.ClusterId,
HttpdnsClusterIdsJSON: httpdnsJSON,
})
if err != nil {
this.ErrorPage(err)
return
}
}
}
} else if params.FeaturesType == "all" {
featuresResp, err := this.RPC().UserRPC().FindAllUserFeatureDefinitions(this.AdminContext(), &pb.FindAllUserFeatureDefinitionsRequest{})

View File

@@ -66,6 +66,28 @@ func (this *IndexAction) RunGet(params struct{}) {
// 当前默认的智能DNS设置
this.Data["nsIsVisible"] = plus.AllowComponent(plus.ComponentCodeNS)
// HTTPDNS 集群列表(用于默认集群多选)
httpdnsClusterResp, err := this.RPC().HTTPDNSClusterRPC().FindAllHTTPDNSClusters(this.AdminContext(), &pb.FindAllHTTPDNSClustersRequest{})
if err != nil {
this.ErrorPage(err)
return
}
httpdnsClusters := make([]maps.Map, 0, len(httpdnsClusterResp.GetClusters()))
for _, cluster := range httpdnsClusterResp.GetClusters() {
httpdnsClusters = append(httpdnsClusters, maps.Map{
"id": cluster.GetId(),
"name": cluster.GetName(),
})
}
this.Data["httpdnsClusters"] = httpdnsClusters
// 当前选中的默认集群(取数组第一个元素)
var httpdnsDefaultClusterId int64
if len(config.HTTPDNSDefaultClusterIds) > 0 {
httpdnsDefaultClusterId = config.HTTPDNSDefaultClusterIds[0]
}
this.Data["httpdnsDefaultClusterId"] = httpdnsDefaultClusterId
this.Show()
}
@@ -102,7 +124,8 @@ func (this *IndexAction) RunPost(params struct {
NsIsOn bool
HttpdnsIsOn bool
HttpdnsIsOn bool
HttpdnsDefaultClusterId int64
Must *actions.Must
CSRF *actionutils.CSRF
@@ -154,6 +177,11 @@ func (this *IndexAction) RunPost(params struct {
config.NSIsOn = params.NsIsOn
config.HTTPDNSIsOn = params.HttpdnsIsOn
if params.HttpdnsDefaultClusterId > 0 {
config.HTTPDNSDefaultClusterIds = []int64{params.HttpdnsDefaultClusterId}
} else {
config.HTTPDNSDefaultClusterIds = []int64{}
}
configJSON, err := json.Marshal(config)
if err != nil {

View File

@@ -1,6 +1,8 @@
package users
import (
"encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/users/userutils"
"github.com/TeaOSLab/EdgeCommon/pkg/langs/codes"
@@ -85,6 +87,46 @@ func (this *UpdateAction) RunGet(params struct {
this.Data["clusterId"] = user.NodeCluster.Id
}
// 检查用户是否开通了 HTTPDNS 功能
var hasHTTPDNSFeature = false
userFeaturesResp, err := this.RPC().UserRPC().FindUserFeatures(this.AdminContext(), &pb.FindUserFeaturesRequest{UserId: params.UserId})
if err != nil {
this.ErrorPage(err)
return
}
for _, f := range userFeaturesResp.Features {
if f.Code == "httpdns" {
hasHTTPDNSFeature = true
break
}
}
this.Data["hasHTTPDNSFeature"] = hasHTTPDNSFeature
// 读取用户已关联的 HTTPDNS 集群(取第一个作为下拉默认值)
var httpdnsClusterId int64
if len(user.HttpdnsClusterIdsJSON) > 0 {
var userHTTPDNSClusterIds []int64
if json.Unmarshal(user.HttpdnsClusterIdsJSON, &userHTTPDNSClusterIds) == nil && len(userHTTPDNSClusterIds) > 0 {
httpdnsClusterId = userHTTPDNSClusterIds[0]
}
}
this.Data["httpdnsClusterId"] = httpdnsClusterId
// 加载所有 HTTPDNS 集群
httpdnsClusterResp, err := this.RPC().HTTPDNSClusterRPC().FindAllHTTPDNSClusters(this.AdminContext(), &pb.FindAllHTTPDNSClustersRequest{})
if err != nil {
this.ErrorPage(err)
return
}
httpdnsClusters := make([]maps.Map, 0, len(httpdnsClusterResp.GetClusters()))
for _, c := range httpdnsClusterResp.GetClusters() {
httpdnsClusters = append(httpdnsClusters, maps.Map{
"id": c.GetId(),
"name": c.GetName(),
})
}
this.Data["httpdnsClusters"] = httpdnsClusters
this.Show()
}
@@ -99,8 +141,9 @@ func (this *UpdateAction) RunPost(params struct {
Email string
Remark string
IsOn bool
ClusterId int64
BandwidthAlgo string
ClusterId int64
HttpdnsClusterId int64
BandwidthAlgo string
// OTP
OtpOn bool
@@ -151,18 +194,25 @@ func (this *UpdateAction) RunPost(params struct {
Email("请输入正确的电子邮箱")
}
var httpdnsClusterIds []int64
if params.HttpdnsClusterId > 0 {
httpdnsClusterIds = []int64{params.HttpdnsClusterId}
}
httpdnsClusterIdsJSON, _ := json.Marshal(httpdnsClusterIds)
_, err = this.RPC().UserRPC().UpdateUser(this.AdminContext(), &pb.UpdateUserRequest{
UserId: params.UserId,
Username: params.Username,
Password: params.Pass1,
Fullname: params.Fullname,
Mobile: params.Mobile,
Tel: params.Tel,
Email: params.Email,
Remark: params.Remark,
IsOn: params.IsOn,
NodeClusterId: params.ClusterId,
BandwidthAlgo: params.BandwidthAlgo,
UserId: params.UserId,
Username: params.Username,
Password: params.Pass1,
Fullname: params.Fullname,
Mobile: params.Mobile,
Tel: params.Tel,
Email: params.Email,
Remark: params.Remark,
IsOn: params.IsOn,
NodeClusterId: params.ClusterId,
BandwidthAlgo: params.BandwidthAlgo,
HttpdnsClusterIdsJSON: httpdnsClusterIdsJSON,
})
if err != nil {
this.ErrorPage(err)

View File

@@ -6,6 +6,8 @@ import (
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/users/userutils"
"github.com/TeaOSLab/EdgeCommon/pkg/iplibrary"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
"github.com/TeaOSLab/EdgeCommon/pkg/systemconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/userconfigs"
"github.com/iwind/TeaGo/maps"
)
@@ -89,6 +91,37 @@ func (this *UserAction) RunGet(params struct {
}
}
// 检查全局是否启用了 HTTPDNS 功能
var hasHTTPDNSFeature = false
sysResp, sysErr := this.RPC().SysSettingRPC().ReadSysSetting(this.AdminContext(), &pb.ReadSysSettingRequest{Code: systemconfigs.SettingCodeUserRegisterConfig})
if sysErr == nil && len(sysResp.ValueJSON) > 0 {
var config = userconfigs.DefaultUserRegisterConfig()
if json.Unmarshal(sysResp.ValueJSON, config) == nil {
hasHTTPDNSFeature = config.HTTPDNSIsOn
}
}
this.Data["hasHTTPDNSFeature"] = hasHTTPDNSFeature
// 读取用户关联的 HTTPDNS 集群
var httpdnsClusterMap maps.Map = nil
if hasHTTPDNSFeature && len(user.HttpdnsClusterIdsJSON) > 0 {
var httpdnsClusterIds []int64
if json.Unmarshal(user.HttpdnsClusterIdsJSON, &httpdnsClusterIds) == nil && len(httpdnsClusterIds) > 0 {
httpdnsClusterResp, httpdnsErr := this.RPC().HTTPDNSClusterRPC().FindAllHTTPDNSClusters(this.AdminContext(), &pb.FindAllHTTPDNSClustersRequest{})
if httpdnsErr == nil {
for _, c := range httpdnsClusterResp.GetClusters() {
if c.GetId() == httpdnsClusterIds[0] {
httpdnsClusterMap = maps.Map{
"id": c.GetId(),
"name": c.GetName(),
}
break
}
}
}
}
}
this.Data["user"] = maps.Map{
"id": user.Id,
"username": user.Username,
@@ -100,6 +133,7 @@ func (this *UserAction) RunGet(params struct {
"mobile": user.Mobile,
"isOn": user.IsOn,
"cluster": clusterMap,
"httpdnsCluster": httpdnsClusterMap,
"countAccessKeys": countAccessKeys,
"isRejected": user.IsRejected,
"rejectReason": user.RejectReason,