loadbalancer_health_checks.go 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446
  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. "yunion.io/x/cloudmux/pkg/cloudprovider"
  18. "yunion.io/x/jsonutils"
  19. "yunion.io/x/log"
  20. "yunion.io/x/pkg/errors"
  21. "yunion.io/x/pkg/util/compare"
  22. "yunion.io/x/sqlchemy"
  23. "yunion.io/x/onecloud/pkg/apis"
  24. api "yunion.io/x/onecloud/pkg/apis/compute"
  25. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  26. "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
  27. "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
  28. "yunion.io/x/onecloud/pkg/cloudcommon/validators"
  29. "yunion.io/x/onecloud/pkg/httperrors"
  30. "yunion.io/x/onecloud/pkg/mcclient"
  31. "yunion.io/x/onecloud/pkg/util/stringutils2"
  32. )
  33. // +onecloud:swagger-gen-model-singular=loadbalancer_health_check
  34. // +onecloud:swagger-gen-model-plural=loadbalancerhealthchecks
  35. type SLoadbalancerHealthCheckManager struct {
  36. SLoadbalancerLogSkipper
  37. db.SVirtualResourceBaseManager
  38. db.SExternalizedResourceBaseManager
  39. SManagedResourceBaseManager
  40. SCloudregionResourceBaseManager
  41. }
  42. var LoadbalancerHealthCheckManager *SLoadbalancerHealthCheckManager
  43. func init() {
  44. LoadbalancerHealthCheckManager = &SLoadbalancerHealthCheckManager{
  45. SVirtualResourceBaseManager: db.NewVirtualResourceBaseManager(
  46. SLoadbalancerHealthCheck{},
  47. "loadbalancer_health_checks_tbl",
  48. "loadbalancer_health_check",
  49. "loadbalancer_health_checks",
  50. ),
  51. }
  52. LoadbalancerHealthCheckManager.SetVirtualObject(LoadbalancerHealthCheckManager)
  53. }
  54. type SLoadbalancerHealthCheck struct {
  55. db.SVirtualResourceBase
  56. db.SExternalizedResourceBase
  57. SManagedResourceBase
  58. SCloudregionResourceBase
  59. SLoadbalancerHealthChecker
  60. }
  61. // 健康检查列表
  62. func (man *SLoadbalancerHealthCheckManager) ListItemFilter(
  63. ctx context.Context,
  64. q *sqlchemy.SQuery,
  65. userCred mcclient.TokenCredential,
  66. query api.LoadbalancerHealthCheckListInput,
  67. ) (*sqlchemy.SQuery, error) {
  68. q, err := man.SVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VirtualResourceListInput)
  69. if err != nil {
  70. return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemFilter")
  71. }
  72. q, err = man.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
  73. if err != nil {
  74. return nil, errors.Wrap(err, "SExternalizedResourceBaseManager.ListItemFilter")
  75. }
  76. q, err = man.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ManagedResourceListInput)
  77. if err != nil {
  78. return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter")
  79. }
  80. q, err = man.SCloudregionResourceBaseManager.ListItemFilter(ctx, q, userCred, query.RegionalFilterListInput)
  81. if err != nil {
  82. return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.ListItemFilter")
  83. }
  84. return q, nil
  85. }
  86. func (man *SLoadbalancerHealthCheckManager) OrderByExtraFields(
  87. ctx context.Context,
  88. q *sqlchemy.SQuery,
  89. userCred mcclient.TokenCredential,
  90. query api.LoadbalancerHealthCheckListInput,
  91. ) (*sqlchemy.SQuery, error) {
  92. var err error
  93. q, err = man.SManagedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ManagedResourceListInput)
  94. if err != nil {
  95. return nil, errors.Wrap(err, "SManagedResourceBaseManager.OrderByExtraFields")
  96. }
  97. q, err = man.SCloudregionResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.RegionalFilterListInput)
  98. if err != nil {
  99. return nil, errors.Wrap(err, "SCloudregionResourceBaseManager.OrderByExtraFields")
  100. }
  101. return q, nil
  102. }
  103. func (man *SLoadbalancerHealthCheckManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
  104. var err error
  105. q, err = man.SManagedResourceBaseManager.QueryDistinctExtraField(q, field)
  106. if err == nil {
  107. return q, nil
  108. }
  109. q, err = man.SCloudregionResourceBaseManager.QueryDistinctExtraField(q, field)
  110. if err == nil {
  111. return q, nil
  112. }
  113. return q, httperrors.ErrNotFound
  114. }
  115. func (manager *SLoadbalancerHealthCheckManager) QueryDistinctExtraFields(q *sqlchemy.SQuery, resource string, fields []string) (*sqlchemy.SQuery, error) {
  116. var err error
  117. q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraFields(q, resource, fields)
  118. if err == nil {
  119. return q, nil
  120. }
  121. return q, httperrors.ErrNotFound
  122. }
  123. func (man *SLoadbalancerHealthCheckManager) ValidateCreateData(
  124. ctx context.Context,
  125. userCred mcclient.TokenCredential,
  126. ownerId mcclient.IIdentityProvider,
  127. query jsonutils.JSONObject,
  128. input *api.SLoadbalancerHealthCheckCreateInput,
  129. ) (*api.SLoadbalancerHealthCheckCreateInput, error) {
  130. var err error
  131. input.VirtualResourceCreateInput, err = man.SVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.VirtualResourceCreateInput)
  132. if err != nil {
  133. return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ValidateCreateData")
  134. }
  135. input.Status = apis.STATUS_CREATING
  136. regionObj, err := validators.ValidateModel(ctx, userCred, CloudregionManager, &input.CloudregionId)
  137. if err != nil {
  138. return nil, err
  139. }
  140. region := regionObj.(*SCloudregion)
  141. if len(input.CloudproviderId) > 0 {
  142. providerObj, err := validators.ValidateModel(ctx, userCred, CloudproviderManager, &input.CloudproviderId)
  143. if err != nil {
  144. return nil, err
  145. }
  146. input.ManagerId = input.CloudproviderId
  147. provider := providerObj.(*SCloudprovider)
  148. if provider.Provider != region.Provider {
  149. return nil, httperrors.NewConflictError("conflict region %s and cloudprovider %s", region.Name, provider.Name)
  150. }
  151. }
  152. return input, nil
  153. }
  154. func (hc *SLoadbalancerHealthCheck) ValidateUpdateData(
  155. ctx context.Context,
  156. userCred mcclient.TokenCredential,
  157. query jsonutils.JSONObject,
  158. input *api.SLoadbalancerHealthCheckUpdateInput,
  159. ) (*api.SLoadbalancerHealthCheckUpdateInput, error) {
  160. var err error
  161. input.VirtualResourceBaseUpdateInput, err = hc.SVirtualResourceBase.ValidateUpdateData(ctx, userCred, query, input.VirtualResourceBaseUpdateInput)
  162. if err != nil {
  163. return nil, errors.Wrap(err, "SVirtualResourceBase.ValidateUpdateData")
  164. }
  165. return input, nil
  166. }
  167. func (hc *SLoadbalancerHealthCheck) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) {
  168. hc.SVirtualResourceBase.PostUpdate(ctx, userCred, query, data)
  169. keys, _ := jsonutils.Marshal(SLoadbalancerHealthChecker{}).(*jsonutils.JSONDict).GetMap()
  170. needUpdate := false
  171. for key := range keys {
  172. if data.Contains(key) {
  173. needUpdate = true
  174. break
  175. }
  176. }
  177. if needUpdate {
  178. hc.StartLoadBalancerHealthCheckUpdateTask(ctx, userCred, "")
  179. }
  180. }
  181. func (hc *SLoadbalancerHealthCheck) StartLoadBalancerHealthCheckUpdateTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
  182. hc.SetStatus(ctx, userCred, api.LB_SYNC_CONF, "")
  183. task, err := taskman.TaskManager.NewTask(ctx, "LoadbalancerHealthCheckUpdateTask", hc, userCred, nil, parentTaskId, "", nil)
  184. if err != nil {
  185. return err
  186. }
  187. return task.ScheduleRun(nil)
  188. }
  189. func (hc *SLoadbalancerHealthCheck) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
  190. hc.SVirtualResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
  191. hc.SetStatus(ctx, userCred, api.LB_CREATING, "")
  192. err := hc.StartLoadBalancerHealthCheckCreateTask(ctx, userCred, "")
  193. if err != nil {
  194. log.Errorf("Failed to create loadbalancer backend error: %v", err)
  195. }
  196. }
  197. func (manager *SLoadbalancerHealthCheckManager) FetchCustomizeColumns(
  198. ctx context.Context,
  199. userCred mcclient.TokenCredential,
  200. query jsonutils.JSONObject,
  201. objs []interface{},
  202. fields stringutils2.SSortedStrings,
  203. isList bool,
  204. ) []api.LoadbalancerHealthCheckDetails {
  205. rows := make([]api.LoadbalancerHealthCheckDetails, len(objs))
  206. stdRows := manager.SVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  207. managerRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  208. regionRows := manager.SCloudregionResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  209. for i := range rows {
  210. rows[i] = api.LoadbalancerHealthCheckDetails{
  211. VirtualResourceDetails: stdRows[i],
  212. ManagedResourceInfo: managerRows[i],
  213. CloudregionResourceInfo: regionRows[i],
  214. }
  215. }
  216. return rows
  217. }
  218. func (hc *SLoadbalancerHealthCheck) StartLoadBalancerHealthCheckCreateTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
  219. task, err := taskman.TaskManager.NewTask(ctx, "LoadbalancerHealthCheckCreateTask", hc, userCred, nil, parentTaskId, "", nil)
  220. if err != nil {
  221. return errors.Wrapf(err, "NewTask")
  222. }
  223. return task.ScheduleRun(nil)
  224. }
  225. func (hc *SLoadbalancerHealthCheck) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
  226. return nil
  227. }
  228. func (hc *SLoadbalancerHealthCheck) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
  229. return hc.SVirtualResourceBase.Delete(ctx, userCred)
  230. }
  231. func (hc *SLoadbalancerHealthCheck) GetIRegion(ctx context.Context) (cloudprovider.ICloudRegion, error) {
  232. region, err := hc.GetRegion()
  233. if err != nil {
  234. return nil, errors.Wrapf(err, "GetRegion")
  235. }
  236. provider, err := hc.GetDriver(ctx)
  237. if err != nil {
  238. return nil, errors.Wrapf(err, "GetDriver")
  239. }
  240. return provider.GetIRegionById(region.ExternalId)
  241. }
  242. func (hc *SLoadbalancerHealthCheck) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
  243. hc.SetStatus(ctx, userCred, api.LB_STATUS_DELETING, "")
  244. return hc.StartLoadBalancerHealthCheckDeleteTask(ctx, userCred, jsonutils.NewDict(), "")
  245. }
  246. func (hc *SLoadbalancerHealthCheck) StartLoadBalancerHealthCheckDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, params *jsonutils.JSONDict, parentTaskId string) error {
  247. task, err := taskman.TaskManager.NewTask(ctx, "LoadbalancerHealthCheckDeleteTask", hc, userCred, params, parentTaskId, "", nil)
  248. if err != nil {
  249. return err
  250. }
  251. return task.ScheduleRun(nil)
  252. }
  253. func (region *SCloudregion) GetLoadbalancerHealthChecks(managerId string) ([]SLoadbalancerHealthCheck, error) {
  254. q := LoadbalancerHealthCheckManager.Query().Equals("manager_id", managerId).Equals("cloudregion_id", region.Id)
  255. ret := []SLoadbalancerHealthCheck{}
  256. err := db.FetchModelObjects(LoadbalancerHealthCheckManager, q, &ret)
  257. if err != nil {
  258. return nil, errors.Wrap(err, "FetchModelObjects")
  259. }
  260. return ret, nil
  261. }
  262. func (region *SCloudregion) SyncLoadbalancerHealthChecks(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, exts []cloudprovider.ICloudLoadbalancerHealthCheck) compare.SyncResult {
  263. lockman.LockRawObject(ctx, LoadbalancerHealthCheckManager.Keyword(), region.Id)
  264. defer lockman.ReleaseRawObject(ctx, LoadbalancerHealthCheckManager.Keyword(), region.Id)
  265. result := compare.SyncResult{}
  266. dbRes, err := region.GetLoadbalancerHealthChecks(provider.Id)
  267. if err != nil {
  268. result.Error(err)
  269. return result
  270. }
  271. removed := []SLoadbalancerHealthCheck{}
  272. commondb := []SLoadbalancerHealthCheck{}
  273. commonext := []cloudprovider.ICloudLoadbalancerHealthCheck{}
  274. added := []cloudprovider.ICloudLoadbalancerHealthCheck{}
  275. err = compare.CompareSets(dbRes, exts, &removed, &commondb, &commonext, &added)
  276. if err != nil {
  277. result.Error(err)
  278. return result
  279. }
  280. for i := 0; i < len(removed); i++ {
  281. err = removed[i].syncRemove(ctx, userCred)
  282. if err != nil {
  283. result.DeleteError(err)
  284. continue
  285. }
  286. result.Delete()
  287. }
  288. for i := 0; i < len(commondb); i++ {
  289. err = commondb[i].SyncWithCloudLoadbalancerHealthCheck(ctx, userCred, commonext[i], provider)
  290. if err != nil {
  291. result.UpdateError(err)
  292. continue
  293. }
  294. result.Update()
  295. }
  296. for i := 0; i < len(added); i++ {
  297. err := region.newFromCloudLoadbalancerHealthCheck(ctx, userCred, added[i], provider)
  298. if err != nil {
  299. result.AddError(err)
  300. continue
  301. }
  302. result.Add()
  303. }
  304. return result
  305. }
  306. func (hc *SLoadbalancerHealthCheck) SyncWithCloudLoadbalancerHealthCheck(
  307. ctx context.Context,
  308. userCred mcclient.TokenCredential,
  309. ext cloudprovider.ICloudLoadbalancerHealthCheck,
  310. provider *SCloudprovider,
  311. ) error {
  312. diff, err := db.UpdateWithLock(ctx, hc, func() error {
  313. hc.HealthCheck = ext.GetHealthCheck()
  314. hc.HealthCheckType = ext.GetHealthCheckType()
  315. hc.HealthCheckDomain = ext.GetHealthCheckDomain()
  316. hc.HealthCheckURI = ext.GetHealthCheckURI()
  317. hc.HealthCheckHttpCode = ext.GetHealthCheckCode()
  318. hc.HealthCheckMethod = ext.GetHealthCheckMethod()
  319. hc.HealthCheckPort = ext.GetHealthCheckPort()
  320. hc.HealthCheckRise = ext.GetHealthCheckRise()
  321. hc.HealthCheckFall = ext.GetHealthCheckFail()
  322. hc.HealthCheckTimeout = ext.GetHealthCheckTimeout()
  323. hc.HealthCheckInterval = ext.GetHealthCheckInterval()
  324. hc.HealthCheckReq = ext.GetHealthCheckReq()
  325. hc.HealthCheckExp = ext.GetHealthCheckExp()
  326. return nil
  327. })
  328. if err != nil {
  329. return err
  330. }
  331. syncVirtualResourceMetadata(ctx, userCred, hc, ext, false)
  332. SyncCloudProject(ctx, userCred, hc, provider.GetOwnerId(), ext, provider)
  333. if len(diff) > 0 {
  334. db.OpsLog.LogSyncUpdate(hc, diff, userCred)
  335. }
  336. return nil
  337. }
  338. func (region *SCloudregion) newFromCloudLoadbalancerHealthCheck(
  339. ctx context.Context,
  340. userCred mcclient.TokenCredential,
  341. ext cloudprovider.ICloudLoadbalancerHealthCheck,
  342. provider *SCloudprovider,
  343. ) error {
  344. hc := &SLoadbalancerHealthCheck{}
  345. hc.SetModelManager(LoadbalancerHealthCheckManager, hc)
  346. hc.Name = ext.GetName()
  347. hc.Status = ext.GetStatus()
  348. hc.ManagerId = provider.Id
  349. hc.CloudregionId = region.Id
  350. hc.ExternalId = ext.GetGlobalId()
  351. hc.HealthCheck = ext.GetHealthCheck()
  352. hc.HealthCheckType = ext.GetHealthCheckType()
  353. hc.HealthCheckDomain = ext.GetHealthCheckDomain()
  354. hc.HealthCheckURI = ext.GetHealthCheckURI()
  355. hc.HealthCheckHttpCode = ext.GetHealthCheckCode()
  356. hc.HealthCheckMethod = ext.GetHealthCheckMethod()
  357. hc.HealthCheckPort = ext.GetHealthCheckPort()
  358. hc.HealthCheckRise = ext.GetHealthCheckRise()
  359. hc.HealthCheckFall = ext.GetHealthCheckFail()
  360. hc.HealthCheckTimeout = ext.GetHealthCheckTimeout()
  361. hc.HealthCheckInterval = ext.GetHealthCheckInterval()
  362. hc.HealthCheckReq = ext.GetHealthCheckReq()
  363. hc.HealthCheckExp = ext.GetHealthCheckExp()
  364. hc.DomainId = provider.DomainId
  365. hc.ProjectId = provider.ProjectId
  366. err := LoadbalancerHealthCheckManager.TableSpec().Insert(ctx, hc)
  367. if err != nil {
  368. return errors.Wrap(err, "Insert")
  369. }
  370. syncVirtualResourceMetadata(ctx, userCred, hc, ext, false)
  371. SyncCloudProject(ctx, userCred, hc, provider.GetOwnerId(), ext, provider)
  372. return nil
  373. }
  374. func (hc *SLoadbalancerHealthCheck) syncRemove(ctx context.Context, userCred mcclient.TokenCredential) error {
  375. lockman.LockObject(ctx, hc)
  376. defer lockman.ReleaseObject(ctx, hc)
  377. return hc.RealDelete(ctx, userCred)
  378. }
  379. func (hc *SLoadbalancerHealthCheck) PerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  380. return nil, StartResourceSyncStatusTask(ctx, userCred, hc, "LoadbalancerHealthCheckSyncstatusTask", "")
  381. }
  382. func (manager *SLoadbalancerHealthCheckManager) ListItemExportKeys(ctx context.Context,
  383. q *sqlchemy.SQuery,
  384. userCred mcclient.TokenCredential,
  385. keys stringutils2.SSortedStrings,
  386. ) (*sqlchemy.SQuery, error) {
  387. var err error
  388. q, err = manager.SVirtualResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
  389. if err != nil {
  390. return nil, errors.Wrap(err, "SVirtualResourceBaseManager.ListItemExportKeys")
  391. }
  392. return q, nil
  393. }