diff --git a/cmd/climc/shell/cloudproviders.go b/cmd/climc/shell/cloudproviders.go index f35da1d11f..e582e8e1a4 100644 --- a/cmd/climc/shell/cloudproviders.go +++ b/cmd/climc/shell/cloudproviders.go @@ -20,7 +20,6 @@ func init() { params, err = args.BaseListOptions.Params() if err != nil { return err - } } result, err := modules.Cloudproviders.List(s, params) @@ -139,12 +138,13 @@ func init() { }) type CloudproviderSyncOptions struct { - ID string `help:"ID or Name of cloud provider"` - Force bool `help:"Force sync no matter what"` - FullSync bool `help:"Synchronize everything"` - Region []string `help:"region to sync"` - Zone []string `help:"region to sync"` - Host []string `help:"region to sync"` + ID string `help:"ID or Name of cloud provider"` + Force bool `help:"Force sync no matter what"` + FullSync bool `help:"Synchronize everything"` + ProjectSync bool `help:"Auto sync project info"` + Region []string `help:"region to sync"` + Zone []string `help:"region to sync"` + Host []string `help:"region to sync"` } R(&CloudproviderSyncOptions{}, "cloud-provider-sync", "Sync of a cloud provider account", func(s *mcclient.ClientSession, args *CloudproviderSyncOptions) error { params := jsonutils.NewDict() @@ -154,6 +154,9 @@ func init() { if args.FullSync { params.Add(jsonutils.JSONTrue, "full_sync") } + if args.ProjectSync { + params.Add(jsonutils.JSONTrue, "project_sync") + } if len(args.Region) > 0 { params.Add(jsonutils.NewStringArray(args.Region), "region") } diff --git a/cmd/climc/shell/external_projects.go b/cmd/climc/shell/external_projects.go new file mode 100644 index 0000000000..409cd5e5f1 --- /dev/null +++ b/cmd/climc/shell/external_projects.go @@ -0,0 +1,44 @@ +package shell + +import ( + "yunion.io/x/jsonutils" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" +) + +func init() { + type ExternalProjectListOptions struct { + options.BaseListOptions + } + R(&ExternalProjectListOptions{}, "external-project-list", "List public cloud projects", func(s *mcclient.ClientSession, opts *ExternalProjectListOptions) error { + params, err := options.ListStructToParams(opts) + if err != nil { + return err + } + + result, err := modules.ExternalProjects.List(s, params) + if err != nil { + return err + } + printList(result, modules.Disks.GetColumns(s)) + return nil + }) + + type ExternalProjectUpdateOptions struct { + ID string `help:"ExternalProject ID or Name"` + PROJECT string `help:"Local project ID or Name"` + } + + R(&ExternalProjectUpdateOptions{}, "external-project-update", "Update external project point to local project", func(s *mcclient.ClientSession, args *ExternalProjectUpdateOptions) error { + params := jsonutils.NewDict() + params.Add(jsonutils.NewString(args.PROJECT), "project") + result, err := modules.ExternalProjects.Update(s, args.ID, params) + if err != nil { + return err + } + printObject(result) + return nil + }) + +} diff --git a/cmd/qcloudcli/main.go b/cmd/qcloudcli/main.go index 6764f03e00..3409e282b8 100644 --- a/cmd/qcloudcli/main.go +++ b/cmd/qcloudcli/main.go @@ -13,6 +13,7 @@ import ( ) type BaseOptions struct { + Debug bool `help:"debug mode"` Help bool `help:"Show help"` AppID string `help:"AppID" default:"$QCLOUD_APPID"` SecretID string `help:"Secret" default:"$QCLOUD_SECRET_ID"` @@ -75,7 +76,7 @@ func newClient(options *BaseOptions) (*qcloud.SRegion, error) { account = fmt.Sprintf("%s/%s", account, options.AppID) } - if cli, err := qcloud.NewQcloudClient("", "", account, options.SecretKey); err != nil { + if cli, err := qcloud.NewQcloudClient("", "", account, options.SecretKey, options.Debug); err != nil { return nil, err } else if region := cli.GetRegion(options.RegionId); region == nil { return nil, fmt.Errorf("No such region %s", options.RegionId) diff --git a/pkg/cloudcommon/db/opslog.go b/pkg/cloudcommon/db/opslog.go index 0ffee3eb56..9177bd8743 100644 --- a/pkg/cloudcommon/db/opslog.go +++ b/pkg/cloudcommon/db/opslog.go @@ -127,6 +127,8 @@ const ( ACT_SYNCING_HOST = "syncing_host" ACT_SYNC_HOST_COMPLETE = "sync_host_end" + ACT_SYNC_PROJECT_COMPLETE = "sync_project_end" + ACT_SYNC_LB_START = "sync_lb_start" ACT_SYNCING_LB = "syncing_lb" ACT_SYNC_LB_COMPLETE = "sync_lb_end" @@ -138,9 +140,10 @@ const ( ACT_UNCACHE_IMAGE_FAIL = "uncache_image_fail" ACT_UNCACHED_IMAGE = "uncached_image" - ACT_SYNC_CLOUD_DISK = "sync_cloud_disk" - ACT_SYNC_CLOUD_SERVER = "sync_cloud_server" - ACT_SYNC_CLOUD_EIP = "sync_cloud_eip" + ACT_SYNC_CLOUD_DISK = "sync_cloud_disk" + ACT_SYNC_CLOUD_SERVER = "sync_cloud_server" + ACT_SYNC_CLOUD_EIP = "sync_cloud_eip" + ACT_SYNC_CLOUD_PROJECT = "sync_cloud_project" ACT_PENDING_DELETE = "pending_delete" ACT_CANCEL_DELETE = "cancel_delete" diff --git a/pkg/cloudcommon/db/virtualresource.go b/pkg/cloudcommon/db/virtualresource.go index 531b782673..a1cb9997e5 100644 --- a/pkg/cloudcommon/db/virtualresource.go +++ b/pkg/cloudcommon/db/virtualresource.go @@ -17,6 +17,11 @@ import ( "yunion.io/x/onecloud/pkg/util/logclient" ) +const ( + PROJECT_SOURCE_LOCAL = "local" + PROJECT_SOURCE_CLOUD = "cloud" +) + type SVirtualResourceBaseManager struct { SStatusStandaloneResourceBaseManager } @@ -29,7 +34,8 @@ func NewVirtualResourceBaseManager(dt interface{}, tableName string, keyword str type SVirtualResourceBase struct { SStatusStandaloneResourceBase - ProjectId string `name:"tenant_id" width:"128" charset:"ascii" nullable:"false" index:"true" list:"user"` + ProjectId string `name:"tenant_id" width:"128" charset:"ascii" nullable:"false" index:"true" list:"user"` + ProjectSrc string `width:"10" charset:"ascii" nullable:"false" list:"user" default:"local"` IsSystem bool `nullable:"true" default:"false" list:"admin" create:"optional"` @@ -227,6 +233,7 @@ func (model *SVirtualResourceBase) PerformChangeOwner(ctx context.Context, userC } _, err := model.GetModelManager().TableSpec().Update(model, func() error { model.ProjectId = tobj.GetId() + model.ProjectSrc = PROJECT_SOURCE_LOCAL return nil }) if err != nil { diff --git a/pkg/cloudprovider/cloudprovider.go b/pkg/cloudprovider/cloudprovider.go index 1e3465e31c..16eb2a088e 100644 --- a/pkg/cloudprovider/cloudprovider.go +++ b/pkg/cloudprovider/cloudprovider.go @@ -43,6 +43,7 @@ type ICloudProvider interface { GetVersion() string GetIRegions() []ICloudRegion + GetIProjects() ([]ICloudProject, error) GetIRegionById(id string) (ICloudRegion, error) GetOnPremiseIRegion() (ICloudRegion, error) diff --git a/pkg/cloudprovider/resources.go b/pkg/cloudprovider/resources.go index 8da284d0db..9c5a8cff1a 100644 --- a/pkg/cloudprovider/resources.go +++ b/pkg/cloudprovider/resources.go @@ -25,6 +25,10 @@ type ICloudResource interface { GetMetadata() *jsonutils.JSONDict } +type IVirtualResource interface { + GetProjectId() string +} + type IBillingResource interface { GetBillingType() string GetExpiredAt() time.Time @@ -190,6 +194,7 @@ type ICloudHost interface { type ICloudVM interface { ICloudResource IBillingResource + IVirtualResource GetCreateTime() time.Time GetIHost() ICloudHost @@ -254,6 +259,7 @@ type ICloudNic interface { type ICloudEIP interface { ICloudResource IBillingResource + IVirtualResource GetIpAddr() string GetMode() string @@ -276,6 +282,7 @@ type ICloudEIP interface { type ICloudSecurityGroup interface { ICloudResource + IVirtualResource GetDescription() string GetRules() ([]secrules.SecurityRule, error) @@ -303,6 +310,7 @@ type ICloudRoute interface { type ICloudDisk interface { ICloudResource IBillingResource + IVirtualResource GetIStorage() (ICloudStorage, error) @@ -335,6 +343,8 @@ type ICloudDisk interface { type ICloudSnapshot interface { ICloudResource + IVirtualResource + GetSize() int32 GetDiskId() string GetDiskType() string @@ -373,6 +383,7 @@ type ICloudWire interface { type ICloudNetwork interface { ICloudResource + IVirtualResource GetIWire() ICloudWire // GetStatus() string @@ -401,6 +412,7 @@ type ICloudHostNetInterface interface { type ICloudLoadbalancer interface { ICloudResource + IVirtualResource GetAddress() string GetAddressType() string @@ -428,6 +440,7 @@ type ICloudLoadbalancer interface { type ICloudLoadbalancerListener interface { ICloudResource + IVirtualResource GetListenerType() string GetListenerPort() int @@ -487,6 +500,7 @@ type ICloudLoadbalancerListenerRule interface { type ICloudLoadbalancerBackendGroup interface { ICloudResource + IVirtualResource IsDefault() bool GetType() string @@ -500,6 +514,7 @@ type ICloudLoadbalancerBackendGroup interface { type ICloudLoadbalancerBackend interface { ICloudResource + IVirtualResource GetWeight() int GetPort() int @@ -510,6 +525,7 @@ type ICloudLoadbalancerBackend interface { type ICloudLoadbalancerCertificate interface { ICloudResource + IVirtualResource Sync(name, privateKey, publickKey string) error Delete() error @@ -522,6 +538,7 @@ type ICloudLoadbalancerCertificate interface { type ICloudLoadbalancerAcl interface { ICloudResource + IVirtualResource GetAclEntries() []SLoadbalancerAccessControlListEntry Sync(acl *SLoadbalancerAccessControlList) error @@ -562,3 +579,7 @@ type ICloudSku interface { GetGpuCount() int GetGpuMaxCount() int } + +type ICloudProject interface { + ICloudResource +} diff --git a/pkg/compute/models/disks.go b/pkg/compute/models/disks.go index eb6e852d43..94ad8b25b1 100644 --- a/pkg/compute/models/disks.go +++ b/pkg/compute/models/disks.go @@ -1004,6 +1004,7 @@ func (self *SDisk) syncWithCloudDisk(ctx context.Context, userCred mcclient.Toke if provider.GetFactory().IsSupportPrepaidResources() && len(guests) == 1 && guests[0].IsPrepaidRecycle() { recycle = true } + storage := self.GetStorage() _, err := self.GetModelManager().TableSpec().Update(self, func() error { extDisk.Refresh() // self.Name = extDisk.GetName() @@ -1030,8 +1031,15 @@ func (self *SDisk) syncWithCloudDisk(ctx context.Context, userCred mcclient.Toke } // self.ProjectId = userCred.GetProjectId() - if projectSync && len(projectId) > 0 { - self.ProjectId = projectId + if projectSync && self.ProjectSrc != db.PROJECT_SOURCE_LOCAL { + if extProjectId := extDisk.GetProjectId(); len(extProjectId) > 0 { + extProject, err := ExternalProjectManager.GetProject(extProjectId, storage.ManagerId) + if err != nil { + log.Errorf(err.Error()) + } else { + self.ProjectId = extProject.ProjectId + } + } } return nil }) @@ -1064,10 +1072,19 @@ func (manager *SDiskManager) newFromCloudDisk(ctx context.Context, userCred mccl disk.Status = extDisk.GetStatus() disk.ExternalId = extDisk.GetGlobalId() disk.StorageId = storage.Id + disk.ProjectSrc = db.PROJECT_SOURCE_CLOUD disk.ProjectId = userCred.GetProjectId() if len(projectId) > 0 { disk.ProjectId = projectId } + if extProjectId := extDisk.GetProjectId(); len(extProjectId) > 0 { + externalProject, err := ExternalProjectManager.GetProject(extProjectId, storage.ManagerId) + if err != nil { + log.Errorf(err.Error()) + } else { + disk.ProjectId = externalProject.ProjectId + } + } disk.DiskFormat = extDisk.GetDiskFormat() disk.DiskSize = extDisk.GetDiskSizeMB() disk.AutoDelete = extDisk.GetIsAutoDelete() diff --git a/pkg/compute/models/elasticips.go b/pkg/compute/models/elasticips.go index dd90cf12a0..36b2d13792 100644 --- a/pkg/compute/models/elasticips.go +++ b/pkg/compute/models/elasticips.go @@ -302,8 +302,15 @@ func (self *SElasticip) SyncWithCloudEip(userCred mcclient.TokenCredential, prov // self.ManagerId = ext.GetManagerId() self.IsEmulated = ext.IsEmulated() self.ProjectId = userCred.GetProjectId() - if projectSync && len(projectId) > 0 { - self.ProjectId = projectId + if projectSync && self.ProjectSrc != db.PROJECT_SOURCE_LOCAL { + if extProjectId := ext.GetProjectId(); len(extProjectId) > 0 { + extProject, err := ExternalProjectManager.GetProject(extProjectId, self.ManagerId) + if err != nil { + log.Errorf(err.Error()) + } else { + self.ProjectId = extProject.ProjectId + } + } } self.ChargeType = ext.GetInternetChargeType() @@ -335,11 +342,21 @@ func (manager *SElasticipManager) newFromCloudEip(ctx context.Context, userCred eip.CloudregionId = region.Id eip.ChargeType = extEip.GetInternetChargeType() + eip.ProjectSrc = db.PROJECT_SOURCE_CLOUD eip.ProjectId = userCred.GetProjectId() if len(projectId) > 0 { eip.ProjectId = projectId } + if extProjectId := extEip.GetProjectId(); len(extProjectId) > 0 { + externalProject, err := ExternalProjectManager.GetProject(extProjectId, eip.ManagerId) + if err != nil { + log.Errorf(err.Error()) + } else { + eip.ProjectId = externalProject.ProjectId + } + } + err := manager.TableSpec().Insert(&eip) if err != nil { log.Errorf("newFromCloudEip fail %s", err) diff --git a/pkg/compute/models/external_projects.go b/pkg/compute/models/external_projects.go new file mode 100644 index 0000000000..670eafb622 --- /dev/null +++ b/pkg/compute/models/external_projects.go @@ -0,0 +1,188 @@ +package models + +import ( + "context" + "database/sql" + "fmt" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/cloudprovider" + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/pkg/util/compare" +) + +type SExternalProjectManager struct { + db.SStandaloneResourceBaseManager +} + +var ExternalProjectManager *SExternalProjectManager + +func init() { + ExternalProjectManager = &SExternalProjectManager{ + SStandaloneResourceBaseManager: db.NewStandaloneResourceBaseManager( + SExternalProject{}, + "externalprojects_tbl", + "externalproject", + "externalprojects", + ), + } +} + +type SExternalProject struct { + db.SStandaloneResourceBase + SManagedResourceBase + + ProjectId string `name:"tenant_id" width:"128" charset:"ascii" nullable:"true" list:"admin" update:"admin"` +} + +func (manager *SExternalProjectManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { + return db.IsAdminAllowList(userCred, manager) +} + +func (self *SExternalProject) AllowUpdateItem(ctx context.Context, userCred mcclient.TokenCredential) bool { + return db.IsAdminAllowUpdate(userCred, self) +} + +func (self *SExternalProject) ValidateUpdateData(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data *jsonutils.JSONDict) (*jsonutils.JSONDict, error) { + if project := jsonutils.GetAnyString(data, []string{"project_id", "project", "tenant_id", "tenant"}); len(project) > 0 { + _project, err := db.TenantCacheManager.FetchByIdOrName(userCred, project) + if err != nil { + if err == sql.ErrNoRows { + return nil, httperrors.NewTenantNotFoundError("tenant %s not find", project) + } + return nil, err + } + data.Set("tenant_id", jsonutils.NewString(_project.GetId())) + } + return self.SStandaloneResourceBase.ValidateUpdateData(ctx, userCred, query, data) +} + +func (manager *SExternalProjectManager) getProjectsByProvider(provider *SCloudprovider) ([]SExternalProject, error) { + projects := []SExternalProject{} + q := manager.Query() + if provider != nil { + q = q.Equals("manager_id", provider.Id) + } + err := db.FetchModelObjects(manager, q, &projects) + if err != nil { + return nil, err + } + return projects, nil +} + +func (self *SExternalProject) getMoreDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, extra *jsonutils.JSONDict) *jsonutils.JSONDict { + tenant, err := db.TenantCacheManager.FetchTenantById(ctx, self.ProjectId) + if err == nil { + extra.Add(jsonutils.NewString(tenant.GetName()), "tenant") + } + return extra +} + +func (self *SExternalProject) GetCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) *jsonutils.JSONDict { + extra := self.SStandaloneResourceBase.GetCustomizeColumns(ctx, userCred, query) + return self.getMoreDetails(ctx, userCred, query, extra) +} + +func (self *SExternalProject) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*jsonutils.JSONDict, error) { + extra, err := self.SStandaloneResourceBase.GetExtraDetails(ctx, userCred, query) + if err != nil { + return nil, err + } + return self.getMoreDetails(ctx, userCred, query, extra), nil +} + +func (manager *SExternalProjectManager) GetProject(externalId string, providerId string) (*SExternalProject, error) { + project := &SExternalProject{} + project.SetModelManager(manager) + q := manager.Query().Equals("external_id", externalId).Equals("manager_id", providerId) + count := q.Count() + if count == 0 { + return nil, fmt.Errorf("no external project record %s for provider %s", externalId, providerId) + } + if count > 1 { + return nil, fmt.Errorf("dumplicate external project record %s for provider %s", externalId, providerId) + } + return project, q.First(project) +} + +func (manager *SExternalProjectManager) SyncProjects(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, projects []cloudprovider.ICloudProject) compare.SyncResult { + syncResult := compare.SyncResult{} + + dbProjects, err := manager.getProjectsByProvider(provider) + if err != nil { + syncResult.Error(err) + return syncResult + } + + removed := make([]SExternalProject, 0) + commondb := make([]SExternalProject, 0) + commonext := make([]cloudprovider.ICloudProject, 0) + added := make([]cloudprovider.ICloudProject, 0) + + err = compare.CompareSets(dbProjects, projects, &removed, &commondb, &commonext, &added) + if err != nil { + syncResult.Error(err) + return syncResult + } + + for i := 0; i < len(removed); i++ { + err = removed[i].Delete(ctx, userCred) + if err != nil { + syncResult.DeleteError(err) + } else { + syncResult.Delete() + } + } + for i := 0; i < len(commondb); i++ { + err = commondb[i].SyncWithCloudProject(ctx, userCred, provider, commonext[i]) + if err != nil { + syncResult.UpdateError(err) + } else { + syncResult.Update() + } + } + for i := 0; i < len(added); i++ { + _, err := manager.newFromCloudProject(ctx, userCred, provider, added[i]) + if err != nil { + syncResult.AddError(err) + } else { + syncResult.Add() + } + } + return syncResult +} + +func (self *SExternalProject) SyncWithCloudProject(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, ext cloudprovider.ICloudProject) error { + _, err := self.GetModelManager().TableSpec().Update(self, func() error { + self.Name = ext.GetName() + self.IsEmulated = ext.IsEmulated() + return nil + }) + if err != nil { + log.Errorf("SyncWithCloudProject fail %s", err) + } + return err +} + +func (manager *SExternalProjectManager) newFromCloudProject(ctx context.Context, userCred mcclient.TokenCredential, provider *SCloudprovider, extProject cloudprovider.ICloudProject) (*SExternalProject, error) { + project := SExternalProject{} + project.SetModelManager(manager) + + project.Name = extProject.GetName() + project.ExternalId = extProject.GetGlobalId() + project.IsEmulated = extProject.IsEmulated() + project.ManagerId = provider.Id + project.ProjectId = provider.ProjectId + + err := manager.TableSpec().Insert(&project) + if err != nil { + log.Errorf("newFromCloudProject fail %s", err) + return nil, err + } + + db.OpsLog.LogEvent(&project, db.ACT_SYNC_CLOUD_PROJECT, project.GetShortDesc(ctx), userCred) + return &project, nil +} diff --git a/pkg/compute/models/guests.go b/pkg/compute/models/guests.go index 7e7c1dd6dd..b4aa7284ff 100644 --- a/pkg/compute/models/guests.go +++ b/pkg/compute/models/guests.go @@ -1853,8 +1853,15 @@ func (self *SGuest) syncWithCloudVM(ctx context.Context, userCred mcclient.Token self.VmemSize = extVM.GetVmemSizeMB() } - if projectSync && len(projectId) > 0 { - self.ProjectId = projectId + if projectSync && self.ProjectSrc != db.PROJECT_SOURCE_LOCAL { + if extProjectId := extVM.GetProjectId(); len(extProjectId) > 0 { + extProject, err := ExternalProjectManager.GetProject(extProjectId, host.ManagerId) + if err != nil { + log.Errorf(err.Error()) + } else { + self.ProjectId = extProject.ProjectId + } + } } self.Hypervisor = extVM.GetHypervisor() @@ -1978,10 +1985,19 @@ func (manager *SGuestManager) newCloudVM(ctx context.Context, userCred mcclient. guest.VmemSize = extVM.GetVmemSizeMB() } + guest.ProjectSrc = db.PROJECT_SOURCE_CLOUD guest.ProjectId = userCred.GetProjectId() if len(projectId) > 0 { guest.ProjectId = projectId } + if extProjectId := extVM.GetProjectId(); len(extProjectId) > 0 { + externalProject, err := ExternalProjectManager.GetProject(extProjectId, host.ManagerId) + if err != nil { + log.Errorf(err.Error()) + } else { + guest.ProjectId = externalProject.ProjectId + } + } extraSecgroups := []*SSecurityGroup{} if metaData != nil && metaData.Contains("secgroupIds") { diff --git a/pkg/compute/models/loadbalanceracls.go b/pkg/compute/models/loadbalanceracls.go index f4d727f63b..e4437484c7 100644 --- a/pkg/compute/models/loadbalanceracls.go +++ b/pkg/compute/models/loadbalanceracls.go @@ -384,11 +384,21 @@ func (man *SLoadbalancerAclManager) newFromCloudLoadbalancerAcl(ctx context.Cont acl.ManagerId = provider.Id acl.CloudregionId = region.Id + acl.ProjectSrc = db.PROJECT_SOURCE_CLOUD acl.ProjectId = userCred.GetProjectId() if len(provider.ProjectId) > 0 { acl.ProjectId = provider.ProjectId } + if extProjectId := extAcl.GetProjectId(); len(extProjectId) > 0 { + externalProject, err := ExternalProjectManager.GetProject(extProjectId, acl.ManagerId) + if err != nil { + log.Errorf(err.Error()) + } else { + acl.ProjectId = externalProject.ProjectId + } + } + acl.AclEntries = &SLoadbalancerAclEntries{} for _, entry := range extAcl.GetAclEntries() { *acl.AclEntries = append(*acl.AclEntries, &SLoadbalancerAclEntry{Cidr: entry.CIDR, Comment: entry.Comment}) @@ -403,8 +413,15 @@ func (acl *SLoadbalancerAcl) SyncWithCloudLoadbalancerAcl(ctx context.Context, u for _, entry := range extAcl.GetAclEntries() { *acl.AclEntries = append(*acl.AclEntries, &SLoadbalancerAclEntry{Cidr: entry.CIDR, Comment: entry.Comment}) } - if projectSync && len(projectId) > 0 { - acl.ProjectId = projectId + if projectSync && acl.ProjectSrc != db.PROJECT_SOURCE_LOCAL { + if extProjectId := extAcl.GetProjectId(); len(extProjectId) > 0 { + extProject, err := ExternalProjectManager.GetProject(extProjectId, acl.ManagerId) + if err != nil { + log.Errorf(err.Error()) + } else { + acl.ProjectId = extProject.ProjectId + } + } } return nil }) diff --git a/pkg/compute/models/loadbalancerbackendgroups.go b/pkg/compute/models/loadbalancerbackendgroups.go index 5e89ab27d6..6f9e666996 100644 --- a/pkg/compute/models/loadbalancerbackendgroups.go +++ b/pkg/compute/models/loadbalancerbackendgroups.go @@ -403,8 +403,15 @@ func (lbbg *SLoadbalancerBackendGroup) SyncWithCloudLoadbalancerBackendgroup(ctx _, err := lbbg.GetModelManager().TableSpec().Update(lbbg, func() error { lbbg.constructFieldsFromCloudBackendgroup(lb, extLoadbalancerBackendgroup) - if projectSync && len(projectId) > 0 { - lbbg.ProjectId = projectId + if projectSync && lbbg.ProjectSrc != db.PROJECT_SOURCE_LOCAL { + if extProjectId := extLoadbalancerBackendgroup.GetProjectId(); len(extProjectId) > 0 { + extProject, err := ExternalProjectManager.GetProject(extProjectId, lb.ManagerId) + if err != nil { + log.Errorf(err.Error()) + } else { + lbbg.ProjectId = extProject.ProjectId + } + } } if extLoadbalancerBackendgroup.IsDefault() { @@ -433,10 +440,21 @@ func (man *SLoadbalancerBackendGroupManager) newFromCloudLoadbalancerBackendgrou lbbg.ManagerId = lb.ManagerId lbbg.constructFieldsFromCloudBackendgroup(lb, extLoadbalancerBackendgroup) + lbbg.ProjectSrc = db.PROJECT_SOURCE_CLOUD lbbg.ProjectId = userCred.GetProjectId() if len(projectId) > 0 { lbbg.ProjectId = projectId } + + if extProjectId := extLoadbalancerBackendgroup.GetProjectId(); len(extProjectId) > 0 { + externalProject, err := ExternalProjectManager.GetProject(extProjectId, lb.ManagerId) + if err != nil { + log.Errorf(err.Error()) + } else { + lbbg.ProjectId = externalProject.ProjectId + } + } + err := man.TableSpec().Insert(lbbg) if err != nil { return nil, err diff --git a/pkg/compute/models/loadbalancerbackends.go b/pkg/compute/models/loadbalancerbackends.go index 1d19680af7..7eb1371ee2 100644 --- a/pkg/compute/models/loadbalancerbackends.go +++ b/pkg/compute/models/loadbalancerbackends.go @@ -354,8 +354,15 @@ func (lbb *SLoadbalancerBackend) constructFieldsFromCloudLoadbalancerBackend(ext func (lbb *SLoadbalancerBackend) SyncWithCloudLoadbalancerBackend(ctx context.Context, userCred mcclient.TokenCredential, extLoadbalancerBackend cloudprovider.ICloudLoadbalancerBackend, projectId string, projectSync bool) error { _, err := lbb.GetModelManager().TableSpec().Update(lbb, func() error { - if projectSync && len(projectId) > 0 { - lbb.ProjectId = projectId + if projectSync && lbb.ProjectSrc != db.PROJECT_SOURCE_LOCAL { + if extProjectId := extLoadbalancerBackend.GetProjectId(); len(extProjectId) > 0 { + extProject, err := ExternalProjectManager.GetProject(extProjectId, lbb.ManagerId) + if err != nil { + log.Errorf(err.Error()) + } else { + lbb.ProjectId = extProject.ProjectId + } + } } return lbb.constructFieldsFromCloudLoadbalancerBackend(extLoadbalancerBackend) }) @@ -376,10 +383,21 @@ func (man *SLoadbalancerBackendManager) newFromCloudLoadbalancerBackend(ctx cont return nil, err } + lbb.ProjectSrc = db.PROJECT_SOURCE_CLOUD lbb.ProjectId = userCred.GetProjectId() if len(projectId) > 0 { lbb.ProjectId = projectId } + + if extProjectId := extLoadbalancerBackend.GetProjectId(); len(extProjectId) > 0 { + externalProject, err := ExternalProjectManager.GetProject(extProjectId, loadbalancerBackendgroup.ManagerId) + if err != nil { + log.Errorf(err.Error()) + } else { + lbb.ProjectId = externalProject.ProjectId + } + } + return lbb, man.TableSpec().Insert(lbb) } diff --git a/pkg/compute/models/loadbalancercertificates.go b/pkg/compute/models/loadbalancercertificates.go index 1d908a4ccc..0a0e0d5ea9 100644 --- a/pkg/compute/models/loadbalancercertificates.go +++ b/pkg/compute/models/loadbalancercertificates.go @@ -370,11 +370,21 @@ func (man *SLoadbalancerCertificateManager) newFromCloudLoadbalancerCertificate( lbcert.Fingerprint = extCertificate.GetFingerprint() lbcert.NotAfter = extCertificate.GetExpireTime() + lbcert.ProjectSrc = db.PROJECT_SOURCE_CLOUD lbcert.ProjectId = userCred.GetProjectId() if len(projectId) > 0 { lbcert.ProjectId = projectId } + if extProjectId := extCertificate.GetProjectId(); len(extProjectId) > 0 { + externalProject, err := ExternalProjectManager.GetProject(extProjectId, lbcert.ManagerId) + if err != nil { + log.Errorf(err.Error()) + } else { + lbcert.ProjectId = externalProject.ProjectId + } + } + return &lbcert, man.TableSpec().Insert(&lbcert) } @@ -386,8 +396,15 @@ func (lbcert *SLoadbalancerCertificate) SyncWithCloudLoadbalancerCertificate(ctx lbcert.Fingerprint = extCertificate.GetFingerprint() lbcert.NotAfter = extCertificate.GetExpireTime() - if projectSync && len(projectId) > 0 { - lbcert.ProjectId = projectId + if projectSync && lbcert.ProjectSrc != db.PROJECT_SOURCE_LOCAL { + if extProjectId := extCertificate.GetProjectId(); len(extProjectId) > 0 { + extProject, err := ExternalProjectManager.GetProject(extProjectId, lbcert.ManagerId) + if err != nil { + log.Errorf(err.Error()) + } else { + lbcert.ProjectId = extProject.ProjectId + } + } } return nil diff --git a/pkg/compute/models/loadbalancerlistenerrules.go b/pkg/compute/models/loadbalancerlistenerrules.go index 277e8bfd21..53d10f1da1 100644 --- a/pkg/compute/models/loadbalancerlistenerrules.go +++ b/pkg/compute/models/loadbalancerlistenerrules.go @@ -368,23 +368,21 @@ func (man *SLoadbalancerListenerRuleManager) newFromCloudLoadbalancerListenerRul lbr.ExternalId = extRule.GetGlobalId() lbr.ListenerId = listener.Id + lbr.ManagerId = listener.ManagerId lbr.constructFieldsFromCloudListenerRule(extRule) - lbr.ProjectId = userCred.GetProjectId() - if len(projectId) > 0 { - lbr.ProjectId = projectId - } + lbr.ProjectSrc = db.PROJECT_SOURCE_CLOUD + lbr.ProjectId = listener.ProjectId return lbr, man.TableSpec().Insert(lbr) } func (lbr *SLoadbalancerListenerRule) SyncWithCloudLoadbalancerListenerRule(ctx context.Context, userCred mcclient.TokenCredential, extRule cloudprovider.ICloudLoadbalancerListenerRule, projectId string, projectSync bool) error { + listener := lbr.GetLoadbalancerListener() _, err := lbr.GetModelManager().TableSpec().Update(lbr, func() error { lbr.constructFieldsFromCloudListenerRule(extRule) - - if projectSync && len(projectId) > 0 { - lbr.ProjectId = projectId - } + lbr.ManagerId = listener.ManagerId + lbr.ProjectId = listener.ProjectId return nil }) return err diff --git a/pkg/compute/models/loadbalancerlisteners.go b/pkg/compute/models/loadbalancerlisteners.go index 95abad6f8d..f668ae7321 100644 --- a/pkg/compute/models/loadbalancerlisteners.go +++ b/pkg/compute/models/loadbalancerlisteners.go @@ -736,6 +736,7 @@ func (man *SLoadbalancerListenerManager) SyncLoadbalancerListeners(ctx context.C } func (lblis *SLoadbalancerListener) constructFieldsFromCloudListener(lb *SLoadbalancer, extListener cloudprovider.ICloudLoadbalancerListener) { + lblis.ManagerId = lb.ManagerId lblis.Name = extListener.GetName() lblis.ListenerType = extListener.GetListenerType() lblis.ListenerPort = extListener.GetListenerPort() @@ -797,8 +798,15 @@ func (lblis *SLoadbalancerListener) constructFieldsFromCloudListener(lb *SLoadba func (lblis *SLoadbalancerListener) SyncWithCloudLoadbalancerListener(ctx context.Context, userCred mcclient.TokenCredential, lb *SLoadbalancer, extListener cloudprovider.ICloudLoadbalancerListener, projectId string, projectSync bool) error { _, err := lblis.GetModelManager().TableSpec().Update(lblis, func() error { lblis.constructFieldsFromCloudListener(lb, extListener) - if projectSync && len(projectId) > 0 { - lblis.ProjectId = projectId + if projectSync && lblis.ProjectSrc != db.PROJECT_SOURCE_LOCAL { + if extProjectId := extListener.GetProjectId(); len(extProjectId) > 0 { + extProject, err := ExternalProjectManager.GetProject(extProjectId, lblis.ManagerId) + if err != nil { + log.Errorf(err.Error()) + } else { + lblis.ProjectId = extProject.ProjectId + } + } } return nil }) @@ -813,10 +821,21 @@ func (man *SLoadbalancerListenerManager) newFromCloudLoadbalancerListener(ctx co lblis.ExternalId = extListener.GetGlobalId() lblis.constructFieldsFromCloudListener(lb, extListener) + lblis.ProjectSrc = db.PROJECT_SOURCE_CLOUD lblis.ProjectId = userCred.GetProjectId() if len(projectId) > 0 { lblis.ProjectId = projectId } + + if extProjectId := extListener.GetProjectId(); len(extProjectId) > 0 { + externalProject, err := ExternalProjectManager.GetProject(extProjectId, lblis.ManagerId) + if err != nil { + log.Errorf(err.Error()) + } else { + lblis.ProjectId = externalProject.ProjectId + } + } + return lblis, man.TableSpec().Insert(lblis) } diff --git a/pkg/compute/models/loadbalancers.go b/pkg/compute/models/loadbalancers.go index 9522a32c24..715d7a6154 100644 --- a/pkg/compute/models/loadbalancers.go +++ b/pkg/compute/models/loadbalancers.go @@ -550,11 +550,21 @@ func (man *SLoadbalancerManager) newFromCloudLoadbalancer(ctx context.Context, u } } + lb.ProjectSrc = db.PROJECT_SOURCE_CLOUD lb.ProjectId = userCred.GetProjectId() if len(provider.ProjectId) > 0 { lb.ProjectId = provider.ProjectId } + if extProjectId := extLb.GetProjectId(); len(extProjectId) > 0 { + externalProject, err := ExternalProjectManager.GetProject(extProjectId, lb.ManagerId) + if err != nil { + log.Errorf(err.Error()) + } else { + lb.ProjectId = externalProject.ProjectId + } + } + if extLb.GetMetadata() != nil { lb.LBInfo = extLb.GetMetadata() } @@ -593,8 +603,15 @@ func (lb *SLoadbalancer) SyncWithCloudLoadbalancer(ctx context.Context, userCred lb.LBInfo = extLb.GetMetadata() } - if projectSync && len(projectId) > 0 { - lb.ProjectId = projectId + if projectSync && lb.ProjectSrc != db.PROJECT_SOURCE_LOCAL { + if extProjectId := extLb.GetProjectId(); len(extProjectId) > 0 { + extProject, err := ExternalProjectManager.GetProject(extProjectId, lb.ManagerId) + if err != nil { + log.Errorf(err.Error()) + } else { + lb.ProjectId = extProject.ProjectId + } + } } return nil }) diff --git a/pkg/compute/models/networks.go b/pkg/compute/models/networks.go index 8cfb067641..90760978ea 100644 --- a/pkg/compute/models/networks.go +++ b/pkg/compute/models/networks.go @@ -520,6 +520,7 @@ func (manager *SNetworkManager) SyncNetworks(ctx context.Context, userCred mccli } func (self *SNetwork) SyncWithCloudNetwork(userCred mcclient.TokenCredential, extNet cloudprovider.ICloudNetwork, projectId string, projectSync bool) error { + vpc := self.GetWire().getVpc() _, err := self.GetModelManager().TableSpec().Update(self, func() error { extNet.Refresh() self.Name = extNet.GetName() @@ -534,8 +535,15 @@ func (self *SNetwork) SyncWithCloudNetwork(userCred mcclient.TokenCredential, ex self.AllocTimoutSeconds = extNet.GetAllocTimeoutSeconds() self.ProjectId = userCred.GetProjectId() - if projectSync && len(projectId) > 0 { - self.ProjectId = projectId + if projectSync && self.ProjectSrc != db.PROJECT_SOURCE_LOCAL { + if extProjectId := extNet.GetProjectId(); len(extProjectId) > 0 { + extProject, err := ExternalProjectManager.GetProject(extProjectId, vpc.ManagerId) + if err != nil { + log.Errorf(err.Error()) + } else { + self.ProjectId = extProject.ProjectId + } + } } return nil }) @@ -562,10 +570,22 @@ func (manager *SNetworkManager) newFromCloudNetwork(userCred mcclient.TokenCrede net.AllocTimoutSeconds = extNet.GetAllocTimeoutSeconds() + net.ProjectSrc = db.PROJECT_SOURCE_CLOUD net.ProjectId = userCred.GetProjectId() if len(projectId) > 0 { net.ProjectId = projectId } + + vpc := wire.getVpc() + if extProjectId := extNet.GetProjectId(); len(extProjectId) > 0 { + externalProject, err := ExternalProjectManager.GetProject(extProjectId, vpc.ManagerId) + if err != nil { + log.Errorf(err.Error()) + } else { + net.ProjectId = externalProject.ProjectId + } + } + err := manager.TableSpec().Insert(&net) if err != nil { log.Errorf("newFromCloudZone fail %s", err) diff --git a/pkg/compute/models/secgroups.go b/pkg/compute/models/secgroups.go index b53dd3f62f..2184499f45 100644 --- a/pkg/compute/models/secgroups.go +++ b/pkg/compute/models/secgroups.go @@ -269,8 +269,15 @@ func (self *SSecurityGroup) SyncWithCloudSecurityGroup(userCred mcclient.TokenCr self.Name = extSec.GetName() self.Description = extSec.GetDescription() self.ProjectId = userCred.GetProjectId() - if projectSync && len(projectId) > 0 { - self.ProjectId = projectId + if projectSync && self.ProjectSrc != db.PROJECT_SOURCE_LOCAL { + if extProjectId := extSec.GetProjectId(); len(extProjectId) > 0 { + extProject, err := ExternalProjectManager.GetProject(extProjectId, vpc.ManagerId) + if err != nil { + log.Errorf(err.Error()) + } else { + self.ProjectId = extProject.ProjectId + } + } } return nil }); err != nil { @@ -301,11 +308,22 @@ func (manager *SSecurityGroupManager) newFromCloudVpc(userCred mcclient.TokenCre secgroup.Name = extSec.GetName() secgroup.ExternalId = extSec.GetGlobalId() secgroup.Description = extSec.GetDescription() + + secgroup.ProjectSrc = db.PROJECT_SOURCE_CLOUD secgroup.ProjectId = userCred.GetProjectId() if len(projectId) > 0 { secgroup.ProjectId = projectId } + if extProjectId := extSec.GetProjectId(); len(extProjectId) > 0 { + externalProject, err := ExternalProjectManager.GetProject(extProjectId, vpc.ManagerId) + if err != nil { + log.Errorf(err.Error()) + } else { + secgroup.ProjectId = externalProject.ProjectId + } + } + if err := manager.TableSpec().Insert(&secgroup); err != nil { return nil, true, err } diff --git a/pkg/compute/models/snapshots.go b/pkg/compute/models/snapshots.go index 007f34f7b1..988279e51f 100644 --- a/pkg/compute/models/snapshots.go +++ b/pkg/compute/models/snapshots.go @@ -536,8 +536,15 @@ func (self *SSnapshot) SyncWithCloudSnapshot(userCred mcclient.TokenCredential, self.Name = ext.GetName() self.Status = ext.GetStatus() self.DiskType = ext.GetDiskType() - if projectSync && len(projectId) > 0 { - self.ProjectId = projectId + if projectSync && self.ProjectSrc != db.PROJECT_SOURCE_LOCAL { + if extProjectId := ext.GetProjectId(); len(extProjectId) > 0 { + extProject, err := ExternalProjectManager.GetProject(extProjectId, self.ManagerId) + if err != nil { + log.Errorf(err.Error()) + } else { + self.ProjectId = extProject.ProjectId + } + } } self.CloudregionId = region.Id return nil @@ -569,10 +576,21 @@ func (manager *SSnapshotManager) newFromCloudSnapshot(ctx context.Context, userC snapshot.ManagerId = provider.Id snapshot.CloudregionId = region.Id + snapshot.ProjectSrc = db.PROJECT_SOURCE_CLOUD snapshot.ProjectId = userCred.GetProjectId() if len(projectId) > 0 { snapshot.ProjectId = projectId } + + if extProjectId := extSnapshot.GetProjectId(); len(extProjectId) > 0 { + externalProject, err := ExternalProjectManager.GetProject(extProjectId, snapshot.ManagerId) + if err != nil { + log.Errorf(err.Error()) + } else { + snapshot.ProjectId = externalProject.ProjectId + } + } + err := manager.TableSpec().Insert(&snapshot) if err != nil { log.Errorf("newFromCloudEip fail %s", err) diff --git a/pkg/compute/service/handlers.go b/pkg/compute/service/handlers.go index dd2462f5b7..80539956d2 100644 --- a/pkg/compute/service/handlers.go +++ b/pkg/compute/service/handlers.go @@ -81,6 +81,7 @@ func InitHandlers(app *appsrv.Application) { models.DynamicschedtagManager, models.ServerSkuManager, + models.ExternalProjectManager, } { db.RegisterModelManager(manager) handler := db.NewModelHandler(manager) diff --git a/pkg/compute/tasks/cloud_provider_sync_info_task.go b/pkg/compute/tasks/cloud_provider_sync_info_task.go index 852d01468f..a86af39a30 100644 --- a/pkg/compute/tasks/cloud_provider_sync_info_task.go +++ b/pkg/compute/tasks/cloud_provider_sync_info_task.go @@ -149,12 +149,15 @@ func syncPublicCloudProviderInfo(ctx context.Context, provider *models.SCloudpro storageCachePairs := make([]sStoragecacheSyncPair, 0) + syncProjects(ctx, driver, provider, task) + db.OpsLog.LogEvent(provider, db.ACT_SYNC_HOST_COMPLETE, msg, task.UserCred) // logclient.AddActionLog(provider, getAction(task.Params), "", task.UserCred, true) for i := 0; i < len(localRegions); i += 1 { if len(syncRange.Region) > 0 && !utils.IsInStringArray(localRegions[i].Id, syncRange.Region) { continue } + syncRegionEips(ctx, provider, task, &localRegions[i], remoteRegions[i], syncRange) localZones, remoteZones := syncRegionZones(ctx, provider, task, &localRegions[i], remoteRegions[i]) @@ -391,6 +394,25 @@ func syncRegionSnapshots(ctx context.Context, provider *models.SCloudprovider, t db.OpsLog.LogEvent(provider, db.ACT_SYNC_HOST_COMPLETE, msg, task.GetUserCred()) } +func syncProjects(ctx context.Context, driver cloudprovider.ICloudProvider, provider *models.SCloudprovider, task *CloudProviderSyncInfoTask) { + 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 := models.ExternalProjectManager.SyncProjects(ctx, task.UserCred, provider, projects) + 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, provider *models.SCloudprovider, task *CloudProviderSyncInfoTask, localRegion *models.SCloudregion, remoteRegion cloudprovider.ICloudRegion, syncRange *models.SSyncRange) { eips, err := remoteRegion.GetIEips() if err != nil { diff --git a/pkg/mcclient/modules/mod_externalprojects.go b/pkg/mcclient/modules/mod_externalprojects.go new file mode 100644 index 0000000000..96cdd268c2 --- /dev/null +++ b/pkg/mcclient/modules/mod_externalprojects.go @@ -0,0 +1,13 @@ +package modules + +var ( + ExternalProjects ResourceManager +) + +func init() { + ExternalProjects = NewComputeManager("externalproject", "externalprojects", + []string{"ID", "Name", "ExternalId", "Created_at", "TenantId", "Tenant"}, + []string{}) + + registerComputeV2(&ExternalProjects) +} diff --git a/pkg/util/aliyun/aliyun.go b/pkg/util/aliyun/aliyun.go index 0eb3d7bd11..e0f6117ed1 100644 --- a/pkg/util/aliyun/aliyun.go +++ b/pkg/util/aliyun/aliyun.go @@ -242,3 +242,10 @@ func (self *SAliyunClient) GetIStorageById(id string) (cloudprovider.ICloudStora } return nil, cloudprovider.ErrNotFound } + +func (region *SAliyunClient) GetIProjects() ([]cloudprovider.ICloudProject, error) { + // 阿里云并未公布资源组的api地址 + // params := map[string]string{} + // body, err := region.ecsRequest("ListResourceGroups", params) + return nil, cloudprovider.ErrNotImplemented +} diff --git a/pkg/util/aliyun/disk.go b/pkg/util/aliyun/disk.go index 2f52be2bf1..b8a7f2f534 100644 --- a/pkg/util/aliyun/disk.go +++ b/pkg/util/aliyun/disk.go @@ -406,3 +406,7 @@ func (self *SRegion) rebuildDisk(diskId string) error { } return nil } + +func (self *SDisk) GetProjectId() string { + return "" +} diff --git a/pkg/util/aliyun/eip.go b/pkg/util/aliyun/eip.go index af609a9f3a..89b45bad32 100644 --- a/pkg/util/aliyun/eip.go +++ b/pkg/util/aliyun/eip.go @@ -326,3 +326,7 @@ func (region *SRegion) UpdateEipBandwidth(eipId string, bw int) error { } return err } + +func (self *SEipAddress) GetProjectId() string { + return "" +} diff --git a/pkg/util/aliyun/instance.go b/pkg/util/aliyun/instance.go index c42365e4a6..d210fe6e82 100644 --- a/pkg/util/aliyun/instance.go +++ b/pkg/util/aliyun/instance.go @@ -938,3 +938,7 @@ func (region *SRegion) RenewInstance(instanceId string, bc billing.SBillingCycle } return nil } + +func (self *SInstance) GetProjectId() string { + return "" +} diff --git a/pkg/util/aliyun/loadbalancer.go b/pkg/util/aliyun/loadbalancer.go index 3dc907c90d..5187ba5fce 100644 --- a/pkg/util/aliyun/loadbalancer.go +++ b/pkg/util/aliyun/loadbalancer.go @@ -336,3 +336,7 @@ func (lb *SLoadbalancer) GetILoadBalancerListeners() ([]cloudprovider.ICloudLoad } return listeners, nil } + +func (lb *SLoadbalancer) GetProjectId() string { + return "" +} diff --git a/pkg/util/aliyun/loadbalanceracl.go b/pkg/util/aliyun/loadbalanceracl.go index 226040a686..aa9bc6fb97 100644 --- a/pkg/util/aliyun/loadbalanceracl.go +++ b/pkg/util/aliyun/loadbalanceracl.go @@ -138,3 +138,7 @@ func (acl *SLoadbalancerAcl) Sync(_acl *cloudprovider.SLoadbalancerAccessControl } return nil } + +func (acl *SLoadbalancerAcl) GetProjectId() string { + return "" +} diff --git a/pkg/util/aliyun/loadbalancerbackend.go b/pkg/util/aliyun/loadbalancerbackend.go index 61aba6ada0..2e1ed324a0 100644 --- a/pkg/util/aliyun/loadbalancerbackend.go +++ b/pkg/util/aliyun/loadbalancerbackend.go @@ -84,3 +84,7 @@ func (region *SRegion) GetLoadbalancerBackends(backendgroupId string) ([]SLoadba backends := []SLoadbalancerBackend{} return backends, body.Unmarshal(&backends, "BackendServers", "BackendServer") } + +func (backend *SLoadbalancerBackend) GetProjectId() string { + return "" +} diff --git a/pkg/util/aliyun/loadbalancerbackendgroup.go b/pkg/util/aliyun/loadbalancerbackendgroup.go index c0825f566a..69732b08bd 100644 --- a/pkg/util/aliyun/loadbalancerbackendgroup.go +++ b/pkg/util/aliyun/loadbalancerbackendgroup.go @@ -215,3 +215,7 @@ func (backendgroup *SLoadbalancerBackendGroup) AddBackendServer(serverId string, func (backendgroup *SLoadbalancerBackendGroup) RemoveBackendServer(serverId string, weight, port int) error { return backendgroup.lb.region.RemoveBackendVServer(backendgroup.lb.LoadBalancerId, backendgroup.VServerGroupId, serverId, port) } + +func (backendgroup *SLoadbalancerBackendGroup) GetProjectId() string { + return "" +} diff --git a/pkg/util/aliyun/loadbalancerdefaultbackend.go b/pkg/util/aliyun/loadbalancerdefaultbackend.go index 148d56ba3d..485f8ae706 100644 --- a/pkg/util/aliyun/loadbalancerdefaultbackend.go +++ b/pkg/util/aliyun/loadbalancerdefaultbackend.go @@ -62,3 +62,7 @@ func (backend *SLoadbalancerDefaultBackend) GetBackendRole() string { func (backend *SLoadbalancerDefaultBackend) GetBackendId() string { return backend.ServerId } + +func (backend *SLoadbalancerDefaultBackend) GetProjectId() string { + return "" +} diff --git a/pkg/util/aliyun/loadbalancerdefaultbackendgroup.go b/pkg/util/aliyun/loadbalancerdefaultbackendgroup.go index 17a2b657ca..996d2e9782 100644 --- a/pkg/util/aliyun/loadbalancerdefaultbackendgroup.go +++ b/pkg/util/aliyun/loadbalancerdefaultbackendgroup.go @@ -102,3 +102,7 @@ func (region *SRegion) RemoveBackendServer(loadbalancerId, serverId string) erro func (backendgroup *SLoadbalancerDefaultBackendGroup) RemoveBackendServer(serverId string, weight, port int) error { return backendgroup.lb.region.RemoveBackendServer(backendgroup.lb.LoadBalancerId, serverId) } + +func (backendgroup *SLoadbalancerDefaultBackendGroup) GetProjectId() string { + return "" +} diff --git a/pkg/util/aliyun/loadbalancerhttplistener.go b/pkg/util/aliyun/loadbalancerhttplistener.go index 501dd4b27d..d3bb95579f 100644 --- a/pkg/util/aliyun/loadbalancerhttplistener.go +++ b/pkg/util/aliyun/loadbalancerhttplistener.go @@ -342,3 +342,7 @@ func (region *SRegion) SyncLoadbalancerHTTPListener(lb *SLoadbalancer, listener func (listerner *SLoadbalancerHTTPListener) Sync(lblis *cloudprovider.SLoadbalancerListener) error { return listerner.lb.region.SyncLoadbalancerHTTPListener(listerner.lb, lblis) } + +func (listerner *SLoadbalancerHTTPListener) GetProjectId() string { + return "" +} diff --git a/pkg/util/aliyun/loadbalancerhttpslistener.go b/pkg/util/aliyun/loadbalancerhttpslistener.go index 2dde32b0af..59deaa7678 100644 --- a/pkg/util/aliyun/loadbalancerhttpslistener.go +++ b/pkg/util/aliyun/loadbalancerhttpslistener.go @@ -349,3 +349,7 @@ func (region *SRegion) SyncLoadbalancerHTTPSListener(lb *SLoadbalancer, listener func (listerner *SLoadbalancerHTTPSListener) Sync(lblis *cloudprovider.SLoadbalancerListener) error { return listerner.lb.region.SyncLoadbalancerHTTPSListener(listerner.lb, lblis) } + +func (listerner *SLoadbalancerHTTPSListener) GetProjectId() string { + return "" +} diff --git a/pkg/util/aliyun/loadbalancermasterslavebackend.go b/pkg/util/aliyun/loadbalancermasterslavebackend.go index d1047a009f..fb30afe141 100644 --- a/pkg/util/aliyun/loadbalancermasterslavebackend.go +++ b/pkg/util/aliyun/loadbalancermasterslavebackend.go @@ -65,3 +65,7 @@ func (backend *SLoadbalancerMasterSlaveBackend) GetBackendRole() string { func (backend *SLoadbalancerMasterSlaveBackend) GetBackendId() string { return backend.ServerId } + +func (backend *SLoadbalancerMasterSlaveBackend) GetProjectId() string { + return "" +} diff --git a/pkg/util/aliyun/loadbalancermasterslavebackendgroup.go b/pkg/util/aliyun/loadbalancermasterslavebackendgroup.go index 7a6a9f5f85..5e9a560616 100644 --- a/pkg/util/aliyun/loadbalancermasterslavebackendgroup.go +++ b/pkg/util/aliyun/loadbalancermasterslavebackendgroup.go @@ -161,3 +161,7 @@ func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) AddBackendServer(serve func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) RemoveBackendServer(serverId string, weight, port int) error { return cloudprovider.ErrNotSupported } + +func (backendgroup *SLoadbalancerMasterSlaveBackendGroup) GetProjectId() string { + return "" +} diff --git a/pkg/util/aliyun/loadbalancerservercertificate.go b/pkg/util/aliyun/loadbalancerservercertificate.go index e7c2ec37f3..048056a020 100644 --- a/pkg/util/aliyun/loadbalancerservercertificate.go +++ b/pkg/util/aliyun/loadbalancerservercertificate.go @@ -113,3 +113,7 @@ func (region *SRegion) GetLoadbalancerServerCertificates() ([]SLoadbalancerServe certificates := []SLoadbalancerServerCertificate{} return certificates, body.Unmarshal(&certificates, "ServerCertificates", "ServerCertificate") } + +func (certificate *SLoadbalancerServerCertificate) GetProjectId() string { + return "" +} diff --git a/pkg/util/aliyun/loadbalancertcplistener.go b/pkg/util/aliyun/loadbalancertcplistener.go index e7956589f6..6c4ed55aa5 100644 --- a/pkg/util/aliyun/loadbalancertcplistener.go +++ b/pkg/util/aliyun/loadbalancertcplistener.go @@ -329,3 +329,7 @@ func (region *SRegion) SyncLoadbalancerTCPListener(lb *SLoadbalancer, listener * func (listerner *SLoadbalancerTCPListener) Sync(lblis *cloudprovider.SLoadbalancerListener) error { return listerner.lb.region.SyncLoadbalancerTCPListener(listerner.lb, lblis) } + +func (listerner *SLoadbalancerTCPListener) GetProjectId() string { + return "" +} diff --git a/pkg/util/aliyun/loadbalancerudplistener.go b/pkg/util/aliyun/loadbalancerudplistener.go index a3da297884..5ca3bf9015 100644 --- a/pkg/util/aliyun/loadbalancerudplistener.go +++ b/pkg/util/aliyun/loadbalancerudplistener.go @@ -255,3 +255,7 @@ func (region *SRegion) SyncLoadbalancerUDPListener(lb *SLoadbalancer, listener * func (listerner *SLoadbalancerUDPListener) Sync(lblis *cloudprovider.SLoadbalancerListener) error { return listerner.lb.region.SyncLoadbalancerUDPListener(listerner.lb, lblis) } + +func (listerner *SLoadbalancerUDPListener) GetProjectId() string { + return "" +} diff --git a/pkg/util/aliyun/project.go b/pkg/util/aliyun/project.go new file mode 100644 index 0000000000..ea03a4fbd0 --- /dev/null +++ b/pkg/util/aliyun/project.go @@ -0,0 +1,12 @@ +package aliyun + +import "time" + +type SProject struct { + Status string + AccountId string + DisplayName string + Id string + CreateDate time.Time + Name string +} diff --git a/pkg/util/aliyun/provider/provider.go b/pkg/util/aliyun/provider/provider.go index 3a23c62047..336723c069 100644 --- a/pkg/util/aliyun/provider/provider.go +++ b/pkg/util/aliyun/provider/provider.go @@ -129,3 +129,7 @@ func (self *SAliyunProvider) GetBalance() (float64, error) { func (self *SAliyunProvider) GetOnPremiseIRegion() (cloudprovider.ICloudRegion, error) { return nil, cloudprovider.ErrNotImplemented } + +func (self *SAliyunProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return self.client.GetIProjects() +} diff --git a/pkg/util/aliyun/securitygroup.go b/pkg/util/aliyun/securitygroup.go index 458474ada9..6205815fa0 100644 --- a/pkg/util/aliyun/securitygroup.go +++ b/pkg/util/aliyun/securitygroup.go @@ -543,3 +543,7 @@ func (self *SRegion) DeleteSecurityGroup(vpcId, secGrpId string) error { } return nil } + +func (self *SSecurityGroup) GetProjectId() string { + return "" +} diff --git a/pkg/util/aliyun/shell/project.go b/pkg/util/aliyun/shell/project.go new file mode 100644 index 0000000000..f97f56124d --- /dev/null +++ b/pkg/util/aliyun/shell/project.go @@ -0,0 +1,19 @@ +package shell + +import ( + "yunion.io/x/onecloud/pkg/util/aliyun" + "yunion.io/x/onecloud/pkg/util/shellutils" +) + +func init() { + type ProjectListOptions struct { + } + shellutils.R(&ProjectListOptions{}, "project-list", "List project", func(cli *aliyun.SRegion, args *ProjectListOptions) error { + project, err := cli.GetClient().GetIProjects() + if err != nil { + return err + } + printList(project, 0, 0, 0, nil) + return nil + }) +} diff --git a/pkg/util/aliyun/snapshot.go b/pkg/util/aliyun/snapshot.go index bfbc5b21c5..3ca2eb4602 100644 --- a/pkg/util/aliyun/snapshot.go +++ b/pkg/util/aliyun/snapshot.go @@ -179,3 +179,7 @@ func (self *SRegion) DeleteSnapshot(snapshotId string) error { _, err := self.ecsRequest("DeleteSnapshot", params) return err } + +func (self *SSnapshot) GetProjectId() string { + return "" +} diff --git a/pkg/util/aliyun/vswitch.go b/pkg/util/aliyun/vswitch.go index 6db526fceb..b410f76d86 100644 --- a/pkg/util/aliyun/vswitch.go +++ b/pkg/util/aliyun/vswitch.go @@ -10,6 +10,7 @@ import ( "yunion.io/x/pkg/utils" "fmt" + "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" ) @@ -239,3 +240,7 @@ func (vsw *SVSwitch) dissociateWithSNAT() error { } return nil } + +func (self *SVSwitch) GetProjectId() string { + return "" +} diff --git a/pkg/util/aws/aws.go b/pkg/util/aws/aws.go index a048dc4d68..1dda19cbaf 100644 --- a/pkg/util/aws/aws.go +++ b/pkg/util/aws/aws.go @@ -204,3 +204,7 @@ func (self *SAwsClient) QueryAccountBalance() (*SAccountBalance, error) { // todo: aws 貌似没有余额? panic("implement me") } + +func (self *SAwsClient) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return nil, cloudprovider.ErrNotImplemented +} diff --git a/pkg/util/aws/disk.go b/pkg/util/aws/disk.go index c2e232c403..58405acc8c 100644 --- a/pkg/util/aws/disk.go +++ b/pkg/util/aws/disk.go @@ -480,3 +480,7 @@ func (self *SDisk) Rebuild(ctx context.Context) error { _, err := self.storage.zone.region.resetDisk(self.DiskId, "") return err } + +func (self *SDisk) GetProjectId() string { + return "" +} diff --git a/pkg/util/aws/eip.go b/pkg/util/aws/eip.go index 8ac7d7e1ee..8e7ab29c34 100644 --- a/pkg/util/aws/eip.go +++ b/pkg/util/aws/eip.go @@ -304,3 +304,7 @@ func (self *SEipAddress) GetBillingType() string { func (self *SEipAddress) GetExpiredAt() time.Time { return time.Time{} } + +func (self *SEipAddress) GetProjectId() string { + return "" +} diff --git a/pkg/util/aws/instance.go b/pkg/util/aws/instance.go index 5b20e7f774..e4f3d342c2 100644 --- a/pkg/util/aws/instance.go +++ b/pkg/util/aws/instance.go @@ -939,3 +939,7 @@ func (self *SInstance) CreateDisk(ctx context.Context, sizeMb int, uuid string, func (self *SInstance) Renew(bc billing.SBillingCycle) error { return cloudprovider.ErrNotSupported } + +func (self *SInstance) GetProjectId() string { + return "" +} diff --git a/pkg/util/aws/network.go b/pkg/util/aws/network.go index 7c73f87aab..cca05ed670 100644 --- a/pkg/util/aws/network.go +++ b/pkg/util/aws/network.go @@ -207,3 +207,7 @@ func (self *SRegion) GetNetwroks(ids []string, vpcId string, limit int, offset i } return subnets, len(subnets), nil } + +func (self *SNetwork) GetProjectId() string { + return "" +} diff --git a/pkg/util/aws/provider/provider.go b/pkg/util/aws/provider/provider.go index cf9a3c543f..25eb79016d 100644 --- a/pkg/util/aws/provider/provider.go +++ b/pkg/util/aws/provider/provider.go @@ -132,3 +132,7 @@ func (self *SAwsProvider) GetBalance() (float64, error) { func (self *SAwsProvider) GetOnPremiseIRegion() (cloudprovider.ICloudRegion, error) { return nil, cloudprovider.ErrNotImplemented } + +func (self *SAwsProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return self.client.GetIProjects() +} diff --git a/pkg/util/aws/securitygroup.go b/pkg/util/aws/securitygroup.go index 0fa1a30941..9dc067ca23 100644 --- a/pkg/util/aws/securitygroup.go +++ b/pkg/util/aws/securitygroup.go @@ -474,3 +474,7 @@ func (self *SRegion) GetSecurityGroups(vpcId string, secgroupId string, offset i return securityGroups, len(securityGroups), nil } + +func (self *SSecurityGroup) GetProjectId() string { + return "" +} diff --git a/pkg/util/aws/snapshot.go b/pkg/util/aws/snapshot.go index 8e765dc432..25a02f3d57 100644 --- a/pkg/util/aws/snapshot.go +++ b/pkg/util/aws/snapshot.go @@ -200,3 +200,7 @@ func (self *SRegion) DeleteSnapshot(snapshotId string) error { _, err := self.ec2Client.DeleteSnapshot(params) return err } + +func (self *SSnapshot) GetProjectId() string { + return "" +} diff --git a/pkg/util/azure/azure.go b/pkg/util/azure/azure.go index 89353eefe5..89359220df 100644 --- a/pkg/util/azure/azure.go +++ b/pkg/util/azure/azure.go @@ -768,3 +768,27 @@ type SAccountBalance struct { func (self *SAzureClient) QueryAccountBalance() (*SAccountBalance, error) { return nil, cloudprovider.ErrNotImplemented } + +func getResourceGroup(id string) string { + if info := strings.Split(id, "/resourceGroups/"); len(info) == 2 { + if resourcegroupInfo := strings.Split(info[1], "/"); len(resourcegroupInfo) > 0 { + return strings.ToLower(resourcegroupInfo[0]) + } + } + return "" +} + +func (self *SAzureClient) GetIProjects() ([]cloudprovider.ICloudProject, error) { + resourceGroups := []SResourceGroup{} + if err := self.List("resourcegroups", &resourceGroups); err != nil { + return nil, err + } + iprojects := []cloudprovider.ICloudProject{} + for i := 0; i < len(resourceGroups); i++ { + if groupInfo := strings.Split(resourceGroups[i].ID, "/"); len(groupInfo) > 0 { + resourceGroups[i].ID = strings.ToLower(groupInfo[len(groupInfo)-1]) + } + iprojects = append(iprojects, &resourceGroups[i]) + } + return iprojects, nil +} diff --git a/pkg/util/azure/classic_disk.go b/pkg/util/azure/classic_disk.go index 581d0f1e87..4ec487fcaa 100644 --- a/pkg/util/azure/classic_disk.go +++ b/pkg/util/azure/classic_disk.go @@ -223,3 +223,7 @@ func (disk *SClassicDisk) GetAccessPath() string { func (self *SClassicDisk) Rebuild(ctx context.Context) error { return cloudprovider.ErrNotSupported } + +func (self *SClassicDisk) GetProjectId() string { + return "" +} diff --git a/pkg/util/azure/classic_eip.go b/pkg/util/azure/classic_eip.go index 71415c7b93..4d5cc07ea7 100644 --- a/pkg/util/azure/classic_eip.go +++ b/pkg/util/azure/classic_eip.go @@ -151,3 +151,7 @@ func (self *SClassicEipAddress) GetBillingType() string { func (self *SClassicEipAddress) GetExpiredAt() time.Time { return time.Time{} } + +func (self *SClassicEipAddress) GetProjectId() string { + return getResourceGroup(self.ID) +} diff --git a/pkg/util/azure/classic_instance.go b/pkg/util/azure/classic_instance.go index bd3fb44378..2957068bfc 100644 --- a/pkg/util/azure/classic_instance.go +++ b/pkg/util/azure/classic_instance.go @@ -535,3 +535,7 @@ func (self *SClassicInstance) CreateDisk(ctx context.Context, sizeMb int, uuid s func (self *SClassicInstance) Renew(bc billing.SBillingCycle) error { return cloudprovider.ErrNotSupported } + +func (self *SClassicInstance) GetProjectId() string { + return getResourceGroup(self.ID) +} diff --git a/pkg/util/azure/classic_network.go b/pkg/util/azure/classic_network.go index df8a217fdf..7a85fa9ca6 100644 --- a/pkg/util/azure/classic_network.go +++ b/pkg/util/azure/classic_network.go @@ -112,3 +112,7 @@ func (self *SClassicNetwork) Refresh() error { func (self *SClassicNetwork) GetAllocTimeoutSeconds() int { return 120 // 2 minutes } + +func (self *SClassicNetwork) GetProjectId() string { + return "" +} diff --git a/pkg/util/azure/classic_secruitygroup.go b/pkg/util/azure/classic_secruitygroup.go index d472924704..491d62dccb 100644 --- a/pkg/util/azure/classic_secruitygroup.go +++ b/pkg/util/azure/classic_secruitygroup.go @@ -359,3 +359,7 @@ func (region *SRegion) syncClassicSecurityGroup(secgroupId, name, desc string, r } return region.syncClassicSecgroupRules(secgroupId, rules) } + +func (self *SClassicSecurityGroup) GetProjectId() string { + return getResourceGroup(self.ID) +} diff --git a/pkg/util/azure/classic_snapshot.go b/pkg/util/azure/classic_snapshot.go index 561d515538..47703dcff5 100644 --- a/pkg/util/azure/classic_snapshot.go +++ b/pkg/util/azure/classic_snapshot.go @@ -77,3 +77,7 @@ func (self *SClassicSnapshot) GetRegionId() string { func (self *SClassicSnapshot) GetDiskType() string { return "" } + +func (self *SClassicSnapshot) GetProjectId() string { + return "" +} diff --git a/pkg/util/azure/disk.go b/pkg/util/azure/disk.go index e9dfc53f6d..9bd372e886 100644 --- a/pkg/util/azure/disk.go +++ b/pkg/util/azure/disk.go @@ -341,3 +341,7 @@ func (self *SDisk) Rebuild(ctx context.Context) error { // TODO return cloudprovider.ErrNotSupported } + +func (self *SDisk) GetProjectId() string { + return getResourceGroup(self.ID) +} diff --git a/pkg/util/azure/eip.go b/pkg/util/azure/eip.go index 68ddbe06c3..d240825523 100644 --- a/pkg/util/azure/eip.go +++ b/pkg/util/azure/eip.go @@ -242,3 +242,7 @@ func (self *SEipAddress) GetBillingType() string { func (self *SEipAddress) GetExpiredAt() time.Time { return time.Time{} } + +func (self *SEipAddress) GetProjectId() string { + return getResourceGroup(self.ID) +} diff --git a/pkg/util/azure/instance.go b/pkg/util/azure/instance.go index 663cfd8e5c..7d1f96dcbf 100644 --- a/pkg/util/azure/instance.go +++ b/pkg/util/azure/instance.go @@ -1043,3 +1043,7 @@ func (self *SInstance) CreateDisk(ctx context.Context, sizeMb int, uuid string, func (self *SInstance) Renew(bc billing.SBillingCycle) error { return cloudprovider.ErrNotSupported } + +func (self *SInstance) GetProjectId() string { + return getResourceGroup(self.ID) +} diff --git a/pkg/util/azure/network.go b/pkg/util/azure/network.go index a3eea9ac0c..57eb731074 100644 --- a/pkg/util/azure/network.go +++ b/pkg/util/azure/network.go @@ -112,3 +112,7 @@ func (self *SNetwork) Refresh() error { func (self *SNetwork) GetAllocTimeoutSeconds() int { return 120 // 2 minutes } + +func (self *SNetwork) GetProjectId() string { + return getResourceGroup(self.ID) +} diff --git a/pkg/util/azure/provider/provider.go b/pkg/util/azure/provider/provider.go index 936827e17c..baf64b8f97 100644 --- a/pkg/util/azure/provider/provider.go +++ b/pkg/util/azure/provider/provider.go @@ -138,3 +138,7 @@ func (self *SAzureProvider) GetBalance() (float64, error) { func (self *SAzureProvider) GetOnPremiseIRegion() (cloudprovider.ICloudRegion, error) { return nil, cloudprovider.ErrNotImplemented } + +func (self *SAzureProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return self.client.GetIProjects() +} diff --git a/pkg/util/azure/resourcegroup.go b/pkg/util/azure/resourcegroup.go index c9589ef0bf..f1fccd2960 100644 --- a/pkg/util/azure/resourcegroup.go +++ b/pkg/util/azure/resourcegroup.go @@ -30,3 +30,31 @@ func (self *SRegion) CreateResourceGroup(groupName string) (*SResourceGroup, err resourceGroup := SResourceGroup{Name: groupName, Location: self.Name} return &resourceGroup, self.client.Create(jsonutils.Marshal(resourceGroup), &resourceGroup) } + +func (r *SResourceGroup) GetName() string { + return r.Name +} + +func (r *SResourceGroup) GetId() string { + return r.ID +} + +func (r *SResourceGroup) GetGlobalId() string { + return r.ID +} + +func (r *SResourceGroup) GetStatus() string { + return "" +} + +func (r *SResourceGroup) GetMetadata() *jsonutils.JSONDict { + return nil +} + +func (r *SResourceGroup) IsEmulated() bool { + return false +} + +func (r *SResourceGroup) Refresh() error { + return nil +} diff --git a/pkg/util/azure/securitygroup.go b/pkg/util/azure/securitygroup.go index 5cc52f9e97..87e4e29607 100644 --- a/pkg/util/azure/securitygroup.go +++ b/pkg/util/azure/securitygroup.go @@ -487,3 +487,7 @@ func (region *SRegion) AssiginSecurityGroup(instanceId, secgroupId string) error } return region.AttachSecurityToInterfaces(secgroupId, nicIds) } + +func (self *SSecurityGroup) GetProjectId() string { + return getResourceGroup(self.ID) +} diff --git a/pkg/util/azure/snapshot.go b/pkg/util/azure/snapshot.go index 72cc1a3cb4..450e9eccfb 100644 --- a/pkg/util/azure/snapshot.go +++ b/pkg/util/azure/snapshot.go @@ -172,3 +172,7 @@ func (self *SSnapshot) GetDiskId() string { func (self *SSnapshot) GetDiskType() string { return "" } + +func (self *SSnapshot) GetProjectId() string { + return getResourceGroup(self.ID) +} diff --git a/pkg/util/esxi/provider/provider.go b/pkg/util/esxi/provider/provider.go index aece6af9f1..ef9137d7ab 100644 --- a/pkg/util/esxi/provider/provider.go +++ b/pkg/util/esxi/provider/provider.go @@ -162,3 +162,7 @@ func (self *SESXiProvider) GetBalance() (float64, error) { func (self *SESXiProvider) GetOnPremiseIRegion() (cloudprovider.ICloudRegion, error) { return self.client, nil } + +func (self *SESXiProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return nil, cloudprovider.ErrNotSupported +} diff --git a/pkg/util/esxi/vdisk.go b/pkg/util/esxi/vdisk.go index e177b57c7e..53c80ce2ae 100644 --- a/pkg/util/esxi/vdisk.go +++ b/pkg/util/esxi/vdisk.go @@ -244,3 +244,7 @@ func (disk *SVirtualDisk) GetExpiredAt() time.Time { func (disk *SVirtualDisk) Rebuild(ctx context.Context) error { return disk.vm.rebuildDisk(ctx, disk) } + +func (disk *SVirtualDisk) GetProjectId() string { + return "" +} diff --git a/pkg/util/esxi/virtualmachine.go b/pkg/util/esxi/virtualmachine.go index 6ccdad303a..34f222d6cd 100644 --- a/pkg/util/esxi/virtualmachine.go +++ b/pkg/util/esxi/virtualmachine.go @@ -718,3 +718,7 @@ func (self *SVirtualMachine) createDiskInternal(ctx context.Context, sizeMb int, func (self *SVirtualMachine) Renew(bc billing.SBillingCycle) error { return cloudprovider.ErrNotSupported } + +func (self *SVirtualMachine) GetProjectId() string { + return "" +} diff --git a/pkg/util/huawei/disk.go b/pkg/util/huawei/disk.go index 5e19812ea9..17e83d285d 100644 --- a/pkg/util/huawei/disk.go +++ b/pkg/util/huawei/disk.go @@ -482,3 +482,7 @@ func (self *SRegion) resetDisk(diskId, snapshotId string) (string, error) { _, err := self.ecsClient.OsSnapshots.PerformAction2("rollback", snapshotId, params, "") return diskId, err } + +func (self *SDisk) GetProjectId() string { + return "" +} diff --git a/pkg/util/huawei/eip.go b/pkg/util/huawei/eip.go index b0aa932fc3..b4b7564fee 100644 --- a/pkg/util/huawei/eip.go +++ b/pkg/util/huawei/eip.go @@ -367,3 +367,7 @@ func (self *SRegion) GetPorts(instanceId string) ([]Port, error) { err := doListAllWithMarker(self.ecsClient.Port.List, querys, &ports) return ports, err } + +func (self *SEipAddress) GetProjectId() string { + return "" +} diff --git a/pkg/util/huawei/instance.go b/pkg/util/huawei/instance.go index 6bfa34d8b8..e70f103ab2 100644 --- a/pkg/util/huawei/instance.go +++ b/pkg/util/huawei/instance.go @@ -1155,3 +1155,7 @@ func (self *SRegion) UnsubscribeInstance(instanceId string, domianId string) (js self.ecsClient.Orders.SetDomainId(domianId) return self.ecsClient.Orders.PerformAction("resources/delete", "", unsubObj) } + +func (self *SInstance) GetProjectId() string { + return "" +} diff --git a/pkg/util/huawei/network.go b/pkg/util/huawei/network.go index 7a71b3a8b5..4b28daf6f5 100644 --- a/pkg/util/huawei/network.go +++ b/pkg/util/huawei/network.go @@ -149,3 +149,7 @@ func (self *SRegion) deleteNetwork(vpcId string, networkId string) error { ctx := &modules.SManagerContext{InstanceId: vpcId, InstanceManager: self.ecsClient.Vpcs} return DoDeleteWithSpec(self.ecsClient.Subnets.DeleteInContextWithSpec, ctx, networkId, "", nil, nil) } + +func (self *SNetwork) GetProjectId() string { + return "" +} diff --git a/pkg/util/huawei/project.go b/pkg/util/huawei/project.go index 2e0c99392a..64fdc4a1e0 100644 --- a/pkg/util/huawei/project.go +++ b/pkg/util/huawei/project.go @@ -4,6 +4,8 @@ import ( "strings" "fmt" + + "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/util/huawei/client" ) @@ -57,3 +59,7 @@ func (self *SHuaweiClient) GetProjectById(projectId string) (SProject, error) { func (self *SHuaweiClient) GetProjects() ([]SProject, error) { return self.fetchProjects() } + +func (self *SHuaweiClient) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return nil, cloudprovider.ErrNotImplemented +} diff --git a/pkg/util/huawei/provider/provider.go b/pkg/util/huawei/provider/provider.go index 532f05b00a..fd2724c28a 100644 --- a/pkg/util/huawei/provider/provider.go +++ b/pkg/util/huawei/provider/provider.go @@ -132,3 +132,7 @@ func (self *SHuaweiProvider) GetBalance() (float64, error) { func (self *SHuaweiProvider) GetSubAccounts() ([]cloudprovider.SSubAccount, error) { return self.client.GetSubAccounts() } + +func (self *SHuaweiProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return self.client.GetIProjects() +} diff --git a/pkg/util/huawei/securitygroup.go b/pkg/util/huawei/securitygroup.go index 63769e5808..b11fa01a35 100644 --- a/pkg/util/huawei/securitygroup.go +++ b/pkg/util/huawei/securitygroup.go @@ -301,3 +301,7 @@ func (self *SRegion) GetSecurityGroups(vpcId string) ([]SSecurityGroup, error) { return securitygroups, nil } + +func (self *SSecurityGroup) GetProjectId() string { + return "" +} diff --git a/pkg/util/huawei/snapshot.go b/pkg/util/huawei/snapshot.go index ba9e3cd3e0..9f9cbf666d 100644 --- a/pkg/util/huawei/snapshot.go +++ b/pkg/util/huawei/snapshot.go @@ -169,3 +169,7 @@ func (self *SRegion) CreateSnapshot(diskId, name, desc string) (string, error) { err := DoCreate(self.ecsClient.Snapshots.Create, params, &snapshot) return snapshot.ID, err } + +func (self *SSnapshot) GetProjectId() string { + return "" +} diff --git a/pkg/util/openstack/disk.go b/pkg/util/openstack/disk.go index 78eafd20a9..cc79682a72 100644 --- a/pkg/util/openstack/disk.go +++ b/pkg/util/openstack/disk.go @@ -316,3 +316,7 @@ func (disk *SDisk) GetAccessPath() string { func (disk *SDisk) Rebuild(ctx context.Context) error { return cloudprovider.ErrNotSupported } + +func (disk *SDisk) GetProjectId() string { + return disk.TenantID +} diff --git a/pkg/util/openstack/instance.go b/pkg/util/openstack/instance.go index 2ed3213075..14072850ba 100644 --- a/pkg/util/openstack/instance.go +++ b/pkg/util/openstack/instance.go @@ -613,3 +613,7 @@ func (instance *SInstance) Renew(bc billing.SBillingCycle) error { func (region *SRegion) RenewInstances(instanceId []string, bc billing.SBillingCycle) error { return cloudprovider.ErrNotSupported } + +func (instance *SInstance) GetProjectId() string { + return instance.TenantID +} diff --git a/pkg/util/openstack/network.go b/pkg/util/openstack/network.go index 43512a7e3a..089628a8e9 100644 --- a/pkg/util/openstack/network.go +++ b/pkg/util/openstack/network.go @@ -169,3 +169,7 @@ func (region *SRegion) CreateNetwork(vpcId string, name string, cidr string, des } return resp.GetString("subnet", "id") } + +func (network *SNetwork) GetProjectId() string { + return network.TenantID +} diff --git a/pkg/util/openstack/openstack.go b/pkg/util/openstack/openstack.go index 12b34f7c8c..9c3dd58d5a 100644 --- a/pkg/util/openstack/openstack.go +++ b/pkg/util/openstack/openstack.go @@ -12,6 +12,7 @@ import ( "yunion.io/x/onecloud/pkg/cloudprovider" "yunion.io/x/onecloud/pkg/compute/models" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/mcclient/modules" "yunion.io/x/onecloud/pkg/util/httputils" "yunion.io/x/onecloud/pkg/util/version" ) @@ -183,3 +184,25 @@ func (cli *SOpenStackClient) GetRegions() []SRegion { } return regions } + +func (cli *SOpenStackClient) GetIProjects() ([]cloudprovider.ICloudProject, error) { + if len(cli.iregions) > 0 { + region := cli.iregions[0].(*SRegion) + s := cli.client.NewSession(context.Background(), region.Name, "", cli.endpointType, cli.tokenCredential, "") + result, err := modules.Projects.List(s, jsonutils.NewDict()) + if err != nil { + return nil, err + } + iprojects := []cloudprovider.ICloudProject{} + for i := 0; i < len(result.Data); i++ { + project := &SProject{} + if err := result.Data[i].Unmarshal(project); err != nil { + return nil, err + } + iprojects = append(iprojects, project) + } + return iprojects, nil + } + + return nil, cloudprovider.ErrNotImplemented +} diff --git a/pkg/util/openstack/project.go b/pkg/util/openstack/project.go new file mode 100644 index 0000000000..fd7843f0c9 --- /dev/null +++ b/pkg/util/openstack/project.go @@ -0,0 +1,38 @@ +package openstack + +import "yunion.io/x/jsonutils" + +type SProject struct { + Description string + Enabled bool + ID string + Name string +} + +func (p *SProject) GetId() string { + return p.ID +} + +func (p *SProject) GetGlobalId() string { + return p.GetId() +} + +func (p *SProject) GetMetadata() *jsonutils.JSONDict { + return nil +} + +func (p *SProject) GetName() string { + return p.Name +} + +func (p *SProject) GetStatus() string { + return "" +} + +func (p *SProject) IsEmulated() bool { + return false +} + +func (p *SProject) Refresh() error { + return nil +} diff --git a/pkg/util/openstack/provider/provider.go b/pkg/util/openstack/provider/provider.go index 67771e2f51..de588f037c 100644 --- a/pkg/util/openstack/provider/provider.go +++ b/pkg/util/openstack/provider/provider.go @@ -175,3 +175,7 @@ func (self *SOpenStackProvider) GetBalance() (float64, error) { func (self *SOpenStackProvider) GetOnPremiseIRegion() (cloudprovider.ICloudRegion, error) { return nil, cloudprovider.ErrNotImplemented } + +func (self *SOpenStackProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return self.client.GetIProjects() +} diff --git a/pkg/util/openstack/securitygroup.go b/pkg/util/openstack/securitygroup.go index b90b112e48..8503fa8f50 100644 --- a/pkg/util/openstack/securitygroup.go +++ b/pkg/util/openstack/securitygroup.go @@ -351,3 +351,7 @@ func (region *SRegion) CreateSecurityGroup(name, description string) (*SSecurity secgroup := &SSecurityGroup{} return secgroup, resp.Unmarshal(secgroup, "security_group") } + +func (secgroup *SSecurityGroup) GetProjectId() string { + return secgroup.TenantID +} diff --git a/pkg/util/openstack/shell/project.go b/pkg/util/openstack/shell/project.go new file mode 100644 index 0000000000..71f4307cba --- /dev/null +++ b/pkg/util/openstack/shell/project.go @@ -0,0 +1,19 @@ +package shell + +import ( + "yunion.io/x/onecloud/pkg/util/openstack" + "yunion.io/x/onecloud/pkg/util/shellutils" +) + +func init() { + type ProjectListOptions struct { + } + shellutils.R(&ProjectListOptions{}, "project-list", "List project", func(cli *openstack.SRegion, args *ProjectListOptions) error { + project, err := cli.GetClient().GetIProjects() + if err != nil { + return err + } + printList(project, 0, 0, 0, nil) + return nil + }) +} diff --git a/pkg/util/openstack/snapshot.go b/pkg/util/openstack/snapshot.go index 265daeef8e..d8cdcd4eeb 100644 --- a/pkg/util/openstack/snapshot.go +++ b/pkg/util/openstack/snapshot.go @@ -163,3 +163,7 @@ func (region *SRegion) CreateSnapshot(diskId, name, desc string) (*SSnapshot, er snapshot := &SSnapshot{region: region} return snapshot, resp.Unmarshal(snapshot, "snapshot") } + +func (self *SSnapshot) GetProjectId() string { + return self.ProjectID +} diff --git a/pkg/util/qcloud/disk.go b/pkg/util/qcloud/disk.go index ac9d7c2fb1..7c314038f6 100644 --- a/pkg/util/qcloud/disk.go +++ b/pkg/util/qcloud/disk.go @@ -4,6 +4,7 @@ import ( "context" "fmt" "sort" + "strconv" "strings" "time" @@ -382,3 +383,7 @@ func (self *SDisk) Rebuild(ctx context.Context) error { // TODO return cloudprovider.ErrNotSupported } + +func (self *SDisk) GetProjectId() string { + return strconv.Itoa(self.Placement.ProjectId) +} diff --git a/pkg/util/qcloud/eip.go b/pkg/util/qcloud/eip.go index afd6dc666d..e30942b643 100644 --- a/pkg/util/qcloud/eip.go +++ b/pkg/util/qcloud/eip.go @@ -330,3 +330,7 @@ func (region *SRegion) UpdateInstanceBandwidth(instanceId string, bw int) error _, err := region.cvmRequest("ResetInstancesInternetMaxBandwidth", params) return err } + +func (self *SEipAddress) GetProjectId() string { + return "" +} diff --git a/pkg/util/qcloud/instance.go b/pkg/util/qcloud/instance.go index 8feea35642..719596d6e3 100644 --- a/pkg/util/qcloud/instance.go +++ b/pkg/util/qcloud/instance.go @@ -2,6 +2,7 @@ package qcloud import ( "fmt" + "strconv" "time" "context" @@ -821,3 +822,7 @@ func (region *SRegion) RenewInstances(instanceId []string, bc billing.SBillingCy } return nil } + +func (self *SInstance) GetProjectId() string { + return strconv.Itoa(self.Placement.ProjectId) +} diff --git a/pkg/util/qcloud/loadbalancer.go b/pkg/util/qcloud/loadbalancer.go index a82f9231d8..2bf9664005 100755 --- a/pkg/util/qcloud/loadbalancer.go +++ b/pkg/util/qcloud/loadbalancer.go @@ -578,3 +578,7 @@ func (self *SRegion) WaitLBTaskSuccess(requestId string, interval time.Duration, return cloudprovider.ErrTimeout } + +func (self *SLoadbalancer) GetProjectId() string { + return strconv.Itoa(int(self.ProjectID)) +} diff --git a/pkg/util/qcloud/loadbalancer_acl.go b/pkg/util/qcloud/loadbalancer_acl.go index c2026a1861..2a7ea962db 100755 --- a/pkg/util/qcloud/loadbalancer_acl.go +++ b/pkg/util/qcloud/loadbalancer_acl.go @@ -40,3 +40,7 @@ func (self *SLBACL) GetMetadata() *jsonutils.JSONDict { func (self *SLBACL) GetAclEntries() *jsonutils.JSONArray { return nil } + +func (self *SLBACL) GetProjectId() string { + return "" +} diff --git a/pkg/util/qcloud/loadbalancer_backend.go b/pkg/util/qcloud/loadbalancer_backend.go index 51cf72e28b..cd3704eb5a 100755 --- a/pkg/util/qcloud/loadbalancer_backend.go +++ b/pkg/util/qcloud/loadbalancer_backend.go @@ -169,3 +169,7 @@ func (self *SRegion) GetLBBackends(t LB_TYPE, lbId, listenerId, ruleId string) ( return nil, fmt.Errorf("GetLBBackends unsupported loadbalancer type %d", t) } } + +func (self *SLBBackend) GetProjectId() string { + return "" +} diff --git a/pkg/util/qcloud/loadbalancer_backendgroup.go b/pkg/util/qcloud/loadbalancer_backendgroup.go index 1cc7608761..36218cdd5d 100755 --- a/pkg/util/qcloud/loadbalancer_backendgroup.go +++ b/pkg/util/qcloud/loadbalancer_backendgroup.go @@ -222,3 +222,7 @@ func (self *SLBBackendGroup) GetBackends() ([]SLBBackend, error) { return backends, nil } + +func (self *SLBBackendGroup) GetProjectId() string { + return "" +} diff --git a/pkg/util/qcloud/loadbalancer_certificate.go b/pkg/util/qcloud/loadbalancer_certificate.go index 1ec5df50c1..7b46c27fd9 100755 --- a/pkg/util/qcloud/loadbalancer_certificate.go +++ b/pkg/util/qcloud/loadbalancer_certificate.go @@ -81,3 +81,7 @@ func (self *SLBCertificate) GetFingerprint() string { func (self *SLBCertificate) GetExpireTime() time.Time { return self.CERTEndTime } + +func (self *SLBCertificate) GetProjectId() string { + return "" +} diff --git a/pkg/util/qcloud/loadbalancer_listener.go b/pkg/util/qcloud/loadbalancer_listener.go index 6081ccad7a..2a6477a3a7 100755 --- a/pkg/util/qcloud/loadbalancer_listener.go +++ b/pkg/util/qcloud/loadbalancer_listener.go @@ -780,3 +780,7 @@ func certificateParams(t LB_TYPE, params map[string]string, cert *certificate, p } return params } + +func (self *SLBListener) GetProjectId() string { + return "" +} diff --git a/pkg/util/qcloud/localdisk.go b/pkg/util/qcloud/localdisk.go index 723ca61952..18338b2ff7 100644 --- a/pkg/util/qcloud/localdisk.go +++ b/pkg/util/qcloud/localdisk.go @@ -139,3 +139,7 @@ func (self *SLocalDisk) Rebuild(ctx context.Context) error { // TODO return cloudprovider.ErrNotSupported } + +func (disk *SLocalDisk) GetProjectId() string { + return "" +} diff --git a/pkg/util/qcloud/network.go b/pkg/util/qcloud/network.go index ae09760e3a..24370db91a 100644 --- a/pkg/util/qcloud/network.go +++ b/pkg/util/qcloud/network.go @@ -131,3 +131,7 @@ func (self *SRegion) CreateNetwork(zoneId string, vpcId string, name string, cid } return body.GetString("Subnet", "SubnetId") } + +func (self *SNetwork) GetProjectId() string { + return "" +} diff --git a/pkg/util/qcloud/project.go b/pkg/util/qcloud/project.go new file mode 100644 index 0000000000..a4ce9b33d7 --- /dev/null +++ b/pkg/util/qcloud/project.go @@ -0,0 +1,47 @@ +package qcloud + +import ( + "strings" + "time" + + "yunion.io/x/jsonutils" +) + +type SProject struct { + ProjectName string `json:"projectName"` + ProjectId string `json:projectId` + CreateTime time.Time `json:createTime` + CreateorUin int `json:"creatorUin"` + ProjectInfo string `json:"projectInfo"` +} + +func (p *SProject) GetId() string { + if strings.Index(p.ProjectId, ".") != -1 { + return strings.Split(p.ProjectId, ".")[0] + } + return "" +} + +func (p *SProject) GetGlobalId() string { + return p.GetId() +} + +func (p *SProject) GetMetadata() *jsonutils.JSONDict { + return nil +} + +func (p *SProject) GetName() string { + return p.ProjectName +} + +func (p *SProject) GetStatus() string { + return "" +} + +func (p *SProject) IsEmulated() bool { + return false +} + +func (p *SProject) Refresh() error { + return nil +} diff --git a/pkg/util/qcloud/provider/provider.go b/pkg/util/qcloud/provider/provider.go index d7bbf95255..183b016cc2 100644 --- a/pkg/util/qcloud/provider/provider.go +++ b/pkg/util/qcloud/provider/provider.go @@ -91,7 +91,7 @@ func (self *SQcloudProviderFactory) ValidateUpdateCloudaccountCredential(ctx con } func (self *SQcloudProviderFactory) GetProvider(providerId, providerName, url, account, secret string) (cloudprovider.ICloudProvider, error) { - client, err := qcloud.NewQcloudClient(providerId, providerName, account, secret) + client, err := qcloud.NewQcloudClient(providerId, providerName, account, secret, false) if err != nil { return nil, err } @@ -146,3 +146,7 @@ func (self *SQcloudProvider) GetBalance() (float64, error) { func (self *SQcloudProvider) GetOnPremiseIRegion() (cloudprovider.ICloudRegion, error) { return nil, cloudprovider.ErrNotImplemented } + +func (self *SQcloudProvider) GetIProjects() ([]cloudprovider.ICloudProject, error) { + return self.client.GetIProjects() +} diff --git a/pkg/util/qcloud/qcloud.go b/pkg/util/qcloud/qcloud.go index 5695735f55..94db99aebd 100644 --- a/pkg/util/qcloud/qcloud.go +++ b/pkg/util/qcloud/qcloud.go @@ -36,10 +36,12 @@ type SQcloudClient struct { SecretID string SecretKey string iregions []cloudprovider.ICloudRegion + + Debug bool } -func NewQcloudClient(providerId string, providerName string, secretID string, secretKey string) (*SQcloudClient, error) { - client := SQcloudClient{providerId: providerId, providerName: providerName, SecretID: secretID, SecretKey: secretKey} +func NewQcloudClient(providerId string, providerName string, secretID string, secretKey string, isDebug bool) (*SQcloudClient, error) { + client := SQcloudClient{providerId: providerId, providerName: providerName, SecretID: secretID, SecretKey: secretKey, Debug: isDebug} if account := strings.Split(secretID, "/"); len(account) == 2 { client.SecretID = account[0] client.AppID = account[1] @@ -63,42 +65,47 @@ func apiDomain(product string, params map[string]string) string { } } -func jsonRequest(client *common.Client, apiName string, params map[string]string) (jsonutils.JSONObject, error) { +func jsonRequest(client *common.Client, apiName string, params map[string]string, debug bool) (jsonutils.JSONObject, error) { domain := apiDomain("cvm", params) - return _jsonRequest(client, domain, QCLOUD_API_VERSION, apiName, params) + return _jsonRequest(client, domain, QCLOUD_API_VERSION, apiName, params, debug) } -func vpcRequest(client *common.Client, apiName string, params map[string]string) (jsonutils.JSONObject, error) { +func vpcRequest(client *common.Client, apiName string, params map[string]string, debug bool) (jsonutils.JSONObject, error) { domain := apiDomain("vpc", params) - return _jsonRequest(client, domain, QCLOUD_API_VERSION, apiName, params) + return _jsonRequest(client, domain, QCLOUD_API_VERSION, apiName, params, debug) } -func cbsRequest(client *common.Client, apiName string, params map[string]string) (jsonutils.JSONObject, error) { +func cbsRequest(client *common.Client, apiName string, params map[string]string, debug bool) (jsonutils.JSONObject, error) { domain := apiDomain("cbs", params) - return _jsonRequest(client, domain, QCLOUD_API_VERSION, apiName, params) + return _jsonRequest(client, domain, QCLOUD_API_VERSION, apiName, params, debug) +} + +func accountRequest(client *common.Client, apiName string, params map[string]string, debug bool) (jsonutils.JSONObject, error) { + domain := "account.api.qcloud.com" + return _phpJsonRequest(client, &wssJsonResponse{}, domain, "/v2/index.php", "", apiName, params, debug) } // loadbalancer服务 api 3.0 -func clbRequest(client *common.Client, apiName string, params map[string]string) (jsonutils.JSONObject, error) { +func clbRequest(client *common.Client, apiName string, params map[string]string, debug bool) (jsonutils.JSONObject, error) { domain := apiDomain("clb", params) - return _jsonRequest(client, domain, QCLOUD_CLB_API_VERSION, apiName, params) + return _jsonRequest(client, domain, QCLOUD_CLB_API_VERSION, apiName, params, debug) } // loadbalancer服务 api 2017 -func lbRequest(client *common.Client, apiName string, params map[string]string) (jsonutils.JSONObject, error) { +func lbRequest(client *common.Client, apiName string, params map[string]string, debug bool) (jsonutils.JSONObject, error) { domain := "lb.api.qcloud.com" - return _phpJsonRequest(client, &lbJsonResponse{}, domain, "/v2/index.php", "", apiName, params) + return _phpJsonRequest(client, &lbJsonResponse{}, domain, "/v2/index.php", "", apiName, params, debug) } // ssl 证书服务 -func wssRequest(client *common.Client, apiName string, params map[string]string) (jsonutils.JSONObject, error) { +func wssRequest(client *common.Client, apiName string, params map[string]string, debug bool) (jsonutils.JSONObject, error) { domain := "wss.api.qcloud.com" - return _phpJsonRequest(client, &wssJsonResponse{}, domain, "/v2/index.php", "", apiName, params) + return _phpJsonRequest(client, &wssJsonResponse{}, domain, "/v2/index.php", "", apiName, params, debug) } -func billingRequest(client *common.Client, apiName string, params map[string]string) (jsonutils.JSONObject, error) { +func billingRequest(client *common.Client, apiName string, params map[string]string, debug bool) (jsonutils.JSONObject, error) { domain := "billing.tencentcloudapi.com" - return _jsonRequest(client, domain, QCLOUD_BILLING_API_VERSION, apiName, params) + return _jsonRequest(client, domain, QCLOUD_BILLING_API_VERSION, apiName, params, debug) } // ============phpJsonRequest============ @@ -198,7 +205,7 @@ func (r *QcloudResponse) GetResponse() *interface{} { return r.Response } -func _jsonRequest(client *common.Client, domain string, version string, apiName string, params map[string]string) (jsonutils.JSONObject, error) { +func _jsonRequest(client *common.Client, domain string, version string, apiName string, params map[string]string, debug bool) (jsonutils.JSONObject, error) { req := &tchttp.BaseRequest{} if region, ok := params["Region"]; ok { client = client.Init(region) @@ -218,12 +225,12 @@ func _jsonRequest(client *common.Client, domain string, version string, apiName resp := &QcloudResponse{ BaseResponse: &tchttp.BaseResponse{}, } - return _baseJsonRequest(client, req, resp) + return _baseJsonRequest(client, req, resp, debug) } // 老版本腾讯云api。 适用于类似 https://cvm.api.qcloud.com/v2/index.php 这样的带/v2/index.php路径的接口 // todo: 添加自定义response参数 -func _phpJsonRequest(client *common.Client, resp qcloudResponse, domain string, path string, version string, apiName string, params map[string]string) (jsonutils.JSONObject, error) { +func _phpJsonRequest(client *common.Client, resp qcloudResponse, domain string, path string, version string, apiName string, params map[string]string, debug bool) (jsonutils.JSONObject, error) { req := &phpJsonRequest{Path: path} if region, ok := params["Region"]; ok { client = client.Init(region) @@ -240,10 +247,10 @@ func _phpJsonRequest(client *common.Client, resp qcloudResponse, domain string, req.GetParams()[k] = v } - return _baseJsonRequest(client, req, resp) + return _baseJsonRequest(client, req, resp, debug) } -func _baseJsonRequest(client *common.Client, req tchttp.Request, resp qcloudResponse) (jsonutils.JSONObject, error) { +func _baseJsonRequest(client *common.Client, req tchttp.Request, resp qcloudResponse, debug bool) (jsonutils.JSONObject, error) { for i := 1; i <= 3; i++ { err := client.Send(req, resp) if err == nil { @@ -264,6 +271,10 @@ func _baseJsonRequest(client *common.Client, req tchttp.Request, resp qcloudResp log.Errorf("request url: %s\nparams: %s\nresponse: %s\nerror: %v", req.GetDomain(), jsonutils.Marshal(req.GetParams()).PrettyString(), resp.GetResponse(), err) return nil, err } + if debug { + log.Debugf("request: %s", req.GetParams()) + log.Debugf("response: %s", jsonutils.Marshal(resp.GetResponse()).PrettyString()) + } return jsonutils.Marshal(resp.GetResponse()), nil } @@ -285,7 +296,7 @@ func (client *SQcloudClient) vpcRequest(apiName string, params map[string]string if err != nil { return nil, err } - return vpcRequest(cli, apiName, params) + return vpcRequest(cli, apiName, params, client.Debug) } func (client *SQcloudClient) cbsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { @@ -293,7 +304,15 @@ func (client *SQcloudClient) cbsRequest(apiName string, params map[string]string if err != nil { return nil, err } - return cbsRequest(cli, apiName, params) + return cbsRequest(cli, apiName, params, client.Debug) +} + +func (client *SQcloudClient) accountRequestRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + cli, err := client.getDefaultClient() + if err != nil { + return nil, err + } + return accountRequest(cli, apiName, params, client.Debug) } func (client *SQcloudClient) clbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { @@ -301,7 +320,7 @@ func (client *SQcloudClient) clbRequest(apiName string, params map[string]string if err != nil { return nil, err } - return clbRequest(cli, apiName, params) + return clbRequest(cli, apiName, params, client.Debug) } func (client *SQcloudClient) lbRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { @@ -309,7 +328,7 @@ func (client *SQcloudClient) lbRequest(apiName string, params map[string]string) if err != nil { return nil, err } - return lbRequest(cli, apiName, params) + return lbRequest(cli, apiName, params, client.Debug) } func (client *SQcloudClient) wssRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { @@ -317,7 +336,7 @@ func (client *SQcloudClient) wssRequest(apiName string, params map[string]string if err != nil { return nil, err } - return wssRequest(cli, apiName, params) + return wssRequest(cli, apiName, params, client.Debug) } func (client *SQcloudClient) billingRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { @@ -325,7 +344,7 @@ func (client *SQcloudClient) billingRequest(apiName string, params map[string]st if err != nil { return nil, err } - return billingRequest(cli, apiName, params) + return billingRequest(cli, apiName, params, client.Debug) } func (client *SQcloudClient) jsonRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { @@ -333,7 +352,7 @@ func (client *SQcloudClient) jsonRequest(apiName string, params map[string]strin if err != nil { return nil, err } - return jsonRequest(cli, apiName, params) + return jsonRequest(cli, apiName, params, client.Debug) } func (client *SQcloudClient) fetchRegions() error { @@ -457,3 +476,25 @@ func (client *SQcloudClient) QueryAccountBalance() (*SAccountBalance, error) { balance.AvailableAmount = balanceCent / 100.0 return &balance, nil } + +func (client *SQcloudClient) GetIProjects() ([]cloudprovider.ICloudProject, error) { + projects := []SProject{} + params := map[string]string{"allList": "1"} + body, err := client.accountRequestRequest("DescribeProject", params) + if err != nil { + return nil, err + } + if err := body.Unmarshal(&projects); err != nil { + return nil, err + } + projects = append(projects, SProject{ + ProjectId: "0", + ProjectName: "默认项目", + CreateTime: time.Time{}, + }) + iprojects := []cloudprovider.ICloudProject{} + for i := 0; i < len(projects); i++ { + iprojects = append(iprojects, &projects[i]) + } + return iprojects, nil +} diff --git a/pkg/util/qcloud/region.go b/pkg/util/qcloud/region.go index d3464cadb2..31ebc63569 100644 --- a/pkg/util/qcloud/region.go +++ b/pkg/util/qcloud/region.go @@ -602,6 +602,10 @@ func (self *SRegion) cvmRequest(apiName string, params map[string]string) (jsonu return self.client.jsonRequest(apiName, params) } +func (self *SRegion) accountRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { + return self.client.accountRequestRequest(apiName, params) +} + func (self *SRegion) cbsRequest(apiName string, params map[string]string) (jsonutils.JSONObject, error) { params["Region"] = self.Region return self.client.cbsRequest(apiName, params) diff --git a/pkg/util/qcloud/securitygroup.go b/pkg/util/qcloud/securitygroup.go index 2ec2733b26..7240337e57 100644 --- a/pkg/util/qcloud/securitygroup.go +++ b/pkg/util/qcloud/securitygroup.go @@ -508,3 +508,7 @@ func (self *SRegion) CreateSecurityGroup(name, description string) (*SSecurityGr } return &secgroup, nil } + +func (self *SSecurityGroup) GetProjectId() string { + return "" +} diff --git a/pkg/util/qcloud/shell/project.go b/pkg/util/qcloud/shell/project.go new file mode 100644 index 0000000000..81d2c40edb --- /dev/null +++ b/pkg/util/qcloud/shell/project.go @@ -0,0 +1,19 @@ +package shell + +import ( + "yunion.io/x/onecloud/pkg/util/qcloud" + "yunion.io/x/onecloud/pkg/util/shellutils" +) + +func init() { + type ProjectListOptions struct { + } + shellutils.R(&ProjectListOptions{}, "project-list", "List project", func(cli *qcloud.SRegion, args *ProjectListOptions) error { + project, err := cli.GetClient().GetIProjects() + if err != nil { + return err + } + printList(project, 0, 0, 0, nil) + return nil + }) +} diff --git a/pkg/util/qcloud/snapshot.go b/pkg/util/qcloud/snapshot.go index 96fb56e61b..e54277cbfe 100644 --- a/pkg/util/qcloud/snapshot.go +++ b/pkg/util/qcloud/snapshot.go @@ -2,6 +2,7 @@ package qcloud import ( "fmt" + "strconv" "time" "yunion.io/x/jsonutils" @@ -217,3 +218,7 @@ func (self *SRegion) CreateSnapshot(diskId, name, desc string) (string, error) { } return body.GetString("SnapshotId") } + +func (self *SSnapshot) GetProjectId() string { + return strconv.Itoa(self.Placement.ProjectId) +}