organizations.go 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669
  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. "strings"
  20. "yunion.io/x/jsonutils"
  21. "yunion.io/x/log"
  22. "yunion.io/x/pkg/errors"
  23. "yunion.io/x/pkg/tristate"
  24. "yunion.io/x/pkg/util/rbacscope"
  25. "yunion.io/x/pkg/utils"
  26. "yunion.io/x/sqlchemy"
  27. "yunion.io/x/onecloud/pkg/apis"
  28. api "yunion.io/x/onecloud/pkg/apis/identity"
  29. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  30. "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
  31. "yunion.io/x/onecloud/pkg/httperrors"
  32. "yunion.io/x/onecloud/pkg/mcclient"
  33. "yunion.io/x/onecloud/pkg/util/logclient"
  34. "yunion.io/x/onecloud/pkg/util/stringutils2"
  35. "yunion.io/x/onecloud/pkg/util/tagutils"
  36. )
  37. var _ db.IModelManager = (*SOrganizationManager)(nil)
  38. var _ db.IModel = (*SOrganization)(nil)
  39. type SOrganizationManager struct {
  40. SEnabledIdentityBaseResourceManager
  41. db.SSharableBaseResourceManager
  42. db.SStatusResourceBaseManager
  43. cache *db.SCacheManager[SOrganization]
  44. }
  45. var OrganizationManager *SOrganizationManager
  46. func init() {
  47. OrganizationManager = &SOrganizationManager{
  48. SEnabledIdentityBaseResourceManager: NewEnabledIdentityBaseResourceManager(
  49. SOrganization{},
  50. "organizations_tbl",
  51. "organization",
  52. "organizations",
  53. ),
  54. }
  55. OrganizationManager.SetVirtualObject(OrganizationManager)
  56. OrganizationManager.cache = db.NewCacheManager[SOrganization](OrganizationManager)
  57. }
  58. type SOrganization struct {
  59. SEnabledIdentityBaseResource
  60. db.SSharableBaseResource
  61. db.SStatusResourceBase
  62. Type api.TOrgType `width:"32" charset:"ascii" list:"user" create:"admin_required"`
  63. Keys string `width:"256" charset:"utf8" list:"user" create:"admin_optional"`
  64. Level int `list:"user" create:"admin_optional"`
  65. }
  66. func (manager *SOrganizationManager) fetchOrganizationById(orgId string) (*SOrganization, error) {
  67. org, err := manager.cache.FetchById(orgId)
  68. if err != nil {
  69. if errors.Cause(err) == sql.ErrNoRows {
  70. obj, err := manager.FetchById(orgId)
  71. if err != nil {
  72. return nil, errors.Wrap(err, "manager.FetchById")
  73. }
  74. manager.cache.Invalidate()
  75. org = obj.(*SOrganization)
  76. } else {
  77. return nil, errors.Wrapf(err, "cache.FetchById %s", orgId)
  78. }
  79. }
  80. return org, nil
  81. }
  82. // 组织列表
  83. func (manager *SOrganizationManager) ListItemFilter(
  84. ctx context.Context,
  85. q *sqlchemy.SQuery,
  86. userCred mcclient.TokenCredential,
  87. query api.OrganizationListInput,
  88. ) (*sqlchemy.SQuery, error) {
  89. var err error
  90. q, err = manager.SEnabledIdentityBaseResourceManager.ListItemFilter(ctx, q, userCred, query.EnabledIdentityBaseResourceListInput)
  91. if err != nil {
  92. return nil, errors.Wrap(err, "SEnabledIdentityBaseResourceManager.ListItemFilter")
  93. }
  94. q, err = manager.SSharableBaseResourceManager.ListItemFilter(ctx, q, userCred, query.SharableResourceBaseListInput)
  95. if err != nil {
  96. return nil, errors.Wrap(err, "SSharableBaseResourceManager.ListItemFilter")
  97. }
  98. q, err = manager.SStatusResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusResourceBaseListInput)
  99. if err != nil {
  100. return nil, errors.Wrap(err, "SStatusResourceBaseManager.ListItemFilter")
  101. }
  102. if len(query.Type) > 0 {
  103. q = q.In("type", query.Type)
  104. }
  105. if len(query.Key) > 0 {
  106. q = q.Contains("keys", query.Key)
  107. }
  108. return q, nil
  109. }
  110. func (manager *SOrganizationManager) ExtendListQuery(
  111. ctx context.Context,
  112. q *sqlchemy.SQuery,
  113. userCred mcclient.TokenCredential,
  114. query api.OrganizationListInput,
  115. ) (*sqlchemy.SQuery, error) {
  116. return q, nil
  117. }
  118. func (manager *SOrganizationManager) OrderByExtraFields(
  119. ctx context.Context,
  120. q *sqlchemy.SQuery,
  121. userCred mcclient.TokenCredential,
  122. query api.OrganizationListInput,
  123. ) (*sqlchemy.SQuery, error) {
  124. var err error
  125. q, err = manager.SEnabledIdentityBaseResourceManager.OrderByExtraFields(ctx, q, userCred, query.EnabledIdentityBaseResourceListInput)
  126. if err != nil {
  127. return nil, errors.Wrap(err, "SEnabledIdentityBaseResourceManager.OrderByExtraFields")
  128. }
  129. q, err = manager.SStatusResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusResourceBaseListInput)
  130. if err != nil {
  131. return nil, errors.Wrap(err, "SStatusResourceBaseManager.ListItemFilter")
  132. }
  133. return q, nil
  134. }
  135. func (manager *SOrganizationManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
  136. var err error
  137. q, err = manager.SEnabledIdentityBaseResourceManager.QueryDistinctExtraField(q, field)
  138. if err == nil {
  139. return q, nil
  140. }
  141. return q, httperrors.ErrNotFound
  142. }
  143. func (manager *SOrganizationManager) FetchCustomizeColumns(
  144. ctx context.Context,
  145. userCred mcclient.TokenCredential,
  146. query jsonutils.JSONObject,
  147. objs []interface{},
  148. fields stringutils2.SSortedStrings,
  149. isList bool,
  150. ) []api.SOrganizationDetails {
  151. rows := make([]api.SOrganizationDetails, len(objs))
  152. infRows := manager.SEnabledIdentityBaseResourceManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  153. sharedRows := manager.SSharableBaseResourceManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  154. for i := range rows {
  155. // org := objs[i].(*SOrganization)
  156. rows[i] = api.SOrganizationDetails{
  157. EnabledIdentityBaseResourceDetails: infRows[i],
  158. SharableResourceBaseInfo: sharedRows[i],
  159. }
  160. }
  161. return rows
  162. }
  163. func (manager *SOrganizationManager) FetchOrgnaizations(filter func(q *sqlchemy.SQuery) *sqlchemy.SQuery) ([]SOrganization, error) {
  164. q := manager.Query()
  165. q = filter(q)
  166. ret := make([]SOrganization, 0)
  167. err := db.FetchModelObjects(manager, q, &ret)
  168. if err != nil {
  169. return nil, errors.Wrap(err, "FetchModelObjects")
  170. }
  171. return ret, nil
  172. }
  173. func (org *SOrganization) getNodesQuery() *sqlchemy.SQuery {
  174. return OrganizationNodeManager.Query().Equals("org_id", org.Id)
  175. }
  176. func (org *SOrganization) getNodesCount() (int, error) {
  177. q := org.getNodesQuery()
  178. return q.CountWithError()
  179. }
  180. func (org *SOrganization) getNodes() ([]SOrganizationNode, error) {
  181. q := org.getNodesQuery()
  182. q = q.Asc("level")
  183. q = q.Asc("weight")
  184. q = q.Asc("full_label")
  185. nodes := make([]SOrganizationNode, 0)
  186. err := db.FetchModelObjects(OrganizationNodeManager, q, &nodes)
  187. if err != nil {
  188. return nil, errors.Wrap(err, "FetchModelObjects")
  189. }
  190. return nodes, nil
  191. }
  192. func (org *SOrganization) getNode(fullLabel string) (*SOrganizationNode, error) {
  193. q := org.getNodesQuery()
  194. q = q.Equals("full_label", fullLabel)
  195. node := &SOrganizationNode{}
  196. err := q.First(node)
  197. if err != nil {
  198. return nil, errors.Wrap(err, "First")
  199. }
  200. node.SetModelManager(OrganizationNodeManager, node)
  201. return node, nil
  202. }
  203. func (org *SOrganization) ValidateDeleteCondition(ctx context.Context, info *api.ProjectDetails) error {
  204. if org.GetEnabled() {
  205. return errors.Wrap(httperrors.ErrInvalidStatus, "organization enabled")
  206. }
  207. return org.SEnabledIdentityBaseResource.ValidateDeleteCondition(ctx, nil)
  208. }
  209. func (org *SOrganization) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
  210. err := org.removeAll(ctx, userCred)
  211. if err != nil {
  212. return errors.Wrap(err, "removeAll")
  213. }
  214. OrganizationManager.cache.Delete(org)
  215. // pending delete
  216. err = org.SEnabledIdentityBaseResource.Delete(ctx, userCred)
  217. if err != nil {
  218. return errors.Wrap(err, "SEnabledIdentityBaseResource.Delete")
  219. }
  220. return nil
  221. }
  222. func (manager *SOrganizationManager) ValidateCreateData(
  223. ctx context.Context,
  224. userCred mcclient.TokenCredential,
  225. ownerId mcclient.IIdentityProvider,
  226. query jsonutils.JSONObject,
  227. input api.OrganizationCreateInput,
  228. ) (api.OrganizationCreateInput, error) {
  229. var err error
  230. input.EnabledIdentityBaseResourceCreateInput, err = manager.SEnabledIdentityBaseResourceManager.ValidateCreateData(ctx, userCred, ownerId, query, input.EnabledIdentityBaseResourceCreateInput)
  231. if err != nil {
  232. return input, errors.Wrap(err, "SEnabledIdentityBaseResourceManager.ValidateCreateData")
  233. }
  234. input.SharableResourceBaseCreateInput, err = db.SharableManagerValidateCreateData(manager, ctx, userCred, ownerId, query, input.SharableResourceBaseCreateInput)
  235. if err != nil {
  236. return input, errors.Wrap(err, "SharableManagerValidateCreateData")
  237. }
  238. if !api.IsValidOrgType(input.Type) {
  239. return input, errors.Wrapf(httperrors.ErrInputParameter, "invalid organization type %s", input.Type)
  240. }
  241. // allow empty key
  242. // if len(input.Key) == 0 {
  243. // return input, errors.Wrap(httperrors.ErrInputParameter, "empty key")
  244. // }
  245. input.Level = len(input.Key)
  246. // keys should be uniq
  247. keyMap := make(map[string]struct{})
  248. for _, k := range input.Key {
  249. if _, ok := keyMap[k]; ok {
  250. return input, errors.Wrapf(httperrors.ErrInputParameter, "duplicate key %s", k)
  251. } else {
  252. keyMap[k] = struct{}{}
  253. }
  254. }
  255. input.Keys = api.JoinLabels(input.Key...)
  256. return input, nil
  257. }
  258. func (org *SOrganization) CustomizeCreate(
  259. ctx context.Context,
  260. userCred mcclient.TokenCredential,
  261. ownerId mcclient.IIdentityProvider,
  262. query jsonutils.JSONObject,
  263. data jsonutils.JSONObject,
  264. ) error {
  265. org.SetShare(rbacscope.ScopeSystem)
  266. org.Enabled = tristate.False
  267. org.Status = api.OrganizationStatusReady
  268. return org.SEnabledIdentityBaseResource.CustomizeCreate(ctx, userCred, ownerId, query, data)
  269. }
  270. func (org *SOrganization) PostCreate(
  271. ctx context.Context,
  272. userCred mcclient.TokenCredential,
  273. ownerId mcclient.IIdentityProvider,
  274. query jsonutils.JSONObject,
  275. data jsonutils.JSONObject,
  276. ) {
  277. org.SEnabledIdentityBaseResource.PostCreate(ctx, userCred, ownerId, query, data)
  278. OrganizationManager.cache.Update(org)
  279. }
  280. func (org *SOrganization) ValidateUpdateData(
  281. ctx context.Context,
  282. userCred mcclient.TokenCredential,
  283. query jsonutils.JSONObject,
  284. input api.OrganizationUpdateInput,
  285. ) (api.OrganizationUpdateInput, error) {
  286. return input, nil
  287. }
  288. func (org *SOrganization) PostUpdate(
  289. ctx context.Context,
  290. userCred mcclient.TokenCredential,
  291. query jsonutils.JSONObject,
  292. data jsonutils.JSONObject,
  293. ) {
  294. org.SEnabledIdentityBaseResource.PostUpdate(ctx, userCred, query, data)
  295. OrganizationManager.cache.Update(org)
  296. }
  297. func (org *SOrganization) PerformAddLevel(
  298. ctx context.Context,
  299. userCred mcclient.TokenCredential,
  300. query jsonutils.JSONObject,
  301. input api.OrganizationPerformAddLevelsInput,
  302. ) (jsonutils.JSONObject, error) {
  303. keys := api.SplitLabel(org.Keys)
  304. for _, nk := range input.Key {
  305. if len(nk) == 0 {
  306. return nil, errors.Wrap(httperrors.ErrInputParameter, "empty key")
  307. }
  308. if utils.IsInArray(nk, keys) {
  309. return nil, errors.Wrapf(httperrors.ErrInputParameter, "key %s duplicated", nk)
  310. } else {
  311. keys = append(keys, nk)
  312. }
  313. }
  314. if len(input.Tags) > 0 {
  315. if len(input.Tags) != len(keys) {
  316. return nil, errors.Wrapf(httperrors.ErrInputParameter, "inconsist level of key %d and tags %d", len(keys), len(input.Tags))
  317. }
  318. for _, k := range keys {
  319. if _, ok := input.Tags[k]; !ok {
  320. return nil, errors.Wrapf(httperrors.ErrInputParameter, "missing value for key %s", k)
  321. }
  322. }
  323. }
  324. _, err := db.Update(org, func() error {
  325. org.Keys = api.JoinLabels(keys...)
  326. org.Level = len(keys)
  327. return nil
  328. })
  329. if err != nil {
  330. return nil, errors.Wrap(err, "Update")
  331. }
  332. OrganizationManager.cache.Update(org)
  333. db.OpsLog.LogEvent(org, db.ACT_UPDATE, org.GetShortDesc(ctx), userCred)
  334. logclient.AddSimpleActionLog(org, logclient.ACT_UPDATE, org.GetShortDesc(ctx), userCred, true)
  335. if len(input.Tags) > 0 {
  336. _, err := org.PerformAddNode(ctx, userCred, query, input.OrganizationPerformAddNodeInput)
  337. if err != nil {
  338. return nil, errors.Wrap(err, "AddNode")
  339. }
  340. }
  341. return nil, nil
  342. }
  343. func (org *SOrganization) GetShortDesc(ctx context.Context) *jsonutils.JSONDict {
  344. desc := org.SEnabledIdentityBaseResource.GetShortDesc(ctx)
  345. desc.Set("status", jsonutils.NewString(org.Status))
  346. desc.Set("keys", jsonutils.NewString(org.Keys))
  347. desc.Set("level", jsonutils.NewInt(int64(org.Level)))
  348. return desc
  349. }
  350. func (org *SOrganization) GetKeys() []string {
  351. return api.SplitLabel(org.Keys)
  352. }
  353. func (org *SOrganization) PerformAddNode(
  354. ctx context.Context,
  355. userCred mcclient.TokenCredential,
  356. query jsonutils.JSONObject,
  357. input api.OrganizationPerformAddNodeInput,
  358. ) (jsonutils.JSONObject, error) {
  359. labels := make([]string, 0)
  360. for _, k := range org.GetKeys() {
  361. if label, ok := input.Tags[k]; !ok {
  362. break
  363. } else {
  364. labels = append(labels, label)
  365. }
  366. }
  367. for i := 0; i < len(labels); i++ {
  368. var weight *int
  369. var desc string
  370. if i == len(labels)-1 {
  371. weight = &input.Weight
  372. desc = input.Description
  373. }
  374. _, err := OrganizationNodeManager.ensureNode(ctx, org.Id, api.JoinLabels(labels[0:i+1]...), weight, desc)
  375. if err != nil {
  376. return nil, errors.Wrapf(err, "fail to insert node %s", api.JoinLabels(labels[i:i]...))
  377. }
  378. }
  379. return nil, nil
  380. }
  381. func (org *SOrganization) PerformSync(
  382. ctx context.Context,
  383. userCred mcclient.TokenCredential,
  384. query jsonutils.JSONObject,
  385. input api.OrganizationPerformSyncInput,
  386. ) (jsonutils.JSONObject, error) {
  387. if input.Reset != nil && *input.Reset {
  388. err := org.removeAll(ctx, userCred)
  389. if err != nil {
  390. return nil, errors.Wrap(err, "removeAll")
  391. }
  392. }
  393. err := org.startOrganizationSyncTask(ctx, userCred, input.ResourceType)
  394. if err != nil {
  395. return nil, errors.Wrap(err, "startOrganizationSyncTask")
  396. }
  397. return nil, nil
  398. }
  399. func (org *SOrganization) removeAll(ctx context.Context, userCred mcclient.TokenCredential) error {
  400. nodes, err := org.getNodes()
  401. if err != nil {
  402. return errors.Wrap(err, "getNodes")
  403. }
  404. for i := range nodes {
  405. err := nodes[i].Delete(ctx, userCred)
  406. if err != nil {
  407. return errors.Wrapf(err, "Delete %s", nodes[i].FullLabel)
  408. }
  409. }
  410. return nil
  411. }
  412. func (org *SOrganization) SetStatus(ctx context.Context, userCred mcclient.TokenCredential, status string, reason string) error {
  413. return db.StatusBaseSetStatus(ctx, org, userCred, status, reason)
  414. }
  415. func (org *SOrganization) startOrganizationSyncTask(
  416. ctx context.Context,
  417. userCred mcclient.TokenCredential,
  418. resourceType string,
  419. ) error {
  420. org.SetStatus(ctx, userCred, api.OrganizationStatusSync, "start sync task")
  421. params := jsonutils.NewDict()
  422. if len(resourceType) > 0 {
  423. params.Add(jsonutils.NewString(resourceType), "resource_type")
  424. }
  425. task, err := taskman.TaskManager.NewTask(ctx, "OrganizationSyncTask", org, userCred, params, "", "", nil)
  426. if err != nil {
  427. return err
  428. }
  429. task.ScheduleRun(nil)
  430. return nil
  431. }
  432. func (org *SOrganization) SyncTags(ctx context.Context, userCred mcclient.TokenCredential, resourceType string) error {
  433. switch org.Type {
  434. case api.OrgTypeProject:
  435. return org.syncProjectTags(ctx, userCred)
  436. case api.OrgTypeDomain:
  437. return org.syncDomainTags(ctx, userCred)
  438. case api.OrgTypeObject:
  439. return org.syncObjectTags(ctx, userCred, resourceType)
  440. }
  441. return nil
  442. }
  443. func (org *SOrganization) syncProjectTags(ctx context.Context, userCred mcclient.TokenCredential) error {
  444. return org.syncIModelManagerTags(ctx, userCred, ProjectManager)
  445. }
  446. func (org *SOrganization) syncIModelManagerTags(ctx context.Context, userCred mcclient.TokenCredential, manager db.IStandaloneModelManager) error {
  447. query := jsonutils.NewDict()
  448. query.Set("scope", jsonutils.NewString("system"))
  449. keys := api.SplitLabel(org.Keys)
  450. userKeys := make([]string, len(keys))
  451. for i := range keys {
  452. userKeys[i] = fmt.Sprintf("%s%s", db.USER_TAG_PREFIX, keys[i])
  453. }
  454. orgKeys := make([]string, len(keys))
  455. for i := range keys {
  456. orgKeys[i] = fmt.Sprintf("%s%s", db.ORGANIZATION_TAG_PREFIX, keys[i])
  457. }
  458. {
  459. tagValMaps, err := db.GetTagValueCountMap(manager, manager.Keyword(), "id", "", userKeys, ctx, userCred, query)
  460. if err != nil {
  461. return errors.Wrap(err, "GetTagValueCountMap")
  462. }
  463. for i := range tagValMaps {
  464. labels, err := org.syncTagValueMap(ctx, tagValMaps[i])
  465. if err != nil {
  466. return errors.Wrap(err, "syncTagValueMap")
  467. }
  468. err = db.CopyTags(ctx, manager.Keyword(), userKeys, labels, orgKeys)
  469. if err != nil {
  470. return errors.Wrap(err, "copyTags")
  471. }
  472. }
  473. }
  474. {
  475. tagValMaps, err := db.GetTagValueCountMap(manager, manager.Keyword(), "id", "", orgKeys, ctx, userCred, query)
  476. if err != nil {
  477. return errors.Wrap(err, "GetTagValueCountMap")
  478. }
  479. for i := range tagValMaps {
  480. _, err := org.syncTagValueMap(ctx, tagValMaps[i])
  481. if err != nil {
  482. return errors.Wrap(err, "syncTagValueMap")
  483. }
  484. }
  485. }
  486. return nil
  487. }
  488. func (org *SOrganization) syncDomainTags(ctx context.Context, userCred mcclient.TokenCredential) error {
  489. return org.syncIModelManagerTags(ctx, userCred, DomainManager)
  490. }
  491. func (org *SOrganization) syncObjectTags(ctx context.Context, userCred mcclient.TokenCredential, resourceType string) error {
  492. // XXX TODO QJ
  493. return errors.Wrap(httperrors.ErrNotImplemented, "not ready yet")
  494. }
  495. func (org *SOrganization) syncTagValueMap(ctx context.Context, tagVal map[string]string) ([]string, error) {
  496. labels := make([]string, 0)
  497. for i := 0; i < org.Level; i++ {
  498. key := db.TagValueKey(i)
  499. if val, ok := tagVal[key]; ok && val != tagutils.NoValue {
  500. labels = append(labels, val)
  501. log.Debugf("%d %s %s %s", i, key, val, strings.Join(labels, "/"))
  502. _, err := OrganizationNodeManager.ensureNode(ctx, org.Id, api.JoinLabels(labels...), nil, "")
  503. if err != nil {
  504. return nil, errors.Wrapf(err, "fail to insert node %s", api.JoinLabels(labels...))
  505. }
  506. } else {
  507. break
  508. }
  509. }
  510. return labels, nil
  511. }
  512. func (org *SOrganization) PerformEnable(
  513. ctx context.Context,
  514. userCred mcclient.TokenCredential,
  515. query jsonutils.JSONObject,
  516. input apis.PerformEnableInput,
  517. ) (jsonutils.JSONObject, error) {
  518. if !org.GetEnabled() {
  519. _, err := org.SEnabledIdentityBaseResource.PerformEnable(ctx, userCred, query, input)
  520. if err != nil {
  521. return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBase.PerformEnable")
  522. }
  523. OrganizationManager.cache.Update(org)
  524. // disable other org of the same type
  525. otherOrgs, err := OrganizationManager.FetchOrgnaizations(func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  526. q = q.Equals("type", org.Type)
  527. q = q.NotEquals("id", org.Id)
  528. q = q.IsTrue("enabled")
  529. return q
  530. })
  531. if err != nil {
  532. return nil, errors.Wrap(err, "FetchOrgnaizations")
  533. }
  534. for i := range otherOrgs {
  535. _, err := otherOrgs[i].PerformDisable(ctx, userCred, query, apis.PerformDisableInput{})
  536. if err != nil {
  537. return nil, errors.Wrap(err, "PerformDisable")
  538. }
  539. }
  540. }
  541. return nil, nil
  542. }
  543. func (org *SOrganization) PerformDisable(
  544. ctx context.Context,
  545. userCred mcclient.TokenCredential,
  546. query jsonutils.JSONObject,
  547. input apis.PerformDisableInput,
  548. ) (jsonutils.JSONObject, error) {
  549. if org.GetEnabled() {
  550. _, err := org.SEnabledIdentityBaseResource.PerformDisable(ctx, userCred, query, input)
  551. if err != nil {
  552. return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBase.PerformDisable")
  553. }
  554. OrganizationManager.cache.Update(org)
  555. }
  556. return nil, nil
  557. }
  558. func (org *SOrganization) getProjectOrganization(tags map[string]string) (*api.SProjectOrganization, error) {
  559. keys := api.SplitLabel(org.Keys)
  560. ret := api.SProjectOrganization{
  561. Id: org.Id,
  562. Name: org.Name,
  563. Keys: keys,
  564. Nodes: make([]api.SProjectOrganizationNode, 0, len(keys)),
  565. }
  566. labels := make([]string, 0, len(keys))
  567. for _, k := range keys {
  568. if val, ok := tags[k]; ok {
  569. labels = append(labels, val)
  570. fullLabel := api.JoinLabels(labels...)
  571. node, err := org.getNode(fullLabel)
  572. if err != nil {
  573. return nil, errors.Wrapf(err, "getNode %s", fullLabel)
  574. }
  575. ret.Nodes = append(ret.Nodes, api.SProjectOrganizationNode{
  576. Id: node.Id,
  577. Labels: api.SplitLabel(fullLabel),
  578. })
  579. } else {
  580. break
  581. }
  582. }
  583. return &ret, nil
  584. }
  585. func (org *SOrganization) PerformClean(
  586. ctx context.Context,
  587. userCred mcclient.TokenCredential,
  588. query jsonutils.JSONObject,
  589. input api.OrganizationPerformCleanInput,
  590. ) (jsonutils.JSONObject, error) {
  591. err := org.removeAll(ctx, userCred)
  592. if err != nil {
  593. return nil, errors.Wrap(err, "removeAll")
  594. }
  595. return nil, nil
  596. }