fix: misc bugs about resource sharing

This commit is contained in:
Qiu Jian
2020-04-14 22:23:23 +08:00
parent 9ff7f481b7
commit 021ef662bb
13 changed files with 156 additions and 39 deletions
+5
View File
@@ -85,6 +85,8 @@ func init() {
NAME string `help:"Role name"`
Domain string `help:"Domain"`
Desc string `help:"Description"`
PublicScope string `help:"public scope" choices:"none|system"`
}
R(&RoleCreateOptions{}, "role-create", "Create a new role", func(s *mcclient.ClientSession, args *RoleCreateOptions) error {
params := jsonutils.NewDict()
@@ -99,6 +101,9 @@ func init() {
if len(args.Desc) > 0 {
params.Add(jsonutils.NewString(args.Desc), "description")
}
if len(args.PublicScope) > 0 {
params.Add(jsonutils.NewString(args.PublicScope), "public_scope")
}
role, err := modules.RolesV3.Create(s, params)
if err != nil {
return err
+5 -1
View File
@@ -110,6 +110,10 @@ func (manager *SInfrasResourceBaseManager) ValidateCreateData(
if err != nil {
return input, errors.Wrap(err, "manager.SDomainLevelResourceBaseManager.ValidateCreateData")
}
input.SharableResourceBaseCreateInput, err = SharableManagerValidateCreateData(manager.GetIInfrasModelManager(), ctx, userCred, ownerId, query, input.SharableResourceBaseCreateInput)
if err != nil {
return input, errors.Wrap(err, "SharableManagerValidateCreateData")
}
return input, nil
}
@@ -204,7 +208,7 @@ func (model *SInfrasResourceBase) PerformChangeOwner(
}
func (model *SInfrasResourceBase) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
model.SSharableBaseResource.CustomizeCreate(ctx, userCred, ownerId, query, data)
SharableModelCustomizeCreate(model.GetIInfrasModel(), ctx, userCred, ownerId, query, data)
return model.SDomainLevelResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
}
+4
View File
@@ -24,6 +24,10 @@ type IOwnerResourceBaseModel interface {
GetChangeOwnerCandidateDomainIds() []string
}
type IManagedResourceBase interface {
IsManaged() bool
}
func IOwnerResourceBaseModelGetChangeOwnerCandidateDomains(model IOwnerResourceBaseModel) (apis.ChangeOwnerCandidateDomainsOutput, error) {
output := apis.ChangeOwnerCandidateDomainsOutput{}
candidateIds := model.GetChangeOwnerCandidateDomainIds()
+84 -12
View File
@@ -144,6 +144,54 @@ func (manager *SSharableBaseResourceManager) FetchCustomizeColumns(
return rows
}
func SharableManagerValidateCreateData(
manager IStandaloneModelManager,
ctx context.Context,
userCred mcclient.TokenCredential,
ownerId mcclient.IIdentityProvider,
query jsonutils.JSONObject,
input apis.SharableResourceBaseCreateInput,
) (apis.SharableResourceBaseCreateInput, error) {
if len(input.PublicScope) == 0 {
return input, nil
}
resScope := manager.ResourceScope()
reqScope := resScope
isPublic := true
switch resScope {
case rbacutils.ScopeProject:
if input.PublicScope == string(rbacutils.ScopeSystem) {
input.IsPublic = &isPublic
reqScope = rbacutils.ScopeSystem
} else if input.PublicScope == string(rbacutils.ScopeDomain) {
input.IsPublic = &isPublic
reqScope = rbacutils.ScopeDomain
} else if input.IsPublic != nil && *input.IsPublic {
return input, errors.Wrap(httperrors.ErrNotSupported, "domain level resource can be shared to system ONLY")
} else {
input.IsPublic = nil
input.PublicScope = string(rbacutils.ScopeNone)
}
case rbacutils.ScopeDomain:
if input.PublicScope == string(rbacutils.ScopeSystem) {
input.IsPublic = &isPublic
reqScope = rbacutils.ScopeSystem
} else if input.IsPublic != nil && *input.IsPublic {
return input, errors.Wrap(httperrors.ErrNotSupported, "domain level resource can be shared to system ONLY")
} else {
input.IsPublic = nil
input.PublicScope = string(rbacutils.ScopeNone)
}
default:
return input, errors.Wrap(httperrors.ErrInputParameter, "the resource is not sharable")
}
allowScope := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), manager.KeywordPlural(), policy.PolicyActionPerform, "public")
if reqScope.HigherThan(allowScope) {
return input, errors.Wrapf(httperrors.ErrNotSufficientPrivilege, "require %s allow %s", reqScope, allowScope)
}
return input, nil
}
func SharableManagerFilterByOwner(manager IStandaloneModelManager, q *sqlchemy.SQuery, owner mcclient.IIdentityProvider, scope rbacutils.TRbacScope) *sqlchemy.SQuery {
if owner != nil {
resScope := manager.ResourceScope()
@@ -215,7 +263,7 @@ type ISharableBaseModel interface {
}
type ISharableBase interface {
SetShare(pub bool, scoe rbacutils.TRbacScope)
SetShare(scoe rbacutils.TRbacScope)
GetIsPublic() bool
GetPublicScope() rbacutils.TRbacScope
GetSharableTargetDomainIds() []string
@@ -310,9 +358,14 @@ func SharableModelIsSharable(model ISharableBaseModel, reqUsrId mcclient.IIdenti
return false
}
func (m *SSharableBaseResource) SetShare(pub bool, scope rbacutils.TRbacScope) {
func (m *SSharableBaseResource) SetShare(scope rbacutils.TRbacScope) {
pub := false
if scope != rbacutils.ScopeNone {
pub = true
}
m.IsPublic = pub
m.PublicScope = string(scope)
m.PublicSrc = string(apis.OWNER_SOURCE_LOCAL)
}
func (m SSharableBaseResource) GetIsPublic() bool {
@@ -355,13 +408,16 @@ func SharablePerformPublic(model ISharableBaseModel, ctx context.Context, userCr
} else if len(requireIds) > 1 {
return errors.Wrap(httperrors.ErrForbidden, "require to be shared to other domain")
}
if len(input.SharedProjects) == 0 {
return errors.Wrap(httperrors.ErrEmptyRequest, "empty shared target project list")
}
// if len(input.SharedProjects) == 0 {
// return errors.Wrap(httperrors.ErrEmptyRequest, "empty shared target project list")
// }
shareResult.SharedProjects, err = SharedResourceManager.shareToTarget(ctx, userCred, model, SharedTargetProject, input.SharedProjects, nil, nil)
if err != nil {
return errors.Wrap(err, "shareToTarget")
}
if len(shareResult.SharedProjects) == 0 {
targetScope = rbacutils.ScopeNone
}
case rbacutils.ScopeDomain:
if len(requireIds) == 0 {
return errors.Wrap(httperrors.ErrForbidden, "require to be shared to system")
@@ -374,6 +430,9 @@ func SharablePerformPublic(model ISharableBaseModel, ctx context.Context, userCr
if err != nil {
return errors.Wrap(err, "shareToTarget add domains")
}
if len(shareResult.SharedDomains) == 0 && resourceScope == rbacutils.ScopeDomain {
targetScope = rbacutils.ScopeNone
}
case rbacutils.ScopeSystem:
if len(candidateIds) > 0 {
return errors.Wrapf(httperrors.ErrForbidden, "sharing is limited to domains %s", jsonutils.Marshal(candidateIds))
@@ -394,7 +453,7 @@ func SharablePerformPublic(model ISharableBaseModel, ctx context.Context, userCr
}
_, err = Update(model, func() error {
model.SetShare(true, targetScope)
model.SetShare(targetScope)
return nil
})
@@ -402,7 +461,9 @@ func SharablePerformPublic(model ISharableBaseModel, ctx context.Context, userCr
return errors.Wrap(err, "Update")
}
OpsLog.LogEvent(model, ACT_PUBLIC, shareResult, userCred)
if targetScope != rbacutils.ScopeNone {
OpsLog.LogEvent(model, ACT_PUBLIC, shareResult, userCred)
}
model.GetIStandaloneModel().ClearSchedDescCache()
return nil
@@ -432,7 +493,7 @@ func SharablePerformPrivate(model ISharableBaseModel, ctx context.Context, userC
}
diff, err := Update(model, func() error {
model.SetShare(false, rbacutils.ScopeNone)
model.SetShare(rbacutils.ScopeNone)
return nil
})
@@ -475,9 +536,20 @@ func SharableModelIsShared(model ISharableBaseModel) bool {
return false
}
func (base *SSharableBaseResource) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
base.IsPublic = false
base.PublicScope = string(rbacutils.ScopeNone)
base.PublicSrc = string(apis.OWNER_SOURCE_LOCAL)
func SharableModelCustomizeCreate(model ISharableBaseModel, ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
if !data.Contains("public_scope") {
resScope := model.GetModelManager().ResourceScope()
isManaged := false
if managedModel, ok := model.(IManagedResourceBase); ok {
isManaged = managedModel.IsManaged()
}
if !isManaged && IsAdminAllowPerform(userCred, model, "public") && ownerId.GetProjectDomainId() == userCred.GetProjectDomainId() {
model.SetShare(rbacutils.ScopeSystem)
} else if !isManaged && IsDomainAllowPerform(userCred, model, "public") && resScope == rbacutils.ScopeProject && ownerId.GetProjectId() == userCred.GetProjectId() {
model.SetShare(rbacutils.ScopeDomain)
} else {
model.SetShare(rbacutils.ScopeNone)
}
}
return nil
}
+5 -1
View File
@@ -99,6 +99,10 @@ func (manager *SSharableVirtualResourceBaseManager) ValidateCreateData(ctx conte
if err != nil {
return input, errors.Wrap(err, "manager.VirtualResourceBaseManager.ValidateCreateData")
}
input.SharableResourceBaseCreateInput, err = SharableManagerValidateCreateData(manager.GetISharableVirtualModelManager(), ctx, userCred, ownerId, query, input.SharableResourceBaseCreateInput)
if err != nil {
return input, errors.Wrap(err, "SharableManagerValidateCreateData")
}
return input, nil
}
@@ -197,7 +201,7 @@ func (model *SSharableVirtualResourceBase) PerformChangeOwner(
}
func (model *SSharableVirtualResourceBase) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
model.SSharableBaseResource.CustomizeCreate(ctx, userCred, ownerId, query, data)
SharableModelCustomizeCreate(model.GetISharableVirtualModel(), ctx, userCred, ownerId, query, data)
return model.SVirtualResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
}
+6 -2
View File
@@ -153,7 +153,9 @@ func (manager *SSharedResourceManager) shareToTarget(
return nil, errors.Wrap(httperrors.ErrBadRequest, "can't shared project to other domain")
}
if tenant.GetId() == modelOwnerId.GetProjectId() {
return nil, errors.Wrap(httperrors.ErrBadRequest, "can't share to self project")
// ignore self project
continue
// return nil, errors.Wrap(httperrors.ErrBadRequest, "can't share to self project")
}
newIds = stringutils2.Append(newIds, tenant.GetId())
case SharedTargetDomain:
@@ -162,7 +164,9 @@ func (manager *SSharedResourceManager) shareToTarget(
return nil, errors.Wrapf(err, "fetch domain %s error", targetIds[i])
}
if domain.GetId() == modelOwnerId.GetProjectDomainId() {
return nil, errors.Wrapf(httperrors.ErrBadRequest, "can't share to self domain %s", modelOwnerId.GetProjectDomainId())
// ignore self domain
continue
// return nil, errors.Wrapf(httperrors.ErrBadRequest, "can't share to self domain %s", modelOwnerId.GetProjectDomainId())
}
if len(candidateIds) > 0 && !utils.IsInStringArray(domain.GetId(), candidateIds) {
return nil, errors.Wrapf(httperrors.ErrForbidden, "share target domain %s not in candidate list %s", domain.GetId(), candidateIds)
+2 -4
View File
@@ -4920,8 +4920,6 @@ func (self *SHost) StartSyncConfig(ctx context.Context, userCred mcclient.TokenC
func (model *SHost) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
// make host default public
model.IsPublic = true
model.PublicScope = string(rbacutils.ScopeSystem)
return model.SEnabledStatusInfrasResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
}
@@ -4978,7 +4976,7 @@ func (host *SHost) PerformPublic(ctx context.Context, userCred mcclient.TokenCre
// perform public for all connected local storage
storages := host.GetAttachedLocalStorages()
for i := range storages {
_, err := storages[i].PerformPublic(ctx, userCred, query, input)
_, err := storages[i].performPublicInternal(ctx, userCred, query, input)
if err != nil {
return nil, errors.Wrap(err, "storage.PerformPublic")
}
@@ -4990,7 +4988,7 @@ func (host *SHost) PerformPrivate(ctx context.Context, userCred mcclient.TokenCr
// perform private for all connected local storage
storages := host.GetAttachedLocalStorages()
for i := range storages {
_, err := storages[i].PerformPrivate(ctx, userCred, query, input)
_, err := storages[i].performPrivateInternal(ctx, userCred, query, input)
if err != nil {
return nil, errors.Wrap(err, "storage.PerformPrivate")
}
+19 -8
View File
@@ -1550,17 +1550,28 @@ func isOverlapNetworks(nets []SNetwork, startIp netutils.IPV4Addr, endIp netutil
return false
}
func (self *SNetwork) IsManaged() bool {
wire := self.GetWire()
if wire == nil {
return false
}
return wire.IsManaged()
}
func (self *SNetwork) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
if db.IsDomainAllowCreate(userCred, self.GetModelManager()) && ownerId.GetProjectId() == userCred.GetProjectId() && self.ServerType == api.NETWORK_TYPE_GUEST {
self.IsPublic = true
if options.Options.NonDefaultDomainProjects {
self.PublicScope = string(rbacutils.ScopeDomain)
if !data.Contains("public_scope") {
if self.ServerType == api.NETWORK_TYPE_GUEST && !self.IsManaged() {
if db.IsAdminAllowPerform(userCred, self, "public") && ownerId.GetProjectDomainId() == userCred.GetProjectDomainId() {
self.SetShare(rbacutils.ScopeSystem)
} else if db.IsDomainAllowPerform(userCred, self, "public") && ownerId.GetProjectId() == userCred.GetProjectId() {
self.SetShare(rbacutils.ScopeDomain)
} else {
self.SetShare(rbacutils.ScopeNone)
}
} else {
self.PublicScope = string(rbacutils.ScopeSystem)
self.SetShare(rbacutils.ScopeNone)
}
} else {
self.IsPublic = false
self.PublicScope = string(rbacutils.ScopeNone)
data.(*jsonutils.JSONDict).Set("public_scope", jsonutils.NewString(self.PublicScope))
}
return self.SSharableVirtualResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
}
+8 -3
View File
@@ -233,9 +233,6 @@ func (manager *SStorageManager) ValidateCreateData(
func (self *SStorage) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
self.SetEnabled(true)
self.SetStatus(userCred, api.STORAGE_OFFLINE, "CustomizeCreate")
// make storage shared to system by default
self.IsPublic = true
self.PublicScope = string(rbacutils.ScopeSystem)
return self.SEnabledStatusInfrasResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
}
@@ -1465,6 +1462,10 @@ func (storage *SStorage) PerformPublic(ctx context.Context, userCred mcclient.To
return nil, errors.Wrap(httperrors.ErrForbidden, "not allow to perform public for local storage")
}
}
return storage.performPublicInternal(ctx, userCred, query, input)
}
func (storage *SStorage) performPublicInternal(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformPublicInput) (jsonutils.JSONObject, error) {
return storage.SEnabledStatusInfrasResourceBase.PerformPublic(ctx, userCred, query, input)
}
@@ -1476,5 +1477,9 @@ func (storage *SStorage) PerformPrivate(ctx context.Context, userCred mcclient.T
return nil, errors.Wrap(httperrors.ErrForbidden, "not allow to perform private for local storage")
}
}
return storage.performPrivateInternal(ctx, userCred, query, input)
}
func (storage *SStorage) performPrivateInternal(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, input apis.PerformPrivateInput) (jsonutils.JSONObject, error) {
return storage.SEnabledStatusInfrasResourceBase.PerformPrivate(ctx, userCred, query, input)
}
-3
View File
@@ -107,9 +107,6 @@ func (self *SVpc) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCr
if len(idstr) > 0 {
self.Id = idstr
}
// make vpc default to share to system
self.IsPublic = true
self.PublicScope = string(rbacutils.ScopeSystem)
return self.SEnabledStatusInfrasResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
}
+8 -3
View File
@@ -992,10 +992,15 @@ func (man *SWireManager) removeWiresByVpc(ctx context.Context, userCred mcclient
return errors.NewAggregate(errs)
}
func (self *SWire) IsManaged() bool {
vpc := self.GetVpc()
if vpc == nil {
return false
}
return vpc.IsManaged()
}
func (model *SWire) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
// make host default public
model.IsPublic = true
model.PublicScope = string(rbacutils.ScopeSystem)
return model.SInfrasResourceBase.CustomizeCreate(ctx, userCred, ownerId, query, data)
}
+5 -1
View File
@@ -127,6 +127,10 @@ func (manager *SPolicyManager) ValidateCreateData(
if err != nil {
return input, errors.Wrap(err, "SEnabledIdentityBaseResourceManager.ValidateCreateData")
}
input.SharableResourceBaseCreateInput, err = db.SharableManagerValidateCreateData(manager, ctx, userCred, ownerId, query, input.SharableResourceBaseCreateInput)
if err != nil {
return input, errors.Wrap(err, "SharableManagerValidateCreateData")
}
quota := &SIdentityQuota{
SBaseDomainQuotaKeys: quotas.SBaseDomainQuotaKeys{DomainId: ownerId.GetProjectDomainId()},
@@ -222,7 +226,7 @@ func (policy *SPolicy) PerformPrivate(ctx context.Context, userCred mcclient.Tok
}
func (policy *SPolicy) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
policy.SSharableBaseResource.CustomizeCreate(ctx, userCred, ownerId, query, data)
db.SharableModelCustomizeCreate(policy, ctx, userCred, ownerId, query, data)
return policy.SEnabledIdentityBaseResource.CustomizeCreate(ctx, userCred, ownerId, query, data)
}
+5 -1
View File
@@ -446,7 +446,7 @@ func (role *SRole) PerformPrivate(ctx context.Context, userCred mcclient.TokenCr
}
func (role *SRole) CustomizeCreate(ctx context.Context, userCred mcclient.TokenCredential, ownerId mcclient.IIdentityProvider, query jsonutils.JSONObject, data jsonutils.JSONObject) error {
role.SSharableBaseResource.CustomizeCreate(ctx, userCred, ownerId, query, data)
db.SharableModelCustomizeCreate(role, ctx, userCred, ownerId, query, data)
return role.SIdentityBaseResource.CustomizeCreate(ctx, userCred, ownerId, query, data)
}
@@ -471,6 +471,10 @@ func (manager *SRoleManager) ValidateCreateData(
if err != nil {
return input, errors.Wrap(err, "SIdentityBaseResourceManager.ValidateCreateData")
}
input.SharableResourceBaseCreateInput, err = db.SharableManagerValidateCreateData(manager, ctx, userCred, ownerId, query, input.SharableResourceBaseCreateInput)
if err != nil {
return input, errors.Wrap(err, "SharableManagerValidateCreateData")
}
quota := &SIdentityQuota{
SBaseDomainQuotaKeys: quotas.SBaseDomainQuotaKeys{DomainId: ownerId.GetProjectDomainId()},