Files
cloudpods/pkg/cloudid/models/cloudaccount.go
2024-09-06 11:49:02 +08:00

347 lines
10 KiB
Go

// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package models
import (
"context"
"database/sql"
"fmt"
"strings"
"yunion.io/x/cloudmux/pkg/cloudprovider"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/tristate"
"yunion.io/x/onecloud/pkg/apis"
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudid/options"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/mcclient/auth"
"yunion.io/x/onecloud/pkg/mcclient/informer"
modules "yunion.io/x/onecloud/pkg/mcclient/modules/compute"
)
// +onecloud:swagger-gen-ignore
type SCloudaccountManager struct {
db.SDomainLevelResourceBaseManager
}
var CloudaccountManager *SCloudaccountManager
func init() {
CloudaccountManager = &SCloudaccountManager{
SDomainLevelResourceBaseManager: db.NewDomainLevelResourceBaseManager(
SCloudaccount{},
"cloudaccounts_tbl",
"cloudaccount",
"cloudaccounts",
),
}
CloudaccountManager.SetVirtualObject(CloudaccountManager)
}
type SCloudaccount struct {
db.SStandaloneResourceBase
db.SDomainizedResourceBase
AccountId string `width:"128" charset:"utf8" nullable:"true" list:"domain" create:"domain_optional"`
Provider string `width:"64" charset:"ascii" list:"domain"`
Brand string `width:"64" charset:"utf8" nullable:"true" list:"domain"`
IamLoginUrl string `width:"512" charset:"ascii"`
SAMLAuth tristate.TriState `list:"domain" default:"false"`
AccessUrl string `width:"64" charset:"ascii" nullable:"true" list:"domain" update:"domain" create:"domain_optional"`
ReadOnly bool `default:"false" create:"domain_optional" list:"domain" update:"domain"`
}
func (manager *SCloudaccountManager) GetResourceCount() ([]db.SScopeResourceCount, error) {
return []db.SScopeResourceCount{}, nil
}
func (manager *SCloudaccountManager) GetCloudaccounts() ([]SCloudaccount, error) {
accounts := []SCloudaccount{}
q := manager.Query()
err := db.FetchModelObjects(manager, q, &accounts)
if err != nil {
return nil, err
}
return accounts, nil
}
func (self *SCloudaccount) GetCloudproviderId() string {
return ""
}
func (self *SCloudaccount) GetSamlusers() ([]SSamluser, error) {
q := SamluserManager.Query().Equals("cloudaccount_id", self.Id)
users := []SSamluser{}
err := db.FetchModelObjects(SamluserManager, q, &users)
if err != nil {
return nil, errors.Wrapf(err, "db.FetchModelObjects")
}
return users, nil
}
func (self *SCloudaccount) GetProvider() (cloudprovider.ICloudProvider, error) {
ctx := context.Background()
s := auth.GetAdminSession(ctx, options.Options.Region)
return modules.Cloudaccounts.GetProvider(ctx, s, self.Id)
}
func (self *SCloudaccount) GetDriver() (IProviderDriver, error) {
return GetProviderDriver(self.Provider)
}
func (self *SCloudaccount) GetCloudpolicies(managerId string) ([]SCloudpolicy, error) {
q := CloudpolicyManager.Query().Equals("cloudaccount_id", self.Id)
if len(managerId) > 0 {
q = q.Equals("manager_id", managerId)
}
policies := []SCloudpolicy{}
err := db.FetchModelObjects(CloudpolicyManager, q, &policies)
if err != nil {
return nil, errors.Wrap(err, "db.FetchModelObjects")
}
return policies, nil
}
func (self *SCloudaccount) GetCloudproviders() ([]SCloudprovider, error) {
q := CloudproviderManager.Query().Equals("cloudaccount_id", self.Id)
providers := []SCloudprovider{}
err := db.FetchModelObjects(CloudproviderManager, q, &providers)
if err != nil {
return nil, errors.Wrap(err, "db.FetchModelObjects")
}
return providers, nil
}
func (self *SCloudaccount) GetCloudgroups(managerId string) ([]SCloudgroup, error) {
groups := []SCloudgroup{}
q := CloudgroupManager.Query().Equals("cloudaccount_id", self.Id)
if len(managerId) > 0 {
q = q.Equals("manager_id", managerId)
}
err := db.FetchModelObjects(CloudgroupManager, q, &groups)
if err != nil {
return nil, errors.Wrap(err, "db.FetchModelObjects")
}
return groups, nil
}
func (manager *SCloudaccountManager) SyncCloudaccountResources(ctx context.Context, userCred mcclient.TokenCredential, isStart bool) {
accounts, err := manager.GetCloudaccounts()
if err != nil {
log.Errorf("GetCloudaccounts error: %v", err)
return
}
for i := range accounts {
err = accounts[i].StartSyncCloudaccountResourcesTask(ctx, userCred, "")
if err != nil {
log.Errorf("StartCloudaccountSyncResourcesTask for account %s(%s) error: %v", accounts[i].Name, accounts[i].Provider, err)
}
}
}
func (self *SCloudaccount) IsSAMLProviderValid() (*SSAMLProvider, bool) {
provider, err := self.RegisterSAMProvider()
if err != nil {
return provider, false
}
if len(provider.ExternalId) == 0 {
return provider, false
}
return provider, true
}
func (self *SCloudaccount) RegisterSAMProvider() (*SSAMLProvider, error) {
if len(options.Options.ApiServer) == 0 {
return nil, fmt.Errorf("empty api server")
}
sps, err := self.GetSAMLProviders("")
if err != nil {
return nil, errors.Wrapf(err, "GetSAMLProviders")
}
for i := range sps {
if sps[i].EntityId == options.Options.ApiServer {
return &sps[i], nil
}
}
sp := &SSAMLProvider{}
sp.SetModelManager(SAMLProviderManager, sp)
sp.Name = func() string {
name := strings.TrimPrefix(options.Options.ApiServer, "https://")
name = strings.TrimPrefix(name, "http://")
return name
}()
sp.EntityId = options.Options.ApiServer
sp.CloudaccountId = self.Id
sp.DomainId = self.DomainId
sp.Status = apis.STATUS_CREATING
metadata := SamlIdpInstance().GetMetadata(self.Id).String()
sp.MetadataDocument = metadata
err = SAMLProviderManager.TableSpec().Insert(context.TODO(), sp)
if err != nil {
return nil, errors.Wrapf(err, "Insert")
}
return sp, nil
}
func (self *SCloudaccount) StartSAMLProviderCreateTask(ctx context.Context, userCred mcclient.TokenCredential) error {
params := jsonutils.NewDict()
task, err := taskman.TaskManager.NewTask(ctx, "SAMLProviderCreateTask", self, userCred, params, "", "", nil)
if err != nil {
return errors.Wrap(err, "NewTask")
}
return task.ScheduleRun(nil)
}
func (self *SCloudaccount) GetSAMLProviders(managerId string) ([]SSAMLProvider, error) {
q := SAMLProviderManager.Query().Equals("cloudaccount_id", self.Id).Desc("external_id")
if len(managerId) > 0 {
q = q.Equals("manager_id", managerId)
}
samls := []SSAMLProvider{}
err := db.FetchModelObjects(SAMLProviderManager, q, &samls)
if err != nil {
return nil, errors.Wrapf(err, "db.FetchModelObjects")
}
return samls, nil
}
func (self *SCloudaccount) StartSyncCloudaccountResourcesTask(ctx context.Context, userCred mcclient.TokenCredential, parentTaskId string) error {
params := jsonutils.NewDict()
task, err := taskman.TaskManager.NewTask(ctx, "CloudaccountSyncResourcesTask", self, userCred, params, parentTaskId, "", nil)
if err != nil {
return errors.Wrap(err, "NewTask")
}
return task.ScheduleRun(nil)
}
func (self *SCloudaccount) GetCloudroles(managerId string) ([]SCloudrole, error) {
roles := []SCloudrole{}
q := CloudroleManager.Query().Equals("cloudaccount_id", self.Id)
if len(managerId) > 0 {
q = q.Equals("manager_id", managerId)
}
err := db.FetchModelObjects(CloudroleManager, q, &roles)
if err != nil {
return nil, errors.Wrapf(err, "db.FetchModelObjects")
}
return roles, nil
}
func (m *SCloudaccountManager) StartWatchSAMLInRegion() error {
adminSession := auth.GetAdminSession(context.Background(), "")
watchMan, err := informer.NewWatchManagerBySession(adminSession)
if err != nil {
return err
}
resMan := &modules.Cloudaccounts
return watchMan.For(resMan).AddEventHandler(context.Background(), m)
}
func (m *SCloudaccountManager) OnAdd(obj *jsonutils.JSONDict) {
account := &SCloudaccount{}
obj.Unmarshal(account)
log.Debugf("OnAdd provider %s %s(%s)", account.Provider, account.Name, account.Id)
account.SetModelManager(m, account)
ctx := context.Background()
if len(account.Provider) == 0 {
s := auth.GetAdminSession(ctx, options.Options.Region)
data, err := modules.Cloudaccounts.GetById(s, account.Id, nil)
if err != nil {
return
}
err = data.Unmarshal(account)
if err != nil {
return
}
}
err := m.TableSpec().Insert(ctx, account)
if err != nil {
return
}
account.StartSyncCloudaccountResourcesTask(ctx, auth.AdminCredential(), "")
}
func (m *SCloudaccountManager) FetchAccount(id string) (*SCloudaccount, error) {
account, err := m.FetchById(id)
if err != nil {
return nil, errors.Wrapf(err, "fetch by id %s", id)
}
return account.(*SCloudaccount), nil
}
func (self *SCloudaccount) GetSamlProvider() (*SSAMLProvider, error) {
q := SAMLProviderManager.Query().Equals("status", apis.STATUS_AVAILABLE).
Equals("entity_id", options.Options.ApiServer).Equals("cloudaccount_id", self.Id).IsNotEmpty("external_id")
ret := &SSAMLProvider{}
ret.SetModelManager(SAMLProviderManager, ret)
err := q.First(ret)
if err != nil {
return nil, err
}
return ret, nil
}
func (m *SCloudaccountManager) OnDelete(obj *jsonutils.JSONDict) {
log.Debugf("OnDelete %s", obj)
account, err := func() (*SCloudaccount, error) {
id, err := obj.GetString("id")
if err != nil {
return nil, errors.Wrapf(err, "get id")
}
return m.FetchAccount(id)
}()
if err != nil {
log.Errorf("fetch account error: %v", err)
return
}
err = account.purge(context.Background())
if err != nil {
log.Errorf("purge account error: %v", err)
return
}
}
func (m *SCloudaccountManager) OnUpdate(oldObj, newObj *jsonutils.JSONDict) {
id, err := newObj.GetString("id")
if err != nil {
return
}
account, err := m.FetchAccount(id)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
m.OnAdd(newObj)
return
}
return
}
db.Update(account, func() error {
newObj.Unmarshal(account)
return nil
})
oSaml, _ := oldObj.Bool("saml_auth")
nSaml, _ := newObj.Bool("saml_auth")
if !oSaml && nSaml {
log.Debugf("OnUpdate provider %s %s(%s) enable saml auth", account.Provider, account.Name, account.Id)
account.StartSAMLProviderCreateTask(context.Background(), auth.AdminCredential())
}
}