fix: recode sync public_src of cloud resources

This commit is contained in:
Qiu Jian
2020-05-08 01:06:31 +08:00
parent ffd8ab638a
commit bea90b4b19
6 changed files with 435 additions and 70 deletions
+4 -3
View File
@@ -15,6 +15,7 @@
package compute
import (
"yunion.io/x/onecloud/pkg/apis"
"yunion.io/x/onecloud/pkg/cloudprovider"
)
@@ -103,9 +104,9 @@ const (
)
const (
CLOUD_ACCOUNT_SHARE_MODE_ACCOUNT_DOMAIN = "account_domain"
CLOUD_ACCOUNT_SHARE_MODE_SYSTEM = "system"
CLOUD_ACCOUNT_SHARE_MODE_PROVIDER_DOMAIN = "provider_domain"
CLOUD_ACCOUNT_SHARE_MODE_ACCOUNT_DOMAIN = apis.CLOUD_ACCOUNT_SHARE_MODE_ACCOUNT_DOMAIN
CLOUD_ACCOUNT_SHARE_MODE_SYSTEM = apis.CLOUD_ACCOUNT_SHARE_MODE_SYSTEM
CLOUD_ACCOUNT_SHARE_MODE_PROVIDER_DOMAIN = apis.CLOUD_ACCOUNT_SHARE_MODE_PROVIDER_DOMAIN
)
var (
+146 -1
View File
@@ -14,7 +14,16 @@
package apis
import "yunion.io/x/onecloud/pkg/util/rbacutils"
import (
"yunion.io/x/onecloud/pkg/util/rbacutils"
"yunion.io/x/onecloud/pkg/util/stringutils2"
)
const (
CLOUD_ACCOUNT_SHARE_MODE_ACCOUNT_DOMAIN = "account_domain"
CLOUD_ACCOUNT_SHARE_MODE_SYSTEM = "system"
CLOUD_ACCOUNT_SHARE_MODE_PROVIDER_DOMAIN = "provider_domain"
)
type SAccountShareInfo struct {
IsPublic bool
@@ -22,3 +31,139 @@ type SAccountShareInfo struct {
ShareMode string
SharedDomains []string
}
type SShareInfo struct {
IsPublic bool
PublicScope rbacutils.TRbacScope
SharedDomains []string
SharedProjects []string
}
func (i SAccountShareInfo) GetProjectShareInfo() SShareInfo {
ret := SShareInfo{}
switch i.ShareMode {
case CLOUD_ACCOUNT_SHARE_MODE_ACCOUNT_DOMAIN:
ret.IsPublic = true
ret.PublicScope = rbacutils.ScopeDomain
case CLOUD_ACCOUNT_SHARE_MODE_PROVIDER_DOMAIN:
ret.IsPublic = true
ret.PublicScope = rbacutils.ScopeDomain
case CLOUD_ACCOUNT_SHARE_MODE_SYSTEM:
ret.IsPublic = true
if i.IsPublic && i.PublicScope == rbacutils.ScopeSystem {
ret.PublicScope = rbacutils.ScopeSystem
} else {
ret.PublicScope = rbacutils.ScopeDomain
ret.SharedDomains = i.SharedDomains
}
}
return ret
}
func (i SAccountShareInfo) GetDomainShareInfo() SShareInfo {
ret := SShareInfo{}
switch i.ShareMode {
case CLOUD_ACCOUNT_SHARE_MODE_ACCOUNT_DOMAIN:
ret.IsPublic = false
ret.PublicScope = rbacutils.ScopeNone
case CLOUD_ACCOUNT_SHARE_MODE_PROVIDER_DOMAIN:
ret.IsPublic = false
ret.PublicScope = rbacutils.ScopeNone
case CLOUD_ACCOUNT_SHARE_MODE_SYSTEM:
if i.IsPublic && i.PublicScope == rbacutils.ScopeSystem {
ret.IsPublic = true
ret.PublicScope = rbacutils.ScopeSystem
} else if len(i.SharedDomains) > 0 {
ret.IsPublic = true
ret.PublicScope = rbacutils.ScopeDomain
ret.SharedDomains = i.SharedDomains
} else {
ret.IsPublic = false
ret.PublicScope = rbacutils.ScopeNone
}
}
return ret
}
func (i SShareInfo) IsViolate(i2 SShareInfo) bool {
if i.IsPublic && !i2.IsPublic {
return true
} else if !i.IsPublic && i2.IsPublic {
return false
}
// is_public equals
if i.PublicScope.HigherThan(i2.PublicScope) {
return true
} else if i2.PublicScope.HigherThan(i.PublicScope) {
return false
}
// public_scope equals
aNoB, _, bNoA := stringutils2.Split(stringutils2.NewSortedStrings(i.SharedDomains), stringutils2.NewSortedStrings(i2.SharedDomains))
if len(aNoB) > 0 {
return true
} else if len(bNoA) > 0 {
return false
}
// shared_domains equals
aNoB, _, bNoA = stringutils2.Split(stringutils2.NewSortedStrings(i.SharedProjects), stringutils2.NewSortedStrings(i2.SharedProjects))
if len(aNoB) > 0 {
return true
} else if len(bNoA) > 0 {
return false
}
return false
}
func (i SShareInfo) Intersect(i2 SShareInfo) SShareInfo {
if i.IsPublic && !i2.IsPublic {
return i2
} else if !i.IsPublic && i2.IsPublic {
return i
}
// is_public equals
if i.PublicScope.HigherThan(i2.PublicScope) {
return i2
} else if i2.PublicScope.HigherThan(i.PublicScope) {
return i
}
// public_scope equals
_, domains, _ := stringutils2.Split(stringutils2.NewSortedStrings(i.SharedDomains), stringutils2.NewSortedStrings(i2.SharedDomains))
_, projs, _ := stringutils2.Split(stringutils2.NewSortedStrings(i.SharedProjects), stringutils2.NewSortedStrings(i2.SharedProjects))
ret := SShareInfo{
IsPublic: i.IsPublic,
PublicScope: i.PublicScope,
SharedDomains: domains,
SharedProjects: projs,
}
if ret.PublicScope == rbacutils.ScopeProject && len(ret.SharedProjects) == 0 {
ret.IsPublic = false
ret.PublicScope = rbacutils.ScopeNone
}
return ret
}
func (i SShareInfo) Equals(i2 SShareInfo) bool {
if !i.IsViolate(i2) && !i2.IsViolate(i) {
return true
} else {
return false
}
}
func (i *SShareInfo) FixProjectShare() {
if i.PublicScope == rbacutils.ScopeProject && len(i.SharedProjects) == 0 {
i.IsPublic = false
i.PublicScope = rbacutils.ScopeNone
}
}
func (i *SShareInfo) FixDomainShare() {
if i.PublicScope == rbacutils.ScopeProject {
i.IsPublic = false
i.PublicScope = rbacutils.ScopeNone
i.SharedProjects = nil
} else if i.PublicScope == rbacutils.ScopeDomain && len(i.SharedDomains) == 0 {
i.IsPublic = false
i.PublicScope = rbacutils.ScopeNone
}
}
+199
View File
@@ -0,0 +1,199 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package apis
import (
"testing"
"yunion.io/x/onecloud/pkg/util/rbacutils"
)
func TestSShareInfo_IsViolate(t *testing.T) {
cases := []struct {
name string
s1 SShareInfo
s2 SShareInfo
violate1 bool
violate2 bool
}{
{
name: "case1",
s1: SShareInfo{
IsPublic: false,
PublicScope: rbacutils.ScopeNone,
},
s2: SShareInfo{
IsPublic: true,
PublicScope: rbacutils.ScopeSystem,
},
violate1: false,
violate2: true,
},
{
name: "case2",
s1: SShareInfo{
IsPublic: true,
PublicScope: rbacutils.ScopeProject,
SharedProjects: []string{"p1"},
},
s2: SShareInfo{
IsPublic: true,
PublicScope: rbacutils.ScopeProject,
SharedProjects: []string{"p2"},
},
violate1: true,
violate2: true,
},
{
name: "case3",
s1: SShareInfo{
IsPublic: true,
PublicScope: rbacutils.ScopeDomain,
SharedDomains: []string{"p1"},
},
s2: SShareInfo{
IsPublic: true,
PublicScope: rbacutils.ScopeProject,
SharedProjects: []string{"p2"},
},
violate1: true,
violate2: false,
},
{
name: "case4",
s1: SShareInfo{
IsPublic: true,
PublicScope: rbacutils.ScopeDomain,
SharedDomains: []string{"p1", "p2"},
},
s2: SShareInfo{
IsPublic: true,
PublicScope: rbacutils.ScopeDomain,
SharedDomains: []string{"p1", "p2"},
},
violate1: false,
violate2: false,
},
}
for _, c := range cases {
if c.s1.IsViolate(c.s2) != c.violate1 {
t.Errorf("[%s] s1.violate(s2) want %v", c.name, c.violate1)
} else if c.s2.IsViolate(c.s1) != c.violate2 {
t.Errorf("[%s] s2.violate(s1) want: %v", c.name, c.violate2)
}
}
}
func TestSShareInfo_Intersect(t *testing.T) {
cases := []struct {
name string
s1 SShareInfo
s2 SShareInfo
want SShareInfo
}{
{
name: "case1",
s1: SShareInfo{
IsPublic: false,
PublicScope: rbacutils.ScopeNone,
},
s2: SShareInfo{
IsPublic: true,
PublicScope: rbacutils.ScopeSystem,
},
want: SShareInfo{
IsPublic: false,
PublicScope: rbacutils.ScopeNone,
},
},
{
name: "case2",
s1: SShareInfo{
IsPublic: true,
PublicScope: rbacutils.ScopeProject,
SharedProjects: []string{"p1"},
},
s2: SShareInfo{
IsPublic: true,
PublicScope: rbacutils.ScopeProject,
SharedProjects: []string{"p2"},
},
want: SShareInfo{
IsPublic: false,
PublicScope: rbacutils.ScopeNone,
},
},
{
name: "case3",
s1: SShareInfo{
IsPublic: true,
PublicScope: rbacutils.ScopeDomain,
SharedDomains: []string{"p1"},
},
s2: SShareInfo{
IsPublic: true,
PublicScope: rbacutils.ScopeProject,
SharedProjects: []string{"p2"},
},
want: SShareInfo{
IsPublic: true,
PublicScope: rbacutils.ScopeProject,
SharedProjects: []string{"p2"},
},
},
{
name: "case4",
s1: SShareInfo{
IsPublic: true,
PublicScope: rbacutils.ScopeDomain,
SharedDomains: []string{"p1", "p2"},
},
s2: SShareInfo{
IsPublic: true,
PublicScope: rbacutils.ScopeDomain,
SharedDomains: []string{"p1", "p2"},
},
want: SShareInfo{
IsPublic: true,
PublicScope: rbacutils.ScopeDomain,
SharedDomains: []string{"p1", "p2"},
},
},
{
name: "case5",
s1: SShareInfo{
IsPublic: true,
PublicScope: rbacutils.ScopeDomain,
SharedDomains: []string{"p1", "p2", "p4"},
},
s2: SShareInfo{
IsPublic: true,
PublicScope: rbacutils.ScopeDomain,
SharedDomains: []string{"p1", "p2", "p3"},
},
want: SShareInfo{
IsPublic: true,
PublicScope: rbacutils.ScopeDomain,
SharedDomains: []string{"p1", "p2"},
},
},
}
for _, c := range cases {
inter := c.s1.Intersect(c.s2)
if !inter.Equals(c.want) {
t.Errorf("[%s] intersect got %#v != want %#v", c.name, inter, c.want)
}
}
}
+40 -36
View File
@@ -22,7 +22,6 @@ import (
"yunion.io/x/sqlchemy"
"yunion.io/x/onecloud/pkg/apis"
"yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/rbacutils"
@@ -217,43 +216,48 @@ func (model *SInfrasResourceBase) Delete(ctx context.Context, userCred mcclient.
return model.SDomainLevelResourceBase.Delete(ctx, userCred)
}
func (model *SInfrasResourceBase) GetSharedInfo() apis.SShareInfo {
ret := apis.SShareInfo{}
ret.IsPublic = model.IsPublic
ret.PublicScope = rbacutils.String2ScopeDefault(model.PublicScope, rbacutils.ScopeNone)
ret.SharedDomains = model.GetSharedDomains()
ret.SharedProjects = nil
// fix
if len(ret.SharedDomains) > 0 {
ret.PublicScope = rbacutils.ScopeDomain
ret.SharedProjects = nil
ret.IsPublic = true
} else if !ret.IsPublic {
ret.PublicScope = rbacutils.ScopeNone
}
return ret
}
func (model *SInfrasResourceBase) SaveSharedInfo(src apis.TOwnerSource, ctx context.Context, userCred mcclient.TokenCredential, si apis.SShareInfo) {
diff, _ := Update(model, func() error {
model.PublicSrc = string(src)
model.IsPublic = si.IsPublic
model.PublicScope = string(si.PublicScope)
return nil
})
if len(diff) > 0 {
OpsLog.LogEvent(model, ACT_SYNC_SHARE, diff, userCred)
}
SharedResourceManager.shareToTarget(ctx, userCred, model.GetIInfrasModel(), SharedTargetProject, nil, nil, nil)
SharedResourceManager.shareToTarget(ctx, userCred, model.GetIInfrasModel(), SharedTargetDomain, si.SharedDomains, nil, nil)
}
func (model *SInfrasResourceBase) SyncShareState(ctx context.Context, userCred mcclient.TokenCredential, shareInfo apis.SAccountShareInfo) {
si := shareInfo.GetDomainShareInfo()
if model.PublicSrc != string(apis.OWNER_SOURCE_LOCAL) {
diff, _ := Update(model, func() error {
model.PublicSrc = string(apis.OWNER_SOURCE_CLOUD)
switch shareInfo.ShareMode {
case compute.CLOUD_ACCOUNT_SHARE_MODE_ACCOUNT_DOMAIN:
model.IsPublic = false
model.PublicScope = string(rbacutils.ScopeNone)
SharedResourceManager.shareToTarget(ctx, userCred, model.GetIInfrasModel(), SharedTargetProject, nil, nil, nil)
SharedResourceManager.shareToTarget(ctx, userCred, model.GetIInfrasModel(), SharedTargetDomain, nil, nil, nil)
case compute.CLOUD_ACCOUNT_SHARE_MODE_PROVIDER_DOMAIN:
model.IsPublic = false
model.PublicScope = string(rbacutils.ScopeNone)
SharedResourceManager.shareToTarget(ctx, userCred, model.GetIInfrasModel(), SharedTargetProject, nil, nil, nil)
SharedResourceManager.shareToTarget(ctx, userCred, model.GetIInfrasModel(), SharedTargetDomain, nil, nil, nil)
case compute.CLOUD_ACCOUNT_SHARE_MODE_SYSTEM:
if shareInfo.IsPublic && shareInfo.PublicScope == rbacutils.ScopeSystem {
model.IsPublic = true
model.PublicScope = string(rbacutils.ScopeSystem)
SharedResourceManager.shareToTarget(ctx, userCred, model.GetIInfrasModel(), SharedTargetProject, nil, nil, nil)
SharedResourceManager.shareToTarget(ctx, userCred, model.GetIInfrasModel(), SharedTargetDomain, nil, nil, nil)
} else if len(shareInfo.SharedDomains) > 0 {
model.IsPublic = true
model.PublicScope = string(rbacutils.ScopeDomain)
SharedResourceManager.shareToTarget(ctx, userCred, model.GetIInfrasModel(), SharedTargetProject, nil, nil, nil)
SharedResourceManager.shareToTarget(ctx, userCred, model.GetIInfrasModel(), SharedTargetDomain, shareInfo.SharedDomains, nil, nil)
} else {
model.IsPublic = false
model.PublicScope = string(rbacutils.ScopeNone)
SharedResourceManager.shareToTarget(ctx, userCred, model.GetIInfrasModel(), SharedTargetProject, nil, nil, nil)
SharedResourceManager.shareToTarget(ctx, userCred, model.GetIInfrasModel(), SharedTargetDomain, nil, nil, nil)
}
}
return nil
})
if len(diff) > 0 {
OpsLog.LogEvent(model, ACT_SYNC_SHARE, diff, userCred)
model.SaveSharedInfo(apis.OWNER_SOURCE_CLOUD, ctx, userCred, si)
} else {
localSi := model.GetSharedInfo()
if localSi.IsViolate(si) {
newSi := localSi.Intersect(si)
newSi.FixDomainShare()
// reset to cloud base public_src
model.SaveSharedInfo(apis.OWNER_SOURCE_CLOUD, ctx, userCred, newSi)
}
}
}
+44 -30
View File
@@ -22,7 +22,6 @@ import (
"yunion.io/x/sqlchemy"
"yunion.io/x/onecloud/pkg/apis"
"yunion.io/x/onecloud/pkg/apis/compute"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/rbacutils"
@@ -210,37 +209,52 @@ func (model *SSharableVirtualResourceBase) Delete(ctx context.Context, userCred
return model.SVirtualResourceBase.Delete(ctx, userCred)
}
func (model *SSharableVirtualResourceBase) GetSharedInfo() apis.SShareInfo {
ret := apis.SShareInfo{}
ret.IsPublic = model.IsPublic
ret.PublicScope = rbacutils.String2ScopeDefault(model.PublicScope, rbacutils.ScopeNone)
ret.SharedDomains = model.GetSharedDomains()
ret.SharedProjects = model.GetSharedProjects()
// fix
if len(ret.SharedDomains) > 0 {
ret.PublicScope = rbacutils.ScopeDomain
ret.SharedProjects = nil
ret.IsPublic = true
} else if len(ret.SharedProjects) > 0 {
ret.PublicScope = rbacutils.ScopeProject
ret.SharedDomains = nil
ret.IsPublic = true
} else if !ret.IsPublic {
ret.PublicScope = rbacutils.ScopeNone
}
return ret
}
func (model *SSharableVirtualResourceBase) SaveSharedInfo(src apis.TOwnerSource, ctx context.Context, userCred mcclient.TokenCredential, si apis.SShareInfo) {
diff, _ := Update(model, func() error {
model.PublicSrc = string(src)
model.IsPublic = si.IsPublic
model.PublicScope = string(si.PublicScope)
return nil
})
if len(diff) > 0 {
OpsLog.LogEvent(model, ACT_SYNC_SHARE, diff, userCred)
}
SharedResourceManager.shareToTarget(ctx, userCred, model.GetISharableVirtualModel(), SharedTargetProject, si.SharedProjects, nil, nil)
SharedResourceManager.shareToTarget(ctx, userCred, model.GetISharableVirtualModel(), SharedTargetDomain, si.SharedDomains, nil, nil)
}
func (model *SSharableVirtualResourceBase) SyncShareState(ctx context.Context, userCred mcclient.TokenCredential, shareInfo apis.SAccountShareInfo) {
si := shareInfo.GetProjectShareInfo()
if model.PublicSrc != string(apis.OWNER_SOURCE_LOCAL) {
diff, _ := Update(model, func() error {
model.PublicSrc = string(apis.OWNER_SOURCE_CLOUD)
switch shareInfo.ShareMode {
case compute.CLOUD_ACCOUNT_SHARE_MODE_ACCOUNT_DOMAIN:
model.IsPublic = true
model.PublicScope = string(rbacutils.ScopeDomain)
SharedResourceManager.shareToTarget(ctx, userCred, model.GetISharableVirtualModel(), SharedTargetProject, nil, nil, nil)
SharedResourceManager.shareToTarget(ctx, userCred, model.GetISharableVirtualModel(), SharedTargetDomain, nil, nil, nil)
case compute.CLOUD_ACCOUNT_SHARE_MODE_PROVIDER_DOMAIN:
model.IsPublic = true
model.PublicScope = string(rbacutils.ScopeDomain)
SharedResourceManager.shareToTarget(ctx, userCred, model.GetISharableVirtualModel(), SharedTargetProject, nil, nil, nil)
SharedResourceManager.shareToTarget(ctx, userCred, model.GetISharableVirtualModel(), SharedTargetDomain, nil, nil, nil)
case compute.CLOUD_ACCOUNT_SHARE_MODE_SYSTEM:
model.IsPublic = true
if shareInfo.IsPublic && shareInfo.PublicScope == rbacutils.ScopeSystem {
model.PublicScope = string(rbacutils.ScopeSystem)
SharedResourceManager.shareToTarget(ctx, userCred, model.GetISharableVirtualModel(), SharedTargetProject, nil, nil, nil)
SharedResourceManager.shareToTarget(ctx, userCred, model.GetISharableVirtualModel(), SharedTargetDomain, nil, nil, nil)
} else {
model.PublicScope = string(rbacutils.ScopeDomain)
SharedResourceManager.shareToTarget(ctx, userCred, model.GetISharableVirtualModel(), SharedTargetProject, nil, nil, nil)
SharedResourceManager.shareToTarget(ctx, userCred, model.GetISharableVirtualModel(), SharedTargetDomain, shareInfo.SharedDomains, nil, nil)
}
}
return nil
})
if len(diff) > 0 {
OpsLog.LogEvent(model, ACT_SYNC_SHARE, diff, userCred)
model.SaveSharedInfo(apis.OWNER_SOURCE_CLOUD, ctx, userCred, si)
} else {
localSi := model.GetSharedInfo()
if localSi.IsViolate(si) {
newSi := localSi.Intersect(si)
newSi.FixProjectShare()
// reset to cloud base public_src
model.SaveSharedInfo(apis.OWNER_SOURCE_CLOUD, ctx, userCred, newSi)
}
}
}
+2
View File
@@ -219,6 +219,7 @@ func (manager *SBucketManager) newFromCloudBucket(
}
SyncCloudProject(userCred, &bucket, provider.GetOwnerId(), extBucket, provider.Id)
bucket.SyncShareState(ctx, userCred, provider.getAccountShareInfo())
db.OpsLog.LogEvent(&bucket, db.ACT_CREATE, bucket.GetShortDesc(ctx), userCred)
@@ -292,6 +293,7 @@ func (bucket *SBucket) syncWithCloudBucket(
if provider != nil {
SyncCloudProject(userCred, bucket, provider.GetOwnerId(), extBucket, provider.Id)
bucket.SyncShareState(ctx, userCred, provider.getAccountShareInfo())
}
return nil