networkaddresses.go 23 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729
  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. "strconv"
  19. "strings"
  20. "time"
  21. "yunion.io/x/cloudmux/pkg/cloudprovider"
  22. "yunion.io/x/jsonutils"
  23. "yunion.io/x/log"
  24. "yunion.io/x/pkg/errors"
  25. "yunion.io/x/pkg/util/delayedwork"
  26. "yunion.io/x/pkg/util/rbacscope"
  27. "yunion.io/x/sqlchemy"
  28. api "yunion.io/x/onecloud/pkg/apis/compute"
  29. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  30. "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
  31. "yunion.io/x/onecloud/pkg/httperrors"
  32. "yunion.io/x/onecloud/pkg/mcclient"
  33. "yunion.io/x/onecloud/pkg/mcclient/auth"
  34. ctxutils "yunion.io/x/onecloud/pkg/util/ctx"
  35. "yunion.io/x/onecloud/pkg/util/stringutils2"
  36. )
  37. // +onecloud:swagger-gen-model-singular=networkaddress
  38. // +onecloud:swagger-gen-model-plural=networkaddresses
  39. type SNetworkAddressManager struct {
  40. db.SStandaloneAnonResourceBaseManager
  41. SNetworkResourceBaseManager
  42. delayedWorkManager *delayedwork.DelayedWorkManager
  43. }
  44. var NetworkAddressManager *SNetworkAddressManager
  45. func init() {
  46. NetworkAddressManager = &SNetworkAddressManager{
  47. SStandaloneAnonResourceBaseManager: db.NewStandaloneAnonResourceBaseManager(
  48. SNetworkAddress{},
  49. "networkaddresses_tbl",
  50. "networkaddress",
  51. "networkaddresses",
  52. ),
  53. }
  54. NetworkAddressManager.SetVirtualObject(NetworkAddressManager)
  55. NetworkAddressManager.delayedWorkManager = delayedwork.NewDelayedWorkManager()
  56. }
  57. type SNetworkAddress struct {
  58. db.SStandaloneAnonResourceBase
  59. Type string `width:"16" charset:"ascii" list:"user" create:"required"`
  60. ParentType api.TNetworkAddressParentType `width:"16" charset:"ascii" list:"user" create:"required"`
  61. ParentId string `width:"16" charset:"ascii" list:"user" create:"optional"`
  62. SNetworkResourceBase
  63. IpAddr string `width:"16" charset:"ascii" list:"user" create:"optional"`
  64. SubCtrVid int `create:"optional"`
  65. }
  66. func (man *SNetworkAddressManager) InitializeData() error {
  67. go man.delayedWorkManager.Start(context.Background())
  68. {
  69. err := man.cleanDeletedGuestnetworkSubIPs()
  70. if err != nil {
  71. return errors.Wrapf(err, "cleanDeletedGuestnetworkSubIPs")
  72. }
  73. }
  74. return nil
  75. }
  76. func (man *SNetworkAddressManager) queryByParentTypeId(typ api.TNetworkAddressParentType, id string) *sqlchemy.SQuery {
  77. q := NetworkAddressManager.Query().
  78. Equals("parent_type", string(typ)).
  79. Equals("parent_id", id)
  80. return q
  81. }
  82. func (man *SNetworkAddressManager) queryByGuestnetworkId(rowid int64) *sqlchemy.SQuery {
  83. id := strconv.FormatInt(rowid, 10)
  84. return man.queryByParentTypeId(api.NetworkAddressParentTypeGuestnetwork, id)
  85. }
  86. func (man *SNetworkAddressManager) fetchByParentTypeId(typ api.TNetworkAddressParentType, id string) ([]SNetworkAddress, error) {
  87. var (
  88. q = man.queryByParentTypeId(typ, id)
  89. nas []SNetworkAddress
  90. )
  91. if err := db.FetchModelObjects(man, q, &nas); err != nil {
  92. return nil, err
  93. }
  94. return nas, nil
  95. }
  96. func (man *SNetworkAddressManager) fetchByGuestnetworkId(rowid int64) ([]SNetworkAddress, error) {
  97. id := strconv.FormatInt(rowid, 10)
  98. return man.fetchByParentTypeId(api.NetworkAddressParentTypeGuestnetwork, id)
  99. }
  100. func (man *SNetworkAddressManager) fetchAddressCountByGuestnetworkId(rowid int64) (int, error) {
  101. q := man.queryByGuestnetworkId(rowid)
  102. return q.CountWithError()
  103. }
  104. func (man *SNetworkAddressManager) fetchAddressesByGuestnetworkId(rowid int64) ([]api.NetworkAddrConf, error) {
  105. var (
  106. naq = man.queryByGuestnetworkId(rowid).SubQuery()
  107. nq = NetworkManager.Query().SubQuery()
  108. ipnetsq = naq.Query(
  109. naq.Field("id"),
  110. naq.Field("type"),
  111. naq.Field("ip_addr"),
  112. nq.Field("guest_ip_mask").Label("masklen"),
  113. nq.Field("guest_gateway").Label("gateway"),
  114. ).Join(nq, sqlchemy.Equals(
  115. naq.Field("network_id"),
  116. nq.Field("id")),
  117. )
  118. ipnets []api.NetworkAddrConf
  119. )
  120. if err := ipnetsq.All(&ipnets); err != nil {
  121. return nil, errors.Wrapf(err, "fetch addresses ipnets by guestnetwork row id: %d", rowid)
  122. }
  123. return ipnets, nil
  124. }
  125. func (man *SNetworkAddressManager) deleteByGuestnetworkId(ctx context.Context, userCred mcclient.TokenCredential, rowid int64) error {
  126. nas, err := NetworkAddressManager.fetchByGuestnetworkId(rowid)
  127. if err != nil {
  128. return errors.Wrap(err, "fetch attached network addresses")
  129. }
  130. var errs []error
  131. for i := range nas {
  132. na := &nas[i]
  133. if err := na.remoteUnassignAddress(ctx, userCred); err != nil {
  134. errs = append(errs, err)
  135. continue
  136. }
  137. if err := db.DeleteModel(ctx, userCred, na); err != nil {
  138. errs = append(errs, err)
  139. continue
  140. }
  141. }
  142. return errors.NewAggregate(errs)
  143. }
  144. func (man *SNetworkAddressManager) syncGuestnetworkICloudNic(ctx context.Context, userCred mcclient.TokenCredential, guestnetwork *SGuestnetwork, iNic cloudprovider.ICloudNic) error {
  145. ipAddrs, err := iNic.GetSubAddress()
  146. if err != nil {
  147. return errors.Wrap(err, "iNic.GetSubAddress")
  148. }
  149. if err := man.syncGuestnetworkSubIPs(ctx, userCred, guestnetwork, ipAddrs); err != nil {
  150. return errors.Wrap(err, "syncGuestnetworkSubIPs")
  151. }
  152. return nil
  153. }
  154. func (man *SNetworkAddressManager) syncGuestnetworkSubIPs(ctx context.Context, userCred mcclient.TokenCredential, guestnetwork *SGuestnetwork, ipAddrs []string) error {
  155. nas, err := man.fetchByGuestnetworkId(guestnetwork.RowId)
  156. if err != nil {
  157. return errors.Wrap(err, "fetchByGuestnetworkId")
  158. }
  159. existings := stringutils2.NewSortedStrings(nil)
  160. for i := range nas {
  161. existings = existings.Append(nas[i].IpAddr)
  162. }
  163. probed := stringutils2.NewSortedStrings(ipAddrs)
  164. removes, _, adds := stringutils2.Split(existings, probed)
  165. log.Debugf("syncGuestnetworkSubIPs removes: %s add %s", jsonutils.Marshal(removes), jsonutils.Marshal(adds))
  166. if err := man.removeGuestnetworkSubIPs(ctx, userCred, guestnetwork, removes); err != nil {
  167. return err
  168. }
  169. if _, err := man.addGuestnetworkSubIPs(ctx, userCred, guestnetwork, api.GuestAddSubIpsInfo{
  170. SubIps: adds,
  171. Reserved: true,
  172. }); err != nil {
  173. return err
  174. }
  175. return nil
  176. }
  177. func (man *SNetworkAddressManager) removeGuestnetworkSubIPs(ctx context.Context, userCred mcclient.TokenCredential, guestnetwork *SGuestnetwork, ipAddrs []string) error {
  178. q := man.queryByGuestnetworkId(guestnetwork.RowId)
  179. q = q.In("ip_addr", ipAddrs)
  180. var nas []SNetworkAddress
  181. if err := db.FetchModelObjects(man, q, &nas); err != nil {
  182. return errors.Wrapf(err, "removeGuestnetworkSubIPs by ipAddrs %s", strings.Join(ipAddrs, ", "))
  183. }
  184. for i := range nas {
  185. na := &nas[i]
  186. if err := db.DeleteModel(ctx, userCred, na); err != nil {
  187. return err
  188. }
  189. }
  190. return nil
  191. }
  192. func (man *SNetworkAddressManager) addGuestnetworkSubIPs(ctx context.Context, userCred mcclient.TokenCredential, guestnetwork *SGuestnetwork, input api.GuestAddSubIpsInfo) ([]string, error) {
  193. net, err := guestnetwork.GetNetwork()
  194. if err != nil {
  195. return nil, errors.Wrapf(err, "GetNetwork")
  196. }
  197. lockman.LockObject(ctx, net)
  198. defer lockman.ReleaseObject(ctx, net)
  199. var (
  200. usedAddrMap = net.GetUsedAddresses(ctx)
  201. recentUsedAddrTable = GuestnetworkManager.getRecentlyReleasedIPAddresses(net.Id, net.getAllocTimoutDuration())
  202. )
  203. if input.Count == 0 {
  204. input.Count = len(input.SubIps)
  205. }
  206. if input.Count == 0 {
  207. // nil operation
  208. return nil, nil
  209. }
  210. addedIps := make([]string, 0)
  211. errs := make([]error, 0)
  212. for i := 0; i < input.Count; i++ {
  213. var candidate string
  214. if i < len(input.SubIps) {
  215. candidate = input.SubIps[i]
  216. }
  217. ipAddr, err := net.GetFreeIP(ctx, userCred, usedAddrMap, recentUsedAddrTable, candidate, input.AllocDir, input.Reserved, api.AddressTypeIPv4)
  218. if err != nil {
  219. errs = append(errs, errors.Wrap(err, "GetFreeIP"))
  220. continue
  221. }
  222. m, err := db.NewModelObject(man)
  223. if err != nil {
  224. errs = append(errs, errors.Wrap(err, "NewModelObject"))
  225. continue
  226. }
  227. na := m.(*SNetworkAddress)
  228. na.NetworkId = guestnetwork.NetworkId
  229. na.ParentType = api.NetworkAddressParentTypeGuestnetwork
  230. na.ParentId = strconv.FormatInt(guestnetwork.RowId, 10)
  231. na.Type = api.NetworkAddressTypeSubIP
  232. na.IpAddr = ipAddr
  233. if err := man.TableSpec().Insert(ctx, na); err != nil {
  234. errs = append(errs, errors.Wrapf(err, "addGuestnetworkSubIPs"))
  235. continue
  236. }
  237. usedAddrMap[ipAddr] = true
  238. addedIps = append(addedIps, ipAddr)
  239. }
  240. if len(errs) > 0 {
  241. return addedIps, errors.NewAggregate(errs)
  242. }
  243. return addedIps, nil
  244. }
  245. func (man *SNetworkAddressManager) ValidateCreateData(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, input api.NetworkAddressCreateInput) (api.NetworkAddressCreateInput, error) {
  246. return input, errors.Wrap(httperrors.ErrNotSupported, "no supported")
  247. }
  248. func (na *SNetworkAddress) parentIdInt64() int64 {
  249. r, err := strconv.ParseInt(na.ParentId, 10, 64)
  250. if err != nil {
  251. panic(fmt.Sprintf("networkaddress %s: invalid parent_id %s", na.Id, na.ParentId))
  252. }
  253. return r
  254. }
  255. func (na *SNetworkAddress) getGuestnetwork(ctx context.Context, userCred mcclient.TokenCredential) (*SGuestnetwork, error) {
  256. if na.ParentType == api.NetworkAddressParentTypeGuestnetwork {
  257. guestnetwork, err := GuestnetworkManager.fetchByRowId(ctx, userCred, na.parentIdInt64())
  258. if err != nil {
  259. return nil, err
  260. }
  261. return guestnetwork, nil
  262. }
  263. return nil, errors.Errorf("getGuestnetwork: expect parent_type %s, got %s", api.NetworkAddressParentTypeGuestnetwork, na.ParentType)
  264. }
  265. func (na *SNetworkAddress) getGuest(ctx context.Context, userCred mcclient.TokenCredential) (*SGuest, error) {
  266. guestnetwork, err := na.getGuestnetwork(ctx, userCred)
  267. if err != nil {
  268. return nil, err
  269. }
  270. guest := guestnetwork.GetGuest()
  271. if guest != nil {
  272. return guest, nil
  273. }
  274. return nil, errors.Wrapf(errors.ErrNotFound, "getGuest: guestnetwork guest_id %s", guestnetwork.GuestId)
  275. }
  276. func (na *SNetworkAddress) getIVM(ctx context.Context, userCred mcclient.TokenCredential) (cloudprovider.ICloudVM, error) {
  277. guest, err := na.getGuest(ctx, userCred)
  278. if err != nil {
  279. return nil, err
  280. }
  281. if guest.ExternalId == "" {
  282. return nil, errors.Errorf("getIVM: guest %s(%s) has empty external_id", guest.Name, guest.Id)
  283. }
  284. ivm, err := guest.GetIVM(ctx)
  285. if err != nil {
  286. return nil, err
  287. }
  288. return ivm, nil
  289. }
  290. func (na *SNetworkAddress) getICloudNic(ctx context.Context, userCred mcclient.TokenCredential) (cloudprovider.ICloudNic, error) {
  291. guestnetwork, err := na.getGuestnetwork(ctx, userCred)
  292. if err != nil {
  293. return nil, err
  294. }
  295. iVM, err := na.getIVM(ctx, userCred)
  296. if err != nil {
  297. return nil, err
  298. }
  299. iNics, err := iVM.GetINics()
  300. if err != nil {
  301. return nil, err
  302. }
  303. for _, iNic := range iNics {
  304. if iNic.GetIP() == guestnetwork.IpAddr && iNic.GetMAC() == guestnetwork.MacAddr {
  305. return iNic, nil
  306. }
  307. }
  308. return nil, errors.Wrapf(errors.ErrNotFound, "getICloudNic: no cloud nic with ip %s, mac %s", guestnetwork.IpAddr, guestnetwork.MacAddr)
  309. }
  310. /*func (na *SNetworkAddress) remoteAssignAddress(ctx context.Context, userCred mcclient.TokenCredential) error {
  311. if na.ParentType == api.NetworkAddressParentTypeGuestnetwork {
  312. guest, err := na.getGuest(ctx, userCred)
  313. if err != nil {
  314. return err
  315. }
  316. if guest.ExternalId != "" {
  317. iNic, err := na.getICloudNic(ctx, userCred)
  318. if err != nil {
  319. return err
  320. }
  321. if err := iNic.AssignAddress([]string{na.IpAddr}); err != nil {
  322. if errors.Cause(err) == cloudprovider.ErrAddressCountExceed {
  323. return httperrors.NewNotAcceptableError("exceed address count limit: %v", err)
  324. }
  325. return err
  326. }
  327. } else {
  328. NetworkAddressManager.submitGuestSyncTask(ctx, userCred, guest)
  329. }
  330. }
  331. return nil
  332. }*/
  333. func (na *SNetworkAddress) remoteUnassignAddress(ctx context.Context, userCred mcclient.TokenCredential) error {
  334. if na.ParentType == api.NetworkAddressParentTypeGuestnetwork {
  335. guest, err := na.getGuest(ctx, userCred)
  336. if err != nil {
  337. if errors.Cause(err) == errors.ErrNotFound {
  338. return nil
  339. }
  340. return err
  341. }
  342. if guest.ExternalId != "" {
  343. iNic, err := na.getICloudNic(ctx, userCred)
  344. if err != nil {
  345. if errors.Cause(err) == errors.ErrNotFound {
  346. return nil
  347. }
  348. return err
  349. }
  350. if err := iNic.UnassignAddress([]string{na.IpAddr}); err != nil {
  351. return err
  352. }
  353. } else {
  354. NetworkAddressManager.submitGuestSyncTask(ctx, userCred, guest)
  355. }
  356. }
  357. return nil
  358. }
  359. func (na *SNetworkAddress) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
  360. if err := na.remoteUnassignAddress(ctx, userCred); err != nil {
  361. return err
  362. }
  363. return nil
  364. }
  365. func (man *SNetworkAddressManager) ListItemExportKeys(ctx context.Context,
  366. q *sqlchemy.SQuery,
  367. userCred mcclient.TokenCredential,
  368. keys stringutils2.SSortedStrings,
  369. ) (*sqlchemy.SQuery, error) {
  370. return db.ApplyListItemExportKeys(ctx, q, userCred, keys,
  371. &man.SStandaloneAnonResourceBaseManager,
  372. &man.SNetworkResourceBaseManager,
  373. )
  374. }
  375. func (man *SNetworkAddressManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
  376. return db.ApplyQueryDistinctExtraField(q, field,
  377. &man.SStandaloneAnonResourceBaseManager,
  378. &man.SNetworkResourceBaseManager,
  379. )
  380. }
  381. func (man *SNetworkAddressManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, input api.NetworkAddressListInput) (*sqlchemy.SQuery, error) {
  382. var err error
  383. q, err = man.SStandaloneAnonResourceBaseManager.ListItemFilter(ctx, q, userCred, input.StandaloneAnonResourceListInput)
  384. if err != nil {
  385. return nil, errors.Wrap(err, "SStandaloneAnonResourceBaseManager.ListItemFilter")
  386. }
  387. q, err = man.SNetworkResourceBaseManager.ListItemFilter(ctx, q, userCred, input.NetworkFilterListInput)
  388. if err != nil {
  389. return nil, errors.Wrap(err, "SNetworkResourceBaseManager.ListItemFilter")
  390. }
  391. if len(input.GuestId) > 0 {
  392. gnq := GuestnetworkManager.Query().SubQuery()
  393. gq := GuestManager.Query().
  394. In("id", input.GuestId).
  395. SubQuery()
  396. idq := man.Query("id").
  397. Equals("parent_type", api.NetworkAddressParentTypeGuestnetwork)
  398. idq = idq.Join(gnq, sqlchemy.Equals(gnq.Field("row_id"), idq.Field("parent_id")))
  399. idq = idq.Join(gq, sqlchemy.Equals(gq.Field("id"), gnq.Field("guest_id")))
  400. q = q.In("id", idq.SubQuery())
  401. }
  402. q, err = managedResourceFilterByAccount(
  403. ctx,
  404. q, input.ManagedResourceListInput, "network_id", func() *sqlchemy.SQuery {
  405. networks := NetworkManager.Query()
  406. wires := WireManager.Query("id", "vpc_id", "manager_id").SubQuery()
  407. vpcs := VpcManager.Query("id", "manager_id").SubQuery()
  408. networks = networks.Join(wires, sqlchemy.Equals(wires.Field("id"), networks.Field("wire_id")))
  409. networks = networks.Join(vpcs, sqlchemy.Equals(vpcs.Field("id"), wires.Field("vpc_id")))
  410. networks = networks.AppendField(networks.Field("id"))
  411. networks = networks.AppendField(sqlchemy.NewFunction(sqlchemy.NewCase().When(sqlchemy.IsNullOrEmpty(wires.Field("manager_id")), vpcs.Field("manager_id")).Else(wires.Field("manager_id")), "manager_id", false))
  412. subq := networks.SubQuery().Query()
  413. subq = subq.AppendField(subq.Field("id"))
  414. return subq
  415. })
  416. if err != nil {
  417. return nil, errors.Wrap(err, "ManagedResourceFilterByAccount")
  418. }
  419. return q, nil
  420. }
  421. func (man *SNetworkAddressManager) OrderByExtraFields(
  422. ctx context.Context,
  423. q *sqlchemy.SQuery,
  424. userCred mcclient.TokenCredential,
  425. query api.NetworkAddressListInput,
  426. ) (*sqlchemy.SQuery, error) {
  427. var err error
  428. q, err = man.SNetworkResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.NetworkFilterListInput)
  429. if err != nil {
  430. return nil, err
  431. }
  432. q, err = man.SStandaloneAnonResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StandaloneAnonResourceListInput)
  433. if err != nil {
  434. return nil, err
  435. }
  436. return q, nil
  437. }
  438. func (man *SNetworkAddressManager) FetchCustomizeColumns(
  439. ctx context.Context,
  440. userCred mcclient.TokenCredential,
  441. query jsonutils.JSONObject,
  442. objs []interface{},
  443. fields stringutils2.SSortedStrings,
  444. isList bool,
  445. ) []api.NetworkAddressDetails {
  446. ret := make([]api.NetworkAddressDetails, len(objs))
  447. netCols := man.SNetworkResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  448. for i := range netCols {
  449. ret[i].NetworkResourceInfo = netCols[i]
  450. }
  451. stdaCols := man.SStandaloneAnonResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  452. for i := range stdaCols {
  453. ret[i].StandaloneAnonResourceDetails = stdaCols[i]
  454. }
  455. {
  456. guestnetworkRowIds := make([]int64, 0, len(objs))
  457. for i := range objs {
  458. na := objs[i].(*SNetworkAddress)
  459. if na.ParentType == api.NetworkAddressParentTypeGuestnetwork {
  460. rowId, _ := strconv.ParseInt(na.ParentId, 10, 64)
  461. guestnetworkRowIds = append(guestnetworkRowIds, rowId)
  462. }
  463. }
  464. if len(guestnetworkRowIds) > 0 {
  465. gns, err := GuestnetworkManager.fetchByRowIds(ctx, userCred, guestnetworkRowIds)
  466. if err == nil && len(gns) > 0 {
  467. gnObjs := make([]interface{}, len(gns))
  468. for i := range gns {
  469. gnObjs[i] = &gns[i]
  470. }
  471. gnds := GuestnetworkManager.FetchCustomizeColumns(ctx, userCred, query, gnObjs, fields, isList)
  472. for i, j := 0, 0; i < len(objs); i++ {
  473. na := objs[i].(*SNetworkAddress)
  474. if na.ParentType == api.NetworkAddressParentTypeGuestnetwork {
  475. ret[i].Guestnetwork = gnds[j]
  476. j++
  477. }
  478. }
  479. }
  480. }
  481. }
  482. return ret
  483. }
  484. func (man *SNetworkAddressManager) FilterByOwner(ctx context.Context, q *sqlchemy.SQuery, manager db.FilterByOwnerProvider, userCred mcclient.TokenCredential, owner mcclient.IIdentityProvider, scope rbacscope.TRbacScope) *sqlchemy.SQuery {
  485. q = db.ApplyFilterByOwner(ctx, q, userCred, owner, scope,
  486. &man.SStandaloneAnonResourceBaseManager,
  487. )
  488. if owner != nil {
  489. var condVar, condVal string
  490. switch scope {
  491. case rbacscope.ScopeProject:
  492. condVar, condVal = "tenant_id", owner.GetProjectId()
  493. case rbacscope.ScopeDomain:
  494. condVar, condVal = "domain_id", owner.GetProjectDomainId()
  495. default:
  496. return q
  497. }
  498. {
  499. var (
  500. gnq = GuestnetworkManager.Query().SubQuery()
  501. gq = GuestManager.Query().SubQuery()
  502. naq = NetworkAddressManager.Query("id")
  503. )
  504. naq = naq.
  505. Join(gnq, sqlchemy.Equals(naq.Field("parent_id"), gnq.Field("row_id"))).
  506. Join(gq, sqlchemy.Equals(gnq.Field("guest_id"), gq.Field("id")))
  507. naq = naq.Equals("parent_type", api.NetworkAddressParentTypeGuestnetwork)
  508. naq = naq.Filter(sqlchemy.Equals(gq.Field(condVar), condVal))
  509. q = q.In("id", naq.SubQuery())
  510. }
  511. }
  512. return q
  513. }
  514. func (man *SNetworkAddressManager) submitGuestSyncTask(ctx context.Context, userCred mcclient.TokenCredential, guest *SGuest) {
  515. man.delayedWorkManager.Submit(ctx, delayedwork.DelayedWorkRequest{
  516. ID: guest.Id,
  517. SoftDelay: 2 * time.Second,
  518. HardDelay: 5 * time.Second,
  519. Func: func(ctx context.Context) {
  520. var (
  521. fwOnly = false
  522. parentTaskId = ""
  523. )
  524. err := guest.StartSyncTask(ctx, userCred, fwOnly, parentTaskId)
  525. if err != nil {
  526. log.Errorf("guest StartSyncTask: %v", err)
  527. }
  528. },
  529. })
  530. }
  531. func (g *SGuest) PerformUpdateSubIps(
  532. ctx context.Context,
  533. userCred mcclient.TokenCredential,
  534. query jsonutils.JSONObject,
  535. input api.GuestUpdateSubIpsInput,
  536. ) (jsonutils.JSONObject, error) {
  537. gn, err := g.findGuestnetworkByInfo(input.ServerNetworkInfo)
  538. if err != nil {
  539. return nil, errors.Wrapf(err, "getGuestnetworkByIpOrMac ip=%s mac=%s", input.IpAddr, input.Mac)
  540. }
  541. var iNic cloudprovider.ICloudNic
  542. if g.ExternalId != "" {
  543. // sync to cloud
  544. var err error
  545. iNic, err = g.getICloudNic(ctx, gn)
  546. if err != nil {
  547. return nil, errors.Wrap(err, "getICloudNic")
  548. }
  549. }
  550. errs := make([]error, 0)
  551. {
  552. err := NetworkAddressManager.removeGuestnetworkSubIPs(ctx, userCred, gn, input.RemoveSubIps)
  553. if err != nil {
  554. errs = append(errs, errors.Wrap(err, "removeGuestnetworkSubIPs"))
  555. }
  556. }
  557. addedIps, err := NetworkAddressManager.addGuestnetworkSubIPs(ctx, userCred, gn, input.GuestAddSubIpsInfo)
  558. if err != nil {
  559. errs = append(errs, errors.Wrap(err, "addGuestnetworkSubIPs"))
  560. }
  561. if g.ExternalId != "" {
  562. // sync to cloud
  563. if len(input.RemoveSubIps) > 0 {
  564. if err := iNic.UnassignAddress(addedIps); err != nil {
  565. errs = append(errs, errors.Wrapf(err, "UnassignAddress %s", addedIps))
  566. }
  567. }
  568. if len(addedIps) > 0 {
  569. if err := iNic.AssignAddress(addedIps); err != nil {
  570. if errors.Cause(err) == cloudprovider.ErrAddressCountExceed {
  571. errs = append(errs, httperrors.NewNotAcceptableError("exceed address count limit: %v", err))
  572. } else {
  573. errs = append(errs, errors.Wrapf(err, "AssignAddress %s", addedIps))
  574. }
  575. }
  576. }
  577. } else {
  578. NetworkAddressManager.submitGuestSyncTask(ctx, userCred, g)
  579. }
  580. if len(errs) > 0 {
  581. return nil, errors.NewAggregate(errs)
  582. }
  583. return nil, nil
  584. }
  585. func (g *SGuest) PerformAddSubIps(
  586. ctx context.Context,
  587. userCred mcclient.TokenCredential,
  588. query jsonutils.JSONObject,
  589. input api.GuestAddSubIpsInput,
  590. ) (jsonutils.JSONObject, error) {
  591. gn, err := g.findGuestnetworkByInfo(input.ServerNetworkInfo)
  592. if err != nil {
  593. return nil, errors.Wrapf(err, "getGuestnetworkByIpOrMac ip=%s mac=%s", input.IpAddr, input.Mac)
  594. }
  595. addedIps, err := NetworkAddressManager.addGuestnetworkSubIPs(ctx, userCred, gn, input.GuestAddSubIpsInfo)
  596. if err != nil {
  597. return nil, errors.Wrap(err, "addGuestnetworkSubIPs")
  598. }
  599. if g.ExternalId != "" && len(addedIps) > 0 {
  600. // sync to cloud
  601. iNic, err := g.getICloudNic(ctx, gn)
  602. if err != nil {
  603. return nil, errors.Wrap(err, "getICloudNic")
  604. }
  605. if err := iNic.AssignAddress(addedIps); err != nil {
  606. if errors.Cause(err) == cloudprovider.ErrAddressCountExceed {
  607. return nil, httperrors.NewNotAcceptableError("exceed address count limit: %v", err)
  608. }
  609. return nil, errors.Wrapf(err, "AssignAddress %s", addedIps)
  610. }
  611. } else {
  612. NetworkAddressManager.submitGuestSyncTask(ctx, userCred, g)
  613. }
  614. return nil, nil
  615. }
  616. func (g *SGuest) getICloudNic(ctx context.Context, gn *SGuestnetwork) (cloudprovider.ICloudNic, error) {
  617. ivm, err := g.GetIVM(ctx)
  618. if err != nil {
  619. return nil, errors.Wrap(err, "GetIVM")
  620. }
  621. iNics, err := ivm.GetINics()
  622. if err != nil {
  623. return nil, errors.Wrap(err, "GetINics %s")
  624. }
  625. for _, iNic := range iNics {
  626. if iNic.GetIP() == gn.IpAddr && iNic.GetMAC() == gn.MacAddr {
  627. return iNic, nil
  628. }
  629. }
  630. return nil, errors.Wrapf(errors.ErrNotFound, "no nic of ip %s mac %s", gn.IpAddr, gn.MacAddr)
  631. }
  632. func (manager *SNetworkAddressManager) fetchSubIpsQuery(parentType api.TNetworkAddressParentType) *sqlchemy.SQuery {
  633. subIPQ := manager.Query("parent_id").Equals("parent_type", string(parentType))
  634. subIPQ = subIPQ.AppendField(sqlchemy.GROUP_CONCAT("sub_ips", subIPQ.Field("ip_addr")))
  635. subIPQ = subIPQ.GroupBy(subIPQ.Field("parent_id"))
  636. return subIPQ
  637. }
  638. func (manager *SNetworkAddressManager) cleanDeletedGuestnetworkSubIPs() error {
  639. ctx := ctxutils.CtxWithTime()
  640. userCred := auth.AdminCredential()
  641. gnQ := GuestnetworkManager.Query("row_id").SubQuery()
  642. q := manager.Query().Equals("parent_type", api.NetworkAddressParentTypeGuestnetwork)
  643. q = q.LeftJoin(gnQ, sqlchemy.Equals(q.Field("parent_id"), gnQ.Field("row_id")))
  644. q = q.Filter(sqlchemy.IsNull(gnQ.Field("row_id")))
  645. netaddrs := make([]SNetworkAddress, 0)
  646. err := db.FetchModelObjects(manager, q, &netaddrs)
  647. if err != nil {
  648. return errors.Wrapf(err, "FetchModelObjects")
  649. }
  650. for i := range netaddrs {
  651. na := &netaddrs[i]
  652. if err := db.DeleteModel(ctx, userCred, na); err != nil {
  653. return errors.Wrapf(err, "DeleteModel")
  654. }
  655. }
  656. return nil
  657. }