dnszones.go 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750
  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. "strings"
  19. "yunion.io/x/cloudmux/pkg/cloudprovider"
  20. "yunion.io/x/jsonutils"
  21. "yunion.io/x/log"
  22. "yunion.io/x/pkg/errors"
  23. "yunion.io/x/pkg/gotypes"
  24. "yunion.io/x/pkg/tristate"
  25. "yunion.io/x/pkg/util/compare"
  26. "yunion.io/x/pkg/util/rbacscope"
  27. "yunion.io/x/pkg/util/regutils"
  28. "yunion.io/x/pkg/utils"
  29. "yunion.io/x/sqlchemy"
  30. "yunion.io/x/onecloud/pkg/apis"
  31. api "yunion.io/x/onecloud/pkg/apis/compute"
  32. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  33. "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
  34. "yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
  35. "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
  36. "yunion.io/x/onecloud/pkg/cloudcommon/validators"
  37. "yunion.io/x/onecloud/pkg/httperrors"
  38. "yunion.io/x/onecloud/pkg/mcclient"
  39. "yunion.io/x/onecloud/pkg/util/stringutils2"
  40. )
  41. type SDnsZoneManager struct {
  42. db.SSharableVirtualResourceBaseManager
  43. db.SEnabledResourceBaseManager
  44. db.SExternalizedResourceBaseManager
  45. SManagedResourceBaseManager
  46. }
  47. var DnsZoneManager *SDnsZoneManager
  48. func init() {
  49. DnsZoneManager = &SDnsZoneManager{
  50. SSharableVirtualResourceBaseManager: db.NewSharableVirtualResourceBaseManager(
  51. SDnsZone{},
  52. "dnszones_tbl",
  53. "dns_zone",
  54. "dns_zones",
  55. ),
  56. }
  57. DnsZoneManager.SetVirtualObject(DnsZoneManager)
  58. }
  59. type SDnsZone struct {
  60. db.SSharableVirtualResourceBase
  61. db.SEnabledResourceBase `default:"true" create:"optional" list:"user"`
  62. db.SExternalizedResourceBase
  63. SManagedResourceBase
  64. NameServers *api.SNameServers `width:"256" charset:"utf8" nullable:"true" list:"user" create:"optional"`
  65. OriginalNameServers *api.SNameServers `width:"256" charset:"utf8" nullable:"true" list:"user" create:"optional"`
  66. ZoneType string `width:"32" charset:"ascii" nullable:"false" list:"domain" create:"domain_required"`
  67. Registrar string `width:"32" charset:"utf8" nullable:"true" list:"domain" create:"domain_optional"`
  68. ProductType string `width:"32" charset:"ascii" nullable:"false" list:"domain" create:"domain_optional"`
  69. }
  70. func (self *SDnsZone) GetUniqValues() jsonutils.JSONObject {
  71. return jsonutils.Marshal(map[string]string{"manager_id": self.ManagerId})
  72. }
  73. func (manager *SDnsZoneManager) FetchUniqValues(ctx context.Context, data jsonutils.JSONObject) jsonutils.JSONObject {
  74. managerId, _ := data.GetString("manager_id")
  75. return jsonutils.Marshal(map[string]string{"manager_id": managerId})
  76. }
  77. func (manager *SDnsZoneManager) FilterByUniqValues(q *sqlchemy.SQuery, values jsonutils.JSONObject) *sqlchemy.SQuery {
  78. managerId, _ := values.GetString("manager_id")
  79. if len(managerId) > 0 {
  80. q = q.Equals("manager_id", managerId)
  81. } else {
  82. q = q.IsNullOrEmpty("manager_id")
  83. }
  84. return q
  85. }
  86. // 创建
  87. func (manager *SDnsZoneManager) ValidateCreateData(
  88. ctx context.Context,
  89. userCred mcclient.TokenCredential,
  90. ownerId mcclient.IIdentityProvider,
  91. query jsonutils.JSONObject,
  92. input *api.DnsZoneCreateInput,
  93. ) (*api.DnsZoneCreateInput, error) {
  94. var err error
  95. input.SharableVirtualResourceCreateInput, err = manager.SSharableVirtualResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.SharableVirtualResourceCreateInput)
  96. if err != nil {
  97. return nil, err
  98. }
  99. if !regutils.MatchDomainName(input.Name) {
  100. return nil, httperrors.NewInputParameterError("invalid domain name %s", input.Name)
  101. }
  102. if len(input.ZoneType) == 0 {
  103. return nil, httperrors.NewMissingParameterError("zone_type")
  104. }
  105. var provider *SCloudprovider = nil
  106. if len(input.CloudproviderId) > 0 {
  107. providerObj, err := validators.ValidateModel(ctx, userCred, CloudproviderManager, &input.CloudproviderId)
  108. if err != nil {
  109. return nil, err
  110. }
  111. provider = providerObj.(*SCloudprovider)
  112. input.ManagerId = provider.Id
  113. input.CloudproviderId = provider.Id
  114. }
  115. switch cloudprovider.TDnsZoneType(input.ZoneType) {
  116. case cloudprovider.PrivateZone:
  117. vpcIds := []string{}
  118. for i := range input.VpcIds {
  119. vpcObj, err := validators.ValidateModel(ctx, userCred, VpcManager, &input.VpcIds[i])
  120. if err != nil {
  121. return input, err
  122. }
  123. vpc := vpcObj.(*SVpc)
  124. if len(input.ManagerId) == 0 {
  125. input.ManagerId = vpc.ManagerId
  126. input.CloudproviderId = vpc.ManagerId
  127. }
  128. if vpc.ManagerId != input.ManagerId {
  129. return nil, httperrors.NewConflictError("conflict cloudprovider %s with vpc %s", input.ManagerId, vpc.Name)
  130. }
  131. if len(vpc.ManagerId) > 0 {
  132. factory, err := vpc.GetProviderFactory()
  133. if err != nil {
  134. return input, errors.Wrapf(err, "vpc.GetProviderFactory")
  135. }
  136. zoneTypes := factory.GetSupportedDnsZoneTypes()
  137. if isIn, _ := utils.InArray(cloudprovider.TDnsZoneType(input.ZoneType), zoneTypes); !isIn && len(zoneTypes) > 0 {
  138. return input, httperrors.NewNotSupportedError("Not support %s for vpc %s, supported %s", input.ZoneType, vpc.Name, zoneTypes)
  139. }
  140. }
  141. vpcIds = append(vpcIds, vpc.GetId())
  142. }
  143. input.VpcIds = vpcIds
  144. case cloudprovider.PublicZone:
  145. if len(input.CloudproviderId) == 0 {
  146. return nil, httperrors.NewMissingParameterError("cloudprovider_id")
  147. }
  148. input.ManagerId = provider.Id
  149. factory, err := provider.GetProviderFactory()
  150. if err != nil {
  151. return input, httperrors.NewGeneralError(errors.Wrapf(err, "GetProviderFactory"))
  152. }
  153. zoneTypes := factory.GetSupportedDnsZoneTypes()
  154. if isIn, _ := utils.InArray(cloudprovider.TDnsZoneType(input.ZoneType), zoneTypes); !isIn && len(zoneTypes) > 0 {
  155. return input, httperrors.NewNotSupportedError("Not support %s for account %s, supported %s", input.ZoneType, provider.Name, zoneTypes)
  156. }
  157. if !strings.ContainsRune(input.Name, '.') {
  158. return input, httperrors.NewNotSupportedError("top level public domain name %s not support", input.Name)
  159. }
  160. default:
  161. return input, httperrors.NewInputParameterError("unknown zone type %s", input.ZoneType)
  162. }
  163. if !gotypes.IsNil(provider) {
  164. switch provider.Provider {
  165. case api.CLOUD_PROVIDER_AWS:
  166. if len(input.VpcIds) == 0 && input.ZoneType == string(cloudprovider.PrivateZone) {
  167. return nil, httperrors.NewMissingParameterError("vpc_ids")
  168. }
  169. }
  170. }
  171. quota := &SDomainQuota{
  172. SBaseDomainQuotaKeys: quotas.SBaseDomainQuotaKeys{
  173. DomainId: ownerId.GetProjectDomainId(),
  174. },
  175. DnsZone: 1,
  176. }
  177. err = quotas.CheckSetPendingQuota(ctx, userCred, quota)
  178. if err != nil {
  179. return input, httperrors.NewOutOfQuotaError("%v", err)
  180. }
  181. return input, nil
  182. }
  183. func (self *SDnsZone) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
  184. quota := &SDomainQuota{
  185. SBaseDomainQuotaKeys: quotas.SBaseDomainQuotaKeys{
  186. DomainId: ownerId.GetProjectDomainId(),
  187. },
  188. DnsZone: 1,
  189. }
  190. err := quotas.CancelPendingUsage(ctx, userCred, quota, quota, true)
  191. if err != nil {
  192. log.Errorf("SDnsZone CancelPendingUsage fail %s", err)
  193. }
  194. self.SSharableVirtualResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
  195. input := &api.DnsZoneCreateInput{}
  196. data.Unmarshal(input)
  197. switch cloudprovider.TDnsZoneType(input.ZoneType) {
  198. case cloudprovider.PrivateZone:
  199. for _, vpcId := range input.VpcIds {
  200. self.AddVpc(ctx, vpcId)
  201. }
  202. }
  203. self.StartDnsZoneCreateTask(ctx, userCred, "")
  204. }
  205. func (self *SDnsZone) StartDnsZoneCreateTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
  206. params := jsonutils.NewDict()
  207. task, err := taskman.TaskManager.NewTask(ctx, "DnsZoneCreateTask", self, userCred, params, parentTaskId, "", nil)
  208. if err != nil {
  209. return errors.Wrap(err, "NewTask")
  210. }
  211. self.SetStatus(ctx, userCred, api.DNS_ZONE_STATUS_CREATING, "")
  212. return task.ScheduleRun(nil)
  213. }
  214. // 列表
  215. func (manager *SDnsZoneManager) ListItemFilter(
  216. ctx context.Context,
  217. q *sqlchemy.SQuery,
  218. userCred mcclient.TokenCredential,
  219. query api.DnsZoneListInput,
  220. ) (*sqlchemy.SQuery, error) {
  221. var err error
  222. q, err = manager.SSharableVirtualResourceBaseManager.ListItemFilter(ctx, q, userCred, query.SharableVirtualResourceListInput)
  223. if err != nil {
  224. return nil, err
  225. }
  226. q, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ManagedResourceListInput)
  227. if err != nil {
  228. return nil, err
  229. }
  230. if len(query.ZoneType) > 0 {
  231. q = q.Equals("zone_type", query.ZoneType)
  232. }
  233. if len(query.VpcId) > 0 {
  234. vpc, err := VpcManager.FetchByIdOrName(ctx, userCred, query.VpcId)
  235. if err != nil {
  236. if errors.Cause(err) == sql.ErrNoRows {
  237. return nil, httperrors.NewResourceNotFoundError2("vpc", query.VpcId)
  238. }
  239. return nil, httperrors.NewGeneralError(errors.Wrapf(err, "VpcManager.FetchByIdOrName"))
  240. }
  241. sq := DnsZoneVpcManager.Query("dns_zone_id").Equals("vpc_id", vpc.GetId())
  242. q = q.In("id", sq.SubQuery())
  243. }
  244. return q, nil
  245. }
  246. // 解析详情
  247. func (manager *SDnsZoneManager) FetchCustomizeColumns(
  248. ctx context.Context,
  249. userCred mcclient.TokenCredential,
  250. query jsonutils.JSONObject,
  251. objs []interface{},
  252. fields stringutils2.SSortedStrings,
  253. isList bool,
  254. ) []api.DnsZoneDetails {
  255. rows := make([]api.DnsZoneDetails, len(objs))
  256. enRows := manager.SSharableVirtualResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  257. managerRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  258. zoneIds := make([]string, len(objs))
  259. for i := range rows {
  260. rows[i] = api.DnsZoneDetails{
  261. SharableVirtualResourceDetails: enRows[i],
  262. ManagedResourceInfo: managerRows[i],
  263. }
  264. zone := objs[i].(*SDnsZone)
  265. zoneIds[i] = zone.Id
  266. }
  267. q := DnsZoneVpcManager.Query().In("dns_zone_id", zoneIds)
  268. vpcs := []SDnsZoneVpc{}
  269. err := q.All(&vpcs)
  270. if err != nil {
  271. log.Errorf("query dns zone vpcs error: %v", err)
  272. return rows
  273. }
  274. vpcMap := map[string][]string{}
  275. for i := range vpcs {
  276. _, ok := vpcMap[vpcs[i].DnsZoneId]
  277. if !ok {
  278. vpcMap[vpcs[i].DnsZoneId] = []string{}
  279. }
  280. vpcMap[vpcs[i].DnsZoneId] = append(vpcMap[vpcs[i].DnsZoneId], vpcs[i].VpcId)
  281. }
  282. q = DnsRecordManager.Query().In("dns_zone_id", zoneIds)
  283. records := []SDnsRecord{}
  284. err = q.All(&records)
  285. if err != nil {
  286. log.Errorf("query dns zone records error: %v", err)
  287. return rows
  288. }
  289. recordMap := map[string][]SDnsRecord{}
  290. for i := range records {
  291. _, ok := recordMap[records[i].DnsZoneId]
  292. if !ok {
  293. recordMap[records[i].DnsZoneId] = []SDnsRecord{}
  294. }
  295. recordMap[records[i].DnsZoneId] = append(recordMap[records[i].DnsZoneId], records[i])
  296. }
  297. for i := range rows {
  298. vpcs, _ := vpcMap[zoneIds[i]]
  299. rows[i].VpcCount = len(vpcs)
  300. records, _ := recordMap[zoneIds[i]]
  301. rows[i].DnsRecordCount = len(records)
  302. }
  303. return rows
  304. }
  305. func (self *SDnsZone) RemoveVpc(ctx context.Context, vpcId string) error {
  306. q := DnsZoneVpcManager.Query().Equals("dns_zone_id", self.Id).Equals("vpc_id", vpcId)
  307. zvs := []SDnsZoneVpc{}
  308. err := db.FetchModelObjects(DnsZoneVpcManager, q, &zvs)
  309. if err != nil {
  310. return errors.Wrapf(err, "db.FetchModelObjects")
  311. }
  312. for i := range zvs {
  313. err = zvs[i].Delete(ctx, nil)
  314. if err != nil {
  315. return errors.Wrap(err, "Delete")
  316. }
  317. }
  318. return nil
  319. }
  320. func (self *SDnsZone) AddVpc(ctx context.Context, vpcId string) error {
  321. zv := &SDnsZoneVpc{}
  322. zv.SetModelManager(DnsZoneVpcManager, zv)
  323. zv.VpcId = vpcId
  324. zv.DnsZoneId = self.Id
  325. return DnsZoneVpcManager.TableSpec().Insert(ctx, zv)
  326. }
  327. func (self *SDnsZone) GetVpcs() ([]SVpc, error) {
  328. sq := DnsZoneVpcManager.Query("vpc_id").Equals("dns_zone_id", self.Id)
  329. q := VpcManager.Query().In("id", sq.SubQuery())
  330. vpcs := []SVpc{}
  331. err := db.FetchModelObjects(VpcManager, q, &vpcs)
  332. if err != nil {
  333. return nil, errors.Wrapf(err, "db.FetchModelObjects")
  334. }
  335. return vpcs, nil
  336. }
  337. func (self *SDnsZone) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
  338. return self.StartDnsZoneDeleteTask(ctx, userCred, "")
  339. }
  340. func (self *SDnsZone) StartDnsZoneDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
  341. task, err := taskman.TaskManager.NewTask(ctx, "DnsZoneDeleteTask", self, userCred, nil, parentTaskId, "", nil)
  342. if err != nil {
  343. return errors.Wrap(err, "NewTask")
  344. }
  345. self.SetStatus(ctx, userCred, api.DNS_ZONE_STATUS_DELETING, "")
  346. return task.ScheduleRun(nil)
  347. }
  348. func (self *SDnsZone) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
  349. return nil
  350. }
  351. func (self *SDnsZone) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
  352. dnsVpcs := DnsZoneVpcManager.Query("row_id").Equals("dns_zone_id", self.Id)
  353. records := DnsRecordManager.Query("id").Equals("dns_zone_id", self.Id)
  354. pairs := []purgePair{
  355. {manager: DnsZoneVpcManager, key: "row_id", q: dnsVpcs},
  356. {manager: DnsRecordManager, key: "id", q: records},
  357. }
  358. for i := range pairs {
  359. err := pairs[i].purgeAll(ctx)
  360. if err != nil {
  361. return err
  362. }
  363. }
  364. return self.SSharableVirtualResourceBase.Delete(ctx, userCred)
  365. }
  366. func (self *SDnsZone) GetDetailsExports(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  367. records, err := self.GetDnsRecordSets()
  368. if err != nil {
  369. return nil, errors.Wrapf(err, "GetDnsRecordSets")
  370. }
  371. result := "$ORIGIN " + self.Name + ".\n"
  372. lines := []string{}
  373. for _, record := range records {
  374. lines = append(lines, record.ToZoneLine())
  375. }
  376. result += strings.Join(lines, "\n")
  377. rr := make(map[string]string)
  378. rr["zone"] = result
  379. return jsonutils.Marshal(rr), nil
  380. }
  381. func (self *SDnsZone) GetDnsRecordSets() ([]SDnsRecord, error) {
  382. records := []SDnsRecord{}
  383. q := DnsRecordManager.Query().Equals("dns_zone_id", self.Id)
  384. err := db.FetchModelObjects(DnsRecordManager, q, &records)
  385. if err != nil {
  386. return nil, errors.Wrapf(err, "db.FetchModelObjects")
  387. }
  388. return records, nil
  389. }
  390. func (self *SCloudprovider) GetDnsZones() ([]SDnsZone, error) {
  391. q := DnsZoneManager.Query().Equals("manager_id", self.Id)
  392. ret := []SDnsZone{}
  393. return ret, db.FetchModelObjects(DnsZoneManager, q, &ret)
  394. }
  395. func (self *SCloudprovider) SyncDnsZones(ctx context.Context, userCred mcclient.TokenCredential, zones []cloudprovider.ICloudDnsZone, xor bool) ([]SDnsZone, []cloudprovider.ICloudDnsZone, compare.SyncResult) {
  396. lockman.LockRawObject(ctx, DnsZoneManager.Keyword(), self.Id)
  397. defer lockman.ReleaseRawObject(ctx, DnsZoneManager.Keyword(), self.Id)
  398. local := make([]SDnsZone, 0)
  399. remote := make([]cloudprovider.ICloudDnsZone, 0)
  400. result := compare.SyncResult{}
  401. dbZones, err := self.GetDnsZones()
  402. if err != nil {
  403. result.Error(err)
  404. return nil, nil, result
  405. }
  406. removed := make([]SDnsZone, 0)
  407. commondb := make([]SDnsZone, 0)
  408. commonext := make([]cloudprovider.ICloudDnsZone, 0)
  409. added := make([]cloudprovider.ICloudDnsZone, 0)
  410. err = compare.CompareSets(dbZones, zones, &removed, &commondb, &commonext, &added)
  411. if err != nil {
  412. result.Error(err)
  413. return nil, nil, result
  414. }
  415. for i := 0; i < len(removed); i += 1 {
  416. err = removed[i].syncRemoveDnsZone(ctx, userCred)
  417. if err != nil {
  418. result.DeleteError(err)
  419. continue
  420. }
  421. result.Delete()
  422. }
  423. if !xor {
  424. for i := 0; i < len(commondb); i += 1 {
  425. err = commondb[i].SyncWithDnsZone(ctx, userCred, commonext[i])
  426. if err != nil {
  427. result.UpdateError(err)
  428. continue
  429. }
  430. local = append(local, commondb[i])
  431. remote = append(remote, commonext[i])
  432. result.Update()
  433. }
  434. }
  435. for i := 0; i < len(added); i += 1 {
  436. zone, err := self.newFromCloudDnsZone(ctx, userCred, added[i])
  437. if err != nil {
  438. result.AddError(err)
  439. continue
  440. }
  441. local = append(local, *zone)
  442. remote = append(remote, added[i])
  443. result.Add()
  444. }
  445. return local, remote, result
  446. }
  447. func (self *SDnsZone) syncRemoveDnsZone(ctx context.Context, userCred mcclient.TokenCredential) error {
  448. return self.RealDelete(ctx, userCred)
  449. }
  450. func (self *SDnsZone) GetProvider(ctx context.Context) (cloudprovider.ICloudProvider, error) {
  451. if len(self.ManagerId) == 0 {
  452. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty manager id")
  453. }
  454. provider := self.GetCloudprovider()
  455. if provider == nil {
  456. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "failed to found provider")
  457. }
  458. return provider.GetProvider(ctx)
  459. }
  460. func (self *SDnsZone) GetICloudDnsZone(ctx context.Context) (cloudprovider.ICloudDnsZone, error) {
  461. if len(self.ExternalId) == 0 {
  462. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty external id")
  463. }
  464. provider, err := self.GetProvider(ctx)
  465. if err != nil {
  466. return nil, err
  467. }
  468. return provider.GetICloudDnsZoneById(self.ExternalId)
  469. }
  470. func (self *SDnsZone) SyncWithDnsZone(ctx context.Context, userCred mcclient.TokenCredential, ext cloudprovider.ICloudDnsZone) error {
  471. _, err := db.Update(self, func() error {
  472. self.ExternalId = ext.GetGlobalId()
  473. self.Status = ext.GetStatus()
  474. self.ProductType = string(ext.GetDnsProductType())
  475. if v, err := ext.GetNameServers(); err == nil {
  476. ns := api.SNameServers{}
  477. ns = append(ns, v...)
  478. self.NameServers = &ns
  479. }
  480. if v, err := ext.GetOriginalNameServers(); err == nil {
  481. ns := api.SNameServers{}
  482. ns = append(ns, v...)
  483. self.OriginalNameServers = &ns
  484. }
  485. self.Registrar = ext.GetRegistrar()
  486. return nil
  487. })
  488. if err != nil {
  489. return err
  490. }
  491. provider := self.GetCloudprovider()
  492. if provider != nil {
  493. if account, _ := provider.GetCloudaccount(); account != nil {
  494. syncVirtualResourceMetadata(ctx, userCred, self, ext, account.ReadOnly)
  495. }
  496. SyncCloudProject(ctx, userCred, self, provider.GetOwnerId(), ext, provider)
  497. }
  498. return nil
  499. }
  500. func (self *SCloudprovider) newFromCloudDnsZone(ctx context.Context, userCred mcclient.TokenCredential, ext cloudprovider.ICloudDnsZone) (*SDnsZone, error) {
  501. zone := &SDnsZone{}
  502. zone.Name = ext.GetName()
  503. zone.ExternalId = ext.GetGlobalId()
  504. zone.ManagerId = self.Id
  505. zone.Status = ext.GetStatus()
  506. zone.Enabled = tristate.True
  507. zone.ZoneType = string(ext.GetZoneType())
  508. zone.ProductType = string(ext.GetDnsProductType())
  509. if v, err := ext.GetNameServers(); err == nil {
  510. ns := api.SNameServers{}
  511. ns = append(ns, v...)
  512. zone.NameServers = &ns
  513. }
  514. if v, err := ext.GetOriginalNameServers(); err == nil {
  515. ns := api.SNameServers{}
  516. ns = append(ns, v...)
  517. zone.OriginalNameServers = &ns
  518. }
  519. zone.Registrar = ext.GetRegistrar()
  520. zone.SetModelManager(DnsZoneManager, zone)
  521. err := DnsZoneManager.TableSpec().Insert(ctx, zone)
  522. if err != nil {
  523. return nil, errors.Wrapf(err, "Insert")
  524. }
  525. syncVirtualResourceMetadata(ctx, userCred, zone, ext, false)
  526. SyncCloudProject(ctx, userCred, zone, self.GetOwnerId(), ext, self)
  527. return zone, nil
  528. }
  529. func (self *SDnsZone) GetDnsRecords() ([]SDnsRecord, error) {
  530. q := DnsRecordManager.Query().Equals("dns_zone_id", self.Id)
  531. ret := []SDnsRecord{}
  532. return ret, db.FetchModelObjects(DnsRecordManager, q, &ret)
  533. }
  534. // 同步状态
  535. func (self *SDnsZone) PerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.DnsZoneSyncStatusInput) (jsonutils.JSONObject, error) {
  536. return nil, StartResourceSyncStatusTask(ctx, userCred, self, "DnsZoneSyncstatusTask", "")
  537. }
  538. // 添加VPC
  539. func (self *SDnsZone) PerformAddVpcs(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.DnsZoneAddVpcsInput) (jsonutils.JSONObject, error) {
  540. if self.Status != api.DNS_ZONE_STATUS_AVAILABLE {
  541. return nil, httperrors.NewInvalidStatusError("dns zone can not uncache in status %s", self.Status)
  542. }
  543. if cloudprovider.TDnsZoneType(self.ZoneType) != cloudprovider.PrivateZone {
  544. return nil, httperrors.NewUnsupportOperationError("Only %s support cache for account", cloudprovider.PrivateZone)
  545. }
  546. vpcs, err := self.GetVpcs()
  547. if err != nil {
  548. return nil, httperrors.NewGeneralError(errors.Wrapf(err, "GetVpcs"))
  549. }
  550. localVpcIds := []string{}
  551. for _, vpc := range vpcs {
  552. localVpcIds = append(localVpcIds, vpc.Id)
  553. }
  554. if len(input.VpcIds) == 0 {
  555. return nil, httperrors.NewMissingParameterError("vpc_ids")
  556. }
  557. for i := range input.VpcIds {
  558. vpcObj, err := validators.ValidateModel(ctx, userCred, VpcManager, &input.VpcIds[i])
  559. if err != nil {
  560. return nil, err
  561. }
  562. vpc := vpcObj.(*SVpc)
  563. if utils.IsInStringArray(vpc.GetId(), localVpcIds) {
  564. return nil, httperrors.NewConflictError("vpc %s has already in this dns zone", input.VpcIds[i])
  565. }
  566. if vpc.ManagerId != self.ManagerId {
  567. return nil, httperrors.NewConflictError("vpc %s not same with dns zone account", input.VpcIds[i])
  568. }
  569. }
  570. return nil, self.StartDnsZoneAddVpcsTask(ctx, userCred, input.VpcIds, "")
  571. }
  572. func (self *SDnsZone) StartDnsZoneAddVpcsTask(ctx context.Context, userCred mcclient.TokenCredential, vpcIds []string, parentTaskId string) error {
  573. params := jsonutils.NewDict()
  574. params.Set("vpc_ids", jsonutils.NewStringArray(vpcIds))
  575. task, err := taskman.TaskManager.NewTask(ctx, "DnsZoneAddVpcsTask", self, userCred, params, parentTaskId, "", nil)
  576. if err != nil {
  577. return errors.Wrap(err, "NewTask")
  578. }
  579. self.SetStatus(ctx, userCred, apis.STATUS_SYNC_STATUS, "")
  580. return task.ScheduleRun(nil)
  581. }
  582. func (self *SDnsZone) StartDnsZoneRemoveVpcsTask(ctx context.Context, userCred mcclient.TokenCredential, vpcIds []string, parentTaskId string) error {
  583. params := jsonutils.NewDict()
  584. params.Set("vpc_ids", jsonutils.NewStringArray(vpcIds))
  585. task, err := taskman.TaskManager.NewTask(ctx, "DnsZoneRemoveVpcsTask", self, userCred, params, parentTaskId, "", nil)
  586. if err != nil {
  587. return errors.Wrap(err, "NewTask")
  588. }
  589. self.SetStatus(ctx, userCred, apis.STATUS_SYNC_STATUS, "")
  590. return task.ScheduleRun(nil)
  591. }
  592. // 移除VPC
  593. func (self *SDnsZone) PerformRemoveVpcs(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.DnsZoneRemoveVpcsInput) (jsonutils.JSONObject, error) {
  594. if self.Status != api.DNS_ZONE_STATUS_AVAILABLE {
  595. return nil, httperrors.NewInvalidStatusError("dns zone can not uncache in status %s", self.Status)
  596. }
  597. if cloudprovider.TDnsZoneType(self.ZoneType) != cloudprovider.PrivateZone {
  598. return nil, httperrors.NewUnsupportOperationError("Only %s support cache for account", cloudprovider.PrivateZone)
  599. }
  600. vpcs, err := self.GetVpcs()
  601. if err != nil {
  602. return nil, httperrors.NewGeneralError(errors.Wrapf(err, "GetVpcs"))
  603. }
  604. vpcIds := []string{}
  605. for _, vpc := range vpcs {
  606. vpcIds = append(vpcIds, vpc.Id)
  607. }
  608. for _, vpcId := range input.VpcIds {
  609. if !utils.IsInStringArray(vpcId, vpcIds) {
  610. return nil, httperrors.NewResourceNotFoundError("vpc %s not in dns zone", vpcId)
  611. }
  612. }
  613. return nil, self.StartDnsZoneRemoveVpcsTask(ctx, userCred, input.VpcIds, "")
  614. }
  615. func (manager *SDnsZoneManager) GetPropertyCapability(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  616. return jsonutils.Marshal(cloudprovider.GetDnsCapabilities()), nil
  617. }
  618. func (self *SDnsZone) PerformPurge(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.DnsZonePurgeInput) (jsonutils.JSONObject, error) {
  619. return nil, self.RealDelete(ctx, userCred)
  620. }
  621. func (manager *SDnsZoneManager) totalCount(scope rbacscope.TRbacScope, ownerId mcclient.IIdentityProvider) int {
  622. q := manager.Query()
  623. switch scope {
  624. case rbacscope.ScopeProject, rbacscope.ScopeDomain:
  625. q = q.Equals("domain_id", ownerId.GetProjectDomainId())
  626. }
  627. cnt, _ := q.CountWithError()
  628. return cnt
  629. }
  630. func (dzone *SDnsZone) GetUsages() []db.IUsage {
  631. if dzone.Deleted {
  632. return nil
  633. }
  634. usage := SDomainQuota{DnsZone: 1}
  635. usage.SetKeys(quotas.SBaseDomainQuotaKeys{DomainId: dzone.DomainId})
  636. return []db.IUsage{
  637. &usage,
  638. }
  639. }
  640. func (manager *SDnsZoneManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
  641. var err error
  642. q, err = manager.SSharableVirtualResourceBaseManager.QueryDistinctExtraField(q, field)
  643. if err == nil {
  644. return q, nil
  645. }
  646. q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraField(q, field)
  647. if err == nil {
  648. return q, nil
  649. }
  650. return q, httperrors.ErrNotFound
  651. }
  652. func (manager *SDnsZoneManager) QueryDistinctExtraFields(q *sqlchemy.SQuery, resource string, fields []string) (*sqlchemy.SQuery, error) {
  653. var err error
  654. q, err = manager.SManagedResourceBaseManager.QueryDistinctExtraFields(q, resource, fields)
  655. if err == nil {
  656. return q, nil
  657. }
  658. return q, httperrors.ErrNotFound
  659. }
  660. func (manager *SDnsZoneManager) OrderByExtraFields(
  661. ctx context.Context,
  662. q *sqlchemy.SQuery,
  663. userCred mcclient.TokenCredential,
  664. query api.DnsZoneListInput,
  665. ) (*sqlchemy.SQuery, error) {
  666. var err error
  667. q, err = manager.SSharableVirtualResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.SharableVirtualResourceListInput)
  668. if err != nil {
  669. return nil, errors.Wrap(err, "SSharableVirtualResourceBaseManager.OrderByExtraFields")
  670. }
  671. return q, nil
  672. }