cloudgroup.go 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  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 huawei
  15. import (
  16. "fmt"
  17. "net/url"
  18. "yunion.io/x/pkg/errors"
  19. api "yunion.io/x/cloudmux/pkg/apis/cloudid"
  20. "yunion.io/x/cloudmux/pkg/cloudprovider"
  21. )
  22. type SCloudgroup struct {
  23. client *SHuaweiClient
  24. Name string
  25. Description string
  26. Id string
  27. CreateTime string
  28. }
  29. func (group *SCloudgroup) GetName() string {
  30. return group.Name
  31. }
  32. func (group *SCloudgroup) GetDescription() string {
  33. return group.Description
  34. }
  35. func (group *SCloudgroup) GetGlobalId() string {
  36. return group.Id
  37. }
  38. func (group *SCloudgroup) Delete() error {
  39. return group.client.DeleteGroup(group.Id)
  40. }
  41. func (group *SCloudgroup) AddUser(name string) error {
  42. user, err := group.client.GetIClouduserByName(name)
  43. if err != nil {
  44. return errors.Wrap(err, "GetIClouduserByName")
  45. }
  46. return group.client.AddUserToGroup(group.Id, user.GetGlobalId())
  47. }
  48. func (group *SCloudgroup) RemoveUser(name string) error {
  49. user, err := group.client.GetIClouduserByName(name)
  50. if err != nil {
  51. if errors.Cause(err) == cloudprovider.ErrNotFound {
  52. return nil
  53. }
  54. return errors.Wrapf(err, "GetIClouduserByName(%s)", name)
  55. }
  56. return group.client.RemoveUserFromGroup(group.Id, user.GetGlobalId())
  57. }
  58. func (group *SCloudgroup) DetachPolicy(roleId string, policyType api.TPolicyType) error {
  59. if policyType == api.PolicyTypeCustom {
  60. return group.client.DetachGroupCustomRole(group.Id, roleId)
  61. }
  62. return group.client.DetachGroupRole(group.Id, roleId)
  63. }
  64. func (group *SCloudgroup) AttachPolicy(roleId string, policyType api.TPolicyType) error {
  65. if policyType == api.PolicyTypeCustom {
  66. return group.client.AttachGroupCustomRole(group.Id, roleId)
  67. }
  68. return group.client.AttachGroupRole(group.Id, roleId)
  69. }
  70. func (group *SCloudgroup) GetICloudpolicies() ([]cloudprovider.ICloudpolicy, error) {
  71. roles, err := group.client.GetGroupRoles(group.Id)
  72. if err != nil {
  73. return nil, errors.Wrap(err, "GetGroupRoles")
  74. }
  75. ret := []cloudprovider.ICloudpolicy{}
  76. for i := range roles {
  77. ret = append(ret, &roles[i])
  78. }
  79. return ret, nil
  80. }
  81. func (group *SCloudgroup) GetICloudusers() ([]cloudprovider.IClouduser, error) {
  82. users, err := group.client.GetGroupUsers(group.Id)
  83. if err != nil {
  84. return nil, err
  85. }
  86. ret := []cloudprovider.IClouduser{}
  87. for i := range users {
  88. users[i].client = group.client
  89. ret = append(ret, &users[i])
  90. }
  91. return ret, nil
  92. }
  93. // https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneListGroups
  94. func (self *SHuaweiClient) GetGroups(domainId, name string) ([]SCloudgroup, error) {
  95. query := url.Values{}
  96. if len(domainId) > 0 {
  97. query.Set("domain_id", self.ownerId)
  98. }
  99. if len(name) > 0 {
  100. query.Set("name", name)
  101. }
  102. groups := []SCloudgroup{}
  103. resp, err := self.list(SERVICE_IAM_V3, "", "groups", query)
  104. if err != nil {
  105. return nil, err
  106. }
  107. err = resp.Unmarshal(&groups, "groups")
  108. if err != nil {
  109. return nil, errors.Wrapf(err, "Unmarshal")
  110. }
  111. return groups, nil
  112. }
  113. func (self *SHuaweiClient) GetICloudgroups() ([]cloudprovider.ICloudgroup, error) {
  114. groups, err := self.GetGroups("", "")
  115. if err != nil {
  116. return nil, errors.Wrap(err, "GetGroup")
  117. }
  118. ret := []cloudprovider.ICloudgroup{}
  119. for i := range groups {
  120. if groups[i].Name != "admin" {
  121. groups[i].client = self
  122. ret = append(ret, &groups[i])
  123. }
  124. }
  125. return ret, nil
  126. }
  127. // https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneListUsersForGroupByAdmin
  128. func (self *SHuaweiClient) GetGroupUsers(groupId string) ([]SClouduser, error) {
  129. resp, err := self.list(SERVICE_IAM_V3, "", fmt.Sprintf("groups/%s/users", groupId), nil)
  130. if err != nil {
  131. return nil, errors.Wrapf(err, "list group users")
  132. }
  133. users := []SClouduser{}
  134. err = resp.Unmarshal(&users, "users")
  135. if err != nil {
  136. return nil, errors.Wrap(err, "Unmarshal")
  137. }
  138. return users, nil
  139. }
  140. // https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneCheckDomainPermissionForGroup
  141. func (self *SHuaweiClient) GetGroupRoles(groupId string) ([]SRole, error) {
  142. res := fmt.Sprintf("domains/%s/groups/%s/roles", self.ownerId, groupId)
  143. resp, err := self.list(SERVICE_IAM_V3, "", res, nil)
  144. if err != nil {
  145. return nil, errors.Wrap(err, "ListRoles")
  146. }
  147. roles := []SRole{}
  148. err = resp.Unmarshal(&roles, "roles")
  149. if err != nil {
  150. return nil, errors.Wrap(err, "Unmarshal")
  151. }
  152. return roles, nil
  153. }
  154. // https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneCreateGroup
  155. func (self *SHuaweiClient) CreateGroup(name, desc string) (*SCloudgroup, error) {
  156. params := map[string]interface{}{
  157. "name": name,
  158. }
  159. if len(desc) > 0 {
  160. params["description"] = desc
  161. }
  162. resp, err := self.post(SERVICE_IAM_V3, "", "groups", map[string]interface{}{"group": params})
  163. if err != nil {
  164. return nil, err
  165. }
  166. group := &SCloudgroup{client: self}
  167. err = resp.Unmarshal(group, "group")
  168. if err != nil {
  169. return nil, errors.Wrapf(err, "Unmarshal")
  170. }
  171. return group, nil
  172. }
  173. func (self *SHuaweiClient) CreateICloudgroup(name, desc string) (cloudprovider.ICloudgroup, error) {
  174. group, err := self.CreateGroup(name, desc)
  175. if err != nil {
  176. return nil, errors.Wrap(err, "CreateGroup")
  177. }
  178. return group, nil
  179. }
  180. // https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneDeleteGroup
  181. func (self *SHuaweiClient) DeleteGroup(id string) error {
  182. _, err := self.delete(SERVICE_IAM_V3, "", "groups/"+id)
  183. return err
  184. }
  185. func (self *SHuaweiClient) GetICloudgroupByName(name string) (cloudprovider.ICloudgroup, error) {
  186. groups, err := self.GetGroups(self.ownerId, name)
  187. if err != nil {
  188. return nil, errors.Wrap(err, "GetGroups")
  189. }
  190. if len(groups) == 0 {
  191. return nil, cloudprovider.ErrNotFound
  192. }
  193. if len(groups) > 1 {
  194. return nil, cloudprovider.ErrDuplicateId
  195. }
  196. groups[0].client = self
  197. return &groups[0], nil
  198. }
  199. // https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneAddUserToGroup
  200. func (self *SHuaweiClient) AddUserToGroup(groupId, userId string) error {
  201. _, err := self.put(SERVICE_IAM_V3, "", fmt.Sprintf("groups/%s/users/%s", groupId, userId), nil)
  202. return err
  203. }
  204. // https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneRemoveUserFromGroup
  205. func (self *SHuaweiClient) RemoveUserFromGroup(groupId, userId string) error {
  206. _, err := self.delete(SERVICE_IAM_V3, "", fmt.Sprintf("groups/%s/users/%s", groupId, userId))
  207. return err
  208. }
  209. // https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=ListCustomPolicies
  210. func (self *SHuaweiClient) GetCustomRoles() ([]SRole, error) {
  211. query := url.Values{}
  212. query.Set("per_page", "300")
  213. page := 1
  214. query.Set("page", fmt.Sprintf("%d", page))
  215. ret := []SRole{}
  216. for {
  217. resp, err := self.list(SERVICE_IAM, "", "OS-ROLE/roles", query)
  218. if err != nil {
  219. return nil, err
  220. }
  221. part := struct {
  222. Roles []SRole
  223. TotalNumber int
  224. }{}
  225. err = resp.Unmarshal(&part)
  226. if err != nil {
  227. return nil, err
  228. }
  229. ret = append(ret, part.Roles...)
  230. if len(ret) >= part.TotalNumber || len(part.Roles) == 0 {
  231. break
  232. }
  233. page++
  234. query.Set("page", fmt.Sprintf("%d", page))
  235. }
  236. return ret, nil
  237. }
  238. func (self *SHuaweiClient) GetCustomRole(id string) (*SRole, error) {
  239. resp, err := self.list(SERVICE_IAM, "", "OS-ROLE/roles/"+id, nil)
  240. if err != nil {
  241. return nil, err
  242. }
  243. ret := &SRole{}
  244. err = resp.Unmarshal(ret, "role")
  245. if err != nil {
  246. return nil, err
  247. }
  248. return ret, nil
  249. }
  250. func (self *SHuaweiClient) GetRole(id string) (*SRole, error) {
  251. resp, err := self.list(SERVICE_IAM_V3, "", "roles/"+id, nil)
  252. if err != nil {
  253. return nil, err
  254. }
  255. ret := &SRole{}
  256. err = resp.Unmarshal(ret, "role")
  257. if err != nil {
  258. return nil, errors.Wrapf(err, "Unmarshal")
  259. }
  260. return ret, nil
  261. }
  262. func (self *SHuaweiClient) DetachGroupRole(groupId, roleId string) error {
  263. role, err := self.GetRole(roleId)
  264. if err != nil {
  265. return errors.Wrapf(err, "GetRole(%s)", roleId)
  266. }
  267. if role.Type == "AX" || role.Type == "AA" {
  268. err := self.KeystoneRemoveDomainPermissionFromGroup(self.ownerId, groupId, roleId)
  269. if err != nil {
  270. return errors.Wrapf(err, "remove domain role")
  271. }
  272. }
  273. if role.Type == "XA" || role.Type == "AA" {
  274. projects, err := self.GetProjects()
  275. if err != nil {
  276. return errors.Wrapf(err, "GetProjects")
  277. }
  278. for _, project := range projects {
  279. err := self.KeystoneRemoveProjectPermissionFromGroup(project.Id, groupId, role.Id)
  280. if err != nil {
  281. return errors.Wrapf(err, "remove project role ")
  282. }
  283. }
  284. }
  285. return nil
  286. }
  287. // https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneRemoveProjectPermissionFromGroup
  288. func (self *SHuaweiClient) KeystoneRemoveProjectPermissionFromGroup(projectId, groupId, roleId string) error {
  289. res := fmt.Sprintf("projects/%s/groups/%s/roles/%s", projectId, groupId, roleId)
  290. _, err := self.delete(SERVICE_IAM_V3, "", res)
  291. return err
  292. }
  293. // https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneAssociateGroupWithProjectPermission
  294. func (self *SHuaweiClient) KeystoneAssociateGroupWithProjectPermission(projectId, groupId, roleId string) error {
  295. res := fmt.Sprintf("projects/%s/groups/%s/roles/%s", self.GetMosProjectId(), groupId, roleId)
  296. _, err := self.put(SERVICE_IAM_V3, "", res, nil)
  297. return err
  298. }
  299. // https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneAssociateGroupWithDomainPermission
  300. func (self *SHuaweiClient) KeystoneAssociateGroupWithDomainPermission(domainId, groupId, roleId string) error {
  301. res := fmt.Sprintf("domains/%s/groups/%s/roles/%s", domainId, groupId, roleId)
  302. _, err := self.put(SERVICE_IAM_V3, "", res, nil)
  303. return err
  304. }
  305. // https://console.huaweicloud.com/apiexplorer/#/openapi/IAM/doc?api=KeystoneRemoveDomainPermissionFromGroup
  306. func (self *SHuaweiClient) KeystoneRemoveDomainPermissionFromGroup(domainId, groupId, roleId string) error {
  307. res := fmt.Sprintf("domains/%s/groups/%s/roles/%s", domainId, groupId, roleId)
  308. _, err := self.delete(SERVICE_IAM_V3, "", res)
  309. return err
  310. }
  311. func (self *SHuaweiClient) AttachGroupRole(groupId, roleId string) error {
  312. role, err := self.GetRole(roleId)
  313. if err != nil {
  314. return errors.Wrapf(err, "GetRole(%s)", roleId)
  315. }
  316. if role.Type == "AX" || role.Type == "AA" {
  317. err := self.KeystoneAssociateGroupWithDomainPermission(self.ownerId, groupId, roleId)
  318. if err != nil {
  319. return errors.Wrapf(err, "AddRole")
  320. }
  321. }
  322. if role.Type == "XA" || role.Type == "AA" {
  323. projects, err := self.GetProjects()
  324. if err != nil {
  325. return errors.Wrapf(err, "GetProjects")
  326. }
  327. for _, project := range projects {
  328. err := self.KeystoneAssociateGroupWithProjectPermission(project.Id, groupId, role.Id)
  329. if err != nil {
  330. return errors.Wrapf(err, "add project role ")
  331. }
  332. }
  333. }
  334. return nil
  335. }
  336. func (self *SHuaweiClient) AttachGroupCustomRole(groupId, roleId string) error {
  337. role, err := self.GetCustomRole(roleId)
  338. if err != nil {
  339. return errors.Wrapf(err, "GetRole(%s)", roleId)
  340. }
  341. if role.Type == "AX" || role.Type == "AA" {
  342. err := self.KeystoneAssociateGroupWithDomainPermission(self.ownerId, groupId, roleId)
  343. if err != nil {
  344. return errors.Wrapf(err, "AddRole")
  345. }
  346. }
  347. if role.Type == "XA" || role.Type == "AA" {
  348. projects, err := self.GetProjects()
  349. if err != nil {
  350. return errors.Wrapf(err, "GetProjects")
  351. }
  352. for _, project := range projects {
  353. err := self.KeystoneAssociateGroupWithProjectPermission(project.Id, groupId, role.Id)
  354. if err != nil {
  355. return errors.Wrapf(err, "add project role ")
  356. }
  357. }
  358. }
  359. return nil
  360. }
  361. func (self *SHuaweiClient) DetachGroupCustomRole(groupId, roleId string) error {
  362. role, err := self.GetCustomRole(roleId)
  363. if err != nil {
  364. return errors.Wrapf(err, "GetCustomRole(%s)", roleId)
  365. }
  366. if role.Type == "AX" || role.Type == "AA" {
  367. err := self.KeystoneRemoveDomainPermissionFromGroup(self.ownerId, groupId, roleId)
  368. if err != nil {
  369. return errors.Wrapf(err, "DeleteRole")
  370. }
  371. }
  372. if role.Type == "XA" || role.Type == "AA" {
  373. projects, err := self.GetProjects()
  374. if err != nil {
  375. return errors.Wrapf(err, "GetProjects")
  376. }
  377. for _, project := range projects {
  378. err := self.KeystoneRemoveProjectPermissionFromGroup(project.Id, groupId, role.Id)
  379. if err != nil {
  380. return errors.Wrapf(err, "remove project role ")
  381. }
  382. }
  383. }
  384. return nil
  385. }