mirror of
https://github.com/TeaOSLab/EdgeAdmin.git
synced 2025-11-03 20:40:26 +08:00
初步实现多集群共享节点
This commit is contained in:
@@ -11,7 +11,7 @@ import (
|
||||
"strconv"
|
||||
)
|
||||
|
||||
// 创建节点
|
||||
// CreateNodeAction 创建节点
|
||||
type CreateNodeAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
@@ -57,8 +57,10 @@ func (this *CreateNodeAction) RunGet(params struct {
|
||||
}
|
||||
for _, route := range routesResp.Routes {
|
||||
dnsRouteMaps = append(dnsRouteMaps, maps.Map{
|
||||
"name": route.Name,
|
||||
"code": route.Code,
|
||||
"domainId": domainId,
|
||||
"domainName": clusterDNSResp.Domain.Name,
|
||||
"name": route.Name,
|
||||
"code": route.Code,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package node
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils"
|
||||
@@ -37,6 +38,7 @@ func (this *DetailAction) RunGet(params struct {
|
||||
return
|
||||
}
|
||||
|
||||
// 主集群
|
||||
var clusterMap maps.Map = nil
|
||||
if node.NodeCluster != nil {
|
||||
clusterId := node.NodeCluster.Id
|
||||
@@ -55,6 +57,16 @@ func (this *DetailAction) RunGet(params struct {
|
||||
}
|
||||
}
|
||||
|
||||
// 从集群
|
||||
var secondaryClustersMaps = []maps.Map{}
|
||||
for _, cluster := range node.SecondaryNodeClusters {
|
||||
secondaryClustersMaps = append(secondaryClustersMaps, maps.Map{
|
||||
"id": cluster.Id,
|
||||
"name": cluster.Name,
|
||||
"isOn": cluster.IsOn,
|
||||
})
|
||||
}
|
||||
|
||||
// IP地址
|
||||
ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledIPAddressesWithNodeIdRequest{
|
||||
NodeId: params.NodeId,
|
||||
@@ -64,6 +76,7 @@ func (this *DetailAction) RunGet(params struct {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var ipAddresses = ipAddressesResp.Addresses
|
||||
ipAddressMaps := []maps.Map{}
|
||||
for _, addr := range ipAddressesResp.Addresses {
|
||||
ipAddressMaps = append(ipAddressMaps, maps.Map{
|
||||
@@ -75,33 +88,56 @@ func (this *DetailAction) RunGet(params struct {
|
||||
}
|
||||
|
||||
// DNS相关
|
||||
dnsInfoResp, err := this.RPC().NodeRPC().FindEnabledNodeDNS(this.AdminContext(), &pb.FindEnabledNodeDNSRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
dnsRouteMaps := []maps.Map{}
|
||||
recordName := ""
|
||||
recordValue := ""
|
||||
if dnsInfoResp.Node != nil {
|
||||
recordName = dnsInfoResp.Node.NodeClusterDNSName + "." + dnsInfoResp.Node.DnsDomainName
|
||||
recordValue = dnsInfoResp.Node.IpAddr
|
||||
for _, dnsInfo := range dnsInfoResp.Node.Routes {
|
||||
dnsRouteMaps = append(dnsRouteMaps, maps.Map{
|
||||
"name": dnsInfo.Name,
|
||||
"code": dnsInfo.Code,
|
||||
})
|
||||
var clusters = []*pb.NodeCluster{node.NodeCluster}
|
||||
clusters = append(clusters, node.SecondaryNodeClusters...)
|
||||
var recordMaps = []maps.Map{}
|
||||
var routeMaps = []maps.Map{}
|
||||
for _, cluster := range clusters {
|
||||
dnsInfoResp, err := this.RPC().NodeRPC().FindEnabledNodeDNS(this.AdminContext(), &pb.FindEnabledNodeDNSRequest{
|
||||
NodeId: params.NodeId,
|
||||
NodeClusterId: cluster.Id,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var dnsInfo = dnsInfoResp.Node
|
||||
if len(dnsInfo.DnsDomainName) == 0 || len(dnsInfo.NodeClusterDNSName) == 0 {
|
||||
continue
|
||||
}
|
||||
var domainName = dnsInfo.DnsDomainName
|
||||
|
||||
// 默认线路
|
||||
if len(dnsInfo.Routes) == 0 {
|
||||
dnsInfo.Routes = append(dnsInfo.Routes, &pb.DNSRoute{})
|
||||
} else {
|
||||
for _, route := range dnsInfo.Routes {
|
||||
routeMaps = append(routeMaps, maps.Map{
|
||||
"domainName": domainName,
|
||||
"code": route.Code,
|
||||
"name": route.Name,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
for _, addr := range ipAddresses {
|
||||
if !addr.CanAccess {
|
||||
continue
|
||||
}
|
||||
for _, route := range dnsInfo.Routes {
|
||||
var recordType = "A"
|
||||
if utils.IsIPv6(addr.Ip) {
|
||||
recordType = "AAAA"
|
||||
}
|
||||
recordMaps = append(recordMaps, maps.Map{
|
||||
"name": dnsInfo.NodeClusterDNSName + "." + domainName,
|
||||
"type": recordType,
|
||||
"route": route.Name,
|
||||
"value": addr.Ip,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(dnsRouteMaps) == 0 {
|
||||
dnsRouteMaps = append(dnsRouteMaps, maps.Map{
|
||||
"name": "",
|
||||
"code": "",
|
||||
})
|
||||
}
|
||||
this.Data["dnsRoutes"] = dnsRouteMaps
|
||||
this.Data["dnsRecordName"] = recordName
|
||||
this.Data["dnsRecordValue"] = recordValue
|
||||
|
||||
// 登录信息
|
||||
var loginMap maps.Map = nil
|
||||
@@ -217,17 +253,20 @@ func (this *DetailAction) RunGet(params struct {
|
||||
}
|
||||
|
||||
this.Data["node"] = maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
"ipAddresses": ipAddressMaps,
|
||||
"cluster": clusterMap,
|
||||
"login": loginMap,
|
||||
"installDir": node.InstallDir,
|
||||
"isInstalled": node.IsInstalled,
|
||||
"uniqueId": node.UniqueId,
|
||||
"secret": node.Secret,
|
||||
"maxCPU": node.MaxCPU,
|
||||
"isOn": node.IsOn,
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
"ipAddresses": ipAddressMaps,
|
||||
"cluster": clusterMap,
|
||||
"secondaryClusters": secondaryClustersMaps,
|
||||
"login": loginMap,
|
||||
"installDir": node.InstallDir,
|
||||
"isInstalled": node.IsInstalled,
|
||||
"uniqueId": node.UniqueId,
|
||||
"secret": node.Secret,
|
||||
"maxCPU": node.MaxCPU,
|
||||
"isOn": node.IsOn,
|
||||
"records": recordMaps,
|
||||
"routes": routeMaps,
|
||||
|
||||
"status": maps.Map{
|
||||
"isActive": status.IsActive,
|
||||
|
||||
@@ -66,44 +66,64 @@ func (this *UpdateAction) RunGet(params struct {
|
||||
}
|
||||
|
||||
// DNS相关
|
||||
dnsInfoResp, err := this.RPC().NodeRPC().FindEnabledNodeDNS(this.AdminContext(), &pb.FindEnabledNodeDNSRequest{NodeId: params.NodeId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
nodeDNS := dnsInfoResp.Node
|
||||
dnsRouteMaps := []maps.Map{}
|
||||
if nodeDNS != nil {
|
||||
for _, dnsInfo := range nodeDNS.Routes {
|
||||
dnsRouteMaps = append(dnsRouteMaps, maps.Map{
|
||||
"name": dnsInfo.Name,
|
||||
"code": dnsInfo.Code,
|
||||
})
|
||||
var clusters = []*pb.NodeCluster{node.NodeCluster}
|
||||
clusters = append(clusters, node.SecondaryNodeClusters...)
|
||||
var allDNSRouteMaps = map[int64][]maps.Map{} // domain id => routes
|
||||
var routeMaps = map[int64][]maps.Map{} // domain id => routes
|
||||
for _, cluster := range clusters {
|
||||
dnsInfoResp, err := this.RPC().NodeRPC().FindEnabledNodeDNS(this.AdminContext(), &pb.FindEnabledNodeDNSRequest{
|
||||
NodeId: params.NodeId,
|
||||
NodeClusterId: cluster.Id,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
this.Data["dnsRoutes"] = dnsRouteMaps
|
||||
this.Data["allDNSRoutes"] = []maps.Map{}
|
||||
if nodeDNS != nil {
|
||||
this.Data["dnsDomainId"] = nodeDNS.DnsDomainId
|
||||
} else {
|
||||
this.Data["dnsDomainId"] = 0
|
||||
}
|
||||
if nodeDNS != nil && nodeDNS.DnsDomainId > 0 {
|
||||
routesMaps := []maps.Map{}
|
||||
var dnsInfo = dnsInfoResp.Node
|
||||
if dnsInfo.DnsDomainId <= 0 || len(dnsInfo.DnsDomainName) == 0 {
|
||||
continue
|
||||
}
|
||||
var domainId = dnsInfo.DnsDomainId
|
||||
var domainName = dnsInfo.DnsDomainName
|
||||
if len(dnsInfo.Routes) > 0 {
|
||||
for _, route := range dnsInfo.Routes {
|
||||
routeMaps[domainId] = append(routeMaps[domainId], maps.Map{
|
||||
"domainId": domainId,
|
||||
"domainName": domainName,
|
||||
"code": route.Code,
|
||||
"name": route.Name,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
// 所有线路选项
|
||||
routesResp, err := this.RPC().DNSDomainRPC().FindAllDNSDomainRoutes(this.AdminContext(), &pb.FindAllDNSDomainRoutesRequest{DnsDomainId: dnsInfoResp.Node.DnsDomainId})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
for _, route := range routesResp.Routes {
|
||||
routesMaps = append(routesMaps, maps.Map{
|
||||
"name": route.Name,
|
||||
"code": route.Code,
|
||||
allDNSRouteMaps[domainId] = append(allDNSRouteMaps[domainId], maps.Map{
|
||||
"domainId": domainId,
|
||||
"domainName": domainName,
|
||||
"name": route.Name,
|
||||
"code": route.Code,
|
||||
})
|
||||
}
|
||||
this.Data["allDNSRoutes"] = routesMaps
|
||||
}
|
||||
|
||||
var domainRoutes = []maps.Map{}
|
||||
for _, m := range routeMaps {
|
||||
domainRoutes = append(domainRoutes, m...)
|
||||
}
|
||||
this.Data["dnsRoutes"] = domainRoutes
|
||||
|
||||
var allDomainRoutes = []maps.Map{}
|
||||
for _, m := range allDNSRouteMaps {
|
||||
allDomainRoutes = append(allDomainRoutes, m...)
|
||||
}
|
||||
this.Data["allDNSRoutes"] = allDomainRoutes
|
||||
|
||||
// 登录信息
|
||||
var loginMap maps.Map = nil
|
||||
if node.Login != nil {
|
||||
@@ -188,7 +208,7 @@ func (this *UpdateAction) RunGet(params struct {
|
||||
}
|
||||
}
|
||||
|
||||
this.Data["node"] = maps.Map{
|
||||
var m = maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
"ipAddresses": ipAddressMaps,
|
||||
@@ -202,23 +222,29 @@ func (this *UpdateAction) RunGet(params struct {
|
||||
"maxCacheMemoryCapacity": maxCacheMemoryCapacity,
|
||||
}
|
||||
|
||||
// 所有集群
|
||||
resp, err := this.RPC().NodeClusterRPC().FindAllEnabledNodeClusters(this.AdminContext(), &pb.FindAllEnabledNodeClustersRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
if node.NodeCluster != nil {
|
||||
m["primaryCluster"] = maps.Map{
|
||||
"id": node.NodeCluster.Id,
|
||||
"name": node.NodeCluster.Name,
|
||||
}
|
||||
} else {
|
||||
m["primaryCluster"] = nil
|
||||
}
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
|
||||
if len(node.SecondaryNodeClusters) > 0 {
|
||||
var secondaryClusterMaps = []maps.Map{}
|
||||
for _, cluster := range node.SecondaryNodeClusters {
|
||||
secondaryClusterMaps = append(secondaryClusterMaps, maps.Map{
|
||||
"id": cluster.Id,
|
||||
"name": cluster.Name,
|
||||
})
|
||||
}
|
||||
m["secondaryClusters"] = secondaryClusterMaps
|
||||
} else {
|
||||
m["secondaryClusters"] = []interface{}{}
|
||||
}
|
||||
clusterMaps := []maps.Map{}
|
||||
for _, cluster := range resp.NodeClusters {
|
||||
clusterMaps = append(clusterMaps, maps.Map{
|
||||
"id": cluster.Id,
|
||||
"name": cluster.Name,
|
||||
})
|
||||
}
|
||||
this.Data["clusters"] = clusterMaps
|
||||
|
||||
this.Data["node"] = m
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -230,7 +256,8 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
RegionId int64
|
||||
Name string
|
||||
IPAddressesJSON []byte `alias:"ipAddressesJSON"`
|
||||
ClusterId int64
|
||||
PrimaryClusterId int64
|
||||
SecondaryClusterIds []byte
|
||||
GrantId int64
|
||||
SshHost string
|
||||
SshPort int
|
||||
@@ -256,8 +283,17 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
Require("请输入节点名称")
|
||||
|
||||
// TODO 检查cluster
|
||||
if params.ClusterId <= 0 {
|
||||
this.Fail("请选择所在集群")
|
||||
if params.PrimaryClusterId <= 0 {
|
||||
this.Fail("请选择节点所在主集群")
|
||||
}
|
||||
|
||||
var secondaryClusterIds = []int64{}
|
||||
if len(params.SecondaryClusterIds) > 0 {
|
||||
err := json.Unmarshal(params.SecondaryClusterIds, &secondaryClusterIds)
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// IP地址
|
||||
@@ -325,18 +361,19 @@ func (this *UpdateAction) RunPost(params struct {
|
||||
|
||||
// 保存
|
||||
_, err := this.RPC().NodeRPC().UpdateNode(this.AdminContext(), &pb.UpdateNodeRequest{
|
||||
NodeId: params.NodeId,
|
||||
NodeGroupId: params.GroupId,
|
||||
NodeRegionId: params.RegionId,
|
||||
Name: params.Name,
|
||||
NodeClusterId: params.ClusterId,
|
||||
NodeLogin: loginInfo,
|
||||
MaxCPU: params.MaxCPU,
|
||||
IsOn: params.IsOn,
|
||||
DnsDomainId: params.DnsDomainId,
|
||||
DnsRoutes: dnsRouteCodes,
|
||||
MaxCacheDiskCapacity: pbMaxCacheDiskCapacity,
|
||||
MaxCacheMemoryCapacity: pbMaxCacheMemoryCapacity,
|
||||
NodeId: params.NodeId,
|
||||
NodeGroupId: params.GroupId,
|
||||
NodeRegionId: params.RegionId,
|
||||
Name: params.Name,
|
||||
NodeClusterId: params.PrimaryClusterId,
|
||||
SecondaryNodeClusterIds: secondaryClusterIds,
|
||||
NodeLogin: loginInfo,
|
||||
MaxCPU: params.MaxCPU,
|
||||
IsOn: params.IsOn,
|
||||
DnsDomainId: params.DnsDomainId,
|
||||
DnsRoutes: dnsRouteCodes,
|
||||
MaxCacheDiskCapacity: pbMaxCacheDiskCapacity,
|
||||
MaxCacheMemoryCapacity: pbMaxCacheMemoryCapacity,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
|
||||
@@ -156,6 +156,16 @@ func (this *NodesAction) RunGet(params struct {
|
||||
dnsRouteNames = append(dnsRouteNames, route.Name)
|
||||
}
|
||||
|
||||
// 从集群
|
||||
var secondaryClusterMaps []maps.Map
|
||||
for _, secondaryCluster := range node.SecondaryNodeClusters {
|
||||
secondaryClusterMaps = append(secondaryClusterMaps, maps.Map{
|
||||
"id": secondaryCluster.Id,
|
||||
"name": secondaryCluster.Name,
|
||||
"isOn": secondaryCluster.IsOn,
|
||||
})
|
||||
}
|
||||
|
||||
nodeMaps = append(nodeMaps, maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
@@ -183,11 +193,12 @@ func (this *NodesAction) RunGet(params struct {
|
||||
"id": node.NodeCluster.Id,
|
||||
"name": node.NodeCluster.Name,
|
||||
},
|
||||
"isSynced": isSynced,
|
||||
"ipAddresses": ipAddresses,
|
||||
"group": groupMap,
|
||||
"region": regionMap,
|
||||
"dnsRouteNames": dnsRouteNames,
|
||||
"secondaryClusters": secondaryClusterMaps,
|
||||
"isSynced": isSynced,
|
||||
"ipAddresses": ipAddresses,
|
||||
"group": groupMap,
|
||||
"region": regionMap,
|
||||
"dnsRouteNames": dnsRouteNames,
|
||||
})
|
||||
}
|
||||
this.Data["nodes"] = nodeMaps
|
||||
|
||||
@@ -63,6 +63,14 @@ func (this *IndexAction) RunPost(params struct {
|
||||
// 创建日志
|
||||
defer this.CreateLog(oplogs.LevelInfo, "修改集群 %d DNS设置", params.ClusterId)
|
||||
|
||||
if params.DnsDomainId <= 0 {
|
||||
this.Fail("请选择集群的主域名")
|
||||
}
|
||||
|
||||
params.Must.
|
||||
Field("dnsName", params.DnsName).
|
||||
Require("请输入DNS子域名")
|
||||
|
||||
// 检查DNS名称
|
||||
if len(params.DnsName) > 0 {
|
||||
if !domainutils.ValidateDomainFormat(params.DnsName) {
|
||||
|
||||
@@ -235,6 +235,16 @@ func (this *IndexAction) searchNodes(keyword string) {
|
||||
dnsRouteNames = append(dnsRouteNames, route.Name)
|
||||
}
|
||||
|
||||
// 从集群
|
||||
var secondaryClusterMaps []maps.Map
|
||||
for _, secondaryCluster := range node.SecondaryNodeClusters {
|
||||
secondaryClusterMaps = append(secondaryClusterMaps, maps.Map{
|
||||
"id": secondaryCluster.Id,
|
||||
"name": secondaryCluster.Name,
|
||||
"isOn": secondaryCluster.IsOn,
|
||||
})
|
||||
}
|
||||
|
||||
nodeMaps = append(nodeMaps, maps.Map{
|
||||
"id": node.Id,
|
||||
"name": node.Name,
|
||||
@@ -260,11 +270,12 @@ func (this *IndexAction) searchNodes(keyword string) {
|
||||
"id": node.NodeCluster.Id,
|
||||
"name": node.NodeCluster.Name,
|
||||
},
|
||||
"isSynced": isSynced,
|
||||
"ipAddresses": ipAddresses,
|
||||
"group": groupMap,
|
||||
"region": regionMap,
|
||||
"dnsRouteNames": dnsRouteNames,
|
||||
"secondaryClusters": secondaryClusterMaps,
|
||||
"isSynced": isSynced,
|
||||
"ipAddresses": ipAddresses,
|
||||
"group": groupMap,
|
||||
"region": regionMap,
|
||||
"dnsRouteNames": dnsRouteNames,
|
||||
})
|
||||
}
|
||||
this.Data["nodes"] = nodeMaps
|
||||
|
||||
@@ -20,6 +20,7 @@ func init() {
|
||||
EndHelpers().
|
||||
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeCommon)).
|
||||
Post("/options", new(OptionsAction)).
|
||||
GetPost("/selectPopup", new(SelectPopupAction)).
|
||||
|
||||
EndAll()
|
||||
})
|
||||
|
||||
64
internal/web/actions/default/clusters/selectPopup.go
Normal file
64
internal/web/actions/default/clusters/selectPopup.go
Normal file
@@ -0,0 +1,64 @@
|
||||
// Copyright 2021 Liuxiangchao iwind.liu@gmail.com. All rights reserved.
|
||||
|
||||
package clusters
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/lists"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
)
|
||||
|
||||
type SelectPopupAction struct {
|
||||
actionutils.ParentAction
|
||||
}
|
||||
|
||||
func (this *SelectPopupAction) Init() {
|
||||
this.Nav("", "", "")
|
||||
}
|
||||
|
||||
func (this *SelectPopupAction) RunGet(params struct {
|
||||
SelectedClusterIds string
|
||||
}) {
|
||||
var selectedIds = utils.SplitNumbers(params.SelectedClusterIds)
|
||||
|
||||
countResp, err := this.RPC().NodeClusterRPC().CountAllEnabledNodeClusters(this.AdminContext(), &pb.CountAllEnabledNodeClustersRequest{})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var count = countResp.Count
|
||||
var page = this.NewPage(count)
|
||||
this.Data["page"] = page.AsHTML()
|
||||
|
||||
clustersResp, err := this.RPC().NodeClusterRPC().ListEnabledNodeClusters(this.AdminContext(), &pb.ListEnabledNodeClustersRequest{
|
||||
Offset: page.Offset,
|
||||
Size: page.Size,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var clusterMaps = []maps.Map{}
|
||||
for _, cluster := range clustersResp.NodeClusters {
|
||||
// 节点数
|
||||
countNodesResp, err := this.RPC().NodeRPC().CountAllEnabledNodesMatch(this.AdminContext(), &pb.CountAllEnabledNodesMatchRequest{NodeClusterId: cluster.Id})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
var countNodes = countNodesResp.Count
|
||||
|
||||
clusterMaps = append(clusterMaps, maps.Map{
|
||||
"id": cluster.Id,
|
||||
"name": cluster.Name,
|
||||
"isOn": cluster.IsOn,
|
||||
"countNodes": countNodes,
|
||||
"isSelected": lists.ContainsInt64(selectedIds, cluster.Id),
|
||||
})
|
||||
}
|
||||
this.Data["clusters"] = clusterMaps
|
||||
|
||||
this.Show()
|
||||
}
|
||||
@@ -43,16 +43,21 @@ func (this *ClustersPopupAction) RunGet(params struct {
|
||||
for _, cluster := range clustersResp.NodeClusters {
|
||||
isOk := false
|
||||
if len(cluster.Name) > 0 {
|
||||
checkResp, err := this.RPC().DNSDomainRPC().ExistDNSDomainRecord(this.AdminContext(), &pb.ExistDNSDomainRecordRequest{
|
||||
DnsDomainId: params.DomainId,
|
||||
Name: cluster.DnsName,
|
||||
Type: "A",
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
for _, recordType := range []string{"A", "AAAA"} {
|
||||
checkResp, err := this.RPC().DNSDomainRPC().ExistDNSDomainRecord(this.AdminContext(), &pb.ExistDNSDomainRecordRequest{
|
||||
DnsDomainId: params.DomainId,
|
||||
Name: cluster.DnsName,
|
||||
Type: recordType,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
}
|
||||
if checkResp.IsOk {
|
||||
isOk = true
|
||||
break
|
||||
}
|
||||
}
|
||||
isOk = checkResp.IsOk
|
||||
}
|
||||
|
||||
clusterMaps = append(clusterMaps, maps.Map{
|
||||
|
||||
@@ -33,12 +33,17 @@ func ValidateDomainFormat(domain string) bool {
|
||||
}
|
||||
|
||||
// ConvertRoutesToMaps 转换线路列表
|
||||
func ConvertRoutesToMaps(routes []*pb.DNSRoute) []maps.Map {
|
||||
func ConvertRoutesToMaps(info *pb.NodeDNSInfo) []maps.Map {
|
||||
if info == nil {
|
||||
return []maps.Map{}
|
||||
}
|
||||
result := []maps.Map{}
|
||||
for _, route := range routes {
|
||||
for _, route := range info.Routes {
|
||||
result = append(result, maps.Map{
|
||||
"name": route.Name,
|
||||
"code": route.Code,
|
||||
"name": route.Name,
|
||||
"code": route.Code,
|
||||
"domainId": info.DnsDomainId,
|
||||
"domainName": info.DnsDomainName,
|
||||
})
|
||||
}
|
||||
return result
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package domains
|
||||
|
||||
import (
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||
"github.com/iwind/TeaGo/maps"
|
||||
@@ -55,10 +56,14 @@ func (this *NodesPopupAction) RunGet(params struct {
|
||||
// 检查是否有域名解析记录
|
||||
isOk := false
|
||||
if len(route.Name) > 0 && len(node.IpAddr) > 0 && len(cluster.DnsName) > 0 {
|
||||
var recordType = "A"
|
||||
if utils.IsIPv6(node.IpAddr) {
|
||||
recordType = "AAAA"
|
||||
}
|
||||
checkResp, err := this.RPC().DNSDomainRPC().ExistDNSDomainRecord(this.AdminContext(), &pb.ExistDNSDomainRecordRequest{
|
||||
DnsDomainId: params.DomainId,
|
||||
Name: cluster.DnsName,
|
||||
Type: "A",
|
||||
Type: recordType,
|
||||
Route: route.Code,
|
||||
Value: node.IpAddr,
|
||||
})
|
||||
|
||||
@@ -20,11 +20,15 @@ func (this *UpdateNodePopupAction) Init() {
|
||||
}
|
||||
|
||||
func (this *UpdateNodePopupAction) RunGet(params struct {
|
||||
NodeId int64
|
||||
ClusterId int64
|
||||
NodeId int64
|
||||
}) {
|
||||
this.Data["nodeId"] = params.NodeId
|
||||
|
||||
dnsInfoResp, err := this.RPC().NodeRPC().FindEnabledNodeDNS(this.AdminContext(), &pb.FindEnabledNodeDNSRequest{NodeId: params.NodeId})
|
||||
dnsInfoResp, err := this.RPC().NodeRPC().FindEnabledNodeDNS(this.AdminContext(), &pb.FindEnabledNodeDNSRequest{
|
||||
NodeId: params.NodeId,
|
||||
NodeClusterId: params.ClusterId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
@@ -35,7 +39,7 @@ func (this *UpdateNodePopupAction) RunGet(params struct {
|
||||
return
|
||||
}
|
||||
this.Data["ipAddr"] = dnsInfo.IpAddr
|
||||
this.Data["routes"] = domainutils.ConvertRoutesToMaps(dnsInfo.Routes)
|
||||
this.Data["routes"] = domainutils.ConvertRoutesToMaps(dnsInfo)
|
||||
this.Data["domainId"] = dnsInfo.DnsDomainId
|
||||
this.Data["domainName"] = dnsInfo.DnsDomainName
|
||||
|
||||
@@ -50,13 +54,17 @@ func (this *UpdateNodePopupAction) RunGet(params struct {
|
||||
if len(routesResp.Routes) > 0 {
|
||||
for _, route := range routesResp.Routes {
|
||||
allRouteMaps = append(allRouteMaps, maps.Map{
|
||||
"name": route.Name,
|
||||
"code": route.Code,
|
||||
"name": route.Name,
|
||||
"code": route.Code,
|
||||
"domainName": dnsInfo.DnsDomainName,
|
||||
"domainId": dnsInfo.DnsDomainId,
|
||||
})
|
||||
}
|
||||
|
||||
// 筛选
|
||||
this.Data["routes"] = domainutils.ConvertRoutesToMaps(domainutils.FilterRoutes(dnsInfo.Routes, routesResp.Routes))
|
||||
var routes = domainutils.FilterRoutes(dnsInfo.Routes, routesResp.Routes)
|
||||
dnsInfo.Routes = routes
|
||||
this.Data["routes"] = domainutils.ConvertRoutesToMaps(dnsInfo)
|
||||
}
|
||||
}
|
||||
this.Data["allRoutes"] = allRouteMaps
|
||||
|
||||
@@ -10,12 +10,16 @@ type DeleteAction struct {
|
||||
}
|
||||
|
||||
func (this *DeleteAction) RunPost(params struct {
|
||||
NodeId int64
|
||||
ClusterId int64
|
||||
NodeId int64
|
||||
}) {
|
||||
// 创建日志
|
||||
defer this.CreateLogInfo("删除节点", params.NodeId)
|
||||
defer this.CreateLogInfo("从集群 %d 中删除节点 %d", params.ClusterId, params.NodeId)
|
||||
|
||||
_, err := this.RPC().NodeRPC().DeleteNode(this.AdminContext(), &pb.DeleteNodeRequest{NodeId: params.NodeId})
|
||||
_, err := this.RPC().NodeRPC().DeleteNodeFromNodeCluster(this.AdminContext(), &pb.DeleteNodeFromNodeClusterRequest{
|
||||
NodeId: params.NodeId,
|
||||
NodeClusterId: params.ClusterId,
|
||||
})
|
||||
if err != nil {
|
||||
this.ErrorPage(err)
|
||||
return
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
// 单个集群选择
|
||||
Vue.component("cluster-selector", {
|
||||
mounted: function () {
|
||||
let that = this
|
||||
|
||||
28
web/public/js/components/cluster/node-clusters-labels.js
Normal file
28
web/public/js/components/cluster/node-clusters-labels.js
Normal file
@@ -0,0 +1,28 @@
|
||||
// 显示节点的多个集群
|
||||
Vue.component("node-clusters-labels", {
|
||||
props: ["v-primary-cluster", "v-secondary-clusters", "size"],
|
||||
data: function () {
|
||||
let cluster = this.vPrimaryCluster
|
||||
let secondaryClusters = this.vSecondaryClusters
|
||||
if (secondaryClusters == null) {
|
||||
secondaryClusters = []
|
||||
}
|
||||
|
||||
let labelSize = this.size
|
||||
if (labelSize == null) {
|
||||
labelSize = "small"
|
||||
}
|
||||
if (labelSize == "tiny") {
|
||||
labelSize += " olive"
|
||||
}
|
||||
return {
|
||||
cluster: cluster,
|
||||
secondaryClusters: secondaryClusters,
|
||||
labelSize: labelSize
|
||||
}
|
||||
},
|
||||
template: `<div>
|
||||
<a v-if="cluster != null" :href="'/clusters/cluster?clusterId=' + cluster.id" class="ui label basic" :class="labelSize" title="主集群" style="margin-bottom: 0.3em;">{{cluster.name}}</a>
|
||||
<a v-for="c in secondaryClusters" :href="'/clusters/cluster?clusterId=' + c.id" class="ui label basic" :class="labelSize" title="从集群" style="margin-bottom: 0.3em;"><span class="grey" style="text-decoration: none">{{c.name}}</span></a>
|
||||
</div>`
|
||||
})
|
||||
98
web/public/js/components/cluster/node-clusters-selector.js
Normal file
98
web/public/js/components/cluster/node-clusters-selector.js
Normal file
@@ -0,0 +1,98 @@
|
||||
// 一个节点的多个集群选择器
|
||||
Vue.component("node-clusters-selector", {
|
||||
props: ["v-primary-cluster", "v-secondary-clusters"],
|
||||
data: function () {
|
||||
let primaryCluster = this.vPrimaryCluster
|
||||
|
||||
let secondaryClusters = this.vSecondaryClusters
|
||||
if (secondaryClusters == null) {
|
||||
secondaryClusters = []
|
||||
}
|
||||
|
||||
return {
|
||||
primaryClusterId: (primaryCluster == null) ? 0 : primaryCluster.id,
|
||||
secondaryClusterIds: secondaryClusters.map(function (v) {
|
||||
return v.id
|
||||
}),
|
||||
|
||||
primaryCluster: primaryCluster,
|
||||
secondaryClusters: secondaryClusters
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
addPrimary: function () {
|
||||
let that = this
|
||||
let selectedClusterIds = [this.primaryClusterId].concat(this.secondaryClusterIds)
|
||||
teaweb.popup("/clusters/selectPopup?selectedClusterIds=" + selectedClusterIds.join(",") + "&mode=single", {
|
||||
height: "38em",
|
||||
width: "50em",
|
||||
callback: function (resp) {
|
||||
if (resp.data.cluster != null) {
|
||||
that.primaryCluster = resp.data.cluster
|
||||
that.primaryClusterId = that.primaryCluster.id
|
||||
that.notifyChange()
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
removePrimary: function () {
|
||||
this.primaryClusterId = 0
|
||||
this.primaryCluster = null
|
||||
this.notifyChange()
|
||||
},
|
||||
addSecondary: function () {
|
||||
let that = this
|
||||
let selectedClusterIds = [this.primaryClusterId].concat(this.secondaryClusterIds)
|
||||
teaweb.popup("/clusters/selectPopup?selectedClusterIds=" + selectedClusterIds.join(",") + "&mode=multiple", {
|
||||
height: "38em",
|
||||
width: "50em",
|
||||
callback: function (resp) {
|
||||
if (resp.data.cluster != null) {
|
||||
that.secondaryClusterIds.push(resp.data.cluster.id)
|
||||
that.secondaryClusters.push(resp.data.cluster)
|
||||
that.notifyChange()
|
||||
}
|
||||
}
|
||||
})
|
||||
},
|
||||
removeSecondary: function (index) {
|
||||
this.secondaryClusterIds.$remove(index)
|
||||
this.secondaryClusters.$remove(index)
|
||||
this.notifyChange()
|
||||
},
|
||||
notifyChange: function () {
|
||||
this.$emit("change", {
|
||||
clusterId: this.primaryClusterId
|
||||
})
|
||||
}
|
||||
},
|
||||
template: `<div>
|
||||
<input type="hidden" name="primaryClusterId" :value="primaryClusterId"/>
|
||||
<input type="hidden" name="secondaryClusterIds" :value="JSON.stringify(secondaryClusterIds)"/>
|
||||
<table class="ui table">
|
||||
<tr>
|
||||
<td class="title">主集群</td>
|
||||
<td>
|
||||
<div v-if="primaryCluster != null">
|
||||
<div class="ui label basic small">{{primaryCluster.name}} <a href="" title="删除" @click.prevent="removePrimary"><i class="icon remove small"></i></a> </div>
|
||||
</div>
|
||||
<div style="margin-top: 0.6em" v-if="primaryClusterId == 0">
|
||||
<button class="ui button tiny" type="button" @click.prevent="addPrimary">+</button>
|
||||
</div>
|
||||
<p class="comment">多个集群配置有冲突时,优先使用主集群配置。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>从集群</td>
|
||||
<td>
|
||||
<div v-if="secondaryClusters.length > 0">
|
||||
<div class="ui label basic small" v-for="(cluster, index) in secondaryClusters"><span class="grey">{{cluster.name}}</span> <a href="" title="删除" @click.prevent="removeSecondary(index)"><i class="icon remove small"></i></a> </div>
|
||||
</div>
|
||||
<div style="margin-top: 0.6em">
|
||||
<button class="ui button tiny" type="button" @click.prevent="addSecondary">+</button>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>`
|
||||
})
|
||||
@@ -8,7 +8,7 @@ Vue.component("dns-route-selector", {
|
||||
return {
|
||||
routes: routes,
|
||||
routeCodes: routes.$map(function (k, v) {
|
||||
return v.code
|
||||
return v.code + "@" + v.domainId
|
||||
}),
|
||||
isAdding: false,
|
||||
routeCode: ""
|
||||
@@ -31,7 +31,7 @@ Vue.component("dns-route-selector", {
|
||||
}
|
||||
let that = this
|
||||
let route = this.vAllRoutes.$find(function (k, v) {
|
||||
return v.code == that.routeCode
|
||||
return v.code + "@" + v.domainId == that.routeCode
|
||||
})
|
||||
if (route == null) {
|
||||
return
|
||||
@@ -53,8 +53,8 @@ Vue.component("dns-route-selector", {
|
||||
template: `<div>
|
||||
<input type="hidden" name="dnsRoutesJSON" :value="JSON.stringify(routeCodes)"/>
|
||||
<div v-if="routes.length > 0">
|
||||
<tiny-basic-label v-for="route in routes" :key="route.code">
|
||||
{{route.name}} <a href="" @click.prevent="remove(route)"><i class="icon remove"></i></a>
|
||||
<tiny-basic-label v-for="route in routes" :key="route.code + '@' + route.domainId">
|
||||
{{route.name}} <span class="grey small">({{route.domainName}})</span><a href="" @click.prevent="remove(route)"><i class="icon remove"></i></a>
|
||||
</tiny-basic-label>
|
||||
<div class="ui divider"></div>
|
||||
</div>
|
||||
@@ -64,7 +64,7 @@ Vue.component("dns-route-selector", {
|
||||
<div class="ui field">
|
||||
<select class="ui dropdown auto-width" v-model="routeCode">
|
||||
<option value="">[请选择]</option>
|
||||
<option v-for="route in vAllRoutes" :value="route.code">{{route.name}}</option>
|
||||
<option v-for="route in vAllRoutes" :value="route.code + '@' + route.domainId">{{route.name}}({{route.domainName}})</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="ui field">
|
||||
|
||||
@@ -317,6 +317,27 @@ window.teaweb = {
|
||||
|
||||
Swal.fire(config);
|
||||
},
|
||||
toast: function (message, timeout, callback) {
|
||||
if (timeout == null) {
|
||||
timeout = 2000
|
||||
}
|
||||
var width = "20em";
|
||||
if (message.length > 30) {
|
||||
width = "30em";
|
||||
}
|
||||
Swal.fire({
|
||||
text: message,
|
||||
icon: "info",
|
||||
width: width,
|
||||
timer: timeout,
|
||||
showConfirmButton: false,
|
||||
onAfterClose: function () {
|
||||
if (typeof callback == "function") {
|
||||
callback()
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
successToast: function (message, timeout, callback) {
|
||||
if (timeout == null) {
|
||||
timeout = 2000
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -440,6 +440,7 @@ body.expanded .main {
|
||||
|
||||
.main-menu.theme1 {
|
||||
background: #14539A !important;
|
||||
|
||||
.menu {
|
||||
background: #14539A !important;
|
||||
}
|
||||
@@ -447,6 +448,7 @@ body.expanded .main {
|
||||
|
||||
.main-menu.theme2 {
|
||||
background: #276AC6 !important;
|
||||
|
||||
.menu {
|
||||
background: #276AC6 !important;
|
||||
}
|
||||
@@ -454,6 +456,7 @@ body.expanded .main {
|
||||
|
||||
.main-menu.theme3 {
|
||||
background: #007D9C !important;
|
||||
|
||||
.menu {
|
||||
background: #007D9C !important;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<second-menu>
|
||||
<menu-item :href="'/clusters/cluster/nodes?clusterId=' + clusterId">节点列表</menu-item>
|
||||
<menu-item :href="'/clusters/cluster/nodes?clusterId=' + clusterId">节点列表</menu-item>
|
||||
<span class="item disabled">|</span>
|
||||
<menu-item :href="'/clusters/cluster/node?clusterId=' + clusterId + '&nodeId=' + node.id" code="node"
|
||||
v-if="!teaIsPlus">"{{node.name}}"节点详情</menu-item>
|
||||
@@ -7,6 +7,6 @@
|
||||
<menu-item :href="'/clusters/cluster/node/detail?clusterId=' + clusterId + '&nodeId=' + node.id" code="node" v-if="teaIsPlus">节点详情</menu-item>
|
||||
<menu-item :href="'/clusters/cluster/node/thresholds?clusterId=' + clusterId + '&nodeId=' + node.id" code="threshold" v-if="teaIsPlus">阈值设置</menu-item>
|
||||
<menu-item :href="'/clusters/cluster/node/logs?clusterId=' + clusterId + '&nodeId=' + node.id" code="log">运行日志</menu-item>
|
||||
<menu-item :href="'/clusters/cluster/node/install?clusterId=' + clusterId + '&nodeId=' + node.id" code="install">安装节点</menu-item>
|
||||
<menu-item :href="'/clusters/cluster/node/update?clusterId=' + clusterId + '&nodeId=' + node.id" code="update">修改设置</menu-item>
|
||||
<menu-item :href="'/clusters/cluster/node/install?clusterId=' + clusterId + '&nodeId=' + node.id" code="install">安装节点</menu-item>
|
||||
</second-menu>
|
||||
@@ -12,6 +12,12 @@
|
||||
<td>状态</td>
|
||||
<td><label-on :v-is-on="node.isOn"></label-on></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>所属集群</td>
|
||||
<td>
|
||||
<node-clusters-labels :v-primary-cluster="node.cluster" :v-secondary-clusters="node.secondaryClusters"></node-clusters-labels>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>IP地址</td>
|
||||
<td>
|
||||
@@ -29,38 +35,34 @@
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="dnsRoutes.length > 0 && dnsRoutes[0].name.length > 0">
|
||||
<tr v-if="node.routes.length > 0">
|
||||
<td>DNS线路</td>
|
||||
<td>
|
||||
<span class="ui label tiny basic" v-for="route in dnsRoutes">{{route.name}}</span>
|
||||
<span class="ui label tiny basic" v-for="route in node.routes">{{route.name}} <span class="grey small">({{route.domainName}})</span></span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="dnsRecordName.length > 0 && dnsRecordValue.length > 0">
|
||||
<tr v-if="node.records.length > 0">
|
||||
<td>DNS记录</td>
|
||||
<td>
|
||||
<table class="ui table celled">
|
||||
<thead class="full-width">
|
||||
<tr>
|
||||
<th>记录名</th>
|
||||
<th>记录类型</th>
|
||||
<th>线路</th>
|
||||
<th>记录值</th>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>记录名</th>
|
||||
<th>记录类型</th>
|
||||
<th>线路</th>
|
||||
<th>记录值</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody v-for="address in node.ipAddresses" v-if="address.canAccess">
|
||||
<tr v-for="route in dnsRoutes">
|
||||
<td>{{dnsRecordName}}</td>
|
||||
<td>
|
||||
<span v-if="address.ip.indexOf(':') > -1">AAAA</span>
|
||||
<span v-else>A</span>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="route.name.length > 0">{{route.name}}</span>
|
||||
<span v-else class="disabled">默认</span>
|
||||
</td>
|
||||
<td>{{address.ip}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
|
||||
<tr v-for="record in node.records">
|
||||
<td>{{record.name}}</td>
|
||||
<td>{{record.type}}</td>
|
||||
<td>
|
||||
<span v-if="record.route.length > 0">{{record.route}}</span>
|
||||
<span v-else class="disabled">默认</span>
|
||||
</td>
|
||||
<td>{{record.value}}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p class="comment">通过设置A记录可以将集群上的服务请求转发到不同线路的节点上。</p>
|
||||
</td>
|
||||
|
||||
@@ -13,6 +13,12 @@
|
||||
<input type="text" name="name" maxlength="50" ref="focus" v-model="node.name"/>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>所属集群</td>
|
||||
<td>
|
||||
<node-clusters-selector :v-primary-cluster="node.primaryCluster" :v-secondary-clusters="node.secondaryClusters" @change="changeClusters"></node-clusters-selector>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>IP地址 *</td>
|
||||
<td>
|
||||
@@ -20,22 +26,13 @@
|
||||
<p class="comment">用于访问节点和域名解析等。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr v-if="allDNSRoutes.length > 0">
|
||||
<tr v-if="allDNSRoutes.length > 0">
|
||||
<td>DNS线路</td>
|
||||
<td>
|
||||
<input type="hidden" name="dnsDomainId" :value="dnsDomainId"/>
|
||||
<dns-route-selector :v-all-routes="allDNSRoutes" :v-routes="dnsRoutes"></dns-route-selector>
|
||||
<p class="comment">当前节点对应的DNS线路,可用线路是根据集群设置的域名获取的,注意DNS服务商可能对这些线路有其他限制。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>所属集群</td>
|
||||
<td>
|
||||
<select class="ui dropdown" name="clusterId" style="width:10em" v-model="clusterId">
|
||||
<option v-for="cluster in clusters" :value="cluster.id">{{cluster.name}}</option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>所属区域</td>
|
||||
<td>
|
||||
|
||||
@@ -1,27 +1,32 @@
|
||||
Tea.context(function () {
|
||||
this.clusterId = 0;
|
||||
this.clusterId = 0
|
||||
if (this.node.cluster != null && this.node.cluster.id > 0) {
|
||||
this.clusterId = this.node.cluster.id;
|
||||
this.clusterId = this.node.cluster.id
|
||||
}
|
||||
|
||||
this.success = NotifySuccess("保存成功", "/clusters/cluster/node?clusterId=" + this.clusterId + "&nodeId=" + this.node.id);
|
||||
this.success = function () {
|
||||
let that = this
|
||||
teaweb.success("保存成功", function () {
|
||||
window.location = "/clusters/cluster/node/detail?clusterId=" + that.clusterId + "&nodeId=" + that.node.id
|
||||
})
|
||||
}
|
||||
|
||||
// IP地址相关
|
||||
this.ipAddresses = this.node.ipAddresses;
|
||||
this.ipAddresses = this.node.ipAddresses
|
||||
|
||||
// 认证相关
|
||||
this.grant = null;
|
||||
this.grant = null
|
||||
|
||||
this.sshHost = "";
|
||||
this.sshPort = "";
|
||||
this.loginId = 0;
|
||||
this.sshHost = ""
|
||||
this.sshPort = ""
|
||||
this.loginId = 0
|
||||
if (this.node.login != null) {
|
||||
this.loginId = this.node.login.id;
|
||||
this.loginId = this.node.login.id
|
||||
|
||||
if (this.node.login.params != null) {
|
||||
this.sshHost = this.node.login.params.host;
|
||||
this.sshHost = this.node.login.params.host
|
||||
if (this.node.login.params.port > 0) {
|
||||
this.sshPort = this.node.login.params.port;
|
||||
this.sshPort = this.node.login.params.port
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,7 +36,11 @@ Tea.context(function () {
|
||||
name: this.node.login.grant.name,
|
||||
method: this.node.login.grant.method,
|
||||
methodName: this.node.login.grant.methodName
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.changeClusters = function (info) {
|
||||
this.clusterId = info.clusterId
|
||||
}
|
||||
})
|
||||
@@ -68,10 +68,13 @@
|
||||
<tr v-for="node in nodes">
|
||||
<td>{{node.name}}
|
||||
<div style="margin-top: 0.5em" v-if="node.region != null">
|
||||
<tiny-basic-label>区域:{{node.region.name}}</tiny-basic-label>
|
||||
<tiny-basic-label class="olive">区域:{{node.region.name}}</tiny-basic-label>
|
||||
</div>
|
||||
<div style="margin-top: 0.5em" v-if="node.group != null">
|
||||
<tiny-basic-label>分组:{{node.group.name}}</tiny-basic-label>
|
||||
<tiny-basic-label class="olive">分组:{{node.group.name}}</tiny-basic-label>
|
||||
</div>
|
||||
<div style="margin-top: 0.5em">
|
||||
<node-clusters-labels :v-primary-cluster="node.cluster" :v-secondary-clusters="node.secondaryClusters" size="tiny"></node-clusters-labels>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
@@ -2,9 +2,10 @@ Tea.context(function () {
|
||||
this.teaweb = teaweb
|
||||
|
||||
this.deleteNode = function (nodeId) {
|
||||
teaweb.confirm("确定要删除这个节点吗?", function () {
|
||||
teaweb.confirm("确定要从当前集群中删除这个节点吗?", function () {
|
||||
this.$post("/nodes/delete")
|
||||
.params({
|
||||
clusterId: this.clusterId,
|
||||
nodeId: nodeId
|
||||
})
|
||||
.refresh();
|
||||
|
||||
@@ -9,14 +9,14 @@
|
||||
|
||||
<table class="ui table selectable definition">
|
||||
<tr v-if="hasDomains">
|
||||
<td>选择主域名</td>
|
||||
<td>选择主域名 *</td>
|
||||
<td>
|
||||
<dns-domain-selector :v-domain-id="domainId" :v-domain-name="domainName"></dns-domain-selector>
|
||||
<p class="comment">用于生成集群节点和网站服务的DNS解析记录。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="title">DNS子域名</td>
|
||||
<td class="title">DNS子域名 *</td>
|
||||
<td>
|
||||
<div class="ui input right labeled">
|
||||
<input type="text" name="dnsName" maxlength="64" style="width:10em" v-model="dnsName"/>
|
||||
|
||||
4
web/views/@default/clusters/create.css
Normal file
4
web/views/@default/clusters/create.css
Normal file
@@ -0,0 +1,4 @@
|
||||
h4 span {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
/*# sourceMappingURL=create.css.map */
|
||||
1
web/views/@default/clusters/create.css.map
Normal file
1
web/views/@default/clusters/create.css.map
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"sources":["create.less"],"names":[],"mappings":"AAAA,EAAG;EACF,gBAAA","file":"create.css"}
|
||||
@@ -13,17 +13,19 @@
|
||||
<td>默认缓存设置 *</td>
|
||||
<td>
|
||||
<http-cache-policy-selector></http-cache-policy-selector>
|
||||
<p class="comment">此全局设置不会强制应用到每个网站服务。</p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>默认WAF设置 *</td>
|
||||
<td>
|
||||
<http-firewall-policy-selector></http-firewall-policy-selector>
|
||||
<p class="comment">此全局设置不会强制应用到每个网站服务。</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h4>节点安装选项</h4>
|
||||
<h4>节点安装选项 <span class="grey small">(可选)</span></h4>
|
||||
<table class="ui table selectable definition">
|
||||
<tr>
|
||||
<td class="title">默认SSH登录方式</td>
|
||||
@@ -49,7 +51,7 @@
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h4>DNS设置选项</h4>
|
||||
<h4>DNS设置选项 <span class="grey small">(可选)</span></h4>
|
||||
<table class="ui table selectable definition">
|
||||
<tr v-if="hasDomains">
|
||||
<td>选择主域名</td>
|
||||
|
||||
3
web/views/@default/clusters/create.less
Normal file
3
web/views/@default/clusters/create.less
Normal file
@@ -0,0 +1,3 @@
|
||||
h4 span {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
@@ -93,7 +93,7 @@
|
||||
<tr v-for="node in nodes">
|
||||
<td><keyword :v-word="keyword">{{node.name}}</keyword>
|
||||
<div style="margin-top: 0.5em">
|
||||
<span class="ui label tiny">集群:{{node.cluster.name}}</span>
|
||||
<node-clusters-labels :v-primary-cluster="node.cluster" :v-secondary-clusters="node.secondaryClusters" size="tiny"></node-clusters-labels>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
25
web/views/@default/clusters/selectPopup.html
Normal file
25
web/views/@default/clusters/selectPopup.html
Normal file
@@ -0,0 +1,25 @@
|
||||
{$layout "layout_popup"}
|
||||
|
||||
<h3>选择集群</h3>
|
||||
|
||||
<table class="ui table celled selectable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>集群名称</th>
|
||||
<th>节点数</th>
|
||||
<th class="two wide">状态</th>
|
||||
<th class="two op">操作</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tr v-for="cluster in clusters">
|
||||
<td>{{cluster.name}}</td>
|
||||
<td>{{cluster.countNodes}}</td>
|
||||
<td><label-on :v-is-on="cluster.isOn"></label-on></td>
|
||||
<td>
|
||||
<span class="disabled" v-if="cluster.isSelected">已选择</span>
|
||||
<a href="" @click.prevent="select(cluster)" v-if="!cluster.isSelected">选择</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<div v-html="page"></div>
|
||||
11
web/views/@default/clusters/selectPopup.js
Normal file
11
web/views/@default/clusters/selectPopup.js
Normal file
@@ -0,0 +1,11 @@
|
||||
Tea.context(function () {
|
||||
this.select = function (cluster) {
|
||||
NotifyPopup({
|
||||
code: 200,
|
||||
message: "",
|
||||
data: {
|
||||
cluster: cluster
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
@@ -71,7 +71,7 @@
|
||||
<link-red @click.prevent="updateCluster(issue.targetId)">修复</link-red>
|
||||
</div>
|
||||
<div v-if="issue.type == 'node'">
|
||||
<link-red @click.prevent="updateNode(issue.targetId)">修复</link-red>
|
||||
<link-red @click.prevent="updateNode(issue.params.clusterId, issue.targetId)">修复</link-red>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -108,18 +108,18 @@
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="node.ipAddr.length > 0">{{node.ipAddr}}</span>
|
||||
<link-red title="点击设置" v-else @click.prevent="updateNode(node.id)">没有设置</link-red>
|
||||
<link-red title="点击设置" v-else @click.prevent="updateNode(node.clusterId, node.id)">没有设置</link-red>
|
||||
</td>
|
||||
<td>
|
||||
<span v-if="node.route.code.length > 0">{{node.route.name}}</span>
|
||||
<link-red v-else title="点击设置" @click.prevent="updateNode(node.id)">没有设置</link-red>
|
||||
<link-red v-else title="点击设置" @click.prevent="updateNode(node.clusterId, node.id)">没有设置</link-red>
|
||||
</td>
|
||||
<td>
|
||||
<span class="green" v-if="node.isResolved">已解析</span>
|
||||
<span v-else class="red">未解析</span>
|
||||
</td>
|
||||
<td>
|
||||
<link-popup @click.prevent="updateNode(node.id)">修改</link-popup>
|
||||
<link-popup @click.prevent="updateNode(node.clusterId, node.id)">修改</link-popup>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
@@ -10,8 +10,8 @@ Tea.context(function () {
|
||||
})
|
||||
}
|
||||
|
||||
this.updateNode = function (nodeId) {
|
||||
teaweb.popup("/dns/issues/updateNodePopup?nodeId=" + nodeId, {
|
||||
this.updateNode = function (clusterId, nodeId) {
|
||||
teaweb.popup("/dns/issues/updateNodePopup?clusterId=" + clusterId + "&nodeId=" + nodeId, {
|
||||
height: "26em",
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
|
||||
@@ -43,7 +43,7 @@
|
||||
<link-red @click.prevent="updateCluster(issue.targetId)">修复</link-red>
|
||||
</div>
|
||||
<div v-if="issue.type == 'node'">
|
||||
<link-red @click.prevent="updateNode(issue.targetId)">修复</link-red>
|
||||
<link-red @click.prevent="updateNode(issue.params.clusterId, issue.targetId)">修复</link-red>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
@@ -17,9 +17,9 @@ Tea.context(function () {
|
||||
})
|
||||
}
|
||||
|
||||
this.updateNode = function (nodeId) {
|
||||
this.updateNode = function (clusterId, nodeId) {
|
||||
let that = this
|
||||
teaweb.popup("/dns/issues/updateNodePopup?nodeId=" + nodeId, {
|
||||
teaweb.popup("/dns/issues/updateNodePopup?clusterId=" + clusterId + "&nodeId=" + nodeId, {
|
||||
callback: function () {
|
||||
teaweb.success("保存成功", function () {
|
||||
that.reload()
|
||||
|
||||
Reference in New Issue
Block a user