mirror of
https://github.com/yunionio/cloudpods.git
synced 2026-09-24 16:03:43 +08:00
Merge pull request #16348 from swordqiu/hotfix/qj-auto-fix-cloud-account-missing-default-tenant
fix: allow set project-id auto-crate-project of cloudaccount
This commit is contained in:
@@ -513,6 +513,10 @@ type CloudaccountSyncSkusInput struct {
|
||||
}
|
||||
|
||||
type CloudaccountProjectMappingInput struct {
|
||||
AutoCreateProject bool `json:"auto_create_project"`
|
||||
|
||||
ProjectId string `json:"project_id"`
|
||||
|
||||
// 同步策略Id, 若不传此参数则解绑
|
||||
// 绑定同步策略要求当前云账号此刻未绑定其他同步策略
|
||||
ProjectMappingId string `json:"project_mapping_id"`
|
||||
|
||||
@@ -410,7 +410,7 @@ func (tenant *STenant) GetDomainId() string {
|
||||
}*/
|
||||
|
||||
func (manager *STenantCacheManager) findFirstProjectOfDomain(domainId string) (*STenant, error) {
|
||||
q := manager.Query().Equals("domain_id", domainId)
|
||||
q := manager.Query().Equals("domain_id", domainId).Asc("created_at")
|
||||
tenant := STenant{}
|
||||
tenant.SetModelManager(manager, &tenant)
|
||||
err := q.First(&tenant)
|
||||
|
||||
@@ -1474,6 +1474,32 @@ func (manager *SCloudaccountManager) initializeVMWareAccountId() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (manager *SCloudaccountManager) initializeDefaultTenantId() error {
|
||||
// init accountid
|
||||
q := manager.Query().IsNullOrEmpty("tenant_id")
|
||||
cloudaccounts := make([]SCloudaccount, 0)
|
||||
err := db.FetchModelObjects(manager, q, &cloudaccounts)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "fetch empty defaullt tenant_id fail")
|
||||
}
|
||||
for i := range cloudaccounts {
|
||||
account := cloudaccounts[i]
|
||||
// auto fix accounts without default project
|
||||
defaultTenant, err := db.TenantCacheManager.FindFirstProjectOfDomain(context.Background(), account.DomainId)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "FindFirstProjectOfDomain(%s)", account.DomainId)
|
||||
}
|
||||
_, err = db.Update(&account, func() error {
|
||||
account.ProjectId = defaultTenant.Id
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "db.Update for account")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (manager *SCloudaccountManager) InitializeData() error {
|
||||
cloudproviders := []SCloudprovider{}
|
||||
q := CloudproviderManager.Query()
|
||||
@@ -1505,6 +1531,10 @@ func (manager *SCloudaccountManager) InitializeData() error {
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "initializePublicScope")
|
||||
}
|
||||
err = manager.initializeDefaultTenantId()
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "initializeDefaultTenantId")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -1570,15 +1600,15 @@ func (account *SCloudaccount) PerformChangeOwner(ctx context.Context, userCred m
|
||||
return nil, errors.Wrap(httperrors.ErrForbidden, "can't change domain owner of cloudaccount, use PerformChangeProject instead")
|
||||
}
|
||||
|
||||
func (self *SCloudaccount) PerformChangeProject(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformChangeProjectOwnerInput) (jsonutils.JSONObject, error) {
|
||||
if self.IsShared() {
|
||||
func (account *SCloudaccount) PerformChangeProject(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformChangeProjectOwnerInput) (jsonutils.JSONObject, error) {
|
||||
if account.IsShared() {
|
||||
return nil, errors.Wrap(httperrors.ErrInvalidStatus, "cannot change owner when shared!")
|
||||
}
|
||||
|
||||
project := input.ProjectId
|
||||
domain := input.ProjectDomainId
|
||||
if len(domain) == 0 {
|
||||
domain = self.DomainId
|
||||
domain = account.DomainId
|
||||
}
|
||||
|
||||
tenant, err := db.TenantCacheManager.FetchTenantByIdOrNameInDomain(ctx, project, domain)
|
||||
@@ -1586,34 +1616,34 @@ func (self *SCloudaccount) PerformChangeProject(ctx context.Context, userCred mc
|
||||
return nil, httperrors.NewNotFoundError("project %s not found", project)
|
||||
}
|
||||
|
||||
if tenant.Id == self.ProjectId {
|
||||
if tenant.Id == account.ProjectId {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
providers := self.GetCloudproviders()
|
||||
if len(self.ProjectId) > 0 {
|
||||
providers := account.GetCloudproviders()
|
||||
if len(account.ProjectId) > 0 {
|
||||
if len(providers) > 0 {
|
||||
for i := range providers {
|
||||
if providers[i].ProjectId != self.ProjectId {
|
||||
if providers[i].ProjectId != account.ProjectId {
|
||||
return nil, errors.Wrap(httperrors.ErrConflict, "cloudproviders' project is different from cloudaccount's")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if tenant.DomainId != self.DomainId {
|
||||
if tenant.DomainId != account.DomainId {
|
||||
// do change domainId
|
||||
input2 := apis.PerformChangeDomainOwnerInput{}
|
||||
input2.ProjectDomainId = tenant.DomainId
|
||||
_, err := self.SEnabledStatusInfrasResourceBase.PerformChangeOwner(ctx, userCred, query, input2)
|
||||
_, err := account.SEnabledStatusInfrasResourceBase.PerformChangeOwner(ctx, userCred, query, input2)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "SEnabledStatusInfrasResourceBase.PerformChangeOwner")
|
||||
}
|
||||
}
|
||||
|
||||
// save project_id change
|
||||
diff, err := db.Update(self, func() error {
|
||||
self.ProjectId = tenant.Id
|
||||
diff, err := db.Update(account, func() error {
|
||||
account.ProjectId = tenant.Id
|
||||
return nil
|
||||
})
|
||||
|
||||
@@ -1621,7 +1651,7 @@ func (self *SCloudaccount) PerformChangeProject(ctx context.Context, userCred mc
|
||||
return nil, errors.Wrap(err, "db.Update ProjectId")
|
||||
}
|
||||
|
||||
db.OpsLog.LogEvent(self, db.ACT_UPDATE, diff, userCred)
|
||||
db.OpsLog.LogEvent(account, db.ACT_UPDATE, diff, userCred)
|
||||
|
||||
if len(providers) > 0 {
|
||||
for i := range providers {
|
||||
@@ -1898,6 +1928,7 @@ func (account *SCloudaccount) probeAccountStatus(ctx context.Context, userCred m
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
version := manager.GetVersion()
|
||||
sysInfo, err := manager.GetSysInfo()
|
||||
if err != nil {
|
||||
@@ -1921,6 +1952,7 @@ func (account *SCloudaccount) probeAccountStatus(ctx context.Context, userCred m
|
||||
account.Version = version
|
||||
account.Sysinfo = sysInfo
|
||||
account.IamLoginUrl = iamLoginUrl
|
||||
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
@@ -2831,28 +2863,43 @@ func (cd *SCloudaccount) GetHost2Wire(ctx context.Context, userCred mcclient.Tok
|
||||
}
|
||||
|
||||
// 绑定同步策略
|
||||
func (self *SCloudaccount) PerformProjectMapping(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CloudaccountProjectMappingInput) (jsonutils.JSONObject, error) {
|
||||
func (account *SCloudaccount) PerformProjectMapping(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input api.CloudaccountProjectMappingInput) (jsonutils.JSONObject, error) {
|
||||
if len(input.ProjectMappingId) > 0 {
|
||||
_, err := validators.ValidateModel(userCred, ProjectMappingManager, &input.ProjectMappingId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "ValidateModel")
|
||||
}
|
||||
if len(self.ProjectMappingId) > 0 && self.ProjectMappingId != input.ProjectMappingId {
|
||||
return nil, httperrors.NewInputParameterError("account %s has aleady bind project mapping %s", self.Name, self.ProjectMappingId)
|
||||
/*if len(account.ProjectMappingId) > 0 && account.ProjectMappingId != input.ProjectMappingId {
|
||||
return nil, httperrors.NewInputParameterError("account %s has aleady bind project mapping %s", account.Name, account.ProjectMappingId)
|
||||
}*/
|
||||
if (input.EnableProjectSync == nil || !*input.EnableProjectSync) && (input.EnableResourceSync == nil || !*input.EnableResourceSync) {
|
||||
return nil, errors.Wrap(httperrors.ErrInputParameter, "either enable_project_sync or enable_resource_sync must be set")
|
||||
}
|
||||
}
|
||||
_, err := db.Update(self, func() error {
|
||||
self.ProjectMappingId = input.ProjectMappingId
|
||||
|
||||
if len(input.ProjectId) == 0 {
|
||||
return nil, errors.Wrap(httperrors.ErrInputParameter, "empty project_id")
|
||||
}
|
||||
t, err := db.TenantCacheManager.FetchTenantByIdOrNameInDomain(ctx, input.ProjectId, account.DomainId)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(err, "FetchTenantByIdOrNameInDomain")
|
||||
}
|
||||
input.ProjectId = t.Id
|
||||
|
||||
_, err = db.Update(account, func() error {
|
||||
account.ProjectId = input.ProjectId
|
||||
account.AutoCreateProject = input.AutoCreateProject
|
||||
account.ProjectMappingId = input.ProjectMappingId
|
||||
if input.EnableProjectSync != nil {
|
||||
self.EnableProjectSync = tristate.NewFromBool(*input.EnableProjectSync)
|
||||
account.EnableProjectSync = tristate.NewFromBool(*input.EnableProjectSync)
|
||||
}
|
||||
if input.EnableResourceSync != nil {
|
||||
self.EnableResourceSync = tristate.NewFromBool(*input.EnableResourceSync)
|
||||
account.EnableResourceSync = tristate.NewFromBool(*input.EnableResourceSync)
|
||||
}
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, errors.Wrap(err, "update")
|
||||
}
|
||||
return nil, refreshPmCaches()
|
||||
}
|
||||
|
||||
@@ -483,9 +483,9 @@ func createTenant(ctx context.Context, name, domainId, desc string) (string, str
|
||||
return domainId, projectId, nil
|
||||
}
|
||||
|
||||
func (self *SCloudaccount) getOrCreateTenant(ctx context.Context, name, domainId, projectId, desc string) (string, string, error) {
|
||||
func (account *SCloudaccount) getOrCreateTenant(ctx context.Context, name, domainId, projectId, desc string) (string, string, error) {
|
||||
if len(domainId) == 0 {
|
||||
domainId = self.DomainId
|
||||
domainId = account.DomainId
|
||||
}
|
||||
ctx = context.WithValue(ctx, time.Now().String(), utils.GenRequestId(20))
|
||||
uuid := stringutils.UUID4()
|
||||
@@ -499,8 +499,8 @@ func (self *SCloudaccount) getOrCreateTenant(ctx context.Context, name, domainId
|
||||
}
|
||||
return createTenant(ctx, name, domainId, desc)
|
||||
}
|
||||
share := self.GetSharedInfo()
|
||||
if tenant.DomainId == self.DomainId || (share.PublicScope == rbacscope.ScopeSystem ||
|
||||
share := account.GetSharedInfo()
|
||||
if tenant.DomainId == account.DomainId || (share.PublicScope == rbacscope.ScopeSystem ||
|
||||
(share.PublicScope == rbacscope.ScopeDomain && utils.IsInStringArray(tenant.DomainId, share.SharedDomains))) {
|
||||
return tenant.DomainId, tenant.Id, nil
|
||||
}
|
||||
@@ -1117,27 +1117,47 @@ func (manager *SCloudproviderManager) FetchCustomizeColumns(
|
||||
return rows
|
||||
}
|
||||
|
||||
func (manager *SCloudproviderManager) InitializeData() error {
|
||||
// fill empty projectId with system project ID
|
||||
func (manager *SCloudproviderManager) initializeDefaultTenantId() error {
|
||||
// init accountid
|
||||
q := manager.Query().IsNullOrEmpty("tenant_id")
|
||||
providers := make([]SCloudprovider, 0)
|
||||
q := CloudproviderManager.Query()
|
||||
q = q.Filter(sqlchemy.OR(sqlchemy.IsEmpty(q.Field("tenant_id")), sqlchemy.IsNull(q.Field("tenant_id"))))
|
||||
err := db.FetchModelObjects(CloudproviderManager, q, &providers)
|
||||
err := db.FetchModelObjects(manager, q, &providers)
|
||||
if err != nil {
|
||||
log.Errorf("query cloudproviders with empty tenant_id fail %s", err)
|
||||
return err
|
||||
return errors.Wrap(err, "fetch empty defaullt tenant_id fail")
|
||||
}
|
||||
for i := 0; i < len(providers); i += 1 {
|
||||
_, err := db.Update(&providers[i], func() error {
|
||||
providers[i].DomainId = auth.AdminCredential().GetProjectDomainId()
|
||||
providers[i].ProjectId = auth.AdminCredential().GetProjectId()
|
||||
for i := range providers {
|
||||
provider := providers[i]
|
||||
domainId := provider.DomainId
|
||||
if len(domainId) == 0 {
|
||||
account, err := provider.GetCloudaccount()
|
||||
if err != nil {
|
||||
log.Errorf("GetCloudaccount fail %s", err)
|
||||
continue
|
||||
}
|
||||
domainId = account.DomainId
|
||||
}
|
||||
// auto fix accounts without default project
|
||||
defaultTenant, err := db.TenantCacheManager.FindFirstProjectOfDomain(context.Background(), domainId)
|
||||
if err != nil {
|
||||
return errors.Wrapf(err, "FindFirstProjectOfDomain(%s)", provider.DomainId)
|
||||
}
|
||||
_, err = db.Update(&provider, func() error {
|
||||
provider.ProjectId = defaultTenant.Id
|
||||
provider.DomainId = defaultTenant.DomainId
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
log.Errorf("update cloudprovider project fail %s", err)
|
||||
return err
|
||||
return errors.Wrap(err, "db.Update for account")
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (manager *SCloudproviderManager) InitializeData() error {
|
||||
err := manager.initializeDefaultTenantId()
|
||||
if err != nil {
|
||||
log.Errorf("initializeDefaultTenantId %s", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -32,8 +32,8 @@ func InitDB() error {
|
||||
|
||||
QuotaManager,
|
||||
|
||||
CloudproviderManager,
|
||||
CloudaccountManager,
|
||||
CloudproviderManager,
|
||||
CloudregionManager,
|
||||
ZoneManager,
|
||||
VpcManager,
|
||||
|
||||
@@ -1123,13 +1123,15 @@ func (opts *SubscriptionCreateOptions) Params() (jsonutils.JSONObject, error) {
|
||||
|
||||
type ClouaccountProjectMappingOptions struct {
|
||||
SCloudAccountIdOptions
|
||||
ProjectId string `json:"project_id" help:"default project id"`
|
||||
AutoCreateProject bool `help:"auto create project"`
|
||||
ProjectMappingId string `json:"project_mapping_id" help:"project mapping id"`
|
||||
EnableProjectSync bool
|
||||
EnableResourceSync bool
|
||||
}
|
||||
|
||||
func (opts *ClouaccountProjectMappingOptions) Params() (jsonutils.JSONObject, error) {
|
||||
return jsonutils.Marshal(map[string]string{"project_mapping_id": opts.ProjectMappingId}), nil
|
||||
return jsonutils.Marshal(opts), nil
|
||||
}
|
||||
|
||||
type SNutanixCloudAccountCreateOptions struct {
|
||||
|
||||
Reference in New Issue
Block a user