routetables.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package models
  15. import (
  16. "context"
  17. "fmt"
  18. "yunion.io/x/cloudmux/pkg/cloudprovider"
  19. "yunion.io/x/jsonutils"
  20. "yunion.io/x/log"
  21. "yunion.io/x/pkg/errors"
  22. "yunion.io/x/pkg/gotypes"
  23. "yunion.io/x/pkg/util/compare"
  24. "yunion.io/x/sqlchemy"
  25. api "yunion.io/x/onecloud/pkg/apis/compute"
  26. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  27. "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
  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. type SRouteTableManager struct {
  34. db.SStatusInfrasResourceBaseManager
  35. db.SExternalizedResourceBaseManager
  36. SVpcResourceBaseManager
  37. }
  38. var RouteTableManager *SRouteTableManager
  39. func init() {
  40. RouteTableManager = &SRouteTableManager{
  41. SStatusInfrasResourceBaseManager: db.NewStatusInfrasResourceBaseManager(
  42. SRouteTable{},
  43. "route_tables_tbl",
  44. "route_table",
  45. "route_tables",
  46. ),
  47. }
  48. RouteTableManager.SetVirtualObject(RouteTableManager)
  49. }
  50. type SRouteTable struct {
  51. db.SStatusInfrasResourceBase
  52. db.SExternalizedResourceBase
  53. SVpcResourceBase `create:"required"`
  54. Type string `width:"16" charset:"ascii" nullable:"false" list:"user"`
  55. Routes *api.SRoutes `list:"user" update:"user" create:"required"`
  56. }
  57. // VPC虚拟路由表列表
  58. func (man *SRouteTableManager) ListItemFilter(
  59. ctx context.Context,
  60. q *sqlchemy.SQuery,
  61. userCred mcclient.TokenCredential,
  62. query api.RouteTableListInput,
  63. ) (*sqlchemy.SQuery, error) {
  64. var err error
  65. q, err = man.SStatusInfrasResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusInfrasResourceBaseListInput)
  66. if err != nil {
  67. return nil, errors.Wrap(err, "SStatusInfrasResourceBaseManager.ListItemFilter")
  68. }
  69. q, err = man.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
  70. if err != nil {
  71. return nil, errors.Wrap(err, "SExternalizedResourceBaseManager.ListItemFilter")
  72. }
  73. q, err = man.SVpcResourceBaseManager.ListItemFilter(ctx, q, userCred, query.VpcFilterListInput)
  74. if err != nil {
  75. return nil, errors.Wrap(err, "SVpcResourceBaseManager.ListItemFilter")
  76. }
  77. if len(query.Type) > 0 {
  78. q = q.In("type", query.Type)
  79. }
  80. return q, nil
  81. }
  82. func (man *SRouteTableManager) OrderByExtraFields(
  83. ctx context.Context,
  84. q *sqlchemy.SQuery,
  85. userCred mcclient.TokenCredential,
  86. query api.RouteTableListInput,
  87. ) (*sqlchemy.SQuery, error) {
  88. var err error
  89. q, err = man.SStatusInfrasResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusInfrasResourceBaseListInput)
  90. if err != nil {
  91. return nil, errors.Wrap(err, "SStatusInfrasResourceBaseManager.OrderByExtraFields")
  92. }
  93. q, err = man.SVpcResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.VpcFilterListInput)
  94. if err != nil {
  95. return nil, errors.Wrap(err, "SVpcResourceBaseManager.OrderByExtraFields")
  96. }
  97. return q, nil
  98. }
  99. func (man *SRouteTableManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
  100. var err error
  101. q, err = man.SInfrasResourceBaseManager.QueryDistinctExtraField(q, field)
  102. if err == nil {
  103. return q, nil
  104. }
  105. q, err = man.SVpcResourceBaseManager.QueryDistinctExtraField(q, field)
  106. if err == nil {
  107. return q, nil
  108. }
  109. return q, httperrors.ErrNotFound
  110. }
  111. func (man *SRouteTableManager) validateRoutes(ctx context.Context, data *jsonutils.JSONDict, update bool) (*jsonutils.JSONDict, error) {
  112. routes := api.SRoutes{}
  113. routesV := validators.NewStructValidator("routes", &routes)
  114. if update {
  115. routesV.Optional(true)
  116. }
  117. err := routesV.Validate(ctx, data)
  118. if err != nil {
  119. return nil, err
  120. }
  121. return data, nil
  122. }
  123. func (man *SRouteTableManager) ValidateCreateData(
  124. ctx context.Context,
  125. userCred mcclient.TokenCredential,
  126. ownerId mcclient.IIdentityProvider,
  127. query jsonutils.JSONObject,
  128. input api.RouteTableCreateInput,
  129. ) (api.RouteTableCreateInput, error) {
  130. _, err := man.validateRoutes(ctx, jsonutils.Marshal(input).(*jsonutils.JSONDict), false)
  131. if err != nil {
  132. return input, errors.Wrap(err, "validateRoutes")
  133. }
  134. _, err = validators.ValidateModel(ctx, userCred, VpcManager, &input.VpcId)
  135. if err != nil {
  136. return input, err
  137. }
  138. input.StatusInfrasResourceBaseCreateInput, err = man.SStatusInfrasResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.StatusInfrasResourceBaseCreateInput)
  139. if err != nil {
  140. return input, errors.Wrap(err, "SStatusInfrasResourceBaseManager.ValidateCreateData")
  141. }
  142. return input, nil
  143. }
  144. func (rt *SRouteTable) PerformPurge(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  145. err := rt.ValidateDeleteCondition(ctx, nil)
  146. if err != nil {
  147. return nil, err
  148. }
  149. provider := rt.GetCloudprovider()
  150. if provider != nil {
  151. if provider.GetEnabled() {
  152. return nil, httperrors.NewInvalidStatusError("Cannot purge route_table on enabled cloud provider")
  153. }
  154. }
  155. err = rt.RealDelete(ctx, userCred)
  156. return nil, err
  157. }
  158. func (rt *SRouteTable) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
  159. routeSets, err := rt.GetRouteTableRouteSets()
  160. if err != nil {
  161. return errors.Wrapf(err, "GetRouteTableRouteSets for %s(%s)", rt.Name, rt.Id)
  162. }
  163. for i := range routeSets {
  164. err = routeSets[i].RealDelete(ctx, userCred)
  165. if err != nil {
  166. return errors.Wrapf(err, "Delete routeSet %s(%s)", routeSets[i].Name, routeSets[i].Id)
  167. }
  168. }
  169. associations, err := rt.GetRouteTableAssociations()
  170. if err != nil {
  171. return errors.Wrapf(err, "GetRouteTableAssociations for %s(%s)", rt.Name, rt.Id)
  172. }
  173. for i := range associations {
  174. err = associations[i].RealDelete(ctx, userCred)
  175. if err != nil {
  176. return errors.Wrapf(err, "Delete routetable associations %s(%s)", associations[i].Name, associations[i].Id)
  177. }
  178. }
  179. return rt.SStatusInfrasResourceBase.Delete(ctx, userCred)
  180. }
  181. func (rt *SRouteTable) ValidateUpdateData(
  182. ctx context.Context,
  183. userCred mcclient.TokenCredential,
  184. query jsonutils.JSONObject,
  185. input api.RouteTableUpdateInput,
  186. ) (api.RouteTableUpdateInput, error) {
  187. _, err := RouteTableManager.validateRoutes(ctx, jsonutils.Marshal(input).(*jsonutils.JSONDict), true)
  188. if err != nil {
  189. return input, errors.Wrap(err, "RouteTableManager.validateRoutes")
  190. }
  191. input.StatusInfrasResourceBaseUpdateInput, err = rt.SStatusInfrasResourceBase.ValidateUpdateData(ctx, userCred, query, input.StatusInfrasResourceBaseUpdateInput)
  192. if err != nil {
  193. return input, errors.Wrap(err, "SStatusInfrasResourceBase.ValidateUpdateData")
  194. }
  195. return input, nil
  196. }
  197. // PerformAddRoutes patches acl entries by adding then deleting the specified acls.
  198. // This is intended mainly for command line operations.
  199. func (rt *SRouteTable) PerformAddRoutes(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
  200. var routes api.SRoutes
  201. if rt.Routes != nil {
  202. routes_ := gotypes.DeepCopy(rt.Routes).(*api.SRoutes)
  203. routes = *routes_
  204. }
  205. {
  206. adds := api.SRoutes{}
  207. addsV := validators.NewStructValidator("routes", &adds)
  208. addsV.Optional(true)
  209. err := addsV.Validate(ctx, data)
  210. if err != nil {
  211. return nil, err
  212. }
  213. for _, add := range adds {
  214. found := false
  215. for _, route := range routes {
  216. if route.Cidr == add.Cidr {
  217. found = true
  218. break
  219. }
  220. }
  221. if !found {
  222. routes = append(routes, add)
  223. }
  224. }
  225. }
  226. _, err := db.Update(rt, func() error {
  227. rt.Routes = &routes
  228. return nil
  229. })
  230. if err != nil {
  231. return nil, err
  232. }
  233. return nil, nil
  234. }
  235. func (rt *SRouteTable) PerformDelRoutes(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) {
  236. var routes api.SRoutes
  237. if rt.Routes != nil {
  238. routes_ := gotypes.DeepCopy(rt.Routes).(*api.SRoutes)
  239. routes = *routes_
  240. }
  241. {
  242. cidrs := []string{}
  243. err := data.Unmarshal(&cidrs, "cidrs")
  244. if err != nil {
  245. return nil, httperrors.NewInputParameterError("unmarshaling cidrs failed: %s", err)
  246. }
  247. for _, cidr := range cidrs {
  248. for i := len(routes) - 1; i >= 0; i-- {
  249. route := routes[i]
  250. if route.Type == "system" {
  251. continue
  252. }
  253. if route.Cidr == cidr {
  254. routes = append(routes[:i], routes[i+1:]...)
  255. break
  256. }
  257. }
  258. }
  259. }
  260. _, err := db.Update(rt, func() error {
  261. rt.Routes = &routes
  262. return nil
  263. })
  264. if err != nil {
  265. return nil, err
  266. }
  267. return nil, nil
  268. }
  269. func (manager *SRouteTableManager) FetchCustomizeColumns(
  270. ctx context.Context,
  271. userCred mcclient.TokenCredential,
  272. query jsonutils.JSONObject,
  273. objs []interface{},
  274. fields stringutils2.SSortedStrings,
  275. isList bool,
  276. ) []api.RouteTableDetails {
  277. rows := make([]api.RouteTableDetails, len(objs))
  278. routeTableIds := make([]string, len(objs))
  279. virtRows := manager.SStatusInfrasResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  280. vpcRows := manager.SVpcResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  281. for i := range rows {
  282. rows[i] = api.RouteTableDetails{
  283. StatusInfrasResourceBaseDetails: virtRows[i],
  284. VpcResourceInfo: vpcRows[i],
  285. }
  286. routeTable := objs[i].(*SRouteTable)
  287. routeTableIds[i] = routeTable.GetId()
  288. }
  289. routeSets := []SRouteTableRouteSet{}
  290. q := RouteTableRouteSetManager.Query().In("route_table_id", routeTableIds)
  291. err := db.FetchModelObjects(RouteTableRouteSetManager, q, &routeSets)
  292. if err != nil {
  293. return rows
  294. }
  295. routeSetMap := map[string][]string{}
  296. for i := range routeSets {
  297. if _, ok := routeSetMap[routeSets[i].RouteTableId]; !ok {
  298. routeSetMap[routeSets[i].RouteTableId] = []string{}
  299. }
  300. routeSetMap[routeSets[i].RouteTableId] = append(routeSetMap[routeSets[i].RouteTableId], routeSets[i].Id)
  301. }
  302. associations := []SRouteTableAssociation{}
  303. q = RouteTableAssociationManager.Query().In("route_table_id", routeTableIds)
  304. err = db.FetchModelObjects(RouteTableAssociationManager, q, &associations)
  305. if err != nil {
  306. return rows
  307. }
  308. associationMap := map[string][]string{}
  309. for i := range associations {
  310. if _, ok := associationMap[associations[i].RouteTableId]; !ok {
  311. associationMap[associations[i].RouteTableId] = []string{}
  312. }
  313. associationMap[associations[i].RouteTableId] = append(associationMap[associations[i].RouteTableId], associations[i].Id)
  314. }
  315. for i := range rows {
  316. rows[i].RouteSetCount = len(routeSetMap[routeTableIds[i]])
  317. rows[i].AccociationCount = len(associationMap[routeTableIds[i]])
  318. }
  319. return rows
  320. }
  321. func (man *SRouteTableManager) SyncRouteTables(
  322. ctx context.Context,
  323. userCred mcclient.TokenCredential,
  324. vpc *SVpc,
  325. cloudRouteTables []cloudprovider.ICloudRouteTable,
  326. provider *SCloudprovider,
  327. xor bool,
  328. ) ([]SRouteTable, []cloudprovider.ICloudRouteTable, compare.SyncResult) {
  329. lockman.LockRawObject(ctx, man.Keyword(), vpc.Id)
  330. defer lockman.ReleaseRawObject(ctx, man.Keyword(), vpc.Id)
  331. localRouteTables := make([]SRouteTable, 0)
  332. remoteRouteTables := make([]cloudprovider.ICloudRouteTable, 0)
  333. syncResult := compare.SyncResult{}
  334. dbRouteTables := []SRouteTable{}
  335. if err := db.FetchModelObjects(man, man.Query().Equals("vpc_id", vpc.Id), &dbRouteTables); err != nil {
  336. syncResult.Error(err)
  337. return nil, nil, syncResult
  338. }
  339. removed := make([]SRouteTable, 0)
  340. commondb := make([]SRouteTable, 0)
  341. commonext := make([]cloudprovider.ICloudRouteTable, 0)
  342. added := make([]cloudprovider.ICloudRouteTable, 0)
  343. if err := compare.CompareSets(dbRouteTables, cloudRouteTables, &removed, &commondb, &commonext, &added); err != nil {
  344. syncResult.Error(err)
  345. return nil, nil, syncResult
  346. }
  347. for i := 0; i < len(removed); i += 1 {
  348. err := removed[i].syncRemoveCloudRouteTable(ctx, userCred)
  349. if err != nil {
  350. syncResult.DeleteError(err)
  351. } else {
  352. syncResult.Delete()
  353. }
  354. }
  355. if !xor {
  356. for i := 0; i < len(commondb); i += 1 {
  357. err := commondb[i].SyncWithCloudRouteTable(ctx, userCred, vpc, commonext[i], provider)
  358. if err != nil {
  359. syncResult.UpdateError(err)
  360. continue
  361. }
  362. localRouteTables = append(localRouteTables, commondb[i])
  363. remoteRouteTables = append(remoteRouteTables, commonext[i])
  364. syncResult.Update()
  365. }
  366. }
  367. for i := 0; i < len(added); i += 1 {
  368. routeTableNew, err := man.insertFromCloud(ctx, userCred, vpc, added[i], provider)
  369. if err != nil {
  370. syncResult.AddError(err)
  371. continue
  372. }
  373. syncMetadata(ctx, userCred, routeTableNew, added[i], false)
  374. localRouteTables = append(localRouteTables, *routeTableNew)
  375. remoteRouteTables = append(remoteRouteTables, added[i])
  376. syncResult.Add()
  377. }
  378. return localRouteTables, remoteRouteTables, syncResult
  379. }
  380. func (man *SRouteTableManager) newRouteTableFromCloud(ctx context.Context, userCred mcclient.TokenCredential, vpc *SVpc, cloudRouteTable cloudprovider.ICloudRouteTable) (*SRouteTable, error) {
  381. routes := api.SRoutes{}
  382. {
  383. cloudRoutes, err := cloudRouteTable.GetIRoutes()
  384. if err != nil {
  385. return nil, err
  386. }
  387. for _, cloudRoute := range cloudRoutes {
  388. route := &api.SRoute{
  389. Type: cloudRoute.GetType(),
  390. Cidr: cloudRoute.GetCidr(),
  391. NextHopType: cloudRoute.GetNextHopType(),
  392. NextHopId: cloudRoute.GetNextHop(),
  393. }
  394. routes = append(routes, route)
  395. }
  396. }
  397. routeTable := &SRouteTable{
  398. Type: string(cloudRouteTable.GetType()),
  399. Routes: &routes,
  400. }
  401. routeTable.VpcId = vpc.Id
  402. {
  403. basename := routeTableBasename(cloudRouteTable.GetName(), vpc.Name)
  404. newName, err := db.GenerateName(ctx, man, userCred, basename)
  405. if err != nil {
  406. return nil, err
  407. }
  408. routeTable.Name = newName
  409. }
  410. // routeTable.ManagerId = vpc.ManagerId
  411. routeTable.Status = cloudRouteTable.GetStatus()
  412. routeTable.ExternalId = cloudRouteTable.GetGlobalId()
  413. routeTable.Description = cloudRouteTable.GetDescription()
  414. // routeTable.ProjectId = userCred.GetProjectId()
  415. // routeTable.DomainId = userCred.GetProjectDomainId()
  416. routeTable.SetModelManager(man, routeTable)
  417. return routeTable, nil
  418. }
  419. func routeTableBasename(name, vpcName string) string {
  420. if name != "" {
  421. return name
  422. } else if vpcName != "" {
  423. return "rtbl-" + vpcName
  424. } else {
  425. return "rtbl"
  426. }
  427. }
  428. func (man *SRouteTableManager) insertFromCloud(ctx context.Context, userCred mcclient.TokenCredential, vpc *SVpc, cloudRouteTable cloudprovider.ICloudRouteTable, provider *SCloudprovider) (*SRouteTable, error) {
  429. var routeTable *SRouteTable
  430. var err error
  431. err = func() error {
  432. lockman.LockRawObject(ctx, man.Keyword(), "name")
  433. defer lockman.ReleaseRawObject(ctx, man.Keyword(), "name")
  434. routeTable, err = man.newRouteTableFromCloud(ctx, userCred, vpc, cloudRouteTable)
  435. if err != nil {
  436. return err
  437. }
  438. return man.TableSpec().Insert(ctx, routeTable)
  439. }()
  440. if err != nil {
  441. return nil, err
  442. }
  443. if provider != nil {
  444. SyncCloudDomain(userCred, routeTable, provider.GetOwnerId())
  445. routeTable.SyncShareState(ctx, userCred, provider.getAccountShareInfo())
  446. }
  447. db.OpsLog.LogEvent(routeTable, db.ACT_CREATE, routeTable.GetShortDesc(ctx), userCred)
  448. return routeTable, nil
  449. }
  450. func (self *SRouteTable) syncRemoveCloudRouteTable(ctx context.Context, userCred mcclient.TokenCredential) error {
  451. lockman.LockObject(ctx, self)
  452. defer lockman.ReleaseObject(ctx, self)
  453. err := self.ValidateDeleteCondition(ctx, nil)
  454. if err != nil {
  455. return err
  456. }
  457. err = self.RealDelete(ctx, userCred)
  458. return err
  459. }
  460. func (self *SRouteTable) SyncWithCloudRouteTable(ctx context.Context, userCred mcclient.TokenCredential, vpc *SVpc, cloudRouteTable cloudprovider.ICloudRouteTable, provider *SCloudprovider) error {
  461. man := self.GetModelManager().(*SRouteTableManager)
  462. routeTable, err := man.newRouteTableFromCloud(ctx, userCred, vpc, cloudRouteTable)
  463. if err != nil {
  464. return err
  465. }
  466. diff, err := db.UpdateWithLock(ctx, self, func() error {
  467. // self.CloudregionId = routeTable.CloudregionId
  468. self.Status = routeTable.GetStatus()
  469. self.VpcId = vpc.Id
  470. self.Type = routeTable.Type
  471. self.Routes = routeTable.Routes
  472. return nil
  473. })
  474. if err != nil {
  475. return err
  476. }
  477. if provider != nil {
  478. SyncCloudDomain(userCred, self, provider.GetOwnerId())
  479. self.SyncShareState(ctx, userCred, provider.getAccountShareInfo())
  480. if account, _ := provider.GetCloudaccount(); account != nil {
  481. syncMetadata(ctx, userCred, self, cloudRouteTable, account.ReadOnly)
  482. }
  483. }
  484. db.OpsLog.LogSyncUpdate(self, diff, userCred)
  485. return nil
  486. }
  487. func (self *SRouteTable) SyncRouteTableRouteSets(
  488. ctx context.Context,
  489. userCred mcclient.TokenCredential,
  490. ext cloudprovider.ICloudRouteTable,
  491. provider *SCloudprovider,
  492. xor bool,
  493. ) compare.SyncResult {
  494. lockman.LockRawObject(ctx, self.Keyword(), fmt.Sprintf("%s-records", self.Id))
  495. defer lockman.ReleaseRawObject(ctx, self.Keyword(), fmt.Sprintf("%s-records", self.Id))
  496. syncResult := compare.SyncResult{}
  497. iRoutes, err := ext.GetIRoutes()
  498. if err != nil {
  499. syncResult.Error(errors.Wrapf(err, "GetIRoutes"))
  500. return syncResult
  501. }
  502. dbRouteSets, err := self.GetRouteTableRouteSets()
  503. if err != nil {
  504. syncResult.Error(errors.Wrapf(err, "GetRouteTableRouteSets"))
  505. return syncResult
  506. }
  507. removed := make([]SRouteTableRouteSet, 0)
  508. commondb := make([]SRouteTableRouteSet, 0)
  509. commonext := make([]cloudprovider.ICloudRoute, 0)
  510. added := make([]cloudprovider.ICloudRoute, 0)
  511. if err := compare.CompareSets(dbRouteSets, iRoutes, &removed, &commondb, &commonext, &added); err != nil {
  512. syncResult.Error(err)
  513. return syncResult
  514. }
  515. for i := range dbRouteSets {
  516. if len(dbRouteSets[i].ExternalId) == 0 {
  517. removed = append(removed, dbRouteSets[i])
  518. }
  519. }
  520. for i := 0; i < len(removed); i++ {
  521. err := removed[i].syncRemoveRouteSet(ctx, userCred)
  522. if err != nil {
  523. syncResult.DeleteError(err)
  524. } else {
  525. syncResult.Delete()
  526. }
  527. }
  528. if !xor {
  529. for i := 0; i < len(commondb); i++ {
  530. err := commondb[i].syncWithCloudRouteSet(ctx, userCred, provider, commonext[i])
  531. if err != nil {
  532. syncResult.UpdateError(err)
  533. continue
  534. }
  535. syncResult.Update()
  536. }
  537. }
  538. for i := 0; i < len(added); i++ {
  539. _, err := RouteTableRouteSetManager.newRouteSetFromCloud(ctx, userCred, self, provider, added[i])
  540. if err != nil {
  541. syncResult.AddError(err)
  542. continue
  543. }
  544. syncResult.Add()
  545. }
  546. return syncResult
  547. }
  548. func (self *SRouteTable) GetRouteTableRouteSets() ([]SRouteTableRouteSet, error) {
  549. routes := []SRouteTableRouteSet{}
  550. q := RouteTableRouteSetManager.Query().Equals("route_table_id", self.Id)
  551. err := db.FetchModelObjects(RouteTableRouteSetManager, q, &routes)
  552. if err != nil {
  553. return nil, errors.Wrapf(err, "db.FetchModelObjects")
  554. }
  555. return routes, nil
  556. }
  557. func (self *SRouteTable) SyncRouteTableAssociations(
  558. ctx context.Context,
  559. userCred mcclient.TokenCredential,
  560. ext cloudprovider.ICloudRouteTable,
  561. provider *SCloudprovider,
  562. xor bool,
  563. ) compare.SyncResult {
  564. lockman.LockRawObject(ctx, self.Keyword(), fmt.Sprintf("%s-records", self.Id))
  565. defer lockman.ReleaseRawObject(ctx, self.Keyword(), fmt.Sprintf("%s-records", self.Id))
  566. syncResult := compare.SyncResult{}
  567. extAssociations := ext.GetAssociations()
  568. dbAssociation, err := self.GetRouteTableAssociations()
  569. if err != nil {
  570. syncResult.Error(errors.Wrapf(err, "GetRouteTableRouteSets"))
  571. return syncResult
  572. }
  573. removed := make([]SRouteTableAssociation, 0)
  574. commondb := make([]SRouteTableAssociation, 0)
  575. commonext := make([]cloudprovider.RouteTableAssociation, 0)
  576. added := make([]cloudprovider.RouteTableAssociation, 0)
  577. if err := compare.CompareSets(dbAssociation, extAssociations, &removed, &commondb, &commonext, &added); err != nil {
  578. syncResult.Error(err)
  579. return syncResult
  580. }
  581. for i := range dbAssociation {
  582. if len(dbAssociation[i].ExternalId) == 0 {
  583. removed = append(removed, dbAssociation[i])
  584. }
  585. }
  586. for i := 0; i < len(removed); i++ {
  587. err := removed[i].syncRemoveAssociation(ctx, userCred)
  588. if err != nil {
  589. syncResult.DeleteError(err)
  590. } else {
  591. syncResult.Delete()
  592. }
  593. }
  594. if !xor {
  595. for i := 0; i < len(commondb); i++ {
  596. err := commondb[i].syncWithCloudAssociation(ctx, userCred, provider, commonext[i])
  597. if err != nil {
  598. syncResult.UpdateError(err)
  599. continue
  600. }
  601. syncResult.Update()
  602. }
  603. }
  604. for i := 0; i < len(added); i++ {
  605. _, err := RouteTableAssociationManager.newAssociationFromCloud(ctx, userCred, self, provider, added[i])
  606. if err != nil {
  607. syncResult.AddError(err)
  608. continue
  609. }
  610. syncResult.Add()
  611. }
  612. return syncResult
  613. }
  614. func (self *SRouteTable) GetRouteTableAssociations() ([]SRouteTableAssociation, error) {
  615. association := []SRouteTableAssociation{}
  616. q := RouteTableAssociationManager.Query().Equals("route_table_id", self.Id)
  617. err := db.FetchModelObjects(RouteTableAssociationManager, q, &association)
  618. if err != nil {
  619. return nil, errors.Wrapf(err, "db.FetchModelObjects")
  620. }
  621. return association, nil
  622. }
  623. func (self *SRouteTable) getVpc() (*SVpc, error) {
  624. val, err := VpcManager.FetchById(self.VpcId)
  625. if err != nil {
  626. log.Errorf("VpcManager.FetchById fail %s", err)
  627. return nil, err
  628. }
  629. return val.(*SVpc), nil
  630. }
  631. func (self *SRouteTable) getRegion() (*SCloudregion, error) {
  632. vpc, err := self.getVpc()
  633. if err != nil {
  634. return nil, err
  635. }
  636. return vpc.GetRegion()
  637. }
  638. func (self *SRouteTable) getCloudProviderInfo() SCloudProviderInfo {
  639. region, _ := self.getRegion()
  640. provider := self.GetCloudprovider()
  641. return MakeCloudProviderInfo(region, nil, provider)
  642. }
  643. func (self *SRouteTable) PerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.VpcSyncstatusInput) (jsonutils.JSONObject, error) {
  644. return nil, StartResourceSyncStatusTask(ctx, userCred, self, "RouteTableSyncStatusTask", "")
  645. }
  646. func (self *SRouteTable) GetICloudRouteTable(ctx context.Context) (cloudprovider.ICloudRouteTable, error) {
  647. vpc, err := self.getVpc()
  648. if err != nil {
  649. return nil, errors.Wrap(err, "self.getVpc()")
  650. }
  651. ivpc, err := vpc.GetIVpc(ctx)
  652. if err != nil {
  653. return nil, errors.Wrap(err, "self.GetIVpc()")
  654. }
  655. if len(self.ExternalId) == 0 {
  656. return nil, errors.Wrap(errors.ErrNotFound, "ExternalId not found")
  657. }
  658. iRouteTable, err := ivpc.GetIRouteTableById(self.ExternalId)
  659. if err != nil {
  660. return nil, errors.Wrapf(err, "ivpc.GetIRouteTableById(%s)", self.ExternalId)
  661. }
  662. return iRouteTable, nil
  663. }