cloudaccount.go 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346
  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/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/onecloud/pkg/apis"
  26. "yunion.io/x/onecloud/pkg/cloudcommon/db"
  27. "yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
  28. "yunion.io/x/onecloud/pkg/cloudid/options"
  29. "yunion.io/x/onecloud/pkg/mcclient"
  30. "yunion.io/x/onecloud/pkg/mcclient/auth"
  31. "yunion.io/x/onecloud/pkg/mcclient/informer"
  32. modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
  33. )
  34. // +onecloud:swagger-gen-ignore
  35. type SCloudaccountManager struct {
  36. db.SDomainLevelResourceBaseManager
  37. }
  38. var CloudaccountManager *SCloudaccountManager
  39. func init() {
  40. CloudaccountManager = &SCloudaccountManager{
  41. SDomainLevelResourceBaseManager: db.NewDomainLevelResourceBaseManager(
  42. SCloudaccount{},
  43. "cloudaccounts_tbl",
  44. "cloudaccount",
  45. "cloudaccounts",
  46. ),
  47. }
  48. CloudaccountManager.SetVirtualObject(CloudaccountManager)
  49. }
  50. type SCloudaccount struct {
  51. db.SStandaloneResourceBase
  52. db.SDomainizedResourceBase
  53. AccountId string `width:"128" charset:"utf8" nullable:"true" list:"domain" create:"domain_optional"`
  54. Provider string `width:"64" charset:"ascii" list:"domain"`
  55. Brand string `width:"64" charset:"utf8" nullable:"true" list:"domain"`
  56. IamLoginUrl string `width:"512" charset:"ascii"`
  57. SAMLAuth tristate.TriState `list:"domain" default:"false"`
  58. AccessUrl string `width:"64" charset:"ascii" nullable:"true" list:"domain" update:"domain" create:"domain_optional"`
  59. ReadOnly bool `default:"false" create:"domain_optional" list:"domain" update:"domain"`
  60. }
  61. func (manager *SCloudaccountManager) GetResourceCount() ([]db.SScopeResourceCount, error) {
  62. return []db.SScopeResourceCount{}, nil
  63. }
  64. func (manager *SCloudaccountManager) GetCloudaccounts() ([]SCloudaccount, error) {
  65. accounts := []SCloudaccount{}
  66. q := manager.Query()
  67. err := db.FetchModelObjects(manager, q, &accounts)
  68. if err != nil {
  69. return nil, err
  70. }
  71. return accounts, nil
  72. }
  73. func (self *SCloudaccount) GetCloudproviderId() string {
  74. return ""
  75. }
  76. func (self *SCloudaccount) GetSamlusers() ([]SSamluser, error) {
  77. q := SamluserManager.Query().Equals("cloudaccount_id", self.Id)
  78. users := []SSamluser{}
  79. err := db.FetchModelObjects(SamluserManager, q, &users)
  80. if err != nil {
  81. return nil, errors.Wrapf(err, "db.FetchModelObjects")
  82. }
  83. return users, nil
  84. }
  85. func (self *SCloudaccount) GetProvider() (cloudprovider.ICloudProvider, error) {
  86. ctx := context.Background()
  87. s := auth.GetAdminSession(ctx, options.Options.Region)
  88. return modules.Cloudaccounts.GetProvider(ctx, s, self.Id)
  89. }
  90. func (self *SCloudaccount) GetDriver() (IProviderDriver, error) {
  91. return GetProviderDriver(self.Provider)
  92. }
  93. func (self *SCloudaccount) GetCloudpolicies(managerId string) ([]SCloudpolicy, error) {
  94. q := CloudpolicyManager.Query().Equals("cloudaccount_id", self.Id)
  95. if len(managerId) > 0 {
  96. q = q.Equals("manager_id", managerId)
  97. }
  98. policies := []SCloudpolicy{}
  99. err := db.FetchModelObjects(CloudpolicyManager, q, &policies)
  100. if err != nil {
  101. return nil, errors.Wrap(err, "db.FetchModelObjects")
  102. }
  103. return policies, nil
  104. }
  105. func (self *SCloudaccount) GetCloudproviders() ([]SCloudprovider, error) {
  106. q := CloudproviderManager.Query().Equals("cloudaccount_id", self.Id)
  107. providers := []SCloudprovider{}
  108. err := db.FetchModelObjects(CloudproviderManager, q, &providers)
  109. if err != nil {
  110. return nil, errors.Wrap(err, "db.FetchModelObjects")
  111. }
  112. return providers, nil
  113. }
  114. func (self *SCloudaccount) GetCloudgroups(managerId string) ([]SCloudgroup, error) {
  115. groups := []SCloudgroup{}
  116. q := CloudgroupManager.Query().Equals("cloudaccount_id", self.Id)
  117. if len(managerId) > 0 {
  118. q = q.Equals("manager_id", managerId)
  119. }
  120. err := db.FetchModelObjects(CloudgroupManager, q, &groups)
  121. if err != nil {
  122. return nil, errors.Wrap(err, "db.FetchModelObjects")
  123. }
  124. return groups, nil
  125. }
  126. func (manager *SCloudaccountManager) SyncCloudaccountResources(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
  127. accounts, err := manager.GetCloudaccounts()
  128. if err != nil {
  129. log.Errorf("GetCloudaccounts error: %v", err)
  130. return
  131. }
  132. for i := range accounts {
  133. err = accounts[i].StartSyncCloudaccountResourcesTask(ctx, userCred, "")
  134. if err != nil {
  135. log.Errorf("StartCloudaccountSyncResourcesTask for account %s(%s) error: %v", accounts[i].Name, accounts[i].Provider, err)
  136. }
  137. }
  138. }
  139. func (self *SCloudaccount) IsSAMLProviderValid() (*SSAMLProvider, bool) {
  140. provider, err := self.RegisterSAMProvider()
  141. if err != nil {
  142. return provider, false
  143. }
  144. if len(provider.ExternalId) == 0 {
  145. return provider, false
  146. }
  147. return provider, true
  148. }
  149. func (self *SCloudaccount) RegisterSAMProvider() (*SSAMLProvider, error) {
  150. if len(options.Options.ApiServer) == 0 {
  151. return nil, fmt.Errorf("empty api server")
  152. }
  153. sps, err := self.GetSAMLProviders("")
  154. if err != nil {
  155. return nil, errors.Wrapf(err, "GetSAMLProviders")
  156. }
  157. for i := range sps {
  158. if sps[i].EntityId == options.Options.ApiServer {
  159. return &sps[i], nil
  160. }
  161. }
  162. sp := &SSAMLProvider{}
  163. sp.SetModelManager(SAMLProviderManager, sp)
  164. sp.Name = func() string {
  165. name := strings.TrimPrefix(options.Options.ApiServer, "https://")
  166. name = strings.TrimPrefix(name, "http://")
  167. return name
  168. }()
  169. sp.EntityId = options.Options.ApiServer
  170. sp.CloudaccountId = self.Id
  171. sp.DomainId = self.DomainId
  172. sp.Status = apis.STATUS_CREATING
  173. metadata := SamlIdpInstance().GetMetadata(self.Id).String()
  174. sp.MetadataDocument = metadata
  175. err = SAMLProviderManager.TableSpec().Insert(context.TODO(), sp)
  176. if err != nil {
  177. return nil, errors.Wrapf(err, "Insert")
  178. }
  179. return sp, nil
  180. }
  181. func (self *SCloudaccount) StartSAMLProviderCreateTask(ctx context.Context, userCred mcclient.TokenCredential) error {
  182. params := jsonutils.NewDict()
  183. task, err := taskman.TaskManager.NewTask(ctx, "SAMLProviderCreateTask", self, userCred, params, "", "", nil)
  184. if err != nil {
  185. return errors.Wrap(err, "NewTask")
  186. }
  187. return task.ScheduleRun(nil)
  188. }
  189. func (self *SCloudaccount) GetSAMLProviders(managerId string) ([]SSAMLProvider, error) {
  190. q := SAMLProviderManager.Query().Equals("cloudaccount_id", self.Id).Desc("external_id")
  191. if len(managerId) > 0 {
  192. q = q.Equals("manager_id", managerId)
  193. }
  194. samls := []SSAMLProvider{}
  195. err := db.FetchModelObjects(SAMLProviderManager, q, &samls)
  196. if err != nil {
  197. return nil, errors.Wrapf(err, "db.FetchModelObjects")
  198. }
  199. return samls, nil
  200. }
  201. func (self *SCloudaccount) StartSyncCloudaccountResourcesTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
  202. params := jsonutils.NewDict()
  203. task, err := taskman.TaskManager.NewTask(ctx, "CloudaccountSyncResourcesTask", self, userCred, params, parentTaskId, "", nil)
  204. if err != nil {
  205. return errors.Wrap(err, "NewTask")
  206. }
  207. return task.ScheduleRun(nil)
  208. }
  209. func (self *SCloudaccount) GetCloudroles(managerId string) ([]SCloudrole, error) {
  210. roles := []SCloudrole{}
  211. q := CloudroleManager.Query().Equals("cloudaccount_id", self.Id)
  212. if len(managerId) > 0 {
  213. q = q.Equals("manager_id", managerId)
  214. }
  215. err := db.FetchModelObjects(CloudroleManager, q, &roles)
  216. if err != nil {
  217. return nil, errors.Wrapf(err, "db.FetchModelObjects")
  218. }
  219. return roles, nil
  220. }
  221. func (m *SCloudaccountManager) StartWatchSAMLInRegion() error {
  222. adminSession := auth.GetAdminSession(context.Background(), "")
  223. watchMan, err := informer.NewWatchManagerBySession(adminSession)
  224. if err != nil {
  225. return err
  226. }
  227. resMan := &modules.Cloudaccounts
  228. return watchMan.For(resMan).AddEventHandler(context.Background(), m)
  229. }
  230. func (m *SCloudaccountManager) OnAdd(obj *jsonutils.JSONDict) {
  231. account := &SCloudaccount{}
  232. obj.Unmarshal(account)
  233. log.Debugf("OnAdd provider %s %s(%s)", account.Provider, account.Name, account.Id)
  234. account.SetModelManager(m, account)
  235. ctx := context.Background()
  236. if len(account.Provider) == 0 {
  237. s := auth.GetAdminSession(ctx, options.Options.Region)
  238. data, err := modules.Cloudaccounts.GetById(s, account.Id, nil)
  239. if err != nil {
  240. return
  241. }
  242. err = data.Unmarshal(account)
  243. if err != nil {
  244. return
  245. }
  246. }
  247. err := m.TableSpec().Insert(ctx, account)
  248. if err != nil {
  249. return
  250. }
  251. account.StartSyncCloudaccountResourcesTask(ctx, auth.AdminCredential(), "")
  252. }
  253. func (m *SCloudaccountManager) FetchAccount(id string) (*SCloudaccount, error) {
  254. account, err := m.FetchById(id)
  255. if err != nil {
  256. return nil, errors.Wrapf(err, "fetch by id %s", id)
  257. }
  258. return account.(*SCloudaccount), nil
  259. }
  260. func (self *SCloudaccount) GetSamlProvider() (*SSAMLProvider, error) {
  261. q := SAMLProviderManager.Query().Equals("status", apis.STATUS_AVAILABLE).
  262. Equals("entity_id", options.Options.ApiServer).Equals("cloudaccount_id", self.Id).IsNotEmpty("external_id")
  263. ret := &SSAMLProvider{}
  264. ret.SetModelManager(SAMLProviderManager, ret)
  265. err := q.First(ret)
  266. if err != nil {
  267. return nil, err
  268. }
  269. return ret, nil
  270. }
  271. func (m *SCloudaccountManager) OnDelete(obj *jsonutils.JSONDict) {
  272. log.Debugf("OnDelete %s", obj)
  273. account, err := func() (*SCloudaccount, error) {
  274. id, err := obj.GetString("id")
  275. if err != nil {
  276. return nil, errors.Wrapf(err, "get id")
  277. }
  278. return m.FetchAccount(id)
  279. }()
  280. if err != nil {
  281. log.Errorf("fetch account error: %v", err)
  282. return
  283. }
  284. err = account.purge(context.Background())
  285. if err != nil {
  286. log.Errorf("purge account error: %v", err)
  287. return
  288. }
  289. }
  290. func (m *SCloudaccountManager) OnUpdate(oldObj, newObj *jsonutils.JSONDict) {
  291. id, err := newObj.GetString("id")
  292. if err != nil {
  293. return
  294. }
  295. account, err := m.FetchAccount(id)
  296. if err != nil {
  297. if errors.Cause(err) == sql.ErrNoRows {
  298. m.OnAdd(newObj)
  299. return
  300. }
  301. return
  302. }
  303. db.Update(account, func() error {
  304. newObj.Unmarshal(account)
  305. return nil
  306. })
  307. oSaml, _ := oldObj.Bool("saml_auth")
  308. nSaml, _ := newObj.Bool("saml_auth")
  309. if !oSaml && nSaml {
  310. log.Debugf("OnUpdate provider %s %s(%s) enable saml auth", account.Provider, account.Name, account.Id)
  311. account.StartSAMLProviderCreateTask(context.Background(), auth.AdminCredential())
  312. }
  313. }