diff --git a/cmd/climc/shell/cloudproviderregions.go b/cmd/climc/shell/cloudproviderregions.go index 097cd3a8ba..ab486ada76 100644 --- a/cmd/climc/shell/cloudproviderregions.go +++ b/cmd/climc/shell/cloudproviderregions.go @@ -27,6 +27,8 @@ func init() { type CloudproviderRegionListOptions struct { options.BaseListOptions Region string `help:"ID or Name of Host"` + + Capability []string `help:"capability filter" choices:"project|compute|network|loadbalancer|objectstore|rds|cache|event"` } R(&CloudproviderRegionListOptions{}, "cloud-provider-region-list", "List cloudprovider region synchronization status", func(s *mcclient.ClientSession, args *CloudproviderRegionListOptions) error { var params *jsonutils.JSONDict diff --git a/cmd/climc/shell/cloudregions.go b/cmd/climc/shell/cloudregions.go index e39cbe5bd0..cb8a3ddf4b 100644 --- a/cmd/climc/shell/cloudregions.go +++ b/cmd/climc/shell/cloudregions.go @@ -35,6 +35,8 @@ func init() { City string `help:"List regions in the specified city"` + Capability []string `help:"capability filter" choices:"project|compute|network|loadbalancer|objectstore|rds|cache|event"` + DistinctField string `help:"list the specified distinct field, e.g. city, region"` } R(&CloudregionListOptions{}, "cloud-region-list", "List cloud regions", func(s *mcclient.ClientSession, opts *CloudregionListOptions) error { diff --git a/pkg/apis/compute/cloudaccount_const.go b/pkg/apis/compute/cloudaccount_const.go index e10a8ff950..30c644fe9a 100644 --- a/pkg/apis/compute/cloudaccount_const.go +++ b/pkg/apis/compute/cloudaccount_const.go @@ -14,6 +14,10 @@ package compute +import ( + "yunion.io/x/onecloud/pkg/cloudprovider" +) + const ( CLOUD_PROVIDER_INIT = "init" CLOUD_PROVIDER_CONNECTED = "connected" @@ -91,11 +95,11 @@ var ( ) const ( - CLOUD_ENV_PUBLIC_CLOUD = "public" - CLOUD_ENV_PRIVATE_CLOUD = "private" - CLOUD_ENV_ON_PREMISE = "onpremise" + CLOUD_ENV_PUBLIC_CLOUD = cloudprovider.CLOUD_ENV_PUBLIC_CLOUD + CLOUD_ENV_PRIVATE_CLOUD = cloudprovider.CLOUD_ENV_PRIVATE_CLOUD + CLOUD_ENV_ON_PREMISE = cloudprovider.CLOUD_ENV_ON_PREMISE - CLOUD_ENV_PRIVATE_ON_PREMISE = "private_or_onpremise" + CLOUD_ENV_PRIVATE_ON_PREMISE = cloudprovider.CLOUD_ENV_PRIVATE_ON_PREMISE ) const ( diff --git a/pkg/apis/compute/cloudproviderregion.go b/pkg/apis/compute/cloudproviderregion.go index 039094b55e..1e3ccefb64 100644 --- a/pkg/apis/compute/cloudproviderregion.go +++ b/pkg/apis/compute/cloudproviderregion.go @@ -38,6 +38,9 @@ type CloudproviderregionDetails struct { // 自动同步周期 // example: 300 SyncIntervalSeconds int `json:"sync_interval_seconds"` + + // 支持服务列表 + Capabilities []string `json:"capabilities"` } type CloudproviderregionListInput struct { @@ -45,6 +48,7 @@ type CloudproviderregionListInput struct { SyncableBaseResourceListInput RegionalFilterListInput ManagedResourceListInput + CapabilityListInput // 是否启用 Enabled *bool `json:"enabled"` diff --git a/pkg/apis/compute/cloudregion.go b/pkg/apis/compute/cloudregion.go index 0a47806a6a..02df725532 100644 --- a/pkg/apis/compute/cloudregion.go +++ b/pkg/apis/compute/cloudregion.go @@ -40,6 +40,10 @@ type CloudregionDetails struct { SCloudregionUsage SCloudregion + + // 云类型, public, private or onpremise + // example: public + CloudEnv string `json:"cloud_env"` } type CloudregionResourceInfo struct { diff --git a/pkg/apis/compute/geo_input.go b/pkg/apis/compute/geo_input.go index d4464cbfac..1668bd924b 100644 --- a/pkg/apis/compute/geo_input.go +++ b/pkg/apis/compute/geo_input.go @@ -77,6 +77,8 @@ type CloudregionListInput struct { UsableResourceListInput UsableVpcResourceListInput + CapabilityListInput + // 过滤位于指定城市的区域 City string `json:"city"` // 过滤提供特定服务的区域 diff --git a/pkg/cloudprovider/cloudprovider.go b/pkg/cloudprovider/cloudprovider.go index 2b0abd97b0..78d9e5b194 100644 --- a/pkg/cloudprovider/cloudprovider.go +++ b/pkg/cloudprovider/cloudprovider.go @@ -324,6 +324,20 @@ func GetOnPremiseProviders() []string { return providers } +func GetProviderCloudEnv(provider string) string { + p, err := GetProviderFactory(provider) + if err != nil { + return "" + } + if p.IsPublicCloud() { + return CLOUD_ENV_PUBLIC_CLOUD + } + if p.IsOnPremise() { + return CLOUD_ENV_ON_PREMISE + } + return CLOUD_ENV_PRIVATE_CLOUD +} + type baseProviderFactory struct { } diff --git a/pkg/cloudprovider/consts.go b/pkg/cloudprovider/consts.go index a7efe124d6..3f8881640b 100644 --- a/pkg/cloudprovider/consts.go +++ b/pkg/cloudprovider/consts.go @@ -50,3 +50,11 @@ const ( CLOUD_CAPABILITY_CACHE = "cache" CLOUD_CAPABILITY_EVENT = "event" ) + +const ( + CLOUD_ENV_PUBLIC_CLOUD = "public" + CLOUD_ENV_PRIVATE_CLOUD = "private" + CLOUD_ENV_ON_PREMISE = "onpremise" + + CLOUD_ENV_PRIVATE_ON_PREMISE = "private_or_onpremise" +) diff --git a/pkg/cloudprovider/resources.go b/pkg/cloudprovider/resources.go index 169c2f781a..bd2054a8fe 100644 --- a/pkg/cloudprovider/resources.go +++ b/pkg/cloudprovider/resources.go @@ -136,6 +136,8 @@ type ICloudRegion interface { GetProvider() string GetICloudEvents(start time.Time, end time.Time, withReadEvent bool) ([]ICloudEvent, error) //获取公有云操作日志接口 + + GetCapabilities() []string } type ICloudZone interface { diff --git a/pkg/compute/models/cloudprovidercapacities.go b/pkg/compute/models/cloudprovidercapacities.go index 968fcb5866..f65d5da829 100644 --- a/pkg/compute/models/cloudprovidercapacities.go +++ b/pkg/compute/models/cloudprovidercapacities.go @@ -47,11 +47,16 @@ type SCloudproviderCapability struct { db.SResourceBase CloudproviderId string `width:"36" charset:"ascii" nullable:"false" primary:"true"` + CloudregionId string `width:"36" charset:"ascii" nullable:"false" default:"" primary:"true"` Capability string `width:"18" charset:"ascii" nullable:"false" primary:"true"` } func (manager *SCloudproviderCapabilityManager) setCapabilities(ctx context.Context, userCred mcclient.TokenCredential, cloudproviderId string, capabilities []string) error { - oldCapabilities, err := manager.getCapabilities(cloudproviderId) + return manager.setRegionCapabilities(ctx, userCred, cloudproviderId, "", capabilities) +} + +func (manager *SCloudproviderCapabilityManager) setRegionCapabilities(ctx context.Context, userCred mcclient.TokenCredential, cloudproviderId string, cloudregionId string, capabilities []string) error { + oldCapabilities, err := manager.getRegionCapabilities(cloudproviderId, cloudregionId) if err != nil { return errors.Wrap(err, "manager.getCapabilities") } @@ -61,6 +66,7 @@ func (manager *SCloudproviderCapabilityManager) setCapabilities(ctx context.Cont cpc := SCloudproviderCapability{ CloudproviderId: cloudproviderId, + CloudregionId: cloudregionId, } cpc.SetModelManager(manager, &cpc) @@ -82,7 +88,11 @@ func (manager *SCloudproviderCapabilityManager) setCapabilities(ctx context.Cont } func (manager *SCloudproviderCapabilityManager) getCapabilities(cloudproviderId string) ([]string, error) { - q := manager.Query().Equals("cloudprovider_id", cloudproviderId) + return manager.getRegionCapabilities(cloudproviderId, "") +} + +func (manager *SCloudproviderCapabilityManager) getRegionCapabilities(cloudproviderId string, cloudregionId string) ([]string, error) { + q := manager.Query().Equals("cloudprovider_id", cloudproviderId).Equals("cloudregion_id", cloudregionId) capabilities := make([]SCloudproviderCapability, 0) err := db.FetchModelObjects(manager, q, &capabilities) if err != nil { @@ -97,5 +107,9 @@ func (manager *SCloudproviderCapabilityManager) getCapabilities(cloudproviderId } func (manager *SCloudproviderCapabilityManager) removeCapabilities(ctx context.Context, userCred mcclient.TokenCredential, cloudproviderId string) error { - return manager.setCapabilities(ctx, userCred, cloudproviderId, []string{}) + return manager.removeRegionCapabilities(ctx, userCred, cloudproviderId, "") +} + +func (manager *SCloudproviderCapabilityManager) removeRegionCapabilities(ctx context.Context, userCred mcclient.TokenCredential, cloudproviderId string, cloudregionId string) error { + return manager.setRegionCapabilities(ctx, userCred, cloudproviderId, cloudregionId, []string{}) } diff --git a/pkg/compute/models/cloudproviderregions.go b/pkg/compute/models/cloudproviderregions.go index ab2e14dcd3..f4585afb11 100644 --- a/pkg/compute/models/cloudproviderregions.go +++ b/pkg/compute/models/cloudproviderregions.go @@ -147,6 +147,7 @@ func (manager *SCloudproviderregionManager) FetchCustomizeColumns( for i := range rows { rows[i].JointResourceBaseDetails = jointRows[i] rows[i].CloudregionResourceInfo = regionRows[i] + rows[i].Capabilities, _ = objs[i].(*SCloudproviderregion).getCapabilities() managerIds[i] = objs[i].(*SCloudproviderregion).CloudproviderId } @@ -521,6 +522,15 @@ func (manager *SCloudproviderregionManager) ListItemFilter( } } + if len(query.Capability) > 0 { + subq := CloudproviderCapabilityManager.Query().SubQuery() + q = q.Join(subq, sqlchemy.AND( + sqlchemy.Equals(q.Field("cloudprovider_id"), subq.Field("cloudprovider_id")), + sqlchemy.Equals(q.Field("cloudregion_id"), subq.Field("cloudregion_id")), + )) + q = q.Filter(sqlchemy.In(subq.Field("capability"), query.Capability)) + } + return q, nil } @@ -566,3 +576,15 @@ func (manager *SCloudproviderregionManager) QueryDistinctExtraField(q *sqlchemy. return q, httperrors.ErrNotFound } + +func (cpr *SCloudproviderregion) setCapabilities(ctx context.Context, userCred mcclient.TokenCredential, capa []string) error { + return CloudproviderCapabilityManager.setRegionCapabilities(ctx, userCred, cpr.CloudproviderId, cpr.CloudregionId, capa) +} + +func (cpr *SCloudproviderregion) removeCapabilities(ctx context.Context, userCred mcclient.TokenCredential) error { + return CloudproviderCapabilityManager.removeRegionCapabilities(ctx, userCred, cpr.CloudproviderId, cpr.CloudregionId) +} + +func (cpr *SCloudproviderregion) getCapabilities() ([]string, error) { + return CloudproviderCapabilityManager.getRegionCapabilities(cpr.CloudproviderId, cpr.CloudregionId) +} diff --git a/pkg/compute/models/cloudproviders.go b/pkg/compute/models/cloudproviders.go index 648fa987d1..d3a7c0b60c 100644 --- a/pkg/compute/models/cloudproviders.go +++ b/pkg/compute/models/cloudproviders.go @@ -1154,6 +1154,7 @@ func (provider *SCloudprovider) prepareCloudproviderRegions(ctx context.Context, } if driver.GetFactory().IsOnPremise() { cpr := CloudproviderRegionManager.FetchByIdsOrCreate(provider.Id, api.DEFAULT_REGION_ID) + cpr.setCapabilities(ctx, userCred, driver.GetCapabilities()) return []SCloudproviderregion{*cpr}, nil } iregions := driver.GetIRegions() diff --git a/pkg/compute/models/cloudregions.go b/pkg/compute/models/cloudregions.go index b695494cdb..1e19c86712 100644 --- a/pkg/compute/models/cloudregions.go +++ b/pkg/compute/models/cloudregions.go @@ -65,10 +65,10 @@ type SCloudregion struct { // 云环境 // example: ChinaCloud - Environment string `width:"32" charset:"ascii" list:"user" json:"environment"` + Environment string `width:"32" charset:"ascii" list:"user"` // 云平台 // example: Huawei - Provider string `width:"64" charset:"ascii" list:"user" nullable:"false" default:"OneCloud" json:"provider"` + Provider string `width:"64" charset:"ascii" list:"user" nullable:"false" default:"OneCloud"` } func (manager *SCloudregionManager) AllowListItems(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) bool { @@ -277,6 +277,7 @@ func (manager *SCloudregionManager) FetchCustomizeColumns( rows[i] = api.CloudregionDetails{ EnabledStatusStandaloneResourceDetails: stdRows[i], SCloudregionUsage: region.getUsage(), + CloudEnv: region.GetCloudEnv(), } } return rows @@ -376,6 +377,7 @@ func (manager *SCloudregionManager) SyncRegions( } else { syncMetadata(ctx, userCred, &commondb[i], commonext[i]) cpr := CloudproviderRegionManager.FetchByIdsOrCreate(cloudProvider.Id, commondb[i].Id) + cpr.setCapabilities(ctx, userCred, commonext[i].GetCapabilities()) cloudProviderRegions = append(cloudProviderRegions, *cpr) localRegions = append(localRegions, commondb[i]) remoteRegions = append(remoteRegions, commonext[i]) @@ -389,6 +391,7 @@ func (manager *SCloudregionManager) SyncRegions( } else { syncMetadata(ctx, userCred, new, added[i]) cpr := CloudproviderRegionManager.FetchByIdsOrCreate(cloudProvider.Id, new.Id) + cpr.setCapabilities(ctx, userCred, added[i].GetCapabilities()) cloudProviderRegions = append(cloudProviderRegions, *cpr) localRegions = append(localRegions, *new) remoteRegions = append(remoteRegions, added[i]) @@ -415,6 +418,9 @@ func (self *SCloudregion) syncRemoveCloudRegion(ctx context.Context, userCred mc cpr := CloudproviderRegionManager.FetchByIds(cloudProvider.Id, self.Id) if cpr != nil { err = cpr.Detach(ctx, userCred) + if err == nil { + err = cpr.removeCapabilities(ctx, userCred) + } } return err @@ -541,16 +547,20 @@ func (manager *SCloudregionManager) InitializeData() error { defRegion.Status = api.CLOUD_REGION_STATUS_INSERVER defRegion.Provider = api.CLOUD_PROVIDER_ONECLOUD err := manager.TableSpec().Insert(&defRegion) - return err + if err != nil { + return errors.Wrap(err, "insert default region") + } + } else { + return errors.Wrap(err, "fetch default region") } - return err - } - if region := obj.(*SCloudregion); region.Provider != api.CLOUD_PROVIDER_ONECLOUD { + } else if region := obj.(*SCloudregion); region.Provider != api.CLOUD_PROVIDER_ONECLOUD { _, err := db.Update(region, func() error { region.Provider = api.CLOUD_PROVIDER_ONECLOUD return nil }) - return err + if err != nil { + return errors.Wrap(err, "update default region provider") + } } return nil } @@ -767,6 +777,11 @@ func (manager *SCloudregionManager) ListItemFilter( q = q.In("environment", query.Environment) } + if len(query.Capability) > 0 { + subq := CloudproviderCapabilityManager.Query("cloudregion_id").In("capability", query.Capability).Distinct().SubQuery() + q = q.In("id", subq) + } + return q, nil } @@ -804,6 +819,7 @@ func (self *SCloudregion) getCloudaccounts() []SCloudaccount { func (self *SCloudregion) GetRegionCloudenvInfo() api.CloudenvResourceInfo { info := api.CloudenvResourceInfo{ + CloudEnv: self.GetCloudEnv(), Provider: self.Provider, Environment: self.Environment, } @@ -871,3 +887,7 @@ func (self *SCloudregion) getMaxDataDiskCount() int { func (manager *SCloudregionManager) FetchDefaultRegion() *SCloudregion { return manager.FetchRegionById(api.DEFAULT_REGION_ID) } + +func (self *SCloudregion) GetCloudEnv() string { + return cloudprovider.GetProviderCloudEnv(self.Provider) +} diff --git a/pkg/multicloud/aliyun/region.go b/pkg/multicloud/aliyun/region.go index afe99aa3c2..c8e571ea0e 100644 --- a/pkg/multicloud/aliyun/region.go +++ b/pkg/multicloud/aliyun/region.go @@ -1123,3 +1123,7 @@ func (self *SRegion) GetIElasticcaches() ([]cloudprovider.ICloudElasticcache, er return icaches, nil } + +func (region *SRegion) GetCapabilities() []string { + return region.client.GetCapabilities() +} diff --git a/pkg/multicloud/aws/region.go b/pkg/multicloud/aws/region.go index 70de88a4bc..c949039fcf 100644 --- a/pkg/multicloud/aws/region.go +++ b/pkg/multicloud/aws/region.go @@ -1091,3 +1091,7 @@ func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreat } return self.GetISecurityGroupById(groupId) } + +func (region *SRegion) GetCapabilities() []string { + return region.client.GetCapabilities() +} diff --git a/pkg/multicloud/azure/region.go b/pkg/multicloud/azure/region.go index 2830cd7dd3..eec9752dbd 100644 --- a/pkg/multicloud/azure/region.go +++ b/pkg/multicloud/azure/region.go @@ -685,3 +685,7 @@ func (region *SRegion) GetIBucketById(name string) (cloudprovider.ICloudBucket, func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) { return region.GetIBucketById(name) } + +func (region *SRegion) GetCapabilities() []string { + return region.client.GetCapabilities() +} diff --git a/pkg/multicloud/ctyun/region.go b/pkg/multicloud/ctyun/region.go index d00fb8f3b9..3aad348f87 100644 --- a/pkg/multicloud/ctyun/region.go +++ b/pkg/multicloud/ctyun/region.go @@ -520,3 +520,7 @@ func (self *SRegion) GetInstanceFlavors() ([]FlavorObj, error) { return ret, nil } + +func (region *SRegion) GetCapabilities() []string { + return region.client.GetCapabilities() +} diff --git a/pkg/multicloud/google/google.go b/pkg/multicloud/google/google.go index e3c8222b8b..3e6069d429 100644 --- a/pkg/multicloud/google/google.go +++ b/pkg/multicloud/google/google.go @@ -133,17 +133,23 @@ func (self *SGoogleClient) fetchRegions() error { regions[i].client = self self.iregions = append(self.iregions, ®ions[i]) } + + objectstoreCapability := []string{ + cloudprovider.CLOUD_CAPABILITY_OBJECTSTORE, + } for _, region := range MultiRegions { _region := SRegion{ - Name: region, - client: self, + Name: region, + client: self, + capabilities: objectstoreCapability, } self.iregions = append(self.iregions, &_region) } for _, region := range DualRegions { _region := SRegion{ - Name: region, - client: self, + Name: region, + client: self, + capabilities: objectstoreCapability, } self.iregions = append(self.iregions, &_region) } diff --git a/pkg/multicloud/google/region.go b/pkg/multicloud/google/region.go index bfdf1d2701..ca1124050f 100644 --- a/pkg/multicloud/google/region.go +++ b/pkg/multicloud/google/region.go @@ -34,6 +34,8 @@ type SRegion struct { multicloud.SRegion client *SGoogleClient + capabilities []string + Description string ID string Kind string @@ -626,3 +628,10 @@ func (region *SRegion) CreateEIP(args *cloudprovider.SEip) (cloudprovider.ICloud } return eip, nil } + +func (region *SRegion) GetCapabilities() []string { + if region.capabilities == nil { + return region.client.GetCapabilities() + } + return region.capabilities +} diff --git a/pkg/multicloud/huawei/region.go b/pkg/multicloud/huawei/region.go index 436cadef99..f01c71fc67 100644 --- a/pkg/multicloud/huawei/region.go +++ b/pkg/multicloud/huawei/region.go @@ -1073,3 +1073,7 @@ func (self *SRegion) GetIElasticcaches() ([]cloudprovider.ICloudElasticcache, er return icaches, nil } + +func (region *SRegion) GetCapabilities() []string { + return region.client.GetCapabilities() +} diff --git a/pkg/multicloud/objectstore/interface.go b/pkg/multicloud/objectstore/interface.go index 3a374d6380..d1814aec15 100644 --- a/pkg/multicloud/objectstore/interface.go +++ b/pkg/multicloud/objectstore/interface.go @@ -40,5 +40,5 @@ type IBucketProvider interface { GetIBucketAcl(name string) (cloudprovider.TBucketACLType, error) SetIBucketAcl(name string, cannedAcl cloudprovider.TBucketACLType) error - GetCapabilities() []string + // GetCapabilities() []string } diff --git a/pkg/multicloud/openstack/region.go b/pkg/multicloud/openstack/region.go index 6e2db336be..8201827f5d 100644 --- a/pkg/multicloud/openstack/region.go +++ b/pkg/multicloud/openstack/region.go @@ -534,3 +534,7 @@ func (region *SRegion) GetISecurityGroupByName(vpcId string, name string) (cloud func (region *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { return region.CreateSecurityGroup(conf.Name, conf.Desc) } + +func (region *SRegion) GetCapabilities() []string { + return region.client.GetCapabilities() +} diff --git a/pkg/multicloud/qcloud/region.go b/pkg/multicloud/qcloud/region.go index 0944387285..e2b7ee9489 100644 --- a/pkg/multicloud/qcloud/region.go +++ b/pkg/multicloud/qcloud/region.go @@ -947,3 +947,7 @@ func (self *SRegion) GetISecurityGroupByName(vpcId string, name string) (cloudpr func (self *SRegion) CreateISecurityGroup(conf *cloudprovider.SecurityGroupCreateInput) (cloudprovider.ICloudSecurityGroup, error) { return self.CreateSecurityGroup(conf.Name, conf.Desc) } + +func (region *SRegion) GetCapabilities() []string { + return region.client.GetCapabilities() +} diff --git a/pkg/multicloud/ucloud/region.go b/pkg/multicloud/ucloud/region.go index bb54536b07..25f586f517 100644 --- a/pkg/multicloud/ucloud/region.go +++ b/pkg/multicloud/ucloud/region.go @@ -751,3 +751,7 @@ func (region *SRegion) GetIBucketById(bucketId string) (cloudprovider.ICloudBuck func (region *SRegion) GetIBucketByName(name string) (cloudprovider.ICloudBucket, error) { return region.GetIBucketByName(name) } + +func (region *SRegion) GetCapabilities() []string { + return region.client.GetCapabilities() +} diff --git a/pkg/multicloud/zstack/region.go b/pkg/multicloud/zstack/region.go index 14547e3fec..0a3aeeee67 100644 --- a/pkg/multicloud/zstack/region.go +++ b/pkg/multicloud/zstack/region.go @@ -401,3 +401,7 @@ func (region *SRegion) SyncSecurityGroup(secgroupId string, vpcId string, name s } return secgroupId, region.syncSecgroupRules(secgroupId, rules) } + +func (region *SRegion) GetCapabilities() []string { + return region.client.GetCapabilities() +}