mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-05-07 22:24:32 +08:00
854 lines
28 KiB
Go
854 lines
28 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"
|
|
"fmt"
|
|
|
|
"yunion.io/x/cloudmux/pkg/cloudprovider"
|
|
"yunion.io/x/jsonutils"
|
|
"yunion.io/x/log"
|
|
"yunion.io/x/pkg/errors"
|
|
"yunion.io/x/pkg/gotypes"
|
|
"yunion.io/x/pkg/util/compare"
|
|
"yunion.io/x/pkg/util/rbacscope"
|
|
"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/notifyclient"
|
|
"yunion.io/x/onecloud/pkg/cloudcommon/policy"
|
|
"yunion.io/x/onecloud/pkg/cloudcommon/validators"
|
|
"yunion.io/x/onecloud/pkg/httperrors"
|
|
"yunion.io/x/onecloud/pkg/mcclient"
|
|
"yunion.io/x/onecloud/pkg/util/stringutils2"
|
|
)
|
|
|
|
// +onecloud:swagger-gen-model-singular=loadbalancerbackendgroup
|
|
// +onecloud:swagger-gen-model-plural=loadbalancerbackendgroups
|
|
type SLoadbalancerBackendGroupManager struct {
|
|
SLoadbalancerLogSkipper
|
|
db.SStatusStandaloneResourceBaseManager
|
|
db.SExternalizedResourceBaseManager
|
|
SLoadbalancerResourceBaseManager
|
|
}
|
|
|
|
var LoadbalancerBackendGroupManager *SLoadbalancerBackendGroupManager
|
|
|
|
func init() {
|
|
LoadbalancerBackendGroupManager = &SLoadbalancerBackendGroupManager{
|
|
SStatusStandaloneResourceBaseManager: db.NewStatusStandaloneResourceBaseManager(
|
|
SLoadbalancerBackendGroup{},
|
|
"loadbalancerbackendgroups_tbl",
|
|
"loadbalancerbackendgroup",
|
|
"loadbalancerbackendgroups",
|
|
),
|
|
}
|
|
LoadbalancerBackendGroupManager.SetVirtualObject(LoadbalancerBackendGroupManager)
|
|
}
|
|
|
|
type SLoadbalancerBackendGroup struct {
|
|
db.SStatusStandaloneResourceBase
|
|
db.SExternalizedResourceBase
|
|
|
|
SLoadbalancerResourceBase `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"`
|
|
LoadbalancerHealthCheckId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"`
|
|
Scheduler string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"`
|
|
|
|
Type string `width:"36" charset:"ascii" nullable:"false" list:"user" default:"normal" create:"optional"`
|
|
}
|
|
|
|
func (manager *SLoadbalancerBackendGroupManager) ResourceScope() rbacscope.TRbacScope {
|
|
return rbacscope.ScopeProject
|
|
}
|
|
|
|
func (self *SLoadbalancerBackendGroup) GetOwnerId() mcclient.IIdentityProvider {
|
|
lb, err := self.GetLoadbalancer()
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
return lb.GetOwnerId()
|
|
}
|
|
|
|
func (manager *SLoadbalancerBackendGroupManager) FetchOwnerId(ctx context.Context, data jsonutils.JSONObject) (mcclient.IIdentityProvider, error) {
|
|
lbId, _ := data.GetString("loadbalancer_id")
|
|
if len(lbId) > 0 {
|
|
lb, err := db.FetchById(LoadbalancerManager, lbId)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "db.FetchById(LoadbalancerManager, %s)", lbId)
|
|
}
|
|
return lb.(*SLoadbalancer).GetOwnerId(), nil
|
|
}
|
|
return db.FetchProjectInfo(ctx, data)
|
|
}
|
|
|
|
func (manager *SLoadbalancerBackendGroupManager) FilterByOwner(ctx context.Context, q *sqlchemy.SQuery, man db.FilterByOwnerProvider, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, scope rbacscope.TRbacScope) *sqlchemy.SQuery {
|
|
if ownerId != nil {
|
|
sq := LoadbalancerManager.Query("id")
|
|
switch scope {
|
|
case rbacscope.ScopeProject:
|
|
sq = sq.Equals("tenant_id", ownerId.GetProjectId())
|
|
return q.In("loadbalancer_id", sq.SubQuery())
|
|
case rbacscope.ScopeDomain:
|
|
sq = sq.Equals("domain_id", ownerId.GetProjectDomainId())
|
|
return q.In("loadbalancer_id", sq.SubQuery())
|
|
}
|
|
}
|
|
return q
|
|
}
|
|
|
|
// 负载均衡后端服务器组列表
|
|
func (man *SLoadbalancerBackendGroupManager) ListItemFilter(
|
|
ctx context.Context,
|
|
q *sqlchemy.SQuery,
|
|
userCred mcclient.TokenCredential,
|
|
query api.LoadbalancerBackendGroupListInput,
|
|
) (*sqlchemy.SQuery, error) {
|
|
q, err := man.SStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusStandaloneResourceListInput)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ListItemFilter")
|
|
}
|
|
|
|
q, err = man.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "SExternalizedResourceBaseManager.ListItemFilter")
|
|
}
|
|
|
|
q, err = man.SLoadbalancerResourceBaseManager.ListItemFilter(ctx, q, userCred, query.LoadbalancerFilterListInput)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "SLoadbalancerResourceBaseManager.ListItemFilter")
|
|
}
|
|
|
|
if query.NoRef != nil && *query.NoRef {
|
|
q, err = man.FilterZeroRefBackendGroup(q)
|
|
if err != nil {
|
|
log.Errorf("SLoadbalancerBackendGroupManager ListItemFilter %s", err)
|
|
return nil, httperrors.NewInternalServerError("query backend group releated resource failed.")
|
|
}
|
|
}
|
|
|
|
if len(query.Type) > 0 {
|
|
q = q.In("type", query.Type)
|
|
}
|
|
|
|
return q, nil
|
|
}
|
|
|
|
func (man *SLoadbalancerBackendGroupManager) OrderByExtraFields(
|
|
ctx context.Context,
|
|
q *sqlchemy.SQuery,
|
|
userCred mcclient.TokenCredential,
|
|
query api.LoadbalancerBackendGroupListInput,
|
|
) (*sqlchemy.SQuery, error) {
|
|
var err error
|
|
|
|
q, err = man.SStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusStandaloneResourceListInput)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.OrderByExtraFields")
|
|
}
|
|
q, err = man.SLoadbalancerResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.LoadbalancerFilterListInput)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "SLoadbalancerResourceBaseManager.OrderByExtraFields")
|
|
}
|
|
|
|
return q, nil
|
|
}
|
|
|
|
func (man *SLoadbalancerBackendGroupManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
|
|
var err error
|
|
|
|
q, err = man.SStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field)
|
|
if err == nil {
|
|
return q, nil
|
|
}
|
|
q, err = man.SLoadbalancerResourceBaseManager.QueryDistinctExtraField(q, field)
|
|
if err == nil {
|
|
return q, nil
|
|
}
|
|
|
|
return q, httperrors.ErrNotFound
|
|
}
|
|
|
|
type sBackendgroup struct {
|
|
Name string
|
|
LoadbalancerId string
|
|
}
|
|
|
|
func (self *SLoadbalancerBackendGroup) GetUniqValues() jsonutils.JSONObject {
|
|
return jsonutils.Marshal(sBackendgroup{Name: self.Name, LoadbalancerId: self.LoadbalancerId})
|
|
}
|
|
|
|
func (manager *SLoadbalancerBackendGroupManager) FetchUniqValues(ctx context.Context, data jsonutils.JSONObject) jsonutils.JSONObject {
|
|
info := sBackendgroup{}
|
|
data.Unmarshal(&info)
|
|
return jsonutils.Marshal(info)
|
|
}
|
|
|
|
func (manager *SLoadbalancerBackendGroupManager) FilterByUniqValues(q *sqlchemy.SQuery, values jsonutils.JSONObject) *sqlchemy.SQuery {
|
|
info := sBackendgroup{}
|
|
values.Unmarshal(&info)
|
|
if len(info.LoadbalancerId) > 0 {
|
|
q = q.Equals("loadbalancer_id", info.LoadbalancerId)
|
|
}
|
|
if len(info.Name) > 0 {
|
|
q = q.Equals("name", info.Name)
|
|
}
|
|
return q
|
|
}
|
|
|
|
func (man *SLoadbalancerBackendGroupManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input *api.LoadbalancerBackendGroupCreateInput) (*api.LoadbalancerBackendGroupCreateInput, error) {
|
|
lbObj, err := validators.ValidateModel(ctx, userCred, LoadbalancerManager, &input.LoadbalancerId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
lb := lbObj.(*SLoadbalancer)
|
|
input.StatusStandaloneResourceCreateInput, err = man.SStatusStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.StatusStandaloneResourceCreateInput)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if len(input.LoadbalancerHealthCheckId) > 0 {
|
|
_, err := validators.ValidateModel(ctx, userCred, LoadbalancerHealthCheckManager, &input.LoadbalancerHealthCheckId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
}
|
|
|
|
region, err := lb.GetRegion()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
lbIsManaged := lb.IsManaged()
|
|
for i := 0; i < len(input.Backends); i++ {
|
|
if len(input.Backends[i].BackendType) == 0 {
|
|
input.Backends[i].BackendType = api.LB_BACKEND_GUEST
|
|
}
|
|
if input.Backends[i].Weight < 0 || input.Backends[i].Weight > 256 {
|
|
return nil, httperrors.NewInputParameterError("weight %d not support, only support range 0 ~ 256", input.Backends[i].Weight)
|
|
}
|
|
if input.Backends[i].Port < 1 || input.Backends[i].Port > 65535 {
|
|
return nil, httperrors.NewInputParameterError("port %d not support, only support range 1 ~ 65535", input.Backends[i].Port)
|
|
}
|
|
if len(input.Backends[i].Id) == 0 && input.Backends[i].BackendType != api.LB_BACKEND_ADDRESS {
|
|
return nil, httperrors.NewMissingParameterError("Missing backend id")
|
|
}
|
|
|
|
var backendRegion *SCloudregion
|
|
|
|
switch input.Backends[i].BackendType {
|
|
case api.LB_BACKEND_GUEST:
|
|
guestObj, err := validators.ValidateModel(ctx, userCred, GuestManager, &input.Backends[i].Id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
guest := guestObj.(*SGuest)
|
|
host, err := guest.GetHost()
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "GetHost")
|
|
}
|
|
input.Backends[i].ZoneId = host.ZoneId
|
|
input.Backends[i].HostName = host.Name
|
|
input.Backends[i].Id = guest.Id
|
|
input.Backends[i].Name = guest.Name
|
|
input.Backends[i].ExternalId = guest.ExternalId
|
|
|
|
address, err := guest.GetAddress()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
input.Backends[i].Address = address
|
|
backendRegion, _ = host.GetRegion()
|
|
case api.LB_BACKEND_HOST:
|
|
if db.IsAdminAllowCreate(userCred, man).Result.IsDeny() {
|
|
return nil, httperrors.NewForbiddenError("only sysadmin can specify host as backend")
|
|
}
|
|
hostObj, err := validators.ValidateModel(ctx, userCred, HostManager, &input.Backends[i].Id)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
host := hostObj.(*SHost)
|
|
input.Backends[i].Id = host.Id
|
|
input.Backends[i].Name = host.Name
|
|
input.Backends[i].ExternalId = host.ExternalId
|
|
input.Backends[i].Address = host.AccessIp
|
|
backendRegion, _ = host.GetRegion()
|
|
case api.LB_BACKEND_ADDRESS:
|
|
default:
|
|
return nil, httperrors.NewInputParameterError("unexpected backend type %s", input.Backends[i].BackendType)
|
|
}
|
|
if lbIsManaged && backendRegion != nil && backendRegion.Id != region.Id {
|
|
return nil, httperrors.NewInputParameterError("region of backend %d does not match that of lb's", i)
|
|
}
|
|
}
|
|
return region.GetDriver().ValidateCreateLoadbalancerBackendGroupData(ctx, userCred, lb, input)
|
|
}
|
|
|
|
func (lbbg *SLoadbalancerBackendGroup) GetLoadbalancerListenerRules() ([]SLoadbalancerListenerRule, error) {
|
|
q := LoadbalancerListenerRuleManager.Query().Equals("backend_group_id", lbbg.Id)
|
|
rules := []SLoadbalancerListenerRule{}
|
|
err := db.FetchModelObjects(LoadbalancerListenerRuleManager, q, &rules)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return rules, nil
|
|
}
|
|
|
|
func (lbbg *SLoadbalancerBackendGroup) GetLoadbalancerListeners() ([]SLoadbalancerListener, error) {
|
|
q := LoadbalancerListenerManager.Query().Equals("backend_group_id", lbbg.Id)
|
|
listeners := []SLoadbalancerListener{}
|
|
err := db.FetchModelObjects(LoadbalancerListenerManager, q, &listeners)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return listeners, nil
|
|
}
|
|
|
|
func (lbbg *SLoadbalancerBackendGroup) GetLoadbalancer() (*SLoadbalancer, error) {
|
|
lb, err := LoadbalancerManager.FetchById(lbbg.LoadbalancerId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return lb.(*SLoadbalancer), nil
|
|
}
|
|
|
|
func (llbg *SLoadbalancerBackendGroup) GetRegion() (*SCloudregion, error) {
|
|
loadbalancer, err := llbg.GetLoadbalancer()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return loadbalancer.GetRegion()
|
|
}
|
|
|
|
func (lbbg *SLoadbalancerBackendGroup) GetIRegion(ctx context.Context) (cloudprovider.ICloudRegion, error) {
|
|
loadbalancer, err := lbbg.GetLoadbalancer()
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "GetLoadbalancer")
|
|
}
|
|
return loadbalancer.GetIRegion(ctx)
|
|
}
|
|
|
|
func (lbbg *SLoadbalancerBackendGroup) GetBackends() ([]SLoadbalancerBackend, error) {
|
|
backends := make([]SLoadbalancerBackend, 0)
|
|
q := LoadbalancerBackendManager.Query().Equals("backend_group_id", lbbg.GetId())
|
|
err := db.FetchModelObjects(LoadbalancerBackendManager, q, &backends)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
return backends, nil
|
|
}
|
|
|
|
// 返回值 TotalRef
|
|
func (lbbg *SLoadbalancerBackendGroup) RefCount() (int, error) {
|
|
men := lbbg.getRefManagers()
|
|
var count int
|
|
for _, m := range men {
|
|
cnt, err := lbbg.refCount(m)
|
|
if err != nil {
|
|
return -1, err
|
|
}
|
|
count += cnt
|
|
}
|
|
|
|
return count, nil
|
|
}
|
|
|
|
func (lbbg *SLoadbalancerBackendGroup) refCount(man db.IModelManager) (int, error) {
|
|
return man.Query().Equals("backend_group_id", lbbg.Id).CountWithError()
|
|
}
|
|
|
|
func lbbgRefManagers() []db.IModelManager {
|
|
return []db.IModelManager{
|
|
LoadbalancerListenerManager,
|
|
}
|
|
}
|
|
|
|
func (lbbg *SLoadbalancerBackendGroup) getRefManagers() []db.IModelManager {
|
|
// 引用Backend Group的数据库
|
|
return lbbgRefManagers()
|
|
}
|
|
|
|
func (man *SLoadbalancerBackendGroupManager) FilterZeroRefBackendGroup(q *sqlchemy.SQuery) (*sqlchemy.SQuery, error) {
|
|
ids := []string{}
|
|
sq := q.SubQuery()
|
|
rows, err := sq.Query(sq.Field("id")).Rows()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
defer rows.Close()
|
|
for rows.Next() {
|
|
var lbbgId string
|
|
err = rows.Scan(&lbbgId)
|
|
if err != nil {
|
|
log.Errorf("Get backendgroup id with scan err: %v", err)
|
|
return nil, err
|
|
}
|
|
ids = append(ids, lbbgId)
|
|
}
|
|
|
|
for _, m := range lbbgRefManagers() {
|
|
_ids := m.Query("backend_group_id").In("backend_group_id", ids).SubQuery()
|
|
q = q.NotIn("id", _ids)
|
|
}
|
|
|
|
return q, nil
|
|
}
|
|
|
|
func (lbbg *SLoadbalancerBackendGroup) isDefault(ctx context.Context) (bool, error) {
|
|
q := LoadbalancerManager.Query().Equals("backend_group_id", lbbg.GetId()).Equals("id", lbbg.LoadbalancerId)
|
|
count, err := q.CountWithError()
|
|
if err != nil {
|
|
return false, errors.Wrap(err, "loadbalancerBackendGroup.isDefault")
|
|
}
|
|
return count > 0, nil
|
|
}
|
|
|
|
func (lbbg *SLoadbalancerBackendGroup) ValidateDeleteCondition(ctx context.Context, info *api.LoadbalancerBackendGroupDetails) error {
|
|
if gotypes.IsNil(info) {
|
|
info = &api.LoadbalancerBackendGroupDetails{}
|
|
info.IsDefault, _ = lbbg.isDefault(ctx)
|
|
info.LbListenerCount, _ = lbbg.GetListenerCount()
|
|
}
|
|
if info.IsDefault {
|
|
return httperrors.NewResourceBusyError("backend group %s is default backend group", lbbg.Id)
|
|
}
|
|
if info.LbListenerCount > 0 {
|
|
return httperrors.NewResourceBusyError("backend group %s is still referred by %d %s",
|
|
lbbg.Id, info.LbListenerCount, LoadbalancerListenerManager.KeywordPlural())
|
|
}
|
|
|
|
return lbbg.SStatusStandaloneResourceBase.ValidateDeleteCondition(ctx, nil)
|
|
}
|
|
|
|
func (man *SLoadbalancerBackendGroupManager) FetchCustomizeColumns(
|
|
ctx context.Context,
|
|
userCred mcclient.TokenCredential,
|
|
query jsonutils.JSONObject,
|
|
objs []interface{},
|
|
fields stringutils2.SSortedStrings,
|
|
isList bool,
|
|
) []api.LoadbalancerBackendGroupDetails {
|
|
rows := make([]api.LoadbalancerBackendGroupDetails, len(objs))
|
|
|
|
stdRows := man.SStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
|
|
lbRows := man.SLoadbalancerResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
|
|
|
|
lbIds := make([]string, len(objs))
|
|
lbbgIds := make([]string, len(objs))
|
|
hcIds := make([]string, len(objs))
|
|
for i := range rows {
|
|
rows[i] = api.LoadbalancerBackendGroupDetails{
|
|
StatusStandaloneResourceDetails: stdRows[i],
|
|
LoadbalancerResourceInfo: lbRows[i],
|
|
}
|
|
lbbg := objs[i].(*SLoadbalancerBackendGroup)
|
|
lbIds[i] = lbbg.LoadbalancerId
|
|
lbbgIds[i] = lbbg.Id
|
|
hcIds[i] = lbbg.LoadbalancerHealthCheckId
|
|
}
|
|
|
|
lbs := map[string]SLoadbalancer{}
|
|
err := db.FetchStandaloneObjectsByIds(LoadbalancerManager, lbIds, &lbs)
|
|
if err != nil {
|
|
return rows
|
|
}
|
|
|
|
defaultLbgIds := []string{}
|
|
virObjs := make([]interface{}, len(objs))
|
|
for i := range rows {
|
|
if lb, ok := lbs[lbIds[i]]; ok {
|
|
virObjs[i] = &lb
|
|
rows[i].ProjectId = lb.ProjectId
|
|
if !utils.IsInStringArray(lb.BackendGroupId, defaultLbgIds) {
|
|
defaultLbgIds = append(defaultLbgIds, lb.BackendGroupId)
|
|
}
|
|
}
|
|
}
|
|
|
|
hcMap, err := db.FetchIdNameMap2(LoadbalancerHealthCheckManager, hcIds)
|
|
if err != nil {
|
|
return rows
|
|
}
|
|
|
|
for i := range rows {
|
|
rows[i].IsDefault = utils.IsInStringArray(lbbgIds[i], defaultLbgIds)
|
|
if hcId, ok := hcMap[hcIds[i]]; ok {
|
|
rows[i].LoadbalancerHealthCheck = hcId
|
|
}
|
|
}
|
|
|
|
for i := range objs {
|
|
q := LoadbalancerListenerManager.Query().Equals("backend_group_id", lbbgIds[i])
|
|
ownerId, queryScope, err, _ := db.FetchCheckQueryOwnerScope(ctx, userCred, query, LoadbalancerListenerManager, policy.PolicyActionList, true)
|
|
if err != nil {
|
|
log.Errorf("FetchCheckQueryOwnerScope error: %v", err)
|
|
return rows
|
|
}
|
|
|
|
q = LoadbalancerListenerManager.FilterByOwner(ctx, q, LoadbalancerListenerManager, userCred, ownerId, queryScope)
|
|
rows[i].LbListenerCount, _ = q.CountWithError()
|
|
}
|
|
|
|
return rows
|
|
}
|
|
|
|
func (lbbg *SLoadbalancerBackendGroup) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
|
|
lbbg.SStatusStandaloneResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
|
|
input := &api.LoadbalancerBackendGroupCreateInput{}
|
|
data.Unmarshal(input)
|
|
for i := range input.Backends {
|
|
backend := &SLoadbalancerBackend{
|
|
BackendId: input.Backends[i].Id,
|
|
BackendType: input.Backends[i].BackendType,
|
|
BackendRole: input.Backends[i].BackendRole,
|
|
Weight: input.Backends[i].Weight,
|
|
Address: input.Backends[i].Address,
|
|
Port: input.Backends[i].Port,
|
|
}
|
|
backend.Name = input.Backends[i].Name
|
|
backend.BackendGroupId = lbbg.Id
|
|
backend.Status = api.LB_STATUS_ENABLED
|
|
if backend.BackendType == api.LB_BACKEND_GUEST {
|
|
backend.Name = fmt.Sprintf("%s-%s-%s", lbbg.Name, backend.BackendType, backend.Name)
|
|
}
|
|
backend.SetModelManager(LoadbalancerBackendManager, backend)
|
|
LoadbalancerBackendManager.TableSpec().Insert(ctx, backend)
|
|
}
|
|
lbbg.StartLoadBalancerBackendGroupCreateTask(ctx, userCred, "")
|
|
}
|
|
|
|
func (lbbg *SLoadbalancerBackendGroup) StartLoadBalancerBackendGroupCreateTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) {
|
|
lbbg.SetStatus(ctx, userCred, api.LB_CREATING, "")
|
|
err := func() error {
|
|
task, err := taskman.TaskManager.NewTask(ctx, "LoadbalancerLoadbalancerBackendGroupCreateTask", lbbg, userCred, nil, parentTaskId, "", nil)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "NewTask")
|
|
}
|
|
return task.ScheduleRun(nil)
|
|
}()
|
|
if err != nil {
|
|
lbbg.SetStatus(ctx, userCred, api.LB_CREATE_FAILED, err.Error())
|
|
}
|
|
}
|
|
|
|
func (self *SLoadbalancerBackendGroup) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
|
|
backends, err := self.GetBackends()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
for i := range backends {
|
|
err := backends[i].RealDelete(ctx, userCred)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "RealDelete backend %s", backends[i].Id)
|
|
}
|
|
}
|
|
return self.SStatusStandaloneResourceBase.Delete(ctx, userCred)
|
|
}
|
|
|
|
func (lbbg *SLoadbalancerBackendGroup) PerformPurge(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
|
|
parasm := jsonutils.NewDict()
|
|
parasm.Add(jsonutils.JSONTrue, "purge")
|
|
return nil, lbbg.StartLoadBalancerBackendGroupDeleteTask(ctx, userCred, parasm, "")
|
|
}
|
|
|
|
func (lbbg *SLoadbalancerBackendGroup) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
|
|
lbbg.SetStatus(ctx, userCred, api.LB_STATUS_DELETING, "")
|
|
return lbbg.StartLoadBalancerBackendGroupDeleteTask(ctx, userCred, jsonutils.NewDict(), "")
|
|
}
|
|
|
|
func (lbbg *SLoadbalancerBackendGroup) StartLoadBalancerBackendGroupDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error {
|
|
task, err := taskman.TaskManager.NewTask(ctx, "LoadbalancerBackendGroupDeleteTask", lbbg, userCred, params, parentTaskId, "", nil)
|
|
if err != nil {
|
|
return errors.Wrapf(err, "NewTask")
|
|
}
|
|
return task.ScheduleRun(nil)
|
|
}
|
|
|
|
func (lbbg *SLoadbalancerBackendGroup) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
|
|
return nil
|
|
}
|
|
|
|
func (lbbg *SLoadbalancerBackendGroup) GetListener() *SLoadbalancerListener {
|
|
ret := &SLoadbalancerListener{}
|
|
err := LoadbalancerListenerManager.Query().Equals("backend_group_id", lbbg.Id).First(ret)
|
|
if err != nil {
|
|
return nil
|
|
}
|
|
return ret
|
|
}
|
|
|
|
func (lbbg *SLoadbalancerBackendGroup) GetListenerCount() (int, error) {
|
|
return LoadbalancerListenerManager.Query().Equals("backend_group_id", lbbg.Id).CountWithError()
|
|
}
|
|
|
|
func (lbbg *SLoadbalancerBackendGroup) GetBackendsParams() ([]cloudprovider.SLoadbalancerBackend, error) {
|
|
backends, err := lbbg.GetBackends()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ret := make([]cloudprovider.SLoadbalancerBackend, len(backends))
|
|
for i := range backends {
|
|
b := backends[i]
|
|
|
|
externalId := ""
|
|
guest := b.GetGuest()
|
|
if guest != nil {
|
|
externalId = guest.GetExternalId()
|
|
}
|
|
|
|
ret[i] = cloudprovider.SLoadbalancerBackend{
|
|
Weight: b.Weight,
|
|
Port: b.Port,
|
|
Id: b.Id,
|
|
Name: b.Name,
|
|
ExternalId: externalId,
|
|
BackendType: b.BackendType,
|
|
BackendRole: b.BackendRole,
|
|
Address: b.Address,
|
|
}
|
|
}
|
|
|
|
return ret, nil
|
|
}
|
|
|
|
func (lbbg *SLoadbalancerBackendGroup) GetICloudLoadbalancerBackendGroup(ctx context.Context) (cloudprovider.ICloudLoadbalancerBackendGroup, error) {
|
|
if len(lbbg.ExternalId) == 0 {
|
|
return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty external id")
|
|
}
|
|
|
|
lb, err := lbbg.GetLoadbalancer()
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "GetLoadbalacer")
|
|
}
|
|
|
|
iregion, err := lb.GetIRegion(ctx)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ilb, err := iregion.GetILoadBalancerById(lb.GetExternalId())
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ilbbg, err := ilb.GetILoadBalancerBackendGroupById(lbbg.ExternalId)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return ilbbg, nil
|
|
}
|
|
|
|
func (lb *SLoadbalancer) SyncLoadbalancerBackendgroups(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, exts []cloudprovider.ICloudLoadbalancerBackendGroup) ([]SLoadbalancerBackendGroup, []cloudprovider.ICloudLoadbalancerBackendGroup, compare.SyncResult) {
|
|
lockman.LockRawObject(ctx, LoadbalancerBackendGroupManager.Keyword(), lb.Id)
|
|
defer lockman.ReleaseRawObject(ctx, LoadbalancerBackendGroupManager.Keyword(), lb.Id)
|
|
|
|
localLbgs := []SLoadbalancerBackendGroup{}
|
|
remoteLbbgs := []cloudprovider.ICloudLoadbalancerBackendGroup{}
|
|
syncResult := compare.SyncResult{}
|
|
|
|
dbRes, err := lb.GetLoadbalancerBackendgroups()
|
|
if err != nil {
|
|
syncResult.Error(err)
|
|
return nil, nil, syncResult
|
|
}
|
|
|
|
removed := []SLoadbalancerBackendGroup{}
|
|
commondb := []SLoadbalancerBackendGroup{}
|
|
commonext := []cloudprovider.ICloudLoadbalancerBackendGroup{}
|
|
added := []cloudprovider.ICloudLoadbalancerBackendGroup{}
|
|
|
|
err = compare.CompareSets(dbRes, exts, &removed, &commondb, &commonext, &added)
|
|
if err != nil {
|
|
syncResult.Error(err)
|
|
return nil, nil, syncResult
|
|
}
|
|
|
|
for i := 0; i < len(removed); i++ {
|
|
err = removed[i].syncRemove(ctx, userCred)
|
|
if err != nil {
|
|
syncResult.DeleteError(err)
|
|
continue
|
|
}
|
|
syncResult.Delete()
|
|
}
|
|
for i := 0; i < len(commondb); i++ {
|
|
err = commondb[i].SyncWithCloudLoadbalancerBackendgroup(ctx, userCred, lb, commonext[i])
|
|
if err != nil {
|
|
syncResult.UpdateError(err)
|
|
continue
|
|
}
|
|
localLbgs = append(localLbgs, commondb[i])
|
|
remoteLbbgs = append(remoteLbbgs, commonext[i])
|
|
syncResult.Update()
|
|
}
|
|
for i := 0; i < len(added); i++ {
|
|
lbbg, err := lb.newFromCloudLoadbalancerBackendgroup(ctx, userCred, added[i])
|
|
if err != nil {
|
|
syncResult.AddError(err)
|
|
continue
|
|
}
|
|
localLbgs = append(localLbgs, *lbbg)
|
|
remoteLbbgs = append(remoteLbbgs, added[i])
|
|
syncResult.Add()
|
|
}
|
|
return localLbgs, remoteLbbgs, syncResult
|
|
}
|
|
|
|
func (lbbg *SLoadbalancerBackendGroup) syncRemove(ctx context.Context, userCred mcclient.TokenCredential) error {
|
|
lockman.LockObject(ctx, lbbg)
|
|
defer lockman.ReleaseObject(ctx, lbbg)
|
|
|
|
notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
|
|
Obj: lbbg,
|
|
Action: notifyclient.ActionSyncDelete,
|
|
})
|
|
return lbbg.RealDelete(ctx, userCred)
|
|
}
|
|
|
|
func (lbbg *SLoadbalancerBackendGroup) SyncWithCloudLoadbalancerBackendgroup(
|
|
ctx context.Context,
|
|
userCred mcclient.TokenCredential,
|
|
lb *SLoadbalancer,
|
|
ext cloudprovider.ICloudLoadbalancerBackendGroup,
|
|
) error {
|
|
diff, err := db.UpdateWithLock(ctx, lbbg, func() error {
|
|
lbbg.Type = ext.GetType()
|
|
lbbg.Status = ext.GetStatus()
|
|
lbbg.Scheduler = ext.GetScheduler()
|
|
if hcId := ext.GetHealthCheckId(); hcId != "" {
|
|
hc, err := db.FetchByExternalIdAndManagerId(LoadbalancerHealthCheckManager, hcId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
|
|
return q.Equals("manager_id", lb.ManagerId)
|
|
})
|
|
if err == nil {
|
|
lbbg.LoadbalancerHealthCheckId = hc.GetId()
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if len(diff) > 0 {
|
|
notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
|
|
Obj: lbbg,
|
|
Action: notifyclient.ActionSyncUpdate,
|
|
})
|
|
}
|
|
if account := lb.GetCloudaccount(); account != nil {
|
|
syncMetadata(ctx, userCred, lbbg, ext, account.ReadOnly)
|
|
}
|
|
db.OpsLog.LogSyncUpdate(lbbg, diff, userCred)
|
|
|
|
if ext.IsDefault() {
|
|
diff, err := db.UpdateWithLock(ctx, lb, func() error {
|
|
lb.BackendGroupId = lbbg.Id
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
log.Errorf("failed to set backendgroup id for lb %s error: %v", lb.Name, err)
|
|
return err
|
|
}
|
|
db.OpsLog.LogEvent(lb, db.ACT_UPDATE, diff, userCred)
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (lb *SLoadbalancer) newFromCloudLoadbalancerBackendgroup(
|
|
ctx context.Context,
|
|
userCred mcclient.TokenCredential,
|
|
ext cloudprovider.ICloudLoadbalancerBackendGroup,
|
|
) (*SLoadbalancerBackendGroup, error) {
|
|
lbbg := &SLoadbalancerBackendGroup{}
|
|
lbbg.SetModelManager(LoadbalancerBackendGroupManager, lbbg)
|
|
|
|
lbbg.LoadbalancerId = lb.Id
|
|
lbbg.ExternalId = ext.GetGlobalId()
|
|
|
|
lbbg.Type = ext.GetType()
|
|
lbbg.Status = ext.GetStatus()
|
|
lbbg.Scheduler = ext.GetScheduler()
|
|
lbbg.Name = ext.GetName()
|
|
if hcId := ext.GetHealthCheckId(); hcId != "" {
|
|
hc, err := db.FetchByExternalIdAndManagerId(LoadbalancerHealthCheckManager, hcId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
|
|
return q.Equals("manager_id", lb.ManagerId)
|
|
})
|
|
if err == nil {
|
|
lbbg.LoadbalancerHealthCheckId = hc.GetId()
|
|
}
|
|
}
|
|
|
|
err := LoadbalancerBackendGroupManager.TableSpec().Insert(ctx, lbbg)
|
|
if err != nil {
|
|
return nil, errors.Wrapf(err, "Insert")
|
|
}
|
|
|
|
notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
|
|
Obj: lbbg,
|
|
Action: notifyclient.ActionSyncCreate,
|
|
})
|
|
|
|
db.OpsLog.LogEvent(lbbg, db.ACT_CREATE, lbbg.GetShortDesc(ctx), userCred)
|
|
|
|
if ext.IsDefault() {
|
|
_, err := db.Update(lb, func() error {
|
|
lb.BackendGroupId = lbbg.Id
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
log.Errorf("failed to set backendgroup id for lb %s error: %v", lb.Name, err)
|
|
}
|
|
}
|
|
return lbbg, nil
|
|
}
|
|
|
|
func (lbbg *SLoadbalancerBackendGroup) GetHealthCheck() (*SLoadbalancerHealthCheck, error) {
|
|
obj, err := db.FetchById(LoadbalancerHealthCheckManager, lbbg.LoadbalancerHealthCheckId)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "FetchById")
|
|
}
|
|
return obj.(*SLoadbalancerHealthCheck), nil
|
|
}
|
|
|
|
func (manager *SLoadbalancerBackendGroupManager) ListItemExportKeys(ctx context.Context,
|
|
q *sqlchemy.SQuery,
|
|
userCred mcclient.TokenCredential,
|
|
keys stringutils2.SSortedStrings,
|
|
) (*sqlchemy.SQuery, error) {
|
|
var err error
|
|
|
|
q, err = manager.SStatusStandaloneResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ListItemExportKeys")
|
|
}
|
|
|
|
if keys.ContainsAny(manager.SLoadbalancerResourceBaseManager.GetExportKeys()...) {
|
|
q, err = manager.SLoadbalancerResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
|
|
if err != nil {
|
|
return nil, errors.Wrap(err, "SLoadbalancerResourceBaseManager.ListItemExportKeys")
|
|
}
|
|
}
|
|
|
|
return q, nil
|
|
}
|
|
|
|
func (man *SLoadbalancerBackendGroupManager) InitializeData() error {
|
|
return nil
|
|
}
|