增加批量增加节点IP接口

This commit is contained in:
GoEdgeLab
2021-12-07 18:22:46 +08:00
parent 55ae78929c
commit 2eca40e040
9 changed files with 280 additions and 58 deletions

View File

@@ -1,14 +1,17 @@
package utils package utils
import ( import (
"bytes"
"encoding/binary" "encoding/binary"
"errors"
"github.com/iwind/TeaGo/types"
"math/big" "math/big"
"net" "net"
"regexp" "regexp"
"strings" "strings"
) )
// 将IP转换为整型 // IP2Long 将IP转换为整型
func IP2Long(ip string) uint64 { func IP2Long(ip string) uint64 {
s := net.ParseIP(ip) s := net.ParseIP(ip)
if len(s) != 16 { if len(s) != 16 {
@@ -23,7 +26,7 @@ func IP2Long(ip string) uint64 {
return uint64(binary.BigEndian.Uint32(s.To4())) return uint64(binary.BigEndian.Uint32(s.To4()))
} }
// 判断是否为IPv4 // IsIPv4 判断是否为IPv4
func IsIPv4(ip string) bool { func IsIPv4(ip string) bool {
if !regexp.MustCompile(`^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$`).MatchString(ip) { if !regexp.MustCompile(`^\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}$`).MatchString(ip) {
return false return false
@@ -34,10 +37,100 @@ func IsIPv4(ip string) bool {
return true return true
} }
// 判断是否为IPv6 // IsIPv6 判断是否为IPv6
func IsIPv6(ip string) bool { func IsIPv6(ip string) bool {
if !strings.Contains(ip, ":") { if !strings.Contains(ip, ":") {
return false return false
} }
return len(net.ParseIP(ip)) == net.IPv6len return len(net.ParseIP(ip)) == net.IPv6len
} }
// ExtractIP 分解IP
// 只支持D段掩码的CIDR
// 最多只记录255个值
func ExtractIP(ipStrings string) ([]string, error) {
ipStrings = strings.ReplaceAll(ipStrings, " ", "")
// CIDR
if strings.Contains(ipStrings, "/") {
_, cidrNet, err := net.ParseCIDR(ipStrings)
if err != nil {
return nil, err
}
var index = strings.Index(ipStrings, "/")
var ipFrom = ipStrings[:index]
var bits = types.Int(ipStrings[index+1:])
if bits < 24 {
return nil, errors.New("CIDR bits should be greater than 24")
}
var ipv4 = net.ParseIP(ipFrom).To4()
if len(ipv4) == 0 {
return nil, errors.New("support IPv4 only")
}
var result = []string{}
ipv4[3] = 0 // 从0开始
for i := 0; i <= 255; i++ {
if cidrNet.Contains(ipv4) {
result = append(result, ipv4.String())
}
ipv4 = NextIP(ipv4)
}
return result, nil
}
// IP Range
if strings.Contains(ipStrings, "-") {
var index = strings.Index(ipStrings, "-")
var ipFromString = ipStrings[:index]
var ipToString = ipStrings[index+1:]
var ipFrom = net.ParseIP(ipFromString).To4()
if len(ipFrom) == 0 {
return nil, errors.New("invalid ip '" + ipFromString + "'")
}
var ipTo = net.ParseIP(ipToString).To4()
if len(ipTo) == 0 {
return nil, errors.New("invalid ip '" + ipToString + "'")
}
if bytes.Compare(ipFrom, ipTo) > 0 {
ipFrom, ipTo = ipTo, ipFrom
}
var result = []string{}
for i := 0; i < 255; i++ {
if bytes.Compare(ipFrom, ipTo) > 0 {
break
}
result = append(result, ipFrom.String())
ipFrom = NextIP(ipFrom)
}
return result, nil
}
return []string{ipStrings}, nil
}
// NextIP IP增加1
func NextIP(prevIP net.IP) net.IP {
var ip = make(net.IP, len(prevIP))
copy(ip, prevIP)
var index = len(ip) - 1
for {
if ip[index] == 255 {
ip[index] = 0
index--
if index < 0 {
break
}
} else {
ip[index]++
break
}
}
return ip
}

View File

@@ -1,6 +1,7 @@
package utils package utils
import ( import (
"net"
"testing" "testing"
) )
@@ -83,3 +84,27 @@ func TestIsIPv6(t *testing.T) {
} }
} }
} }
func TestExtractIP(t *testing.T) {
t.Log(ExtractIP("192.168.1.100"))
}
func TestExtractIP_CIDR(t *testing.T) {
t.Log(ExtractIP("192.168.2.100/24"))
}
func TestExtractIP_Range(t *testing.T) {
t.Log(ExtractIP("192.168.2.100 - 192.168.4.2"))
}
func TestNextIP(t *testing.T) {
for _, ip := range []string{"192.168.1.1", "0.0.0.0", "255.255.255.255", "192.168.2.255", "192.168.255.255"} {
t.Log(ip+":", NextIP(net.ParseIP(ip).To4()))
}
}
func TestNextIP_Copy(t *testing.T) {
var ip = net.ParseIP("192.168.1.100")
var nextIP = NextIP(ip)
t.Log(ip, nextIP)
}

View File

@@ -3,6 +3,7 @@ package cluster
import ( import (
"encoding/json" "encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs" "github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
"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/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils" "github.com/TeaOSLab/EdgeAdmin/internal/web/actions/default/clusters/grants/grantutils"
"github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
@@ -167,9 +168,13 @@ func (this *CreateNodeAction) RunPost(params struct {
nodeId := createResp.NodeId nodeId := createResp.NodeId
// IP地址 // IP地址
var resultIPAddresses = []string{}
for _, addr := range ipAddresses { for _, addr := range ipAddresses {
var resultAddrIds = []int64{}
addrId := addr.GetInt64("id") addrId := addr.GetInt64("id")
if addrId > 0 { if addrId > 0 {
resultAddrIds = append(resultAddrIds, addrId)
_, err = this.RPC().NodeIPAddressRPC().UpdateNodeIPAddressNodeId(this.AdminContext(), &pb.UpdateNodeIPAddressNodeIdRequest{ _, err = this.RPC().NodeIPAddressRPC().UpdateNodeIPAddressNodeId(this.AdminContext(), &pb.UpdateNodeIPAddressNodeIdRequest{
NodeIPAddressId: addrId, NodeIPAddressId: addrId,
NodeId: nodeId, NodeId: nodeId,
@@ -178,20 +183,50 @@ func (this *CreateNodeAction) RunPost(params struct {
this.ErrorPage(err) this.ErrorPage(err)
return return
} }
resultIPAddresses = append(resultIPAddresses, addr.GetString("ip"))
} else { } else {
createResp, err := this.RPC().NodeIPAddressRPC().CreateNodeIPAddress(this.AdminContext(), &pb.CreateNodeIPAddressRequest{ var ipStrings = addr.GetString("ip")
NodeId: nodeId, result, err := utils.ExtractIP(ipStrings)
Role: nodeconfigs.NodeRoleNode,
Name: addr.GetString("name"),
Ip: addr.GetString("ip"),
CanAccess: addr.GetBool("canAccess"),
IsUp: addr.GetBool("isUp"),
})
if err != nil { if err != nil {
this.ErrorPage(err) this.Fail("节点创建成功但是保存IP失败" + err.Error())
return }
resultIPAddresses = append(resultIPAddresses, result...)
if len(result) == 1 {
// 单个创建
createResp, err := this.RPC().NodeIPAddressRPC().CreateNodeIPAddress(this.AdminContext(), &pb.CreateNodeIPAddressRequest{
NodeId: nodeId,
Role: nodeconfigs.NodeRoleNode,
Name: addr.GetString("name"),
Ip: result[0],
CanAccess: addr.GetBool("canAccess"),
IsUp: addr.GetBool("isUp"),
})
if err != nil {
this.ErrorPage(err)
return
}
addrId = createResp.NodeIPAddressId
resultAddrIds = append(resultAddrIds, addrId)
} else if len(result) > 1 {
// 批量创建
createResp, err := this.RPC().NodeIPAddressRPC().CreateNodeIPAddresses(this.AdminContext(), &pb.CreateNodeIPAddressesRequest{
NodeId: nodeId,
Role: nodeconfigs.NodeRoleNode,
Name: addr.GetString("name"),
IpList: result,
CanAccess: addr.GetBool("canAccess"),
IsUp: addr.GetBool("isUp"),
GroupValue: ipStrings,
})
if err != nil {
this.ErrorPage(err)
return
}
resultAddrIds = append(resultAddrIds, createResp.NodeIPAddressIds...)
} }
addrId = createResp.NodeIPAddressId
} }
// 阈值 // 阈值
@@ -202,13 +237,16 @@ func (this *CreateNodeAction) RunPost(params struct {
this.ErrorPage(err) this.ErrorPage(err)
return return
} }
_, err = this.RPC().NodeIPAddressThresholdRPC().UpdateAllNodeIPAddressThresholds(this.AdminContext(), &pb.UpdateAllNodeIPAddressThresholdsRequest{
NodeIPAddressId: addrId, for _, addrId := range resultAddrIds {
NodeIPAddressThresholdsJSON: thresholdsJSON, _, err = this.RPC().NodeIPAddressThresholdRPC().UpdateAllNodeIPAddressThresholds(this.AdminContext(), &pb.UpdateAllNodeIPAddressThresholdsRequest{
}) NodeIPAddressId: addrId,
if err != nil { NodeIPAddressThresholdsJSON: thresholdsJSON,
this.ErrorPage(err) })
return if err != nil {
this.ErrorPage(err)
return
}
} }
} }
} }
@@ -224,11 +262,6 @@ func (this *CreateNodeAction) RunPost(params struct {
return return
} }
if nodeResp.Node != nil { if nodeResp.Node != nil {
var addresses = []string{}
for _, addrMap := range ipAddresses {
addresses = append(addresses, addrMap.GetString("ip"))
}
var grantMap maps.Map = nil var grantMap maps.Map = nil
grantId := params.GrantId grantId := params.GrantId
if grantId > 0 { if grantId > 0 {
@@ -253,7 +286,7 @@ func (this *CreateNodeAction) RunPost(params struct {
"name": nodeResp.Node.Name, "name": nodeResp.Node.Name,
"uniqueId": nodeResp.Node.UniqueId, "uniqueId": nodeResp.Node.UniqueId,
"secret": nodeResp.Node.Secret, "secret": nodeResp.Node.Secret,
"addresses": addresses, "addresses": resultIPAddresses,
"login": maps.Map{ "login": maps.Map{
"id": 0, "id": 0,
"name": "SSH", "name": "SSH",

View File

@@ -3,6 +3,7 @@ package ipAddresses
import ( import (
"encoding/json" "encoding/json"
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const" teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
"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/nodeconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/iwind/TeaGo/actions" "github.com/iwind/TeaGo/actions"
@@ -39,9 +40,15 @@ func (this *CreatePopupAction) RunPost(params struct {
Field("ip", params.IP). Field("ip", params.IP).
Require("请输入IP地址") Require("请输入IP地址")
ip := net.ParseIP(params.IP) result, err := utils.ExtractIP(params.IP)
if len(ip) == 0 { if err != nil {
this.FailField("ip", "请输入正确的IP") this.Fail("IP格式错误'" + params.IP + "'")
}
for _, ip := range result {
if len(net.ParseIP(ip)) == 0 {
this.FailField("ip", "请输入正确的IP")
}
} }
// 阈值设置 // 阈值设置

View File

@@ -2,6 +2,7 @@ package ipaddressutils
import ( import (
"encoding/json" "encoding/json"
"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/nodeconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
@@ -16,8 +17,11 @@ func UpdateNodeIPAddresses(parentAction *actionutils.ParentAction, nodeId int64,
return err return err
} }
for _, addr := range addresses { for _, addr := range addresses {
var resultAddrIds = []int64{}
addrId := addr.GetInt64("id") addrId := addr.GetInt64("id")
if addrId > 0 { if addrId > 0 {
resultAddrIds = append(resultAddrIds, addrId)
var isOn = false var isOn = false
if !addr.Has("isOn") { // 兼容老版本 if !addr.Has("isOn") { // 兼容老版本
isOn = true isOn = true
@@ -37,18 +41,40 @@ func UpdateNodeIPAddresses(parentAction *actionutils.ParentAction, nodeId int64,
return err return err
} }
} else { } else {
createResp, err := parentAction.RPC().NodeIPAddressRPC().CreateNodeIPAddress(parentAction.AdminContext(), &pb.CreateNodeIPAddressRequest{ var ipStrings = addr.GetString("ip")
NodeId: nodeId, result, _ := utils.ExtractIP(ipStrings)
Role: role,
Name: addr.GetString("name"), if len(result) == 1 {
Ip: addr.GetString("ip"), // 单个创建
CanAccess: addr.GetBool("canAccess"), createResp, err := parentAction.RPC().NodeIPAddressRPC().CreateNodeIPAddress(parentAction.AdminContext(), &pb.CreateNodeIPAddressRequest{
IsUp: addr.GetBool("isUp"), NodeId: nodeId,
}) Role: role,
if err != nil { Name: addr.GetString("name"),
return err Ip: result[0],
CanAccess: addr.GetBool("canAccess"),
IsUp: addr.GetBool("isUp"),
})
if err != nil {
return err
}
addrId = createResp.NodeIPAddressId
resultAddrIds = append(resultAddrIds, addrId)
} else if len(result) > 1 {
// 批量创建
createResp, err := parentAction.RPC().NodeIPAddressRPC().CreateNodeIPAddresses(parentAction.AdminContext(), &pb.CreateNodeIPAddressesRequest{
NodeId: nodeId,
Role: role,
Name: addr.GetString("name"),
IpList: result,
CanAccess: addr.GetBool("canAccess"),
IsUp: addr.GetBool("isUp"),
GroupValue: ipStrings,
})
if err != nil {
return err
}
resultAddrIds = append(resultAddrIds, createResp.NodeIPAddressIds...)
} }
addrId = createResp.NodeIPAddressId
} }
// 保存阈值 // 保存阈值
@@ -58,12 +84,15 @@ func UpdateNodeIPAddresses(parentAction *actionutils.ParentAction, nodeId int64,
if err != nil { if err != nil {
return err return err
} }
_, err = parentAction.RPC().NodeIPAddressThresholdRPC().UpdateAllNodeIPAddressThresholds(parentAction.AdminContext(), &pb.UpdateAllNodeIPAddressThresholdsRequest{
NodeIPAddressId: addrId, for _, addrId := range resultAddrIds {
NodeIPAddressThresholdsJSON: thresholdsJSON, _, err = parentAction.RPC().NodeIPAddressThresholdRPC().UpdateAllNodeIPAddressThresholds(parentAction.AdminContext(), &pb.UpdateAllNodeIPAddressThresholdsRequest{
}) NodeIPAddressId: addrId,
if err != nil { NodeIPAddressThresholdsJSON: thresholdsJSON,
return err })
if err != nil {
return err
}
} }
} }
} }

View File

@@ -3,6 +3,7 @@ package ipAddresses
import ( import (
"encoding/json" "encoding/json"
teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const" teaconst "github.com/TeaOSLab/EdgeAdmin/internal/const"
"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/nodeconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
@@ -57,9 +58,22 @@ func (this *UpdatePopupAction) RunPost(params struct {
} }
} }
ip := net.ParseIP(params.IP) if params.AddressId > 0 {
if len(ip) == 0 { ip := net.ParseIP(params.IP)
this.Fail("请输入正确的IP") if len(ip) == 0 {
this.Fail("请输入正确的IP")
}
} else {
result, err := utils.ExtractIP(params.IP)
if err != nil {
this.Fail("IP格式错误'" + params.IP + "'")
}
for _, ip := range result {
if len(net.ParseIP(ip)) == 0 {
this.FailField("ip", "请输入正确的IP")
}
}
} }
var thresholds = []*nodeconfigs.IPAddressThresholdConfig{} var thresholds = []*nodeconfigs.IPAddressThresholdConfig{}

View File

@@ -3,6 +3,7 @@ package cluster
import ( import (
"encoding/json" "encoding/json"
"github.com/TeaOSLab/EdgeAdmin/internal/oplogs" "github.com/TeaOSLab/EdgeAdmin/internal/oplogs"
"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/nodeconfigs" "github.com/TeaOSLab/EdgeCommon/pkg/nodeconfigs"
"github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb" "github.com/TeaOSLab/EdgeCommon/pkg/rpc/pb"
@@ -87,14 +88,31 @@ func (this *CreateNodeAction) RunPost(params struct {
NodeId: nodeId, NodeId: nodeId,
}) })
} else { } else {
_, err = this.RPC().NodeIPAddressRPC().CreateNodeIPAddress(this.AdminContext(), &pb.CreateNodeIPAddressRequest{ var ipStrings = addrMap.GetString("ip")
NodeId: nodeId, result, _ := utils.ExtractIP(ipStrings)
Role: nodeconfigs.NodeRoleDNS,
Name: addrMap.GetString("name"), if len(result) == 1 {
Ip: addrMap.GetString("ip"), // 单个创建
CanAccess: addrMap.GetBool("canAccess"), _, err = this.RPC().NodeIPAddressRPC().CreateNodeIPAddress(this.AdminContext(), &pb.CreateNodeIPAddressRequest{
IsUp: addrMap.GetBool("isUp"), NodeId: nodeId,
}) Role: nodeconfigs.NodeRoleDNS,
Name: addrMap.GetString("name"),
Ip: result[0],
CanAccess: addrMap.GetBool("canAccess"),
IsUp: addrMap.GetBool("isUp"),
})
} else if len(result) > 1 {
// 批量创建
_, err = this.RPC().NodeIPAddressRPC().CreateNodeIPAddresses(this.AdminContext(), &pb.CreateNodeIPAddressesRequest{
NodeId: nodeId,
Role: nodeconfigs.NodeRoleDNS,
Name: addrMap.GetString("name"),
IpList: result,
CanAccess: addrMap.GetBool("canAccess"),
IsUp: addrMap.GetBool("isUp"),
GroupValue: ipStrings,
})
}
} }
if err != nil { if err != nil {
this.ErrorPage(err) this.ErrorPage(err)

View File

@@ -8,6 +8,7 @@
<td class="title">IP地址 *</td> <td class="title">IP地址 *</td>
<td> <td>
<input type="text" name="ip" maxlength="128" ref="focus"/> <input type="text" name="ip" maxlength="128" ref="focus"/>
<p class="comment">支持单个IP、CIDR格式的一组IP位数不能小于24、IP范围类似于<code-label>x.x.x.x-x.x.x.x</code-label>最多只取256个等。</p>
</td> </td>
</tr> </tr>
<tr> <tr>

View File

@@ -9,6 +9,8 @@
<td class="title">IP地址 *</td> <td class="title">IP地址 *</td>
<td> <td>
<input type="text" name="ip" maxlength="128" ref="focus" v-model="address.ip"/> <input type="text" name="ip" maxlength="128" ref="focus" v-model="address.ip"/>
<p class="comment" v-if="address.id > 0">只支持单个IP。</p>
<p class="comment" v-if="address.id == 0">支持单个IP、CIDR格式的一组IP位数不能小于24、IP范围类似于<code-label>x.x.x.x-x.x.x.x</code-label>最多只取256个等。</p>
</td> </td>
</tr> </tr>
<tr> <tr>