mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-24 16:03:43 +08:00
feat(region): larger suggest network and more complete vlanid
1. 抓取标准 PortGroup 的 vlanid,以前只有分布式 PortGroup 的 vlanid 2. 提供的建议网络会尽可能的大
This commit is contained in:
@@ -357,29 +357,28 @@ func (scm *SCloudaccountManager) AllowPerformPrepareNets(_ context.Context, user
|
||||
return db.IsAdminAllowPerform(userCred, scm, "prepare-nets")
|
||||
}
|
||||
|
||||
type sHostVMIp struct {
|
||||
hostIps map[string]string
|
||||
vms []esxi.SSimpleVM
|
||||
prefix string
|
||||
type sNetworkInfo struct {
|
||||
esxi.SNetworkInfo
|
||||
prefix string
|
||||
}
|
||||
|
||||
func (scm *SCloudaccountManager) hostVMIPsPrepareNets(ctx context.Context, client *esxi.SESXiClient, input api.CloudaccountPerformPrepareNetsInput) ([]sHostVMIp, error) {
|
||||
func (scm *SCloudaccountManager) hostVMIPsPrepareNets(ctx context.Context, client *esxi.SESXiClient,
|
||||
input api.CloudaccountPerformPrepareNetsInput) ([]sNetworkInfo, error) {
|
||||
caName := input.Name
|
||||
wireLevel := input.WireLevelForVmware
|
||||
ret := make([]sHostVMIp, 0)
|
||||
ret := make([]sNetworkInfo, 0)
|
||||
if len(wireLevel) == 0 {
|
||||
wireLevel = api.CLOUD_ACCOUNT_WIRE_LEVEL_VCENTER
|
||||
}
|
||||
switch wireLevel {
|
||||
case api.CLOUD_ACCOUNT_WIRE_LEVEL_VCENTER:
|
||||
hostIps, simpleVms, err := client.HostVmIPs(ctx)
|
||||
nInfo, err := client.HostVmIPs(ctx)
|
||||
if err != nil {
|
||||
return ret, errors.Wrap(err, "unable to fetch ips of hosts and vms")
|
||||
return nil, errors.Wrap(err, "unable to fetch ips of hosts and vms")
|
||||
}
|
||||
ret = append(ret, sHostVMIp{
|
||||
hostIps: hostIps,
|
||||
vms: simpleVms,
|
||||
prefix: caName,
|
||||
ret = append(ret, sNetworkInfo{
|
||||
SNetworkInfo: nInfo,
|
||||
prefix: caName,
|
||||
})
|
||||
case api.CLOUD_ACCOUNT_WIRE_LEVEL_DATACENTER:
|
||||
dcs, err := client.GetDatacenters()
|
||||
@@ -387,14 +386,13 @@ func (scm *SCloudaccountManager) hostVMIPsPrepareNets(ctx context.Context, clien
|
||||
return ret, errors.Wrap(err, "GetDatacenters")
|
||||
}
|
||||
for _, dc := range dcs {
|
||||
hostIps, simpleVms, err := client.HostVmIPsInDc(ctx, dc)
|
||||
nInfo, err := client.HostVmIPsInDc(ctx, dc)
|
||||
if err != nil {
|
||||
return ret, errors.Wrapf(err, "unable to fetch ips of hosts and vms for dc %q", dc.GetName())
|
||||
}
|
||||
ret = append(ret, sHostVMIp{
|
||||
hostIps: hostIps,
|
||||
vms: simpleVms,
|
||||
prefix: fmt.Sprintf("%s/%s", caName, dc.GetName()),
|
||||
ret = append(ret, sNetworkInfo{
|
||||
SNetworkInfo: nInfo,
|
||||
prefix: fmt.Sprintf("%s/%s", caName, dc.GetName()),
|
||||
})
|
||||
}
|
||||
case api.CLOUD_ACCOUNT_WIRE_LEVEL_CLUSTER:
|
||||
@@ -408,14 +406,13 @@ func (scm *SCloudaccountManager) hostVMIPsPrepareNets(ctx context.Context, clien
|
||||
return nil, errors.Wrapf(err, "unable to ListCluster for dc %q", dc.GetName())
|
||||
}
|
||||
for _, cluster := range clusters {
|
||||
hostIps, simpleVms, err := client.HostVmIPsInCluster(ctx, cluster)
|
||||
nInfo, err := client.HostVmIPsInCluster(ctx, cluster)
|
||||
if err != nil {
|
||||
return ret, errors.Wrapf(err, "unable to fetch ips of hosts and vms for dc %q cluster %q", dc.GetName(), cluster.GetName())
|
||||
}
|
||||
ret = append(ret, sHostVMIp{
|
||||
hostIps: hostIps,
|
||||
vms: simpleVms,
|
||||
prefix: fmt.Sprintf("%s/%s/%s", caName, dc.GetName(), cluster.GetName()),
|
||||
ret = append(ret, sNetworkInfo{
|
||||
SNetworkInfo: nInfo,
|
||||
prefix: fmt.Sprintf("%s/%s/%s", caName, dc.GetName(), cluster.GetName()),
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -478,7 +475,7 @@ func (scm *SCloudaccountManager) PerformPrepareNets(ctx context.Context, userCre
|
||||
zoneids = append(zoneids, id)
|
||||
}
|
||||
// fetch all wire candidate
|
||||
wires, err := scm.fetchWires(zoneids, domainId)
|
||||
wires, err := scm.fetchWires(userCred, zoneids, domainId)
|
||||
if err != nil {
|
||||
return output, errors.Wrap(err, "unable to fetch wires")
|
||||
}
|
||||
@@ -521,7 +518,7 @@ func (scm *SCloudaccountManager) PerformPrepareNets(ctx context.Context, userCre
|
||||
}
|
||||
// hack
|
||||
client := iregion.(*esxi.SESXiClient)
|
||||
hostVMIPs, err := scm.hostVMIPsPrepareNets(ctx, client, input)
|
||||
nInfos, err := scm.hostVMIPsPrepareNets(ctx, client, input)
|
||||
if err != nil {
|
||||
return output, err
|
||||
}
|
||||
@@ -534,13 +531,11 @@ func (scm *SCloudaccountManager) PerformPrepareNets(ctx context.Context, userCre
|
||||
}
|
||||
networks[i] = nets
|
||||
}
|
||||
output.CAWireNets = make([]api.CAWireNet, 0, len(hostVMIPs))
|
||||
for _, hv := range hostVMIPs {
|
||||
output.CAWireNets = make([]api.CAWireNet, 0, len(nInfos))
|
||||
for _, ni := range nInfos {
|
||||
var (
|
||||
wireNet api.CAWireNet
|
||||
hostIps = hv.hostIps
|
||||
simpleVms = hv.vms
|
||||
prefix = hv.prefix
|
||||
wireNet api.CAWireNet
|
||||
hostIps = ni.HostIps
|
||||
)
|
||||
|
||||
// key of ipHosts is host's ip
|
||||
@@ -590,7 +585,7 @@ func (scm *SCloudaccountManager) PerformPrepareNets(ctx context.Context, userCre
|
||||
} else {
|
||||
wireNet.SuggestedWire = api.CAWireConf{
|
||||
ZoneIds: zoneids,
|
||||
Name: prefix + "-wire",
|
||||
Name: ni.prefix + "-wire",
|
||||
Description: fmt.Sprintf("Auto created Wire for VMware account %q", input.Name),
|
||||
}
|
||||
}
|
||||
@@ -615,7 +610,7 @@ func (scm *SCloudaccountManager) PerformPrepareNets(ctx context.Context, userCre
|
||||
confs := make([]api.CANetConf, len(sConfs))
|
||||
for i := range confs {
|
||||
confs[i].CASimpleNetConf = sConfs[i]
|
||||
confs[i].Name = fmt.Sprintf("%s-host-network-%d", prefix, i+1)
|
||||
confs[i].Name = fmt.Sprintf("%s-host-network-%d", ni.prefix, i+1)
|
||||
}
|
||||
wireNet.HostSuggestedNetworks = confs
|
||||
}
|
||||
@@ -628,214 +623,96 @@ func (scm *SCloudaccountManager) PerformPrepareNets(ctx context.Context, userCre
|
||||
return output, err
|
||||
}
|
||||
}
|
||||
|
||||
type vm struct {
|
||||
FakeID int
|
||||
IP netutils.IPV4Addr
|
||||
Name string
|
||||
VlanID int32
|
||||
type simpleNet struct {
|
||||
Id string
|
||||
Vlan int32
|
||||
}
|
||||
vms := make([]vm, 0, len(simpleVms))
|
||||
var nip netutils.IPV4Addr
|
||||
guestMap := make(map[int]*api.CAGuestNet)
|
||||
for i := range simpleVms {
|
||||
id := i
|
||||
if len(simpleVms[i].IPVlans) == 0 {
|
||||
if _, ok := guestMap[id]; !ok {
|
||||
guestMap[id] = &api.CAGuestNet{
|
||||
Name: simpleVms[i].Name,
|
||||
IPNets: []api.CAIPNet{},
|
||||
}
|
||||
}
|
||||
}
|
||||
for _, ipVlan := range simpleVms[i].IPVlans {
|
||||
nip, err = netutils.NewIPV4Addr(ipVlan.IP)
|
||||
if err != nil {
|
||||
return output, err
|
||||
}
|
||||
vms = append(vms, vm{
|
||||
FakeID: i,
|
||||
IP: nip,
|
||||
Name: simpleVms[i].Name,
|
||||
VlanID: ipVlan.VlanID,
|
||||
})
|
||||
}
|
||||
}
|
||||
// sort vms via vm's ip
|
||||
sort.Slice(vms, func(i, j int) bool {
|
||||
return vms[i].IP < vms[j].IP
|
||||
})
|
||||
|
||||
type sExcludeNet struct {
|
||||
StartIp netutils.IPV4Addr
|
||||
EndIp netutils.IPV4Addr
|
||||
Id string
|
||||
}
|
||||
excludeNets := make([]sExcludeNet, 0, len(allNets)+len(wireNet.HostSuggestedNetworks))
|
||||
existedNetMap := make(map[netutils.IPV4Addr]simpleNet, len(allNets))
|
||||
for i := range allNets {
|
||||
startIp, _ := netutils.NewIPV4Addr(allNets[i].GuestIpStart)
|
||||
endIp, _ := netutils.NewIPV4Addr(allNets[i].GuestIpEnd)
|
||||
excludeNets = append(excludeNets, sExcludeNet{
|
||||
StartIp: startIp,
|
||||
EndIp: endIp,
|
||||
Id: allNets[i].GetId(),
|
||||
})
|
||||
}
|
||||
for i := range wireNet.HostSuggestedNetworks {
|
||||
startIp, _ := netutils.NewIPV4Addr(wireNet.HostSuggestedNetworks[i].GuestIpStart)
|
||||
endIp, _ := netutils.NewIPV4Addr(wireNet.HostSuggestedNetworks[i].GuestIpEnd)
|
||||
excludeNets = append(excludeNets, sExcludeNet{
|
||||
StartIp: startIp,
|
||||
EndIp: endIp,
|
||||
})
|
||||
}
|
||||
// sort excludeNets via their GuestIpStart
|
||||
sort.Slice(excludeNets, func(i, j int) bool {
|
||||
return excludeNets[i].StartIp < excludeNets[j].StartIp
|
||||
})
|
||||
|
||||
svNets := make([]api.CASimpleNetConf, 0, 5)
|
||||
var vmi, neti int
|
||||
|
||||
Loop:
|
||||
for neti = 0; neti < len(excludeNets); {
|
||||
if vmi >= len(vms) {
|
||||
break
|
||||
}
|
||||
startIp := excludeNets[neti].StartIp
|
||||
endIp := excludeNets[neti].EndIp
|
||||
switch {
|
||||
case vms[vmi].IP > endIp:
|
||||
neti++
|
||||
case vms[vmi].IP >= startIp:
|
||||
for vms[vmi].IP <= endIp {
|
||||
id := vms[vmi].FakeID
|
||||
if _, ok := guestMap[id]; !ok {
|
||||
guestMap[id] = &api.CAGuestNet{
|
||||
Name: vms[vmi].Name,
|
||||
IPNets: []api.CAIPNet{},
|
||||
}
|
||||
}
|
||||
guestMap[id].IPNets = append(guestMap[id].IPNets, api.CAIPNet{
|
||||
IP: vms[vmi].IP.String(),
|
||||
SuitableNetwork: excludeNets[neti].Id,
|
||||
VlanID: vms[vmi].VlanID,
|
||||
})
|
||||
vmi += 1
|
||||
if vmi == len(vms) {
|
||||
break Loop
|
||||
}
|
||||
}
|
||||
neti++
|
||||
default:
|
||||
for vms[vmi].IP < startIp {
|
||||
suggestStartIp := vms[vmi].IP
|
||||
suggestEndIp := vms[vmi].IP
|
||||
endLimitIp := suggestStartIp.NetAddr(24) + 255
|
||||
vlanId := vms[vmi].VlanID
|
||||
for {
|
||||
id := vms[vmi].FakeID
|
||||
if _, ok := guestMap[id]; !ok {
|
||||
guestMap[id] = &api.CAGuestNet{
|
||||
Name: vms[vmi].Name,
|
||||
IPNets: []api.CAIPNet{},
|
||||
}
|
||||
}
|
||||
guestMap[id].IPNets = append(guestMap[id].IPNets, api.CAIPNet{
|
||||
IP: vms[vmi].IP.String(),
|
||||
VlanID: vms[vmi].VlanID,
|
||||
})
|
||||
vmi++
|
||||
if vmi == len(vms) {
|
||||
break
|
||||
}
|
||||
if suggestEndIp == endLimitIp {
|
||||
break
|
||||
}
|
||||
if vms[vmi].IP > suggestEndIp+1 {
|
||||
break
|
||||
}
|
||||
if vms[vmi].IP >= startIp {
|
||||
break
|
||||
}
|
||||
if vms[vmi].VlanID != vlanId {
|
||||
break
|
||||
}
|
||||
suggestEndIp = vms[vmi].IP
|
||||
}
|
||||
svNets = append(svNets, api.CASimpleNetConf{
|
||||
GuestIpStart: suggestStartIp.String(),
|
||||
GuestIpEnd: suggestEndIp.String(),
|
||||
VlanID: vlanId,
|
||||
GuestIpMask: 24,
|
||||
GuestGateway: (suggestStartIp.NetAddr(24) + netutils.IPV4Addr(options.Options.DefaultNetworkGatewayAddressEsxi)).String(),
|
||||
})
|
||||
if vmi == len(vms) {
|
||||
break Loop
|
||||
}
|
||||
}
|
||||
ipStart, _ := netutils.NewIPV4Addr(allNets[i].GuestIpStart)
|
||||
ipEnd, _ := netutils.NewIPV4Addr(allNets[i].GuestIpEnd)
|
||||
for ip := ipStart; ip <= ipEnd; ip++ {
|
||||
existedNetMap[ip] = simpleNet{Id: allNets[i].Id, Vlan: int32(allNets[i].VlanId)}
|
||||
}
|
||||
}
|
||||
|
||||
for vmi < len(vms) {
|
||||
suggestStartIp := vms[vmi].IP
|
||||
endLimitIp := suggestStartIp.NetAddr(24) + 255
|
||||
suggestEndIp := suggestStartIp
|
||||
vlanId := vms[vmi].VlanID
|
||||
for {
|
||||
id := vms[vmi].FakeID
|
||||
if _, ok := guestMap[id]; !ok {
|
||||
guestMap[id] = &api.CAGuestNet{
|
||||
Name: vms[vmi].Name,
|
||||
IPNets: []api.CAIPNet{},
|
||||
}
|
||||
guests := make([]api.CAGuestNet, len(ni.VMs))
|
||||
for i := range guests {
|
||||
guests[i].Name = ni.VMs[i].Name
|
||||
for _, ipvlan := range ni.VMs[i].IPVlans {
|
||||
var suitableNetId string
|
||||
sn, ok := existedNetMap[ipvlan.IP]
|
||||
if ok {
|
||||
suitableNetId = sn.Id
|
||||
}
|
||||
guestMap[id].IPNets = append(guestMap[id].IPNets, api.CAIPNet{
|
||||
IP: vms[vmi].IP.String(),
|
||||
guests[i].IPNets = append(guests[i].IPNets, api.CAIPNet{
|
||||
IP: ipvlan.IP.String(),
|
||||
VlanID: ipvlan.VlanId,
|
||||
SuitableNetwork: suitableNetId,
|
||||
})
|
||||
vmi++
|
||||
if vmi == len(vms) {
|
||||
break
|
||||
}
|
||||
if suggestEndIp == endLimitIp {
|
||||
break
|
||||
}
|
||||
if vms[vmi].IP > suggestEndIp+1 {
|
||||
break
|
||||
}
|
||||
if vms[vmi].VlanID != vlanId {
|
||||
break
|
||||
}
|
||||
suggestEndIp = vms[vmi].IP
|
||||
}
|
||||
svNets = append(svNets, api.CASimpleNetConf{
|
||||
GuestIpStart: suggestStartIp.String(),
|
||||
GuestIpEnd: suggestEndIp.String(),
|
||||
VlanID: vlanId,
|
||||
GuestIpMask: 24,
|
||||
GuestGateway: (suggestStartIp.NetAddr(24) + netutils.IPV4Addr(options.Options.DefaultNetworkGatewayAddressEsxi)).String(),
|
||||
})
|
||||
}
|
||||
wireNet.Guests = guests
|
||||
|
||||
for _, guest := range guestMap {
|
||||
wireNet.Guests = append(wireNet.Guests, *guest)
|
||||
}
|
||||
|
||||
if len(svNets) > 0 {
|
||||
confs := make([]api.CANetConf, len(svNets))
|
||||
for i := range confs {
|
||||
confs[i].CASimpleNetConf = svNets[i]
|
||||
confs[i].Name = fmt.Sprintf("%s-guest-network-%d", prefix, i+1)
|
||||
for vlan, ips := range ni.VlanIps {
|
||||
for i := 0; i < len(ips); i++ {
|
||||
ip := ips[i]
|
||||
if _, ok := existedNetMap[ip]; ok {
|
||||
continue
|
||||
}
|
||||
net := ip.NetAddr(24)
|
||||
netLimitLow := net + 1
|
||||
netLimitUp := net + 254
|
||||
// find startip
|
||||
startIp := ip - 1
|
||||
for ; startIp >= netLimitLow; startIp-- {
|
||||
if _, ok := existedNetMap[startIp]; ok {
|
||||
break
|
||||
}
|
||||
if _, ok := ni.IPPool.Get(startIp); ok {
|
||||
break
|
||||
}
|
||||
}
|
||||
endIp := ip + 1
|
||||
for ; endIp <= netLimitUp; endIp++ {
|
||||
if _, ok := existedNetMap[endIp]; ok {
|
||||
break
|
||||
}
|
||||
if proc, ok := ni.IPPool.Get(endIp); ok {
|
||||
if proc.VlanId == vlan {
|
||||
// find one in ips
|
||||
i++
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
slen := len(wireNet.GuestSuggestedNetworks)
|
||||
wireNet.GuestSuggestedNetworks = append(wireNet.GuestSuggestedNetworks, api.CANetConf{
|
||||
Name: fmt.Sprintf("%s-guest-network-%d", ni.prefix, slen+1),
|
||||
Description: "",
|
||||
CASimpleNetConf: api.CASimpleNetConf{
|
||||
VlanID: vlan,
|
||||
GuestIpStart: (startIp + 1).String(),
|
||||
GuestIpEnd: (endIp - 1).String(),
|
||||
GuestIpMask: 24,
|
||||
GuestGateway: (net + netutils.IPV4Addr(options.Options.DefaultNetworkGatewayAddressEsxi)).
|
||||
String(),
|
||||
},
|
||||
})
|
||||
// Avoid assigning already assigned ip subnet
|
||||
existedNetMap[startIp+1] = simpleNet{}
|
||||
existedNetMap[endIp-1] = simpleNet{}
|
||||
}
|
||||
wireNet.GuestSuggestedNetworks = confs
|
||||
}
|
||||
output.CAWireNets = append(output.CAWireNets, wireNet)
|
||||
}
|
||||
return output, nil
|
||||
}
|
||||
|
||||
func (manager *SCloudaccountManager) fetchWires(zoneIds []string, domainId string) ([]SWire, error) {
|
||||
func (manager *SCloudaccountManager) fetchWires(userCred mcclient.TokenCredential, zoneIds []string, domainId string) ([]SWire, error) {
|
||||
q := WireManager.Query().Equals("domain_id", domainId).In("zone_id", zoneIds)
|
||||
q = WireManager.FilterByOwner(q, userCred, rbacutils.ScopeDomain)
|
||||
wires := make([]SWire, 0, 1)
|
||||
err := db.FetchModelObjects(WireManager, q, &wires)
|
||||
return wires, err
|
||||
|
||||
+133
-103
@@ -19,6 +19,7 @@ import (
|
||||
"fmt"
|
||||
"net/url"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
@@ -105,7 +106,8 @@ type SESXiClient struct {
|
||||
client *govmomi.Client
|
||||
context context.Context
|
||||
|
||||
datacenters []*SDatacenter
|
||||
datacenters []*SDatacenter
|
||||
networkQueryMap *sync.Map
|
||||
}
|
||||
|
||||
func NewESXiClient(cfg *ESXiClientConfig) (*SESXiClient, error) {
|
||||
@@ -682,14 +684,15 @@ func (cli *SESXiClient) MoveDisk(ctx context.Context, src, dst string, isForce b
|
||||
}
|
||||
|
||||
var (
|
||||
SIMPLE_HOST_PROPS = []string{"name", "config.network", "vm"}
|
||||
SIMPLE_VM_PROPS = []string{"name", "guest.net", "config.template", "config.hardware.device"}
|
||||
SIMPLE_DVPG_PROPS = []string{"key", "config.defaultPortConfig"}
|
||||
SIMPLE_HOST_PROPS = []string{"name", "config.network", "vm"}
|
||||
SIMPLE_VM_PROPS = []string{"name", "guest.net", "config.template", "config.hardware.device"}
|
||||
SIMPLE_DVPG_PROPS = []string{"key", "config.defaultPortConfig", "config.distributedVirtualSwitch"}
|
||||
SIMPLE_NETWORK_PROPS = []string{"name"}
|
||||
)
|
||||
|
||||
type SIPVlan struct {
|
||||
IP string
|
||||
VlanID int32
|
||||
IP netutils.IPV4Addr
|
||||
VlanId int32
|
||||
}
|
||||
|
||||
type SSimpleVM struct {
|
||||
@@ -710,54 +713,74 @@ func (cli *SESXiClient) scanAllDvPortgroups() ([]*SDistributedVirtualPortgroup,
|
||||
return dvpgs, nil
|
||||
}
|
||||
|
||||
func (cli *SESXiClient) dvpgKeyVlanMap() (*sync.Map, error) {
|
||||
dvpgs, err := cli.scanAllDvPortgroups()
|
||||
func (cli *SESXiClient) scanAllNetworks() ([]mo.Network, error) {
|
||||
var monets []mo.Network
|
||||
err := cli.scanAllMObjects(SIMPLE_NETWORK_PROPS, &monets)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "scanAllMObjects")
|
||||
}
|
||||
ret := new(sync.Map)
|
||||
for i := range dvpgs {
|
||||
key := dvpgs[i].getMODVPortgroup().Key
|
||||
vlanid := dvpgs[i].GetVlanId()
|
||||
ret.Store(key, vlanid)
|
||||
}
|
||||
return ret, nil
|
||||
return monets, nil
|
||||
}
|
||||
|
||||
func (cli *SESXiClient) HostVmIPsInDc(ctx context.Context, dc *SDatacenter) (map[string]string, []SSimpleVM, error) {
|
||||
func (cli *SESXiClient) networkName(refV string) (string, error) {
|
||||
if cli.networkQueryMap == nil {
|
||||
nets, err := cli.scanAllNetworks()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
cli.networkQueryMap = &sync.Map{}
|
||||
for i := range nets {
|
||||
cli.networkQueryMap.Store(nets[i].Reference().Value, nets[i].Name)
|
||||
}
|
||||
}
|
||||
iter, ok := cli.networkQueryMap.Load(refV)
|
||||
if !ok {
|
||||
return "", nil
|
||||
}
|
||||
return iter.(string), nil
|
||||
}
|
||||
|
||||
func (cli *SESXiClient) HostVmIPsInDc(ctx context.Context, dc *SDatacenter) (SNetworkInfo, error) {
|
||||
var hosts []mo.HostSystem
|
||||
err := cli.scanMObjects(dc.object.Entity().Self, HOST_SYSTEM_PROPS, &hosts)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "scanMObjects")
|
||||
return SNetworkInfo{}, errors.Wrap(err, "scanMObjects")
|
||||
}
|
||||
return cli.hostVMIPs(ctx, hosts)
|
||||
}
|
||||
|
||||
func (cli *SESXiClient) HostVmIPsInCluster(ctx context.Context, cluster *SCluster) (map[string]string, []SSimpleVM,
|
||||
error) {
|
||||
func (cli *SESXiClient) HostVmIPsInCluster(ctx context.Context, cluster *SCluster) (SNetworkInfo, error) {
|
||||
var hosts []mo.HostSystem
|
||||
err := cli.scanMObjects(cluster.object.Entity().Self, HOST_SYSTEM_PROPS, &hosts)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "scanMObjects")
|
||||
return SNetworkInfo{}, errors.Wrap(err, "scanMObjects")
|
||||
}
|
||||
return cli.hostVMIPs(ctx, hosts)
|
||||
}
|
||||
|
||||
func (cli *SESXiClient) hostVMIPs(ctx context.Context, hosts []mo.HostSystem) (map[string]string, []SSimpleVM, error) {
|
||||
dvpgKeyVlanMap, err := cli.dvpgKeyVlanMap()
|
||||
type SNetworkInfo struct {
|
||||
HostIps map[string]string
|
||||
VMs []SSimpleVM
|
||||
VlanIps map[int32][]netutils.IPV4Addr
|
||||
IPPool SIPPool
|
||||
}
|
||||
|
||||
func (cli *SESXiClient) hostVMIPs(ctx context.Context, hosts []mo.HostSystem) (SNetworkInfo, error) {
|
||||
ret := SNetworkInfo{}
|
||||
dvpgMap, err := cli.getDVPGMap()
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "unable to get dvpgKeyVlanMap")
|
||||
return ret, errors.Wrap(err, "unable to get dvpgKeyVlanMap")
|
||||
}
|
||||
group, ctx := errgroup.WithContext(ctx)
|
||||
collection := make([][]SSimpleVM, len(hosts))
|
||||
collection := make([]SNetworkInfo, len(hosts))
|
||||
for i := range hosts {
|
||||
j := i
|
||||
group.Go(func() error {
|
||||
vmIps, err := cli.vmIPs(&hosts[j], dvpgKeyVlanMap)
|
||||
nInfo, err := cli.vmIPs(&hosts[j], dvpgMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
collection[j] = vmIps
|
||||
collection[j] = nInfo
|
||||
return nil
|
||||
})
|
||||
}
|
||||
@@ -771,72 +794,56 @@ func (cli *SESXiClient) hostVMIPs(ctx context.Context, hosts []mo.HostSystem) (m
|
||||
}
|
||||
err = group.Wait()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
return ret, err
|
||||
}
|
||||
// length
|
||||
length := 0
|
||||
for i := range collection {
|
||||
length += len(collection[i])
|
||||
if len(collection) == 0 {
|
||||
ret.HostIps = hostIps
|
||||
return ret, nil
|
||||
}
|
||||
svms := make([]SSimpleVM, 0, length)
|
||||
for i := range collection {
|
||||
for j := range collection[i] {
|
||||
svms = append(svms, collection[i][j])
|
||||
}
|
||||
}
|
||||
return hostIps, svms, nil
|
||||
ni := cli.mergeNetworInfo(collection)
|
||||
ni.HostIps = hostIps
|
||||
return ni, nil
|
||||
}
|
||||
|
||||
func (cli *SESXiClient) HostVmIPs(ctx context.Context) (map[string]string, []SSimpleVM, error) {
|
||||
dvpgKeyVlanMap, err := cli.dvpgKeyVlanMap()
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "unable to get dvpgKeyVlanMap")
|
||||
func (cli *SESXiClient) mergeNetworInfo(nInfos []SNetworkInfo) SNetworkInfo {
|
||||
var vmsLen, vlanIpLen, ipPoolLen int
|
||||
for i := range nInfos {
|
||||
vmsLen += len(nInfos[i].VMs)
|
||||
vlanIpLen += len(nInfos[i].VlanIps)
|
||||
ipPoolLen += nInfos[i].IPPool.Len()
|
||||
}
|
||||
ret := SNetworkInfo{
|
||||
VMs: make([]SSimpleVM, 0, vmsLen),
|
||||
VlanIps: make(map[int32][]netutils.IPV4Addr, vlanIpLen),
|
||||
IPPool: NewIPPool(ipPoolLen),
|
||||
}
|
||||
for i := range nInfos {
|
||||
ret.VMs = append(ret.VMs, nInfos[i].VMs...)
|
||||
for vlan, ips := range nInfos[i].VlanIps {
|
||||
ret.VlanIps[vlan] = append(ret.VlanIps[vlan], ips...)
|
||||
}
|
||||
ret.IPPool.Merge(&nInfos[i].IPPool)
|
||||
}
|
||||
for _, ips := range ret.VlanIps {
|
||||
sort.Slice(ips, func(i, j int) bool {
|
||||
return ips[i] < ips[j]
|
||||
})
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (cli *SESXiClient) HostVmIPs(ctx context.Context) (SNetworkInfo, error) {
|
||||
var hosts []mo.HostSystem
|
||||
err = cli.scanAllMObjects(SIMPLE_HOST_PROPS, &hosts)
|
||||
err := cli.scanAllMObjects(SIMPLE_HOST_PROPS, &hosts)
|
||||
if err != nil {
|
||||
return nil, nil, errors.Wrap(err, "scanAllMObjects")
|
||||
return SNetworkInfo{}, errors.Wrap(err, "scanAllMObjects")
|
||||
}
|
||||
group, ctx := errgroup.WithContext(ctx)
|
||||
collection := make([][]SSimpleVM, len(hosts))
|
||||
for i := range hosts {
|
||||
j := i
|
||||
group.Go(func() error {
|
||||
vmIps, err := cli.vmIPs(&hosts[j], dvpgKeyVlanMap)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
collection[j] = vmIps
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
hostIps := make(map[string]string, len(hosts))
|
||||
for i := range hosts {
|
||||
// find ip
|
||||
host := &SHost{SManagedObject: newManagedObject(cli, &hosts[i], nil)}
|
||||
ip := host.GetAccessIp()
|
||||
hostIps[host.GetName()] = ip
|
||||
}
|
||||
err = group.Wait()
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
// length
|
||||
length := 0
|
||||
for i := range collection {
|
||||
length += len(collection[i])
|
||||
}
|
||||
svms := make([]SSimpleVM, 0, length)
|
||||
for i := range collection {
|
||||
for j := range collection[i] {
|
||||
svms = append(svms, collection[i][j])
|
||||
}
|
||||
}
|
||||
return hostIps, svms, nil
|
||||
return cli.hostVMIPs(ctx, hosts)
|
||||
}
|
||||
|
||||
func (cli *SESXiClient) macVlanMap(movm mo.VirtualMachine, dvpgKeyVlanMap *sync.Map) map[string]int32 {
|
||||
func (cli *SESXiClient) macVlanMap(mohost *mo.HostSystem, movm *mo.VirtualMachine, dvpgMap sVPGMap) map[string]int32 {
|
||||
vpgMap := cli.getVPGMap(mohost)
|
||||
ret := make(map[string]int32, 2)
|
||||
for _, device := range movm.Config.Hardware.Device {
|
||||
bcard, ok := device.(types.BaseVirtualEthernetCard)
|
||||
@@ -845,34 +852,52 @@ func (cli *SESXiClient) macVlanMap(movm mo.VirtualMachine, dvpgKeyVlanMap *sync.
|
||||
}
|
||||
card := bcard.GetVirtualEthernetCard()
|
||||
mac := card.MacAddress
|
||||
dvpgBackInfo, ok := card.Backing.(*types.VirtualEthernetCardDistributedVirtualPortBackingInfo)
|
||||
if !ok {
|
||||
switch bk := card.Backing.(type) {
|
||||
case *types.VirtualEthernetCardDistributedVirtualPortBackingInfo:
|
||||
key := bk.Port.PortgroupKey
|
||||
proc, ok := dvpgMap.Get(key)
|
||||
if !ok {
|
||||
log.Errorf("dvpg %s not found in key-vlanid map", key)
|
||||
ret[mac] = 0
|
||||
continue
|
||||
}
|
||||
ret[mac] = proc.vlanId
|
||||
case *types.VirtualEthernetCardNetworkBackingInfo:
|
||||
netName, err := cli.networkName(bk.Network.Value)
|
||||
if err != nil {
|
||||
log.Errorf("get getNetworkName of %q: %v", bk.Network.Value, err)
|
||||
ret[mac] = 0
|
||||
continue
|
||||
}
|
||||
key := fmt.Sprintf("%s-%s", mohost.Reference().Value, netName)
|
||||
proc, ok := vpgMap.Get(key)
|
||||
if !ok {
|
||||
log.Errorf("vpg %s not found in key-vlanid map", key)
|
||||
ret[mac] = 0
|
||||
continue
|
||||
}
|
||||
ret[mac] = proc.vlanId
|
||||
default:
|
||||
ret[mac] = 0
|
||||
continue
|
||||
}
|
||||
dvpgKey := dvpgBackInfo.Port.PortgroupKey
|
||||
value, ok := dvpgKeyVlanMap.Load(dvpgKey)
|
||||
if !ok {
|
||||
log.Errorf("dvpg %s not found in key-vlanid map", dvpgKey)
|
||||
ret[mac] = 0
|
||||
continue
|
||||
}
|
||||
vlanid := value.(int32)
|
||||
ret[mac] = vlanid
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (cli *SESXiClient) vmIPs(host *mo.HostSystem, dvpgKeyVlanMap *sync.Map) ([]SSimpleVM, error) {
|
||||
func (cli *SESXiClient) vmIPs(host *mo.HostSystem, vpgMap sVPGMap) (SNetworkInfo, error) {
|
||||
nInfo := SNetworkInfo{
|
||||
VMs: make([]SSimpleVM, 0, len(host.Vm)),
|
||||
VlanIps: make(map[int32][]netutils.IPV4Addr),
|
||||
IPPool: NewIPPool(),
|
||||
}
|
||||
if len(host.Vm) == 0 {
|
||||
return []SSimpleVM{}, nil
|
||||
return nInfo, nil
|
||||
}
|
||||
var vms []mo.VirtualMachine
|
||||
err := cli.references2Objects(host.Vm, SIMPLE_VM_PROPS, &vms)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "references2Objects")
|
||||
return nInfo, errors.Wrap(err, "references2Objects")
|
||||
}
|
||||
ret := make([]SSimpleVM, 0, len(vms))
|
||||
for i := range vms {
|
||||
vm := vms[i]
|
||||
if vm.Config == nil || vm.Config.Template {
|
||||
@@ -881,7 +906,7 @@ func (cli *SESXiClient) vmIPs(host *mo.HostSystem, dvpgKeyVlanMap *sync.Map) ([]
|
||||
if vm.Guest == nil {
|
||||
continue
|
||||
}
|
||||
macVlanMap := cli.macVlanMap(vm, dvpgKeyVlanMap)
|
||||
macVlanMap := cli.macVlanMap(host, &vm, vpgMap)
|
||||
guestIps := make([]SIPVlan, 0)
|
||||
for _, net := range vm.Guest.Net {
|
||||
if len(net.Network) == 0 {
|
||||
@@ -899,14 +924,19 @@ func (cli *SESXiClient) vmIPs(host *mo.HostSystem, dvpgKeyVlanMap *sync.Map) ([]
|
||||
if netutils.IsLinkLocal(ipaddr) {
|
||||
continue
|
||||
}
|
||||
vlan := macVlanMap[mac]
|
||||
guestIps = append(guestIps, SIPVlan{
|
||||
IP: ip,
|
||||
VlanID: macVlanMap[mac],
|
||||
IP: ipaddr,
|
||||
VlanId: vlan,
|
||||
})
|
||||
nInfo.VlanIps[vlan] = append(nInfo.VlanIps[vlan], ipaddr)
|
||||
nInfo.IPPool.Insert(ipaddr, SIPProc{
|
||||
VlanId: vlan,
|
||||
})
|
||||
break
|
||||
}
|
||||
}
|
||||
ret = append(ret, SSimpleVM{vm.Name, guestIps})
|
||||
nInfo.VMs = append(nInfo.VMs, SSimpleVM{vm.Name, guestIps})
|
||||
}
|
||||
return ret, nil
|
||||
return nInfo, nil
|
||||
}
|
||||
|
||||
@@ -15,11 +15,15 @@
|
||||
package esxi
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"sync"
|
||||
|
||||
"github.com/vmware/govmomi/object"
|
||||
"github.com/vmware/govmomi/vim25/mo"
|
||||
"github.com/vmware/govmomi/vim25/types"
|
||||
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/util/netutils"
|
||||
)
|
||||
|
||||
type IVMNetwork interface {
|
||||
@@ -261,3 +265,154 @@ func (net *SDistributedVirtualPortgroup) AddHostToDVS(host *SHost) (err error) {
|
||||
}
|
||||
return err
|
||||
}
|
||||
|
||||
type SVirtualSwitch struct {
|
||||
Name string
|
||||
Id string
|
||||
Distributed bool
|
||||
Hosts []string
|
||||
Vlans map[int32]SVirtualLan
|
||||
}
|
||||
|
||||
type SVirtualLan struct {
|
||||
Vlan int32
|
||||
Ips []netutils.IPV4Addr
|
||||
}
|
||||
|
||||
func (h *SHost) getVirtualSwitchs() []SVirtualSwitch {
|
||||
hs := h.getHostSystem()
|
||||
if hs.Config.Network == nil {
|
||||
return nil
|
||||
}
|
||||
vss := make([]SVirtualSwitch, 0, len(hs.Config.Network.Vswitch))
|
||||
vsMap := make(map[string]*SVirtualSwitch)
|
||||
for i := range hs.Config.Network.Vswitch {
|
||||
ivs := hs.Config.Network.Vswitch[i]
|
||||
vsId := fmt.Sprintf("%s-%s", h.GetId(), ivs.Name)
|
||||
vsName := ivs.Name
|
||||
vs := SVirtualSwitch{
|
||||
Name: vsName,
|
||||
Id: vsId,
|
||||
Distributed: false,
|
||||
}
|
||||
vss = append(vss, vs)
|
||||
vsMap[ivs.Name] = &vss[len(vss)-1]
|
||||
}
|
||||
for i := range hs.Config.Network.Portgroup {
|
||||
ipg := hs.Config.Network.Portgroup[i]
|
||||
vlan, vsName := ipg.Spec.VlanId, ipg.Spec.VswitchName
|
||||
ivs := vsMap[vsName]
|
||||
ivs.Vlans[vlan] = SVirtualLan{
|
||||
Vlan: vlan,
|
||||
}
|
||||
}
|
||||
return vss
|
||||
}
|
||||
|
||||
func (cli *SESXiClient) getVPGMap(mohost *mo.HostSystem) sVPGMap {
|
||||
sm := newVPGMap()
|
||||
if mohost.Config.Network == nil {
|
||||
return sm
|
||||
}
|
||||
for i := range mohost.Config.Network.Portgroup {
|
||||
ipg := mohost.Config.Network.Portgroup[i]
|
||||
key := fmt.Sprintf("%s-%s", mohost.Reference().Value, ipg.Spec.Name)
|
||||
vlan := ipg.Spec.VlanId
|
||||
sm.Insert(key, sVPGProc{
|
||||
vlanId: vlan,
|
||||
})
|
||||
// TODO: fill VSId
|
||||
}
|
||||
return sm
|
||||
}
|
||||
|
||||
func (cli *SESXiClient) getDVPGMap() (sVPGMap, error) {
|
||||
sm := newVPGMap()
|
||||
dvpgs, err := cli.scanAllDvPortgroups()
|
||||
if err != nil {
|
||||
return sm, err
|
||||
}
|
||||
for i := range dvpgs {
|
||||
key := dvpgs[i].getMODVPortgroup().Key
|
||||
vlanid := dvpgs[i].GetVlanId()
|
||||
sm.Insert(key, sVPGProc{
|
||||
vlanId: vlanid,
|
||||
})
|
||||
// TODO: fill VSId
|
||||
}
|
||||
return sm, nil
|
||||
}
|
||||
|
||||
func (cli *SESXiClient) getVirtualSwitchs() []SVirtualSwitch {
|
||||
// TODO
|
||||
return nil
|
||||
}
|
||||
|
||||
func newVPGMap() sVPGMap {
|
||||
return sVPGMap{m: &sync.Map{}}
|
||||
}
|
||||
|
||||
type sVPGMap struct {
|
||||
m *sync.Map
|
||||
}
|
||||
|
||||
func (vm *sVPGMap) Insert(key string, proc sVPGProc) {
|
||||
vm.m.Store(key, proc)
|
||||
}
|
||||
|
||||
func (vm *sVPGMap) Get(key string) (sVPGProc, bool) {
|
||||
v, ok := vm.m.Load(key)
|
||||
if !ok {
|
||||
return sVPGProc{}, ok
|
||||
}
|
||||
r := v.(sVPGProc)
|
||||
return r, ok
|
||||
}
|
||||
|
||||
type sVPGProc struct {
|
||||
vlanId int32
|
||||
dvId string
|
||||
}
|
||||
|
||||
type SIPProc struct {
|
||||
VSId string
|
||||
VlanId int32
|
||||
}
|
||||
|
||||
type SIPPool struct {
|
||||
p map[netutils.IPV4Addr]SIPProc
|
||||
}
|
||||
|
||||
func NewIPPool(length ...int) SIPPool {
|
||||
if len(length) > 0 {
|
||||
return SIPPool{p: make(map[netutils.IPV4Addr]SIPProc, length[0])}
|
||||
}
|
||||
return SIPPool{p: make(map[netutils.IPV4Addr]SIPProc)}
|
||||
}
|
||||
|
||||
func (p *SIPPool) Has(ip netutils.IPV4Addr) bool {
|
||||
_, ok := p.p[ip]
|
||||
return ok
|
||||
}
|
||||
|
||||
func (p *SIPPool) Get(ip netutils.IPV4Addr) (SIPProc, bool) {
|
||||
r, ok := p.p[ip]
|
||||
return r, ok
|
||||
}
|
||||
|
||||
func (p *SIPPool) Insert(ip netutils.IPV4Addr, proc SIPProc) {
|
||||
p.p[ip] = proc
|
||||
}
|
||||
|
||||
func (p *SIPPool) Merge(op *SIPPool) {
|
||||
for ip, proc := range op.p {
|
||||
if p.Has(ip) {
|
||||
continue
|
||||
}
|
||||
p.Insert(ip, proc)
|
||||
}
|
||||
}
|
||||
|
||||
func (p *SIPPool) Len() int {
|
||||
return len(p.p)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user