loadbalancerbackendgroups.go 28 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package models
  15. import (
  16. "context"
  17. "fmt"
  18. "yunion.io/x/cloudmux/pkg/cloudprovider"
  19. "yunion.io/x/jsonutils"
  20. "yunion.io/x/log"
  21. "yunion.io/x/pkg/errors"
  22. "yunion.io/x/pkg/gotypes"
  23. "yunion.io/x/pkg/util/compare"
  24. "yunion.io/x/pkg/util/rbacscope"
  25. "yunion.io/x/pkg/utils"
  26. "yunion.io/x/sqlchemy"
  27. api "yunion.io/x/onecloud/pkg/apis/compute"
  28. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  29. "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
  30. "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
  31. "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient"
  32. "yunion.io/x/onecloud/pkg/cloudcommon/policy"
  33. "yunion.io/x/onecloud/pkg/cloudcommon/validators"
  34. "yunion.io/x/onecloud/pkg/httperrors"
  35. "yunion.io/x/onecloud/pkg/mcclient"
  36. "yunion.io/x/onecloud/pkg/util/stringutils2"
  37. )
  38. // +onecloud:swagger-gen-model-singular=loadbalancerbackendgroup
  39. // +onecloud:swagger-gen-model-plural=loadbalancerbackendgroups
  40. type SLoadbalancerBackendGroupManager struct {
  41. SLoadbalancerLogSkipper
  42. db.SStatusStandaloneResourceBaseManager
  43. db.SExternalizedResourceBaseManager
  44. SLoadbalancerResourceBaseManager
  45. }
  46. var LoadbalancerBackendGroupManager *SLoadbalancerBackendGroupManager
  47. func init() {
  48. LoadbalancerBackendGroupManager = &SLoadbalancerBackendGroupManager{
  49. SStatusStandaloneResourceBaseManager: db.NewStatusStandaloneResourceBaseManager(
  50. SLoadbalancerBackendGroup{},
  51. "loadbalancerbackendgroups_tbl",
  52. "loadbalancerbackendgroup",
  53. "loadbalancerbackendgroups",
  54. ),
  55. }
  56. LoadbalancerBackendGroupManager.SetVirtualObject(LoadbalancerBackendGroupManager)
  57. }
  58. type SLoadbalancerBackendGroup struct {
  59. db.SStatusStandaloneResourceBase
  60. db.SExternalizedResourceBase
  61. SLoadbalancerResourceBase `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"`
  62. LoadbalancerHealthCheckId string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"`
  63. Scheduler string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"`
  64. Type string `width:"36" charset:"ascii" nullable:"false" list:"user" default:"normal" create:"optional"`
  65. }
  66. func (manager *SLoadbalancerBackendGroupManager) ResourceScope() rbacscope.TRbacScope {
  67. return rbacscope.ScopeProject
  68. }
  69. func (self *SLoadbalancerBackendGroup) GetOwnerId() mcclient.IIdentityProvider {
  70. lb, err := self.GetLoadbalancer()
  71. if err != nil {
  72. return nil
  73. }
  74. return lb.GetOwnerId()
  75. }
  76. func (manager *SLoadbalancerBackendGroupManager) FetchOwnerId(ctx context.Context, data jsonutils.JSONObject) (mcclient.IIdentityProvider, error) {
  77. lbId, _ := data.GetString("loadbalancer_id")
  78. if len(lbId) > 0 {
  79. lb, err := db.FetchById(LoadbalancerManager, lbId)
  80. if err != nil {
  81. return nil, errors.Wrapf(err, "db.FetchById(LoadbalancerManager, %s)", lbId)
  82. }
  83. return lb.(*SLoadbalancer).GetOwnerId(), nil
  84. }
  85. return db.FetchProjectInfo(ctx, data)
  86. }
  87. func (manager *SLoadbalancerBackendGroupManager) FilterByOwner(ctx context.Context, q *sqlchemy.SQuery, man db.FilterByOwnerProvider, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, scope rbacscope.TRbacScope) *sqlchemy.SQuery {
  88. if ownerId != nil {
  89. sq := LoadbalancerManager.Query("id")
  90. switch scope {
  91. case rbacscope.ScopeProject:
  92. sq = sq.Equals("tenant_id", ownerId.GetProjectId())
  93. return q.In("loadbalancer_id", sq.SubQuery())
  94. case rbacscope.ScopeDomain:
  95. sq = sq.Equals("domain_id", ownerId.GetProjectDomainId())
  96. return q.In("loadbalancer_id", sq.SubQuery())
  97. }
  98. }
  99. return q
  100. }
  101. // 负载均衡后端服务器组列表
  102. func (man *SLoadbalancerBackendGroupManager) ListItemFilter(
  103. ctx context.Context,
  104. q *sqlchemy.SQuery,
  105. userCred mcclient.TokenCredential,
  106. query api.LoadbalancerBackendGroupListInput,
  107. ) (*sqlchemy.SQuery, error) {
  108. q, err := man.SStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusStandaloneResourceListInput)
  109. if err != nil {
  110. return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ListItemFilter")
  111. }
  112. q, err = man.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
  113. if err != nil {
  114. return nil, errors.Wrap(err, "SExternalizedResourceBaseManager.ListItemFilter")
  115. }
  116. q, err = man.SLoadbalancerResourceBaseManager.ListItemFilter(ctx, q, userCred, query.LoadbalancerFilterListInput)
  117. if err != nil {
  118. return nil, errors.Wrap(err, "SLoadbalancerResourceBaseManager.ListItemFilter")
  119. }
  120. if query.NoRef != nil && *query.NoRef {
  121. q, err = man.FilterZeroRefBackendGroup(q)
  122. if err != nil {
  123. log.Errorf("SLoadbalancerBackendGroupManager ListItemFilter %s", err)
  124. return nil, httperrors.NewInternalServerError("query backend group releated resource failed.")
  125. }
  126. }
  127. if len(query.Type) > 0 {
  128. q = q.In("type", query.Type)
  129. }
  130. return q, nil
  131. }
  132. func (man *SLoadbalancerBackendGroupManager) OrderByExtraFields(
  133. ctx context.Context,
  134. q *sqlchemy.SQuery,
  135. userCred mcclient.TokenCredential,
  136. query api.LoadbalancerBackendGroupListInput,
  137. ) (*sqlchemy.SQuery, error) {
  138. var err error
  139. q, err = man.SStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusStandaloneResourceListInput)
  140. if err != nil {
  141. return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.OrderByExtraFields")
  142. }
  143. q, err = man.SLoadbalancerResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.LoadbalancerFilterListInput)
  144. if err != nil {
  145. return nil, errors.Wrap(err, "SLoadbalancerResourceBaseManager.OrderByExtraFields")
  146. }
  147. return q, nil
  148. }
  149. func (man *SLoadbalancerBackendGroupManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
  150. var err error
  151. q, err = man.SStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field)
  152. if err == nil {
  153. return q, nil
  154. }
  155. q, err = man.SLoadbalancerResourceBaseManager.QueryDistinctExtraField(q, field)
  156. if err == nil {
  157. return q, nil
  158. }
  159. return q, httperrors.ErrNotFound
  160. }
  161. type sBackendgroup struct {
  162. Name string
  163. LoadbalancerId string
  164. }
  165. func (self *SLoadbalancerBackendGroup) GetUniqValues() jsonutils.JSONObject {
  166. return jsonutils.Marshal(sBackendgroup{Name: self.Name, LoadbalancerId: self.LoadbalancerId})
  167. }
  168. func (manager *SLoadbalancerBackendGroupManager) FetchUniqValues(ctx context.Context, data jsonutils.JSONObject) jsonutils.JSONObject {
  169. info := sBackendgroup{}
  170. data.Unmarshal(&info)
  171. return jsonutils.Marshal(info)
  172. }
  173. func (manager *SLoadbalancerBackendGroupManager) FilterByUniqValues(q *sqlchemy.SQuery, values jsonutils.JSONObject) *sqlchemy.SQuery {
  174. info := sBackendgroup{}
  175. values.Unmarshal(&info)
  176. if len(info.LoadbalancerId) > 0 {
  177. q = q.Equals("loadbalancer_id", info.LoadbalancerId)
  178. }
  179. if len(info.Name) > 0 {
  180. q = q.Equals("name", info.Name)
  181. }
  182. return q
  183. }
  184. func (man *SLoadbalancerBackendGroupManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input *api.LoadbalancerBackendGroupCreateInput) (*api.LoadbalancerBackendGroupCreateInput, error) {
  185. lbObj, err := validators.ValidateModel(ctx, userCred, LoadbalancerManager, &input.LoadbalancerId)
  186. if err != nil {
  187. return nil, err
  188. }
  189. lb := lbObj.(*SLoadbalancer)
  190. input.StatusStandaloneResourceCreateInput, err = man.SStatusStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.StatusStandaloneResourceCreateInput)
  191. if err != nil {
  192. return nil, err
  193. }
  194. if len(input.LoadbalancerHealthCheckId) > 0 {
  195. _, err := validators.ValidateModel(ctx, userCred, LoadbalancerHealthCheckManager, &input.LoadbalancerHealthCheckId)
  196. if err != nil {
  197. return nil, err
  198. }
  199. }
  200. region, err := lb.GetRegion()
  201. if err != nil {
  202. return nil, err
  203. }
  204. lbIsManaged := lb.IsManaged()
  205. for i := 0; i < len(input.Backends); i++ {
  206. if len(input.Backends[i].BackendType) == 0 {
  207. input.Backends[i].BackendType = api.LB_BACKEND_GUEST
  208. }
  209. if input.Backends[i].Weight < 0 || input.Backends[i].Weight > 256 {
  210. return nil, httperrors.NewInputParameterError("weight %d not support, only support range 0 ~ 256", input.Backends[i].Weight)
  211. }
  212. if input.Backends[i].Port < 1 || input.Backends[i].Port > 65535 {
  213. return nil, httperrors.NewInputParameterError("port %d not support, only support range 1 ~ 65535", input.Backends[i].Port)
  214. }
  215. if len(input.Backends[i].Id) == 0 && input.Backends[i].BackendType != api.LB_BACKEND_ADDRESS {
  216. return nil, httperrors.NewMissingParameterError("Missing backend id")
  217. }
  218. var backendRegion *SCloudregion
  219. switch input.Backends[i].BackendType {
  220. case api.LB_BACKEND_GUEST:
  221. guestObj, err := validators.ValidateModel(ctx, userCred, GuestManager, &input.Backends[i].Id)
  222. if err != nil {
  223. return nil, err
  224. }
  225. guest := guestObj.(*SGuest)
  226. host, err := guest.GetHost()
  227. if err != nil {
  228. return nil, errors.Wrapf(err, "GetHost")
  229. }
  230. input.Backends[i].ZoneId = host.ZoneId
  231. input.Backends[i].HostName = host.Name
  232. input.Backends[i].Id = guest.Id
  233. input.Backends[i].Name = guest.Name
  234. input.Backends[i].ExternalId = guest.ExternalId
  235. address, err := guest.GetAddress()
  236. if err != nil {
  237. return nil, err
  238. }
  239. input.Backends[i].Address = address
  240. backendRegion, _ = host.GetRegion()
  241. case api.LB_BACKEND_HOST:
  242. if db.IsAdminAllowCreate(userCred, man).Result.IsDeny() {
  243. return nil, httperrors.NewForbiddenError("only sysadmin can specify host as backend")
  244. }
  245. hostObj, err := validators.ValidateModel(ctx, userCred, HostManager, &input.Backends[i].Id)
  246. if err != nil {
  247. return nil, err
  248. }
  249. host := hostObj.(*SHost)
  250. input.Backends[i].Id = host.Id
  251. input.Backends[i].Name = host.Name
  252. input.Backends[i].ExternalId = host.ExternalId
  253. input.Backends[i].Address = host.AccessIp
  254. backendRegion, _ = host.GetRegion()
  255. case api.LB_BACKEND_ADDRESS:
  256. default:
  257. return nil, httperrors.NewInputParameterError("unexpected backend type %s", input.Backends[i].BackendType)
  258. }
  259. if lbIsManaged && backendRegion != nil && backendRegion.Id != region.Id {
  260. return nil, httperrors.NewInputParameterError("region of backend %d does not match that of lb's", i)
  261. }
  262. }
  263. return region.GetDriver().ValidateCreateLoadbalancerBackendGroupData(ctx, userCred, lb, input)
  264. }
  265. func (lbbg *SLoadbalancerBackendGroup) GetLoadbalancerListenerRules() ([]SLoadbalancerListenerRule, error) {
  266. q := LoadbalancerListenerRuleManager.Query().Equals("backend_group_id", lbbg.Id)
  267. rules := []SLoadbalancerListenerRule{}
  268. err := db.FetchModelObjects(LoadbalancerListenerRuleManager, q, &rules)
  269. if err != nil {
  270. return nil, err
  271. }
  272. return rules, nil
  273. }
  274. func (lbbg *SLoadbalancerBackendGroup) GetLoadbalancerListeners() ([]SLoadbalancerListener, error) {
  275. q := LoadbalancerListenerManager.Query().Equals("backend_group_id", lbbg.Id)
  276. listeners := []SLoadbalancerListener{}
  277. err := db.FetchModelObjects(LoadbalancerListenerManager, q, &listeners)
  278. if err != nil {
  279. return nil, err
  280. }
  281. return listeners, nil
  282. }
  283. func (lbbg *SLoadbalancerBackendGroup) GetLoadbalancer() (*SLoadbalancer, error) {
  284. lb, err := LoadbalancerManager.FetchById(lbbg.LoadbalancerId)
  285. if err != nil {
  286. return nil, err
  287. }
  288. return lb.(*SLoadbalancer), nil
  289. }
  290. func (llbg *SLoadbalancerBackendGroup) GetRegion() (*SCloudregion, error) {
  291. loadbalancer, err := llbg.GetLoadbalancer()
  292. if err != nil {
  293. return nil, err
  294. }
  295. return loadbalancer.GetRegion()
  296. }
  297. func (lbbg *SLoadbalancerBackendGroup) GetIRegion(ctx context.Context) (cloudprovider.ICloudRegion, error) {
  298. loadbalancer, err := lbbg.GetLoadbalancer()
  299. if err != nil {
  300. return nil, errors.Wrapf(err, "GetLoadbalancer")
  301. }
  302. return loadbalancer.GetIRegion(ctx)
  303. }
  304. func (lbbg *SLoadbalancerBackendGroup) GetBackends() ([]SLoadbalancerBackend, error) {
  305. backends := make([]SLoadbalancerBackend, 0)
  306. q := LoadbalancerBackendManager.Query().Equals("backend_group_id", lbbg.GetId())
  307. err := db.FetchModelObjects(LoadbalancerBackendManager, q, &backends)
  308. if err != nil {
  309. return nil, err
  310. }
  311. return backends, nil
  312. }
  313. // 返回值 TotalRef
  314. func (lbbg *SLoadbalancerBackendGroup) RefCount() (int, error) {
  315. men := lbbg.getRefManagers()
  316. var count int
  317. for _, m := range men {
  318. cnt, err := lbbg.refCount(m)
  319. if err != nil {
  320. return -1, err
  321. }
  322. count += cnt
  323. }
  324. return count, nil
  325. }
  326. func (lbbg *SLoadbalancerBackendGroup) refCount(man db.IModelManager) (int, error) {
  327. return man.Query().Equals("backend_group_id", lbbg.Id).CountWithError()
  328. }
  329. func lbbgRefManagers() []db.IModelManager {
  330. return []db.IModelManager{
  331. LoadbalancerListenerManager,
  332. }
  333. }
  334. func (lbbg *SLoadbalancerBackendGroup) getRefManagers() []db.IModelManager {
  335. // 引用Backend Group的数据库
  336. return lbbgRefManagers()
  337. }
  338. func (man *SLoadbalancerBackendGroupManager) FilterZeroRefBackendGroup(q *sqlchemy.SQuery) (*sqlchemy.SQuery, error) {
  339. ids := []string{}
  340. sq := q.SubQuery()
  341. rows, err := sq.Query(sq.Field("id")).Rows()
  342. if err != nil {
  343. return nil, err
  344. }
  345. defer rows.Close()
  346. for rows.Next() {
  347. var lbbgId string
  348. err = rows.Scan(&lbbgId)
  349. if err != nil {
  350. log.Errorf("Get backendgroup id with scan err: %v", err)
  351. return nil, err
  352. }
  353. ids = append(ids, lbbgId)
  354. }
  355. for _, m := range lbbgRefManagers() {
  356. _ids := m.Query("backend_group_id").In("backend_group_id", ids).SubQuery()
  357. q = q.NotIn("id", _ids)
  358. }
  359. return q, nil
  360. }
  361. func (lbbg *SLoadbalancerBackendGroup) isDefault(ctx context.Context) (bool, error) {
  362. q := LoadbalancerManager.Query().Equals("backend_group_id", lbbg.GetId()).Equals("id", lbbg.LoadbalancerId)
  363. count, err := q.CountWithError()
  364. if err != nil {
  365. return false, errors.Wrap(err, "loadbalancerBackendGroup.isDefault")
  366. }
  367. return count > 0, nil
  368. }
  369. func (lbbg *SLoadbalancerBackendGroup) ValidateDeleteCondition(ctx context.Context, info *api.LoadbalancerBackendGroupDetails) error {
  370. if gotypes.IsNil(info) {
  371. info = &api.LoadbalancerBackendGroupDetails{}
  372. info.IsDefault, _ = lbbg.isDefault(ctx)
  373. info.LbListenerCount, _ = lbbg.GetListenerCount()
  374. }
  375. if info.IsDefault {
  376. return httperrors.NewResourceBusyError("backend group %s is default backend group", lbbg.Id)
  377. }
  378. if info.LbListenerCount > 0 {
  379. return httperrors.NewResourceBusyError("backend group %s is still referred by %d %s",
  380. lbbg.Id, info.LbListenerCount, LoadbalancerListenerManager.KeywordPlural())
  381. }
  382. return lbbg.SStatusStandaloneResourceBase.ValidateDeleteCondition(ctx, nil)
  383. }
  384. func (man *SLoadbalancerBackendGroupManager) FetchCustomizeColumns(
  385. ctx context.Context,
  386. userCred mcclient.TokenCredential,
  387. query jsonutils.JSONObject,
  388. objs []interface{},
  389. fields stringutils2.SSortedStrings,
  390. isList bool,
  391. ) []api.LoadbalancerBackendGroupDetails {
  392. rows := make([]api.LoadbalancerBackendGroupDetails, len(objs))
  393. stdRows := man.SStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  394. lbRows := man.SLoadbalancerResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  395. lbIds := make([]string, len(objs))
  396. lbbgIds := make([]string, len(objs))
  397. hcIds := make([]string, len(objs))
  398. for i := range rows {
  399. rows[i] = api.LoadbalancerBackendGroupDetails{
  400. StatusStandaloneResourceDetails: stdRows[i],
  401. LoadbalancerResourceInfo: lbRows[i],
  402. }
  403. lbbg := objs[i].(*SLoadbalancerBackendGroup)
  404. lbIds[i] = lbbg.LoadbalancerId
  405. lbbgIds[i] = lbbg.Id
  406. hcIds[i] = lbbg.LoadbalancerHealthCheckId
  407. }
  408. lbs := map[string]SLoadbalancer{}
  409. err := db.FetchStandaloneObjectsByIds(LoadbalancerManager, lbIds, &lbs)
  410. if err != nil {
  411. return rows
  412. }
  413. defaultLbgIds := []string{}
  414. virObjs := make([]interface{}, len(objs))
  415. for i := range rows {
  416. if lb, ok := lbs[lbIds[i]]; ok {
  417. virObjs[i] = &lb
  418. rows[i].ProjectId = lb.ProjectId
  419. if !utils.IsInStringArray(lb.BackendGroupId, defaultLbgIds) {
  420. defaultLbgIds = append(defaultLbgIds, lb.BackendGroupId)
  421. }
  422. }
  423. }
  424. hcMap, err := db.FetchIdNameMap2(LoadbalancerHealthCheckManager, hcIds)
  425. if err != nil {
  426. return rows
  427. }
  428. for i := range rows {
  429. rows[i].IsDefault = utils.IsInStringArray(lbbgIds[i], defaultLbgIds)
  430. if hcId, ok := hcMap[hcIds[i]]; ok {
  431. rows[i].LoadbalancerHealthCheck = hcId
  432. }
  433. }
  434. for i := range objs {
  435. q := LoadbalancerListenerManager.Query().Equals("backend_group_id", lbbgIds[i])
  436. ownerId, queryScope, err, _ := db.FetchCheckQueryOwnerScope(ctx, userCred, query, LoadbalancerListenerManager, policy.PolicyActionList, true)
  437. if err != nil {
  438. log.Errorf("FetchCheckQueryOwnerScope error: %v", err)
  439. return rows
  440. }
  441. q = LoadbalancerListenerManager.FilterByOwner(ctx, q, LoadbalancerListenerManager, userCred, ownerId, queryScope)
  442. rows[i].LbListenerCount, _ = q.CountWithError()
  443. }
  444. return rows
  445. }
  446. func (lbbg *SLoadbalancerBackendGroup) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
  447. lbbg.SStatusStandaloneResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
  448. input := &api.LoadbalancerBackendGroupCreateInput{}
  449. data.Unmarshal(input)
  450. for i := range input.Backends {
  451. backend := &SLoadbalancerBackend{
  452. BackendId: input.Backends[i].Id,
  453. BackendType: input.Backends[i].BackendType,
  454. BackendRole: input.Backends[i].BackendRole,
  455. Weight: input.Backends[i].Weight,
  456. Address: input.Backends[i].Address,
  457. Port: input.Backends[i].Port,
  458. }
  459. backend.Name = input.Backends[i].Name
  460. backend.BackendGroupId = lbbg.Id
  461. backend.Status = api.LB_STATUS_ENABLED
  462. if backend.BackendType == api.LB_BACKEND_GUEST {
  463. backend.Name = fmt.Sprintf("%s-%s-%s", lbbg.Name, backend.BackendType, backend.Name)
  464. }
  465. backend.SetModelManager(LoadbalancerBackendManager, backend)
  466. LoadbalancerBackendManager.TableSpec().Insert(ctx, backend)
  467. }
  468. lbbg.StartLoadBalancerBackendGroupCreateTask(ctx, userCred, "")
  469. }
  470. func (lbbg *SLoadbalancerBackendGroup) StartLoadBalancerBackendGroupCreateTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) {
  471. lbbg.SetStatus(ctx, userCred, api.LB_CREATING, "")
  472. err := func() error {
  473. task, err := taskman.TaskManager.NewTask(ctx, "LoadbalancerLoadbalancerBackendGroupCreateTask", lbbg, userCred, nil, parentTaskId, "", nil)
  474. if err != nil {
  475. return errors.Wrapf(err, "NewTask")
  476. }
  477. return task.ScheduleRun(nil)
  478. }()
  479. if err != nil {
  480. lbbg.SetStatus(ctx, userCred, api.LB_CREATE_FAILED, err.Error())
  481. }
  482. }
  483. func (self *SLoadbalancerBackendGroup) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
  484. backends, err := self.GetBackends()
  485. if err != nil {
  486. return err
  487. }
  488. for i := range backends {
  489. err := backends[i].RealDelete(ctx, userCred)
  490. if err != nil {
  491. return errors.Wrapf(err, "RealDelete backend %s", backends[i].Id)
  492. }
  493. }
  494. return self.SStatusStandaloneResourceBase.Delete(ctx, userCred)
  495. }
  496. func (lbbg *SLoadbalancerBackendGroup) PerformPurge(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  497. parasm := jsonutils.NewDict()
  498. parasm.Add(jsonutils.JSONTrue, "purge")
  499. return nil, lbbg.StartLoadBalancerBackendGroupDeleteTask(ctx, userCred, parasm, "")
  500. }
  501. func (lbbg *SLoadbalancerBackendGroup) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
  502. lbbg.SetStatus(ctx, userCred, api.LB_STATUS_DELETING, "")
  503. return lbbg.StartLoadBalancerBackendGroupDeleteTask(ctx, userCred, jsonutils.NewDict(), "")
  504. }
  505. func (lbbg *SLoadbalancerBackendGroup) StartLoadBalancerBackendGroupDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error {
  506. task, err := taskman.TaskManager.NewTask(ctx, "LoadbalancerBackendGroupDeleteTask", lbbg, userCred, params, parentTaskId, "", nil)
  507. if err != nil {
  508. return errors.Wrapf(err, "NewTask")
  509. }
  510. return task.ScheduleRun(nil)
  511. }
  512. func (lbbg *SLoadbalancerBackendGroup) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
  513. return nil
  514. }
  515. func (lbbg *SLoadbalancerBackendGroup) GetListener() *SLoadbalancerListener {
  516. ret := &SLoadbalancerListener{}
  517. err := LoadbalancerListenerManager.Query().Equals("backend_group_id", lbbg.Id).First(ret)
  518. if err != nil {
  519. return nil
  520. }
  521. return ret
  522. }
  523. func (lbbg *SLoadbalancerBackendGroup) GetListenerCount() (int, error) {
  524. return LoadbalancerListenerManager.Query().Equals("backend_group_id", lbbg.Id).CountWithError()
  525. }
  526. func (lbbg *SLoadbalancerBackendGroup) GetBackendsParams() ([]cloudprovider.SLoadbalancerBackend, error) {
  527. backends, err := lbbg.GetBackends()
  528. if err != nil {
  529. return nil, err
  530. }
  531. ret := make([]cloudprovider.SLoadbalancerBackend, len(backends))
  532. for i := range backends {
  533. b := backends[i]
  534. externalId := ""
  535. guest := b.GetGuest()
  536. if guest != nil {
  537. externalId = guest.GetExternalId()
  538. }
  539. ret[i] = cloudprovider.SLoadbalancerBackend{
  540. Weight: b.Weight,
  541. Port: b.Port,
  542. Id: b.Id,
  543. Name: b.Name,
  544. ExternalId: externalId,
  545. BackendType: b.BackendType,
  546. BackendRole: b.BackendRole,
  547. Address: b.Address,
  548. }
  549. }
  550. return ret, nil
  551. }
  552. func (lbbg *SLoadbalancerBackendGroup) GetICloudLoadbalancerBackendGroup(ctx context.Context) (cloudprovider.ICloudLoadbalancerBackendGroup, error) {
  553. if len(lbbg.ExternalId) == 0 {
  554. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty external id")
  555. }
  556. lb, err := lbbg.GetLoadbalancer()
  557. if err != nil {
  558. return nil, errors.Wrapf(err, "GetLoadbalacer")
  559. }
  560. iregion, err := lb.GetIRegion(ctx)
  561. if err != nil {
  562. return nil, err
  563. }
  564. ilb, err := iregion.GetILoadBalancerById(lb.GetExternalId())
  565. if err != nil {
  566. return nil, err
  567. }
  568. ilbbg, err := ilb.GetILoadBalancerBackendGroupById(lbbg.ExternalId)
  569. if err != nil {
  570. return nil, err
  571. }
  572. return ilbbg, nil
  573. }
  574. func (lb *SLoadbalancer) SyncLoadbalancerBackendgroups(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, exts []cloudprovider.ICloudLoadbalancerBackendGroup) ([]SLoadbalancerBackendGroup, []cloudprovider.ICloudLoadbalancerBackendGroup, compare.SyncResult) {
  575. lockman.LockRawObject(ctx, LoadbalancerBackendGroupManager.Keyword(), lb.Id)
  576. defer lockman.ReleaseRawObject(ctx, LoadbalancerBackendGroupManager.Keyword(), lb.Id)
  577. localLbgs := []SLoadbalancerBackendGroup{}
  578. remoteLbbgs := []cloudprovider.ICloudLoadbalancerBackendGroup{}
  579. syncResult := compare.SyncResult{}
  580. dbRes, err := lb.GetLoadbalancerBackendgroups()
  581. if err != nil {
  582. syncResult.Error(err)
  583. return nil, nil, syncResult
  584. }
  585. removed := []SLoadbalancerBackendGroup{}
  586. commondb := []SLoadbalancerBackendGroup{}
  587. commonext := []cloudprovider.ICloudLoadbalancerBackendGroup{}
  588. added := []cloudprovider.ICloudLoadbalancerBackendGroup{}
  589. err = compare.CompareSets(dbRes, exts, &removed, &commondb, &commonext, &added)
  590. if err != nil {
  591. syncResult.Error(err)
  592. return nil, nil, syncResult
  593. }
  594. for i := 0; i < len(removed); i++ {
  595. err = removed[i].syncRemove(ctx, userCred)
  596. if err != nil {
  597. syncResult.DeleteError(err)
  598. continue
  599. }
  600. syncResult.Delete()
  601. }
  602. for i := 0; i < len(commondb); i++ {
  603. err = commondb[i].SyncWithCloudLoadbalancerBackendgroup(ctx, userCred, lb, commonext[i])
  604. if err != nil {
  605. syncResult.UpdateError(err)
  606. continue
  607. }
  608. localLbgs = append(localLbgs, commondb[i])
  609. remoteLbbgs = append(remoteLbbgs, commonext[i])
  610. syncResult.Update()
  611. }
  612. for i := 0; i < len(added); i++ {
  613. lbbg, err := lb.newFromCloudLoadbalancerBackendgroup(ctx, userCred, added[i])
  614. if err != nil {
  615. syncResult.AddError(err)
  616. continue
  617. }
  618. localLbgs = append(localLbgs, *lbbg)
  619. remoteLbbgs = append(remoteLbbgs, added[i])
  620. syncResult.Add()
  621. }
  622. return localLbgs, remoteLbbgs, syncResult
  623. }
  624. func (lbbg *SLoadbalancerBackendGroup) syncRemove(ctx context.Context, userCred mcclient.TokenCredential) error {
  625. lockman.LockObject(ctx, lbbg)
  626. defer lockman.ReleaseObject(ctx, lbbg)
  627. notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
  628. Obj: lbbg,
  629. Action: notifyclient.ActionSyncDelete,
  630. })
  631. return lbbg.RealDelete(ctx, userCred)
  632. }
  633. func (lbbg *SLoadbalancerBackendGroup) SyncWithCloudLoadbalancerBackendgroup(
  634. ctx context.Context,
  635. userCred mcclient.TokenCredential,
  636. lb *SLoadbalancer,
  637. ext cloudprovider.ICloudLoadbalancerBackendGroup,
  638. ) error {
  639. diff, err := db.UpdateWithLock(ctx, lbbg, func() error {
  640. lbbg.Type = ext.GetType()
  641. lbbg.Status = ext.GetStatus()
  642. lbbg.Scheduler = ext.GetScheduler()
  643. if hcId := ext.GetHealthCheckId(); hcId != "" {
  644. hc, err := db.FetchByExternalIdAndManagerId(LoadbalancerHealthCheckManager, hcId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  645. return q.Equals("manager_id", lb.ManagerId)
  646. })
  647. if err == nil {
  648. lbbg.LoadbalancerHealthCheckId = hc.GetId()
  649. }
  650. }
  651. return nil
  652. })
  653. if err != nil {
  654. return err
  655. }
  656. if len(diff) > 0 {
  657. notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
  658. Obj: lbbg,
  659. Action: notifyclient.ActionSyncUpdate,
  660. })
  661. }
  662. if account := lb.GetCloudaccount(); account != nil {
  663. syncMetadata(ctx, userCred, lbbg, ext, account.ReadOnly)
  664. }
  665. db.OpsLog.LogSyncUpdate(lbbg, diff, userCred)
  666. if ext.IsDefault() {
  667. diff, err := db.UpdateWithLock(ctx, lb, func() error {
  668. lb.BackendGroupId = lbbg.Id
  669. return nil
  670. })
  671. if err != nil {
  672. log.Errorf("failed to set backendgroup id for lb %s error: %v", lb.Name, err)
  673. return err
  674. }
  675. db.OpsLog.LogEvent(lb, db.ACT_UPDATE, diff, userCred)
  676. }
  677. return err
  678. }
  679. func (lb *SLoadbalancer) newFromCloudLoadbalancerBackendgroup(
  680. ctx context.Context,
  681. userCred mcclient.TokenCredential,
  682. ext cloudprovider.ICloudLoadbalancerBackendGroup,
  683. ) (*SLoadbalancerBackendGroup, error) {
  684. lbbg := &SLoadbalancerBackendGroup{}
  685. lbbg.SetModelManager(LoadbalancerBackendGroupManager, lbbg)
  686. lbbg.LoadbalancerId = lb.Id
  687. lbbg.ExternalId = ext.GetGlobalId()
  688. lbbg.Type = ext.GetType()
  689. lbbg.Status = ext.GetStatus()
  690. lbbg.Scheduler = ext.GetScheduler()
  691. lbbg.Name = ext.GetName()
  692. if hcId := ext.GetHealthCheckId(); hcId != "" {
  693. hc, err := db.FetchByExternalIdAndManagerId(LoadbalancerHealthCheckManager, hcId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  694. return q.Equals("manager_id", lb.ManagerId)
  695. })
  696. if err == nil {
  697. lbbg.LoadbalancerHealthCheckId = hc.GetId()
  698. }
  699. }
  700. err := LoadbalancerBackendGroupManager.TableSpec().Insert(ctx, lbbg)
  701. if err != nil {
  702. return nil, errors.Wrapf(err, "Insert")
  703. }
  704. notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
  705. Obj: lbbg,
  706. Action: notifyclient.ActionSyncCreate,
  707. })
  708. db.OpsLog.LogEvent(lbbg, db.ACT_CREATE, lbbg.GetShortDesc(ctx), userCred)
  709. if ext.IsDefault() {
  710. _, err := db.Update(lb, func() error {
  711. lb.BackendGroupId = lbbg.Id
  712. return nil
  713. })
  714. if err != nil {
  715. log.Errorf("failed to set backendgroup id for lb %s error: %v", lb.Name, err)
  716. }
  717. }
  718. return lbbg, nil
  719. }
  720. func (lbbg *SLoadbalancerBackendGroup) GetHealthCheck() (*SLoadbalancerHealthCheck, error) {
  721. obj, err := db.FetchById(LoadbalancerHealthCheckManager, lbbg.LoadbalancerHealthCheckId)
  722. if err != nil {
  723. return nil, errors.Wrap(err, "FetchById")
  724. }
  725. return obj.(*SLoadbalancerHealthCheck), nil
  726. }
  727. func (manager *SLoadbalancerBackendGroupManager) ListItemExportKeys(ctx context.Context,
  728. q *sqlchemy.SQuery,
  729. userCred mcclient.TokenCredential,
  730. keys stringutils2.SSortedStrings,
  731. ) (*sqlchemy.SQuery, error) {
  732. var err error
  733. q, err = manager.SStatusStandaloneResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  734. if err != nil {
  735. return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ListItemExportKeys")
  736. }
  737. if keys.ContainsAny(manager.SLoadbalancerResourceBaseManager.GetExportKeys()...) {
  738. q, err = manager.SLoadbalancerResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  739. if err != nil {
  740. return nil, errors.Wrap(err, "SLoadbalancerResourceBaseManager.ListItemExportKeys")
  741. }
  742. }
  743. return q, nil
  744. }
  745. func (man *SLoadbalancerBackendGroupManager) InitializeData() error {
  746. return nil
  747. }