diff --git a/cmd/climc/shell/capabilities.go b/cmd/climc/shell/capabilities.go index 5e5f156902..5058008911 100644 --- a/cmd/climc/shell/capabilities.go +++ b/cmd/climc/shell/capabilities.go @@ -17,13 +17,20 @@ package shell import ( "yunion.io/x/onecloud/pkg/mcclient" "yunion.io/x/onecloud/pkg/mcclient/modules" + "yunion.io/x/onecloud/pkg/mcclient/options" ) func init() { type CapabilitiesOptions struct { + Domain string `help:"ID or name of domain"` + Scope string `help:"query scope" choices:"system|domain|project"` } R(&CapabilitiesOptions{}, "capabilities", "Show backend capabilities", func(s *mcclient.ClientSession, args *CapabilitiesOptions) error { - result, err := modules.Capabilities.List(s, nil) + query, err := options.StructToParams(args) + if err != nil { + return err + } + result, err := modules.Capabilities.List(s, query) if err != nil { return err } diff --git a/cmd/climc/shell/cloudregions.go b/cmd/climc/shell/cloudregions.go index d0a1324749..859b776229 100644 --- a/cmd/climc/shell/cloudregions.go +++ b/cmd/climc/shell/cloudregions.go @@ -176,6 +176,8 @@ func init() { type CloudregionCapabiltyOptions struct { ID string `help:"ID or name of cloud region to check" json:"-"` Domain string `help:"cloud region domain"` + + ShowEmulated bool `help:"show emulated cloud region"` } R(&CloudregionCapabiltyOptions{}, "cloud-region-capability", "Show region's capacibilities", func(s *mcclient.ClientSession, args *CloudregionCapabiltyOptions) error { query, err := options.StructToParams(args) diff --git a/pkg/compute/models/capabilities.go b/pkg/compute/models/capabilities.go index 344232eb28..ad2e71ac8e 100644 --- a/pkg/compute/models/capabilities.go +++ b/pkg/compute/models/capabilities.go @@ -24,9 +24,12 @@ import ( "yunion.io/x/sqlchemy" api "yunion.io/x/onecloud/pkg/apis/compute" + "yunion.io/x/onecloud/pkg/cloudcommon/consts" "yunion.io/x/onecloud/pkg/cloudcommon/db" + "yunion.io/x/onecloud/pkg/cloudcommon/policy" "yunion.io/x/onecloud/pkg/httperrors" "yunion.io/x/onecloud/pkg/mcclient" + "yunion.io/x/onecloud/pkg/util/rbacutils" ) type SCapabilities struct { @@ -46,6 +49,8 @@ type SCapabilities struct { func GetCapabilities(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, region *SCloudregion, zone *SZone) (SCapabilities, error) { capa := SCapabilities{} + scopeStr := jsonutils.GetAnyString(query, []string{"scope"}) + scope := rbacutils.String2Scope(scopeStr) var domainId string domainStr := jsonutils.GetAnyString(query, []string{"domain", "domain_id", "project_domain", "project_domain_id"}) if len(domainStr) > 0 { @@ -60,6 +65,13 @@ func GetCapabilities(ctx context.Context, userCred mcclient.TokenCredential, que } else { domainId = userCred.GetProjectDomainId() } + if scope == rbacutils.ScopeSystem { + result := policy.PolicyManager.Allow(scope, userCred, consts.GetServiceType(), "capabilities", policy.PolicyActionList) + if result != rbacutils.Allow { + return capa, httperrors.NewForbiddenError("not allow to query system capability") + } + domainId = "" + } capa.Hypervisors = getHypervisors(region, zone, domainId) capa.ResourceTypes = getResourceTypes(region, zone, domainId) capa.StorageTypes = getStorageTypes(region, zone, true, domainId) @@ -104,6 +116,7 @@ func getDomainManagerSubq(domainId string) *sqlchemy.SSubQuery { sqlchemy.IsTrue(accounts.Field("is_public")), )) q = q.Filter(sqlchemy.Equals(accounts.Field("status"), api.CLOUD_PROVIDER_CONNECTED)) + q = q.Filter(sqlchemy.IsTrue(accounts.Field("enabled"))) return q.SubQuery() } diff --git a/pkg/compute/models/cloudaccounts.go b/pkg/compute/models/cloudaccounts.go index 1f4fa0c2e7..e662c42cec 100644 --- a/pkg/compute/models/cloudaccounts.go +++ b/pkg/compute/models/cloudaccounts.go @@ -611,6 +611,7 @@ func (self *SCloudaccount) importSubAccount(ctx context.Context, userCred mcclie ProjectId: t.Id, } } + newCloudprovider.DomainId = ownerId.GetProjectDomainId() newCloudprovider.ProjectId = ownerId.GetProjectId() } diff --git a/pkg/compute/models/cloudproviders.go b/pkg/compute/models/cloudproviders.go index 454d6edf17..601924bd87 100644 --- a/pkg/compute/models/cloudproviders.go +++ b/pkg/compute/models/cloudproviders.go @@ -487,14 +487,24 @@ func (self *SCloudprovider) PerformChangeProject(ctx context.Context, userCred m return nil, nil } + if self.DomainId != tenant.DomainId { + return nil, httperrors.NewForbiddenError("not allow change project across domain") + } + notes := struct { OldProjectId string + OldDomainId string NewProjectId string NewProject string + NewDomainId string + NewDomain string }{ OldProjectId: self.ProjectId, + OldDomainId: self.DomainId, NewProjectId: tenant.Id, NewProject: tenant.Name, + NewDomainId: tenant.DomainId, + NewDomain: tenant.Domain, } err = self.saveProject(userCred, tenant.DomainId, tenant.Id) diff --git a/pkg/mcclient/modules/mod_capabilities.go b/pkg/mcclient/modules/mod_capabilities.go index f1dded5043..3f4d190e0f 100644 --- a/pkg/mcclient/modules/mod_capabilities.go +++ b/pkg/mcclient/modules/mod_capabilities.go @@ -25,7 +25,14 @@ type SCapabilityManager struct { } func (this *SCapabilityManager) List(s *mcclient.ClientSession, params jsonutils.JSONObject) (*ListResult, error) { - body, err := this._get(s, "/capabilities", "") + url := "/capabilities" + if params != nil { + qs := params.QueryString() + if len(qs) > 0 { + url += "?" + qs + } + } + body, err := this._get(s, url, "") if err != nil { return nil, err } diff --git a/pkg/mcclient/modules/mod_projects.go b/pkg/mcclient/modules/mod_projects.go index 0ce98e18e7..889d9de709 100644 --- a/pkg/mcclient/modules/mod_projects.go +++ b/pkg/mcclient/modules/mod_projects.go @@ -50,11 +50,16 @@ func (this *ProjectManagerV3) _join(s *mcclient.ClientSession, pid, uid, rid, re return nil } -func (this *ProjectManagerV3) _leave(s *mcclient.ClientSession, pid string, uid string, rid string, ch chan int) error { +func (this *ProjectManagerV3) _leave(s *mcclient.ClientSession, pid string, resource string, uid string, rid string, ch chan int) error { defer func() { ch <- 1 }() - _, err := RolesV3.DeleteInContexts(s, rid, nil, []ManagerContext{{&Projects, pid}, {&UsersV3, uid}}) + var err error + if resource == "users" { + _, err = RolesV3.DeleteInContexts(s, rid, nil, []ManagerContext{{&Projects, pid}, {&UsersV3, uid}}) + } else if resource == "groups" { + _, err = RolesV3.DeleteInContexts(s, rid, nil, []ManagerContext{{&Projects, pid}, {&Groups, uid}}) + } if err != nil { return err } @@ -79,6 +84,12 @@ func (this *ProjectManagerV3) DoLeaveProject(s *mcclient.ClientSession, params j return ret, e } + resource, _ := params.GetString("resource") + + if len(resource) == 0 { + resource = "users" + } + chs := make([]chan int, len(pids)) for i, pid := range pids { @@ -92,7 +103,7 @@ func (this *ProjectManagerV3) DoLeaveProject(s *mcclient.ClientSession, params j } chs[i] = make(chan int) - go this._leave(s, _pid, uid, _rid, chs[i]) + go this._leave(s, _pid, resource, uid, _rid, chs[i]) } for _, ch := range chs {