mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-06-23 06:09:16 +08:00
1029 lines
31 KiB
Go
1029 lines
31 KiB
Go
// 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"
|
|
"database/sql"
|
|
"fmt"
|
|
|
|
"yunion.io/x/jsonutils"
|
|
"yunion.io/x/log"
|
|
"yunion.io/x/pkg/errors"
|
|
"yunion.io/x/pkg/tristate"
|
|
"yunion.io/x/pkg/util/compare"
|
|
"yunion.io/x/pkg/util/netutils"
|
|
"yunion.io/x/pkg/utils"
|
|
"yunion.io/x/sqlchemy"
|
|
|
|
api "yunion.io/x/onecloud/pkg/apis/compute"
|
|
"yunion.io/x/onecloud/pkg/cloudcommon/db"
|
|
"yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
|
|
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
|
|
"yunion.io/x/onecloud/pkg/cloudcommon/validators"
|
|
"yunion.io/x/onecloud/pkg/cloudprovider"
|
|
"yunion.io/x/onecloud/pkg/httperrors"
|
|
"yunion.io/x/onecloud/pkg/mcclient"
|
|
"yunion.io/x/onecloud/pkg/util/rbacutils"
|
|
"yunion.io/x/onecloud/pkg/util/stringutils2"
|
|
)
|
|
|
|
type SWireManager struct {
|
|
db.SInfrasResourceBaseManager
|
|
db.SExternalizedResourceBaseManager
|
|
SVpcResourceBaseManager
|
|
SZoneResourceBaseManager
|
|
}
|
|
|
|
var WireManager *SWireManager
|
|
|
|
func init() {
|
|
WireManager = &SWireManager{
|
|
SInfrasResourceBaseManager: db.NewInfrasResourceBaseManager(
|
|
SWire{},
|
|
"wires_tbl",
|
|
"wire",
|
|
"wires",
|
|
),
|
|
}
|
|
WireManager.SetVirtualObject(WireManager)
|
|
}
|
|
|
|
type SWire struct {
|
|
db.SInfrasResourceBase
|
|
db.SExternalizedResourceBase
|
|
|
|
SVpcResourceBase `wdith:"36" charset:"ascii" nullable:"false" list:"admin" create:"admin_required"`
|
|
SZoneResourceBase `width:"36" charset:"ascii" nullable:"true" list:"admin" create:"admin_required"`
|
|
|
|
// 带宽大小, 单位Mbps
|
|
// example: 1000
|
|
Bandwidth int `list:"admin" update:"admin" nullable:"false" create:"admin_required" json:"bandwidth"`
|
|
// MTU
|
|
// example: 1500
|
|
Mtu int `list:"admin" update:"admin" nullable:"false" create:"admin_optional" default:"1500" json:"mtu"`
|
|
// swagger:ignore
|
|
ScheduleRank int `list:"admin" update:"admin" json:"schedule_rank"`
|
|
|
|
// 可用区Id
|
|
// ZoneId string `width:"36" charset:"ascii" nullable:"true" list:"admin" create:"admin_required"`
|
|
// VPC Id
|
|
// VpcId string `wdith:"36" charset:"ascii" nullable:"false" list:"admin" create:"admin_required"`
|
|
}
|
|
|
|
func (manager *SWireManager) GetContextManagers() [][]db.IModelManager {
|
|
return [][]db.IModelManager{
|
|
{ZoneManager},
|
|
{VpcManager},
|
|
}
|
|
}
|
|
|
|
func (manager *SWireManager) ValidateCreateData(
|
|
ctx context.Context,
|
|
userCred mcclient.TokenCredential,
|
|
ownerId mcclient.IIdentityProvider,
|
|
query jsonutils.JSONObject,
|
|
input api.WireCreateInput,
|
|
) (api.WireCreateInput, error) {
|
|
var err error
|
|
|
|
if input.Bandwidth < 0 {
|
|
return input, httperrors.NewOutOfRangeError("bandwidth must be greater than 0")
|
|
}
|
|
|
|
if input.Mtu < 0 || input.Mtu > 1000000 {
|
|
return input, httperrors.NewOutOfRangeError("mtu must be range of 0~1000000")
|
|
}
|
|
|
|
if len(input.Vpc) == 0 {
|
|
return input, httperrors.NewMissingParameterError("vpc")
|
|
}
|
|
|
|
var vpc *SVpc
|
|
vpc, input.VpcResourceInput, err = ValidateVpcResourceInput(userCred, input.VpcResourceInput)
|
|
if err != nil {
|
|
return input, errors.Wrap(err, "ValidateVpcResourceInput")
|
|
}
|
|
|
|
if len(vpc.ManagerId) > 0 {
|
|
return input, httperrors.NewNotSupportedError("Currently only kvm platform supports creating wire")
|
|
}
|
|
|
|
if len(input.Zone) == 0 {
|
|
return input, httperrors.NewMissingParameterError("zone")
|
|
}
|
|
|
|
_, input.ZoneResourceInput, err = ValidateZoneResourceInput(userCred, input.ZoneResourceInput)
|
|
if err != nil {
|
|
return input, errors.Wrap(err, "ValidateZoneResourceInput")
|
|
}
|
|
|
|
input.InfrasResourceBaseCreateInput, err = manager.SInfrasResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.InfrasResourceBaseCreateInput)
|
|
if err != nil {
|
|
return input, err
|
|
}
|
|
return input, nil
|
|
}
|
|
|
|
func (wire *SWire) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.WireUpdateInput) (api.WireUpdateInput, error) {
|
|
data := jsonutils.Marshal(input).(*jsonutils.JSONDict)
|
|
keysV := []validators.IValidator{
|
|
validators.NewNonNegativeValidator("bandwidth"),
|
|
validators.NewRangeValidator("mtu", 1, 1000000).Optional(true),
|
|
}
|
|
for _, v := range keysV {
|
|
v.Optional(true)
|
|
if err := v.Validate(data); err != nil {
|
|
return input, err
|
|
}
|
|
}
|
|
var err error
|
|
input.InfrasResourceBaseUpdateInput, err = wire.SInfrasResourceBase.ValidateUpdateData(ctx, userCred, query, input.InfrasResourceBaseUpdateInput)
|
|
if err != nil {
|
|
return input, errors.Wrap(err, "SInfrasResourceBase.ValidateUpdateData")
|
|
}
|
|
|
|
return input, nil
|
|
}
|
|
|
|
func (wire *SWire) ValidateDeleteCondition(ctx context.Context) error {
|
|
cnt, err := wire.HostCount()
|
|
if err != nil {
|
|
return httperrors.NewInternalServerError("HostCount fail %s", err)
|
|
}
|
|
if cnt > 0 {
|
|
return httperrors.NewNotEmptyError("wire contains hosts")
|
|
}
|
|
cnt, err = wire.NetworkCount()
|
|
if err != nil {
|
|
return httperrors.NewInternalServerError("NetworkCount fail %s", err)
|
|
}
|
|
if cnt > 0 {
|
|
return httperrors.NewNotEmptyError("wire contains networks")
|
|
}
|
|
return wire.SInfrasResourceBase.ValidateDeleteCondition(ctx)
|
|
}
|
|
|
|
func (manager *SWireManager) getWireExternalIdForClassicNetwork(provider string, vpcId string, zoneId string) string {
|
|
if !utils.IsInStringArray(provider, api.REGIONAL_NETWORK_PROVIDERS) {
|
|
return fmt.Sprintf("%s-%s", vpcId, zoneId)
|
|
}
|
|
return vpcId
|
|
}
|
|
|
|
func (manager *SWireManager) NewWireForClassicNetwork(vpc *SVpc, zone *SZone) (*SWire, error) {
|
|
cloudprovider := vpc.GetCloudprovider()
|
|
if cloudprovider == nil {
|
|
return nil, fmt.Errorf("failed to found cloudprovider for vpc %s(%s)", vpc.Id, vpc.Id)
|
|
}
|
|
externalId := manager.getWireExternalIdForClassicNetwork(cloudprovider.Provider, vpc.Id, zone.Id)
|
|
name := fmt.Sprintf("emulate for vpc %s classic network", vpc.Id)
|
|
zoneId := zone.Id
|
|
if utils.IsInStringArray(cloudprovider.Provider, api.REGIONAL_NETWORK_PROVIDERS) { //reginal network
|
|
zoneId = ""
|
|
} else {
|
|
name = fmt.Sprintf("emulate for zone %s vpc %s classic network", zone.Name, vpc.Id)
|
|
}
|
|
_wire, err := db.FetchByExternalId(manager, externalId)
|
|
if err == nil {
|
|
return _wire.(*SWire), nil
|
|
}
|
|
if errors.Cause(err) != sql.ErrNoRows {
|
|
return nil, errors.Wrap(err, "db.FetchByExternalId")
|
|
}
|
|
wire := &SWire{}
|
|
wire.VpcId = vpc.Id
|
|
wire.ZoneId = zoneId
|
|
wire.SetModelManager(manager, wire)
|
|
wire.ExternalId = externalId
|
|
wire.IsEmulated = true
|
|
wire.Name = name
|
|
err = manager.TableSpec().Insert(wire)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "Insert wire for classic network")
|
|
}
|
|
return wire, nil
|
|
}
|
|
|
|
func (wire *SWire) getHostwireQuery() *sqlchemy.SQuery {
|
|
return HostwireManager.Query().Equals("wire_id", wire.Id)
|
|
}
|
|
|
|
func (wire *SWire) HostCount() (int, error) {
|
|
q := wire.getHostwireQuery()
|
|
return q.CountWithError()
|
|
}
|
|
|
|
func (wire *SWire) GetHostwires() ([]SHostwire, error) {
|
|
q := wire.getHostwireQuery()
|
|
hostwires := make([]SHostwire, 0)
|
|
err := db.FetchModelObjects(HostwireManager, q, &hostwires)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return hostwires, nil
|
|
}
|
|
|
|
func (wire *SWire) NetworkCount() (int, error) {
|
|
q := NetworkManager.Query().Equals("wire_id", wire.Id)
|
|
return q.CountWithError()
|
|
}
|
|
|
|
func (wire *SWire) GetVpcId() string {
|
|
if len(wire.VpcId) == 0 {
|
|
return "default"
|
|
} else {
|
|
return wire.VpcId
|
|
}
|
|
}
|
|
|
|
func (manager *SWireManager) getWiresByVpcAndZone(vpc *SVpc, zone *SZone) ([]SWire, error) {
|
|
wires := make([]SWire, 0)
|
|
q := manager.Query()
|
|
if vpc != nil {
|
|
q = q.Equals("vpc_id", vpc.Id)
|
|
}
|
|
if zone != nil {
|
|
q = q.Equals("zone_id", zone.Id)
|
|
}
|
|
err := db.FetchModelObjects(manager, q, &wires)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return wires, nil
|
|
}
|
|
|
|
func (manager *SWireManager) SyncWires(ctx context.Context, userCred mcclient.TokenCredential, vpc *SVpc, wires []cloudprovider.ICloudWire, provider *SCloudprovider) ([]SWire, []cloudprovider.ICloudWire, compare.SyncResult) {
|
|
lockman.LockClass(ctx, manager, db.GetLockClassKey(manager, userCred))
|
|
defer lockman.ReleaseClass(ctx, manager, db.GetLockClassKey(manager, userCred))
|
|
|
|
localWires := make([]SWire, 0)
|
|
remoteWires := make([]cloudprovider.ICloudWire, 0)
|
|
syncResult := compare.SyncResult{}
|
|
|
|
dbWires, err := manager.getWiresByVpcAndZone(vpc, nil)
|
|
if err != nil {
|
|
syncResult.Error(err)
|
|
return nil, nil, syncResult
|
|
}
|
|
|
|
for i := range dbWires {
|
|
if taskman.TaskManager.IsInTask(&dbWires[i]) {
|
|
syncResult.Error(fmt.Errorf("object in task"))
|
|
return nil, nil, syncResult
|
|
}
|
|
}
|
|
|
|
removed := make([]SWire, 0)
|
|
commondb := make([]SWire, 0)
|
|
commonext := make([]cloudprovider.ICloudWire, 0)
|
|
added := make([]cloudprovider.ICloudWire, 0)
|
|
|
|
err = compare.CompareSets(dbWires, wires, &removed, &commondb, &commonext, &added)
|
|
if err != nil {
|
|
syncResult.Error(err)
|
|
return nil, nil, syncResult
|
|
}
|
|
|
|
for i := 0; i < len(removed); i += 1 {
|
|
err = removed[i].syncRemoveCloudWire(ctx, userCred)
|
|
if err != nil { // cannot delete
|
|
syncResult.DeleteError(err)
|
|
} else {
|
|
syncResult.Delete()
|
|
}
|
|
}
|
|
for i := 0; i < len(commondb); i += 1 {
|
|
err = commondb[i].syncWithCloudWire(ctx, userCred, commonext[i], provider)
|
|
if err != nil {
|
|
syncResult.UpdateError(err)
|
|
} else {
|
|
syncMetadata(ctx, userCred, &commondb[i], commonext[i])
|
|
localWires = append(localWires, commondb[i])
|
|
remoteWires = append(remoteWires, commonext[i])
|
|
syncResult.Update()
|
|
}
|
|
}
|
|
for i := 0; i < len(added); i += 1 {
|
|
new, err := manager.newFromCloudWire(ctx, userCred, added[i], vpc, provider)
|
|
if err != nil {
|
|
syncResult.AddError(err)
|
|
} else {
|
|
syncMetadata(ctx, userCred, new, added[i])
|
|
localWires = append(localWires, *new)
|
|
remoteWires = append(remoteWires, added[i])
|
|
syncResult.Add()
|
|
}
|
|
}
|
|
|
|
return localWires, remoteWires, syncResult
|
|
}
|
|
|
|
func (self *SWire) syncRemoveCloudWire(ctx context.Context, userCred mcclient.TokenCredential) error {
|
|
lockman.LockObject(ctx, self)
|
|
defer lockman.ReleaseObject(ctx, self)
|
|
|
|
vpc := self.GetVpc()
|
|
cloudprovider := vpc.GetCloudprovider()
|
|
if self.ExternalId == WireManager.getWireExternalIdForClassicNetwork(cloudprovider.Provider, self.VpcId, self.ZoneId) {
|
|
return nil
|
|
}
|
|
|
|
err := self.ValidateDeleteCondition(ctx)
|
|
if err != nil { // cannot delete
|
|
err = self.markNetworkUnknown(userCred)
|
|
} else {
|
|
err = self.Delete(ctx, userCred)
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (self *SWire) syncWithCloudWire(ctx context.Context, userCred mcclient.TokenCredential, extWire cloudprovider.ICloudWire, provider *SCloudprovider) error {
|
|
diff, err := db.UpdateWithLock(ctx, self, func() error {
|
|
// self.Name = extWire.GetName()
|
|
self.Bandwidth = extWire.GetBandwidth() // 10G
|
|
|
|
self.IsEmulated = extWire.IsEmulated()
|
|
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
log.Errorf("syncWithCloudWire error %s", err)
|
|
}
|
|
|
|
if provider != nil {
|
|
SyncCloudDomain(userCred, self, provider.GetOwnerId())
|
|
self.SyncShareState(ctx, userCred, provider.getAccountShareInfo())
|
|
}
|
|
|
|
db.OpsLog.LogSyncUpdate(self, diff, userCred)
|
|
return err
|
|
}
|
|
|
|
func (self *SWire) markNetworkUnknown(userCred mcclient.TokenCredential) error {
|
|
nets, err := self.getNetworks()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for i := 0; i < len(nets); i += 1 {
|
|
nets[i].SetStatus(userCred, api.NETWORK_STATUS_UNKNOWN, "wire sync to remove")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (manager *SWireManager) newFromCloudWire(ctx context.Context, userCred mcclient.TokenCredential, extWire cloudprovider.ICloudWire, vpc *SVpc, provider *SCloudprovider) (*SWire, error) {
|
|
wire := SWire{}
|
|
wire.SetModelManager(manager, &wire)
|
|
|
|
newName, err := db.GenerateName(manager, userCred, extWire.GetName())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
wire.Name = newName
|
|
wire.ExternalId = extWire.GetGlobalId()
|
|
wire.Bandwidth = extWire.GetBandwidth()
|
|
wire.VpcId = vpc.Id
|
|
izone := extWire.GetIZone()
|
|
if izone != nil {
|
|
zone, err := vpc.getZoneByExternalId(izone.GetGlobalId())
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "newFromCloudWire.getZoneByExternalId")
|
|
}
|
|
wire.ZoneId = zone.Id
|
|
}
|
|
|
|
wire.IsEmulated = extWire.IsEmulated()
|
|
|
|
err = manager.TableSpec().Insert(&wire)
|
|
if err != nil {
|
|
log.Errorf("newFromCloudWire fail %s", err)
|
|
return nil, err
|
|
}
|
|
|
|
if provider != nil {
|
|
SyncCloudDomain(userCred, &wire, provider.GetOwnerId())
|
|
wire.SyncShareState(ctx, userCred, provider.getAccountShareInfo())
|
|
}
|
|
|
|
db.OpsLog.LogEvent(&wire, db.ACT_CREATE, wire.GetShortDesc(ctx), userCred)
|
|
return &wire, nil
|
|
}
|
|
|
|
func filterByScopeOwnerId(q *sqlchemy.SQuery, scope rbacutils.TRbacScope, ownerId mcclient.IIdentityProvider) *sqlchemy.SQuery {
|
|
switch scope {
|
|
case rbacutils.ScopeSystem:
|
|
case rbacutils.ScopeDomain:
|
|
q = q.Equals("domain_id", ownerId.GetProjectDomainId())
|
|
case rbacutils.ScopeProject:
|
|
q = q.Equals("tenant_id", ownerId.GetProjectId())
|
|
}
|
|
return q
|
|
}
|
|
|
|
func (manager *SWireManager) totalCountQ(
|
|
rangeObjs []db.IStandaloneModel,
|
|
hostTypes []string,
|
|
providers []string, brands []string, cloudEnv string,
|
|
scope rbacutils.TRbacScope,
|
|
ownerId mcclient.IIdentityProvider,
|
|
pendingDeleted bool,
|
|
) *sqlchemy.SQuery {
|
|
guestsQ := filterByScopeOwnerId(GuestManager.Query(), scope, ownerId)
|
|
guests := guestsQ.SubQuery()
|
|
hostsQ := HostManager.Query()
|
|
if len(hostTypes) > 0 {
|
|
hostsQ = hostsQ.In("host_type", hostTypes)
|
|
}
|
|
if len(providers) > 0 || len(brands) > 0 || len(cloudEnv) > 0 {
|
|
hostsQ = CloudProviderFilter(hostsQ, hostsQ.Field("manager_id"), providers, brands, cloudEnv)
|
|
}
|
|
if len(rangeObjs) > 0 {
|
|
hostsQ = rangeObjectsFilter(hostsQ, rangeObjs, nil, hostsQ.Field("zone_id"), hostsQ.Field("manager_id"))
|
|
}
|
|
hosts := hostsQ.SubQuery()
|
|
groups := filterByScopeOwnerId(GroupManager.Query(), scope, ownerId).SubQuery()
|
|
lbsQ := filterByScopeOwnerId(LoadbalancerManager.Query(), scope, ownerId)
|
|
if len(providers) > 0 || len(brands) > 0 || len(cloudEnv) > 0 {
|
|
lbsQ = CloudProviderFilter(lbsQ, lbsQ.Field("manager_id"), providers, brands, cloudEnv)
|
|
}
|
|
if len(rangeObjs) > 0 {
|
|
lbsQ = rangeObjectsFilter(lbsQ, rangeObjs, lbsQ.Field("cloudregion_id"), lbsQ.Field("zone_id"), lbsQ.Field("manager_id"))
|
|
}
|
|
lbs := lbsQ.SubQuery()
|
|
|
|
gNics := GuestnetworkManager.Query().SubQuery()
|
|
gNicQ := gNics.Query(
|
|
gNics.Field("network_id"),
|
|
sqlchemy.COUNT("gnic_count"),
|
|
)
|
|
gNicQ = gNicQ.Join(guests, sqlchemy.Equals(guests.Field("id"), gNics.Field("guest_id")))
|
|
gNicQ = gNicQ.Join(hosts, sqlchemy.Equals(guests.Field("host_id"), hosts.Field("id")))
|
|
gNicQ = gNicQ.Filter(sqlchemy.IsTrue(hosts.Field("enabled")))
|
|
if pendingDeleted {
|
|
gNicQ = gNicQ.Filter(sqlchemy.IsTrue(guests.Field("pending_deleted")))
|
|
} else {
|
|
gNicQ = gNicQ.Filter(sqlchemy.IsFalse(guests.Field("pending_deleted")))
|
|
}
|
|
|
|
hNics := HostnetworkManager.Query().SubQuery()
|
|
hNicQ := hNics.Query(
|
|
hNics.Field("network_id"),
|
|
sqlchemy.COUNT("hnic_count"),
|
|
)
|
|
hNicQ = hNicQ.Join(hosts, sqlchemy.Equals(hNics.Field("baremetal_id"), hosts.Field("id")))
|
|
hNicQ = hNicQ.Filter(sqlchemy.IsTrue(hosts.Field("enabled")))
|
|
|
|
revIps := ReservedipManager.Query().SubQuery()
|
|
revQ := revIps.Query(
|
|
revIps.Field("network_id"),
|
|
sqlchemy.COUNT("rnic_count"),
|
|
)
|
|
|
|
groupNics := GroupnetworkManager.Query().SubQuery()
|
|
grpNicQ := groupNics.Query(
|
|
groupNics.Field("network_id"),
|
|
sqlchemy.COUNT("grpnic_count"),
|
|
)
|
|
grpNicQ = grpNicQ.Join(groups, sqlchemy.Equals(groups.Field("id"), groupNics.Field("group_id")))
|
|
|
|
lbNics := LoadbalancernetworkManager.Query().SubQuery()
|
|
lbNicQ := lbNics.Query(
|
|
lbNics.Field("network_id"),
|
|
sqlchemy.COUNT("lbnic_count"),
|
|
)
|
|
lbNicQ = lbNicQ.Join(lbs, sqlchemy.Equals(lbs.Field("id"), lbNics.Field("loadbalancer_id")))
|
|
if pendingDeleted {
|
|
lbNicQ = lbNicQ.Filter(sqlchemy.IsTrue(lbs.Field("pending_deleted")))
|
|
} else {
|
|
lbNicQ = lbNicQ.Filter(sqlchemy.IsFalse(lbs.Field("pending_deleted")))
|
|
}
|
|
|
|
gNicSQ := gNicQ.GroupBy(gNics.Field("network_id")).SubQuery()
|
|
hNicSQ := hNicQ.GroupBy(hNics.Field("network_id")).SubQuery()
|
|
revSQ := revQ.GroupBy(revIps.Field("network_id")).SubQuery()
|
|
grpNicSQ := grpNicQ.GroupBy(groupNics.Field("network_id")).SubQuery()
|
|
lbNicSQ := lbNicQ.GroupBy(lbNics.Field("network_id")).SubQuery()
|
|
|
|
networks := NetworkManager.Query().SubQuery()
|
|
netQ := networks.Query(
|
|
networks.Field("wire_id"),
|
|
sqlchemy.COUNT("id").Label("net_count"),
|
|
sqlchemy.SUM("gnic_count", gNicQ.Field("gnic_count")),
|
|
sqlchemy.SUM("hnic_count", hNicQ.Field("hnic_count")),
|
|
sqlchemy.SUM("rev_count", revQ.Field("rnic_count")),
|
|
sqlchemy.SUM("grpnic_count", grpNicSQ.Field("grpnic_count")),
|
|
sqlchemy.SUM("lbnic_count", lbNicSQ.Field("lbnic_count")),
|
|
)
|
|
netQ = netQ.LeftJoin(gNicSQ, sqlchemy.Equals(gNicSQ.Field("network_id"), networks.Field("id")))
|
|
netQ = netQ.LeftJoin(hNicSQ, sqlchemy.Equals(hNicSQ.Field("network_id"), networks.Field("id")))
|
|
netQ = netQ.LeftJoin(revSQ, sqlchemy.Equals(revSQ.Field("network_id"), networks.Field("id")))
|
|
netQ = netQ.LeftJoin(grpNicSQ, sqlchemy.Equals(grpNicSQ.Field("network_id"), networks.Field("id")))
|
|
netQ = netQ.LeftJoin(lbNicSQ, sqlchemy.Equals(lbNicSQ.Field("network_id"), networks.Field("id")))
|
|
netQ = netQ.GroupBy(networks.Field("wire_id"))
|
|
netSQ := netQ.SubQuery()
|
|
|
|
wires := WireManager.Query().SubQuery()
|
|
q := wires.Query(
|
|
sqlchemy.COUNT("id").Label("wires_count"),
|
|
sqlchemy.SUM("net_count", netSQ.Field("net_count")),
|
|
sqlchemy.SUM("guest_nic_count", netSQ.Field("gnic_count")),
|
|
sqlchemy.SUM("host_nic_count", netSQ.Field("hnic_count")),
|
|
sqlchemy.SUM("reserved_count", netSQ.Field("rev_count")),
|
|
sqlchemy.SUM("group_nic_count", netSQ.Field("grpnic_count")),
|
|
sqlchemy.SUM("lb_nic_count", netSQ.Field("lbnic_count")),
|
|
)
|
|
q = q.LeftJoin(netSQ, sqlchemy.Equals(wires.Field("id"), netSQ.Field("wire_id")))
|
|
|
|
if len(rangeObjs) > 0 || len(hostTypes) > 0 {
|
|
hostwires := HostwireManager.Query().SubQuery()
|
|
sq := hostwires.Query(hostwires.Field("wire_id"))
|
|
sq = sq.Join(hosts, sqlchemy.Equals(hosts.Field("id"), hostwires.Field("host_id")))
|
|
sq = sq.Filter(sqlchemy.IsTrue(hosts.Field("enabled")))
|
|
sq = AttachUsageQuery(sq, hosts, hostTypes, nil, nil, nil, "", rangeObjs)
|
|
q = q.Filter(sqlchemy.In(wires.Field("id"), sq.Distinct()))
|
|
}
|
|
|
|
if len(providers) > 0 || len(brands) > 0 || len(cloudEnv) > 0 {
|
|
vpcs := VpcManager.Query().SubQuery()
|
|
|
|
subq := vpcs.Query(vpcs.Field("id"))
|
|
subq = CloudProviderFilter(subq, vpcs.Field("manager_id"), providers, brands, cloudEnv)
|
|
q = q.Filter(sqlchemy.In(wires.Field("vpc_id"), subq.SubQuery()))
|
|
}
|
|
|
|
return q
|
|
}
|
|
|
|
type WiresCountStat struct {
|
|
WiresCount int
|
|
NetCount int
|
|
GuestNicCount int
|
|
HostNicCount int
|
|
ReservedCount int
|
|
GroupNicCount int
|
|
LbNicCount int
|
|
}
|
|
|
|
func (wstat WiresCountStat) NicCount() int {
|
|
return wstat.GuestNicCount + wstat.HostNicCount + wstat.ReservedCount + wstat.GroupNicCount + wstat.LbNicCount
|
|
}
|
|
|
|
func (manager *SWireManager) TotalCount(
|
|
rangeObjs []db.IStandaloneModel,
|
|
hostTypes []string,
|
|
providers []string, brands []string, cloudEnv string,
|
|
scope rbacutils.TRbacScope,
|
|
ownerId mcclient.IIdentityProvider,
|
|
pendingDeleted bool,
|
|
) WiresCountStat {
|
|
stat := WiresCountStat{}
|
|
err := manager.totalCountQ(
|
|
rangeObjs,
|
|
hostTypes,
|
|
providers, brands, cloudEnv,
|
|
scope, ownerId,
|
|
pendingDeleted,
|
|
).First(&stat)
|
|
if err != nil {
|
|
log.Errorf("Wire total count: %v", err)
|
|
}
|
|
return stat
|
|
}
|
|
|
|
func (self *SWire) getNetworkQuery() *sqlchemy.SQuery {
|
|
return NetworkManager.Query().Equals("wire_id", self.Id)
|
|
}
|
|
|
|
func (self *SWire) getNetworks() ([]SNetwork, error) {
|
|
q := self.getNetworkQuery()
|
|
nets := make([]SNetwork, 0)
|
|
err := db.FetchModelObjects(NetworkManager, q, &nets)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return nets, nil
|
|
}
|
|
|
|
func (self *SWire) getGatewayNetworkQuery() *sqlchemy.SQuery {
|
|
q := self.getNetworkQuery()
|
|
q = q.IsNotNull("guest_gateway").IsNotEmpty("guest_gateway")
|
|
q = q.Equals("status", api.NETWORK_STATUS_AVAILABLE)
|
|
return q
|
|
}
|
|
|
|
func (self *SWire) getPublicNetworks() ([]SNetwork, error) {
|
|
q := self.getGatewayNetworkQuery()
|
|
q = q.IsTrue("is_public")
|
|
nets := make([]SNetwork, 0)
|
|
err := db.FetchModelObjects(NetworkManager, q, &nets)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return nets, nil
|
|
}
|
|
|
|
func (self *SWire) getPrivateNetworks(userCred mcclient.TokenCredential) ([]SNetwork, error) {
|
|
q := self.getGatewayNetworkQuery()
|
|
q = q.Equals("tenant_id", userCred.GetProjectId()).IsFalse("is_public")
|
|
nets := make([]SNetwork, 0)
|
|
err := db.FetchModelObjects(NetworkManager, q, &nets)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return nets, nil
|
|
}
|
|
|
|
func (self *SWire) GetCandidatePrivateNetwork(userCred mcclient.TokenCredential, isExit bool, serverTypes []string) (*SNetwork, error) {
|
|
nets, err := self.getPrivateNetworks(userCred)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return ChooseCandidateNetworks(nets, isExit, serverTypes), nil
|
|
}
|
|
|
|
func (self *SWire) GetCandidatePublicNetwork(isExit bool, serverTypes []string) (*SNetwork, error) {
|
|
nets, err := self.getPublicNetworks()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return ChooseCandidateNetworks(nets, isExit, serverTypes), nil
|
|
}
|
|
|
|
func (self *SWire) GetCandidateNetworkForIp(userCred mcclient.TokenCredential, ipAddr string) (*SNetwork, error) {
|
|
ip, err := netutils.NewIPV4Addr(ipAddr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
netPrivates, err := self.getPrivateNetworks(userCred)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, net := range netPrivates {
|
|
if net.IsAddressInRange(ip) {
|
|
return &net, nil
|
|
}
|
|
}
|
|
netPublics, err := self.getPublicNetworks()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
for _, net := range netPublics {
|
|
if net.IsAddressInRange(ip) {
|
|
return &net, nil
|
|
}
|
|
}
|
|
return nil, nil
|
|
}
|
|
|
|
func ChooseNetworkByAddressCount(nets []*SNetwork) (*SNetwork, *SNetwork) {
|
|
return chooseNetworkByAddressCount(nets)
|
|
}
|
|
|
|
func chooseNetworkByAddressCount(nets []*SNetwork) (*SNetwork, *SNetwork) {
|
|
minCnt := 65535
|
|
maxCnt := 0
|
|
var minSel *SNetwork
|
|
var maxSel *SNetwork
|
|
for _, net := range nets {
|
|
cnt, err := net.getFreeAddressCount()
|
|
if err != nil || cnt <= 0 {
|
|
continue
|
|
}
|
|
if minSel == nil || minCnt > cnt {
|
|
minSel = net
|
|
minCnt = cnt
|
|
}
|
|
if maxSel == nil || maxCnt < cnt {
|
|
maxSel = net
|
|
maxCnt = cnt
|
|
}
|
|
}
|
|
return minSel, maxSel
|
|
}
|
|
|
|
func ChooseCandidateNetworks(nets []SNetwork, isExit bool, serverTypes []string) *SNetwork {
|
|
for _, s := range serverTypes {
|
|
net := chooseCandidateNetworksByNetworkType(nets, isExit, s)
|
|
if net != nil {
|
|
return net
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func chooseCandidateNetworksByNetworkType(nets []SNetwork, isExit bool, serverType string) *SNetwork {
|
|
matchingNets := make([]*SNetwork, 0)
|
|
notMatchingNets := make([]*SNetwork, 0)
|
|
|
|
for i := 0; i < len(nets); i++ {
|
|
net := nets[i]
|
|
if isExit != net.IsExitNetwork() {
|
|
continue
|
|
}
|
|
if serverType == net.ServerType || (len(net.ServerType) == 0 && serverType == api.NETWORK_TYPE_GUEST) {
|
|
matchingNets = append(matchingNets, &net)
|
|
} else {
|
|
notMatchingNets = append(notMatchingNets, &net)
|
|
}
|
|
}
|
|
minSel, maxSel := chooseNetworkByAddressCount(matchingNets)
|
|
if (isExit && minSel == nil) || (!isExit && maxSel == nil) {
|
|
minSel, maxSel = chooseNetworkByAddressCount(notMatchingNets)
|
|
}
|
|
if isExit {
|
|
return minSel
|
|
} else {
|
|
return maxSel
|
|
}
|
|
}
|
|
|
|
func (manager *SWireManager) InitializeData() error {
|
|
wires := make([]SWire, 0)
|
|
q := manager.Query()
|
|
err := db.FetchModelObjects(manager, q, &wires)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for _, w := range wires {
|
|
if len(w.VpcId) == 0 {
|
|
db.Update(&w, func() error {
|
|
w.VpcId = api.DEFAULT_VPC_ID
|
|
return nil
|
|
})
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (wire *SWire) getEnabledHosts() []SHost {
|
|
hosts := make([]SHost, 0)
|
|
|
|
hostQuery := HostManager.Query().SubQuery()
|
|
hostwireQuery := HostwireManager.Query().SubQuery()
|
|
|
|
q := hostQuery.Query()
|
|
q = q.Join(hostwireQuery, sqlchemy.AND(sqlchemy.Equals(hostQuery.Field("id"), hostwireQuery.Field("host_id")),
|
|
sqlchemy.IsFalse(hostwireQuery.Field("deleted"))))
|
|
q = q.Filter(sqlchemy.Equals(hostwireQuery.Field("wire_id"), wire.Id))
|
|
q = q.Filter(sqlchemy.IsTrue(hostQuery.Field("enabled")))
|
|
q = q.Filter(sqlchemy.Equals(hostQuery.Field("host_status"), api.HOST_ONLINE))
|
|
|
|
err := db.FetchModelObjects(HostManager, q, &hosts)
|
|
if err != nil {
|
|
log.Errorf("getEnabledHosts fail %s", err)
|
|
return nil
|
|
}
|
|
|
|
return hosts
|
|
}
|
|
|
|
func (wire *SWire) clearHostSchedDescCache() error {
|
|
hosts := wire.getEnabledHosts()
|
|
if hosts != nil {
|
|
for i := 0; i < len(hosts); i += 1 {
|
|
err := hosts[i].ClearSchedDescCache()
|
|
if err != nil {
|
|
log.Errorf("%s", err)
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (self *SWire) GetIWire() (cloudprovider.ICloudWire, error) {
|
|
vpc := self.GetVpc()
|
|
if vpc == nil {
|
|
log.Errorf("Cannot find VPC for wire???")
|
|
return nil, fmt.Errorf("No VPC?????")
|
|
}
|
|
ivpc, err := vpc.GetIVpc()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return ivpc.GetIWireById(self.GetExternalId())
|
|
}
|
|
|
|
func (manager *SWireManager) FetchWireById(wireId string) *SWire {
|
|
wireObj, err := manager.FetchById(wireId)
|
|
if err != nil {
|
|
log.Errorf("FetchWireById fail %s", err)
|
|
return nil
|
|
}
|
|
return wireObj.(*SWire)
|
|
}
|
|
|
|
func (manager *SWireManager) GetOnPremiseWireOfIp(ipAddr string) (*SWire, error) {
|
|
net, err := NetworkManager.GetOnPremiseNetworkOfIP(ipAddr, "", tristate.None)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
wire := net.GetWire()
|
|
if wire != nil {
|
|
return wire, nil
|
|
} else {
|
|
return nil, fmt.Errorf("Wire not found")
|
|
}
|
|
}
|
|
|
|
// 二层网络列表
|
|
func (manager *SWireManager) ListItemFilter(
|
|
ctx context.Context,
|
|
q *sqlchemy.SQuery,
|
|
userCred mcclient.TokenCredential,
|
|
query api.WireListInput,
|
|
) (*sqlchemy.SQuery, error) {
|
|
var err error
|
|
|
|
q, err = manager.SVpcResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VpcFilterListInput)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "SVpcResourceBaseManager.ListItemFilter")
|
|
}
|
|
|
|
q, err = manager.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "SExternalizedResourceBaseManager.ListItemFilter")
|
|
}
|
|
|
|
zoneQuery := api.ZonalFilterListInput{
|
|
ZonalFilterListBase: query.ZonalFilterListBase,
|
|
}
|
|
q, err = manager.SZoneResourceBaseManager.ListItemFilter(ctx, q, userCred, zoneQuery)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "SZoneResourceBaseManager.ListItemFilter")
|
|
}
|
|
|
|
q, err = manager.SInfrasResourceBaseManager.ListItemFilter(ctx, q, userCred, query.InfrasResourceBaseListInput)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "SInfrasResourceBaseManager.ListItemFilter")
|
|
}
|
|
|
|
hostStr := query.Host
|
|
if len(hostStr) > 0 {
|
|
hostObj, err := HostManager.FetchByIdOrName(userCred, hostStr)
|
|
if err != nil {
|
|
return nil, httperrors.NewResourceNotFoundError2(HostManager.Keyword(), hostStr)
|
|
}
|
|
sq := HostwireManager.Query("wire_id").Equals("host_id", hostObj.GetId())
|
|
q = q.Filter(sqlchemy.In(q.Field("id"), sq.SubQuery()))
|
|
}
|
|
|
|
return q, nil
|
|
}
|
|
|
|
func (manager *SWireManager) OrderByExtraFields(
|
|
ctx context.Context,
|
|
q *sqlchemy.SQuery,
|
|
userCred mcclient.TokenCredential,
|
|
query api.WireListInput,
|
|
) (*sqlchemy.SQuery, error) {
|
|
var err error
|
|
|
|
q, err = manager.SInfrasResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.InfrasResourceBaseListInput)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "SInfrasResourceBaseManager.OrderByExtraFields")
|
|
}
|
|
q, err = manager.SVpcResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VpcFilterListInput)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "SVpcResourceBaseManager.OrderByExtraFields")
|
|
}
|
|
zoneQuery := api.ZonalFilterListInput{
|
|
ZonalFilterListBase: query.ZonalFilterListBase,
|
|
}
|
|
q, err = manager.SZoneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, zoneQuery)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "SZoneResourceBaseManager.OrderByExtraFields")
|
|
}
|
|
|
|
return q, nil
|
|
}
|
|
|
|
func (manager *SWireManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
|
|
var err error
|
|
|
|
q, err = manager.SInfrasResourceBaseManager.QueryDistinctExtraField(q, field)
|
|
if err == nil {
|
|
return q, nil
|
|
}
|
|
q, err = manager.SVpcResourceBaseManager.QueryDistinctExtraField(q, field)
|
|
if err == nil {
|
|
return q, nil
|
|
}
|
|
q, err = manager.SZoneResourceBaseManager.QueryDistinctExtraField(q, field)
|
|
if err == nil {
|
|
return q, nil
|
|
}
|
|
|
|
return q, httperrors.ErrNotFound
|
|
}
|
|
|
|
/*func (self *SWire) getRegion() *SCloudregion {
|
|
zone := self.GetZone()
|
|
if zone != nil {
|
|
return zone.GetRegion()
|
|
}
|
|
|
|
vpc := self.getVpc()
|
|
if vpc != nil {
|
|
region, _ := vpc.GetRegion()
|
|
return region
|
|
}
|
|
|
|
return nil
|
|
}*/
|
|
|
|
func (self *SWire) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, isList bool) (api.WireDetails, error) {
|
|
return api.WireDetails{}, nil
|
|
}
|
|
|
|
func (manager *SWireManager) FetchCustomizeColumns(
|
|
ctx context.Context,
|
|
userCred mcclient.TokenCredential,
|
|
query jsonutils.JSONObject,
|
|
objs []interface{},
|
|
fields stringutils2.SSortedStrings,
|
|
isList bool,
|
|
) []api.WireDetails {
|
|
rows := make([]api.WireDetails, len(objs))
|
|
|
|
stdRows := manager.SInfrasResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
|
|
vpcRows := manager.SVpcResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
|
|
zoneRows := manager.SZoneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
|
|
|
|
for i := range rows {
|
|
rows[i] = api.WireDetails{
|
|
InfrasResourceBaseDetails: stdRows[i],
|
|
VpcResourceInfo: vpcRows[i],
|
|
ZoneResourceInfoBase: zoneRows[i].ZoneResourceInfoBase,
|
|
}
|
|
wire := objs[i].(*SWire)
|
|
rows[i].Networks, _ = wire.NetworkCount()
|
|
}
|
|
|
|
return rows
|
|
}
|
|
|
|
func (man *SWireManager) removeWiresByVpc(ctx context.Context, userCred mcclient.TokenCredential, vpc *SVpc) error {
|
|
wires := []SWire{}
|
|
q := man.Query().Equals("vpc_id", vpc.Id)
|
|
err := db.FetchModelObjects(man, q, &wires)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
var errs []error
|
|
for i := range wires {
|
|
wire := &wires[i]
|
|
if err := wire.Delete(ctx, userCred); err != nil {
|
|
errs = append(errs, err)
|
|
}
|
|
}
|
|
return errors.NewAggregate(errs)
|
|
}
|
|
|
|
func (self *SWire) IsManaged() bool {
|
|
vpc := self.GetVpc()
|
|
if vpc == nil {
|
|
return false
|
|
}
|
|
return vpc.IsManaged()
|
|
}
|
|
|
|
func (model *SWire) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
|
|
return model.SInfrasResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
|
|
}
|
|
|
|
func (wire *SWire) GetChangeOwnerCandidateDomainIds() []string {
|
|
candidates := [][]string{
|
|
wire.SInfrasResourceBase.GetChangeOwnerCandidateDomainIds(),
|
|
}
|
|
vpc := wire.GetVpc()
|
|
if vpc != nil {
|
|
candidates = append(candidates, db.ISharableChangeOwnerCandidateDomainIds(vpc))
|
|
}
|
|
return db.ISharableMergeChangeOwnerCandidateDomainIds(wire, candidates...)
|
|
}
|
|
|
|
func (wire *SWire) GetRequiredSharedDomainIds() []string {
|
|
networks, _ := wire.getNetworks()
|
|
if len(networks) == 0 {
|
|
return wire.SInfrasResourceBase.GetRequiredSharedDomainIds()
|
|
}
|
|
requires := make([][]string, len(networks))
|
|
for i := range networks {
|
|
requires[i] = db.ISharableChangeOwnerCandidateDomainIds(&networks[i])
|
|
}
|
|
return db.ISharableMergeShareRequireDomainIds(requires...)
|
|
}
|