yunion.io/x/cloudmux@v0.3.10-0-alpha.1/pkg/multicloud/esxi/net_topology.go (about)

     1  // Copyright 2019 Yunion
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package esxi
    16  
    17  import (
    18  	"context"
    19  	"sort"
    20  
    21  	"github.com/vmware/govmomi/vim25/mo"
    22  	"golang.org/x/sync/errgroup"
    23  
    24  	"yunion.io/x/pkg/errors"
    25  	"yunion.io/x/pkg/util/netutils"
    26  	"yunion.io/x/pkg/util/regutils"
    27  )
    28  
    29  func (cli *SESXiClient) HostVmIPsInDc(ctx context.Context, dc *SDatacenter) (SNetworkInfo, error) {
    30  	var hosts []mo.HostSystem
    31  	err := cli.scanMObjects(dc.object.Entity().Self, HOST_SYSTEM_PROPS, &hosts)
    32  	if err != nil {
    33  		return SNetworkInfo{}, errors.Wrap(err, "scanMObjects")
    34  	}
    35  	return cli.hostVMIPs(ctx, hosts)
    36  }
    37  
    38  func (cli *SESXiClient) HostVmIPsInCluster(ctx context.Context, cluster *SCluster) (SNetworkInfo, error) {
    39  	var hosts []mo.HostSystem
    40  	err := cli.scanMObjects(cluster.object.Entity().Self, HOST_SYSTEM_PROPS, &hosts)
    41  	if err != nil {
    42  		return SNetworkInfo{}, errors.Wrap(err, "scanMObjects")
    43  	}
    44  	return cli.hostVMIPs(ctx, hosts)
    45  }
    46  
    47  type SNetworkInfo struct {
    48  	SNetworkInfoBase
    49  
    50  	HostIps map[string]netutils.IPV4Addr
    51  	VlanIps map[int32][]netutils.IPV4Addr
    52  }
    53  
    54  func (s *SNetworkInfo) Insert(proc SIPProc, ip netutils.IPV4Addr) {
    55  	s.SNetworkInfoBase.Insert(proc, ip)
    56  	s.VlanIps[proc.VlanId] = append(s.VlanIps[proc.VlanId], ip)
    57  }
    58  
    59  func (cli *SESXiClient) hostVMIPs(ctx context.Context, hosts []mo.HostSystem) (SNetworkInfo, error) {
    60  	ret := SNetworkInfo{}
    61  	dvpgMap, err := cli.getDVPGMap()
    62  	if err != nil {
    63  		return ret, errors.Wrap(err, "unable to get dvpgKeyVlanMap")
    64  	}
    65  	group, ctx := errgroup.WithContext(ctx)
    66  	collection := make([]*SNetworkInfo, len(hosts))
    67  	for i := range hosts {
    68  		j := i
    69  		group.Go(func() error {
    70  			nInfo, err := cli.vmIPs(&hosts[j], dvpgMap)
    71  			if err != nil {
    72  				return err
    73  			}
    74  			collection[j] = nInfo.(*SNetworkInfo)
    75  			return nil
    76  		})
    77  	}
    78  
    79  	hostIps := make(map[string]netutils.IPV4Addr, len(hosts))
    80  	for i := range hosts {
    81  		// find ip
    82  		host := &SHost{SManagedObject: newManagedObject(cli, &hosts[i], nil)}
    83  		ipStr := host.GetAccessIp()
    84  		ip, err := netutils.NewIPV4Addr(ipStr)
    85  		if err != nil {
    86  			return ret, errors.Wrapf(err, "invalid host ip %q", ipStr)
    87  		}
    88  		hostIps[host.GetName()] = ip
    89  	}
    90  	err = group.Wait()
    91  	if err != nil {
    92  		return ret, err
    93  	}
    94  	// length
    95  	if len(collection) == 0 {
    96  		ret.HostIps = hostIps
    97  		return ret, nil
    98  	}
    99  	ni := cli.mergeNetworInfo(collection)
   100  	ni.HostIps = hostIps
   101  	return ni, nil
   102  }
   103  
   104  func (cli *SESXiClient) mergeNetworInfo(nInfos []*SNetworkInfo) SNetworkInfo {
   105  	var vmsLen, vlanIpLen, ipPoolLen int
   106  	for i := range nInfos {
   107  		vmsLen += len(nInfos[i].VMs)
   108  		vlanIpLen += len(nInfos[i].VlanIps)
   109  		ipPoolLen += nInfos[i].IPPool.Len()
   110  	}
   111  	ret := SNetworkInfo{
   112  		SNetworkInfoBase: SNetworkInfoBase{
   113  			IPPool: NewIPPool(ipPoolLen),
   114  			VMs:    make([]SSimpleVM, 0, vmsLen),
   115  		},
   116  		VlanIps: make(map[int32][]netutils.IPV4Addr, vlanIpLen),
   117  	}
   118  	for i := range nInfos {
   119  		ret.VMs = append(ret.VMs, nInfos[i].VMs...)
   120  		for vlan, ips := range nInfos[i].VlanIps {
   121  			ret.VlanIps[vlan] = append(ret.VlanIps[vlan], ips...)
   122  		}
   123  		ret.IPPool.Merge(&nInfos[i].IPPool)
   124  	}
   125  	for _, ips := range ret.VlanIps {
   126  		sort.Slice(ips, func(i, j int) bool {
   127  			return ips[i] < ips[j]
   128  		})
   129  	}
   130  	return ret
   131  }
   132  
   133  func (cli *SESXiClient) HostVmIPs(ctx context.Context) (SNetworkInfo, error) {
   134  	var hosts []mo.HostSystem
   135  	err := cli.scanAllMObjects(SIMPLE_HOST_PROPS, &hosts)
   136  	if err != nil {
   137  		return SNetworkInfo{}, errors.Wrap(err, "scanAllMObjects")
   138  	}
   139  	return cli.hostVMIPs(ctx, hosts)
   140  }
   141  
   142  func (cli *SESXiClient) vmIPs(host *mo.HostSystem, vpgMap sVPGMap) (INetworkInfo, error) {
   143  	nInfo := NewNetworkInfo(false, len(host.Vm))
   144  	if len(host.Vm) == 0 {
   145  		return nInfo, nil
   146  	}
   147  	var vms []mo.VirtualMachine
   148  	err := cli.references2Objects(host.Vm, SIMPLE_VM_PROPS, &vms)
   149  	if err != nil {
   150  		return nInfo, errors.Wrap(err, "references2Objects")
   151  	}
   152  	for i := range vms {
   153  		vm := vms[i]
   154  		if vm.Config == nil || vm.Config.Template {
   155  			continue
   156  		}
   157  		if vm.Guest == nil {
   158  			continue
   159  		}
   160  		macVlanMap, err := cli.macVlanMap(host, &vm, vpgMap)
   161  		if err != nil {
   162  			return nInfo, errors.Wrap(err, "macVlanMap")
   163  		}
   164  		guestIps := make([]SIPVlan, 0)
   165  		for _, net := range vm.Guest.Net {
   166  			if len(net.Network) == 0 {
   167  				continue
   168  			}
   169  			mac := net.MacAddress
   170  			for _, ip := range net.IpAddress {
   171  				if !regutils.MatchIP4Addr(ip) {
   172  					continue
   173  				}
   174  				if !vmIPV4Filter.Contains(ip) {
   175  					continue
   176  				}
   177  				ipaddr, _ := netutils.NewIPV4Addr(ip)
   178  				if netutils.IsLinkLocal(ipaddr) {
   179  					continue
   180  				}
   181  				proc := macVlanMap[mac]
   182  				guestIps = append(guestIps, SIPVlan{
   183  					IP:     ipaddr,
   184  					VlanId: proc.VlanId,
   185  				})
   186  				nInfo.Insert(proc, ipaddr)
   187  				break
   188  			}
   189  		}
   190  		nInfo.AppendVMs(vm.Name, guestIps)
   191  	}
   192  	return nInfo, nil
   193  }