loadbalancers.go 60 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876
  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. "database/sql"
  18. "fmt"
  19. "net"
  20. "strings"
  21. "time"
  22. "yunion.io/x/cloudmux/pkg/cloudprovider"
  23. "yunion.io/x/jsonutils"
  24. "yunion.io/x/log"
  25. "yunion.io/x/pkg/errors"
  26. "yunion.io/x/pkg/util/billing"
  27. "yunion.io/x/pkg/util/compare"
  28. "yunion.io/x/pkg/util/netutils"
  29. "yunion.io/x/pkg/util/rbacscope"
  30. "yunion.io/x/pkg/utils"
  31. "yunion.io/x/sqlchemy"
  32. "yunion.io/x/onecloud/pkg/apis"
  33. billing_api "yunion.io/x/onecloud/pkg/apis/billing"
  34. api "yunion.io/x/onecloud/pkg/apis/compute"
  35. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  36. "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
  37. "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
  38. "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
  39. "yunion.io/x/onecloud/pkg/cloudcommon/notifyclient"
  40. "yunion.io/x/onecloud/pkg/cloudcommon/policy"
  41. "yunion.io/x/onecloud/pkg/cloudcommon/validators"
  42. "yunion.io/x/onecloud/pkg/compute/options"
  43. "yunion.io/x/onecloud/pkg/httperrors"
  44. "yunion.io/x/onecloud/pkg/mcclient"
  45. "yunion.io/x/onecloud/pkg/util/rbacutils"
  46. "yunion.io/x/onecloud/pkg/util/stringutils2"
  47. )
  48. type SLoadbalancerManager struct {
  49. SLoadbalancerLogSkipper
  50. db.SVirtualResourceBaseManager
  51. db.SExternalizedResourceBaseManager
  52. SDeletePreventableResourceBaseManager
  53. SVpcResourceBaseManager
  54. SZoneResourceBaseManager
  55. SNetworkResourceBaseManager
  56. SBillingResourceBaseManager
  57. SManagedResourceBaseManager
  58. SCloudregionResourceBaseManager
  59. SLoadbalancerClusterResourceBaseManager
  60. }
  61. var LoadbalancerManager *SLoadbalancerManager
  62. func init() {
  63. LoadbalancerManager = &SLoadbalancerManager{
  64. SVirtualResourceBaseManager: db.NewVirtualResourceBaseManager(
  65. SLoadbalancer{},
  66. "loadbalancers_tbl",
  67. "loadbalancer",
  68. "loadbalancers",
  69. ),
  70. }
  71. LoadbalancerManager.SetVirtualObject(LoadbalancerManager)
  72. }
  73. type SLoadbalancer struct {
  74. db.SVirtualResourceBase
  75. db.SExternalizedResourceBase
  76. SBillingResourceBase
  77. SManagedResourceBase
  78. SCloudregionResourceBase
  79. SDeletePreventableResourceBase
  80. // LB might optionally be in a VPC, vpc_id, manager_id, cloudregion_id
  81. SVpcResourceBase `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional"`
  82. // zone_id
  83. SZoneResourceBase
  84. // optional network_id
  85. SNetworkResourceBase `width:"147" charset:"ascii" nullable:"true" list:"user" create:"optional"`
  86. SLoadbalancerRateLimiter
  87. // 备可用区
  88. Zone1 string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"optional" update:"user" json:"zone_1"`
  89. // IP地址
  90. Address string `width:"128" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"address"`
  91. // 地址类型
  92. AddressType string `width:"16" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"address_type"`
  93. // 网络类型
  94. NetworkType string `width:"16" charset:"ascii" nullable:"true" list:"user" create:"optional" json:"network_type"`
  95. SLoadbalancerClusterResourceBase
  96. // 计费类型
  97. SBillingChargeTypeBase
  98. // 套餐名称
  99. LoadbalancerSpec string `list:"user" get:"user" list:"user" create:"optional" json:"loadbalancer_spec"`
  100. // 默认后端服务器组Id
  101. BackendGroupId string `width:"36" charset:"ascii" nullable:"true" list:"user" update:"user" json:"backend_group_id"`
  102. }
  103. // 负载均衡实例列表
  104. func (man *SLoadbalancerManager) ListItemFilter(
  105. ctx context.Context,
  106. q *sqlchemy.SQuery,
  107. userCred mcclient.TokenCredential,
  108. query api.LoadbalancerListInput,
  109. ) (*sqlchemy.SQuery, error) {
  110. var err error
  111. q, err = man.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VirtualResourceListInput)
  112. if err != nil {
  113. return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter")
  114. }
  115. q, err = man.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
  116. if err != nil {
  117. return nil, errors.Wrap(err, "SExternalizedResourceBaseManager.ListItemFilter")
  118. }
  119. q, err = man.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ManagedResourceListInput)
  120. if err != nil {
  121. return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter")
  122. }
  123. q, err = man.SCloudregionResourceBaseManager.ListItemFilter(ctx, q, userCred, query.RegionalFilterListInput)
  124. if err != nil {
  125. return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemFilter")
  126. }
  127. q, err = man.SDeletePreventableResourceBaseManager.ListItemFilter(ctx, q, userCred, query.DeletePreventableResourceBaseListInput)
  128. if err != nil {
  129. return nil, errors.Wrap(err, "SDeletePreventableResourceBaseManager.ListItemFilter")
  130. }
  131. q, err = man.SBillingResourceBaseManager.ListItemFilter(ctx, q, userCred, query.BillingResourceListInput)
  132. if err != nil {
  133. return nil, errors.Wrap(err, "SBillingResourceBaseManager.ListItemFilter")
  134. }
  135. vpcQuery := api.VpcFilterListInput{
  136. VpcFilterListInputBase: query.VpcFilterListInputBase,
  137. }
  138. q, err = man.SVpcResourceBaseManager.ListItemFilter(ctx, q, userCred, vpcQuery)
  139. if err != nil {
  140. return nil, errors.Wrap(err, "SVpcResourceBaseManager.ListItemFilter")
  141. }
  142. zoneQuery := api.ZonalFilterListInput{
  143. ZonalFilterListBase: query.ZonalFilterListBase,
  144. }
  145. q, err = man.SZoneResourceBaseManager.ListItemFilter(ctx, q, userCred, zoneQuery)
  146. if err != nil {
  147. return nil, errors.Wrap(err, "SZoneResourceBaseManager.ListItemFilter")
  148. }
  149. netQuery := api.NetworkFilterListInput{
  150. NetworkFilterListBase: query.NetworkFilterListBase,
  151. }
  152. q, err = man.SNetworkResourceBaseManager.ListItemFilter(ctx, q, userCred, netQuery)
  153. if err != nil {
  154. return nil, errors.Wrap(err, "SNetworkResourceBaseManager.ListItemFilter")
  155. }
  156. ownerId := userCred
  157. data := jsonutils.Marshal(query).(*jsonutils.JSONDict)
  158. q, err = validators.ApplyModelFilters(ctx, q, data, []*validators.ModelFilterOptions{
  159. // {Key: "network", ModelKeyword: "network", OwnerId: ownerId},
  160. {Key: "cluster", ModelKeyword: "loadbalancercluster", OwnerId: ownerId},
  161. })
  162. if err != nil {
  163. return nil, err
  164. }
  165. if len(query.Address) == 1 {
  166. c1 := sqlchemy.In(q.Field("id"), ElasticipManager.Query("associate_id").Contains("ip_addr", query.Address[0]))
  167. c2 := sqlchemy.Contains(q.Field("address"), query.Address[0])
  168. q = q.Filter(sqlchemy.OR(c1, c2))
  169. } else if len(query.Address) > 1 {
  170. c1 := sqlchemy.In(q.Field("id"), ElasticipManager.Query("associate_id").In("ip_addr", query.Address))
  171. c2 := sqlchemy.In(q.Field("address"), query.Address)
  172. q = q.Filter(sqlchemy.OR(c1, c2))
  173. }
  174. // eip filters
  175. usableLbForEipFilter := query.UsableLoadbalancerForEip
  176. if len(usableLbForEipFilter) > 0 {
  177. eipObj, err := ElasticipManager.FetchByIdOrName(ctx, userCred, usableLbForEipFilter)
  178. if err != nil {
  179. if errors.Cause(err) == sql.ErrNoRows {
  180. return nil, httperrors.NewResourceNotFoundError("eip %s not found", usableLbForEipFilter)
  181. }
  182. return nil, httperrors.NewGeneralError(err)
  183. }
  184. eip := eipObj.(*SElasticip)
  185. if len(eip.NetworkId) > 0 {
  186. // kvm
  187. sq := LoadbalancernetworkManager.Query("loadbalancer_id").Equals("network_id", eip.NetworkId).SubQuery()
  188. q = q.NotIn("id", sq)
  189. if cp := eip.GetCloudprovider(); cp == nil || cp.Provider == api.CLOUD_PROVIDER_ONECLOUD {
  190. gnq := LoadbalancernetworkManager.Query().SubQuery()
  191. nq := NetworkManager.Query().SubQuery()
  192. wq := WireManager.Query().SubQuery()
  193. vq := VpcManager.Query().SubQuery()
  194. q.Join(gnq, sqlchemy.Equals(gnq.Field("loadbalancer_id"), q.Field("id")))
  195. q.Join(nq, sqlchemy.Equals(nq.Field("id"), gnq.Field("network_id")))
  196. q.Join(wq, sqlchemy.Equals(wq.Field("id"), nq.Field("wire_id")))
  197. q.Join(vq, sqlchemy.Equals(vq.Field("id"), wq.Field("vpc_id")))
  198. q.Filter(sqlchemy.NotEquals(vq.Field("id"), api.DEFAULT_VPC_ID))
  199. // vpc provider thing will be handled ok below
  200. }
  201. }
  202. if eip.ManagerId != "" {
  203. q = q.Equals("manager_id", eip.ManagerId)
  204. } else {
  205. q = q.IsNullOrEmpty("manager_id")
  206. }
  207. region, err := eip.GetRegion()
  208. if err != nil {
  209. return nil, httperrors.NewGeneralError(errors.Wrapf(err, "eip.GetRegion"))
  210. }
  211. q = q.Equals("cloudregion_id", region.Id)
  212. }
  213. withEip := (query.WithEip != nil && *query.WithEip)
  214. withoutEip := (query.WithoutEip != nil && *query.WithoutEip) || (query.EipAssociable != nil && *query.EipAssociable)
  215. if withEip || withoutEip {
  216. eips := ElasticipManager.Query().SubQuery()
  217. sq := eips.Query(eips.Field("associate_id")).Equals("associate_type", api.EIP_ASSOCIATE_TYPE_LOADBALANCER)
  218. sq = sq.IsNotNull("associate_id").IsNotEmpty("associate_id")
  219. if withEip {
  220. q = q.In("id", sq)
  221. } else if withoutEip {
  222. q = q.NotIn("id", sq)
  223. }
  224. }
  225. if query.EipAssociable != nil {
  226. sq1 := NetworkManager.Query("id")
  227. sq2 := WireManager.Query().SubQuery()
  228. sq3 := VpcManager.Query().SubQuery()
  229. sq1 = sq1.Join(sq2, sqlchemy.Equals(sq1.Field("wire_id"), sq2.Field("id")))
  230. sq1 = sq1.Join(sq3, sqlchemy.Equals(sq2.Field("vpc_id"), sq3.Field("id")))
  231. cond1 := []string{api.VPC_EXTERNAL_ACCESS_MODE_EIP, api.VPC_EXTERNAL_ACCESS_MODE_EIP_DISTGW}
  232. if *query.EipAssociable {
  233. sq1 = sq1.Filter(sqlchemy.In(sq3.Field("external_access_mode"), cond1))
  234. } else {
  235. sq1 = sq1.Filter(sqlchemy.NotIn(sq3.Field("external_access_mode"), cond1))
  236. }
  237. sq := LoadbalancernetworkManager.Query("loadbalancer_id").In("network_id", sq1)
  238. q = q.In("id", sq)
  239. }
  240. if len(query.AddressType) > 0 {
  241. q = q.In("address_type", query.AddressType)
  242. }
  243. if len(query.NetworkType) > 0 {
  244. q = q.In("network_type", query.NetworkType)
  245. }
  246. if len(query.ChargeType) > 0 {
  247. q = q.In("charge_type", query.ChargeType)
  248. }
  249. if len(query.LoadbalancerSpec) > 0 {
  250. q = q.In("loadbalancer_spec", query.LoadbalancerSpec)
  251. }
  252. if len(query.SecgroupId) > 0 {
  253. _, err := validators.ValidateModel(ctx, userCred, SecurityGroupManager, &query.SecgroupId)
  254. if err != nil {
  255. return nil, err
  256. }
  257. sq := LoadbalancerSecurityGroupManager.Query("loadbalancer_id").Equals("secgroup_id", query.SecgroupId)
  258. q = q.In("id", sq.SubQuery())
  259. }
  260. return q, nil
  261. }
  262. func (man *SLoadbalancerManager) OrderByExtraFields(
  263. ctx context.Context,
  264. q *sqlchemy.SQuery,
  265. userCred mcclient.TokenCredential,
  266. query api.LoadbalancerListInput,
  267. ) (*sqlchemy.SQuery, error) {
  268. var err error
  269. q, err = man.SVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VirtualResourceListInput)
  270. if err != nil {
  271. return nil, errors.Wrap(err, "SVirtualResourceBaseManager.OrderByExtraFields")
  272. }
  273. q, err = man.SManagedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ManagedResourceListInput)
  274. if err != nil {
  275. return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter")
  276. }
  277. q, err = man.SCloudregionResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.RegionalFilterListInput)
  278. if err != nil {
  279. return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemFilter")
  280. }
  281. vpcQuery := api.VpcFilterListInput{
  282. VpcFilterListInputBase: query.VpcFilterListInputBase,
  283. }
  284. q, err = man.SVpcResourceBaseManager.OrderByExtraFields(ctx, q, userCred, vpcQuery)
  285. if err != nil {
  286. return nil, errors.Wrap(err, "SVpcResourceBaseManager.OrderByExtraFields")
  287. }
  288. zoneQuery := api.ZonalFilterListInput{
  289. ZonalFilterListBase: query.ZonalFilterListBase,
  290. }
  291. q, err = man.SZoneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, zoneQuery)
  292. if err != nil {
  293. return nil, errors.Wrap(err, "SZoneResourceBaseManager.OrderByExtraFields")
  294. }
  295. netQuery := api.NetworkFilterListInput{
  296. NetworkFilterListBase: query.NetworkFilterListBase,
  297. }
  298. q, err = man.SNetworkResourceBaseManager.OrderByExtraFields(ctx, q, userCred, netQuery)
  299. if err != nil {
  300. return nil, errors.Wrap(err, "SNetworkResourceBaseManager.OrderByExtraFields")
  301. }
  302. return q, nil
  303. }
  304. func (man *SLoadbalancerManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
  305. var err error
  306. q, err = man.SVirtualResourceBaseManager.QueryDistinctExtraField(q, field)
  307. if err == nil {
  308. return q, nil
  309. }
  310. q, err = man.SVpcResourceBaseManager.QueryDistinctExtraField(q, field)
  311. if err == nil {
  312. return q, nil
  313. }
  314. q, err = man.SZoneResourceBaseManager.QueryDistinctExtraField(q, field)
  315. if err == nil {
  316. return q, nil
  317. }
  318. q, err = man.SNetworkResourceBaseManager.QueryDistinctExtraField(q, field)
  319. if err == nil {
  320. return q, nil
  321. }
  322. return q, httperrors.ErrNotFound
  323. }
  324. func (manager *SLoadbalancerManager) QueryDistinctExtraFields(q *sqlchemy.SQuery, resource string, fields []string) (*sqlchemy.SQuery, error) {
  325. var err error
  326. q, err = manager.SVpcResourceBaseManager.QueryDistinctExtraFields(q, resource, fields)
  327. if err == nil {
  328. return q, nil
  329. }
  330. return q, httperrors.ErrNotFound
  331. }
  332. func (man *SLoadbalancerManager) BatchCreateValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input *api.LoadbalancerCreateInput) (*api.LoadbalancerCreateInput, error) {
  333. return man.ValidateCreateData(ctx, userCred, ownerId, query, input)
  334. }
  335. func (man *SLoadbalancerManager) ValidateCreateData(
  336. ctx context.Context,
  337. userCred mcclient.TokenCredential,
  338. ownerId mcclient.IIdentityProvider,
  339. query jsonutils.JSONObject,
  340. input *api.LoadbalancerCreateInput,
  341. ) (*api.LoadbalancerCreateInput, error) {
  342. if len(input.NetworkId) > 0 {
  343. networks := strings.Split(input.NetworkId, ",")
  344. if len(networks) > 1 {
  345. input.Networks = networks[1:]
  346. }
  347. input.NetworkId = networks[0]
  348. networkObj, err := validators.ValidateModel(ctx, userCred, NetworkManager, &input.NetworkId)
  349. if err != nil {
  350. return nil, err
  351. }
  352. network := networkObj.(*SNetwork)
  353. wire, err := network.GetWire()
  354. if err != nil {
  355. return nil, err
  356. }
  357. if len(wire.ZoneId) > 0 {
  358. input.ZoneId = wire.ZoneId
  359. }
  360. vpc, err := network.GetVpc()
  361. if err != nil {
  362. return nil, err
  363. }
  364. input.VpcId = vpc.Id
  365. input.ManagerId = vpc.ManagerId
  366. input.CloudproviderId = vpc.ManagerId
  367. input.CloudregionId = vpc.CloudregionId
  368. for i := range input.Networks {
  369. netObj, err := validators.ValidateModel(ctx, userCred, NetworkManager, &input.Networks[i])
  370. if err != nil {
  371. return nil, err
  372. }
  373. network := netObj.(*SNetwork)
  374. vpc, err := network.GetVpc()
  375. if err != nil {
  376. return nil, err
  377. }
  378. if vpc.Id != input.VpcId {
  379. return nil, httperrors.NewInputParameterError("all networks should in the same vpc.")
  380. }
  381. }
  382. if len(input.Address) > 0 {
  383. addr, err := netutils.NewIPV4Addr(input.Address)
  384. if err != nil {
  385. return nil, httperrors.NewInputParameterError("invalidate address %s", input.Address)
  386. }
  387. if !network.IsAddressInRange(addr) {
  388. return nil, httperrors.NewInputParameterError("address %s not in network %s", input.Address, network.Name)
  389. }
  390. }
  391. } else if len(input.ZoneId) > 0 {
  392. zoneObj, err := validators.ValidateModel(ctx, userCred, ZoneManager, &input.ZoneId)
  393. if err != nil {
  394. return nil, err
  395. }
  396. zone := zoneObj.(*SZone)
  397. input.CloudregionId = zone.CloudregionId
  398. }
  399. if len(input.CloudregionId) == 0 {
  400. return nil, httperrors.NewMissingParameterError("cloudregion_id")
  401. }
  402. var cloudprovider *SCloudprovider = nil
  403. if len(input.CloudproviderId) > 0 {
  404. managerObj, err := validators.ValidateModel(ctx, userCred, CloudproviderManager, &input.CloudproviderId)
  405. if err != nil {
  406. return nil, err
  407. }
  408. input.ManagerId = input.CloudproviderId
  409. cloudprovider = managerObj.(*SCloudprovider)
  410. }
  411. if len(input.VpcId) > 0 {
  412. _vpc, err := validators.ValidateModel(ctx, userCred, VpcManager, &input.VpcId)
  413. if err != nil {
  414. return nil, err
  415. }
  416. vpc := _vpc.(*SVpc)
  417. if input.ManagerId != vpc.ManagerId {
  418. return nil, httperrors.NewInputParameterError("lb manager %s does not match vpc manager %s", input.ManagerId, vpc.ManagerId)
  419. }
  420. if input.CloudregionId != vpc.CloudregionId {
  421. return nil, httperrors.NewInputParameterError("lb region %s does not match vpc region %s", input.CloudregionId, vpc.CloudregionId)
  422. }
  423. }
  424. if len(input.Zone1) > 0 {
  425. _, err := validators.ValidateModel(ctx, userCred, ZoneManager, &input.Zone1)
  426. if err != nil {
  427. return nil, err
  428. }
  429. }
  430. if len(input.AddressType) == 0 {
  431. input.AddressType = api.LB_ADDR_TYPE_INTRANET
  432. }
  433. if len(input.NetworkType) == 0 {
  434. input.NetworkType = api.LB_NETWORK_TYPE_VPC
  435. }
  436. if len(input.EipId) > 0 {
  437. eipObj, err := validators.ValidateModel(ctx, userCred, ElasticipManager, &input.EipId)
  438. if err != nil {
  439. return nil, err
  440. }
  441. eip := eipObj.(*SElasticip)
  442. if eip.CloudregionId != input.CloudregionId {
  443. return nil, httperrors.NewInputParameterError("lb region %s does not match eip region %s", input.CloudregionId, eip.CloudregionId)
  444. }
  445. if eip.Status != api.EIP_STATUS_READY {
  446. return nil, httperrors.NewInvalidStatusError("eip %s status not ready", eip.Name)
  447. }
  448. if len(eip.AssociateType) > 0 {
  449. return nil, httperrors.NewInvalidStatusError("eip %s alread associate %s", eip.Name, eip.AssociateType)
  450. }
  451. if eip.ManagerId != input.ManagerId {
  452. return nil, httperrors.NewInputParameterError("lb manager %s does not match eip manager %s", input.ManagerId, eip.ManagerId)
  453. }
  454. }
  455. if len(input.Status) == 0 {
  456. input.Status = api.LB_STATUS_ENABLED
  457. }
  458. if len(input.AddressType) == 0 {
  459. input.AddressType = api.LB_ADDR_TYPE_INTRANET
  460. }
  461. if !utils.IsInStringArray(input.AddressType, []string{api.LB_ADDR_TYPE_INTRANET, api.LB_ADDR_TYPE_INTERNET}) {
  462. return nil, httperrors.NewInputParameterError("invalid address_type %s", input.AddressType)
  463. }
  464. if input.AddressType == api.LB_ADDR_TYPE_INTRANET && len(input.NetworkId) == 0 {
  465. return nil, httperrors.NewMissingParameterError("network_id")
  466. }
  467. if len(input.ChargeType) == 0 {
  468. input.ChargeType = api.LB_CHARGE_TYPE_BY_TRAFFIC
  469. }
  470. if !utils.IsInStringArray(input.ChargeType, []string{api.LB_CHARGE_TYPE_BY_BANDWIDTH, api.LB_CHARGE_TYPE_BY_TRAFFIC}) {
  471. return nil, httperrors.NewInputParameterError("invalid charge_type %s", input.ChargeType)
  472. }
  473. if len(input.Duration) > 0 {
  474. billingCycle, err := billing.ParseBillingCycle(input.Duration)
  475. if err != nil {
  476. return nil, httperrors.NewInputParameterError("invalid duration %s", input.Duration)
  477. }
  478. if len(input.BillingType) == 0 {
  479. input.BillingType = billing_api.BILLING_TYPE_PREPAID
  480. }
  481. input.BillingCycle = billingCycle.String()
  482. input.Duration = billingCycle.String()
  483. }
  484. regionObj, err := validators.ValidateModel(ctx, userCred, CloudregionManager, &input.CloudregionId)
  485. if err != nil {
  486. return nil, err
  487. }
  488. region := regionObj.(*SCloudregion)
  489. input.VirtualResourceCreateInput, err = man.SVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.VirtualResourceCreateInput)
  490. if err != nil {
  491. return nil, err
  492. }
  493. input, err = region.GetDriver().ValidateCreateLoadbalancerData(ctx, userCred, ownerId, input)
  494. if err != nil {
  495. return nil, err
  496. }
  497. quotaKeys := fetchRegionalQuotaKeys(rbacscope.ScopeProject, ownerId, region, cloudprovider)
  498. pendingUsage := SRegionQuota{Loadbalancer: 1}
  499. if input.EipBw > 0 && len(input.Eip) == 0 {
  500. pendingUsage.Eip = 1
  501. }
  502. pendingUsage.SetKeys(quotaKeys)
  503. if err := quotas.CheckSetPendingQuota(ctx, userCred, &pendingUsage); err != nil {
  504. return nil, httperrors.NewOutOfQuotaError("%s", err)
  505. }
  506. return input, nil
  507. }
  508. func (lb *SLoadbalancer) PerformStatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformStatusInput) (jsonutils.JSONObject, error) {
  509. if _, err := lb.SVirtualResourceBase.PerformStatus(ctx, userCred, query, input); err != nil {
  510. return nil, err
  511. }
  512. if lb.Status == api.LB_STATUS_ENABLED {
  513. return nil, lb.StartLoadBalancerStartTask(ctx, userCred, "")
  514. }
  515. return nil, lb.StartLoadBalancerStopTask(ctx, userCred, "")
  516. }
  517. func (lb *SLoadbalancer) StartLoadBalancerStartTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
  518. task, err := taskman.TaskManager.NewTask(ctx, "LoadbalancerStartTask", lb, userCred, nil, parentTaskId, "", nil)
  519. if err != nil {
  520. return errors.Wrapf(err, "NewTask")
  521. }
  522. return task.ScheduleRun(nil)
  523. }
  524. func (lb *SLoadbalancer) StartLoadBalancerStopTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
  525. task, err := taskman.TaskManager.NewTask(ctx, "LoadbalancerStopTask", lb, userCred, nil, parentTaskId, "", nil)
  526. if err != nil {
  527. return errors.Wrapf(err, "NewTask")
  528. }
  529. return task.ScheduleRun(nil)
  530. }
  531. func (lb *SLoadbalancer) PerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  532. return nil, StartResourceSyncStatusTask(ctx, userCred, lb, "LoadbalancerSyncstatusTask", "")
  533. }
  534. func (lb *SLoadbalancer) StartSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
  535. return StartResourceSyncStatusTask(ctx, userCred, lb, "LoadbalancerSyncstatusTask", parentTaskId)
  536. }
  537. func (lb *SLoadbalancer) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
  538. lb.SVirtualResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
  539. // NOTE lb.Id will only be available after BeforeInsert happens
  540. // NOTE this means lb.UpdateVersion will be 0, then 1 after creation
  541. // NOTE need ways to notify error
  542. pendingUsage := SRegionQuota{Loadbalancer: 1}
  543. pendingUsage.SetKeys(lb.GetQuotaKeys())
  544. err := quotas.CancelPendingUsage(ctx, userCred, &pendingUsage, &pendingUsage, true)
  545. if err != nil {
  546. log.Errorf("CancelPendingUsage error %s", err)
  547. }
  548. input := &api.LoadbalancerCreateInput{}
  549. data.Unmarshal(input)
  550. lb.SetStatus(ctx, userCred, api.LB_CREATING, "")
  551. err = lb.StartLoadBalancerCreateTask(ctx, userCred, input)
  552. if err != nil {
  553. lb.SetStatus(ctx, userCred, api.LB_CREATE_FAILED, err.Error())
  554. }
  555. }
  556. func (lb *SLoadbalancer) GetCloudprovider() *SCloudprovider {
  557. return lb.SManagedResourceBase.GetCloudprovider()
  558. }
  559. func (lb *SLoadbalancer) GetCloudproviderId() string {
  560. return lb.SManagedResourceBase.GetCloudproviderId()
  561. }
  562. func (lb *SLoadbalancer) GetRegion() (*SCloudregion, error) {
  563. return lb.SCloudregionResourceBase.GetRegion()
  564. }
  565. func (lb *SLoadbalancer) GetVpc() (*SVpc, error) {
  566. return lb.SVpcResourceBase.GetVpc()
  567. }
  568. func (lb *SLoadbalancer) GetZone() (*SZone, error) {
  569. return lb.SZoneResourceBase.GetZone()
  570. }
  571. func (lb *SLoadbalancer) GetNetworks() ([]SNetwork, error) {
  572. networks := []SNetwork{}
  573. networkIds := strings.Split(lb.NetworkId, ",")
  574. err := NetworkManager.Query().In("id", networkIds).All(&networks)
  575. if err != nil {
  576. return nil, err
  577. }
  578. if len(networks) == 0 {
  579. return nil, fmt.Errorf("loadbalancer has no releated network found")
  580. }
  581. if len(networks) != len(networkIds) {
  582. return nil, fmt.Errorf("expected %d networks, %d found", len(networkIds), len(networks))
  583. }
  584. return networks, nil
  585. }
  586. func (lb *SLoadbalancer) GetIRegion(ctx context.Context) (cloudprovider.ICloudRegion, error) {
  587. provider, err := lb.GetDriver(ctx)
  588. if err != nil {
  589. return nil, errors.Wrap(err, "lb.GetDriver")
  590. }
  591. region, err := lb.GetRegion()
  592. if err != nil {
  593. return nil, errors.Wrapf(err, "GetRegion")
  594. }
  595. return provider.GetIRegionById(region.ExternalId)
  596. }
  597. func (lb *SLoadbalancer) GetILoadbalancer(ctx context.Context) (cloudprovider.ICloudLoadbalancer, error) {
  598. if len(lb.ExternalId) == 0 {
  599. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty external id")
  600. }
  601. iRegion, err := lb.GetIRegion(ctx)
  602. if err != nil {
  603. return nil, errors.Wrapf(err, "GetIRegion")
  604. }
  605. return iRegion.GetILoadBalancerById(lb.ExternalId)
  606. }
  607. func (lb *SLoadbalancer) PerformPurge(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  608. params := jsonutils.NewDict()
  609. params.Add(jsonutils.JSONTrue, "purge")
  610. return nil, lb.StartLoadBalancerDeleteTask(ctx, userCred, params, "")
  611. }
  612. func (lb *SLoadbalancer) StartLoadBalancerDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error {
  613. task, err := taskman.TaskManager.NewTask(ctx, "LoadbalancerDeleteTask", lb, userCred, params, parentTaskId, "", nil)
  614. if err != nil {
  615. return errors.Wrapf(err, "NewTask")
  616. }
  617. return task.ScheduleRun(nil)
  618. }
  619. func (lb *SLoadbalancer) StartLoadBalancerCreateTask(ctx context.Context, userCred mcclient.TokenCredential, input *api.LoadbalancerCreateInput) error {
  620. params := jsonutils.Marshal(input).(*jsonutils.JSONDict)
  621. task, err := taskman.TaskManager.NewTask(ctx, "LoadbalancerCreateTask", lb, userCred, params, "", "", nil)
  622. if err != nil {
  623. return errors.Wrapf(err, "NewTask")
  624. }
  625. return task.ScheduleRun(nil)
  626. }
  627. func (lb *SLoadbalancer) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
  628. var (
  629. ownerId = lb.GetOwnerId()
  630. backendGroupV = validators.NewModelIdOrNameValidator("backend_group", "loadbalancerbackendgroup", ownerId)
  631. clusterV = validators.NewModelIdOrNameValidator("cluster", "loadbalancercluster", ownerId)
  632. keyV = map[string]validators.IValidator{
  633. "backend_group": backendGroupV,
  634. "cluster": clusterV,
  635. }
  636. )
  637. for _, v := range keyV {
  638. v.Optional(true)
  639. if err := v.Validate(ctx, data); err != nil {
  640. return nil, err
  641. }
  642. }
  643. if backendGroup, ok := backendGroupV.Model.(*SLoadbalancerBackendGroup); ok && backendGroup.LoadbalancerId != lb.Id {
  644. return nil, httperrors.NewInputParameterError("backend group %s(%s) belongs to loadbalancer %s, not %s",
  645. backendGroup.Name, backendGroup.Id, backendGroup.LoadbalancerId, lb.Id)
  646. }
  647. if clusterV.Model != nil {
  648. var (
  649. cluster = clusterV.Model.(*SLoadbalancerCluster)
  650. network, _ = lb.GetNetwork()
  651. wire, _ = network.GetWire()
  652. zone, _ = wire.GetZone()
  653. )
  654. if cluster.ZoneId != zone.Id {
  655. return nil, httperrors.NewInputParameterError("cluster zone %s does not match network zone %s ",
  656. cluster.ZoneId, zone.Id)
  657. }
  658. if cluster.WireId != "" && cluster.WireId != network.WireId {
  659. return nil, httperrors.NewInputParameterError("cluster wire affiliation does not match network's: %s != %s",
  660. cluster.WireId, network.WireId)
  661. }
  662. }
  663. input := apis.VirtualResourceBaseUpdateInput{}
  664. err := data.Unmarshal(&input)
  665. if err != nil {
  666. return nil, errors.Wrap(err, "Unmarshal")
  667. }
  668. input, err = lb.SVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, input)
  669. if err != nil {
  670. return nil, errors.Wrap(err, "SVirtualResourceBase.ValidateUpdateData")
  671. }
  672. data.Update(jsonutils.Marshal(input))
  673. return data, nil
  674. }
  675. type SLoadbalancerUsageCount struct {
  676. Id string
  677. api.LoadbalancerUsage
  678. }
  679. func (lm *SLoadbalancerManager) query(manager db.IModelManager, field string, lbIds []string, filter func(*sqlchemy.SQuery) *sqlchemy.SQuery) *sqlchemy.SSubQuery {
  680. q := manager.Query()
  681. if filter != nil {
  682. q = filter(q)
  683. }
  684. sq := q.SubQuery()
  685. return sq.Query(
  686. sq.Field("loadbalancer_id"),
  687. sqlchemy.COUNT(field),
  688. ).In("loadbalancer_id", lbIds).GroupBy(sq.Field("loadbalancer_id")).SubQuery()
  689. }
  690. func (manager *SLoadbalancerManager) TotalResourceCount(lbIds []string) (map[string]api.LoadbalancerUsage, error) {
  691. // backendGroup
  692. lbgSQ := manager.query(LoadbalancerBackendGroupManager, "backend_group_cnt", lbIds, nil)
  693. // listener
  694. lisSQ := manager.query(LoadbalancerListenerManager, "listener_cnt", lbIds, nil)
  695. lb := manager.Query().SubQuery()
  696. lbQ := lb.Query(
  697. sqlchemy.SUM("backend_group_count", lbgSQ.Field("backend_group_cnt")),
  698. sqlchemy.SUM("listener_count", lisSQ.Field("listener_cnt")),
  699. )
  700. lbQ.AppendField(lbQ.Field("id"))
  701. lbQ = lbQ.LeftJoin(lbgSQ, sqlchemy.Equals(lbQ.Field("id"), lbgSQ.Field("loadbalancer_id")))
  702. lbQ = lbQ.LeftJoin(lisSQ, sqlchemy.Equals(lbQ.Field("id"), lisSQ.Field("loadbalancer_id")))
  703. lbQ = lbQ.Filter(sqlchemy.In(lbQ.Field("id"), lbIds)).GroupBy(lbQ.Field("id"))
  704. lbCount := []SLoadbalancerUsageCount{}
  705. err := lbQ.All(&lbCount)
  706. if err != nil {
  707. return nil, errors.Wrapf(err, "lbQ.All")
  708. }
  709. result := map[string]api.LoadbalancerUsage{}
  710. for i := range lbCount {
  711. result[lbCount[i].Id] = lbCount[i].LoadbalancerUsage
  712. }
  713. return result, nil
  714. }
  715. func (man *SLoadbalancerManager) FetchCustomizeColumns(
  716. ctx context.Context,
  717. userCred mcclient.TokenCredential,
  718. query jsonutils.JSONObject,
  719. objs []interface{},
  720. fields stringutils2.SSortedStrings,
  721. isList bool,
  722. ) []api.LoadbalancerDetails {
  723. rows := make([]api.LoadbalancerDetails, len(objs))
  724. clusterRows := man.SLoadbalancerClusterResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  725. virtRows := man.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  726. manRows := man.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  727. regRows := man.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  728. vpcRows := man.SVpcResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  729. zoneRows := man.SZoneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  730. zone1Rows := man.FetchZone1ResourceInfos(ctx, userCred, query, objs)
  731. netRows := man.SNetworkResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  732. lbIds := make([]string, len(objs))
  733. backendGroupIds := make([]string, len(objs))
  734. for i := range rows {
  735. rows[i] = api.LoadbalancerDetails{
  736. LoadbalancerClusterResourceInfo: clusterRows[i],
  737. VirtualResourceDetails: virtRows[i],
  738. ManagedResourceInfo: manRows[i],
  739. CloudregionResourceInfo: regRows[i],
  740. VpcResourceInfoBase: vpcRows[i].VpcResourceInfoBase,
  741. ZoneResourceInfoBase: zoneRows[i].ZoneResourceInfoBase,
  742. Zone1ResourceInfoBase: zone1Rows[i],
  743. NetworkResourceInfoBase: netRows[i].NetworkResourceInfoBase,
  744. }
  745. lb := objs[i].(*SLoadbalancer)
  746. lbIds[i] = lb.Id
  747. backendGroupIds[i] = lb.BackendGroupId
  748. }
  749. q := ElasticipManager.Query().Equals("associate_type", api.EIP_ASSOCIATE_TYPE_LOADBALANCER).In("associate_id", lbIds)
  750. eips := []SElasticip{}
  751. err := db.FetchModelObjects(ElasticipManager, q, &eips)
  752. if err != nil {
  753. log.Errorf("Fetch eips error: %v", err)
  754. return rows
  755. }
  756. eipMap := map[string][]api.LbEip{}
  757. for i := range eips {
  758. associateId := eips[i].AssociateId
  759. _, ok := eipMap[associateId]
  760. if !ok {
  761. eipMap[associateId] = []api.LbEip{}
  762. }
  763. eipMap[associateId] = append(eipMap[associateId], api.LbEip{
  764. Eip: eips[i].IpAddr,
  765. EipId: eips[i].Id,
  766. EipMode: eips[i].Mode,
  767. })
  768. }
  769. bgMap, err := db.FetchIdNameMap2(LoadbalancerBackendGroupManager, backendGroupIds)
  770. if err != nil {
  771. log.Errorf("Fetch LoadbalancerBackendGroup error: %v", err)
  772. return rows
  773. }
  774. secSQ := SecurityGroupManager.Query().SubQuery()
  775. lsecs := LoadbalancerSecurityGroupManager.Query().SubQuery()
  776. q = secSQ.Query(
  777. secSQ.Field("id"),
  778. secSQ.Field("name"),
  779. lsecs.Field("loadbalancer_id"),
  780. ).
  781. Join(lsecs, sqlchemy.Equals(lsecs.Field("secgroup_id"), secSQ.Field("id"))).
  782. Filter(sqlchemy.In(lsecs.Field("loadbalancer_id"), lbIds))
  783. secInfo := []struct {
  784. Id string
  785. Name string
  786. LoadbalancerId string
  787. }{}
  788. err = q.All(&secInfo)
  789. if err != nil {
  790. log.Errorf("query secgroup info error: %v", err)
  791. return rows
  792. }
  793. groups := map[string][]api.SimpleSecurityGroup{}
  794. for _, sec := range secInfo {
  795. _, ok := groups[sec.LoadbalancerId]
  796. if !ok {
  797. groups[sec.LoadbalancerId] = []api.SimpleSecurityGroup{}
  798. }
  799. groups[sec.LoadbalancerId] = append(groups[sec.LoadbalancerId], api.SimpleSecurityGroup{
  800. Id: sec.Id,
  801. Name: sec.Name,
  802. })
  803. }
  804. usage, err := man.TotalResourceCount(lbIds)
  805. if err != nil {
  806. log.Errorf("TotalResourceCount error: %v", err)
  807. return rows
  808. }
  809. for i := range rows {
  810. eips, ok := eipMap[lbIds[i]]
  811. if ok {
  812. rows[i].Eips = eips
  813. rows[i].Eip = eips[0].Eip
  814. }
  815. bg, ok := bgMap[backendGroupIds[i]]
  816. if ok {
  817. rows[i].BackendGroup = bg
  818. }
  819. rows[i].Secgroups, _ = groups[lbIds[i]]
  820. rows[i].LoadbalancerUsage, _ = usage[lbIds[i]]
  821. }
  822. return rows
  823. }
  824. func (lb *SLoadbalancerManager) FetchZone1ResourceInfos(ctx context.Context,
  825. userCred mcclient.TokenCredential,
  826. query jsonutils.JSONObject,
  827. objs []interface{}) []api.Zone1ResourceInfoBase {
  828. rows := make([]api.Zone1ResourceInfoBase, len(objs))
  829. zoneIds := []string{}
  830. for i := range objs {
  831. zone1 := objs[i].(*SLoadbalancer).Zone1
  832. if len(zone1) > 0 {
  833. zoneIds = append(zoneIds, zone1)
  834. }
  835. }
  836. zones := make(map[string]SZone)
  837. err := db.FetchStandaloneObjectsByIds(ZoneManager, zoneIds, &zones)
  838. if err != nil {
  839. log.Errorf("FetchStandaloneObjectsByIds fail %s", err)
  840. return rows
  841. }
  842. for i := range objs {
  843. if zone, ok := zones[objs[i].(*SLoadbalancer).Zone1]; ok {
  844. rows[i].Zone1Name = zone.GetName()
  845. rows[i].Zone1ExtId = fetchExternalId(zone.GetExternalId())
  846. }
  847. }
  848. return rows
  849. }
  850. func (lb *SLoadbalancer) ValidateDeleteCondition(ctx context.Context, info jsonutils.JSONObject) error {
  851. if lb.DisableDelete.IsTrue() {
  852. return httperrors.NewInvalidStatusError("loadbalancer is locked, cannot delete")
  853. }
  854. return lb.SVirtualResourceBase.ValidateDeleteCondition(ctx, info)
  855. }
  856. func (lb *SLoadbalancer) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
  857. lb.SetStatus(ctx, userCred, api.LB_STATUS_DELETING, "")
  858. params := jsonutils.NewDict()
  859. deleteEip := jsonutils.QueryBoolean(data, "delete_eip", false)
  860. if deleteEip {
  861. params.Set("delete_eip", jsonutils.JSONTrue)
  862. }
  863. return lb.StartLoadBalancerDeleteTask(ctx, userCred, params, "")
  864. }
  865. func (lb *SLoadbalancer) GetLoadbalancerListeners() ([]SLoadbalancerListener, error) {
  866. listeners := []SLoadbalancerListener{}
  867. q := LoadbalancerListenerManager.Query().Equals("loadbalancer_id", lb.Id)
  868. if err := db.FetchModelObjects(LoadbalancerListenerManager, q, &listeners); err != nil {
  869. return nil, err
  870. }
  871. return listeners, nil
  872. }
  873. func (lb *SLoadbalancer) GetLoadbalancerBackendgroups() ([]SLoadbalancerBackendGroup, error) {
  874. lbbgs := []SLoadbalancerBackendGroup{}
  875. q := LoadbalancerBackendGroupManager.Query().Equals("loadbalancer_id", lb.Id)
  876. if err := db.FetchModelObjects(LoadbalancerBackendGroupManager, q, &lbbgs); err != nil {
  877. return nil, err
  878. }
  879. return lbbgs, nil
  880. }
  881. func (lb *SLoadbalancer) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
  882. if len(lb.NetworkId) > 0 {
  883. req := &SLoadbalancerNetworkDeleteData{
  884. loadbalancer: lb,
  885. }
  886. err := LoadbalancernetworkManager.DeleteLoadbalancerNetwork(ctx, userCred, req)
  887. if err != nil {
  888. return errors.Wrapf(err, "DeleteLoadbalancerNetwork")
  889. }
  890. }
  891. lbbgs, err := lb.GetLoadbalancerBackendgroups()
  892. if err != nil {
  893. return errors.Wrapf(err, "GetLoadbalancerBackendgroups")
  894. }
  895. for i := range lbbgs {
  896. err = lbbgs[i].RealDelete(ctx, userCred)
  897. if err != nil {
  898. return errors.Wrapf(err, "RealDelete lbbg %s", lbbgs[i].Id)
  899. }
  900. }
  901. listeners, err := lb.GetLoadbalancerListeners()
  902. if err != nil {
  903. return errors.Wrapf(err, "GetLoadbalancerListeners")
  904. }
  905. for i := range listeners {
  906. err = listeners[i].RealDelete(ctx, userCred)
  907. if err != nil {
  908. return errors.Wrapf(err, "RealDelete listener %s", listeners[i].Id)
  909. }
  910. }
  911. return lb.SVirtualResourceBase.Delete(ctx, userCred)
  912. }
  913. func (lb *SLoadbalancer) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
  914. return nil
  915. }
  916. func (man *SLoadbalancerManager) SyncLoadbalancers(
  917. ctx context.Context,
  918. userCred mcclient.TokenCredential,
  919. provider *SCloudprovider,
  920. region *SCloudregion,
  921. lbs []cloudprovider.ICloudLoadbalancer,
  922. xor bool,
  923. ) ([]SLoadbalancer, []cloudprovider.ICloudLoadbalancer, compare.SyncResult) {
  924. lockman.LockRawObject(ctx, man.Keyword(), fmt.Sprintf("%s-%s", provider.Id, region.Id))
  925. defer lockman.ReleaseRawObject(ctx, man.Keyword(), fmt.Sprintf("%s-%s", provider.Id, region.Id))
  926. localLbs := []SLoadbalancer{}
  927. remoteLbs := []cloudprovider.ICloudLoadbalancer{}
  928. syncResult := compare.SyncResult{}
  929. dbLbs, err := region.GetManagedLoadbalancers(provider.Id)
  930. if err != nil {
  931. syncResult.Error(err)
  932. return nil, nil, syncResult
  933. }
  934. for i := range dbLbs {
  935. if taskman.TaskManager.IsInTask(&dbLbs[i]) {
  936. syncResult.Error(fmt.Errorf("loadbalancer %s(%s)in task", dbLbs[i].Name, dbLbs[i].Id))
  937. return nil, nil, syncResult
  938. }
  939. }
  940. removed := []SLoadbalancer{}
  941. commondb := []SLoadbalancer{}
  942. commonext := []cloudprovider.ICloudLoadbalancer{}
  943. added := []cloudprovider.ICloudLoadbalancer{}
  944. err = compare.CompareSets(dbLbs, lbs, &removed, &commondb, &commonext, &added)
  945. if err != nil {
  946. syncResult.Error(err)
  947. return nil, nil, syncResult
  948. }
  949. for i := 0; i < len(removed); i++ {
  950. err = removed[i].syncRemoveCloudLoadbalancer(ctx, userCred)
  951. if err != nil {
  952. syncResult.DeleteError(err)
  953. } else {
  954. syncResult.Delete()
  955. }
  956. }
  957. if !xor {
  958. for i := 0; i < len(commondb); i++ {
  959. err = commondb[i].syncWithCloudLoadbalancer(ctx, userCred, commonext[i])
  960. if err != nil {
  961. syncResult.UpdateError(err)
  962. continue
  963. }
  964. localLbs = append(localLbs, commondb[i])
  965. remoteLbs = append(remoteLbs, commonext[i])
  966. syncResult.Update()
  967. }
  968. }
  969. for i := 0; i < len(added); i++ {
  970. lb, err := region.newFromCloudLoadbalancer(ctx, userCred, provider, added[i])
  971. if err != nil {
  972. syncResult.AddError(err)
  973. continue
  974. }
  975. localLbs = append(localLbs, *lb)
  976. remoteLbs = append(remoteLbs, added[i])
  977. syncResult.Add()
  978. }
  979. return localLbs, remoteLbs, syncResult
  980. }
  981. func getExtLbNetworkIds(extLb cloudprovider.ICloudLoadbalancer, managerId string) []string {
  982. extNetworkIds := extLb.GetNetworkIds()
  983. lbNetworkIds := []string{}
  984. for _, networkId := range extNetworkIds {
  985. network, err := db.FetchByExternalIdAndManagerId(NetworkManager, networkId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  986. wire := WireManager.Query().SubQuery()
  987. vpc := VpcManager.Query().SubQuery()
  988. return q.Join(wire, sqlchemy.Equals(wire.Field("id"), q.Field("wire_id"))).
  989. Join(vpc, sqlchemy.Equals(vpc.Field("id"), wire.Field("vpc_id"))).
  990. Filter(sqlchemy.Equals(vpc.Field("manager_id"), managerId))
  991. })
  992. if err == nil && network != nil {
  993. lbNetworkIds = append(lbNetworkIds, network.GetId())
  994. }
  995. }
  996. return lbNetworkIds
  997. }
  998. func (region *SCloudregion) newFromCloudLoadbalancer(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, ext cloudprovider.ICloudLoadbalancer) (*SLoadbalancer, error) {
  999. lb := SLoadbalancer{}
  1000. lb.SetModelManager(LoadbalancerManager, &lb)
  1001. lb.ManagerId = provider.Id
  1002. lb.CloudregionId = region.Id
  1003. lb.Address = ext.GetAddress()
  1004. lb.AddressType = ext.GetAddressType()
  1005. lb.NetworkType = ext.GetNetworkType()
  1006. lb.Status = ext.GetStatus()
  1007. lb.LoadbalancerSpec = ext.GetLoadbalancerSpec()
  1008. lb.ChargeType = billing_api.ParseNetChargeType(ext.GetChargeType())
  1009. lb.EgressMbps = ext.GetEgressMbps()
  1010. lb.ExternalId = ext.GetGlobalId()
  1011. lbNetworkIds := getExtLbNetworkIds(ext, lb.ManagerId)
  1012. lb.NetworkId = strings.Join(lbNetworkIds, ",")
  1013. if createdAt := ext.GetCreatedAt(); !createdAt.IsZero() {
  1014. lb.CreatedAt = createdAt
  1015. }
  1016. // vpc
  1017. if vpcId := ext.GetVpcId(); len(vpcId) > 0 {
  1018. if vpc, err := db.FetchByExternalIdAndManagerId(VpcManager, vpcId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  1019. return q.Equals("manager_id", provider.Id)
  1020. }); err == nil && vpc != nil {
  1021. lb.VpcId = vpc.GetId()
  1022. }
  1023. }
  1024. zones, err := region.GetZones()
  1025. if err != nil {
  1026. return nil, errors.Wrapf(err, "GetZones")
  1027. }
  1028. if zoneId := ext.GetZoneId(); len(zoneId) > 0 {
  1029. for i := range zones {
  1030. if strings.HasSuffix(zones[i].ExternalId, zoneId) {
  1031. lb.ZoneId = zones[i].Id
  1032. break
  1033. }
  1034. }
  1035. }
  1036. if zoneId := ext.GetZone1Id(); len(zoneId) > 0 {
  1037. for i := range zones {
  1038. if strings.HasSuffix(zones[i].ExternalId, zoneId) {
  1039. lb.Zone1 = zones[i].Id
  1040. break
  1041. }
  1042. }
  1043. }
  1044. syncOwnerId := provider.GetOwnerId()
  1045. err = func() error {
  1046. lockman.LockRawObject(ctx, LoadbalancerManager.Keyword(), "name")
  1047. defer lockman.ReleaseRawObject(ctx, LoadbalancerManager.Keyword(), "name")
  1048. var err error
  1049. lb.Name, err = db.GenerateName(ctx, LoadbalancerManager, syncOwnerId, ext.GetName())
  1050. if err != nil {
  1051. return err
  1052. }
  1053. return LoadbalancerManager.TableSpec().Insert(ctx, &lb)
  1054. }()
  1055. if err != nil {
  1056. return nil, errors.Wrapf(err, "Insert")
  1057. }
  1058. syncVirtualResourceMetadata(ctx, userCred, &lb, ext, false)
  1059. SyncCloudProject(ctx, userCred, &lb, syncOwnerId, ext, provider)
  1060. db.OpsLog.LogEvent(&lb, db.ACT_CREATE, lb.GetShortDesc(ctx), userCred)
  1061. notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
  1062. Obj: &lb,
  1063. Action: notifyclient.ActionSyncCreate,
  1064. })
  1065. lb.syncLoadbalancerNetwork(ctx, userCred, lbNetworkIds)
  1066. return &lb, nil
  1067. }
  1068. func (lb *SLoadbalancer) syncRemoveCloudLoadbalancer(ctx context.Context, userCred mcclient.TokenCredential) error {
  1069. lockman.LockObject(ctx, lb)
  1070. defer lockman.ReleaseObject(ctx, lb)
  1071. err := lb.SDeletePreventableResourceBase.DeletePreventionOff(lb, userCred)
  1072. if err != nil {
  1073. return err
  1074. }
  1075. err = lb.ValidateDeleteCondition(ctx, nil)
  1076. if err != nil { // cannot delete
  1077. return lb.SetStatus(ctx, userCred, api.LB_STATUS_UNKNOWN, "sync to delete")
  1078. }
  1079. err = lb.DeleteEip(ctx, userCred, false)
  1080. if err != nil {
  1081. return err
  1082. }
  1083. notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
  1084. Obj: lb,
  1085. Action: notifyclient.ActionSyncDelete,
  1086. })
  1087. return lb.RealDelete(ctx, userCred)
  1088. }
  1089. func (lb *SLoadbalancer) syncLoadbalancerNetwork(ctx context.Context, userCred mcclient.TokenCredential, networkIds []string) {
  1090. if len(lb.NetworkId) > 0 {
  1091. ip := ""
  1092. if net.ParseIP(lb.Address) != nil {
  1093. ip = lb.Address
  1094. }
  1095. for i := range networkIds {
  1096. lbNetReq := &SLoadbalancerNetworkRequestData{
  1097. Loadbalancer: lb,
  1098. NetworkId: networkIds[i],
  1099. Address: ip,
  1100. }
  1101. err := LoadbalancernetworkManager.syncLoadbalancerNetwork(ctx, userCred, lbNetReq)
  1102. if err != nil {
  1103. log.Errorf("failed to create loadbalancer network: %v", err)
  1104. }
  1105. }
  1106. }
  1107. }
  1108. func (self *SLoadbalancer) DeleteEip(ctx context.Context, userCred mcclient.TokenCredential, autoDelete bool) error {
  1109. eips, err := self.GetEips()
  1110. if err != nil {
  1111. log.Errorf("Delete eip fail for get Eip %s", err)
  1112. return err
  1113. }
  1114. for _, eip := range eips {
  1115. if eip.Mode == api.EIP_MODE_INSTANCE_PUBLICIP {
  1116. err = eip.RealDelete(ctx, userCred)
  1117. if err != nil {
  1118. log.Errorf("Delete eip on delete server fail %s", err)
  1119. return errors.Wrap(err, "RealDelete")
  1120. }
  1121. } else {
  1122. err = eip.Dissociate(ctx, userCred)
  1123. if err != nil {
  1124. log.Errorf("Dissociate eip on delete server fail %s", err)
  1125. return errors.Wrap(err, "Dissociate")
  1126. }
  1127. if autoDelete {
  1128. err = eip.RealDelete(ctx, userCred)
  1129. if err != nil {
  1130. log.Errorf("Delete eip on delete server fail %s", err)
  1131. return errors.Wrap(err, "RealDelete")
  1132. }
  1133. }
  1134. }
  1135. }
  1136. return nil
  1137. }
  1138. func (self *SLoadbalancer) GetEips() ([]SElasticip, error) {
  1139. q := ElasticipManager.Query().Equals("associate_id", self.Id).Equals("associate_type", api.EIP_ASSOCIATE_TYPE_LOADBALANCER)
  1140. ret := []SElasticip{}
  1141. err := db.FetchModelObjects(ElasticipManager, q, &ret)
  1142. if err != nil {
  1143. return nil, err
  1144. }
  1145. return ret, nil
  1146. }
  1147. func (self *SLoadbalancer) SyncLoadbalancerEips(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, extEips []cloudprovider.ICloudEIP) compare.SyncResult {
  1148. result := compare.SyncResult{}
  1149. eips, err := self.GetEips()
  1150. if err != nil {
  1151. result.Error(fmt.Errorf("getEip error %s", err))
  1152. return result
  1153. }
  1154. removed := []SElasticip{}
  1155. commondb := []SElasticip{}
  1156. commonext := []cloudprovider.ICloudEIP{}
  1157. added := []cloudprovider.ICloudEIP{}
  1158. err = compare.CompareSets(eips, extEips, &removed, &commondb, &commonext, &added)
  1159. if err != nil {
  1160. result.Error(err)
  1161. return result
  1162. }
  1163. for i := 0; i < len(removed); i++ {
  1164. err = removed[i].Dissociate(ctx, userCred)
  1165. if err != nil {
  1166. result.DeleteError(err)
  1167. } else {
  1168. result.Delete()
  1169. }
  1170. }
  1171. for i := 0; i < len(commondb); i++ {
  1172. result.Update()
  1173. }
  1174. for i := 0; i < len(added); i++ {
  1175. region, _ := self.GetRegion()
  1176. neip, err := ElasticipManager.getEipByExtEip(ctx, userCred, added[i], provider, region, provider.GetOwnerId())
  1177. if err != nil {
  1178. log.Errorf("getEipByExtEip error %v", err)
  1179. result.AddError(err)
  1180. } else {
  1181. err = neip.AssociateLoadbalancer(ctx, userCred, self)
  1182. if err != nil {
  1183. log.Errorf("AssociateVM error %v", err)
  1184. result.AddError(err)
  1185. } else {
  1186. result.Add()
  1187. }
  1188. }
  1189. }
  1190. return result
  1191. }
  1192. func (lb *SLoadbalancer) GetSecurityGroups() ([]SSecurityGroup, error) {
  1193. q := SecurityGroupManager.Query()
  1194. sq := LoadbalancerSecurityGroupManager.Query("secgroup_id").Equals("loadbalancer_id", lb.Id)
  1195. q = q.In("id", sq.SubQuery())
  1196. ret := []SSecurityGroup{}
  1197. err := db.FetchModelObjects(SecurityGroupManager, q, &ret)
  1198. if err != nil {
  1199. return nil, err
  1200. }
  1201. return ret, nil
  1202. }
  1203. func (lb *SLoadbalancer) removeSecurityGroups(ctx context.Context, userCred mcclient.TokenCredential, groupIds []string) {
  1204. params := []interface{}{time.Now(), lb.Id}
  1205. placeholder := []string{}
  1206. for _, id := range groupIds {
  1207. params = append(params, id)
  1208. placeholder = append(placeholder, "?")
  1209. }
  1210. sqlchemy.GetDB().Exec(
  1211. fmt.Sprintf(
  1212. "update %s set deleted = 1, deleted_at = ? where loadbalancer_id = ? and secgroup_id in (%s)",
  1213. LoadbalancerSecurityGroupManager.TableSpec().Name(), strings.Join(placeholder, ","),
  1214. ), params...,
  1215. )
  1216. }
  1217. func (lb *SLoadbalancer) addSecurityGroups(ctx context.Context, userCred mcclient.TokenCredential, groupIds []string) {
  1218. for _, groupId := range groupIds {
  1219. lbsec := &SLoadbalancerSecurityGroup{}
  1220. lbsec.LoadbalancerId = lb.Id
  1221. lbsec.SecgroupId = groupId
  1222. lbsec.SetModelManager(LoadbalancerSecurityGroupManager, lbsec)
  1223. LoadbalancerSecurityGroupManager.TableSpec().Insert(ctx, lbsec)
  1224. }
  1225. }
  1226. func (lb *SLoadbalancer) SyncSecurityGroups(ctx context.Context, userCred mcclient.TokenCredential, groupIds []string) compare.SyncResult {
  1227. result := compare.SyncResult{}
  1228. dbSecs, err := lb.GetSecurityGroups()
  1229. if err != nil {
  1230. result.Error(errors.Wrapf(err, "GetSecurityGroups"))
  1231. return result
  1232. }
  1233. remote := []SSecurityGroup{}
  1234. {
  1235. q := SecurityGroupManager.Query().In("external_id", groupIds).Equals("manager_id", lb.ManagerId)
  1236. err := db.FetchModelObjects(SecurityGroupManager, q, &remote)
  1237. if err != nil {
  1238. result.Error(errors.Wrapf(err, "FetchModelObjects"))
  1239. return result
  1240. }
  1241. }
  1242. removed := []string{}
  1243. common := []string{}
  1244. for _, sec := range dbSecs {
  1245. if !utils.IsInStringArray(sec.ExternalId, groupIds) {
  1246. removed = append(removed, sec.Id)
  1247. continue
  1248. }
  1249. common = append(common, sec.Id)
  1250. }
  1251. added := []string{}
  1252. for _, sec := range remote {
  1253. if !utils.IsInStringArray(sec.Id, common) && !utils.IsInStringArray(sec.Id, added) {
  1254. added = append(added, sec.Id)
  1255. }
  1256. }
  1257. lb.removeSecurityGroups(ctx, userCred, removed)
  1258. lb.addSecurityGroups(ctx, userCred, added)
  1259. result.AddCnt = len(added)
  1260. result.UpdateCnt = len(common)
  1261. result.DelCnt = len(removed)
  1262. return result
  1263. }
  1264. func (lb *SLoadbalancer) SyncWithCloudLoadbalancer(ctx context.Context, userCred mcclient.TokenCredential, ext cloudprovider.ICloudLoadbalancer, provider *SCloudprovider) error {
  1265. err := lb.syncWithCloudLoadbalancer(ctx, userCred, ext)
  1266. if err != nil {
  1267. return errors.Wrapf(err, "syncWithCloudLoadbalancer")
  1268. }
  1269. syncLbPeripherals(ctx, userCred, provider, lb, ext)
  1270. return nil
  1271. }
  1272. func (lb *SLoadbalancer) syncWithCloudLoadbalancer(ctx context.Context, userCred mcclient.TokenCredential, ext cloudprovider.ICloudLoadbalancer) error {
  1273. lockman.LockObject(ctx, lb)
  1274. defer lockman.ReleaseObject(ctx, lb)
  1275. diff, err := db.Update(lb, func() error {
  1276. if options.Options.EnableSyncName {
  1277. newName, _ := db.GenerateAlterName(lb, ext.GetName())
  1278. if len(newName) > 0 {
  1279. lb.Name = newName
  1280. }
  1281. }
  1282. lb.Address = ext.GetAddress()
  1283. lb.AddressType = ext.GetAddressType()
  1284. lb.Status = ext.GetStatus()
  1285. lb.LoadbalancerSpec = ext.GetLoadbalancerSpec()
  1286. lb.EgressMbps = ext.GetEgressMbps()
  1287. lb.ChargeType = billing_api.ParseNetChargeType(ext.GetChargeType())
  1288. lbNetworkIds := getExtLbNetworkIds(ext, lb.ManagerId)
  1289. lb.NetworkId = strings.Join(lbNetworkIds, ",")
  1290. if len(lb.VpcId) == 0 {
  1291. if vpcId := ext.GetVpcId(); len(vpcId) > 0 {
  1292. vpc, err := db.FetchByExternalIdAndManagerId(VpcManager, vpcId, func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  1293. return q.Equals("manager_id", lb.ManagerId)
  1294. })
  1295. if err != nil {
  1296. log.Errorf("fetch vpc %s error: %v", vpcId, err)
  1297. } else {
  1298. lb.VpcId = vpc.GetId()
  1299. }
  1300. }
  1301. }
  1302. if createdAt := ext.GetCreatedAt(); !createdAt.IsZero() {
  1303. lb.CreatedAt = createdAt
  1304. }
  1305. return nil
  1306. })
  1307. db.OpsLog.LogSyncUpdate(lb, diff, userCred)
  1308. if len(diff) > 0 {
  1309. notifyclient.EventNotify(ctx, userCred, notifyclient.SEventNotifyParam{
  1310. Obj: lb,
  1311. Action: notifyclient.ActionSyncUpdate,
  1312. })
  1313. }
  1314. networkIds := getExtLbNetworkIds(ext, lb.ManagerId)
  1315. if account := lb.GetCloudaccount(); account != nil {
  1316. syncVirtualResourceMetadata(ctx, userCred, lb, ext, account.ReadOnly)
  1317. }
  1318. provider := lb.GetCloudprovider()
  1319. SyncCloudProject(ctx, userCred, lb, provider.GetOwnerId(), ext, provider)
  1320. lb.syncLoadbalancerNetwork(ctx, userCred, networkIds)
  1321. return err
  1322. }
  1323. func (manager *SLoadbalancerManager) FetchByExternalId(providerId string, extId string) (*SLoadbalancer, error) {
  1324. ret := []SLoadbalancer{}
  1325. vpcs := VpcManager.Query().SubQuery()
  1326. q := manager.Query()
  1327. q = q.Join(vpcs, sqlchemy.Equals(q.Field("vpc_id"), vpcs.Field("id")))
  1328. q = q.Filter(sqlchemy.Equals(vpcs.Field("manager_id"), providerId))
  1329. q = q.Equals("external_id", extId)
  1330. err := db.FetchModelObjects(manager, q, &ret)
  1331. if err != nil {
  1332. return nil, err
  1333. }
  1334. if len(ret) == 1 {
  1335. return &ret[0], nil
  1336. } else {
  1337. return nil, fmt.Errorf("loadbalancerManager.FetchByExternalId provider %s external id %s %d found", providerId, extId, len(ret))
  1338. }
  1339. }
  1340. func (manager *SLoadbalancerManager) GetLbDefaultBackendGroupIds() ([]string, error) {
  1341. lbs := []SLoadbalancer{}
  1342. q := manager.Query().IsNotEmpty("backend_group_id")
  1343. err := q.All(&lbs)
  1344. if err != nil {
  1345. return nil, errors.Wrap(err, "loadbalancerManager.GetLbDefaultBackendGroupIds")
  1346. }
  1347. ret := []string{}
  1348. for i := range lbs {
  1349. ret = append(ret, lbs[i].BackendGroupId)
  1350. }
  1351. return ret, nil
  1352. }
  1353. func (man *SLoadbalancerManager) TotalCount(
  1354. ctx context.Context,
  1355. scope rbacscope.TRbacScope,
  1356. ownerId mcclient.IIdentityProvider,
  1357. rangeObjs []db.IStandaloneModel,
  1358. providers []string, brands []string, cloudEnv string,
  1359. policyResult rbacutils.SPolicyResult,
  1360. ) (int, error) {
  1361. q := man.Query()
  1362. q = db.ObjectIdQueryWithPolicyResult(ctx, q, man, policyResult)
  1363. q = scopeOwnerIdFilter(q, scope, ownerId)
  1364. q = CloudProviderFilter(q, q.Field("manager_id"), providers, brands, cloudEnv)
  1365. q = RangeObjectsFilter(q, rangeObjs, nil, q.Field("zone_id"), q.Field("manager_id"), nil, nil)
  1366. return q.CountWithError()
  1367. }
  1368. func (lb *SLoadbalancer) GetQuotaKeys() quotas.IQuotaKeys {
  1369. region, _ := lb.GetRegion()
  1370. return fetchRegionalQuotaKeys(
  1371. rbacscope.ScopeProject,
  1372. lb.GetOwnerId(),
  1373. region,
  1374. lb.GetCloudprovider(),
  1375. )
  1376. }
  1377. func (lb *SLoadbalancer) GetUsages() []db.IUsage {
  1378. if lb.PendingDeleted || lb.Deleted {
  1379. return nil
  1380. }
  1381. usage := SRegionQuota{Loadbalancer: 1}
  1382. keys := lb.GetQuotaKeys()
  1383. usage.SetKeys(keys)
  1384. return []db.IUsage{
  1385. &usage,
  1386. }
  1387. }
  1388. func (manager *SLoadbalancerManager) ListItemExportKeys(ctx context.Context,
  1389. q *sqlchemy.SQuery,
  1390. userCred mcclient.TokenCredential,
  1391. keys stringutils2.SSortedStrings,
  1392. ) (*sqlchemy.SQuery, error) {
  1393. var err error
  1394. q, err = manager.SVirtualResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  1395. if err != nil {
  1396. return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemExportKeys")
  1397. }
  1398. if keys.ContainsAny(manager.SManagedResourceBaseManager.GetExportKeys()...) {
  1399. q, err = manager.SManagedResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  1400. if err != nil {
  1401. return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemExportKeys")
  1402. }
  1403. }
  1404. if keys.ContainsAny(manager.SCloudregionResourceBaseManager.GetExportKeys()...) {
  1405. q, err = manager.SCloudregionResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  1406. if err != nil {
  1407. return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemExportKeys")
  1408. }
  1409. }
  1410. if keys.Contains("zone") {
  1411. q, err = manager.SZoneResourceBaseManager.ListItemExportKeys(ctx, q, userCred, stringutils2.NewSortedStrings([]string{"zone"}))
  1412. if err != nil {
  1413. return nil, errors.Wrap(err, "SZoneResourceBaseManager.ListItemExportKeys")
  1414. }
  1415. }
  1416. if keys.Contains("vpc") {
  1417. q, err = manager.SVpcResourceBaseManager.ListItemExportKeys(ctx, q, userCred, stringutils2.NewSortedStrings([]string{"vpc"}))
  1418. if err != nil {
  1419. return nil, errors.Wrap(err, "SVpcResourceBaseManager.ListItemExportKeys")
  1420. }
  1421. }
  1422. if keys.ContainsAny("network", "wire") {
  1423. q, err = manager.SNetworkResourceBaseManager.ListItemExportKeys(ctx, q, userCred, stringutils2.NewSortedStrings([]string{"network", "wire"}))
  1424. if err != nil {
  1425. return nil, errors.Wrap(err, "SNetworkResourceBaseManager.ListItemExportKeys")
  1426. }
  1427. }
  1428. return q, nil
  1429. }
  1430. func (self *SLoadbalancer) GetChangeOwnerCandidateDomainIds() []string {
  1431. return self.SManagedResourceBase.GetChangeOwnerCandidateDomainIds()
  1432. }
  1433. func (self *SLoadbalancer) PerformRemoteUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.LoadbalancerRemoteUpdateInput) (jsonutils.JSONObject, error) {
  1434. err := self.StartRemoteUpdateTask(ctx, userCred, (input.ReplaceTags != nil && *input.ReplaceTags), "")
  1435. if err != nil {
  1436. return nil, errors.Wrap(err, "StartRemoteUpdateTask")
  1437. }
  1438. return nil, nil
  1439. }
  1440. func (self *SLoadbalancer) StartRemoteUpdateTask(ctx context.Context, userCred mcclient.TokenCredential, replaceTags bool, parentTaskId string) error {
  1441. data := jsonutils.NewDict()
  1442. if replaceTags {
  1443. data.Add(jsonutils.JSONTrue, "replace_tags")
  1444. }
  1445. if task, err := taskman.TaskManager.NewTask(ctx, "LoadbalancerRemoteUpdateTask", self, userCred, data, parentTaskId, "", nil); err != nil {
  1446. log.Errorln(err)
  1447. return errors.Wrap(err, "Start LoadbalancerRemoteUpdateTask")
  1448. } else {
  1449. self.SetStatus(ctx, userCred, api.LB_UPDATE_TAGS, "StartRemoteUpdateTask")
  1450. task.ScheduleRun(nil)
  1451. }
  1452. return nil
  1453. }
  1454. func (self *SLoadbalancer) OnMetadataUpdated(ctx context.Context, userCred mcclient.TokenCredential) {
  1455. if len(self.ExternalId) == 0 || options.Options.KeepTagLocalization {
  1456. return
  1457. }
  1458. if account := self.GetCloudaccount(); account != nil && account.ReadOnly {
  1459. return
  1460. }
  1461. err := self.StartRemoteUpdateTask(ctx, userCred, true, "")
  1462. if err != nil {
  1463. log.Errorf("StartRemoteUpdateTask fail: %s", err)
  1464. }
  1465. }
  1466. func (lb *SLoadbalancer) IsEipAssociable() error {
  1467. if !utils.IsInStringArray(lb.Status, []string{api.LB_STATUS_ENABLED, api.LB_STATUS_DISABLED}) {
  1468. return errors.Wrapf(httperrors.ErrInvalidStatus, "cannot associate eip in status %s", lb.Status)
  1469. }
  1470. err := ValidateAssociateEip(lb)
  1471. if err != nil {
  1472. return errors.Wrap(err, "ValidateAssociateEip")
  1473. }
  1474. eips, err := lb.GetEips()
  1475. if err != nil {
  1476. return errors.Wrap(err, "GetElasticIp")
  1477. }
  1478. if len(eips) > 0 {
  1479. return httperrors.NewInvalidStatusError("already associate with eip")
  1480. }
  1481. return nil
  1482. }
  1483. // 绑定弹性公网IP, 仅支持kvm
  1484. func (lb *SLoadbalancer) PerformAssociateEip(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.LoadbalancerAssociateEipInput) (jsonutils.JSONObject, error) {
  1485. if lb.IsManaged() {
  1486. return nil, httperrors.NewUnsupportOperationError("not support managed lb")
  1487. }
  1488. err := lb.IsEipAssociable()
  1489. if err != nil {
  1490. return nil, httperrors.NewGeneralError(err)
  1491. }
  1492. eipStr := input.EipId
  1493. if len(eipStr) == 0 {
  1494. return nil, httperrors.NewMissingParameterError("eip_id")
  1495. }
  1496. eipObj, err := ElasticipManager.FetchByIdOrName(ctx, userCred, eipStr)
  1497. if err != nil {
  1498. if err == sql.ErrNoRows {
  1499. return nil, httperrors.NewResourceNotFoundError("eip %s not found", eipStr)
  1500. } else {
  1501. return nil, httperrors.NewGeneralError(err)
  1502. }
  1503. }
  1504. eip := eipObj.(*SElasticip)
  1505. eipRegion, err := eip.GetRegion()
  1506. if err != nil {
  1507. return nil, httperrors.NewGeneralError(errors.Wrapf(err, "eip.GetRegion"))
  1508. }
  1509. instRegion, _ := lb.GetRegion()
  1510. if eip.Mode == api.EIP_MODE_INSTANCE_PUBLICIP {
  1511. return nil, httperrors.NewUnsupportOperationError("fixed eip cannot be associated")
  1512. }
  1513. if eip.IsAssociated() {
  1514. return nil, httperrors.NewConflictError("eip has been associated")
  1515. }
  1516. if eipRegion.Id != instRegion.Id {
  1517. return nil, httperrors.NewInputParameterError("cannot associate eip and instance in different region")
  1518. }
  1519. if len(eip.NetworkId) > 0 {
  1520. nets, err := lb.GetNetworks()
  1521. if err != nil {
  1522. return nil, httperrors.NewGeneralError(errors.Wrap(err, "GetNetworks"))
  1523. }
  1524. for _, net := range nets {
  1525. if net.Id == eip.NetworkId {
  1526. return nil, httperrors.NewInputParameterError("cannot associate eip with same network")
  1527. }
  1528. }
  1529. }
  1530. eipZone, _ := eip.GetZone()
  1531. if eipZone != nil {
  1532. insZone, _ := lb.GetZone()
  1533. if eipZone.Id != insZone.Id {
  1534. return nil, httperrors.NewInputParameterError("cannot associate eip and instance in different zone")
  1535. }
  1536. }
  1537. if lb.ManagerId != eip.ManagerId {
  1538. return nil, httperrors.NewInputParameterError("cannot associate eip and instance in different provider")
  1539. }
  1540. err = eip.AssociateLoadbalancer(ctx, userCred, lb)
  1541. if err != nil {
  1542. return nil, errors.Wrap(err, "AssociateLoadbalancer")
  1543. }
  1544. _, err = db.Update(lb, func() error {
  1545. lb.Address = eip.IpAddr
  1546. lb.AddressType = api.LB_ADDR_TYPE_INTERNET
  1547. return nil
  1548. })
  1549. if err != nil {
  1550. return nil, errors.Wrap(err, "set loadbalancer address")
  1551. }
  1552. return nil, nil
  1553. }
  1554. // 解绑弹性公网IP,仅支持kvm
  1555. func (lb *SLoadbalancer) PerformDissociateEip(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.LoadbalancerDissociateEipInput) (jsonutils.JSONObject, error) {
  1556. if lb.IsManaged() {
  1557. return nil, httperrors.NewUnsupportOperationError("not support managed lb")
  1558. }
  1559. eips, err := lb.GetEips()
  1560. if err != nil {
  1561. log.Errorf("Fail to get Eip %s", err)
  1562. return nil, httperrors.NewGeneralError(err)
  1563. }
  1564. if len(eips) == 0 {
  1565. return nil, httperrors.NewInvalidStatusError("No eip to dissociate")
  1566. }
  1567. err = db.IsObjectRbacAllowed(ctx, &eips[0], userCred, policy.PolicyActionGet)
  1568. if err != nil {
  1569. return nil, errors.Wrap(err, "eip is not accessible")
  1570. }
  1571. lbnet, err := LoadbalancernetworkManager.FetchFirstByLbId(ctx, lb.Id)
  1572. if err != nil {
  1573. return nil, errors.Wrapf(err, "LoadbalancernetworkManager.FetchFirstByLbId(%s)", lb.Id)
  1574. }
  1575. if _, err := db.Update(lb, func() error {
  1576. lb.Address = lbnet.IpAddr
  1577. lb.AddressType = api.LB_ADDR_TYPE_INTRANET
  1578. return nil
  1579. }); err != nil {
  1580. return nil, errors.Wrapf(err, "db.Update")
  1581. }
  1582. autoDelete := (input.AudoDelete != nil && *input.AudoDelete)
  1583. err = lb.DeleteEip(ctx, userCred, autoDelete)
  1584. if err != nil {
  1585. return nil, errors.Wrap(err, "DeleteEip")
  1586. }
  1587. return nil, nil
  1588. }
  1589. func (lb *SLoadbalancer) PerformCreateEip(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.LoadbalancerCreateEipInput) (jsonutils.JSONObject, error) {
  1590. var (
  1591. region, _ = lb.GetRegion()
  1592. regionDriver = region.GetDriver()
  1593. bw = input.Bandwidth
  1594. chargeType = input.ChargeType
  1595. bgpType = input.BgpType
  1596. autoDellocate = (input.AutoDellocate != nil && *input.AutoDellocate)
  1597. )
  1598. err := lb.IsEipAssociable()
  1599. if err != nil {
  1600. return nil, httperrors.NewGeneralError(err)
  1601. }
  1602. if len(chargeType) == 0 {
  1603. chargeType = billing_api.TNetChargeType(regionDriver.GetEipDefaultChargeType())
  1604. }
  1605. if chargeType == billing_api.NET_CHARGE_TYPE_BY_BANDWIDTH {
  1606. if bw == 0 {
  1607. return nil, httperrors.NewMissingParameterError("bandwidth")
  1608. }
  1609. }
  1610. eipPendingUsage := &SRegionQuota{Eip: 1}
  1611. keys := lb.GetQuotaKeys()
  1612. eipPendingUsage.SetKeys(keys)
  1613. err = quotas.CheckSetPendingQuota(ctx, userCred, eipPendingUsage)
  1614. if err != nil {
  1615. return nil, httperrors.NewOutOfQuotaError("Out of eip quota: %s", err)
  1616. }
  1617. eip, err := ElasticipManager.NewEipForVMOnHost(ctx, userCred, &NewEipForVMOnHostArgs{
  1618. Bandwidth: int(bw),
  1619. BgpType: bgpType,
  1620. ChargeType: chargeType,
  1621. AutoDellocate: autoDellocate,
  1622. Loadbalancer: lb,
  1623. PendingUsage: eipPendingUsage,
  1624. })
  1625. if err != nil {
  1626. quotas.CancelPendingUsage(ctx, userCred, eipPendingUsage, eipPendingUsage, false)
  1627. return nil, httperrors.NewGeneralError(err)
  1628. }
  1629. opts := api.ElasticipAssociateInput{
  1630. InstanceId: lb.Id,
  1631. InstanceExternalId: lb.ExternalId,
  1632. InstanceType: api.EIP_ASSOCIATE_TYPE_LOADBALANCER,
  1633. }
  1634. err = eip.AllocateAndAssociateInstance(ctx, userCred, lb, opts, "")
  1635. if err != nil {
  1636. return nil, errors.Wrap(err, "AllocateAndAssociateInstance")
  1637. }
  1638. return nil, nil
  1639. }
  1640. func (man *SLoadbalancerManager) InitializeData() error {
  1641. _, err := sqlchemy.GetDB().Exec(
  1642. fmt.Sprintf(
  1643. "update %s set deleted = true where pending_deleted = true",
  1644. man.TableSpec().Name(),
  1645. ),
  1646. )
  1647. return err
  1648. }