domains.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696
  1. // Copyright 2019 Yunion
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. package models
  15. import (
  16. "context"
  17. "database/sql"
  18. "fmt"
  19. "time"
  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/rbacscope"
  26. "yunion.io/x/pkg/util/timeutils"
  27. "yunion.io/x/pkg/utils"
  28. "yunion.io/x/sqlchemy"
  29. api "yunion.io/x/onecloud/pkg/apis/identity"
  30. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  31. "yunion.io/x/onecloud/pkg/httperrors"
  32. "yunion.io/x/onecloud/pkg/keystone/options"
  33. "yunion.io/x/onecloud/pkg/mcclient"
  34. "yunion.io/x/onecloud/pkg/util/logclient"
  35. "yunion.io/x/onecloud/pkg/util/stringutils2"
  36. "yunion.io/x/onecloud/pkg/util/tagutils"
  37. )
  38. type SDomainManager struct {
  39. db.SStandaloneResourceBaseManager
  40. db.SPendingDeletedBaseManager
  41. }
  42. var (
  43. DomainManager *SDomainManager
  44. )
  45. func init() {
  46. DomainManager = &SDomainManager{
  47. SStandaloneResourceBaseManager: db.NewStandaloneResourceBaseManager(
  48. SDomain{},
  49. "project",
  50. "domain",
  51. "domains",
  52. ),
  53. }
  54. DomainManager.SetVirtualObject(DomainManager)
  55. }
  56. type SDomain struct {
  57. db.SStandaloneResourceBase
  58. db.SPendingDeletedBase
  59. // 额外信息
  60. Extra *jsonutils.JSONDict `nullable:"true"`
  61. // 改域是否启用
  62. Enabled tristate.TriState `default:"true" list:"admin" update:"admin" create:"admin_optional"`
  63. // 是否为域
  64. IsDomain tristate.TriState `default:"false"`
  65. // IdpId string `token:"parent_id" width:"64" charset:"ascii" index:"true" list:"admin"`
  66. DomainId string `width:"64" charset:"ascii" default:"default" nullable:"false" index:"true"`
  67. ParentId string `width:"64" charset:"ascii"`
  68. AdminId string `width:"64" charset:"ascii" nullable:"true"`
  69. }
  70. func (manager *SDomainManager) InitializeData() error {
  71. root, err := manager.FetchDomainById(api.KeystoneDomainRoot)
  72. if err == sql.ErrNoRows {
  73. root = &SDomain{}
  74. root.Id = api.KeystoneDomainRoot
  75. root.Name = api.KeystoneDomainRoot
  76. root.IsDomain = tristate.True
  77. // root.ParentId = api.KeystoneDomainRoot
  78. root.DomainId = api.KeystoneDomainRoot
  79. root.Enabled = tristate.False
  80. root.Description = "The hidden root domain"
  81. err := manager.TableSpec().Insert(context.TODO(), root)
  82. if err != nil {
  83. log.Errorf("fail to insert root domain ... %s", err)
  84. return err
  85. }
  86. } else if err != nil {
  87. return err
  88. }
  89. defDomain, err := manager.FetchDomainById(api.DEFAULT_DOMAIN_ID)
  90. if err == sql.ErrNoRows {
  91. defDomain = &SDomain{}
  92. defDomain.Id = api.DEFAULT_DOMAIN_ID
  93. defDomain.Name = api.DEFAULT_DOMAIN_NAME
  94. defDomain.IsDomain = tristate.True
  95. // defDomain.ParentId = api.KeystoneDomainRoot
  96. defDomain.DomainId = api.KeystoneDomainRoot
  97. defDomain.Enabled = tristate.True
  98. defDomain.Description = "The default domain"
  99. err := manager.TableSpec().Insert(context.TODO(), defDomain)
  100. if err != nil {
  101. log.Errorf("fail to insert default domain ... %s", err)
  102. return err
  103. }
  104. } else if err != nil {
  105. return err
  106. }
  107. /*err = manager.initAdminUsers(context.TODO())
  108. if err != nil {
  109. return errors.Wrap(err, "initAdminUsers")
  110. }*/
  111. return nil
  112. }
  113. /*func (manager *SDomainManager) initAdminUsers(ctx context.Context) error {
  114. q := manager.Query().IsNullOrEmpty("admin_id")
  115. domains := make([]SDomain, 0)
  116. err := db.FetchModelObjects(manager, q, &domains)
  117. if err != nil {
  118. return errors.Wrap(err, "FetchModelObjects")
  119. }
  120. for i := range domains {
  121. err := domains[i].initAdminUser(ctx)
  122. if err != nil {
  123. return errors.Wrap(err, "domains initAdmin")
  124. }
  125. }
  126. return nil
  127. }*/
  128. func (manager *SDomainManager) NewQuery(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, useRawQuery bool) *sqlchemy.SQuery {
  129. return manager.Query()
  130. }
  131. func (manager *SDomainManager) Query(fields ...string) *sqlchemy.SQuery {
  132. return manager.SStandaloneResourceBaseManager.Query(fields...).IsTrue("is_domain")
  133. }
  134. func (manager *SDomainManager) FetchDomainByName(domainName string) (*SDomain, error) {
  135. obj, err := db.NewModelObject(manager)
  136. if err != nil {
  137. return nil, err
  138. }
  139. q := manager.Query().Equals("name", domainName).NotEquals("id", api.KeystoneDomainRoot)
  140. err = q.First(obj)
  141. if err != nil {
  142. return nil, err
  143. }
  144. return obj.(*SDomain), err
  145. }
  146. func (manager *SDomainManager) FetchDomainById(domainId string) (*SDomain, error) {
  147. obj, err := db.NewModelObject(manager)
  148. if err != nil {
  149. return nil, err
  150. }
  151. q := manager.Query().Equals("id", domainId)
  152. err = q.First(obj)
  153. if err != nil {
  154. return nil, err
  155. }
  156. return obj.(*SDomain), err
  157. }
  158. func (manager *SDomainManager) FetchDomain(domainId string, domainName string) (*SDomain, error) {
  159. if len(domainId) == 0 && len(domainName) == 0 {
  160. domainId = api.DEFAULT_DOMAIN_ID
  161. }
  162. if len(domainId) > 0 {
  163. return manager.FetchDomainById(domainId)
  164. } else {
  165. return manager.FetchDomainByName(domainName)
  166. }
  167. }
  168. func (manager *SDomainManager) FetchDomainByIdOrName(domain string) (*SDomain, error) {
  169. if stringutils2.IsUtf8(domain) {
  170. return manager.FetchDomainByName(domain)
  171. }
  172. obj, err := db.NewModelObject(manager)
  173. if err != nil {
  174. return nil, err
  175. }
  176. q := manager.Query().NotEquals("id", api.KeystoneDomainRoot)
  177. if stringutils2.IsUtf8(domain) {
  178. q = q.Equals("name", domain)
  179. } else {
  180. q = q.Filter(sqlchemy.OR(
  181. sqlchemy.Equals(q.Field("id"), domain),
  182. sqlchemy.Equals(q.Field("name"), domain),
  183. ))
  184. }
  185. err = q.First(obj)
  186. if err != nil {
  187. return nil, err
  188. }
  189. return obj.(*SDomain), err
  190. }
  191. // 域列表
  192. func (manager *SDomainManager) ListItemFilter(
  193. ctx context.Context,
  194. q *sqlchemy.SQuery,
  195. userCred mcclient.TokenCredential,
  196. query api.DomainListInput,
  197. ) (*sqlchemy.SQuery, error) {
  198. var err error
  199. q, err = manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput)
  200. if err != nil {
  201. return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter")
  202. }
  203. q = q.NotEquals("id", api.KeystoneDomainRoot)
  204. if !query.PolicyDomainTags.IsEmpty() {
  205. policyFilters := tagutils.STagFilters{}
  206. policyFilters.AddFilters(query.PolicyDomainTags)
  207. q = db.ObjectIdQueryWithTagFilters(ctx, q, "id", "domain", policyFilters)
  208. }
  209. if query.Enabled != nil {
  210. if *query.Enabled {
  211. q = q.IsTrue("enabled")
  212. } else {
  213. q = q.IsFalse("enabled")
  214. }
  215. }
  216. if len(query.IdpId) > 0 {
  217. idpObj, err := IdentityProviderManager.FetchByIdOrName(ctx, userCred, query.IdpId)
  218. if err != nil {
  219. if errors.Cause(err) == sql.ErrNoRows {
  220. return nil, errors.Wrapf(httperrors.ErrResourceNotFound, "%s %s", IdentityProviderManager.Keyword(), query.IdpId)
  221. } else {
  222. return nil, errors.Wrap(err, "IdentityProviderManager.FetchByIdOrName")
  223. }
  224. }
  225. subq := IdmappingManager.FetchPublicIdsExcludesQuery(idpObj.GetId(), api.IdMappingEntityDomain, nil)
  226. q = q.In("id", subq.SubQuery())
  227. }
  228. if len(query.IdpEntityId) > 0 {
  229. subq := IdmappingManager.Query("public_id").Equals("local_id", query.IdpEntityId).Equals("entity_type", api.IdMappingEntityDomain)
  230. q = q.Equals("id", subq.SubQuery())
  231. }
  232. return q, nil
  233. }
  234. func (manager *SDomainManager) OrderByExtraFields(
  235. ctx context.Context,
  236. q *sqlchemy.SQuery,
  237. userCred mcclient.TokenCredential,
  238. query api.DomainListInput,
  239. ) (*sqlchemy.SQuery, error) {
  240. var err error
  241. q, err = manager.SStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StandaloneResourceListInput)
  242. if err != nil {
  243. return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.OrderByExtraFields")
  244. }
  245. return q, nil
  246. }
  247. func (manager *SDomainManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
  248. var err error
  249. q, err = manager.SStandaloneResourceBaseManager.QueryDistinctExtraField(q, field)
  250. if err == nil {
  251. return q, nil
  252. }
  253. return q, httperrors.ErrNotFound
  254. }
  255. func (domain *SDomain) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
  256. // domain.ParentId = api.KeystoneDomainRoot
  257. domain.DomainId = api.KeystoneDomainRoot
  258. domain.IsDomain = tristate.True
  259. return domain.SStandaloneResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
  260. }
  261. func (domain *SDomain) GetProjectCount() (int, error) {
  262. q := ProjectManager.Query().Equals("domain_id", domain.Id)
  263. return q.CountWithError()
  264. }
  265. func (domain *SDomain) GetRoleCount() (int, error) {
  266. q := RoleManager.Query().Equals("domain_id", domain.Id)
  267. return q.CountWithError()
  268. }
  269. func (domain *SDomain) GetPolicyCount() (int, error) {
  270. q := PolicyManager.Query().Equals("domain_id", domain.Id)
  271. return q.CountWithError()
  272. }
  273. func (domain *SDomain) GetUserCount() (int, error) {
  274. q := UserManager.Query().Equals("domain_id", domain.Id)
  275. return q.CountWithError()
  276. }
  277. func (domain *SDomain) GetGroupCount() (int, error) {
  278. q := GroupManager.Query().Equals("domain_id", domain.Id)
  279. return q.CountWithError()
  280. }
  281. func (domain *SDomain) GetIdpCount() (int, error) {
  282. q := IdentityProviderManager.Query().Equals("target_domain_id", domain.Id)
  283. return q.CountWithError()
  284. }
  285. func (domain *SDomain) ValidateDeleteCondition(ctx context.Context, info *api.DomainDetails) error {
  286. return domain.validateDeleteConditionInternal(ctx, info, false)
  287. }
  288. func (domain *SDomain) validateDeleteConditionInternal(ctx context.Context, info *api.DomainDetails, skipIdpCheck bool) error {
  289. if gotypes.IsNil(info) {
  290. info = &api.DomainDetails{}
  291. if usage, _ := DomainManager.TotalResourceCount([]string{domain.Id}); usage != nil {
  292. info.DomainUsage, _ = usage[domain.Id]
  293. }
  294. idpInfo := expandIdpAttributes(api.IdMappingEntityDomain, []string{domain.Id}, stringutils2.SSortedStrings{})
  295. if len(idpInfo) > 0 {
  296. info.IdpResourceInfo = idpInfo[0]
  297. }
  298. }
  299. if !skipIdpCheck && len(info.IdpId) > 0 {
  300. return httperrors.NewForbiddenError("readonly")
  301. }
  302. if domain.Id == api.DEFAULT_DOMAIN_ID {
  303. return httperrors.NewForbiddenError("cannot delete default domain")
  304. }
  305. if domain.Enabled.IsTrue() {
  306. return httperrors.NewInvalidStatusError("domain is enabled")
  307. }
  308. if info.UserCount > 0 {
  309. return httperrors.NewInvalidStatusError("domain is in use by user")
  310. }
  311. if info.GroupCount > 0 {
  312. return httperrors.NewInvalidStatusError("domain is in use by group")
  313. }
  314. if info.ProjectCount > 0 {
  315. return httperrors.NewNotEmptyError("domain is in use by project")
  316. }
  317. if info.RoleCount > 0 {
  318. return httperrors.NewNotEmptyError("domain is in use by role")
  319. }
  320. if info.PolicyCount > 0 {
  321. return httperrors.NewNotEmptyError("domain is in use by policy")
  322. }
  323. return domain.SStandaloneResourceBase.ValidateDeleteCondition(ctx, nil)
  324. }
  325. func (domain *SDomain) ValidateUpdateCondition(ctx context.Context) error {
  326. if domain.Id == api.DEFAULT_DOMAIN_ID {
  327. return httperrors.NewForbiddenError("default domain is protected")
  328. }
  329. return domain.SStandaloneResourceBase.ValidateUpdateCondition(ctx)
  330. }
  331. func (domain *SDomain) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.DomainUpdateInput) (api.DomainUpdateInput, error) {
  332. data := jsonutils.Marshal(input)
  333. if domain.IsReadOnly() {
  334. for _, k := range []string{
  335. "name",
  336. } {
  337. if data.Contains(k) {
  338. return input, httperrors.NewForbiddenError("field %s is readonly", k)
  339. }
  340. }
  341. }
  342. var err error
  343. input.StandaloneResourceBaseUpdateInput, err = domain.SStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, input.StandaloneResourceBaseUpdateInput)
  344. if err != nil {
  345. return input, errors.Wrap(err, "SStandaloneResourceBase.ValidateUpdateData")
  346. }
  347. return input, nil
  348. }
  349. type SDomainUsageCount struct {
  350. Id string
  351. api.DomainUsage
  352. }
  353. func (m *SDomainManager) query(manager db.IModelManager, field string, domainIds []string, filter func(*sqlchemy.SQuery) *sqlchemy.SQuery) *sqlchemy.SSubQuery {
  354. q := manager.Query()
  355. if utils.IsInStringArray(manager.Keyword(), []string{
  356. GroupManager.Keyword(),
  357. UserManager.Keyword(),
  358. ProjectManager.Keyword(),
  359. }) {
  360. q = q.IsFalse("pending_deleted")
  361. }
  362. if filter != nil {
  363. q = filter(q)
  364. }
  365. sq := q.SubQuery()
  366. key := "domain_id"
  367. if manager.Keyword() == IdentityProviderManager.Keyword() {
  368. key = "target_domain_id"
  369. }
  370. return sq.Query(
  371. sq.Field(key),
  372. sqlchemy.COUNT(field),
  373. ).In(key, domainIds).GroupBy(sq.Field(key)).SubQuery()
  374. }
  375. func (manager *SDomainManager) TotalResourceCount(domainIds []string) (map[string]api.DomainUsage, error) {
  376. // group
  377. groupSQ := manager.query(GroupManager, "group_cnt", domainIds, nil)
  378. // user
  379. userSQ := manager.query(UserManager, "user_cnt", domainIds, nil)
  380. // project
  381. projectSQ := manager.query(ProjectManager, "project_cnt", domainIds, nil)
  382. // role
  383. roleSQ := manager.query(RoleManager, "role_cnt", domainIds, nil)
  384. // policy
  385. policySQ := manager.query(PolicyManager, "policy_cnt", domainIds, nil)
  386. // idp
  387. idpSQ := manager.query(IdentityProviderManager, "idp_cnt", domainIds, nil)
  388. domains := manager.Query().SubQuery()
  389. domainQ := domains.Query(
  390. sqlchemy.SUM("group_count", groupSQ.Field("group_cnt")),
  391. sqlchemy.SUM("user_count", userSQ.Field("user_cnt")),
  392. sqlchemy.SUM("project_count", projectSQ.Field("project_cnt")),
  393. sqlchemy.SUM("role_count", roleSQ.Field("role_cnt")),
  394. sqlchemy.SUM("policy_count", policySQ.Field("policy_cnt")),
  395. sqlchemy.SUM("idp_count", idpSQ.Field("idp_cnt")),
  396. )
  397. domainQ.AppendField(domainQ.Field("id"))
  398. domainQ = domainQ.LeftJoin(groupSQ, sqlchemy.Equals(domainQ.Field("id"), groupSQ.Field("domain_id")))
  399. domainQ = domainQ.LeftJoin(userSQ, sqlchemy.Equals(domainQ.Field("id"), userSQ.Field("domain_id")))
  400. domainQ = domainQ.LeftJoin(projectSQ, sqlchemy.Equals(domainQ.Field("id"), projectSQ.Field("domain_id")))
  401. domainQ = domainQ.LeftJoin(roleSQ, sqlchemy.Equals(domainQ.Field("id"), roleSQ.Field("domain_id")))
  402. domainQ = domainQ.LeftJoin(policySQ, sqlchemy.Equals(domainQ.Field("id"), policySQ.Field("domain_id")))
  403. domainQ = domainQ.LeftJoin(idpSQ, sqlchemy.Equals(domainQ.Field("id"), idpSQ.Field("target_domain_id")))
  404. domainQ = domainQ.Filter(sqlchemy.In(domainQ.Field("id"), domainIds)).GroupBy(domainQ.Field("id"))
  405. usage := []SDomainUsageCount{}
  406. err := domainQ.All(&usage)
  407. if err != nil {
  408. return nil, errors.Wrapf(err, "domainQ.All")
  409. }
  410. result := map[string]api.DomainUsage{}
  411. for i := range usage {
  412. result[usage[i].Id] = usage[i].DomainUsage
  413. }
  414. return result, nil
  415. }
  416. func (manager *SDomainManager) FetchCustomizeColumns(
  417. ctx context.Context,
  418. userCred mcclient.TokenCredential,
  419. query jsonutils.JSONObject,
  420. objs []interface{},
  421. fields stringutils2.SSortedStrings,
  422. isList bool,
  423. ) []api.DomainDetails {
  424. rows := make([]api.DomainDetails, len(objs))
  425. stdRows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  426. idList := make([]string, len(rows))
  427. for i := range rows {
  428. rows[i] = api.DomainDetails{
  429. StandaloneResourceDetails: stdRows[i],
  430. }
  431. domain := objs[i].(*SDomain)
  432. idList[i] = domain.Id
  433. external, update, _ := domain.getExternalResources()
  434. if len(external) > 0 {
  435. rows[i].ExtResource = external
  436. rows[i].ExtResourcesLastUpdate = update
  437. if update.IsZero() {
  438. update = time.Now()
  439. }
  440. nextUpdate := update.Add(time.Duration(options.Options.FetchScopeResourceCountIntervalSeconds) * time.Second)
  441. rows[i].ExtResourcesNextUpdate = nextUpdate
  442. }
  443. }
  444. idpRows := expandIdpAttributes(api.IdMappingEntityDomain, idList, fields)
  445. usage, err := manager.TotalResourceCount(idList)
  446. if err != nil {
  447. log.Errorf("TotalResourceCount error: %v", err)
  448. return rows
  449. }
  450. for i := range rows {
  451. rows[i].IdpResourceInfo = idpRows[i]
  452. rows[i].DomainUsage, _ = usage[idList[i]]
  453. }
  454. return rows
  455. }
  456. func (domain *SDomain) getUsers() ([]SUser, error) {
  457. q := UserManager.Query().Equals("domain_id", domain.Id)
  458. usrs := make([]SUser, 0)
  459. err := db.FetchModelObjects(UserManager, q, &usrs)
  460. if err != nil && err != sql.ErrNoRows {
  461. return nil, errors.Wrap(err, "FetchModelObjects")
  462. }
  463. return usrs, nil
  464. }
  465. func (domain *SDomain) getGroups() ([]SGroup, error) {
  466. q := GroupManager.Query().Equals("domain_id", domain.Id)
  467. grps := make([]SGroup, 0)
  468. err := db.FetchModelObjects(GroupManager, q, &grps)
  469. if err != nil && err != sql.ErrNoRows {
  470. return nil, errors.Wrap(err, "FetchModelObjects")
  471. }
  472. return grps, nil
  473. }
  474. func (domain *SDomain) DeleteUserGroups(ctx context.Context, userCred mcclient.TokenCredential) error {
  475. usrs, err := domain.getUsers()
  476. if err != nil {
  477. return errors.Wrap(err, "domain.getUsers")
  478. }
  479. for i := range usrs {
  480. err = usrs[i].ValidateDeleteCondition(ctx, nil)
  481. if err != nil {
  482. return errors.Wrap(err, "usr.ValidateDeleteCondition")
  483. }
  484. err = usrs[i].Delete(ctx, userCred)
  485. if err != nil {
  486. return errors.Wrap(err, "usr.Delete")
  487. }
  488. }
  489. grps, err := domain.getGroups()
  490. if err != nil {
  491. return errors.Wrap(err, "domain.getGroups")
  492. }
  493. for i := range grps {
  494. err = grps[i].ValidateDeleteCondition(ctx, nil)
  495. if err != nil {
  496. return errors.Wrap(err, "grp.ValidateDeleteCondition")
  497. }
  498. err = grps[i].Delete(ctx, userCred)
  499. if err != nil {
  500. return errors.Wrap(err, "grp.Delete")
  501. }
  502. }
  503. return nil
  504. }
  505. func (domain *SDomain) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
  506. err := domain.DeleteUserGroups(ctx, userCred)
  507. if err != nil {
  508. return errors.Wrap(err, "domain.DeleteUserGroups")
  509. }
  510. // return domain.SStandaloneResourceBase.Delete(ctx, userCred)
  511. if !domain.PendingDeleted {
  512. newName := fmt.Sprintf("%s-deleted-%s", domain.Name, timeutils.ShortDate(timeutils.UtcNow()))
  513. err := domain.SPendingDeletedBase.MarkPendingDelete(domain, ctx, userCred, newName)
  514. if err != nil {
  515. return errors.Wrap(err, "MarkPendingDelete")
  516. }
  517. }
  518. err = db.Metadata.RemoveAll(ctx, domain, userCred)
  519. if err != nil {
  520. return errors.Wrapf(err, "Metadata.RemoveAll")
  521. }
  522. return nil
  523. }
  524. func (domain *SDomain) getIdmapping() (*SIdmapping, error) {
  525. return IdmappingManager.FetchFirstEntity(domain.Id, api.IdMappingEntityDomain)
  526. }
  527. func (domain *SDomain) IsReadOnly() bool {
  528. idmap, _ := domain.getIdmapping()
  529. if idmap != nil {
  530. return true
  531. }
  532. return false
  533. }
  534. func (domain *SDomain) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
  535. domain.SStandaloneResourceBase.PostCreate(ctx, userCred, ownerId, query, data)
  536. logclient.AddActionLogWithContext(ctx, domain, logclient.ACT_CREATE, data, userCred, true)
  537. }
  538. func (domain *SDomain) PostUpdate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) {
  539. domain.SStandaloneResourceBase.PostUpdate(ctx, userCred, query, data)
  540. logclient.AddActionLogWithContext(ctx, domain, logclient.ACT_UPDATE, data, userCred, true)
  541. }
  542. func (domain *SDomain) PostDelete(ctx context.Context, userCred mcclient.TokenCredential) {
  543. domain.SStandaloneResourceBase.PostDelete(ctx, userCred)
  544. logclient.AddActionLogWithContext(ctx, domain, logclient.ACT_DELETE, nil, userCred, true)
  545. }
  546. func (domain *SDomain) UnlinkIdp(idpId string) error {
  547. usrs, err := domain.getUsers()
  548. if err != nil {
  549. return errors.Wrap(err, "domain.getUsers")
  550. }
  551. for i := range usrs {
  552. err = usrs[i].UnlinkIdp(idpId)
  553. if err != nil {
  554. return errors.Wrap(err, "usr.UnlinkIdp")
  555. }
  556. }
  557. grps, err := domain.getGroups()
  558. if err != nil {
  559. return errors.Wrap(err, "domain.getGroups")
  560. }
  561. for i := range grps {
  562. err = grps[i].UnlinkIdp(idpId)
  563. if err != nil {
  564. return errors.Wrap(err, "grp.UnlinkIdp")
  565. }
  566. }
  567. return IdmappingManager.deleteAny(idpId, api.IdMappingEntityDomain, domain.Id)
  568. }
  569. func (domain *SDomain) getExternalResources() (map[string]int, time.Time, error) {
  570. return ScopeResourceManager.getScopeResource(domain.Id, "", "")
  571. }
  572. func (manager *SDomainManager) ValidateCreateData(
  573. ctx context.Context,
  574. userCred mcclient.TokenCredential,
  575. ownerId mcclient.IIdentityProvider,
  576. query jsonutils.JSONObject,
  577. input api.DomainCreateInput,
  578. ) (api.DomainCreateInput, error) {
  579. var err error
  580. input.StandaloneResourceCreateInput, err = manager.SStandaloneResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.StandaloneResourceCreateInput)
  581. if err != nil {
  582. return input, errors.Wrap(err, "SStandaloneResourceBaseManager.ValidateCreateData")
  583. }
  584. return input, nil
  585. }
  586. // domain和IDP的指定entityId解除关联
  587. func (domain *SDomain) PerformUnlinkIdp(
  588. ctx context.Context,
  589. userCred mcclient.TokenCredential,
  590. query jsonutils.JSONObject,
  591. input api.UserUnlinkIdpInput,
  592. ) (jsonutils.JSONObject, error) {
  593. mapping, err := domain.getIdmapping()
  594. if err != nil {
  595. if errors.Cause(err) == sql.ErrNoRows {
  596. return nil, nil
  597. } else {
  598. return nil, errors.Wrap(err, "domain.getIdmapping")
  599. }
  600. }
  601. err = domain.UnlinkIdp(mapping.IdpId)
  602. if err != nil {
  603. return nil, errors.Wrap(err, "domain.UnlinkIdp")
  604. }
  605. return nil, nil
  606. }
  607. func (manager *SDomainManager) FilterBySystemAttributes(q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query jsonutils.JSONObject, scope rbacscope.TRbacScope) *sqlchemy.SQuery {
  608. q = manager.SStandaloneResourceBaseManager.FilterBySystemAttributes(q, userCred, query, scope)
  609. q = manager.SPendingDeletedBaseManager.FilterBySystemAttributes(manager.GetIStandaloneModelManager(), q, userCred, query, scope)
  610. return q
  611. }
  612. func (manager *SDomainManager) FilterByOwner(ctx context.Context, q *sqlchemy.SQuery, man db.FilterByOwnerProvider, userCred mcclient.TokenCredential, owner mcclient.IIdentityProvider, scope rbacscope.TRbacScope) *sqlchemy.SQuery {
  613. if userCred != nil && scope != rbacscope.ScopeSystem {
  614. q = q.Equals("id", owner.GetProjectDomainId())
  615. }
  616. return manager.SStandaloneResourceBaseManager.FilterByOwner(ctx, q, man, userCred, owner, scope)
  617. }