feat(esxiagent): determine vs by bridge and network when creating vm

This commit is contained in:
rainzm
2020-12-30 09:52:03 +08:00
parent 0aa5c2ef1c
commit 639e7b16f0
3 changed files with 195 additions and 21 deletions
+2 -1
View File
@@ -3,8 +3,9 @@ package models
import (
"context"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
)
type wireIdChangeArgs struct {
+53 -20
View File
@@ -137,24 +137,65 @@ func NewUSBController(key *int32) types.BaseVirtualDevice {
return &device
}
var getNetwork func(bridge, vlanId string) (IVMNetwork, error)
func NewVNICDev(host *SHost, mac, driver string, bridge string, vlanId int32, key, ctlKey, index int32) (types.BaseVirtualDevice, error) {
desc := types.Description{Label: fmt.Sprintf("Network adapter %d", index+1), Summary: "VM Network"}
var inet IVMNetwork
var err error
if (vlanId == 0 || vlanId == 1) && len(bridge) > 0 {
inet, err = host.findDVPGById(bridge)
newGetNetwork := func(bridge string, vlanId int32) (IVMNetwork, error) {
if len(bridge) == 0 {
log.Warningf("empty bridge for host %s, vlanId %d, mac %s", host.GetGlobalId(), vlanId, mac)
return nil, nil
}
vs, err := findVirtualSwitch(host, bridge)
if err != nil {
log.Errorf("fail to find dvportgroup by name %s: %s", bridge, err)
return nil, errors.Wrapf(err, "findVirtualSwitch for host %s bridge %s", host.GetGlobalId(), bridge)
}
if vs == nil {
log.Infof("can't find vs via host %s, bridge %s", host.GetId(), bridge)
return nil, nil
}
network, err := vs.FindNetworkByVlanID(vlanId)
if err != nil {
return nil, errors.Wrapf(err, "FindNetworkByVlanID for vlanId %q", vlanId)
}
return network, nil
}
oldGetNework := func(bridge string, vlanId int32) (IVMNetwork, error) {
var inet IVMNetwork
var err error
if (vlanId == 0 || vlanId == 1) && len(bridge) > 0 {
inet, err = host.findDVPGById(bridge)
if err != nil {
log.Errorf("fail to find dvportgroup by name %s: %s", bridge, err)
}
}
if inet == nil || reflect.ValueOf(inet).IsNil() {
inet, err = host.FindNetworkByVlanID(vlanId)
if err != nil {
log.Errorf("fail to find network by vlanid %d: %s", vlanId, err)
}
}
if inet == nil || reflect.ValueOf(inet).IsNil() {
return nil, nil
}
return inet, nil
}
inet, err := newGetNetwork(bridge, vlanId)
if err != nil {
return nil, err
}
if inet == nil {
log.Infof("no find network via new method")
inet, err = oldGetNework(bridge, vlanId)
if err != nil {
return nil, err
}
}
if inet == nil || reflect.ValueOf(inet).IsNil() {
inet, err = host.FindNetworkByVlanID(vlanId)
if err != nil {
log.Errorf("fail to find network by vlanid %d: %s", vlanId, err)
}
}
if inet == nil || reflect.ValueOf(inet).IsNil() {
if inet == nil {
return nil, errors.Error(fmt.Sprintf("Brige %s VLAN %d not found", bridge, vlanId))
}
@@ -165,14 +206,6 @@ func NewVNICDev(host *SHost, mac, driver string, bridge string, vlanId int32, ke
var backing types.BaseVirtualDeviceBackingInfo
switch inet.(type) {
case *SDistributedVirtualPortgroup:
// net := inet.(*SDistributedVirtualPortgroup)
// port, err := net.FindPort()
//if err != nil {
// return nil, errors.Wrap(err, "net.FindPort")
// }
// if port == nil {
// return nil, fmt.Errorf("no active port for dvportgroup %q", net.GetName())
// }
net := inet.(*SDistributedVirtualPortgroup)
dvpg := net.getMODVPortgroup()
uuid, err := net.GetDVSUuid()
+140
View File
@@ -0,0 +1,140 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package esxi
import (
"regexp"
"github.com/vmware/govmomi/property"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
"yunion.io/x/pkg/errors"
)
var DVS_PROPS = []string{"name"}
type IVirtualSwitch interface {
FindNetworkByVlanID(vlanID int32) (IVMNetwork, error)
}
type SVirtualSwitch struct {
Host *SHost
HostVirtualSwitch types.HostVirtualSwitch
}
func (vs *SVirtualSwitch) FindNetworkByVlanID(vlanID int32) (IVMNetwork, error) {
vsKey := vs.HostVirtualSwitch.Key
pgs := vs.Host.getHostSystem().Config.Network.Portgroup
var networkName string
for i := range pgs {
if pgs[i].Vswitch != vsKey {
continue
}
if vlanEqual(pgs[i].Spec.VlanId, vlanID) {
networkName = pgs[i].Spec.Name
break
}
}
if len(networkName) == 0 {
return nil, nil
}
networks, err := vs.Host.GetNetworks()
if err != nil {
return nil, errors.Wrapf(err, "can't get networks of host %q", vs.Host.GetGlobalId())
}
for i := range networks {
if networks[i].GetName() == networkName {
return networks[i], nil
}
}
return nil, nil
}
type SDistributedVirtualSwitch struct {
Host *SHost
DistributedVirtualSwitch mo.DistributedVirtualSwitch
}
func (vs *SDistributedVirtualSwitch) FindNetworkByVlanID(vlanID int32) (IVMNetwork, error) {
var modvpgs []mo.DistributedVirtualPortgroup
filter := property.Filter{}
filter["config.distributedVirtualSwitch"] = vs.DistributedVirtualSwitch.Self
err := vs.Host.manager.scanMObjectsWithFilter(vs.Host.datacenter.object.Entity().Self, DVPORTGROUP_PROPS, &modvpgs, filter)
if err != nil {
return nil, errors.Wrapf(err, "can't fetch portgroup of DistributedVirtualSwitch %q", vs.DistributedVirtualSwitch.Name)
}
dvpgs := make([]*SDistributedVirtualPortgroup, 0, len(modvpgs))
for i := range modvpgs {
dvpgs = append(dvpgs, NewDistributedVirtualPortgroup(vs.Host.manager, &modvpgs[i], nil))
}
for i := range dvpgs {
if vlanEqual(dvpgs[i].GetVlanId(), vlanID) {
return dvpgs[i], nil
}
}
return nil, nil
}
func vlanEqual(v1, v2 int32) bool {
if v1 <= 1 && v2 <= 1 {
return true
}
return v1 == v2
}
var (
vsBridgeRegex = regexp.MustCompile(`^(host-\d+)/(.*)`)
dvsBridgeRegex = regexp.MustCompile(`^dvs-\d+$`)
)
// config.distributedVirtualSwitch
func findVirtualSwitch(host *SHost, bridge string) (IVirtualSwitch, error) {
group := vsBridgeRegex.FindStringSubmatch(bridge)
oHost := host.getHostSystem()
if len(group) > 0 {
// vswitch
vsName := group[2]
for _, vs := range oHost.Config.Network.Vswitch {
if vs.Name != vsName {
continue
}
return &SVirtualSwitch{
Host: host,
HostVirtualSwitch: vs,
}, nil
}
return nil, nil
}
// distributed vswitch
if !dvsBridgeRegex.MatchString(bridge) {
return nil, nil
}
objRef := types.ManagedObjectReference{
Type: "VmwareDistributedVirtualSwitch",
Value: bridge,
}
var dvs mo.DistributedVirtualSwitch
err := host.manager.reference2Object(objRef, DVS_PROPS, &dvs)
if err != nil {
return nil, errors.Wrapf(err, "can't fetch DistributedVirtualSwitch %q", objRef.String())
}
return &SDistributedVirtualSwitch{
Host: host,
DistributedVirtualSwitch: dvs,
}, nil
}