fix: 修正项目映射同步

This commit is contained in:
Qu Xuan
2020-06-18 17:13:40 +08:00
parent 8d81393c03
commit 4b16fac0ba
23 changed files with 609 additions and 174 deletions

View File

@@ -16,8 +16,16 @@ package compute
import "yunion.io/x/onecloud/pkg/apis"
const (
EXTERNAL_PROJECT_STATUS_AVAILABLE = "available" // 可用
EXTERNAL_PROJECT_STATUS_UNAVAILABLE = "unavailable" // 不可用
EXTERNAL_PROJECT_STATUS_CREATING = "creating" // 创建中
EXTERNAL_PROJECT_STATUS_DELETING = "deleting" // 删除中
EXTERNAL_PROJECT_STATUS_UNKNOWN = "unknown" // 未知
)
type ExternalProjectDetails struct {
apis.StandaloneResourceDetails
apis.StatusStandaloneResourceDetails
apis.ProjectizedResourceInfo
ManagedResourceInfo

View File

@@ -61,7 +61,7 @@ type CachedimageListInput struct {
}
type ExternalProjectListInput struct {
apis.StandaloneResourceListInput
apis.StatusStandaloneResourceListInput
apis.ProjectizedResourceListInput
apis.ExternalizedResourceBaseListInput

View File

@@ -234,10 +234,26 @@ func (self *SESXiGuestDriver) RequestDeployGuestOnHost(ctx context.Context, gues
}
config.Add(jsonutils.NewString(extId), "guest_ext_id")
accessInfo, err := host.GetCloudaccount().GetVCenterAccessInfo(storage.ExternalId)
account := host.GetCloudaccount()
accessInfo, err := account.GetVCenterAccessInfo(storage.ExternalId)
if err != nil {
return err
}
action, _ := config.GetString("action")
if action == "create" {
extProj, name, err := account.GetExternalProject(ctx, task.GetUserCred(), guest.ProjectId)
if err != nil {
log.Errorf("failed to get external project %s from account %s(%s) error: %v", guest.ProjectId, account.Name, account.Id, err)
}
if extProj != nil {
config.Add(jsonutils.NewString(extProj.ExternalId), "desc", "group_id")
}
if len(name) > 0 {
config.Add(jsonutils.NewString(name), "desc", "resource_pool")
}
}
config.Add(jsonutils.Marshal(accessInfo), "datastore")
url := "/disks/agent/deploy"

View File

@@ -2422,6 +2422,16 @@ func (self *SCloudaccount) Delete(ctx context.Context, userCred mcclient.TokenCr
func (self *SCloudaccount) RealDelete(ctx context.Context, userCred mcclient.TokenCredential) error {
self.SetStatus(userCred, api.CLOUD_PROVIDER_DELETED, "real delete")
projects, err := self.GetExternalProjects()
if err != nil {
return errors.Wrap(err, "GetExternalProjects")
}
for i := range projects {
err = projects[i].Delete(ctx, userCred)
if err != nil {
return errors.Wrapf(err, "project %s Delete", projects[i].Id)
}
}
return self.SEnabledStatusInfrasResourceBase.Delete(ctx, userCred)
}
@@ -2752,6 +2762,16 @@ func (account *SCloudaccount) PerformSyncSkus(ctx context.Context, userCred mccl
return nil, nil
}
func (self *SCloudaccount) GetExternalProjects() ([]SExternalProject, error) {
projects := []SExternalProject{}
q := ExternalProjectManager.Query().Equals("cloudaccount_id", self.Id)
err := db.FetchModelObjects(ExternalProjectManager, q, &projects)
if err != nil {
return nil, errors.Wrap(err, "db.FetchModelObjects")
}
return projects, nil
}
func (manager *SCloudaccountManager) queryCloudAccountByCapability(region *SCloudregion, zone *SZone, domainId string, enabled tristate.TriState, capability string) *sqlchemy.SQuery {
providers := CloudproviderManager.Query().SubQuery()
q := manager.Query()
@@ -2843,3 +2863,57 @@ func (account *SCloudaccount) GetUsages() []db.IUsage {
&usage,
}
}
func (self *SCloudaccount) GetExternalProject(ctx context.Context, userCred mcclient.TokenCredential, id string) (*SExternalProject, string, error) {
projects, err := self.GetExternalProjects()
if err != nil {
return nil, "", errors.Wrap(err, "GetExternalProjects")
}
for i := range projects {
if projects[i].ProjectId == id && projects[i].Status == api.EXTERNAL_PROJECT_STATUS_AVAILABLE {
return &projects[i], projects[i].Name, nil
}
}
project, err := db.TenantCacheManager.FetchById(id)
if err != nil {
return nil, "", errors.Wrap(err, "TenantCacheManager.FetchById")
}
for i := range projects {
if projects[i].Name == project.GetName() {
if projects[i].Status != api.EXTERNAL_PROJECT_STATUS_AVAILABLE {
return nil, "", fmt.Errorf("external project %s not available", projects[i].Name)
}
return &projects[i], project.GetName(), nil
}
}
return nil, project.GetName(), cloudprovider.ErrNotFound
}
func (self *SCloudaccount) SyncProject(ctx context.Context, userCred mcclient.TokenCredential, id string) (string, error) {
lockman.LockRawObject(ctx, self.Id, id)
defer lockman.ReleaseRawObject(ctx, self.Id, id)
project, _, err := self.GetExternalProject(ctx, userCred, id)
if err == nil {
return project.ExternalId, nil
}
if err != cloudprovider.ErrNotFound {
return "", err
}
provider, err := self.GetProvider()
if err != nil {
return "", errors.Wrap(err, "GetProvider")
}
iProject, err := provider.CreateIProject(project.GetName())
if err != nil {
return "", errors.Wrap(err, "CreateIProject")
}
extProj, err := ExternalProjectManager.newFromCloudProject(ctx, userCred, self, iProject)
if err != nil {
return "", errors.Wrap(err, "newFromCloudProject")
}
return extProj.ExternalId, nil
}

View File

@@ -1369,7 +1369,6 @@ func (self *SCloudprovider) RealDelete(ctx context.Context, userCred mcclient.To
ElasticipManager,
NetworkInterfaceManager,
CloudproviderRegionManager,
ExternalProjectManager,
CloudregionManager,
CloudproviderQuotaManager,
} {
@@ -1625,51 +1624,10 @@ func (provider *SCloudprovider) GetChangeOwnerCandidateDomainIds() []string {
return []string{}
}
func (self *SCloudprovider) GetExternalProjects() ([]SExternalProject, error) {
q := ExternalProjectManager.Query().Equals("manager_id", self.Id)
projects := []SExternalProject{}
err := db.FetchModelObjects(ExternalProjectManager, q, &projects)
if err != nil {
return nil, errors.Wrap(err, "FetchModelObjects")
}
return projects, nil
}
func (self *SCloudprovider) SyncProject(ctx context.Context, userCred mcclient.TokenCredential, id string) (string, error) {
lockman.LockRawObject(ctx, self.Id, id)
defer lockman.ReleaseRawObject(ctx, self.Id, id)
projects, err := self.GetExternalProjects()
if err != nil {
return "", errors.Wrap(err, "GetExternalProjects")
account := self.GetCloudaccount()
if account == nil {
return "", fmt.Errorf("failed to get cloudprovider %s account", self.Name)
}
for _, project := range projects {
if project.ProjectId == id {
return project.ExternalId, nil
}
}
project, err := db.TenantCacheManager.FetchById(id)
if err != nil {
return "", errors.Wrap(err, "TenantCacheManager.FetchById")
}
for _, extProj := range projects {
if extProj.Name == project.GetName() {
return extProj.ExternalId, nil
}
}
provider, err := self.GetProvider()
if err != nil {
return "", errors.Wrap(err, "GetProvider")
}
iProject, err := provider.CreateIProject(project.GetName())
if err != nil {
return "", errors.Wrap(err, "CreateIProject")
}
extProj, err := ExternalProjectManager.newFromCloudProject(ctx, userCred, self, iProject)
if err != nil {
return "", errors.Wrap(err, "newFromCloudProject")
}
return extProj.ExternalId, nil
return account.SyncProject(ctx, userCred, id)
}

View File

@@ -172,28 +172,6 @@ func syncRegionSkus(ctx context.Context, userCred mcclient.TokenCredential, loca
}
}
func syncProjects(ctx context.Context, userCred mcclient.TokenCredential, syncResults SSyncResultSet, driver cloudprovider.ICloudProvider, provider *SCloudprovider) {
projects, err := driver.GetIProjects()
if err != nil {
msg := fmt.Sprintf("GetIProjects for provider %s failed %s", provider.GetName(), err)
log.Errorf(msg)
// logSyncFailed(provider, task, msg)
return
}
result := ExternalProjectManager.SyncProjects(ctx, userCred, provider, projects)
syncResults.Add(ExternalProjectManager, result)
msg := result.Result()
log.Infof("SyncProjects for provider %s result: %s", provider.Name, msg)
if result.IsError() {
// logSyncFailed(provider, task, msg)
return
}
// db.OpsLog.LogEvent(provider, db.ACT_SYNC_PROJECT_COMPLETE, msg, task.UserCred)
}
func syncRegionEips(ctx context.Context, userCred mcclient.TokenCredential, syncResults SSyncResultSet, provider *SCloudprovider, localRegion *SCloudregion, remoteRegion cloudprovider.ICloudRegion, syncRange *SSyncRange) {
eips, err := remoteRegion.GetIEips()
if err != nil {
@@ -1027,10 +1005,6 @@ func syncPublicCloudProviderInfo(
storageCachePairs := make([]sStoragecacheSyncPair, 0)
if cloudprovider.IsSupportProject(driver) {
syncProjects(ctx, userCred, syncResults, driver, provider)
}
syncRegionQuotas(ctx, userCred, syncResults, driver, provider, localRegion, remoteRegion)
localZones, remoteZones, _ := syncRegionZones(ctx, userCred, syncResults, provider, localRegion, remoteRegion)
@@ -1124,10 +1098,6 @@ func syncOnPremiseCloudProviderInfo(
) error {
log.Debugf("Start sync on-premise provider %s(%s)", provider.Name, provider.Provider)
if cloudprovider.IsSupportProject(driver) {
syncProjects(ctx, userCred, syncResults, driver, provider)
}
iregion, err := driver.GetOnPremiseIRegion()
if err != nil {
msg := fmt.Sprintf("GetOnPremiseIRegion for provider %s failed %s", provider.GetName(), err)
@@ -1221,7 +1191,7 @@ func SyncCloudProject(userCred mcclient.TokenCredential, model db.IVirtualModel,
if extProjectId := extModel.GetProjectId(); len(extProjectId) > 0 {
extProject, err := ExternalProjectManager.GetProject(extProjectId, managerId)
if err != nil {
log.Errorln(err)
log.Errorf("sync project for %s %s error: %v", model.Keyword(), model.GetName(), err)
} else {
newOwnerId = extProject.GetOwnerId()
}

View File

@@ -16,6 +16,7 @@ package models
import (
"context"
"database/sql"
"fmt"
"yunion.io/x/jsonutils"
@@ -35,7 +36,7 @@ import (
)
type SExternalProjectManager struct {
db.SStandaloneResourceBaseManager
db.SStatusStandaloneResourceBaseManager
db.SProjectizedResourceBaseManager
db.SExternalizedResourceBaseManager
SManagedResourceBaseManager
@@ -45,7 +46,7 @@ var ExternalProjectManager *SExternalProjectManager
func init() {
ExternalProjectManager = &SExternalProjectManager{
SStandaloneResourceBaseManager: db.NewStandaloneResourceBaseManager(
SStatusStandaloneResourceBaseManager: db.NewStatusStandaloneResourceBaseManager(
SExternalProject{},
"externalprojects_tbl",
"externalproject",
@@ -56,10 +57,13 @@ func init() {
}
type SExternalProject struct {
db.SStandaloneResourceBase
db.SStatusStandaloneResourceBase
db.SProjectizedResourceBase
db.SExternalizedResourceBase
SManagedResourceBase
// 归属云账号ID
CloudaccountId string `width:"36" charset:"ascii" nullable:"false" list:"user"`
}
func (manager *SExternalProjectManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool {
@@ -70,15 +74,6 @@ func (self *SExternalProject) AllowUpdateItem(ctx context.Context, userCred mccl
return false
}
func (manager *SExternalProjectManager) getProjectsByProviderId(providerId string) ([]SExternalProject, error) {
projects := []SExternalProject{}
err := fetchByManagerId(manager, providerId, &projects)
if err != nil {
return nil, err
}
return projects, nil
}
func (self *SExternalProject) getCloudProviderInfo() SCloudProviderInfo {
provider := self.GetCloudprovider()
return MakeCloudProviderInfo(nil, nil, provider)
@@ -103,15 +98,15 @@ func (manager *SExternalProjectManager) FetchCustomizeColumns(
) []api.ExternalProjectDetails {
rows := make([]api.ExternalProjectDetails, len(objs))
stdRows := manager.SStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
stdRows := manager.SStatusStandaloneResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
manRows := manager.SManagedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
projRows := manager.SProjectizedResourceBaseManager.FetchCustomizeColumns(ctx, userCred, query, objs, fields, isList)
for i := range rows {
rows[i] = api.ExternalProjectDetails{
StandaloneResourceDetails: stdRows[i],
ManagedResourceInfo: manRows[i],
ProjectizedResourceInfo: projRows[i],
StatusStandaloneResourceDetails: stdRows[i],
ManagedResourceInfo: manRows[i],
ProjectizedResourceInfo: projRows[i],
}
}
@@ -121,7 +116,8 @@ func (manager *SExternalProjectManager) FetchCustomizeColumns(
func (manager *SExternalProjectManager) GetProject(externalId string, providerId string) (*SExternalProject, error) {
project := &SExternalProject{}
project.SetModelManager(manager, project)
q := manager.Query().Equals("external_id", externalId).Equals("manager_id", providerId)
sq := CloudproviderManager.Query("cloudaccount_id").Equals("id", providerId)
q := manager.Query().Equals("external_id", externalId).Equals("cloudaccount_id", sq.SubQuery())
count, err := q.CountWithError()
if err != nil {
return nil, err
@@ -135,13 +131,13 @@ func (manager *SExternalProjectManager) GetProject(externalId string, providerId
return project, q.First(project)
}
func (manager *SExternalProjectManager) SyncProjects(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, projects []cloudprovider.ICloudProject) compare.SyncResult {
func (manager *SExternalProjectManager) SyncProjects(ctx context.Context, userCred mcclient.TokenCredential, account *SCloudaccount, projects []cloudprovider.ICloudProject) compare.SyncResult {
lockman.LockClass(ctx, manager, db.GetLockClassKey(manager, userCred))
defer lockman.ReleaseClass(ctx, manager, db.GetLockClassKey(manager, userCred))
syncResult := compare.SyncResult{}
dbProjects, err := manager.getProjectsByProviderId(provider.Id)
dbProjects, err := account.GetExternalProjects()
if err != nil {
syncResult.Error(err)
return syncResult
@@ -167,7 +163,7 @@ func (manager *SExternalProjectManager) SyncProjects(ctx context.Context, userCr
}
}
for i := 0; i < len(commondb); i++ {
err = commondb[i].SyncWithCloudProject(ctx, userCred, provider, commonext[i])
err = commondb[i].SyncWithCloudProject(ctx, userCred, account, commonext[i])
if err != nil {
syncResult.UpdateError(err)
} else {
@@ -175,7 +171,7 @@ func (manager *SExternalProjectManager) SyncProjects(ctx context.Context, userCr
}
}
for i := 0; i < len(added); i++ {
_, err := manager.newFromCloudProject(ctx, userCred, provider, added[i])
_, err := manager.newFromCloudProject(ctx, userCred, account, added[i])
if err != nil {
syncResult.AddError(err)
} else {
@@ -192,13 +188,14 @@ func (self *SExternalProject) syncRemoveCloudProject(ctx context.Context, userCr
return self.Delete(ctx, userCred)
}
func (self *SExternalProject) SyncWithCloudProject(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, ext cloudprovider.ICloudProject) error {
func (self *SExternalProject) SyncWithCloudProject(ctx context.Context, userCred mcclient.TokenCredential, account *SCloudaccount, ext cloudprovider.ICloudProject) error {
diff, err := db.UpdateWithLock(ctx, self, func() error {
self.Name = ext.GetName()
self.IsEmulated = ext.IsEmulated()
if self.DomainId != provider.DomainId {
self.ProjectId = provider.ProjectId
self.DomainId = provider.DomainId
self.Status = ext.GetStatus()
if self.DomainId != account.DomainId {
self.ProjectId = account.ProjectId
self.DomainId = account.DomainId
}
return nil
})
@@ -210,20 +207,20 @@ func (self *SExternalProject) SyncWithCloudProject(ctx context.Context, userCred
return nil
}
func (manager *SExternalProjectManager) newFromCloudProject(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, extProject cloudprovider.ICloudProject) (*SExternalProject, error) {
func (manager *SExternalProjectManager) newFromCloudProject(ctx context.Context, userCred mcclient.TokenCredential, account *SCloudaccount, extProject cloudprovider.ICloudProject) (*SExternalProject, error) {
project := SExternalProject{}
project.SetModelManager(manager, &project)
project.Name = extProject.GetName()
project.Status = extProject.GetStatus()
project.ExternalId = extProject.GetGlobalId()
project.IsEmulated = extProject.IsEmulated()
project.ManagerId = provider.Id
project.DomainId = provider.DomainId
project.ProjectId = provider.ProjectId
account := provider.GetCloudaccount()
if account != nil && account.AutoCreateProject {
project.CloudaccountId = account.Id
project.DomainId = account.DomainId
project.ProjectId = account.ProjectId
if account.AutoCreateProject {
desc := fmt.Sprintf("auto create from cloud project %s (%s)", project.Name, project.ExternalId)
domainId, projectId, err := getOrCreateTenant(ctx, project.Name, provider.DomainId, "", desc)
domainId, projectId, err := getOrCreateTenant(ctx, project.Name, account.DomainId, "", desc)
if err != nil {
log.Errorf("failed to get or create tenant %s(%s) %v", project.Name, project.ExternalId, err)
} else {
@@ -303,23 +300,46 @@ func (manager *SExternalProjectManager) ListItemFilter(
) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StandaloneResourceListInput)
q, err = manager.SStatusStandaloneResourceBaseManager.ListItemFilter(ctx, q, userCred, query.StatusStandaloneResourceListInput)
if err != nil {
return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemFilter")
return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ListItemFilter")
}
q, err = manager.SExternalizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ExternalizedResourceBaseListInput)
if err != nil {
return nil, errors.Wrap(err, "SExternalizedResourceBaseManager.ListItemFilter")
}
q, err = manager.SManagedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ManagedResourceListInput)
if err != nil {
return nil, errors.Wrap(err, "SManagedResourceBaseManager.ListItemFilter")
}
q, err = manager.SProjectizedResourceBaseManager.ListItemFilter(ctx, q, userCred, query.ProjectizedResourceListInput)
if err != nil {
return nil, errors.Wrap(err, "SProjectizedResourceBaseManager.ListItemFilter")
}
if len(query.Cloudprovider) > 0 {
p, err := CloudproviderManager.FetchByIdOrName(userCred, query.Cloudprovider)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
return nil, httperrors.NewResourceNotFoundError2("cloudprovider", query.Cloudprovider)
}
return nil, httperrors.NewGeneralError(err)
}
provider := p.(*SCloudprovider)
query.Cloudaccount = []string{provider.CloudaccountId}
}
if len(query.Cloudaccount) > 0 {
accountIds := []string{}
for _, _account := range query.Cloudaccount {
account, err := CloudaccountManager.FetchByIdOrName(userCred, _account)
if err != nil {
if errors.Cause(err) == sql.ErrNoRows {
return nil, httperrors.NewResourceNotFoundError2("cloudaccount", _account)
}
return nil, httperrors.NewGeneralError(err)
}
accountIds = append(accountIds, account.GetId())
}
q = q.In("cloudaccount_id", accountIds)
}
return q, nil
}
@@ -331,9 +351,9 @@ func (manager *SExternalProjectManager) OrderByExtraFields(
) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StandaloneResourceListInput)
q, err = manager.SStatusStandaloneResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.StatusStandaloneResourceListInput)
if err != nil {
return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.OrderByExtraFields")
return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.OrderByExtraFields")
}
q, err = manager.SManagedResourceBaseManager.OrderByExtraFields(ctx, q, userCred, query.ManagedResourceListInput)
if err != nil {
@@ -350,7 +370,7 @@ func (manager *SExternalProjectManager) OrderByExtraFields(
func (manager *SExternalProjectManager) QueryDistinctExtraField(q *sqlchemy.SQuery, field string) (*sqlchemy.SQuery, error) {
var err error
q, err = manager.SStandaloneResourceBaseManager.QueryDistinctExtraField(q, field)
q, err = manager.SStatusStandaloneResourceBaseManager.QueryDistinctExtraField(q, field)
if err == nil {
return q, nil
}
@@ -368,9 +388,9 @@ func (manager *SExternalProjectManager) QueryDistinctExtraField(q *sqlchemy.SQue
func (manager *SExternalProjectManager) ListItemExportKeys(ctx context.Context, q *sqlchemy.SQuery, userCred mcclient.TokenCredential,
keys stringutils2.SSortedStrings) (*sqlchemy.SQuery, error) {
q, err := manager.SStandaloneResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
q, err := manager.SStatusStandaloneResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
return nil, errors.Wrap(err, "SStandaloneResourceBaseManager.ListItemExportKeys")
return nil, errors.Wrap(err, "SStatusStandaloneResourceBaseManager.ListItemExportKeys")
}
q, err = manager.SProjectizedResourceBaseManager.ListItemExportKeys(ctx, q, userCred, keys)
if err != nil {
@@ -378,3 +398,23 @@ func (manager *SExternalProjectManager) ListItemExportKeys(ctx context.Context,
}
return q, nil
}
func (manager *SExternalProjectManager) InitializeData() error {
eps := []SExternalProject{}
q := manager.Query().IsNullOrEmpty("cloudaccount_id")
err := db.FetchModelObjects(manager, q, &eps)
if err != nil {
return err
}
for i := range eps {
_, err = db.Update(&eps[i], func() error {
provider := eps[i].GetCloudprovider()
if provider == nil {
return fmt.Errorf("failed to get external project %s cloudprovider", eps[i].Id)
}
eps[i].CloudaccountId = provider.CloudaccountId
return nil
})
}
return nil
}

View File

@@ -58,6 +58,7 @@ func InitDB() error {
ElasticcacheSkuManager,
ScheduledTaskActivityManager,
ExternalProjectManager,
} {
err := manager.InitializeData()
if err != nil {

View File

@@ -1039,20 +1039,6 @@ func (manager *SCloudproviderregionManager) purgeAll(ctx context.Context, userCr
return nil
}
func (manager *SExternalProjectManager) purgeAll(ctx context.Context, userCred mcclient.TokenCredential, providerId string) error {
projs, err := manager.getProjectsByProviderId(providerId)
if err != nil {
return err
}
for i := range projs {
err = projs[i].Delete(ctx, userCred)
if err != nil {
return err
}
}
return nil
}
func (zone *SZone) Purge(ctx context.Context, userCred mcclient.TokenCredential) error {
lockman.LockObject(ctx, zone)
defer lockman.ReleaseObject(ctx, zone)

View File

@@ -16,6 +16,7 @@ package tasks
import (
"context"
"fmt"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
@@ -23,6 +24,7 @@ import (
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/taskman"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/compute/models"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/util/logclient"
@@ -56,6 +58,26 @@ func (self *CloudAccountSyncInfoTask) OnInit(ctx context.Context, obj db.IStanda
return
}
driver, err := cloudaccount.GetProvider()
if err != nil {
cloudaccount.MarkEndSyncWithLock(ctx, self.UserCred)
db.OpsLog.LogEvent(cloudaccount, db.ACT_SYNC_HOST_FAILED, err, self.UserCred)
self.SetStageFailed(ctx, err.Error())
logclient.AddActionLogWithStartable(self, cloudaccount, logclient.ACT_CLOUD_SYNC, err, self.UserCred, false)
return
}
if cloudprovider.IsSupportProject(driver) {
projects, err := driver.GetIProjects()
if err != nil {
msg := fmt.Sprintf("GetIProjects for cloudaccount %s failed %s", cloudaccount.GetName(), err)
log.Errorf(msg)
} else {
result := models.ExternalProjectManager.SyncProjects(ctx, self.GetUserCred(), cloudaccount, projects)
log.Infof("Sync project for cloudaccount %s result: %s", cloudaccount.GetName(), result.Result())
}
}
syncRange := models.SSyncRange{}
syncRangeJson, _ := self.Params.Get("sync_range")
if syncRangeJson != nil {

View File

@@ -20,6 +20,7 @@ import (
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
)
@@ -51,7 +52,16 @@ func (self *SResourceGroup) GetName() string {
}
func (self *SResourceGroup) GetStatus() string {
return ""
switch self.Status {
case "Creating":
return api.EXTERNAL_PROJECT_STATUS_CREATING
case "OK":
return api.EXTERNAL_PROJECT_STATUS_AVAILABLE
case "Deleted", "Deleting", "PendingDelete":
return api.EXTERNAL_PROJECT_STATUS_DELETING
default:
return api.EXTERNAL_PROJECT_STATUS_UNKNOWN
}
}
func (self *SAliyunClient) GetResourceGroups(pageNumber int, pageSize int) ([]SResourceGroup, int, error) {

View File

@@ -19,6 +19,8 @@ import (
"strings"
"yunion.io/x/jsonutils"
api "yunion.io/x/onecloud/pkg/apis/compute"
)
type GroupProperties struct {
@@ -75,7 +77,7 @@ func (r *SResourceGroup) GetGlobalId() string {
}
func (r *SResourceGroup) GetStatus() string {
return r.Properties.ProvisioningState
return api.EXTERNAL_PROJECT_STATUS_AVAILABLE
}
func (r *SResourceGroup) GetMetadata() *jsonutils.JSONDict {

View File

@@ -0,0 +1,106 @@
// 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 esxi
import (
"context"
"fmt"
"github.com/vmware/govmomi/object"
"github.com/vmware/govmomi/vim25/mo"
"github.com/vmware/govmomi/vim25/types"
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
type SCluster struct {
SManagedObject
}
func NewCluster(manager *SESXiClient, cluster *mo.ClusterComputeResource, dc *SDatacenter) *SCluster {
return &SCluster{SManagedObject: newManagedObject(manager, cluster, dc)}
}
func (cluster *SCluster) ListResourcePools() ([]mo.ResourcePool, error) {
var pools, result []mo.ResourcePool
err := cluster.manager.scanMObjects(cluster.object.Entity().Self, RESOURCEPOOL_PROPS, &pools)
if err != nil {
return nil, errors.Wrap(err, "scanMObjects")
}
for i := range pools {
if pools[i].Parent.Type == "ClusterComputeResource" {
continue
}
result = append(result, pools[i])
}
return result, nil
}
func (cluster *SCluster) getDefaultResourcePool() (mo.ResourcePool, error) {
pools := []mo.ResourcePool{}
err := cluster.manager.scanMObjects(cluster.object.Entity().Self, RESOURCEPOOL_PROPS, &pools)
if err != nil {
return mo.ResourcePool{}, errors.Wrap(err, "scanMObjects")
}
for i := range pools {
if pools[i].Parent.Type == "ClusterComputeResource" {
return pools[i], nil
}
}
return mo.ResourcePool{}, cloudprovider.ErrNotFound
}
func (cluster *SCluster) CreateResourcePool(name string) (*mo.ResourcePool, error) {
if len(name) == 0 {
return nil, errors.Error("empty name str")
}
root, err := cluster.getDefaultResourcePool()
if err != nil {
return nil, errors.Wrap(err, "getDefaultResourcePool")
}
pool := object.NewResourcePool(cluster.manager.client.Client, root.Reference())
pool.InventoryPath = fmt.Sprintf("/%s/host/%s/Resources", cluster.datacenter.GetName(), cluster.GetName())
_, err = pool.Create(context.Background(), name, types.DefaultResourceConfigSpec())
if err != nil {
return nil, errors.Wrap(err, "pool.Create")
}
pools, err := cluster.ListResourcePools()
if err != nil {
return nil, errors.Wrap(err, "listResourcePools")
}
for i := range pools {
p := NewResourcePool(cluster.manager, &pools[i], cluster.datacenter)
if p.GetName() == name {
return &pools[i], nil
}
}
return nil, errors.Wrap(cloudprovider.ErrNotFound, "AfterCreate")
}
func (cluster *SCluster) SyncResourcePool(groupId string, name string) (*mo.ResourcePool, error) {
pools, err := cluster.ListResourcePools()
if err != nil {
return nil, errors.Wrap(err, "ListResourcePools")
}
for i := range pools {
if pools[i].Self.Value == groupId || pools[i].Entity().Name == name {
return &pools[i], nil
}
}
return cluster.CreateResourcePool(name)
}

View File

@@ -22,7 +22,6 @@ import (
"github.com/vmware/govmomi/vim25/types"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/utils"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
@@ -67,18 +66,14 @@ func (dc *SDatacenter) getObjectDatacenter() *object.Datacenter {
func (dc *SDatacenter) scanResourcePool() error {
if dc.iresoucePool == nil {
var pools []mo.ResourcePool
err := dc.manager.scanMObjects(dc.object.Entity().Self, RESOURCEPOOL_PROPS, &pools)
pools, err := dc.listResourcePools()
if err != nil {
return errors.Wrap(err, "scanMObjects")
return errors.Wrap(err, "listResourcePools")
}
dc.iresoucePool = []cloudprovider.ICloudProject{}
for i := 0; i < len(pools); i++ {
p := NewResourcePool(dc.manager, &pools[i], dc)
rpPath := p.GetPath()
if utils.IsInStringArray("Resources", rpPath) && rpPath[len(rpPath)-1] != "Resources" {
dc.iresoucePool = append(dc.iresoucePool, p)
}
dc.iresoucePool = append(dc.iresoucePool, p)
}
}
return nil
@@ -117,6 +112,53 @@ func (dc *SDatacenter) GetResourcePools() ([]cloudprovider.ICloudProject, error)
return dc.iresoucePool, nil
}
func (dc *SDatacenter) listResourcePools() ([]mo.ResourcePool, error) {
var pools, result []mo.ResourcePool
err := dc.manager.scanMObjects(dc.object.Entity().Self, RESOURCEPOOL_PROPS, &pools)
if err != nil {
return nil, errors.Wrap(err, "scanMObjects")
}
for i := range pools {
if pools[i].Parent.Type == "ClusterComputeResource" {
continue
}
result = append(result, pools[i])
}
return result, nil
}
func (dc *SDatacenter) ListClusters() ([]*SCluster, error) {
return dc.listClusters()
}
func (dc *SDatacenter) GetCluster(cluster string) (*SCluster, error) {
clusters, err := dc.ListClusters()
if err != nil {
return nil, errors.Wrap(err, "ListClusters")
}
for i := range clusters {
if clusters[i].GetName() == cluster {
return clusters[i], nil
}
}
return nil, cloudprovider.ErrNotFound
}
func (dc *SDatacenter) listClusters() ([]*SCluster, error) {
clusters := []mo.ClusterComputeResource{}
err := dc.manager.scanMObjects(dc.object.Entity().Self, RESOURCEPOOL_PROPS, &clusters)
if err != nil {
return nil, errors.Wrap(err, "scanMObjects")
}
ret := []*SCluster{}
for i := range clusters {
c := NewCluster(dc.manager, &clusters[i], dc)
ret = append(ret, c)
}
return ret, nil
}
func (dc *SDatacenter) GetIHosts() ([]cloudprovider.ICloudHost, error) {
err := dc.scanHosts()
if err != nil {

View File

@@ -645,15 +645,17 @@ func (self *SHost) CreateVM(desc *cloudprovider.SManagedVMCreateConfig) (cloudpr
}
type SCreateVMParam struct {
Name string
Uuid string
OsName string
Cpu int
Mem int
Bios string
Cdrom jsonutils.JSONObject
Disks []SDiskInfo
Nics []jsonutils.JSONObject
Name string
Uuid string
OsName string
Cpu int
Mem int
Bios string
Cdrom jsonutils.JSONObject
Disks []SDiskInfo
Nics []jsonutils.JSONObject
GroupId string // resourcePoolId
ResourcePool string
}
type SDiskInfo struct {
@@ -840,9 +842,9 @@ func (self *SHost) DoCreateVM(ctx context.Context, ds *SDatastore, params SCreat
return nil, errors.Wrap(err, "object.DataCenter.Folders")
}
vmFolder := folders.VmFolder
resourcePool, err := self.GetResourcePool()
resourcePool, err := self.SyncResourcePool(params.GroupId, params.ResourcePool)
if err != nil {
return nil, errors.Wrap(err, "SHost.GetResourcePool")
return nil, errors.Wrap(err, "SyncResourcePool")
}
task, err := vmFolder.CreateVM(ctx, spec, resourcePool, self.GetoHostSystem())
if err != nil {
@@ -1357,7 +1359,7 @@ func (host *SHost) GetoHostSystem() *object.HostSystem {
func (host *SHost) GetResourcePool() (*object.ResourcePool, error) {
var err error
if host.parent == nil {
host.parent, err = host.getResourcePool()
host.parent, err = host.getParent()
if err != nil {
return nil, err
}
@@ -1365,7 +1367,7 @@ func (host *SHost) GetResourcePool() (*object.ResourcePool, error) {
return object.NewResourcePool(host.manager.client.Client, *host.parent.ResourcePool), nil
}
func (host *SHost) getResourcePool() (*mo.ComputeResource, error) {
func (host *SHost) getParent() (*mo.ComputeResource, error) {
var mcr *mo.ComputeResource
var parent interface{}
@@ -1383,19 +1385,58 @@ func (host *SHost) getResourcePool() (*mo.ComputeResource, error) {
return nil, errors.Error(fmt.Sprintf("unknown host parent type: %s", moHost.Parent.Type))
}
err := host.manager.reference2Object(*moHost.Parent, []string{"resourcePool"}, parent)
err := host.manager.reference2Object(*moHost.Parent, []string{"name", "resourcePool"}, parent)
if err != nil {
return nil, errors.Wrap(err, "SESXiClient.reference2Object")
}
return mcr, nil
}
func (host *SHost) GetCluster() (*mo.ComputeResource, error) {
return host.getResourcePool()
func (host *SHost) GetResourcePools() ([]mo.ResourcePool, error) {
cluster, err := host.GetCluster()
if err != nil {
return nil, errors.Wrap(err, "GetCluster")
}
return cluster.ListResourcePools()
}
func (host *SHost) GetCluster() (*SCluster, error) {
cluster, err := host.getCluster()
if err != nil {
return nil, errors.Wrap(err, "getCluster")
}
return NewCluster(host.manager, cluster, host.datacenter), nil
}
func (host *SHost) SyncResourcePool(groupId, name string) (*object.ResourcePool, error) {
cluster, err := host.GetCluster()
if err != nil {
log.Errorf("failed to get host %s cluster info: %v", host.GetName(), err)
return host.GetResourcePool()
}
pool, err := cluster.SyncResourcePool(groupId, name)
if err != nil {
log.Errorf("failed to sync resourcePool(%s, %s) for cluster %s error: %v", groupId, name, cluster.GetName(), err)
return host.GetResourcePool()
}
return object.NewResourcePool(host.manager.client.Client, pool.Reference()), nil
}
func (host *SHost) getCluster() (*mo.ClusterComputeResource, error) {
moHost := host.getHostSystem()
if moHost.Parent.Type != "ClusterComputeResource" {
return nil, fmt.Errorf("host %s parent is not the cluster resource", host.GetName())
}
cluster := &mo.ClusterComputeResource{}
err := host.manager.reference2Object(*moHost.Parent, []string{"name", "resourcePool"}, cluster)
if err != nil {
return nil, errors.Wrap(err, "SESXiClient.reference2Object")
}
return cluster, nil
}
func (host *SHost) GetSiblingHosts() ([]*SHost, error) {
rp, err := host.GetCluster()
rp, err := host.getParent()
if err != nil {
return nil, err
}

View File

@@ -15,8 +15,12 @@
package esxi
import (
"net/url"
"strings"
"github.com/vmware/govmomi/vim25/mo"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/multicloud"
)
@@ -32,12 +36,20 @@ func (pool *SResourcePool) GetGlobalId() string {
}
func (pool *SResourcePool) GetStatus() string {
return ""
return api.EXTERNAL_PROJECT_STATUS_AVAILABLE
}
func (pool *SResourcePool) GetName() string {
path := pool.GetPath()
return path[len(path)-1]
if len(path) > 5 {
path = path[5:]
}
name := []string{}
for _, _name := range path {
p, _ := url.PathUnescape(_name)
name = append([]string{p}, name...)
}
return strings.Join(name, "/")
}
func NewResourcePool(manager *SESXiClient, rp *mo.ResourcePool, dc *SDatacenter) *SResourcePool {

View File

@@ -0,0 +1,87 @@
// 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 shell
import (
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/multicloud/esxi"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type ClusterListOptions struct {
DATACENTER string `help:"List clusters in datacenter"`
}
shellutils.R(&ClusterListOptions{}, "cluster-list", "List all clusters", func(cli *esxi.SESXiClient, args *ClusterListOptions) error {
dc, err := cli.FindDatacenterByMoId(args.DATACENTER)
if err != nil {
return err
}
clusters, err := dc.ListClusters()
if err != nil {
return err
}
printList(clusters, nil)
return nil
})
type ClusterPoolListOptions struct {
DATACENTER string `help:"List clusters in datacenter"`
CLUSTER string `help:"List cluster resource pool"`
}
shellutils.R(&ClusterPoolListOptions{}, "cluster-pool-list", "List all cluster resource pool", func(cli *esxi.SESXiClient, args *ClusterPoolListOptions) error {
dc, err := cli.FindDatacenterByMoId(args.DATACENTER)
if err != nil {
return err
}
cluster, err := dc.GetCluster(args.CLUSTER)
if err != nil {
return err
}
pools, err := cluster.ListResourcePools()
if err != nil {
return errors.Wrap(err, "ListResourcePools")
}
printList(pools, nil)
return nil
})
type ClusterPoolSyncOptions struct {
DATACENTER string `help:"List clusters in datacenter"`
CLUSTER string `help:"List cluster resource pool"`
GroupId string `help:"Resource pool Id"`
Name string `help:"Resource pool name"`
}
shellutils.R(&ClusterPoolSyncOptions{}, "cluster-pool-sync", "Sync cluster resource pool", func(cli *esxi.SESXiClient, args *ClusterPoolSyncOptions) error {
dc, err := cli.FindDatacenterByMoId(args.DATACENTER)
if err != nil {
return err
}
cluster, err := dc.GetCluster(args.CLUSTER)
if err != nil {
return err
}
pool, err := cluster.SyncResourcePool(args.GroupId, args.Name)
if err != nil {
return errors.Wrap(err, "SyncResourcePool")
}
printObject(pool)
return nil
})
}

View File

@@ -89,4 +89,32 @@ func init() {
printList(networks, nil)
return nil
})
shellutils.R(&HostShowOptions{}, "host-cluster", "Show host cluster", func(cli *esxi.SESXiClient,
args *HostShowOptions) error {
host, err := cli.FindHostByIp(args.IP)
if err != nil {
return err
}
cluster, err := host.GetCluster()
if err != nil {
return err
}
printObject(cluster)
return nil
})
shellutils.R(&HostShowOptions{}, "host-pool-list", "List host pools", func(cli *esxi.SESXiClient,
args *HostShowOptions) error {
host, err := cli.FindHostByIp(args.IP)
if err != nil {
return err
}
pool, err := host.GetResourcePool()
if err != nil {
return err
}
printObject(pool)
return nil
})
}

View File

@@ -15,6 +15,8 @@
package shell
import (
"yunion.io/x/pkg/errors"
"yunion.io/x/onecloud/pkg/multicloud/esxi"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
@@ -35,4 +37,27 @@ func init() {
printList(pools, nil)
return nil
})
type ResourcePoolCreateOptions struct {
DATACENTER string `help:"Create resource pool in datacenter"`
CLUSTER string `help:"Cluster name"`
NAME string `help:"Resource pool name"`
}
shellutils.R(&ResourcePoolCreateOptions{}, "resource-pool-create", "Create resource pool", func(cli *esxi.SESXiClient, args *ResourcePoolCreateOptions) error {
dc, err := cli.FindDatacenterByMoId(args.DATACENTER)
if err != nil {
return err
}
cluster, err := dc.GetCluster(args.CLUSTER)
if err != nil {
return errors.Wrap(err, "GetCluster")
}
pool, err := cluster.CreateResourcePool(args.NAME)
if err != nil {
return err
}
printObject(pool)
return nil
})
}

View File

@@ -17,9 +17,10 @@ package google
import (
"time"
"github.com/pkg/errors"
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
)
type SProject struct {
@@ -84,7 +85,7 @@ func (p *SProject) GetGlobalId() string {
}
func (p *SProject) GetStatus() string {
return ""
return api.EXTERNAL_PROJECT_STATUS_AVAILABLE
}
func (p *SProject) Refresh() error {

View File

@@ -21,6 +21,7 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
"yunion.io/x/onecloud/pkg/multicloud"
)
@@ -60,9 +61,9 @@ func (ep *SEnterpriseProject) GetGlobalId() string {
func (ep *SEnterpriseProject) GetStatus() string {
if ep.Status == 1 {
return "available"
return api.EXTERNAL_PROJECT_STATUS_AVAILABLE
}
return "unavailable"
return api.EXTERNAL_PROJECT_STATUS_UNAVAILABLE
}
func (ep *SEnterpriseProject) GetName() string {

View File

@@ -14,7 +14,11 @@
package openstack
import "yunion.io/x/jsonutils"
import (
"yunion.io/x/jsonutils"
api "yunion.io/x/onecloud/pkg/apis/compute"
)
type SProject struct {
Description string
@@ -40,7 +44,7 @@ func (p *SProject) GetName() string {
}
func (p *SProject) GetStatus() string {
return ""
return api.EXTERNAL_PROJECT_STATUS_AVAILABLE
}
func (p *SProject) IsEmulated() bool {

View File

@@ -22,6 +22,7 @@ import (
"yunion.io/x/jsonutils"
"yunion.io/x/pkg/errors"
api "yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
@@ -59,7 +60,7 @@ func (p *SProject) GetName() string {
}
func (p *SProject) GetStatus() string {
return ""
return api.EXTERNAL_PROJECT_STATUS_AVAILABLE
}
func (p *SProject) IsEmulated() bool {