mirror of
https://github.com/TeaOSLab/EdgeAdmin.git
synced 2025-11-12 19:30:26 +08:00
初步实现多集群共享节点
This commit is contained in:
@@ -11,7 +11,7 @@ import (
|
|||||||
"strconv"
|
"strconv"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 创建节点
|
// CreateNodeAction 创建节点
|
||||||
type CreateNodeAction struct {
|
type CreateNodeAction struct {
|
||||||
actionutils.ParentAction
|
actionutils.ParentAction
|
||||||
}
|
}
|
||||||
@@ -57,6 +57,8 @@ func (this *CreateNodeAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
for _, route := range routesResp.Routes {
|
for _, route := range routesResp.Routes {
|
||||||
dnsRouteMaps = append(dnsRouteMaps, maps.Map{
|
dnsRouteMaps = append(dnsRouteMaps, maps.Map{
|
||||||
|
"domainId": domainId,
|
||||||
|
"domainName": clusterDNSResp.Domain.Name,
|
||||||
"name": route.Name,
|
"name": route.Name,
|
||||||
"code": route.Code,
|
"code": route.Code,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package node
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils/numberutils"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils"
|
||||||
@@ -37,6 +38,7 @@ func (this *DetailAction) RunGet(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 主集群
|
||||||
var clusterMap maps.Map = nil
|
var clusterMap maps.Map = nil
|
||||||
if node.NodeCluster != nil {
|
if node.NodeCluster != nil {
|
||||||
clusterId := node.NodeCluster.Id
|
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地址
|
// IP地址
|
||||||
ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledIPAddressesWithNodeIdRequest{
|
ipAddressesResp, err := this.RPC().NodeIPAddressRPC().FindAllEnabledIPAddressesWithNodeId(this.AdminContext(), &pb.FindAllEnabledIPAddressesWithNodeIdRequest{
|
||||||
NodeId: params.NodeId,
|
NodeId: params.NodeId,
|
||||||
@@ -64,6 +76,7 @@ func (this *DetailAction) RunGet(params struct {
|
|||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
var ipAddresses = ipAddressesResp.Addresses
|
||||||
ipAddressMaps := []maps.Map{}
|
ipAddressMaps := []maps.Map{}
|
||||||
for _, addr := range ipAddressesResp.Addresses {
|
for _, addr := range ipAddressesResp.Addresses {
|
||||||
ipAddressMaps = append(ipAddressMaps, maps.Map{
|
ipAddressMaps = append(ipAddressMaps, maps.Map{
|
||||||
@@ -75,33 +88,56 @@ func (this *DetailAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DNS相关
|
// DNS相关
|
||||||
dnsInfoResp, err := this.RPC().NodeRPC().FindEnabledNodeDNS(this.AdminContext(), &pb.FindEnabledNodeDNSRequest{NodeId: params.NodeId})
|
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 {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
dnsRouteMaps := []maps.Map{}
|
var dnsInfo = dnsInfoResp.Node
|
||||||
recordName := ""
|
if len(dnsInfo.DnsDomainName) == 0 || len(dnsInfo.NodeClusterDNSName) == 0 {
|
||||||
recordValue := ""
|
continue
|
||||||
if dnsInfoResp.Node != nil {
|
}
|
||||||
recordName = dnsInfoResp.Node.NodeClusterDNSName + "." + dnsInfoResp.Node.DnsDomainName
|
var domainName = dnsInfo.DnsDomainName
|
||||||
recordValue = dnsInfoResp.Node.IpAddr
|
|
||||||
for _, dnsInfo := range dnsInfoResp.Node.Routes {
|
// 默认线路
|
||||||
dnsRouteMaps = append(dnsRouteMaps, maps.Map{
|
if len(dnsInfo.Routes) == 0 {
|
||||||
"name": dnsInfo.Name,
|
dnsInfo.Routes = append(dnsInfo.Routes, &pb.DNSRoute{})
|
||||||
"code": dnsInfo.Code,
|
} else {
|
||||||
|
for _, route := range dnsInfo.Routes {
|
||||||
|
routeMaps = append(routeMaps, maps.Map{
|
||||||
|
"domainName": domainName,
|
||||||
|
"code": route.Code,
|
||||||
|
"name": route.Name,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if len(dnsRouteMaps) == 0 {
|
|
||||||
dnsRouteMaps = append(dnsRouteMaps, maps.Map{
|
for _, addr := range ipAddresses {
|
||||||
"name": "",
|
if !addr.CanAccess {
|
||||||
"code": "",
|
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,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.Data["dnsRoutes"] = dnsRouteMaps
|
}
|
||||||
this.Data["dnsRecordName"] = recordName
|
}
|
||||||
this.Data["dnsRecordValue"] = recordValue
|
|
||||||
|
|
||||||
// 登录信息
|
// 登录信息
|
||||||
var loginMap maps.Map = nil
|
var loginMap maps.Map = nil
|
||||||
@@ -221,6 +257,7 @@ func (this *DetailAction) RunGet(params struct {
|
|||||||
"name": node.Name,
|
"name": node.Name,
|
||||||
"ipAddresses": ipAddressMaps,
|
"ipAddresses": ipAddressMaps,
|
||||||
"cluster": clusterMap,
|
"cluster": clusterMap,
|
||||||
|
"secondaryClusters": secondaryClustersMaps,
|
||||||
"login": loginMap,
|
"login": loginMap,
|
||||||
"installDir": node.InstallDir,
|
"installDir": node.InstallDir,
|
||||||
"isInstalled": node.IsInstalled,
|
"isInstalled": node.IsInstalled,
|
||||||
@@ -228,6 +265,8 @@ func (this *DetailAction) RunGet(params struct {
|
|||||||
"secret": node.Secret,
|
"secret": node.Secret,
|
||||||
"maxCPU": node.MaxCPU,
|
"maxCPU": node.MaxCPU,
|
||||||
"isOn": node.IsOn,
|
"isOn": node.IsOn,
|
||||||
|
"records": recordMaps,
|
||||||
|
"routes": routeMaps,
|
||||||
|
|
||||||
"status": maps.Map{
|
"status": maps.Map{
|
||||||
"isActive": status.IsActive,
|
"isActive": status.IsActive,
|
||||||
|
|||||||
@@ -66,44 +66,64 @@ func (this *UpdateAction) RunGet(params struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// DNS相关
|
// DNS相关
|
||||||
dnsInfoResp, err := this.RPC().NodeRPC().FindEnabledNodeDNS(this.AdminContext(), &pb.FindEnabledNodeDNSRequest{NodeId: params.NodeId})
|
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 {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
nodeDNS := dnsInfoResp.Node
|
var dnsInfo = dnsInfoResp.Node
|
||||||
dnsRouteMaps := []maps.Map{}
|
if dnsInfo.DnsDomainId <= 0 || len(dnsInfo.DnsDomainName) == 0 {
|
||||||
if nodeDNS != nil {
|
continue
|
||||||
for _, dnsInfo := range nodeDNS.Routes {
|
}
|
||||||
dnsRouteMaps = append(dnsRouteMaps, maps.Map{
|
var domainId = dnsInfo.DnsDomainId
|
||||||
"name": dnsInfo.Name,
|
var domainName = dnsInfo.DnsDomainName
|
||||||
"code": dnsInfo.Code,
|
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,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
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{}
|
|
||||||
routesResp, err := this.RPC().DNSDomainRPC().FindAllDNSDomainRoutes(this.AdminContext(), &pb.FindAllDNSDomainRoutesRequest{DnsDomainId: dnsInfoResp.Node.DnsDomainId})
|
routesResp, err := this.RPC().DNSDomainRPC().FindAllDNSDomainRoutes(this.AdminContext(), &pb.FindAllDNSDomainRoutesRequest{DnsDomainId: dnsInfoResp.Node.DnsDomainId})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
for _, route := range routesResp.Routes {
|
for _, route := range routesResp.Routes {
|
||||||
routesMaps = append(routesMaps, maps.Map{
|
allDNSRouteMaps[domainId] = append(allDNSRouteMaps[domainId], maps.Map{
|
||||||
|
"domainId": domainId,
|
||||||
|
"domainName": domainName,
|
||||||
"name": route.Name,
|
"name": route.Name,
|
||||||
"code": route.Code,
|
"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
|
var loginMap maps.Map = nil
|
||||||
if node.Login != 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,
|
"id": node.Id,
|
||||||
"name": node.Name,
|
"name": node.Name,
|
||||||
"ipAddresses": ipAddressMaps,
|
"ipAddresses": ipAddressMaps,
|
||||||
@@ -202,23 +222,29 @@ func (this *UpdateAction) RunGet(params struct {
|
|||||||
"maxCacheMemoryCapacity": maxCacheMemoryCapacity,
|
"maxCacheMemoryCapacity": maxCacheMemoryCapacity,
|
||||||
}
|
}
|
||||||
|
|
||||||
// 所有集群
|
if node.NodeCluster != nil {
|
||||||
resp, err := this.RPC().NodeClusterRPC().FindAllEnabledNodeClusters(this.AdminContext(), &pb.FindAllEnabledNodeClustersRequest{})
|
m["primaryCluster"] = maps.Map{
|
||||||
if err != nil {
|
"id": node.NodeCluster.Id,
|
||||||
this.ErrorPage(err)
|
"name": node.NodeCluster.Name,
|
||||||
}
|
}
|
||||||
if err != nil {
|
} else {
|
||||||
this.ErrorPage(err)
|
m["primaryCluster"] = nil
|
||||||
return
|
|
||||||
}
|
}
|
||||||
clusterMaps := []maps.Map{}
|
|
||||||
for _, cluster := range resp.NodeClusters {
|
if len(node.SecondaryNodeClusters) > 0 {
|
||||||
clusterMaps = append(clusterMaps, maps.Map{
|
var secondaryClusterMaps = []maps.Map{}
|
||||||
|
for _, cluster := range node.SecondaryNodeClusters {
|
||||||
|
secondaryClusterMaps = append(secondaryClusterMaps, maps.Map{
|
||||||
"id": cluster.Id,
|
"id": cluster.Id,
|
||||||
"name": cluster.Name,
|
"name": cluster.Name,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.Data["clusters"] = clusterMaps
|
m["secondaryClusters"] = secondaryClusterMaps
|
||||||
|
} else {
|
||||||
|
m["secondaryClusters"] = []interface{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.Data["node"] = m
|
||||||
|
|
||||||
this.Show()
|
this.Show()
|
||||||
}
|
}
|
||||||
@@ -230,7 +256,8 @@ func (this *UpdateAction) RunPost(params struct {
|
|||||||
RegionId int64
|
RegionId int64
|
||||||
Name string
|
Name string
|
||||||
IPAddressesJSON []byte `alias:"ipAddressesJSON"`
|
IPAddressesJSON []byte `alias:"ipAddressesJSON"`
|
||||||
ClusterId int64
|
PrimaryClusterId int64
|
||||||
|
SecondaryClusterIds []byte
|
||||||
GrantId int64
|
GrantId int64
|
||||||
SshHost string
|
SshHost string
|
||||||
SshPort int
|
SshPort int
|
||||||
@@ -256,8 +283,17 @@ func (this *UpdateAction) RunPost(params struct {
|
|||||||
Require("请输入节点名称")
|
Require("请输入节点名称")
|
||||||
|
|
||||||
// TODO 检查cluster
|
// TODO 检查cluster
|
||||||
if params.ClusterId <= 0 {
|
if params.PrimaryClusterId <= 0 {
|
||||||
this.Fail("请选择所在集群")
|
this.Fail("请选择节点所在主集群")
|
||||||
|
}
|
||||||
|
|
||||||
|
var secondaryClusterIds = []int64{}
|
||||||
|
if len(params.SecondaryClusterIds) > 0 {
|
||||||
|
err := json.Unmarshal(params.SecondaryClusterIds, &secondaryClusterIds)
|
||||||
|
if err != nil {
|
||||||
|
this.ErrorPage(err)
|
||||||
|
return
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// IP地址
|
// IP地址
|
||||||
@@ -329,7 +365,8 @@ func (this *UpdateAction) RunPost(params struct {
|
|||||||
NodeGroupId: params.GroupId,
|
NodeGroupId: params.GroupId,
|
||||||
NodeRegionId: params.RegionId,
|
NodeRegionId: params.RegionId,
|
||||||
Name: params.Name,
|
Name: params.Name,
|
||||||
NodeClusterId: params.ClusterId,
|
NodeClusterId: params.PrimaryClusterId,
|
||||||
|
SecondaryNodeClusterIds: secondaryClusterIds,
|
||||||
NodeLogin: loginInfo,
|
NodeLogin: loginInfo,
|
||||||
MaxCPU: params.MaxCPU,
|
MaxCPU: params.MaxCPU,
|
||||||
IsOn: params.IsOn,
|
IsOn: params.IsOn,
|
||||||
|
|||||||
@@ -156,6 +156,16 @@ func (this *NodesAction) RunGet(params struct {
|
|||||||
dnsRouteNames = append(dnsRouteNames, route.Name)
|
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{
|
nodeMaps = append(nodeMaps, maps.Map{
|
||||||
"id": node.Id,
|
"id": node.Id,
|
||||||
"name": node.Name,
|
"name": node.Name,
|
||||||
@@ -183,6 +193,7 @@ func (this *NodesAction) RunGet(params struct {
|
|||||||
"id": node.NodeCluster.Id,
|
"id": node.NodeCluster.Id,
|
||||||
"name": node.NodeCluster.Name,
|
"name": node.NodeCluster.Name,
|
||||||
},
|
},
|
||||||
|
"secondaryClusters": secondaryClusterMaps,
|
||||||
"isSynced": isSynced,
|
"isSynced": isSynced,
|
||||||
"ipAddresses": ipAddresses,
|
"ipAddresses": ipAddresses,
|
||||||
"group": groupMap,
|
"group": groupMap,
|
||||||
|
|||||||
@@ -63,6 +63,14 @@ func (this *IndexAction) RunPost(params struct {
|
|||||||
// 创建日志
|
// 创建日志
|
||||||
defer this.CreateLog(oplogs.LevelInfo, "修改集群 %d DNS设置", params.ClusterId)
|
defer this.CreateLog(oplogs.LevelInfo, "修改集群 %d DNS设置", params.ClusterId)
|
||||||
|
|
||||||
|
if params.DnsDomainId <= 0 {
|
||||||
|
this.Fail("请选择集群的主域名")
|
||||||
|
}
|
||||||
|
|
||||||
|
params.Must.
|
||||||
|
Field("dnsName", params.DnsName).
|
||||||
|
Require("请输入DNS子域名")
|
||||||
|
|
||||||
// 检查DNS名称
|
// 检查DNS名称
|
||||||
if len(params.DnsName) > 0 {
|
if len(params.DnsName) > 0 {
|
||||||
if !domainutils.ValidateDomainFormat(params.DnsName) {
|
if !domainutils.ValidateDomainFormat(params.DnsName) {
|
||||||
|
|||||||
@@ -235,6 +235,16 @@ func (this *IndexAction) searchNodes(keyword string) {
|
|||||||
dnsRouteNames = append(dnsRouteNames, route.Name)
|
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{
|
nodeMaps = append(nodeMaps, maps.Map{
|
||||||
"id": node.Id,
|
"id": node.Id,
|
||||||
"name": node.Name,
|
"name": node.Name,
|
||||||
@@ -260,6 +270,7 @@ func (this *IndexAction) searchNodes(keyword string) {
|
|||||||
"id": node.NodeCluster.Id,
|
"id": node.NodeCluster.Id,
|
||||||
"name": node.NodeCluster.Name,
|
"name": node.NodeCluster.Name,
|
||||||
},
|
},
|
||||||
|
"secondaryClusters": secondaryClusterMaps,
|
||||||
"isSynced": isSynced,
|
"isSynced": isSynced,
|
||||||
"ipAddresses": ipAddresses,
|
"ipAddresses": ipAddresses,
|
||||||
"group": groupMap,
|
"group": groupMap,
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ func init() {
|
|||||||
EndHelpers().
|
EndHelpers().
|
||||||
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeCommon)).
|
Helper(helpers.NewUserMustAuth(configloaders.AdminModuleCodeCommon)).
|
||||||
Post("/options", new(OptionsAction)).
|
Post("/options", new(OptionsAction)).
|
||||||
|
GetPost("/selectPopup", new(SelectPopupAction)).
|
||||||
|
|
||||||
EndAll()
|
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 {
|
for _, cluster := range clustersResp.NodeClusters {
|
||||||
isOk := false
|
isOk := false
|
||||||
if len(cluster.Name) > 0 {
|
if len(cluster.Name) > 0 {
|
||||||
|
for _, recordType := range []string{"A", "AAAA"} {
|
||||||
checkResp, err := this.RPC().DNSDomainRPC().ExistDNSDomainRecord(this.AdminContext(), &pb.ExistDNSDomainRecordRequest{
|
checkResp, err := this.RPC().DNSDomainRPC().ExistDNSDomainRecord(this.AdminContext(), &pb.ExistDNSDomainRecordRequest{
|
||||||
DnsDomainId: params.DomainId,
|
DnsDomainId: params.DomainId,
|
||||||
Name: cluster.DnsName,
|
Name: cluster.DnsName,
|
||||||
Type: "A",
|
Type: recordType,
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
isOk = checkResp.IsOk
|
if checkResp.IsOk {
|
||||||
|
isOk = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clusterMaps = append(clusterMaps, maps.Map{
|
clusterMaps = append(clusterMaps, maps.Map{
|
||||||
|
|||||||
@@ -33,12 +33,17 @@ func ValidateDomainFormat(domain string) bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ConvertRoutesToMaps 转换线路列表
|
// ConvertRoutesToMaps 转换线路列表
|
||||||
func ConvertRoutesToMaps(routes []*pb.DNSRoute) []maps.Map {
|
func ConvertRoutesToMaps(info *pb.NodeDNSInfo) []maps.Map {
|
||||||
|
if info == nil {
|
||||||
|
return []maps.Map{}
|
||||||
|
}
|
||||||
result := []maps.Map{}
|
result := []maps.Map{}
|
||||||
for _, route := range routes {
|
for _, route := range info.Routes {
|
||||||
result = append(result, maps.Map{
|
result = append(result, maps.Map{
|
||||||
"name": route.Name,
|
"name": route.Name,
|
||||||
"code": route.Code,
|
"code": route.Code,
|
||||||
|
"domainId": info.DnsDomainId,
|
||||||
|
"domainName": info.DnsDomainName,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package domains
|
package domains
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"github.com/TeaOSLab/EdgeAdmin/internal/utils"
|
||||||
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
"github.com/TeaOSLab/EdgeAdmin/internal/web/actions/actionutils"
|
||||||
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
|
||||||
"github.com/iwind/TeaGo/maps"
|
"github.com/iwind/TeaGo/maps"
|
||||||
@@ -55,10 +56,14 @@ func (this *NodesPopupAction) RunGet(params struct {
|
|||||||
// 检查是否有域名解析记录
|
// 检查是否有域名解析记录
|
||||||
isOk := false
|
isOk := false
|
||||||
if len(route.Name) > 0 && len(node.IpAddr) > 0 && len(cluster.DnsName) > 0 {
|
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{
|
checkResp, err := this.RPC().DNSDomainRPC().ExistDNSDomainRecord(this.AdminContext(), &pb.ExistDNSDomainRecordRequest{
|
||||||
DnsDomainId: params.DomainId,
|
DnsDomainId: params.DomainId,
|
||||||
Name: cluster.DnsName,
|
Name: cluster.DnsName,
|
||||||
Type: "A",
|
Type: recordType,
|
||||||
Route: route.Code,
|
Route: route.Code,
|
||||||
Value: node.IpAddr,
|
Value: node.IpAddr,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -20,11 +20,15 @@ func (this *UpdateNodePopupAction) Init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *UpdateNodePopupAction) RunGet(params struct {
|
func (this *UpdateNodePopupAction) RunGet(params struct {
|
||||||
|
ClusterId int64
|
||||||
NodeId int64
|
NodeId int64
|
||||||
}) {
|
}) {
|
||||||
this.Data["nodeId"] = params.NodeId
|
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 {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
@@ -35,7 +39,7 @@ func (this *UpdateNodePopupAction) RunGet(params struct {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
this.Data["ipAddr"] = dnsInfo.IpAddr
|
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["domainId"] = dnsInfo.DnsDomainId
|
||||||
this.Data["domainName"] = dnsInfo.DnsDomainName
|
this.Data["domainName"] = dnsInfo.DnsDomainName
|
||||||
|
|
||||||
@@ -52,11 +56,15 @@ func (this *UpdateNodePopupAction) RunGet(params struct {
|
|||||||
allRouteMaps = append(allRouteMaps, maps.Map{
|
allRouteMaps = append(allRouteMaps, maps.Map{
|
||||||
"name": route.Name,
|
"name": route.Name,
|
||||||
"code": route.Code,
|
"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
|
this.Data["allRoutes"] = allRouteMaps
|
||||||
|
|||||||
@@ -10,12 +10,16 @@ type DeleteAction struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (this *DeleteAction) RunPost(params struct {
|
func (this *DeleteAction) RunPost(params struct {
|
||||||
|
ClusterId int64
|
||||||
NodeId 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 {
|
if err != nil {
|
||||||
this.ErrorPage(err)
|
this.ErrorPage(err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
// 单个集群选择
|
||||||
Vue.component("cluster-selector", {
|
Vue.component("cluster-selector", {
|
||||||
mounted: function () {
|
mounted: function () {
|
||||||
let that = this
|
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 {
|
return {
|
||||||
routes: routes,
|
routes: routes,
|
||||||
routeCodes: routes.$map(function (k, v) {
|
routeCodes: routes.$map(function (k, v) {
|
||||||
return v.code
|
return v.code + "@" + v.domainId
|
||||||
}),
|
}),
|
||||||
isAdding: false,
|
isAdding: false,
|
||||||
routeCode: ""
|
routeCode: ""
|
||||||
@@ -31,7 +31,7 @@ Vue.component("dns-route-selector", {
|
|||||||
}
|
}
|
||||||
let that = this
|
let that = this
|
||||||
let route = this.vAllRoutes.$find(function (k, v) {
|
let route = this.vAllRoutes.$find(function (k, v) {
|
||||||
return v.code == that.routeCode
|
return v.code + "@" + v.domainId == that.routeCode
|
||||||
})
|
})
|
||||||
if (route == null) {
|
if (route == null) {
|
||||||
return
|
return
|
||||||
@@ -53,8 +53,8 @@ Vue.component("dns-route-selector", {
|
|||||||
template: `<div>
|
template: `<div>
|
||||||
<input type="hidden" name="dnsRoutesJSON" :value="JSON.stringify(routeCodes)"/>
|
<input type="hidden" name="dnsRoutesJSON" :value="JSON.stringify(routeCodes)"/>
|
||||||
<div v-if="routes.length > 0">
|
<div v-if="routes.length > 0">
|
||||||
<tiny-basic-label v-for="route in routes" :key="route.code">
|
<tiny-basic-label v-for="route in routes" :key="route.code + '@' + route.domainId">
|
||||||
{{route.name}} <a href="" @click.prevent="remove(route)"><i class="icon remove"></i></a>
|
{{route.name}} <span class="grey small">({{route.domainName}})</span><a href="" @click.prevent="remove(route)"><i class="icon remove"></i></a>
|
||||||
</tiny-basic-label>
|
</tiny-basic-label>
|
||||||
<div class="ui divider"></div>
|
<div class="ui divider"></div>
|
||||||
</div>
|
</div>
|
||||||
@@ -64,7 +64,7 @@ Vue.component("dns-route-selector", {
|
|||||||
<div class="ui field">
|
<div class="ui field">
|
||||||
<select class="ui dropdown auto-width" v-model="routeCode">
|
<select class="ui dropdown auto-width" v-model="routeCode">
|
||||||
<option value="">[请选择]</option>
|
<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>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
<div class="ui field">
|
<div class="ui field">
|
||||||
|
|||||||
@@ -317,6 +317,27 @@ window.teaweb = {
|
|||||||
|
|
||||||
Swal.fire(config);
|
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) {
|
successToast: function (message, timeout, callback) {
|
||||||
if (timeout == null) {
|
if (timeout == null) {
|
||||||
timeout = 2000
|
timeout = 2000
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -440,6 +440,7 @@ body.expanded .main {
|
|||||||
|
|
||||||
.main-menu.theme1 {
|
.main-menu.theme1 {
|
||||||
background: #14539A !important;
|
background: #14539A !important;
|
||||||
|
|
||||||
.menu {
|
.menu {
|
||||||
background: #14539A !important;
|
background: #14539A !important;
|
||||||
}
|
}
|
||||||
@@ -447,6 +448,7 @@ body.expanded .main {
|
|||||||
|
|
||||||
.main-menu.theme2 {
|
.main-menu.theme2 {
|
||||||
background: #276AC6 !important;
|
background: #276AC6 !important;
|
||||||
|
|
||||||
.menu {
|
.menu {
|
||||||
background: #276AC6 !important;
|
background: #276AC6 !important;
|
||||||
}
|
}
|
||||||
@@ -454,6 +456,7 @@ body.expanded .main {
|
|||||||
|
|
||||||
.main-menu.theme3 {
|
.main-menu.theme3 {
|
||||||
background: #007D9C !important;
|
background: #007D9C !important;
|
||||||
|
|
||||||
.menu {
|
.menu {
|
||||||
background: #007D9C !important;
|
background: #007D9C !important;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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/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/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/logs?clusterId=' + clusterId + '&nodeId=' + node.id" code="log">运行日志</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>
|
<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>
|
||||||
</second-menu>
|
</second-menu>
|
||||||
@@ -12,6 +12,12 @@
|
|||||||
<td>状态</td>
|
<td>状态</td>
|
||||||
<td><label-on :v-is-on="node.isOn"></label-on></td>
|
<td><label-on :v-is-on="node.isOn"></label-on></td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>所属集群</td>
|
||||||
|
<td>
|
||||||
|
<node-clusters-labels :v-primary-cluster="node.cluster" :v-secondary-clusters="node.secondaryClusters"></node-clusters-labels>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>IP地址</td>
|
<td>IP地址</td>
|
||||||
<td>
|
<td>
|
||||||
@@ -29,13 +35,13 @@
|
|||||||
</div>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-if="dnsRoutes.length > 0 && dnsRoutes[0].name.length > 0">
|
<tr v-if="node.routes.length > 0">
|
||||||
<td>DNS线路</td>
|
<td>DNS线路</td>
|
||||||
<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>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr v-if="dnsRecordName.length > 0 && dnsRecordValue.length > 0">
|
<tr v-if="node.records.length > 0">
|
||||||
<td>DNS记录</td>
|
<td>DNS记录</td>
|
||||||
<td>
|
<td>
|
||||||
<table class="ui table celled">
|
<table class="ui table celled">
|
||||||
@@ -47,20 +53,16 @@
|
|||||||
<th>记录值</th>
|
<th>记录值</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody v-for="address in node.ipAddresses" v-if="address.canAccess">
|
|
||||||
<tr v-for="route in dnsRoutes">
|
<tr v-for="record in node.records">
|
||||||
<td>{{dnsRecordName}}</td>
|
<td>{{record.name}}</td>
|
||||||
|
<td>{{record.type}}</td>
|
||||||
<td>
|
<td>
|
||||||
<span v-if="address.ip.indexOf(':') > -1">AAAA</span>
|
<span v-if="record.route.length > 0">{{record.route}}</span>
|
||||||
<span v-else>A</span>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<span v-if="route.name.length > 0">{{route.name}}</span>
|
|
||||||
<span v-else class="disabled">默认</span>
|
<span v-else class="disabled">默认</span>
|
||||||
</td>
|
</td>
|
||||||
<td>{{address.ip}}</td>
|
<td>{{record.value}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
|
||||||
</table>
|
</table>
|
||||||
<p class="comment">通过设置A记录可以将集群上的服务请求转发到不同线路的节点上。</p>
|
<p class="comment">通过设置A记录可以将集群上的服务请求转发到不同线路的节点上。</p>
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
@@ -13,6 +13,12 @@
|
|||||||
<input type="text" name="name" maxlength="50" ref="focus" v-model="node.name"/>
|
<input type="text" name="name" maxlength="50" ref="focus" v-model="node.name"/>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</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>
|
<tr>
|
||||||
<td>IP地址 *</td>
|
<td>IP地址 *</td>
|
||||||
<td>
|
<td>
|
||||||
@@ -23,19 +29,10 @@
|
|||||||
<tr v-if="allDNSRoutes.length > 0">
|
<tr v-if="allDNSRoutes.length > 0">
|
||||||
<td>DNS线路</td>
|
<td>DNS线路</td>
|
||||||
<td>
|
<td>
|
||||||
<input type="hidden" name="dnsDomainId" :value="dnsDomainId"/>
|
|
||||||
<dns-route-selector :v-all-routes="allDNSRoutes" :v-routes="dnsRoutes"></dns-route-selector>
|
<dns-route-selector :v-all-routes="allDNSRoutes" :v-routes="dnsRoutes"></dns-route-selector>
|
||||||
<p class="comment">当前节点对应的DNS线路,可用线路是根据集群设置的域名获取的,注意DNS服务商可能对这些线路有其他限制。</p>
|
<p class="comment">当前节点对应的DNS线路,可用线路是根据集群设置的域名获取的,注意DNS服务商可能对这些线路有其他限制。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</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>
|
<tr>
|
||||||
<td>所属区域</td>
|
<td>所属区域</td>
|
||||||
<td>
|
<td>
|
||||||
|
|||||||
@@ -1,27 +1,32 @@
|
|||||||
Tea.context(function () {
|
Tea.context(function () {
|
||||||
this.clusterId = 0;
|
this.clusterId = 0
|
||||||
if (this.node.cluster != null && this.node.cluster.id > 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地址相关
|
// IP地址相关
|
||||||
this.ipAddresses = this.node.ipAddresses;
|
this.ipAddresses = this.node.ipAddresses
|
||||||
|
|
||||||
// 认证相关
|
// 认证相关
|
||||||
this.grant = null;
|
this.grant = null
|
||||||
|
|
||||||
this.sshHost = "";
|
this.sshHost = ""
|
||||||
this.sshPort = "";
|
this.sshPort = ""
|
||||||
this.loginId = 0;
|
this.loginId = 0
|
||||||
if (this.node.login != null) {
|
if (this.node.login != null) {
|
||||||
this.loginId = this.node.login.id;
|
this.loginId = this.node.login.id
|
||||||
|
|
||||||
if (this.node.login.params != null) {
|
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) {
|
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,
|
name: this.node.login.grant.name,
|
||||||
method: this.node.login.grant.method,
|
method: this.node.login.grant.method,
|
||||||
methodName: this.node.login.grant.methodName
|
methodName: this.node.login.grant.methodName
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
}
|
||||||
|
|
||||||
|
this.changeClusters = function (info) {
|
||||||
|
this.clusterId = info.clusterId
|
||||||
|
}
|
||||||
|
})
|
||||||
@@ -68,10 +68,13 @@
|
|||||||
<tr v-for="node in nodes">
|
<tr v-for="node in nodes">
|
||||||
<td>{{node.name}}
|
<td>{{node.name}}
|
||||||
<div style="margin-top: 0.5em" v-if="node.region != null">
|
<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>
|
||||||
<div style="margin-top: 0.5em" v-if="node.group != null">
|
<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>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
|
|||||||
@@ -2,9 +2,10 @@ Tea.context(function () {
|
|||||||
this.teaweb = teaweb
|
this.teaweb = teaweb
|
||||||
|
|
||||||
this.deleteNode = function (nodeId) {
|
this.deleteNode = function (nodeId) {
|
||||||
teaweb.confirm("确定要删除这个节点吗?", function () {
|
teaweb.confirm("确定要从当前集群中删除这个节点吗?", function () {
|
||||||
this.$post("/nodes/delete")
|
this.$post("/nodes/delete")
|
||||||
.params({
|
.params({
|
||||||
|
clusterId: this.clusterId,
|
||||||
nodeId: nodeId
|
nodeId: nodeId
|
||||||
})
|
})
|
||||||
.refresh();
|
.refresh();
|
||||||
|
|||||||
@@ -9,14 +9,14 @@
|
|||||||
|
|
||||||
<table class="ui table selectable definition">
|
<table class="ui table selectable definition">
|
||||||
<tr v-if="hasDomains">
|
<tr v-if="hasDomains">
|
||||||
<td>选择主域名</td>
|
<td>选择主域名 *</td>
|
||||||
<td>
|
<td>
|
||||||
<dns-domain-selector :v-domain-id="domainId" :v-domain-name="domainName"></dns-domain-selector>
|
<dns-domain-selector :v-domain-id="domainId" :v-domain-name="domainName"></dns-domain-selector>
|
||||||
<p class="comment">用于生成集群节点和网站服务的DNS解析记录。</p>
|
<p class="comment">用于生成集群节点和网站服务的DNS解析记录。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="title">DNS子域名</td>
|
<td class="title">DNS子域名 *</td>
|
||||||
<td>
|
<td>
|
||||||
<div class="ui input right labeled">
|
<div class="ui input right labeled">
|
||||||
<input type="text" name="dnsName" maxlength="64" style="width:10em" v-model="dnsName"/>
|
<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>默认缓存设置 *</td>
|
||||||
<td>
|
<td>
|
||||||
<http-cache-policy-selector></http-cache-policy-selector>
|
<http-cache-policy-selector></http-cache-policy-selector>
|
||||||
|
<p class="comment">此全局设置不会强制应用到每个网站服务。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>默认WAF设置 *</td>
|
<td>默认WAF设置 *</td>
|
||||||
<td>
|
<td>
|
||||||
<http-firewall-policy-selector></http-firewall-policy-selector>
|
<http-firewall-policy-selector></http-firewall-policy-selector>
|
||||||
|
<p class="comment">此全局设置不会强制应用到每个网站服务。</p>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<h4>节点安装选项</h4>
|
<h4>节点安装选项 <span class="grey small">(可选)</span></h4>
|
||||||
<table class="ui table selectable definition">
|
<table class="ui table selectable definition">
|
||||||
<tr>
|
<tr>
|
||||||
<td class="title">默认SSH登录方式</td>
|
<td class="title">默认SSH登录方式</td>
|
||||||
@@ -49,7 +51,7 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<h4>DNS设置选项</h4>
|
<h4>DNS设置选项 <span class="grey small">(可选)</span></h4>
|
||||||
<table class="ui table selectable definition">
|
<table class="ui table selectable definition">
|
||||||
<tr v-if="hasDomains">
|
<tr v-if="hasDomains">
|
||||||
<td>选择主域名</td>
|
<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">
|
<tr v-for="node in nodes">
|
||||||
<td><keyword :v-word="keyword">{{node.name}}</keyword>
|
<td><keyword :v-word="keyword">{{node.name}}</keyword>
|
||||||
<div style="margin-top: 0.5em">
|
<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>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
<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>
|
<link-red @click.prevent="updateCluster(issue.targetId)">修复</link-red>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="issue.type == 'node'">
|
<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>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
@@ -108,18 +108,18 @@
|
|||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<span v-if="node.ipAddr.length > 0">{{node.ipAddr}}</span>
|
<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>
|
||||||
<td>
|
<td>
|
||||||
<span v-if="node.route.code.length > 0">{{node.route.name}}</span>
|
<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>
|
||||||
<td>
|
<td>
|
||||||
<span class="green" v-if="node.isResolved">已解析</span>
|
<span class="green" v-if="node.isResolved">已解析</span>
|
||||||
<span v-else class="red">未解析</span>
|
<span v-else class="red">未解析</span>
|
||||||
</td>
|
</td>
|
||||||
<td>
|
<td>
|
||||||
<link-popup @click.prevent="updateNode(node.id)">修改</link-popup>
|
<link-popup @click.prevent="updateNode(node.clusterId, node.id)">修改</link-popup>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
@@ -10,8 +10,8 @@ Tea.context(function () {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateNode = function (nodeId) {
|
this.updateNode = function (clusterId, nodeId) {
|
||||||
teaweb.popup("/dns/issues/updateNodePopup?nodeId=" + nodeId, {
|
teaweb.popup("/dns/issues/updateNodePopup?clusterId=" + clusterId + "&nodeId=" + nodeId, {
|
||||||
height: "26em",
|
height: "26em",
|
||||||
callback: function () {
|
callback: function () {
|
||||||
teaweb.success("保存成功", function () {
|
teaweb.success("保存成功", function () {
|
||||||
|
|||||||
@@ -43,7 +43,7 @@
|
|||||||
<link-red @click.prevent="updateCluster(issue.targetId)">修复</link-red>
|
<link-red @click.prevent="updateCluster(issue.targetId)">修复</link-red>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="issue.type == 'node'">
|
<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>
|
</div>
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
|||||||
@@ -17,9 +17,9 @@ Tea.context(function () {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
this.updateNode = function (nodeId) {
|
this.updateNode = function (clusterId, nodeId) {
|
||||||
let that = this
|
let that = this
|
||||||
teaweb.popup("/dns/issues/updateNodePopup?nodeId=" + nodeId, {
|
teaweb.popup("/dns/issues/updateNodePopup?clusterId=" + clusterId + "&nodeId=" + nodeId, {
|
||||||
callback: function () {
|
callback: function () {
|
||||||
teaweb.success("保存成功", function () {
|
teaweb.success("保存成功", function () {
|
||||||
that.reload()
|
that.reload()
|
||||||
|
|||||||
Reference in New Issue
Block a user