Merge pull request #1224 from wanyaoqi/feature/wyq/shared-project

feature: shared project resource
This commit is contained in:
yunion-ci-robot
2019-06-16 14:30:53 +08:00
committed by GitHub
9 changed files with 160 additions and 25 deletions
+1
View File
@@ -264,6 +264,7 @@ type ISharableVirtualModel interface {
IVirtualModel
GetISharableVirtualModel() ISharableVirtualModel
GetSharedProjects() []string
}
type IAdminSharableVirtualModelManager interface {
+1 -1
View File
@@ -100,5 +100,5 @@ func (model *SResourceBase) MarkDelete() error {
}
func (model *SResourceBase) Delete(ctx context.Context, userCred mcclient.TokenCredential) error {
return DeleteModel(ctx, userCred, model)
return DeleteModel(ctx, userCred, model.GetIResourceModel())
}
+120 -18
View File
@@ -16,8 +16,10 @@ package db
import (
"context"
"database/sql"
"yunion.io/x/jsonutils"
"yunion.io/x/log"
"yunion.io/x/sqlchemy"
"yunion.io/x/onecloud/pkg/cloudcommon/consts"
@@ -50,9 +52,12 @@ func (manager *SSharableVirtualResourceBaseManager) FilterByOwner(q *sqlchemy.SQ
if owner != nil {
switch scope {
case rbacutils.ScopeProject:
if len(owner.GetProjectId()) > 0 {
ownerProjectid := owner.GetProjectId()
if len(ownerProjectid) > 0 {
rq := SharedResourceManager.Query().SubQuery()
q.LeftJoin(rq, sqlchemy.Equals(q.Field("id"), rq.Field("resource_id")))
q = q.Filter(sqlchemy.OR(
sqlchemy.Equals(q.Field("tenant_id"), owner.GetProjectId()),
sqlchemy.Equals(q.Field("tenant_id"), ownerProjectid),
sqlchemy.AND(
sqlchemy.IsTrue(q.Field("is_public")),
sqlchemy.Equals(q.Field("public_scope"), rbacutils.ScopeSystem),
@@ -62,6 +67,11 @@ func (manager *SSharableVirtualResourceBaseManager) FilterByOwner(q *sqlchemy.SQ
sqlchemy.Equals(q.Field("public_scope"), rbacutils.ScopeDomain),
sqlchemy.Equals(q.Field("domain_id"), owner.GetProjectDomainId()),
),
sqlchemy.AND(
sqlchemy.Equals(rq.Field("resource_type"), manager.Keyword()),
sqlchemy.Equals(rq.Field("target_project_id"), ownerProjectid),
sqlchemy.Equals(q.Field("tenant_id"), rq.Field("owner_project_id")),
),
))
}
case rbacutils.ScopeDomain:
@@ -106,22 +116,64 @@ func (model *SSharableVirtualResourceBase) PerformPublic(ctx context.Context, us
if !model.IsPublic {
targetScopeStr, _ := data.GetString("scope")
targetScope := rbacutils.String2ScopeDefault(targetScopeStr, rbacutils.ScopeSystem)
allowScope := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), model.GetModelManager().KeywordPlural(), policy.PolicyActionPerform, "public")
if targetScope.HigherThan(allowScope) {
return nil, httperrors.NewForbiddenError("not enough privilege")
if targetScope == rbacutils.ScopeProject {
if sharedWithProject, err := data.GetString("shared_with"); err == nil {
tenant, err := TenantCacheManager.FetchTenantByIdOrName(ctx, sharedWithProject)
if err != nil {
return nil, httperrors.NewInternalServerError("fetch tenant error %s", err)
}
if tenant.DomainId != model.DomainId {
return nil, httperrors.NewBadRequestError("can't shared project to other domain")
}
sharedResource := new(SSharedResource)
err = SharedResourceManager.Query().
Equals("resource_type", model.GetModelManager().Keyword()).
Equals("resource_id", model.Id).Equals("owner_project_id", model.ProjectId).
Equals("target_project_id", tenant.GetId()).First(sharedResource)
if err != nil {
if err != sql.ErrNoRows {
return nil, httperrors.NewInternalServerError("query resource failed %s", err)
} else {
sharedResource.ResourceType = model.GetModelManager().Keyword()
sharedResource.ResourceId = model.Id
sharedResource.OwnerProjectId = model.ProjectId
sharedResource.TargetProjectId = tenant.GetId()
if insetErr := SharedResourceManager.TableSpec().Insert(sharedResource); insetErr != nil {
return nil, httperrors.NewInternalServerError("Insert shared resource failed %s", insetErr)
}
diff, err := Update(model, func() error {
model.PublicScope = string(targetScope)
return nil
})
if err == nil {
OpsLog.LogEvent(model, ACT_UPDATE, diff, userCred)
}
return nil, err
}
} else {
return nil, httperrors.NewBadRequestError("Resource has been shared to %s", tenant.GetName())
}
} else {
return nil, httperrors.NewMissingParameterError("shared_with")
}
} else {
allowScope := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), model.GetModelManager().KeywordPlural(), policy.PolicyActionPerform, "public")
if targetScope.HigherThan(allowScope) {
return nil, httperrors.NewForbiddenError("not enough privilege")
}
if targetScope != rbacutils.ScopeSystem && targetScope != rbacutils.ScopeDomain {
return nil, httperrors.NewInputParameterError("invalid scope %s", targetScope)
}
diff, err := Update(model, func() error {
model.IsPublic = true
model.PublicScope = string(targetScope)
return nil
})
if err == nil {
OpsLog.LogEvent(model, ACT_UPDATE, diff, userCred)
}
return nil, err
}
if targetScope != rbacutils.ScopeSystem && targetScope != rbacutils.ScopeDomain {
return nil, httperrors.NewInputParameterError("invalid scope %s", targetScope)
}
diff, err := Update(model, func() error {
model.IsPublic = true
model.PublicScope = string(targetScope)
return nil
})
if err == nil {
OpsLog.LogEvent(model, ACT_UPDATE, diff, userCred)
}
return nil, err
}
return nil, nil
}
@@ -131,6 +183,7 @@ func (model *SSharableVirtualResourceBase) AllowPerformPrivate(ctx context.Conte
}
func (model *SSharableVirtualResourceBase) PerformPrivate(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, data jsonutils.JSONObject) (jsonutils.JSONObject, error) {
if model.IsPublic {
allowScope := policy.PolicyManager.AllowScope(userCred, consts.GetServiceType(), model.GetModelManager().KeywordPlural(), policy.PolicyActionPerform, "private")
requireScope := rbacutils.String2ScopeDefault(model.PublicScope, rbacutils.ScopeSystem)
@@ -138,13 +191,31 @@ func (model *SSharableVirtualResourceBase) PerformPrivate(ctx context.Context, u
return nil, httperrors.NewForbiddenError("not enough privileges: allow %s require %s", allowScope, requireScope)
}
diff, err := Update(model, func() error {
model.PublicScope = string(rbacutils.ScopeProject)
model.IsPublic = false
return nil
})
if err == nil {
OpsLog.LogEvent(model, ACT_UPDATE, diff, userCred)
} else {
return nil, httperrors.NewInternalServerError("Update shared resource error: %s", err)
}
return nil, err
}
var errStr string
srs := make([]SSharedResource, 0)
err := SharedResourceManager.Query().Equals("owner_project_id", model.ProjectId).All(&srs)
if err != nil {
log.Errorln(err)
}
for i := 0; i < len(srs); i++ {
srs[i].SetModelManager(SharedResourceManager, &srs[i])
if err := srs[i].Delete(ctx, userCred); err != nil {
errStr += err.Error()
}
}
if len(errStr) > 0 {
return nil, httperrors.NewInternalServerError("Update shared resource error: %s", errStr)
}
return nil, nil
}
@@ -152,3 +223,34 @@ func (model *SSharableVirtualResourceBase) PerformPrivate(ctx context.Context, u
func (model *SSharableVirtualResourceBase) GetISharableVirtualModel() ISharableVirtualModel {
return model.GetVirtualObject().(ISharableVirtualModel)
}
func (model *SSharableVirtualResourceBase) GetSharedProjects() []string {
sharedResources := make([]SSharedResource, 0)
res := make([]string, 0)
SharedResourceManager.Query().Equals("resource_type", model.GetModelManager().Keyword()).Equals("resource_id", model.GetId()).All(&sharedResources)
for i := 0; i < len(sharedResources); i++ {
res = append(res, sharedResources[i].TargetProjectId)
}
return res
}
func (model *SSharableVirtualResourceBase) getMoreDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject, extra *jsonutils.JSONDict) *jsonutils.JSONDict {
projects := model.GetSharedProjects()
if len(projects) > 0 {
extra.Set("shared_projects", jsonutils.NewStringArray(projects))
}
return extra
}
func (model *SSharableVirtualResourceBase) GetCustomizeColumns(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) *jsonutils.JSONDict {
extra := model.SVirtualResourceBase.GetCustomizeColumns(ctx, userCred, query)
return model.getMoreDetails(ctx, userCred, query, extra)
}
func (model *SSharableVirtualResourceBase) GetExtraDetails(ctx context.Context, userCred mcclient.TokenCredential, query jsonutils.JSONObject) (*jsonutils.JSONDict, error) {
extra, err := model.SVirtualResourceBase.GetExtraDetails(ctx, userCred, query)
if err != nil {
return nil, err
}
return model.getMoreDetails(ctx, userCred, query, extra), nil
}
+30
View File
@@ -0,0 +1,30 @@
package db
// sharing resoure between project
type SSharedResource struct {
SResourceBase
Id int64 `primary:"true" auto_increment:"true" list:"user"`
ResourceType string `width:"32" charset:"ascii" nullable:"false" list:"user"`
ResourceId string `width:"128" charset:"ascii" nullable:"false" index:"true" list:"user"`
OwnerProjectId string `width:"128" charset:"ascii" nullable:"false" index:"true" list:"user"`
TargetProjectId string `width:"128" charset:"ascii" nullable:"false" index:"true" list:"user"`
}
type SSharedResourceManager struct {
SResourceBaseManager
}
var SharedResourceManager *SSharedResourceManager
func init() {
SharedResourceManager = &SSharedResourceManager{
SResourceBaseManager: NewResourceBaseManager(
SSharedResource{},
"shared_resources_tbl",
"shared_resource",
"shared_resources",
),
}
}
+2 -1
View File
@@ -755,7 +755,8 @@ func parseNetworkInfo(userCred mcclient.TokenCredential, info *api.NetworkConfig
}
}
net := netObj.(*SNetwork)
if net.IsOwner(userCred) || net.IsPublic || db.IsAdminAllowGet(userCred, net) {
if net.IsOwner(userCred) || net.IsPublic || db.IsAdminAllowGet(userCred, net) ||
utils.IsInStringArray(userCred.GetProjectId(), net.GetSharedProjects()) {
info.Network = netObj.GetId()
} else {
return nil, httperrors.NewForbiddenError("no allow to access network %s", info.Network)
+1
View File
@@ -47,6 +47,7 @@ func InitHandlers(app *appsrv.Application) {
taskman.TaskObjectManager,
db.UserCacheManager,
db.TenantCacheManager,
db.SharedResourceManager,
models.GuestcdromManager,
models.NetInterfaceManager,
models.VCenterManager,
@@ -99,7 +99,7 @@ func (p *NetworkSchedtagPredicate) IsResourceFitInput(u *core.Unit, _ core.Candi
if network.IsPublic {
return fmt.Errorf("Network %s is public", network.Name)
}
if network.ProjectId != schedData.Project {
if network.ProjectId != schedData.Project && utils.IsInStringArray(schedData.Project, network.GetSharedProjects()) {
return fmt.Errorf("Network project %s not owner by %s", network.ProjectId, schedData.Project)
}
} else {
+2 -2
View File
@@ -140,11 +140,11 @@ func (network *SNetwork) GetIpMask() int8 {
}
func (network *SNetwork) GetIsPublic() bool {
return true
return false
}
func (network *SNetwork) GetPublicScope() rbacutils.TRbacScope {
return rbacutils.ScopeDomain
return rbacutils.ScopeProject
}
func (network *SNetwork) GetServerType() string {
+2 -2
View File
@@ -190,11 +190,11 @@ func (network *SNetwork) GetIpMask() int8 {
func (network *SNetwork) GetIsPublic() bool {
// return network.IsDefault
return true
return false
}
func (self *SNetwork) GetPublicScope() rbacutils.TRbacScope {
return rbacutils.ScopeDomain
return rbacutils.ScopeProject
}
func (network *SNetwork) GetServerType() string {