Files
cloudpods/pkg/compute/models/loadbalanceropenstackcachedlbb.go

300 lines
10 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"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/compare"
"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/cloudprovider"
"yunion.io/x/onecloud/pkg/mcclient"
)
// +onecloud:swagger-gen-ignore
type SOpenstackCachedLbManager struct {
SLoadbalancerLogSkipper
db.SVirtualResourceBaseManager
}
var OpenstackCachedLbManager *SOpenstackCachedLbManager
func init() {
OpenstackCachedLbManager = &SOpenstackCachedLbManager{
SVirtualResourceBaseManager: db.NewVirtualResourceBaseManager(
SOpenstackCachedLb{},
"openstackcachedlbbs_tbl",
"openstackcachedlbb",
"openstackcachedlbbs",
),
}
OpenstackCachedLbManager.SetVirtualObject(OpenstackCachedLbManager)
}
type SOpenstackCachedLb struct {
db.SVirtualResourceBase
db.SExternalizedResourceBase
SManagedResourceBase
SCloudregionResourceBase
BackendServerId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` // 后端服务器 实例ID
BackendId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"` // 本地loadbalancebackend id
CachedBackendGroupId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"`
}
func (manager *SOpenstackCachedLbManager) GetResourceCount() ([]db.SScopeResourceCount, error) {
virts := manager.Query().IsFalse("pending_deleted")
return db.CalculateResourceCount(virts, "tenant_id")
}
func (man *SOpenstackCachedLbManager) GetBackendsByLocalBackendId(backendId string) ([]SOpenstackCachedLb, error) {
loadbalancerBackends := []SOpenstackCachedLb{}
q := man.Query().IsFalse("pending_deleted").Equals("backend_id", backendId)
if err := db.FetchModelObjects(man, q, &loadbalancerBackends); err != nil {
return nil, err
}
return loadbalancerBackends, nil
}
func (man *SOpenstackCachedLbManager) CreateOpenstackCachedLb(ctx context.Context, userCred mcclient.TokenCredential, lbb *SLoadbalancerBackend, cachedLbbg *SOpenstackCachedLbbg, extLoadbalancerBackend cloudprovider.ICloudLoadbalancerBackend, syncOwnerId mcclient.IIdentityProvider) (*SOpenstackCachedLb, error) {
cachedlbb := &SOpenstackCachedLb{}
cachedlbb.SetModelManager(man, cachedlbb)
cachedlbb.CloudregionId = cachedLbbg.CloudregionId
cachedlbb.ManagerId = cachedLbbg.ManagerId
cachedlbb.CachedBackendGroupId = cachedLbbg.GetId()
cachedlbb.BackendId = lbb.GetId()
cachedlbb.ExternalId = extLoadbalancerBackend.GetGlobalId()
if err := cachedlbb.constructFieldsFromCloudLoadbalancerBackend(extLoadbalancerBackend); err != nil {
return nil, err
}
var err = func() error {
lockman.LockRawObject(ctx, man.Keyword(), "name")
defer lockman.ReleaseRawObject(ctx, man.Keyword(), "name")
newName, err := db.GenerateName(ctx, man, syncOwnerId, extLoadbalancerBackend.GetName())
if err != nil {
return err
}
cachedlbb.Name = newName
return man.TableSpec().Insert(ctx, cachedlbb)
}()
if err != nil {
return nil, errors.Wrapf(err, "Insert")
}
SyncCloudProject(userCred, lbb, syncOwnerId, extLoadbalancerBackend, cachedLbbg.ManagerId)
db.OpsLog.LogEvent(cachedlbb, db.ACT_CREATE, lbb.GetShortDesc(ctx), userCred)
return cachedlbb, nil
}
func (lbb *SOpenstackCachedLb) GetCachedBackendGroup() (*SOpenstackCachedLbbg, error) {
lbbg, err := db.FetchById(OpenstackCachedLbbgManager, lbb.CachedBackendGroupId)
if err != nil {
return nil, err
}
return lbbg.(*SOpenstackCachedLbbg), nil
}
func (man *SOpenstackCachedLbManager) getLoadbalancerBackendsByLoadbalancerBackendgroup(loadbalancerBackendgroup *SOpenstackCachedLbbg) ([]SOpenstackCachedLb, error) {
loadbalancerBackends := []SOpenstackCachedLb{}
q := man.Query().Equals("cached_backend_group_id", loadbalancerBackendgroup.Id)
if err := db.FetchModelObjects(man, q, &loadbalancerBackends); err != nil {
return nil, err
}
return loadbalancerBackends, nil
}
func (man *SOpenstackCachedLbManager) SyncLoadbalancerBackends(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, loadbalancerBackendgroup *SOpenstackCachedLbbg, lbbs []cloudprovider.ICloudLoadbalancerBackend, syncRange *SSyncRange) compare.SyncResult {
syncOwnerId := provider.GetOwnerId()
lockman.LockRawObject(ctx, "backends", loadbalancerBackendgroup.Id)
defer lockman.ReleaseRawObject(ctx, "backends", loadbalancerBackendgroup.Id)
syncResult := compare.SyncResult{}
dbLbbs, err := man.getLoadbalancerBackendsByLoadbalancerBackendgroup(loadbalancerBackendgroup)
if err != nil {
syncResult.Error(err)
return syncResult
}
removed := []SOpenstackCachedLb{}
commondb := []SOpenstackCachedLb{}
commonext := []cloudprovider.ICloudLoadbalancerBackend{}
added := []cloudprovider.ICloudLoadbalancerBackend{}
err = compare.CompareSets(dbLbbs, lbbs, &removed, &commondb, &commonext, &added)
if err != nil {
syncResult.Error(err)
return syncResult
}
for i := 0; i < len(removed); i++ {
err = removed[i].syncRemoveCloudLoadbalancerBackend(ctx, userCred)
if err != nil {
syncResult.DeleteError(err)
} else {
syncResult.Delete()
}
}
for i := 0; i < len(commondb); i++ {
err = commondb[i].SyncWithCloudLoadbalancerBackend(ctx, userCred, commonext[i], syncOwnerId)
if err != nil {
syncResult.UpdateError(err)
} else {
syncMetadata(ctx, userCred, &commondb[i], commonext[i])
syncResult.Update()
}
}
for i := 0; i < len(added); i++ {
local, err := man.newFromCloudLoadbalancerBackend(ctx, userCred, loadbalancerBackendgroup, added[i], syncOwnerId)
if err != nil {
syncResult.AddError(err)
} else {
syncMetadata(ctx, userCred, local, added[i])
syncResult.Add()
}
}
return syncResult
}
func (lbb *SOpenstackCachedLb) syncRemoveCloudLoadbalancerBackend(ctx context.Context, userCred mcclient.TokenCredential) error {
lockman.LockObject(ctx, lbb)
defer lockman.ReleaseObject(ctx, lbb)
err := lbb.ValidateDeleteCondition(ctx, nil)
if err != nil { // cannot delete
lbb.SetStatus(userCred, api.LB_STATUS_UNKNOWN, "sync to delete")
return errors.Wrap(err, "lbb.ValidateDeleteCondition(ctx)")
}
lbb.SetModelManager(OpenstackCachedLbManager, lbb)
err = db.DeleteModel(ctx, userCred, lbb)
if err != nil {
return err
}
return nil
}
func (lbb *SOpenstackCachedLb) constructFieldsFromCloudLoadbalancerBackend(extLoadbalancerBackend cloudprovider.ICloudLoadbalancerBackend) error {
lbb.Status = extLoadbalancerBackend.GetStatus()
instance, err := db.FetchByExternalIdAndManagerId(GuestManager, extLoadbalancerBackend.GetBackendId(), func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
sq := HostManager.Query().SubQuery()
return q.Join(sq, sqlchemy.Equals(sq.Field("id"), q.Field("host_id"))).Filter(sqlchemy.Equals(sq.Field("manager_id"), lbb.ManagerId))
})
if err != nil {
return err
}
guest := instance.(*SGuest)
lbb.BackendServerId = guest.Id
return nil
}
func (lbb *SOpenstackCachedLb) SyncWithCloudLoadbalancerBackend(ctx context.Context, userCred mcclient.TokenCredential, extLoadbalancerBackend cloudprovider.ICloudLoadbalancerBackend, syncOwnerId mcclient.IIdentityProvider) error {
lbb.SetModelManager(OpenstackCachedLbManager, lbb)
cacheLbbg, err := lbb.GetCachedBackendGroup()
if err != nil {
return errors.Wrap(err, "OpenstackCachedLb.SyncWithCloudLoadbalancerBackend.GetCachedBackendGroup")
}
localLbbg, err := cacheLbbg.GetLocalBackendGroup(ctx, userCred)
if err != nil {
return errors.Wrap(err, "OpenstackCachedLb.SyncWithCloudLoadbalancerBackend.GetLocalBackendGroup")
}
locallbb, err := newLocalBackendFromCloudLoadbalancerBackend(ctx, userCred, localLbbg, extLoadbalancerBackend, syncOwnerId)
if err != nil {
return errors.Wrap(err, "OpenstackCachedLb.SyncWithCloudLoadbalancerBackend.newLocalBackendFromCloudLoadbalancerBackend")
}
diff, err := db.UpdateWithLock(ctx, lbb, func() error {
if locallbb != nil {
lbb.BackendId = locallbb.GetId()
}
return lbb.constructFieldsFromCloudLoadbalancerBackend(extLoadbalancerBackend)
})
if err != nil {
return err
}
db.OpsLog.LogSyncUpdate(lbb, diff, userCred)
SyncCloudProject(userCred, lbb, syncOwnerId, extLoadbalancerBackend, lbb.ManagerId)
return nil
}
func (man *SOpenstackCachedLbManager) newFromCloudLoadbalancerBackend(ctx context.Context, userCred mcclient.TokenCredential, loadbalancerBackendgroup *SOpenstackCachedLbbg, extLoadbalancerBackend cloudprovider.ICloudLoadbalancerBackend, syncOwnerId mcclient.IIdentityProvider) (*SOpenstackCachedLb, error) {
localBackendGroup, err := loadbalancerBackendgroup.GetLocalBackendGroup(ctx, userCred)
if err != nil {
return nil, err
}
// openstack lb后端是ip:port 不一定有server映射
if len(extLoadbalancerBackend.GetBackendId()) == 0 {
return nil, errors.Wrap(cloudprovider.ErrNotFound, "extLoadbalancerBackend.GetBackendId()")
}
locallbb, err := newLocalBackendFromCloudLoadbalancerBackend(ctx, userCred, localBackendGroup, extLoadbalancerBackend, syncOwnerId)
if err != nil {
return nil, err
}
lbb := &SOpenstackCachedLb{}
lbb.SetModelManager(man, lbb)
lbb.CloudregionId = loadbalancerBackendgroup.CloudregionId
lbb.ManagerId = loadbalancerBackendgroup.ManagerId
lbb.CachedBackendGroupId = loadbalancerBackendgroup.Id
lbb.BackendId = locallbb.GetId()
lbb.ExternalId = extLoadbalancerBackend.GetGlobalId()
if err := lbb.constructFieldsFromCloudLoadbalancerBackend(extLoadbalancerBackend); err != nil {
return nil, err
}
err = func() error {
lockman.LockRawObject(ctx, man.Keyword(), "name")
defer lockman.ReleaseRawObject(ctx, man.Keyword(), "name")
lbb.Name, err = db.GenerateName(ctx, man, syncOwnerId, extLoadbalancerBackend.GetName())
if err != nil {
return err
}
return man.TableSpec().Insert(ctx, lbb)
}()
if err != nil {
return nil, err
}
SyncCloudProject(userCred, lbb, syncOwnerId, extLoadbalancerBackend, loadbalancerBackendgroup.ManagerId)
db.OpsLog.LogEvent(lbb, db.ACT_CREATE, lbb.GetShortDesc(ctx), userCred)
return lbb, nil
}