mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-19 10:46:58 +08:00
fix: prepare esxi host network revisit (#15832)
Co-authored-by: Qiu Jian <qiujian@yunionyun.com>
This commit is contained in:
@@ -208,6 +208,9 @@ type CloudaccountCreateInput struct {
|
||||
ReadOnly bool `json:"read_only"`
|
||||
|
||||
SProjectMappingResourceInput
|
||||
|
||||
// 是否立即开始同步资源
|
||||
StartSync *bool `json:"start_sync"`
|
||||
}
|
||||
|
||||
type SProjectMappingResourceInput struct {
|
||||
|
||||
@@ -32,6 +32,8 @@ const (
|
||||
CLOUD_PROVIDER_DELETE_FAILED = "delete_failed"
|
||||
CLOUD_PROVIDER_SYNC_NETWORK = "sync_network"
|
||||
|
||||
CLOUD_PROVIDER_SYNC_NETWORK_FAILED = "sync_net_failed"
|
||||
|
||||
CLOUD_PROVIDER_SYNC_STATUS_QUEUING = "queuing"
|
||||
CLOUD_PROVIDER_SYNC_STATUS_QUEUED = "queued"
|
||||
CLOUD_PROVIDER_SYNC_STATUS_SYNCING = "syncing"
|
||||
|
||||
@@ -0,0 +1,329 @@
|
||||
// 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 models
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/esxi"
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/tristate"
|
||||
"yunion.io/x/pkg/util/netutils"
|
||||
"yunion.io/x/pkg/util/rbacscope"
|
||||
"yunion.io/x/pkg/utils"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/compute/options"
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
)
|
||||
|
||||
type CASimpleNetConf struct {
|
||||
IpStart string `json:"guest_ip_start"`
|
||||
IpEnd string `json:"guest_ip_end"`
|
||||
IpMask int8 `json:"guest_ip_mask"`
|
||||
Gateway string `json:"guest_gateway"`
|
||||
VlanID int32 `json:"vlan_id"`
|
||||
}
|
||||
|
||||
type CANetConf struct {
|
||||
CASimpleNetConf
|
||||
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
type CAPWire struct {
|
||||
VsId string
|
||||
WireId string
|
||||
Name string
|
||||
Distributed bool
|
||||
Description string
|
||||
Hosts []esxi.SSimpleHostDev
|
||||
HostNetworks []CANetConf
|
||||
// GuestNetworks []CANetConf
|
||||
}
|
||||
|
||||
var ipMaskLen int8 = 24
|
||||
|
||||
func (account *SCloudaccount) PrepareEsxiHostNetwork(ctx context.Context, userCred mcclient.TokenCredential) error {
|
||||
cProvider, err := account.GetProvider(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "account.GetProvider")
|
||||
}
|
||||
// fetch esxiclient
|
||||
iregion, err := cProvider.GetOnPremiseIRegion()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "cProvider.GetOnPremiseIRegion")
|
||||
}
|
||||
esxiClient, ok := iregion.(*esxi.SESXiClient)
|
||||
if !ok {
|
||||
return errors.Wrap(httperrors.ErrNotSupported, "not a esxi provider")
|
||||
}
|
||||
// check network
|
||||
nInfo, err := esxiClient.HostVmIPsPro(ctx)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "esxiClient.HostVmIPsPro")
|
||||
}
|
||||
log.Infof("HostVmIPsPro: %s", jsonutils.Marshal(nInfo).String())
|
||||
|
||||
capWires := make([]CAPWire, 0)
|
||||
vsList := nInfo.VsMap.List()
|
||||
log.Infof("vsList: %s", jsonutils.Marshal(vsList))
|
||||
|
||||
onPremiseNets, err := NetworkManager.fetchAllOnpremiseNetworks("", tristate.None)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "NetworkManager.fetchAllOnpremiseNetworks")
|
||||
}
|
||||
|
||||
zoneId, err := guessEsxiZoneId(vsList, onPremiseNets)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fail to find zone of esxi")
|
||||
}
|
||||
|
||||
desc := fmt.Sprintf("Auto create for cloudaccount %q", account.Name)
|
||||
for i := range vsList {
|
||||
vs := vsList[i]
|
||||
wireName := fmt.Sprintf("%s/%s", account.Name, vs.Name)
|
||||
capWire, err := guessEsxiNetworks(vs, wireName, onPremiseNets)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "guessEsxiNetworks")
|
||||
}
|
||||
if len(capWire.WireId) == 0 {
|
||||
capWire.Description = desc
|
||||
}
|
||||
capWires = append(capWires, *capWire)
|
||||
}
|
||||
log.Infof("capWires: %v", capWires)
|
||||
host2Wire, err := account.createNetworks(ctx, zoneId, capWires)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "account.createNetworks")
|
||||
}
|
||||
err = account.SetHost2Wire(ctx, userCred, host2Wire)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "account.SetHost2Wire")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func guessEsxiZoneId(vsList []esxi.SVirtualSwitchSpec, onPremiseNets []SNetwork) (string, error) {
|
||||
zoneIds, err := ZoneManager.getOnpremiseZoneIds()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "getOnpremiseZoneIds")
|
||||
}
|
||||
if len(zoneIds) == 1 {
|
||||
return zoneIds[0], nil
|
||||
} else if len(zoneIds) == 0 {
|
||||
return "", errors.Wrap(httperrors.ErrNotFound, "no valid on-premise zone")
|
||||
}
|
||||
// there are multiple zones
|
||||
zoneIds = make([]string, 0)
|
||||
for i := range vsList {
|
||||
vs := vsList[i]
|
||||
for _, ips := range vs.HostIps {
|
||||
for _, ip := range ips {
|
||||
for _, net := range onPremiseNets {
|
||||
if net.IsAddressInRange(ip) || net.IsAddressInNet(ip) {
|
||||
zone, _ := net.GetZone()
|
||||
if zone != nil && !utils.IsInStringArray(zone.Id, zoneIds) {
|
||||
zoneIds = append(zoneIds, zone.Id)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(zoneIds) == 0 {
|
||||
// no any clue
|
||||
return "", errors.Wrap(httperrors.ErrNotFound, "no valid on-premise networks")
|
||||
}
|
||||
if len(zoneIds) > 1 {
|
||||
// network span multiple zones
|
||||
return "", errors.Wrap(httperrors.ErrConflict, "spans multiple zones?")
|
||||
}
|
||||
return zoneIds[0], nil
|
||||
}
|
||||
|
||||
type sIpv4List []netutils.IPV4Addr
|
||||
|
||||
func (a sIpv4List) Len() int { return len(a) }
|
||||
func (a sIpv4List) Swap(i, j int) { a[i], a[j] = a[j], a[i] }
|
||||
func (a sIpv4List) Less(i, j int) bool { return uint32(a[i]) < uint32(a[j]) }
|
||||
|
||||
func guessEsxiNetworks(vs esxi.SVirtualSwitchSpec, wireName string, onPremiseNets []SNetwork) (*CAPWire, error) {
|
||||
capWire := CAPWire{
|
||||
Name: wireName,
|
||||
VsId: vs.Id,
|
||||
Distributed: vs.Distributed,
|
||||
Hosts: vs.Hosts,
|
||||
}
|
||||
ipList := make([]netutils.IPV4Addr, 0)
|
||||
for _, ips := range vs.HostIps {
|
||||
for j := 0; j < len(ips); j++ {
|
||||
var net *SNetwork
|
||||
for _, n := range onPremiseNets {
|
||||
if n.IsAddressInRange(ips[j]) {
|
||||
// already covered by existing network
|
||||
net = &n
|
||||
break
|
||||
}
|
||||
}
|
||||
if net != nil {
|
||||
// found a network contains this IP, no need to create
|
||||
if len(capWire.WireId) > 0 && capWire.WireId != net.WireId {
|
||||
return nil, errors.Wrapf(httperrors.ErrConflict, "%s seems attaching conflict wires %s and %s", wireName, capWire.WireId, net.WireId)
|
||||
}
|
||||
capWire.WireId = net.WireId
|
||||
continue
|
||||
}
|
||||
ipList = append(ipList, ips[j])
|
||||
}
|
||||
}
|
||||
if len(ipList) == 0 {
|
||||
return &capWire, nil
|
||||
}
|
||||
sort.Sort(sIpv4List(ipList))
|
||||
for i := 0; i < len(ipList); {
|
||||
simNetConfs := CASimpleNetConf{}
|
||||
var net *SNetwork
|
||||
for _, n := range onPremiseNets {
|
||||
if n.IsAddressInNet(ipList[i]) {
|
||||
// already covered by existing network
|
||||
net = &n
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if net != nil {
|
||||
if len(capWire.WireId) > 0 && capWire.WireId != net.WireId {
|
||||
return nil, errors.Wrapf(httperrors.ErrConflict, "%s seems attaching conflict wires %s and %s", wireName, capWire.WireId, net.WireId)
|
||||
}
|
||||
capWire.WireId = net.WireId
|
||||
simNetConfs.Gateway = net.GuestGateway
|
||||
simNetConfs.IpMask = net.GuestIpMask
|
||||
} else {
|
||||
simNetConfs.Gateway = (ipList[i].NetAddr(ipMaskLen) + netutils.IPV4Addr(options.Options.DefaultNetworkGatewayAddressEsxi)).String()
|
||||
simNetConfs.IpMask = ipMaskLen
|
||||
}
|
||||
netRange := netutils.NewIPV4AddrRange(ipList[i].NetAddr(simNetConfs.IpMask), ipList[i].BroadcastAddr(simNetConfs.IpMask))
|
||||
j := i
|
||||
for j < len(ipList)-1 {
|
||||
if ipList[j]+1 == ipList[j+1] && netRange.Contains(ipList[j+1]) {
|
||||
j++
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
simNetConfs.IpStart = ipList[i].String()
|
||||
simNetConfs.IpEnd = ipList[j].String()
|
||||
i = j + 1
|
||||
capWire.HostNetworks = append(capWire.HostNetworks, CANetConf{
|
||||
Name: fmt.Sprintf("%s-host-network-%d", wireName, len(capWire.HostNetworks)+1),
|
||||
Description: fmt.Sprintf("Auto create for cloudaccount %q", wireName),
|
||||
CASimpleNetConf: simNetConfs,
|
||||
})
|
||||
}
|
||||
return &capWire, nil
|
||||
}
|
||||
|
||||
func (account *SCloudaccount) createNetworks(ctx context.Context, zoneId string, capWires []CAPWire) (map[string][]SVs2Wire, error) {
|
||||
var err error
|
||||
ret := make(map[string][]SVs2Wire)
|
||||
for i := range capWires {
|
||||
// if len(capWires[i].GuestNetworks)+len(capWires[i].HostNetworks) == 0 {
|
||||
if len(capWires[i].HostNetworks) == 0 {
|
||||
continue
|
||||
}
|
||||
var wireId = capWires[i].WireId
|
||||
if len(wireId) == 0 {
|
||||
wireId, err = account.createWire(ctx, api.DEFAULT_VPC_ID, zoneId, capWires[i].Name, capWires[i].Description)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "can't create wire %s", capWires[i].Name)
|
||||
}
|
||||
capWires[i].WireId = wireId
|
||||
}
|
||||
for _, net := range capWires[i].HostNetworks {
|
||||
err := account.createNetwork(ctx, wireId, api.NETWORK_TYPE_BAREMETAL, net)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "can't create network %v", net)
|
||||
}
|
||||
}
|
||||
for _, host := range capWires[i].Hosts {
|
||||
ret[host.Id] = append(ret[host.Id], SVs2Wire{
|
||||
VsId: capWires[i].VsId,
|
||||
WireId: capWires[i].WireId,
|
||||
Distributed: capWires[i].Distributed,
|
||||
Mac: host.Mac,
|
||||
})
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// NETWORK_TYPE_GUEST = "guest"
|
||||
// NETWORK_TYPE_BAREMETAL = "baremetal"
|
||||
func (account *SCloudaccount) createNetwork(ctx context.Context, wireId, networkType string, net CANetConf) error {
|
||||
network := &SNetwork{}
|
||||
network.Name = net.Name
|
||||
if hint, err := NetworkManager.NewIfnameHint(net.Name); err != nil {
|
||||
log.Errorf("can't NewIfnameHint form hint %s", net.Name)
|
||||
} else {
|
||||
network.IfnameHint = hint
|
||||
}
|
||||
network.GuestIpStart = net.IpStart
|
||||
network.GuestIpEnd = net.IpEnd
|
||||
network.GuestIpMask = net.IpMask
|
||||
network.GuestGateway = net.Gateway
|
||||
network.VlanId = int(net.VlanID)
|
||||
network.WireId = wireId
|
||||
network.ServerType = networkType
|
||||
network.IsPublic = true
|
||||
network.Status = api.NETWORK_STATUS_AVAILABLE
|
||||
network.PublicScope = string(rbacscope.ScopeDomain)
|
||||
network.ProjectId = account.ProjectId
|
||||
network.DomainId = account.DomainId
|
||||
network.Description = net.Description
|
||||
|
||||
network.SetModelManager(NetworkManager, network)
|
||||
// TODO: Prevent IP conflict
|
||||
log.Infof("create network %s succussfully", network.Id)
|
||||
err := NetworkManager.TableSpec().Insert(ctx, network)
|
||||
return err
|
||||
}
|
||||
|
||||
func (account *SCloudaccount) createWire(ctx context.Context, vpcId, zoneId, wireName, desc string) (string, error) {
|
||||
wire := &SWire{
|
||||
Bandwidth: 10000,
|
||||
Mtu: 1500,
|
||||
}
|
||||
wire.VpcId = vpcId
|
||||
wire.ZoneId = zoneId
|
||||
wire.IsEmulated = false
|
||||
wire.Name = wireName
|
||||
wire.DomainId = account.GetOwnerId().GetDomainId()
|
||||
wire.Description = desc
|
||||
wire.Status = api.WIRE_STATUS_AVAILABLE
|
||||
wire.SetModelManager(WireManager, wire)
|
||||
err := WireManager.TableSpec().Insert(ctx, wire)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
log.Infof("create wire %s succussfully", wire.GetId())
|
||||
return wire.GetId(), nil
|
||||
}
|
||||
@@ -585,20 +585,13 @@ func (self *SCloudaccount) PostCreate(ctx context.Context, userCred mcclient.Tok
|
||||
self.SEnabledStatusInfrasResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
|
||||
self.savePassword(self.Secret)
|
||||
|
||||
if self.Enabled.IsTrue() {
|
||||
if self.Provider == api.CLOUD_PROVIDER_VMWARE {
|
||||
zone, _ := data.GetString("zone")
|
||||
self.StartSyncVMwareNetworkTask(ctx, userCred, "", zone)
|
||||
} else {
|
||||
self.StartSyncCloudProviderInfoTask(ctx, userCred, nil, "")
|
||||
}
|
||||
if self.Enabled.IsTrue() && jsonutils.QueryBoolean(data, "start_sync", true) {
|
||||
self.StartSyncCloudAccountInfoTask(ctx, userCred, nil, "")
|
||||
} else {
|
||||
self.SubmitSyncAccountTask(ctx, userCred, nil)
|
||||
}
|
||||
}
|
||||
|
||||
func (ca *SCloudaccount) PerformSyncVMwareNetwork(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CloudaccountSyncVMwareNetworkInput) (jsonutils.JSONObject, error) {
|
||||
return nil, ca.StartSyncVMwareNetworkTask(ctx, userCred, "", input.Zone)
|
||||
}
|
||||
|
||||
func (self *SCloudaccount) savePassword(secret string) error {
|
||||
sec, err := utils.EncryptAESBase64(self.Id, secret)
|
||||
if err != nil {
|
||||
@@ -630,7 +623,7 @@ func (self *SCloudaccount) PerformSync(ctx context.Context, userCred mcclient.To
|
||||
syncRange.DeepSync = true
|
||||
}
|
||||
if self.CanSync() || syncRange.Force {
|
||||
return nil, self.StartSyncCloudProviderInfoTask(ctx, userCred, &syncRange, "")
|
||||
return nil, self.StartSyncCloudAccountInfoTask(ctx, userCred, &syncRange, "")
|
||||
}
|
||||
return nil, httperrors.NewInvalidStatusError("Unable to synchronize frequently")
|
||||
}
|
||||
@@ -793,13 +786,13 @@ func (self *SCloudaccount) PerformUpdateCredential(ctx context.Context, userCred
|
||||
logclient.AddActionLogWithContext(ctx, self, logclient.ACT_UPDATE_CREDENTIAL, account.Account, userCred, true)
|
||||
|
||||
self.SetStatus(userCred, api.CLOUD_PROVIDER_INIT, "Change credential")
|
||||
self.StartSyncCloudProviderInfoTask(ctx, userCred, nil, "")
|
||||
self.StartSyncCloudAccountInfoTask(ctx, userCred, nil, "")
|
||||
}
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
func (self *SCloudaccount) StartSyncCloudProviderInfoTask(ctx context.Context, userCred mcclient.TokenCredential, syncRange *SSyncRange, parentTaskId string) error {
|
||||
func (self *SCloudaccount) StartSyncCloudAccountInfoTask(ctx context.Context, userCred mcclient.TokenCredential, syncRange *SSyncRange, parentTaskId string) error {
|
||||
params := jsonutils.NewDict()
|
||||
if syncRange != nil {
|
||||
params.Add(jsonutils.Marshal(syncRange), "sync_range")
|
||||
@@ -863,10 +856,10 @@ func (self *SCloudaccount) MarkEndSyncWithLock(ctx context.Context, userCred mcc
|
||||
return errors.Error("some cloud providers not idle")
|
||||
}
|
||||
|
||||
return self.markEndSync(userCred)
|
||||
return self.MarkEndSync(userCred)
|
||||
}
|
||||
|
||||
func (self *SCloudaccount) markEndSync(userCred mcclient.TokenCredential) error {
|
||||
func (self *SCloudaccount) MarkEndSync(userCred mcclient.TokenCredential) error {
|
||||
_, err := db.Update(self, func() error {
|
||||
self.SyncStatus = api.CLOUD_PROVIDER_SYNC_STATUS_IDLE
|
||||
self.LastSyncEndAt = timeutils.UtcNow()
|
||||
@@ -2228,7 +2221,7 @@ func (account *SCloudaccount) PerformPublic(ctx context.Context, userCred mcclie
|
||||
FullSync: true,
|
||||
},
|
||||
}
|
||||
account.StartSyncCloudProviderInfoTask(ctx, userCred, syncRange, "")
|
||||
account.StartSyncCloudAccountInfoTask(ctx, userCred, syncRange, "")
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
@@ -2262,7 +2255,7 @@ func (account *SCloudaccount) PerformPrivate(ctx context.Context, userCred mccli
|
||||
FullSync: true,
|
||||
},
|
||||
}
|
||||
account.StartSyncCloudProviderInfoTask(ctx, userCred, syncRange, "")
|
||||
account.StartSyncCloudAccountInfoTask(ctx, userCred, syncRange, "")
|
||||
|
||||
return nil, nil
|
||||
}
|
||||
@@ -2711,7 +2704,7 @@ func (self *SCloudaccount) PerformCreateSubscription(ctx context.Context, userCr
|
||||
}
|
||||
|
||||
syncRange := SSyncRange{}
|
||||
return nil, self.StartSyncCloudProviderInfoTask(ctx, userCred, &syncRange, "")
|
||||
return nil, self.StartSyncCloudAccountInfoTask(ctx, userCred, &syncRange, "")
|
||||
}
|
||||
|
||||
func (self *SCloudaccount) GetDnsZoneCaches() ([]SDnsZoneCache, error) {
|
||||
|
||||
@@ -31,7 +31,6 @@ import (
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/proxy"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
|
||||
"yunion.io/x/onecloud/pkg/compute/options"
|
||||
"yunion.io/x/onecloud/pkg/httperrors"
|
||||
"yunion.io/x/onecloud/pkg/mcclient"
|
||||
@@ -672,20 +671,3 @@ func (manager *SCloudaccountManager) suggestHostNetworks(ips []netutils.IPV4Addr
|
||||
})
|
||||
return ret
|
||||
}
|
||||
|
||||
func (ca *SCloudaccount) StartSyncVMwareNetworkTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string, networkZone string) error {
|
||||
if ca.Provider != api.CLOUD_PROVIDER_VMWARE {
|
||||
return errors.ErrNotSupported
|
||||
}
|
||||
params := jsonutils.NewDict()
|
||||
if len(networkZone) != 0 {
|
||||
params.Set("zone", jsonutils.NewString(networkZone))
|
||||
}
|
||||
task, err := taskman.TaskManager.NewTask(ctx, "CloudAccountSyncVMwareNetworkTask", ca, userCred, params, parentTaskId, "", nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
ca.SetStatus(userCred, api.CLOUD_PROVIDER_SYNC_NETWORK, "StartSyncVMwareNetworkTask")
|
||||
task.ScheduleRun(nil)
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ func (self *SNetwork) ValidateDeleteCondition(ctx context.Context, data *api.Net
|
||||
data.SNetworkNics = cnt
|
||||
}
|
||||
}
|
||||
if data.Total > 0 {
|
||||
if data.Total-data.ReserveVnics-data.NetworkinterfaceVnics > 0 {
|
||||
return httperrors.NewNotEmptyError("not an empty network %s", jsonutils.Marshal(data.SNetworkNics).String())
|
||||
}
|
||||
|
||||
@@ -273,12 +273,17 @@ func (self *SNetwork) GetIPRange() netutils.IPV4AddrRange {
|
||||
return self.getIPRange()
|
||||
}
|
||||
|
||||
func (self *SNetwork) getIPRange() netutils.IPV4AddrRange {
|
||||
start, _ := netutils.NewIPV4Addr(self.GuestIpStart)
|
||||
end, _ := netutils.NewIPV4Addr(self.GuestIpEnd)
|
||||
func (net *SNetwork) getIPRange() netutils.IPV4AddrRange {
|
||||
start, _ := netutils.NewIPV4Addr(net.GuestIpStart)
|
||||
end, _ := netutils.NewIPV4Addr(net.GuestIpEnd)
|
||||
return netutils.NewIPV4AddrRange(start, end)
|
||||
}
|
||||
|
||||
func (net *SNetwork) getNetRange() netutils.IPV4AddrRange {
|
||||
start, _ := netutils.NewIPV4Addr(net.GuestIpStart)
|
||||
return netutils.NewIPV4AddrRange(start.NetAddr(net.GuestIpMask), start.BroadcastAddr(net.GuestIpMask))
|
||||
}
|
||||
|
||||
func isIpUsed(ipstr string, addrTable map[string]bool, recentUsedAddrTable map[string]bool) bool {
|
||||
_, ok := addrTable[ipstr]
|
||||
if !ok {
|
||||
@@ -752,8 +757,12 @@ func (manager *SNetworkManager) newFromCloudNetwork(ctx context.Context, userCre
|
||||
return &net, nil
|
||||
}
|
||||
|
||||
func (self *SNetwork) IsAddressInRange(address netutils.IPV4Addr) bool {
|
||||
return self.getIPRange().Contains(address)
|
||||
func (net *SNetwork) IsAddressInRange(address netutils.IPV4Addr) bool {
|
||||
return net.getIPRange().Contains(address)
|
||||
}
|
||||
|
||||
func (net *SNetwork) IsAddressInNet(address netutils.IPV4Addr) bool {
|
||||
return net.getNetRange().Contains(address)
|
||||
}
|
||||
|
||||
func (self *SNetwork) isAddressUsed(address string) (bool, error) {
|
||||
@@ -770,17 +779,10 @@ func (self *SNetwork) isAddressUsed(address string) (bool, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (manager *SNetworkManager) GetOnPremiseNetworkOfIP(ipAddr string, serverType string, isPublic tristate.TriState) (*SNetwork, error) {
|
||||
address, err := netutils.NewIPV4Addr(ipAddr)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
func (manager *SNetworkManager) fetchAllOnpremiseNetworks(serverType string, isPublic tristate.TriState) ([]SNetwork, error) {
|
||||
q := manager.Query()
|
||||
wires := WireManager.Query().SubQuery()
|
||||
// vpcs := VpcManager.Query().SubQuery()
|
||||
q = q.Join(wires, sqlchemy.Equals(q.Field("wire_id"), wires.Field("id")))
|
||||
// q = q.Join(vpcs, sqlchemy.Equals(wires.Field("vpc_id"), vpcs.Field("id")))
|
||||
// q = q.Filter(sqlchemy.IsNullOrEmpty(vpcs.Field("manager_id")))
|
||||
q = q.Filter(sqlchemy.Equals(wires.Field("vpc_id"), api.DEFAULT_VPC_ID))
|
||||
if len(serverType) > 0 {
|
||||
q = q.Filter(sqlchemy.Equals(q.Field("server_type"), serverType))
|
||||
@@ -790,11 +792,22 @@ func (manager *SNetworkManager) GetOnPremiseNetworkOfIP(ipAddr string, serverTyp
|
||||
} else if isPublic.IsFalse() {
|
||||
q = q.Filter(sqlchemy.IsFalse(q.Field("is_public")))
|
||||
}
|
||||
|
||||
nets := make([]SNetwork, 0)
|
||||
err = db.FetchModelObjects(manager, q, &nets)
|
||||
err := db.FetchModelObjects(manager, q, &nets)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "FetchModelObjects")
|
||||
}
|
||||
return nets, nil
|
||||
}
|
||||
|
||||
func (manager *SNetworkManager) GetOnPremiseNetworkOfIP(ipAddr string, serverType string, isPublic tristate.TriState) (*SNetwork, error) {
|
||||
address, err := netutils.NewIPV4Addr(ipAddr)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "NewIPV4Addr")
|
||||
}
|
||||
nets, err := manager.fetchAllOnpremiseNetworks(serverType, isPublic)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "fetchAllOnpremiseNetworks")
|
||||
}
|
||||
for _, n := range nets {
|
||||
if n.IsAddressInRange(address) {
|
||||
@@ -2475,9 +2488,10 @@ func (self *SNetwork) CheckInvalidToMerge(ctx context.Context, net *SNetwork, al
|
||||
if self.VlanId != net.VlanId {
|
||||
failReason = append(failReason, "vlan_id")
|
||||
}
|
||||
if self.ServerType != net.ServerType {
|
||||
// Qiujian: allow merge networks of different server_type
|
||||
/*if self.ServerType != net.ServerType {
|
||||
failReason = append(failReason, "server_type")
|
||||
}
|
||||
}*/
|
||||
|
||||
if len(failReason) > 0 {
|
||||
err := httperrors.NewInputParameterError("Invalid Target Network %s: inconsist %s", net.GetId(), strings.Join(failReason, ","))
|
||||
|
||||
@@ -939,3 +939,7 @@ func (self *SZone) ClearSchedDescCache() error {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (manager *SZoneManager) getOnpremiseZoneIds() ([]string, error) {
|
||||
return zoneRegionFilter([]string{api.DEFAULT_REGION_ID})
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ import (
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
@@ -39,6 +40,24 @@ func init() {
|
||||
func (self *CloudAccountSyncInfoTask) OnInit(ctx context.Context, obj db.IStandaloneModel, body jsonutils.JSONObject) {
|
||||
cloudaccount := obj.(*models.SCloudaccount)
|
||||
|
||||
if cloudaccount.Provider == api.CLOUD_PROVIDER_VMWARE {
|
||||
cloudaccount.SetStatus(self.UserCred, api.CLOUD_PROVIDER_SYNC_NETWORK, "StartSyncVMwareNetworkTask")
|
||||
err := cloudaccount.PrepareEsxiHostNetwork(ctx, self.UserCred)
|
||||
if err != nil {
|
||||
d := jsonutils.NewDict()
|
||||
d.Set("error", jsonutils.NewString(err.Error()))
|
||||
db.OpsLog.LogEvent(cloudaccount, db.ACT_SYNC_NETWORK_FAILED, d, self.UserCred)
|
||||
cloudaccount.SetStatus(self.UserCred, api.CLOUD_PROVIDER_SYNC_NETWORK_FAILED, "sync network failed")
|
||||
logclient.AddActionLogWithStartable(self, cloudaccount, logclient.ACT_CLOUDACCOUNT_SYNC_NETWORK, d, self.UserCred, false)
|
||||
cloudaccount.MarkEndSync(self.UserCred)
|
||||
self.SetStageFailed(ctx, d)
|
||||
return
|
||||
} else {
|
||||
cloudaccount.SetStatus(self.UserCred, api.CLOUD_PROVIDER_INIT, "sync network sucess")
|
||||
logclient.AddActionLogWithStartable(self, cloudaccount, logclient.ACT_CLOUDACCOUNT_SYNC_NETWORK, cloudaccount.GetShortDesc(ctx), self.UserCred, true)
|
||||
}
|
||||
}
|
||||
|
||||
db.OpsLog.LogEvent(cloudaccount, db.ACT_SYNCING_HOST, "", self.UserCred)
|
||||
|
||||
self.SetStage("OnCloudaccountSyncReady", nil)
|
||||
|
||||
@@ -1,556 +0,0 @@
|
||||
// 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 tasks
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"sort"
|
||||
|
||||
"yunion.io/x/cloudmux/pkg/multicloud/esxi"
|
||||
"yunion.io/x/jsonutils"
|
||||
"yunion.io/x/log"
|
||||
"yunion.io/x/pkg/errors"
|
||||
"yunion.io/x/pkg/util/netutils"
|
||||
"yunion.io/x/pkg/util/rbacscope"
|
||||
|
||||
api "yunion.io/x/onecloud/pkg/apis/compute"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
||||
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
|
||||
"yunion.io/x/onecloud/pkg/compute/models"
|
||||
"yunion.io/x/onecloud/pkg/compute/options"
|
||||
"yunion.io/x/onecloud/pkg/util/logclient"
|
||||
)
|
||||
|
||||
type CloudAccountSyncVMwareNetworkTask struct {
|
||||
taskman.STask
|
||||
}
|
||||
|
||||
func init() {
|
||||
taskman.RegisterTask(CloudAccountSyncVMwareNetworkTask{})
|
||||
}
|
||||
|
||||
func (self *CloudAccountSyncVMwareNetworkTask) taskFailed(ctx context.Context, cloudaccount *models.SCloudaccount, desc string, err error) {
|
||||
log.Errorf("err: %v", err)
|
||||
d := jsonutils.NewDict()
|
||||
d.Set("description", jsonutils.NewString(desc))
|
||||
if err != nil {
|
||||
d.Set("error", jsonutils.NewString(err.Error()))
|
||||
}
|
||||
db.OpsLog.LogEvent(cloudaccount, db.ACT_SYNC_NETWORK_FAILED, d, self.UserCred)
|
||||
logclient.AddActionLogWithStartable(self, cloudaccount, logclient.ACT_CLOUDACCOUNT_SYNC_NETWORK, d, self.UserCred, false)
|
||||
self.SetStageFailed(ctx, nil)
|
||||
}
|
||||
|
||||
func (self *CloudAccountSyncVMwareNetworkTask) taskSuccess(ctx context.Context, cloudaccount *models.SCloudaccount, desc string) {
|
||||
d := jsonutils.NewString(desc)
|
||||
db.OpsLog.LogEvent(cloudaccount, db.ACT_SYNC_NETWORK, d, self.UserCred)
|
||||
logclient.AddActionLogWithStartable(self, cloudaccount, logclient.ACT_CLOUDACCOUNT_SYNC_NETWORK, d, self.UserCred, true)
|
||||
self.SetStageComplete(ctx, nil)
|
||||
}
|
||||
|
||||
func (self *CloudAccountSyncVMwareNetworkTask) OnInit(ctx context.Context, obj db.IStandaloneModel, body jsonutils.JSONObject) {
|
||||
cloudaccount := obj.(*models.SCloudaccount)
|
||||
// make sure zone
|
||||
zoneId, err := self.zoneId()
|
||||
if err != nil {
|
||||
self.taskFailed(ctx, cloudaccount, "unable to make sure zoneid", err)
|
||||
return
|
||||
}
|
||||
self.Params.Set("zoneId", jsonutils.NewString(zoneId))
|
||||
cProvider, err := cloudaccount.GetProvider(ctx)
|
||||
if err != nil {
|
||||
self.taskFailed(ctx, cloudaccount, "unable to GetProvider", err)
|
||||
return
|
||||
}
|
||||
// fetch esxiclient
|
||||
iregion, err := cProvider.GetOnPremiseIRegion()
|
||||
if err != nil {
|
||||
self.taskFailed(ctx, cloudaccount, "unable to GetOnPremiseIRegion", err)
|
||||
return
|
||||
}
|
||||
esxiClient := iregion.(*esxi.SESXiClient)
|
||||
// check network
|
||||
nInfo, err := esxiClient.HostVmIPsPro(ctx)
|
||||
if err != nil {
|
||||
self.taskFailed(ctx, cloudaccount, "unable to fetch HostVmIPs", err)
|
||||
return
|
||||
}
|
||||
log.Infof("nInfo: %s", jsonutils.Marshal(nInfo).String())
|
||||
// make sure wire and network existed
|
||||
wires, err := self.fetchWires(cloudaccount, zoneId)
|
||||
if err != nil {
|
||||
self.taskFailed(ctx, cloudaccount, "unable to fetch wires", err)
|
||||
return
|
||||
}
|
||||
existedIPPool, err := self.ipPool(cloudaccount, wires)
|
||||
if err != nil {
|
||||
self.taskFailed(ctx, cloudaccount, "uanble to structure existedIPPool", err)
|
||||
return
|
||||
}
|
||||
excludedIPPool, err := self.ipPool(nil, nil)
|
||||
if err != nil {
|
||||
self.taskFailed(ctx, cloudaccount, "unable to structure excludedIPPool", err)
|
||||
return
|
||||
}
|
||||
vss := nInfo.VsMap.List()
|
||||
for i := range vss {
|
||||
for hostName, ips := range vss[i].HostIps {
|
||||
for _, ip := range ips {
|
||||
if _, ok := existedIPPool.Get(ip); ok {
|
||||
continue
|
||||
}
|
||||
net, ok := excludedIPPool.Get(ip)
|
||||
if !ok {
|
||||
continue
|
||||
}
|
||||
desc := fmt.Sprintf("networks %s shouldn't have ip %s belong to host %s, because the wire %s where in this network don't belong to zone %s or can't be used by cloudaccount %s owner", net.Id, ip, hostName, net.WireId, zoneId, cloudaccount.Id)
|
||||
self.taskFailed(ctx, cloudaccount, desc, nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
capWires := make([]CAPWire, 0)
|
||||
vsList := nInfo.VsMap.List()
|
||||
log.Infof("vsList: %s", jsonutils.Marshal(vsList))
|
||||
desc := fmt.Sprintf("Auto create for cloudaccount %q", cloudaccount.GetName())
|
||||
for i := range vsList {
|
||||
vs := vsList[i]
|
||||
wireName := fmt.Sprintf("%s/%s", cloudaccount.Name, vs.Name)
|
||||
capWire := CAPWire{
|
||||
Name: wireName,
|
||||
VsId: vs.Id,
|
||||
Distributed: vs.Distributed,
|
||||
Hosts: vs.Hosts,
|
||||
}
|
||||
wireScore := make(map[string]int)
|
||||
for _, ips := range vs.HostIps {
|
||||
for j := 0; j < len(ips); j++ {
|
||||
baseNet := ips[j].NetAddr(ipMaskLen)
|
||||
ipWithSameNet := []netutils.IPV4Addr{ips[j]}
|
||||
for k := j + 1; k < len(ips); k++ {
|
||||
net := ips[k].NetAddr(24)
|
||||
if net != baseNet {
|
||||
break
|
||||
}
|
||||
ipWithSameNet = append(ipWithSameNet, ips[k])
|
||||
}
|
||||
ipLimitLow, ipLimitUp := ipWithSameNet[0], ipWithSameNet[len(ips)-1]
|
||||
simNetConfs := self.expandIPRnage(ipWithSameNet, ipLimitLow, ipLimitUp,
|
||||
func(proc esxi.SIPProc) bool {
|
||||
return proc.IsHost
|
||||
},
|
||||
nInfo.IPPool, excludedIPPool,
|
||||
func(net sSimpleNet) {
|
||||
wireScore[net.WireId] += 2
|
||||
},
|
||||
)
|
||||
for k := range simNetConfs {
|
||||
capWire.HostNetworks = append(capWire.HostNetworks, CANetConf{
|
||||
Name: fmt.Sprintf("%s-host-network-%d", wireName, len(capWire.HostNetworks)+1),
|
||||
Description: desc,
|
||||
CASimpleNetConf: simNetConfs[k],
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
/* for vlan, ips := range vs.Vlans {
|
||||
simNetConfs := self.expandIPRnage(ips, 0, 0, func(proc esxi.SIPProc) bool {
|
||||
return proc.VlanId == vlan && proc.VSId == vs.Id && !proc.IsHost
|
||||
}, nInfo.IPPool, excludedIPPool, func(net sSimpleNet) {
|
||||
wireScore[net.WireId] += 1
|
||||
})
|
||||
for j := range simNetConfs {
|
||||
simNetConfs[j].VlanID = vlan
|
||||
capWire.GuestNetworks = append(capWire.GuestNetworks, CANetConf{
|
||||
Name: fmt.Sprintf("%s-guest-network-%d", wireName, len(capWire.GuestNetworks)+1),
|
||||
Description: desc,
|
||||
CASimpleNetConf: simNetConfs[j],
|
||||
})
|
||||
}
|
||||
}*/
|
||||
// make sure wire
|
||||
suitableWire := ""
|
||||
maxScore := 1
|
||||
for wireId, score := range wireScore {
|
||||
if score > maxScore {
|
||||
suitableWire = wireId
|
||||
maxScore = score
|
||||
}
|
||||
}
|
||||
capWire.WireId = suitableWire
|
||||
if len(capWire.WireId) == 0 {
|
||||
capWire.Description = desc
|
||||
}
|
||||
capWires = append(capWires, capWire)
|
||||
}
|
||||
log.Infof("capWires: %v", capWires)
|
||||
host2Wire, err := self.createNetworks(ctx, cloudaccount, zoneId, capWires)
|
||||
if err != nil {
|
||||
self.taskFailed(ctx, cloudaccount, "uable to creat networks", err)
|
||||
return
|
||||
}
|
||||
err = cloudaccount.SetHost2Wire(ctx, self.UserCred, host2Wire)
|
||||
if err != nil {
|
||||
self.taskFailed(ctx, cloudaccount, "unable to store host2wire map", err)
|
||||
return
|
||||
}
|
||||
self.SetStage("OnSyncCloudProviderInfoComplete", nil)
|
||||
err = cloudaccount.StartSyncCloudProviderInfoTask(ctx, self.UserCred, nil, self.GetTaskId())
|
||||
if err != nil {
|
||||
self.taskFailed(ctx, cloudaccount, "unable to StartSyncCloudProviderInfoTask", err)
|
||||
}
|
||||
}
|
||||
|
||||
func (self *CloudAccountSyncVMwareNetworkTask) OnSyncCloudProviderInfoComplete(ctx context.Context, obj db.IStandaloneModel, data jsonutils.JSONObject) {
|
||||
cloudaccount := obj.(*models.SCloudaccount)
|
||||
self.taskSuccess(ctx, cloudaccount, "")
|
||||
}
|
||||
|
||||
func (self *CloudAccountSyncVMwareNetworkTask) OnSyncCloudProviderInfoCompleteFailed(ctx context.Context, obj db.IStandaloneModel, err jsonutils.JSONObject) {
|
||||
cloudaccount := obj.(*models.SCloudaccount)
|
||||
db.OpsLog.LogEvent(cloudaccount, db.ACT_SYNC_NETWORK_FAILED, err, self.UserCred)
|
||||
logclient.AddActionLogWithStartable(self, cloudaccount, logclient.ACT_CLOUDACCOUNT_SYNC_NETWORK, err, self.UserCred, false)
|
||||
self.SetStageFailed(ctx, nil)
|
||||
}
|
||||
|
||||
func (self *CloudAccountSyncVMwareNetworkTask) createNetworks(ctx context.Context, cloudaccount *models.SCloudaccount, zoneId string, capWires []CAPWire) (map[string][]models.SVs2Wire, error) {
|
||||
var err error
|
||||
ret := make(map[string][]models.SVs2Wire)
|
||||
for i := range capWires {
|
||||
// if len(capWires[i].GuestNetworks)+len(capWires[i].HostNetworks) == 0 {
|
||||
if len(capWires[i].HostNetworks) == 0 {
|
||||
continue
|
||||
}
|
||||
var wireId = capWires[i].WireId
|
||||
if len(wireId) == 0 {
|
||||
wireId, err = self.createWire(ctx, cloudaccount, api.DEFAULT_VPC_ID, zoneId, capWires[i].Name, capWires[i].Description)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "can't create wire %s", capWires[i].Name)
|
||||
}
|
||||
capWires[i].WireId = wireId
|
||||
}
|
||||
for _, net := range capWires[i].HostNetworks {
|
||||
err := self.createNetwork(ctx, cloudaccount, wireId, api.NETWORK_TYPE_BAREMETAL, net)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "can't create network %v", net)
|
||||
}
|
||||
}
|
||||
/* for _, net := range capWires[i].GuestNetworks {
|
||||
err := self.createNetwork(ctx, cloudaccount, wireId, api.NETWORK_TYPE_GUEST, net)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "can't create network %v", net)
|
||||
}
|
||||
}*/
|
||||
for _, host := range capWires[i].Hosts {
|
||||
ret[host.Id] = append(ret[host.Id], models.SVs2Wire{
|
||||
VsId: capWires[i].VsId,
|
||||
WireId: capWires[i].WireId,
|
||||
Distributed: capWires[i].Distributed,
|
||||
Mac: host.Mac,
|
||||
})
|
||||
}
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
// NETWORK_TYPE_GUEST = "guest"
|
||||
// NETWORK_TYPE_BAREMETAL = "baremetal"
|
||||
func (self *CloudAccountSyncVMwareNetworkTask) createNetwork(ctx context.Context, cloudaccount *models.SCloudaccount, wireId, networkType string, net CANetConf) error {
|
||||
network := &models.SNetwork{}
|
||||
network.Name = net.Name
|
||||
if hint, err := models.NetworkManager.NewIfnameHint(net.Name); err != nil {
|
||||
log.Errorf("can't NewIfnameHint form hint %s", net.Name)
|
||||
} else {
|
||||
network.IfnameHint = hint
|
||||
}
|
||||
network.GuestIpStart = net.IpStart
|
||||
network.GuestIpEnd = net.IpEnd
|
||||
network.GuestIpMask = net.IpMask
|
||||
network.GuestGateway = net.Gateway
|
||||
network.VlanId = int(net.VlanID)
|
||||
network.WireId = wireId
|
||||
network.ServerType = networkType
|
||||
network.IsPublic = true
|
||||
network.Status = api.NETWORK_STATUS_AVAILABLE
|
||||
network.PublicScope = string(rbacscope.ScopeDomain)
|
||||
network.ProjectId = cloudaccount.ProjectId
|
||||
network.DomainId = cloudaccount.DomainId
|
||||
network.Description = net.Description
|
||||
|
||||
network.SetModelManager(models.NetworkManager, network)
|
||||
// TODO: Prevent IP conflict
|
||||
log.Infof("create network %s succussfully", network.Id)
|
||||
err := models.NetworkManager.TableSpec().Insert(ctx, network)
|
||||
return err
|
||||
}
|
||||
|
||||
func (self *CloudAccountSyncVMwareNetworkTask) createWire(ctx context.Context, cloudaccount *models.SCloudaccount, vpcId, zoneId, wireName, desc string) (string, error) {
|
||||
wire := &models.SWire{
|
||||
Bandwidth: 10000,
|
||||
Mtu: 1500,
|
||||
}
|
||||
wire.VpcId = vpcId
|
||||
wire.ZoneId = zoneId
|
||||
wire.IsEmulated = false
|
||||
wire.Name = wireName
|
||||
wire.DomainId = cloudaccount.GetOwnerId().GetDomainId()
|
||||
wire.Description = desc
|
||||
wire.Status = api.WIRE_STATUS_AVAILABLE
|
||||
wire.SetModelManager(models.WireManager, wire)
|
||||
err := models.WireManager.TableSpec().Insert(ctx, wire)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
log.Infof("create wire %s succussfully", wire.GetId())
|
||||
return wire.GetId(), nil
|
||||
}
|
||||
|
||||
var ipMaskLen int8 = 24
|
||||
|
||||
func (self *CloudAccountSyncVMwareNetworkTask) ipPool(cloudaccount *models.SCloudaccount, wires map[string]*models.SWire) (*sIPPool, error) {
|
||||
networks := make([]models.SNetwork, 0, len(wires))
|
||||
if wires == nil {
|
||||
obj, err := models.VpcManager.FetchById(api.DEFAULT_VPC_ID)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable fetch defaut vpc")
|
||||
}
|
||||
networks, err = obj.(*models.SVpc).GetNetworks()
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "unable to get networks of vpc default")
|
||||
}
|
||||
} else {
|
||||
for _, wire := range wires {
|
||||
nets, err := wire.GetNetworks(cloudaccount.GetOwnerId(), rbacscope.ScopeDomain)
|
||||
if err != nil {
|
||||
return nil, errors.Wrapf(err, "unable to fetch networks of wire %s", wire.GetId())
|
||||
}
|
||||
networks = append(networks, nets...)
|
||||
}
|
||||
}
|
||||
pool := newIPPool(len(networks))
|
||||
for i := range networks {
|
||||
startIp, _ := netutils.NewIPV4Addr(networks[i].GuestIpStart)
|
||||
endIp, _ := netutils.NewIPV4Addr(networks[i].GuestIpEnd)
|
||||
pool.Insert(startIp, sSimpleNet{
|
||||
Diff: endIp - startIp,
|
||||
Vlan: int32(networks[i].VlanId),
|
||||
Id: networks[i].Id,
|
||||
WireId: networks[i].WireId,
|
||||
})
|
||||
}
|
||||
return pool, nil
|
||||
}
|
||||
|
||||
func (self *CloudAccountSyncVMwareNetworkTask) zoneId() (string, error) {
|
||||
if !self.Params.Contains("zone") {
|
||||
zoneids, err := models.CloudaccountManager.FetchEsxiZoneIds()
|
||||
if err != nil {
|
||||
return "", errors.Wrap(err, "unable to fetch esxi zoneids")
|
||||
}
|
||||
return zoneids[0], nil
|
||||
}
|
||||
zone, _ := self.Params.GetString("zone")
|
||||
obj, err := models.ZoneManager.FetchByIdOrName(self.UserCred, zone)
|
||||
if err != nil {
|
||||
return "", errors.Wrapf(err, "unable to fetch zone %q", zone)
|
||||
}
|
||||
return obj.GetId(), nil
|
||||
}
|
||||
|
||||
func (self *CloudAccountSyncVMwareNetworkTask) fetchWires(cloudaccount *models.SCloudaccount, zoneId string) (map[string]*models.SWire, error) {
|
||||
q := models.WireManager.Query().Equals("zone_id", zoneId)
|
||||
q = models.WireManager.FilterByOwner(q, cloudaccount.GetOwnerId(), rbacscope.ScopeDomain)
|
||||
wires := make([]models.SWire, 0, 1)
|
||||
err := db.FetchModelObjects(models.WireManager, q, &wires)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ret := make(map[string]*models.SWire, len(wires))
|
||||
for i := range wires {
|
||||
ret[wires[i].GetId()] = &wires[i]
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func (self *CloudAccountSyncVMwareNetworkTask) fetchEsxiZoneIds() ([]string, error) {
|
||||
q := models.BaremetalagentManager.Query().Equals("agent_type", "esxiagent").Asc("created_at")
|
||||
agents := make([]models.SBaremetalagent, 0, 1)
|
||||
err := db.FetchModelObjects(models.BaremetalagentManager, q, &agents)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ids := make([]string, 0, len(agents))
|
||||
for i := range agents {
|
||||
if agents[i].Status == api.BAREMETAL_AGENT_ENABLED {
|
||||
ids = append(ids, agents[i].ZoneId)
|
||||
}
|
||||
}
|
||||
for i := range agents {
|
||||
if agents[i].Status != api.BAREMETAL_AGENT_ENABLED {
|
||||
ids = append(ids, agents[i].ZoneId)
|
||||
}
|
||||
}
|
||||
return ids, nil
|
||||
}
|
||||
|
||||
func (self *CloudAccountSyncVMwareNetworkTask) expandIPRnage(ips []netutils.IPV4Addr, limitLow, limitUp netutils.IPV4Addr, expand func(esxi.SIPProc) bool, ipPool esxi.SIPPool, existedIpPool *sIPPool, existed func(sSimpleNet)) []CASimpleNetConf {
|
||||
ret := make([]CASimpleNetConf, 0)
|
||||
for i := 0; i < len(ips); i++ {
|
||||
log.Infof("ipPool: %v", ipPool)
|
||||
log.Infof("existedIpPool: %v", existedIpPool)
|
||||
ip := ips[i]
|
||||
if net, ok := existedIpPool.Get(ip); ok {
|
||||
if existed != nil {
|
||||
existed(net)
|
||||
}
|
||||
continue
|
||||
}
|
||||
net := ip.NetAddr(24)
|
||||
netLimitLow := net + 1
|
||||
netLimitUp := net + 254
|
||||
if limitLow != 0 && limitLow > netLimitLow {
|
||||
netLimitLow = limitLow
|
||||
}
|
||||
if limitUp != 0 && limitUp < netLimitUp {
|
||||
netLimitUp = limitUp
|
||||
}
|
||||
log.Infof("ip: %s", ip.String())
|
||||
// find startip
|
||||
startIp := ip - 1
|
||||
for ; startIp >= netLimitLow; startIp-- {
|
||||
log.Infof("startIp: %s", startIp)
|
||||
if _, ok := existedIpPool.Get(startIp); ok {
|
||||
log.Infof("existedIpPool get startIp")
|
||||
break
|
||||
}
|
||||
if _, ok := ipPool.Get(startIp); ok {
|
||||
log.Infof("ipPool get startIp")
|
||||
break
|
||||
}
|
||||
}
|
||||
endIp := ip + 1
|
||||
for ; endIp <= netLimitUp; endIp++ {
|
||||
log.Infof("endIp: %s", endIp)
|
||||
if _, ok := existedIpPool.Get(endIp); ok {
|
||||
log.Infof("existedIpPool get endIp")
|
||||
break
|
||||
}
|
||||
if proc, ok := ipPool.Get(endIp); ok {
|
||||
log.Infof("existedIpPool get endIp")
|
||||
if expand(proc) {
|
||||
i++
|
||||
continue
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
ret = append(ret, CASimpleNetConf{
|
||||
IpStart: (startIp + 1).String(),
|
||||
IpEnd: (endIp - 1).String(),
|
||||
IpMask: ipMaskLen,
|
||||
Gateway: (net + netutils.IPV4Addr(options.Options.DefaultNetworkGatewayAddressEsxi)).String(),
|
||||
})
|
||||
// Avoid assigning already assigned ip subnet
|
||||
existedIpPool.Insert(startIp+1, sSimpleNet{
|
||||
Diff: endIp - startIp - 2,
|
||||
})
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
type sIPPool struct {
|
||||
netranges []netutils.IPV4Addr
|
||||
simpleNetMap map[netutils.IPV4Addr]sSimpleNet
|
||||
}
|
||||
|
||||
func newIPPool(length ...int) *sIPPool {
|
||||
initLen := 0
|
||||
if len(length) > 0 {
|
||||
initLen = length[0]
|
||||
}
|
||||
return &sIPPool{
|
||||
netranges: make([]netutils.IPV4Addr, 0, initLen),
|
||||
simpleNetMap: make(map[netutils.IPV4Addr]sSimpleNet, initLen),
|
||||
}
|
||||
}
|
||||
|
||||
type sSimpleNet struct {
|
||||
Diff netutils.IPV4Addr
|
||||
Id string
|
||||
Vlan int32
|
||||
WireId string
|
||||
}
|
||||
|
||||
func (pl *sIPPool) Insert(startIp netutils.IPV4Addr, sNet sSimpleNet) {
|
||||
// TODO:check
|
||||
index := pl.getIndex(startIp)
|
||||
pl.netranges = append(pl.netranges, 0)
|
||||
pl.netranges = append(pl.netranges[:index+1], pl.netranges[index:len(pl.netranges)-1]...)
|
||||
pl.netranges[index] = startIp
|
||||
pl.simpleNetMap[startIp] = sNet
|
||||
}
|
||||
|
||||
func (pl *sIPPool) getIndex(ip netutils.IPV4Addr) int {
|
||||
index := sort.Search(len(pl.netranges), func(n int) bool {
|
||||
return pl.netranges[n] >= ip
|
||||
})
|
||||
return index
|
||||
}
|
||||
|
||||
func (pl *sIPPool) Get(ip netutils.IPV4Addr) (sSimpleNet, bool) {
|
||||
index := pl.getIndex(ip)
|
||||
if index > len(pl.netranges) || index < 0 {
|
||||
return sSimpleNet{}, false
|
||||
}
|
||||
if index < len(pl.netranges) && pl.netranges[index] == ip {
|
||||
return pl.simpleNetMap[ip], true
|
||||
}
|
||||
if index == 0 {
|
||||
return sSimpleNet{}, false
|
||||
}
|
||||
startIp := pl.netranges[index-1]
|
||||
simpleNet := pl.simpleNetMap[startIp]
|
||||
if ip-startIp <= simpleNet.Diff {
|
||||
return simpleNet, true
|
||||
}
|
||||
return sSimpleNet{}, false
|
||||
}
|
||||
|
||||
type CAPWire struct {
|
||||
VsId string
|
||||
WireId string
|
||||
Name string
|
||||
Distributed bool
|
||||
Description string
|
||||
Hosts []esxi.SSimpleHostDev
|
||||
HostNetworks []CANetConf
|
||||
// GuestNetworks []CANetConf
|
||||
}
|
||||
|
||||
type CASimpleNetConf struct {
|
||||
IpStart string `json:"guest_ip_start"`
|
||||
IpEnd string `json:"guest_ip_end"`
|
||||
IpMask int8 `json:"guest_ip_mask"`
|
||||
Gateway string `json:"guest_gateway"`
|
||||
VlanID int32 `json:"vlan_id"`
|
||||
}
|
||||
|
||||
type CANetConf struct {
|
||||
CASimpleNetConf
|
||||
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
@@ -1351,4 +1351,10 @@ func init() {
|
||||
EN("WebSSH").
|
||||
CN("WebSSH"),
|
||||
)
|
||||
|
||||
o.Set(ACT_CLOUDACCOUNT_SYNC_NETWORK, i18n.NewTableEntry().
|
||||
EN("Probe Network").
|
||||
CN("探测网络配置"),
|
||||
)
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user