clouduser.go 39 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220
  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. "gopkg.in/fatih/set.v0"
  20. "yunion.io/x/cloudmux/pkg/cloudprovider"
  21. "yunion.io/x/jsonutils"
  22. "yunion.io/x/log"
  23. "yunion.io/x/pkg/errors"
  24. "yunion.io/x/pkg/tristate"
  25. "yunion.io/x/pkg/util/compare"
  26. "yunion.io/x/pkg/util/regutils"
  27. "yunion.io/x/pkg/utils"
  28. "yunion.io/x/sqlchemy"
  29. "yunion.io/x/onecloud/pkg/apis"
  30. api "yunion.io/x/onecloud/pkg/apis/cloudid"
  31. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  32. "yunion.io/x/onecloud/pkg/cloudcommon/db/lockman"
  33. "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
  34. "yunion.io/x/onecloud/pkg/cloudcommon/validators"
  35. "yunion.io/x/onecloud/pkg/httperrors"
  36. "yunion.io/x/onecloud/pkg/mcclient"
  37. "yunion.io/x/onecloud/pkg/util/logclient"
  38. "yunion.io/x/onecloud/pkg/util/seclib2"
  39. "yunion.io/x/onecloud/pkg/util/stringutils2"
  40. )
  41. type SClouduserManager struct {
  42. db.SStatusDomainLevelUserResourceBaseManager
  43. db.SExternalizedResourceBaseManager
  44. SCloudaccountResourceBaseManager
  45. SCloudproviderResourceBaseManager
  46. }
  47. var ClouduserManager *SClouduserManager
  48. func init() {
  49. ClouduserManager = &SClouduserManager{
  50. SStatusDomainLevelUserResourceBaseManager: db.NewStatusDomainLevelUserResourceBaseManager(
  51. SClouduser{},
  52. "cloudusers_tbl",
  53. "clouduser",
  54. "cloudusers",
  55. ),
  56. }
  57. ClouduserManager.SetVirtualObject(ClouduserManager)
  58. }
  59. type SClouduser struct {
  60. db.SStatusDomainLevelUserResourceBase
  61. db.SExternalizedResourceBase
  62. SCloudaccountResourceBase
  63. SCloudproviderResourceBase
  64. Secret string `length:"0" charset:"ascii" nullable:"true" list:"user" create:"domain_optional"`
  65. // 是否可以控制台登录
  66. IsConsoleLogin tristate.TriState `default:"false" list:"user" create:"optional"`
  67. // 手机号码
  68. MobilePhone string `width:"36" charset:"ascii" nullable:"true" list:"user" create:"domain_optional"`
  69. // 邮箱地址
  70. Email string `width:"36" charset:"ascii" list:"user" create:"domain_optional"`
  71. }
  72. func (manager *SClouduserManager) EnableGenerateName() bool {
  73. return false
  74. }
  75. func (manager *SClouduserManager) GetResourceCount() ([]db.SScopeResourceCount, error) {
  76. q := manager.Query()
  77. domainCnt, err := db.CalculateResourceCount(q, "domain_id")
  78. if err != nil {
  79. return nil, errors.Wrap(err, "CalculateResourceCount.domain_id")
  80. }
  81. q = manager.Query()
  82. userCnt, err := db.CalculateResourceCount(q, "owner_id")
  83. if err != nil {
  84. return nil, errors.Wrap(err, "CalculateResourceCount.owner_id")
  85. }
  86. return append(domainCnt, userCnt...), nil
  87. }
  88. func (manager *SClouduserManager) GetIVirtualModelManager() db.IVirtualModelManager {
  89. return manager.GetVirtualObject().(db.IVirtualModelManager)
  90. }
  91. func (manager *SClouduserManager) FetchUniqValues(ctx context.Context, data jsonutils.JSONObject) jsonutils.JSONObject {
  92. accountId, _ := data.GetString("cloudaccount_id")
  93. return jsonutils.Marshal(map[string]string{"cloudaccount_id": accountId})
  94. }
  95. func (manager *SClouduserManager) FilterByUniqValues(q *sqlchemy.SQuery, values jsonutils.JSONObject) *sqlchemy.SQuery {
  96. accountId, _ := values.GetString("cloudaccount_id")
  97. if len(accountId) > 0 {
  98. q = q.Equals("cloudaccount_id", accountId)
  99. }
  100. return q
  101. }
  102. // 公有云用户列表
  103. func (manager *SClouduserManager) ListItemFilter(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential, query api.ClouduserListInput) (*sqlchemy.SQuery, error) {
  104. var err error
  105. q, err = manager.SStatusDomainLevelUserResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusDomainLevelUserResourceListInput)
  106. if err != nil {
  107. return nil, err
  108. }
  109. q, err = manager.SCloudaccountResourceBaseManager.ListItemFilter(ctx, q, userCred, query.CloudaccountResourceListInput)
  110. if err != nil {
  111. return nil, err
  112. }
  113. q, err = manager.SCloudproviderResourceBaseManager.ListItemFilter(ctx, q, userCred, query.CloudproviderResourceListInput)
  114. if err != nil {
  115. return nil, err
  116. }
  117. if len(query.CloudpolicyId) > 0 {
  118. _, err = CloudpolicyManager.FetchById(query.CloudpolicyId)
  119. if err != nil {
  120. if errors.Cause(err) == sql.ErrNoRows {
  121. return nil, httperrors.NewResourceNotFoundError2("cloudpolicy", query.CloudpolicyId)
  122. }
  123. return q, httperrors.NewGeneralError(errors.Wrap(err, "CloudpolicyManager.FetchById"))
  124. }
  125. sq := ClouduserPolicyManager.Query("clouduser_id").Equals("cloudpolicy_id", query.CloudpolicyId)
  126. q = q.In("id", sq.SubQuery())
  127. }
  128. if len(query.CloudgroupId) > 0 {
  129. _, err = CloudgroupManager.FetchById(query.CloudgroupId)
  130. if err != nil {
  131. if errors.Cause(err) == sql.ErrNoRows {
  132. return nil, httperrors.NewResourceNotFoundError2("cloudgroup", query.CloudgroupId)
  133. }
  134. return q, httperrors.NewGeneralError(errors.Wrap(err, "CloudgroupManager.FetchById"))
  135. }
  136. sq := CloudgroupUserManager.Query("clouduser_id").Equals("cloudgroup_id", query.CloudgroupId)
  137. q = q.In("id", sq.SubQuery())
  138. }
  139. return q, nil
  140. }
  141. // +onecloud:swagger-gen-ignore
  142. func (self *SClouduser) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ClouduserUpdateInput) (api.ClouduserUpdateInput, error) {
  143. return input, nil
  144. }
  145. func (manager *SClouduserManager) OrderByExtraFields(
  146. ctx context.Context,
  147. q *sqlchemy.SQuery,
  148. userCred mcclient.TokenCredential,
  149. query api.ClouduserListInput,
  150. ) (*sqlchemy.SQuery, error) {
  151. var err error
  152. q, err = manager.SStatusDomainLevelUserResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusDomainLevelUserResourceListInput)
  153. if err != nil {
  154. return nil, errors.Wrap(err, "SStatusDomainLevelUserResourceBaseManager.OrderByExtraFields")
  155. }
  156. return q, nil
  157. }
  158. func (manager *SClouduserManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
  159. var err error
  160. q, err = manager.SStatusDomainLevelUserResourceBaseManager.QueryDistinctExtraField(q, field)
  161. if err == nil {
  162. return q, nil
  163. }
  164. switch field {
  165. case "manager":
  166. managerQuery := CloudproviderManager.Query("name", "id").SubQuery()
  167. q.AppendField(managerQuery.Field("name", field)).Distinct()
  168. q = q.Join(managerQuery, sqlchemy.Equals(q.Field("manager_id"), managerQuery.Field("id")))
  169. return q, nil
  170. case "account":
  171. accountQuery := CloudaccountManager.Query("name", "id").SubQuery()
  172. providers := CloudproviderManager.Query("id", "cloudaccount_id").SubQuery()
  173. q.AppendField(accountQuery.Field("name", field)).Distinct()
  174. q = q.Join(providers, sqlchemy.Equals(q.Field("manager_id"), providers.Field("id")))
  175. q = q.Join(accountQuery, sqlchemy.Equals(providers.Field("cloudaccount_id"), accountQuery.Field("id")))
  176. return q, nil
  177. case "provider", "brand":
  178. accountQuery := CloudaccountManager.Query(field, "id").Distinct().SubQuery()
  179. providers := CloudproviderManager.Query("id", "cloudaccount_id").SubQuery()
  180. q.AppendField(accountQuery.Field(field)).Distinct()
  181. q = q.Join(providers, sqlchemy.Equals(q.Field("manager_id"), providers.Field("id")))
  182. q = q.Join(accountQuery, sqlchemy.Equals(providers.Field("cloudaccount_id"), accountQuery.Field("id")))
  183. return q, nil
  184. }
  185. return q, httperrors.ErrNotFound
  186. }
  187. // 获取公有云用户详情
  188. func (manager *SClouduserManager) FetchCustomizeColumns(
  189. ctx context.Context,
  190. userCred mcclient.TokenCredential,
  191. query jsonutils.JSONObject,
  192. objs []interface{},
  193. fields stringutils2.SSortedStrings,
  194. isList bool,
  195. ) []api.ClouduserDetails {
  196. rows := make([]api.ClouduserDetails, len(objs))
  197. userRows := manager.SStatusDomainLevelUserResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  198. acRows := manager.SCloudaccountResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  199. mRows := manager.SCloudproviderResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
  200. userIds := make([]string, len(objs))
  201. for i := range rows {
  202. rows[i] = api.ClouduserDetails{
  203. StatusDomainLevelUserResourceDetails: userRows[i],
  204. CloudaccountResourceDetails: acRows[i],
  205. CloudproviderResourceDetails: mRows[i],
  206. }
  207. user := objs[i].(*SClouduser)
  208. userIds[i] = user.Id
  209. }
  210. groupSQ := CloudgroupManager.Query().SubQuery()
  211. ugQ := CloudgroupUserManager.Query().SubQuery()
  212. q := groupSQ.Query(
  213. groupSQ.Field("id"),
  214. groupSQ.Field("name"),
  215. ugQ.Field("clouduser_id"),
  216. ).
  217. Join(ugQ, sqlchemy.Equals(ugQ.Field("cloudgroup_id"), groupSQ.Field("id"))).
  218. Filter(sqlchemy.In(ugQ.Field("clouduser_id"), userIds))
  219. baseInfo := []struct {
  220. Id string
  221. Name string
  222. ClouduserId string
  223. }{}
  224. err := q.All(&baseInfo)
  225. if err != nil {
  226. log.Errorf("query user group info error: %v", err)
  227. return rows
  228. }
  229. groups := map[string][]api.SCloudIdBaseResource{}
  230. for _, group := range baseInfo {
  231. _, ok := groups[group.ClouduserId]
  232. if !ok {
  233. groups[group.ClouduserId] = []api.SCloudIdBaseResource{}
  234. }
  235. groups[group.ClouduserId] = append(groups[group.ClouduserId], api.SCloudIdBaseResource{
  236. Id: group.Id,
  237. Name: group.Name,
  238. })
  239. }
  240. policySQ := CloudpolicyManager.Query().SubQuery()
  241. upQ := ClouduserPolicyManager.Query().SubQuery()
  242. q = policySQ.Query(
  243. policySQ.Field("id"),
  244. policySQ.Field("name"),
  245. upQ.Field("clouduser_id"),
  246. ).
  247. Join(upQ, sqlchemy.Equals(upQ.Field("cloudpolicy_id"), policySQ.Field("id"))).
  248. Filter(sqlchemy.In(upQ.Field("clouduser_id"), userIds))
  249. baseInfo = []struct {
  250. Id string
  251. Name string
  252. ClouduserId string
  253. }{}
  254. err = q.All(&baseInfo)
  255. if err != nil {
  256. log.Errorf("query user policy info error: %v", err)
  257. return rows
  258. }
  259. policies := map[string][]api.SCloudIdBaseResource{}
  260. for _, policy := range baseInfo {
  261. _, ok := policies[policy.ClouduserId]
  262. if !ok {
  263. policies[policy.ClouduserId] = []api.SCloudIdBaseResource{}
  264. }
  265. policies[policy.ClouduserId] = append(policies[policy.ClouduserId], api.SCloudIdBaseResource{
  266. Id: policy.Id,
  267. Name: policy.Name,
  268. })
  269. }
  270. for i := range rows {
  271. rows[i].Cloudgroups, _ = groups[userIds[i]]
  272. rows[i].CloudgroupCount = len(rows[i].Cloudgroups)
  273. rows[i].Cloudpolicies, _ = policies[userIds[i]]
  274. rows[i].CloudpolicyCount = len(rows[i].Cloudpolicies)
  275. }
  276. return rows
  277. }
  278. func (self *SClouduser) GetProvider() (cloudprovider.ICloudProvider, error) {
  279. if len(self.ManagerId) > 0 {
  280. provider, err := self.GetCloudprovider()
  281. if err != nil {
  282. return nil, err
  283. }
  284. return provider.GetProvider()
  285. }
  286. if len(self.CloudaccountId) > 0 {
  287. account, err := self.GetCloudaccount()
  288. if err != nil {
  289. if err != nil {
  290. return nil, err
  291. }
  292. }
  293. return account.GetProvider()
  294. }
  295. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty account info")
  296. }
  297. func (self *SClouduser) GetIClouduser() (cloudprovider.IClouduser, error) {
  298. if len(self.ExternalId) == 0 {
  299. return nil, errors.Wrapf(cloudprovider.ErrNotFound, "empty external_id")
  300. }
  301. provider, err := self.GetProvider()
  302. if err != nil {
  303. return nil, errors.Wrap(err, "GetProvider")
  304. }
  305. return provider.GetIClouduserByName(self.Name)
  306. }
  307. // 创建公有云用户
  308. func (manager *SClouduserManager) ValidateCreateData(
  309. ctx context.Context,
  310. userCred mcclient.TokenCredential,
  311. ownerId mcclient.IIdentityProvider,
  312. query jsonutils.JSONObject,
  313. input *api.ClouduserCreateInput,
  314. ) (*api.ClouduserCreateInput, error) {
  315. if len(input.ManagerId) == 0 {
  316. return nil, httperrors.NewMissingParameterError("manager_id")
  317. }
  318. providerObj, err := validators.ValidateModel(ctx, userCred, CloudproviderManager, &input.ManagerId)
  319. if err != nil {
  320. return nil, err
  321. }
  322. provider := providerObj.(*SCloudprovider)
  323. input.CloudaccountId = provider.CloudaccountId
  324. input.Status = apis.STATUS_CREATING
  325. account, err := provider.GetCloudaccount()
  326. if err != nil {
  327. return input, httperrors.NewGeneralError(errors.Wrap(err, "GetCloudaccount"))
  328. }
  329. input.ProjectDomainId = account.DomainId
  330. // 只有系统管理员和账号所在的域管理员可以创建子用户
  331. if !((account.DomainId == userCred.GetProjectDomainId() && db.IsDomainAllowCreate(userCred, manager).Result.IsAllow()) || userCred.HasSystemAdminPrivilege()) {
  332. return input, httperrors.NewForbiddenError("forbidden to create clouduser for cloudaccount %s", account.Name)
  333. }
  334. input.StatusDomainLevelUserResourceCreateInput, err = manager.SStatusDomainLevelUserResourceBaseManager.ValidateCreateData(ctx, userCred, ownerId, query, input.StatusDomainLevelUserResourceCreateInput)
  335. if err != nil {
  336. return input, err
  337. }
  338. if len(input.Email) > 0 && !regutils.MatchEmail(input.Email) {
  339. return input, httperrors.NewInputParameterError("invalid email address")
  340. }
  341. if len(input.OwnerId) > 0 {
  342. user, err := db.UserCacheManager.FetchUserById(ctx, input.OwnerId)
  343. if err != nil {
  344. return input, errors.Wrap(err, "FetchUserById")
  345. }
  346. input.OwnerId = user.Id
  347. if len(input.Name) == 0 {
  348. input.Name = user.Name
  349. }
  350. }
  351. driver, err := provider.GetDriver()
  352. if err != nil {
  353. return nil, err
  354. }
  355. input, err = driver.ValidateCreateClouduser(ctx, userCred, provider, input)
  356. if err != nil {
  357. return nil, err
  358. }
  359. isConsoleLogin := true
  360. if input.IsConsoleLogin != nil && !*input.IsConsoleLogin {
  361. isConsoleLogin = false
  362. }
  363. input.IsConsoleLogin = &isConsoleLogin
  364. if isConsoleLogin && len(input.Password) == 0 {
  365. input.Password = seclib2.RandomPassword2(12)
  366. }
  367. if len(input.Password) > 0 {
  368. err = seclib2.ValidatePassword(input.Password)
  369. if err != nil {
  370. return input, err
  371. }
  372. }
  373. return input, nil
  374. }
  375. func (self *SClouduser) SavePassword(password string) error {
  376. sec, err := utils.EncryptAESBase64(self.Id, password)
  377. if err != nil {
  378. return err
  379. }
  380. _, err = db.Update(self, func() error {
  381. self.Secret = sec
  382. return nil
  383. })
  384. return err
  385. }
  386. func (self *SClouduser) GetPassword() (string, error) {
  387. return utils.DescryptAESBase64(self.Id, self.Secret)
  388. }
  389. func (self *SClouduser) PostCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) {
  390. input := api.ClouduserCreateInput{}
  391. data.Unmarshal(&input)
  392. if len(input.Password) > 0 {
  393. self.SavePassword(input.Password)
  394. }
  395. for _, policyId := range input.CloudpolicyIds {
  396. self.attachPolicy(policyId)
  397. }
  398. for _, groupId := range input.CloudgroupIds {
  399. self.joinGroup(groupId)
  400. }
  401. self.StartClouduserCreateTask(ctx, userCred, input.Notify, "")
  402. }
  403. func (self *SClouduser) GetCloudprovider() (*SCloudprovider, error) {
  404. provider, err := CloudproviderManager.FetchById(self.ManagerId)
  405. if err != nil {
  406. return nil, err
  407. }
  408. return provider.(*SCloudprovider), nil
  409. }
  410. func (self *SClouduser) StartClouduserCreateTask(ctx context.Context, userCred mcclient.TokenCredential, notify bool, parentTaskId string) error {
  411. params := jsonutils.NewDict()
  412. params.Set("notify", jsonutils.NewBool(notify))
  413. task, err := taskman.TaskManager.NewTask(ctx, "ClouduserCreateTask", self, userCred, params, parentTaskId, "", nil)
  414. if err != nil {
  415. return errors.Wrap(err, "NewTask")
  416. }
  417. self.SetStatus(ctx, userCred, apis.STATUS_CREATING, "")
  418. return task.ScheduleRun(nil)
  419. }
  420. func (self *SClouduser) SyncWithClouduser(ctx context.Context, userCred mcclient.TokenCredential, iUser cloudprovider.IClouduser) error {
  421. _, err := db.Update(self, func() error {
  422. self.Name = iUser.GetName()
  423. self.Status = apis.STATUS_AVAILABLE
  424. switch iUser.IsConsoleLogin() {
  425. case true:
  426. self.IsConsoleLogin = tristate.True
  427. case false:
  428. self.IsConsoleLogin = tristate.False
  429. }
  430. account, err := self.GetCloudaccount()
  431. if err != nil {
  432. return errors.Wrap(err, "GetCloudaccount")
  433. }
  434. self.DomainId = account.DomainId
  435. return nil
  436. })
  437. return err
  438. }
  439. func (self *SClouduser) detachPolicy(policyId string) error {
  440. policies := []SClouduserPolicy{}
  441. q := ClouduserPolicyManager.Query().Equals("clouduser_id", self.Id).Equals("cloudpolicy_id", policyId)
  442. err := db.FetchModelObjects(ClouduserPolicyManager, q, &policies)
  443. if err != nil {
  444. return errors.Wrap(err, "db.FetchModelObjects")
  445. }
  446. for i := range policies {
  447. err = policies[i].Delete(context.Background(), nil)
  448. if err != nil {
  449. return errors.Wrap(err, "Delete")
  450. }
  451. }
  452. return nil
  453. }
  454. func (self *SClouduser) SyncCloudpolicies(ctx context.Context, userCred mcclient.TokenCredential, iUser cloudprovider.IClouduser) {
  455. iPolicies, err := iUser.GetICloudpolicies()
  456. if err == nil {
  457. result := self.SyncPolicies(ctx, userCred, iPolicies)
  458. log.Infof("SyncCloudpolicies for user %s(%s) result: %s", self.Name, self.Id, result.Result())
  459. }
  460. }
  461. func (self *SClouduser) SyncCloudgroups(ctx context.Context, userCred mcclient.TokenCredential, iUser cloudprovider.IClouduser) {
  462. iGroups, err := iUser.GetICloudgroups()
  463. if err == nil {
  464. result := self.SyncGroups(ctx, userCred, iGroups)
  465. log.Infof("SyncCloudgroups for user %s(%s) result: %s", self.Name, self.Id, result.Result())
  466. }
  467. }
  468. func (self *SClouduser) SyncPolicies(ctx context.Context, userCred mcclient.TokenCredential, iPolicies []cloudprovider.ICloudpolicy) compare.SyncResult {
  469. result := compare.SyncResult{}
  470. dbPolicies, err := self.GetCloudpolicies()
  471. if err != nil {
  472. result.Error(errors.Wrapf(err, "GetCloudpolicies"))
  473. return result
  474. }
  475. removed := make([]SCloudpolicy, 0)
  476. commondb := make([]SCloudpolicy, 0)
  477. commonext := make([]cloudprovider.ICloudpolicy, 0)
  478. added := make([]cloudprovider.ICloudpolicy, 0)
  479. err = compare.CompareSets(dbPolicies, iPolicies, &removed, &commondb, &commonext, &added)
  480. if err != nil {
  481. result.Error(errors.Wrap(err, "compare.CompareSets"))
  482. return result
  483. }
  484. for i := 0; i < len(removed); i++ {
  485. err := self.detachPolicy(removed[i].Id)
  486. if err != nil {
  487. result.DeleteError(err)
  488. continue
  489. }
  490. result.Delete()
  491. }
  492. result.UpdateCnt = len(commondb)
  493. for i := 0; i < len(added); i++ {
  494. policy, err := db.FetchByExternalIdAndManagerId(CloudpolicyManager, added[i].GetGlobalId(), func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  495. if len(self.ManagerId) > 0 {
  496. return q.Equals("manager_id", self.ManagerId)
  497. }
  498. return q.Equals("cloudaccount_id", self.CloudaccountId)
  499. })
  500. if err != nil {
  501. result.AddError(errors.Wrapf(err, "add %s", added[i].GetName()))
  502. continue
  503. }
  504. err = self.attachPolicy(policy.GetId())
  505. if err != nil {
  506. result.AddError(err)
  507. continue
  508. }
  509. result.Add()
  510. }
  511. return result
  512. }
  513. func (self *SClouduser) SyncGroups(ctx context.Context, userCred mcclient.TokenCredential, iGroups []cloudprovider.ICloudgroup) compare.SyncResult {
  514. result := compare.SyncResult{}
  515. dbGroups, err := self.GetCloudgroups()
  516. if err != nil {
  517. result.Error(errors.Wrap(err, "GetCloudgroupcaches"))
  518. return result
  519. }
  520. removed := make([]SCloudgroup, 0)
  521. commondb := make([]SCloudgroup, 0)
  522. commonext := make([]cloudprovider.ICloudgroup, 0)
  523. added := make([]cloudprovider.ICloudgroup, 0)
  524. err = compare.CompareSets(dbGroups, iGroups, &removed, &commondb, &commonext, &added)
  525. if err != nil {
  526. result.Error(errors.Wrap(err, "compare.CompareSets"))
  527. return result
  528. }
  529. result.UpdateCnt = len(commondb)
  530. for i := 0; i < len(added); i++ {
  531. group, err := db.FetchByExternalIdAndManagerId(CloudgroupManager, added[i].GetGlobalId(), func(q *sqlchemy.SQuery) *sqlchemy.SQuery {
  532. if len(self.ManagerId) > 0 {
  533. return q.Equals("manager_id", self.ManagerId)
  534. }
  535. return q.Equals("cloudaccount_id", self.CloudaccountId)
  536. })
  537. if err != nil {
  538. result.AddError(errors.Wrapf(err, "FetchByExternalId(%s)", added[i].GetGlobalId()))
  539. continue
  540. }
  541. err = self.joinGroup(group.GetId())
  542. if err != nil {
  543. result.AddError(errors.Wrap(err, "joinGroup"))
  544. continue
  545. }
  546. result.Add()
  547. }
  548. for i := 0; i < len(removed); i++ {
  549. err = self.leaveGroup(removed[i].Id)
  550. if err != nil {
  551. result.DeleteError(errors.Wrap(err, "leaveGroup"))
  552. continue
  553. }
  554. result.Delete()
  555. }
  556. return result
  557. }
  558. // 删除公有云用户
  559. func (self *SClouduser) CustomizeDelete(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
  560. params := jsonutils.NewDict()
  561. return self.StartClouduserDeleteTask(ctx, userCred, params, "")
  562. }
  563. func (self *SClouduser) StartClouduserDeleteTask(ctx context.Context, userCred mcclient.TokenCredential, data *jsonutils.JSONDict, parentTaskId string) error {
  564. task, err := taskman.TaskManager.NewTask(ctx, "ClouduserDeleteTask", self, userCred, data, parentTaskId, "", nil)
  565. if err != nil {
  566. return errors.Wrap(err, "NewTask")
  567. }
  568. self.SetStatus(ctx, userCred, apis.STATUS_DELETING, "")
  569. return task.ScheduleRun(nil)
  570. }
  571. func (self *SClouduser) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
  572. return nil
  573. }
  574. func (self *SClouduser) GetClouduserPolicies() ([]SClouduserPolicy, error) {
  575. policies := []SClouduserPolicy{}
  576. q := ClouduserPolicyManager.Query().Equals("clouduser_id", self.Id)
  577. err := db.FetchModelObjects(ClouduserPolicyManager, q, &policies)
  578. if err != nil {
  579. return nil, errors.Wrap(err, "db.FetchModelObjects")
  580. }
  581. return policies, nil
  582. }
  583. func (self *SClouduser) GetCloudpolicyQuery() *sqlchemy.SQuery {
  584. sq := ClouduserPolicyManager.Query("cloudpolicy_id").Equals("clouduser_id", self.Id)
  585. return CloudpolicyManager.Query().In("id", sq.SubQuery())
  586. }
  587. func (self *SClouduser) GetCloudpolicies() ([]SCloudpolicy, error) {
  588. policies := []SCloudpolicy{}
  589. q := self.GetCloudpolicyQuery()
  590. err := db.FetchModelObjects(CloudpolicyManager, q, &policies)
  591. if err != nil {
  592. return nil, errors.Wrap(err, "db.FetchModelObjects")
  593. }
  594. return policies, nil
  595. }
  596. func (self *SClouduser) joinGroup(groupId string) error {
  597. gu := &SCloudgroupUser{}
  598. gu.SetModelManager(CloudgroupUserManager, gu)
  599. gu.ClouduserId = self.Id
  600. gu.CloudgroupId = groupId
  601. return CloudgroupUserManager.TableSpec().Insert(context.Background(), gu)
  602. }
  603. func (self *SClouduser) leaveGroup(groupId string) error {
  604. ugs := []SCloudgroupUser{}
  605. q := CloudgroupUserManager.Query().Equals("clouduser_id", self.Id).Equals("cloudgroup_id", groupId)
  606. err := db.FetchModelObjects(CloudgroupUserManager, q, &ugs)
  607. if err != nil {
  608. return errors.Wrap(err, "FetchModelObjects")
  609. }
  610. for i := range ugs {
  611. err = ugs[i].Delete(context.Background(), nil)
  612. if err != nil {
  613. return errors.Wrapf(err, "ug %d Delete", ugs[i].RowId)
  614. }
  615. }
  616. return nil
  617. }
  618. func (self *SClouduser) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
  619. return self.purge(ctx)
  620. }
  621. func (self *SClouduser) GetCloudpolicy(policyId string) (*SCloudpolicy, error) {
  622. policies := []SCloudpolicy{}
  623. q := self.GetCloudpolicyQuery().Equals("id", policyId)
  624. err := db.FetchModelObjects(CloudpolicyManager, q, &policies)
  625. if err != nil {
  626. return nil, errors.Wrap(err, "db.FetchModelObjects")
  627. }
  628. if len(policies) > 1 {
  629. return nil, sqlchemy.ErrDuplicateEntry
  630. }
  631. if len(policies) == 0 {
  632. return nil, sql.ErrNoRows
  633. }
  634. return &policies[0], nil
  635. }
  636. // 设置用户权限列表(全量覆盖)
  637. // 用户状态必须为: available
  638. func (self *SClouduser) PerformSetPolicies(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ClouduserSetPoliciesInput) (jsonutils.JSONObject, error) {
  639. if self.Status != apis.STATUS_AVAILABLE {
  640. return nil, httperrors.NewInvalidStatusError("Can not set policies in status %s", self.Status)
  641. }
  642. policies, err := self.GetCloudpolicies()
  643. if err != nil {
  644. return nil, httperrors.NewGeneralError(err)
  645. }
  646. policyMaps := map[string]*SCloudpolicy{}
  647. local := set.New(set.ThreadSafe)
  648. for i := range policies {
  649. local.Add(policies[i].Id)
  650. policyMaps[policies[i].Id] = &policies[i]
  651. }
  652. newP := set.New(set.ThreadSafe)
  653. for i := range input.CloudpolicyIds {
  654. policyObj, err := validators.ValidateModel(ctx, userCred, CloudpolicyManager, &input.CloudpolicyIds[i])
  655. if err != nil {
  656. return nil, err
  657. }
  658. policy := policyObj.(*SCloudpolicy)
  659. if policy.ManagerId != self.ManagerId || policy.CloudaccountId != policy.CloudaccountId {
  660. return nil, httperrors.NewConflictError("policy %s(%s) and user not with same provider", policy.Name, policy.Id)
  661. }
  662. newP.Add(policy.Id)
  663. }
  664. add, del := []api.SPolicy{}, []api.SPolicy{}
  665. for _, id := range set.Difference(local, newP).List() {
  666. policy := policyMaps[id.(string)]
  667. del = append(del, api.SPolicy{
  668. Name: policy.Name,
  669. ExternalId: policy.ExternalId,
  670. PolicyType: policy.PolicyType,
  671. })
  672. }
  673. for _, id := range set.Difference(newP, local).List() {
  674. policy := policyMaps[id.(string)]
  675. add = append(add, api.SPolicy{
  676. Name: policy.Name,
  677. ExternalId: policy.ExternalId,
  678. PolicyType: policy.PolicyType,
  679. })
  680. }
  681. return nil, self.StartSetPoliciesTask(ctx, userCred, add, del, "")
  682. }
  683. func (self *SClouduser) StartSetPoliciesTask(ctx context.Context, userCred mcclient.TokenCredential, add, del []api.SPolicy, parentTaskId string) error {
  684. params := jsonutils.NewDict()
  685. if len(add) > 0 {
  686. params.Set("add", jsonutils.Marshal(add))
  687. }
  688. if len(del) > 0 {
  689. params.Set("del", jsonutils.Marshal(del))
  690. }
  691. task, err := taskman.TaskManager.NewTask(ctx, "ClouduserSetPoliciesTask", self, userCred, params, parentTaskId, "", nil)
  692. if err != nil {
  693. return errors.Wrap(err, "NewTask")
  694. }
  695. self.SetStatus(ctx, userCred, apis.STATUS_SYNC_STATUS, "")
  696. return task.ScheduleRun(nil)
  697. }
  698. // 设置用户权限组列表(全量覆盖)
  699. // 用户状态必须为: available
  700. func (self *SClouduser) PerformSetGroups(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ClouduserSetGroupsInput) (jsonutils.JSONObject, error) {
  701. if self.Status != apis.STATUS_AVAILABLE {
  702. return nil, httperrors.NewInvalidStatusError("Can not set groups in status %s", self.Status)
  703. }
  704. groups, err := self.GetCloudgroups()
  705. if err != nil {
  706. return nil, httperrors.NewGeneralError(errors.Wrap(err, "GetCloudgroups"))
  707. }
  708. local := set.New(set.ThreadSafe)
  709. groupMaps := map[string]*SCloudgroup{}
  710. for i := range groups {
  711. local.Add(groups[i].Id)
  712. groupMaps[groups[i].Id] = &groups[i]
  713. }
  714. newG := set.New(set.ThreadSafe)
  715. for i := range input.CloudgroupIds {
  716. groupObj, err := validators.ValidateModel(ctx, userCred, CloudgroupManager, &input.CloudgroupIds[i])
  717. if err != nil {
  718. return nil, err
  719. }
  720. group := groupObj.(*SCloudgroup)
  721. if group.ManagerId != self.ManagerId || group.CloudaccountId != self.CloudaccountId {
  722. return nil, httperrors.NewConflictError("group and user do not belong to the same account")
  723. }
  724. newG.Add(group.Id)
  725. groupMaps[group.Id] = group
  726. }
  727. add, del := []api.SGroup{}, []api.SGroup{}
  728. for _, id := range set.Difference(local, newG).List() {
  729. group := groupMaps[id.(string)]
  730. del = append(del, api.SGroup{
  731. Id: group.Id,
  732. Name: group.Name,
  733. })
  734. }
  735. for _, id := range set.Difference(newG, local).List() {
  736. group := groupMaps[id.(string)]
  737. add = append(add, api.SGroup{
  738. Id: group.Id,
  739. Name: group.Name,
  740. })
  741. }
  742. return nil, self.StartSetGroupsTask(ctx, userCred, add, del, "")
  743. }
  744. func (self *SClouduser) StartSetGroupsTask(ctx context.Context, userCred mcclient.TokenCredential, add, del []api.SGroup, parentTaskId string) error {
  745. params := jsonutils.NewDict()
  746. if len(add) > 0 {
  747. params.Set("add", jsonutils.Marshal(add))
  748. }
  749. if len(del) > 0 {
  750. params.Set("del", jsonutils.Marshal(del))
  751. }
  752. task, err := taskman.TaskManager.NewTask(ctx, "ClouduserSetGroupsTask", self, userCred, params, parentTaskId, "", nil)
  753. if err != nil {
  754. return errors.Wrap(err, "NewTask")
  755. }
  756. self.SetStatus(ctx, userCred, apis.STATUS_SYNC_STATUS, "")
  757. return task.ScheduleRun(nil)
  758. }
  759. // 将用户加入权限组
  760. // 用户状态必须为: available
  761. func (self *SClouduser) PerformJoinGroup(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ClouduserJoinGroupInput) (jsonutils.JSONObject, error) {
  762. if self.Status != apis.STATUS_AVAILABLE {
  763. return nil, httperrors.NewInvalidStatusError("Can not join group in status %s", self.Status)
  764. }
  765. groupObj, err := validators.ValidateModel(ctx, userCred, CloudgroupManager, &input.CloudgroupId)
  766. if err != nil {
  767. return nil, err
  768. }
  769. group := groupObj.(*SCloudgroup)
  770. if group.ManagerId != self.ManagerId || group.CloudaccountId != self.CloudaccountId {
  771. return nil, httperrors.NewConflictError("group and user do not belong to the same account")
  772. }
  773. add := []api.SGroup{
  774. {
  775. Id: group.Id,
  776. Name: group.Name,
  777. },
  778. }
  779. return nil, self.StartSetGroupsTask(ctx, userCred, add, nil, "")
  780. }
  781. // 将用户从权限组中移除
  782. // 用户状态必须为: available
  783. func (self *SClouduser) PerformLeaveGroup(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ClouduserLeaveGroupInput) (jsonutils.JSONObject, error) {
  784. if self.Status != apis.STATUS_AVAILABLE {
  785. return nil, httperrors.NewInvalidStatusError("Can not leave group in status %s", self.Status)
  786. }
  787. groupObj, err := validators.ValidateModel(ctx, userCred, CloudgroupManager, &input.CloudgroupId)
  788. if err != nil {
  789. return nil, err
  790. }
  791. group := groupObj.(*SCloudgroup)
  792. _, err = self.GetCloudgroup(group.Id)
  793. if err != nil && errors.Cause(err) == sql.ErrNoRows {
  794. return nil, nil
  795. }
  796. del := []api.SGroup{
  797. {
  798. Id: group.Id,
  799. Name: group.Name,
  800. },
  801. }
  802. return nil, self.StartSetGroupsTask(ctx, userCred, nil, del, "")
  803. }
  804. // 绑定用户权限
  805. // 用户状态必须为: available
  806. func (self *SClouduser) PerformAttachPolicy(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ClouduserAttachPolicyInput) (jsonutils.JSONObject, error) {
  807. if self.Status != apis.STATUS_AVAILABLE {
  808. return nil, httperrors.NewInvalidStatusError("Can not detach policy in status %s", self.Status)
  809. }
  810. policyObj, err := validators.ValidateModel(ctx, userCred, CloudpolicyManager, &input.CloudpolicyId)
  811. if err != nil {
  812. return nil, err
  813. }
  814. policy := policyObj.(*SCloudpolicy)
  815. if policy.ManagerId != self.ManagerId || policy.CloudaccountId != self.CloudaccountId {
  816. return nil, httperrors.NewConflictError("policy and user do not belong to the same account")
  817. }
  818. _, err = self.GetCloudpolicy(input.CloudpolicyId)
  819. if err == nil || errors.Cause(err) == sqlchemy.ErrDuplicateEntry {
  820. return nil, httperrors.NewDuplicateResourceError("policy %s has aleady attach this user", input.CloudpolicyId)
  821. }
  822. add := []api.SPolicy{
  823. {
  824. Name: policy.Name,
  825. ExternalId: policy.ExternalId,
  826. PolicyType: policy.PolicyType,
  827. },
  828. }
  829. return nil, self.StartSetPoliciesTask(ctx, userCred, add, nil, "")
  830. }
  831. func (self *SClouduser) attachPolicy(policyId string) error {
  832. up := &SClouduserPolicy{}
  833. up.SetModelManager(ClouduserPolicyManager, up)
  834. up.CloudpolicyId = policyId
  835. up.ClouduserId = self.Id
  836. return ClouduserPolicyManager.TableSpec().Insert(context.Background(), up)
  837. }
  838. // 解绑用户权限
  839. // 用户状态必须为: available
  840. func (self *SClouduser) PerformDetachPolicy(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ClouduserDetachPolicyInput) (jsonutils.JSONObject, error) {
  841. if self.Status != apis.STATUS_AVAILABLE {
  842. return nil, httperrors.NewInvalidStatusError("Can not detach policy in status %s", self.Status)
  843. }
  844. policObj, err := validators.ValidateModel(ctx, userCred, CloudpolicyManager, &input.CloudpolicyId)
  845. if err != nil {
  846. return nil, err
  847. }
  848. policy := policObj.(*SCloudpolicy)
  849. _, err = self.GetCloudpolicy(input.CloudpolicyId)
  850. if err != nil && errors.Cause(err) == sql.ErrNoRows {
  851. return nil, nil
  852. }
  853. del := []api.SPolicy{
  854. {
  855. Name: policy.Name,
  856. ExternalId: policy.ExternalId,
  857. PolicyType: policy.PolicyType,
  858. },
  859. }
  860. return nil, self.StartSetPoliciesTask(ctx, userCred, nil, del, "")
  861. }
  862. // 同步用户状态
  863. func (self *SClouduser) PerformSyncstatus(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ClouduserSyncstatusInput) (jsonutils.JSONObject, error) {
  864. return nil, self.StartClouduserSyncstatusTask(ctx, userCred, "")
  865. }
  866. func (self *SClouduser) StartClouduserSyncstatusTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
  867. task, err := taskman.TaskManager.NewTask(ctx, "ClouduserSyncstatusTask", self, userCred, nil, parentTaskId, "", nil)
  868. if err != nil {
  869. return errors.Wrap(err, "NewTask")
  870. }
  871. self.SetStatus(ctx, userCred, apis.STATUS_SYNC_STATUS, "")
  872. return task.ScheduleRun(nil)
  873. }
  874. // 重置用户密码
  875. // 用户状态必须为: available
  876. func (self *SClouduser) PerformResetPassword(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ClouduserResetPasswordInput) (jsonutils.JSONObject, error) {
  877. if self.Status != apis.STATUS_AVAILABLE {
  878. return nil, httperrors.NewInvalidStatusError("Can not reset password in status %s", self.Status)
  879. }
  880. return nil, self.StartClouduserResetPasswordTask(ctx, userCred, input.Password, "")
  881. }
  882. func (self *SClouduser) StartClouduserResetPasswordTask(ctx context.Context, userCred mcclient.TokenCredential, password string, parentTaskId string) error {
  883. if len(password) == 0 {
  884. password = seclib2.RandomPassword2(12)
  885. }
  886. params := jsonutils.Marshal(map[string]string{"password": password}).(*jsonutils.JSONDict)
  887. task, err := taskman.TaskManager.NewTask(ctx, "ClouduserResetPasswordTask", self, userCred, params, parentTaskId, "", nil)
  888. if err != nil {
  889. return errors.Wrap(err, "NewTask")
  890. }
  891. self.SetStatus(ctx, userCred, api.CLOUD_USER_STATUS_RESET_PASSWORD, "")
  892. return task.ScheduleRun(nil)
  893. }
  894. // 变更子账号所属本地用户
  895. func (self *SClouduser) PerformChangeOwner(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ClouduserChangeOwnerInput) (jsonutils.JSONObject, error) {
  896. oldUserId := self.OwnerId
  897. newUserId := ""
  898. if len(input.UserId) > 0 {
  899. user, err := db.UserCacheManager.FetchUserById(ctx, input.UserId)
  900. if err != nil {
  901. return nil, httperrors.NewGeneralError(errors.Wrapf(err, "Not found user %s", input.UserId))
  902. }
  903. newUserId = user.Id
  904. }
  905. _, err := db.Update(self, func() error {
  906. self.OwnerId = newUserId
  907. return nil
  908. })
  909. if err != nil {
  910. return nil, httperrors.NewGeneralError(errors.Wrapf(err, "db.Update"))
  911. }
  912. logclient.AddSimpleActionLog(self, logclient.ACT_CHANGE_OWNER, map[string]interface{}{"old": oldUserId, "newUserId": newUserId}, userCred, true)
  913. return nil, self.StartClouduserResetPasswordTask(ctx, userCred, "", "")
  914. }
  915. func (self *SClouduser) GetCloudgroupQuery() *sqlchemy.SQuery {
  916. sq := CloudgroupUserManager.Query("cloudgroup_id").Equals("clouduser_id", self.Id)
  917. return CloudgroupManager.Query().In("id", sq.SubQuery())
  918. }
  919. func (self *SClouduser) GetCloudgroupCount() (int, error) {
  920. return self.GetCloudgroupQuery().CountWithError()
  921. }
  922. func (self *SClouduser) GetCloudgroup(id string) (*SCloudgroup, error) {
  923. q := self.GetCloudgroupQuery().Equals("id", id)
  924. groups := []SCloudgroup{}
  925. err := db.FetchModelObjects(CloudgroupManager, q, &groups)
  926. if err != nil {
  927. return nil, errors.Wrap(err, "db.FetchModelObjects")
  928. }
  929. if len(groups) > 1 {
  930. return nil, sqlchemy.ErrDuplicateEntry
  931. }
  932. if len(groups) == 0 {
  933. return nil, sql.ErrNoRows
  934. }
  935. return &groups[0], nil
  936. }
  937. func (self *SClouduser) GetCloudgroups() ([]SCloudgroup, error) {
  938. q := self.GetCloudgroupQuery()
  939. groups := []SCloudgroup{}
  940. err := db.FetchModelObjects(CloudgroupManager, q, &groups)
  941. if err != nil {
  942. return nil, errors.Wrap(err, "db.FetchModelObjects")
  943. }
  944. return groups, nil
  945. }
  946. func (self *SClouduser) PerformCreateAccessKey(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ClouduserCreateAccessKeyInput) (jsonutils.JSONObject, error) {
  947. user, err := self.GetIClouduser()
  948. if err != nil {
  949. return nil, errors.Wrapf(err, "GetIClouduser error")
  950. }
  951. ak, err := user.CreateAccessKey(input.Name)
  952. if err != nil {
  953. return nil, errors.Wrapf(err, "GetDetailsAccessKeys error")
  954. }
  955. return jsonutils.Marshal(ak), nil
  956. }
  957. func (self *SClouduser) GetDetailsAccessKeys(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (jsonutils.JSONObject, error) {
  958. user, err := self.GetIClouduser()
  959. if err != nil {
  960. return nil, errors.Wrapf(err, "GetIClouduser")
  961. }
  962. aks, err := user.GetAccessKeys()
  963. if err != nil {
  964. return nil, errors.Wrapf(err, "GetAccessKeys")
  965. }
  966. ret := struct {
  967. Data []cloudprovider.SAccessKey
  968. Total int
  969. Limit int
  970. }{
  971. Data: aks,
  972. Total: len(aks),
  973. Limit: 20,
  974. }
  975. return jsonutils.Marshal(ret), nil
  976. }
  977. func (self *SClouduser) PerformDeleteAccessKey(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.ClouduserDeleteAccessKeyInput) (jsonutils.JSONObject, error) {
  978. user, err := self.GetIClouduser()
  979. if err != nil {
  980. return nil, errors.Wrapf(err, "GetIClouduser")
  981. }
  982. err = user.DeleteAccessKey(input.AccessKey)
  983. if err != nil {
  984. return nil, errors.Wrapf(err, "DeleteAccessKey")
  985. }
  986. return nil, nil
  987. }
  988. func (self *SCloudaccount) SyncCloudusers(
  989. ctx context.Context,
  990. userCred mcclient.TokenCredential,
  991. iUsers []cloudprovider.IClouduser,
  992. managerId string,
  993. ) ([]SClouduser, []cloudprovider.IClouduser, compare.SyncResult) {
  994. lockman.LockRawObject(ctx, ClouduserManager.Keyword(), fmt.Sprintf("%s-%s", self.Id, managerId))
  995. defer lockman.ReleaseRawObject(ctx, ClouduserManager.Keyword(), fmt.Sprintf("%s-%s", self.Id, managerId))
  996. result := compare.SyncResult{}
  997. dbUsers, err := self.GetCloudusers(managerId)
  998. if err != nil {
  999. result.Error(errors.Wrap(err, "GetCloudusers"))
  1000. return nil, nil, result
  1001. }
  1002. localUsers := []SClouduser{}
  1003. remoteUsers := []cloudprovider.IClouduser{}
  1004. removed := make([]SClouduser, 0)
  1005. commondb := make([]SClouduser, 0)
  1006. commonext := make([]cloudprovider.IClouduser, 0)
  1007. added := make([]cloudprovider.IClouduser, 0)
  1008. err = compare.CompareSets(dbUsers, iUsers, &removed, &commondb, &commonext, &added)
  1009. if err != nil {
  1010. result.Error(errors.Wrap(err, "compare.CompareSets"))
  1011. return nil, nil, result
  1012. }
  1013. for i := 0; i < len(removed); i++ {
  1014. err = removed[i].RealDelete(ctx, userCred)
  1015. if err != nil {
  1016. result.DeleteError(err)
  1017. continue
  1018. }
  1019. result.Delete()
  1020. }
  1021. for i := 0; i < len(commondb); i++ {
  1022. err = commondb[i].SyncWithClouduser(ctx, userCred, commonext[i])
  1023. if err != nil {
  1024. result.UpdateError(err)
  1025. continue
  1026. }
  1027. localUsers = append(localUsers, commondb[i])
  1028. remoteUsers = append(remoteUsers, commonext[i])
  1029. result.Update()
  1030. }
  1031. for i := 0; i < len(added); i++ {
  1032. user, err := self.newClouduser(ctx, userCred, added[i], managerId)
  1033. if err != nil {
  1034. result.AddError(err)
  1035. continue
  1036. }
  1037. localUsers = append(localUsers, *user)
  1038. remoteUsers = append(remoteUsers, added[i])
  1039. result.Add()
  1040. }
  1041. return localUsers, remoteUsers, result
  1042. }
  1043. func (self *SCloudaccount) GetCloudusers(managerId string) ([]SClouduser, error) {
  1044. users := []SClouduser{}
  1045. q := ClouduserManager.Query().Equals("cloudaccount_id", self.Id)
  1046. if len(managerId) > 0 {
  1047. q = q.Equals("manager_id", managerId)
  1048. }
  1049. err := db.FetchModelObjects(ClouduserManager, q, &users)
  1050. if err != nil {
  1051. return nil, errors.Wrap(err, "db.FetchModelObjects")
  1052. }
  1053. return users, nil
  1054. }
  1055. func (self *SCloudaccount) newClouduser(ctx context.Context, userCred mcclient.TokenCredential, iUser cloudprovider.IClouduser, managerId string) (*SClouduser, error) {
  1056. lockman.LockObject(ctx, self)
  1057. defer lockman.ReleaseObject(ctx, self)
  1058. user := &SClouduser{}
  1059. user.SetModelManager(ClouduserManager, user)
  1060. user.Name = iUser.GetName()
  1061. user.ExternalId = iUser.GetGlobalId()
  1062. user.Status = apis.STATUS_AVAILABLE
  1063. user.CloudaccountId = self.Id
  1064. user.ManagerId = managerId
  1065. user.DomainId = self.DomainId
  1066. switch iUser.IsConsoleLogin() {
  1067. case true:
  1068. user.IsConsoleLogin = tristate.True
  1069. case false:
  1070. user.IsConsoleLogin = tristate.False
  1071. }
  1072. err := ClouduserManager.TableSpec().Insert(ctx, user)
  1073. if err != nil {
  1074. return nil, errors.Wrap(err, "Insert")
  1075. }
  1076. return user, nil
  1077. }