Merge pull request #9616 from swordqiu/hotfix/qj-fix-policy-role-description-i18n

fix(keystone): add i18n description for policy and role
This commit is contained in:
Zexi Li
2020-12-24 02:13:55 +08:00
committed by GitHub
7 changed files with 843 additions and 0 deletions
+15
View File
@@ -0,0 +1,15 @@
// 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 locale // import "yunion.io/x/onecloud/pkg/keystone/locale"
+247
View File
@@ -0,0 +1,247 @@
// 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 locale
import (
"fmt"
"strings"
"yunion.io/x/jsonutils"
"yunion.io/x/onecloud/pkg/util/rbacutils"
)
var (
allowResult = jsonutils.NewString("allow")
denyResult = jsonutils.NewString("deny")
editorAction = getEditActionPolicy()
viewerAction = getViewerActionPolicy()
)
func getAdminPolicy(services map[string][]string) jsonutils.JSONObject {
policy := jsonutils.NewDict()
for k, resList := range services {
if len(resList) == 0 {
policy.Add(allowResult, k)
} else {
resPolicy := jsonutils.NewDict()
for i := range resList {
resPolicy.Add(allowResult, resList[i])
}
policy.Add(resPolicy, k)
}
}
return policy
}
func getEditActionPolicy() jsonutils.JSONObject {
p := jsonutils.NewDict()
p.Add(denyResult, "create")
p.Add(denyResult, "delete")
perform := jsonutils.NewDict()
perform.Add(denyResult, "purge")
perform.Add(denyResult, "clone")
perform.Add(allowResult, "*")
p.Add(perform, "perform")
p.Add(allowResult, "*")
return p
}
func getViewerActionPolicy() jsonutils.JSONObject {
p := jsonutils.NewDict()
p.Add(allowResult, "get")
p.Add(allowResult, "list")
p.Add(denyResult, "*")
return p
}
func getEditorPolicy(services map[string][]string) jsonutils.JSONObject {
policy := jsonutils.NewDict()
for k, resList := range services {
if len(resList) == 0 {
resList = []string{"*"}
}
resPolicy := jsonutils.NewDict()
for i := range resList {
resPolicy.Add(editorAction, resList[i])
}
policy.Add(resPolicy, k)
}
return policy
}
func getViewerPolicy(services map[string][]string) jsonutils.JSONObject {
policy := jsonutils.NewDict()
for k, resList := range services {
if len(resList) == 0 {
resList = []string{"*"}
}
resPolicy := jsonutils.NewDict()
for i := range resList {
resPolicy.Add(viewerAction, resList[i])
}
policy.Add(resPolicy, k)
}
return policy
}
func addExtraPolicy(policy *jsonutils.JSONDict, extra map[string]map[string][]string) jsonutils.JSONObject {
for s, resources := range extra {
resourcePolicy := jsonutils.NewDict()
for r, actions := range resources {
actionPolicy := jsonutils.NewDict()
for i := range actions {
actionPolicy.Add(allowResult, actions[i])
}
actionPolicy.Add(denyResult, "*")
resourcePolicy.Add(actionPolicy, r)
}
policy.Add(resourcePolicy, s)
}
return policy
}
func GenerateAllPolicies() []SPolicyData {
ret := make([]SPolicyData, 0)
for i := range policyDefinitons {
def := policyDefinitons[i]
for _, scope := range []rbacutils.TRbacScope{
rbacutils.ScopeSystem,
rbacutils.ScopeDomain,
rbacutils.ScopeProject,
} {
if scope.HigherEqual(def.Scope) {
ps := generatePolicies(scope, def)
ret = append(ret, ps...)
}
}
}
return ret
}
type SPolicyData struct {
Name string
Scope rbacutils.TRbacScope
Policy jsonutils.JSONObject
Description string
DescriptionCN string
}
func generatePolicies(scope rbacutils.TRbacScope, def sPolicyDefinition) []SPolicyData {
level := ""
switch scope {
case rbacutils.ScopeSystem:
level = "sys"
if def.Scope == rbacutils.ScopeSystem {
level = ""
}
case rbacutils.ScopeDomain:
level = "domain"
case rbacutils.ScopeProject:
level = "project"
}
type sRoleConf struct {
name string
policyFunc func(services map[string][]string) jsonutils.JSONObject
fullName string
fullNameCN string
}
var roleConfs []sRoleConf
if len(def.Services) > 0 {
roleConfs = []sRoleConf{
{
name: "admin",
policyFunc: getAdminPolicy,
fullNameCN: "管理",
fullName: "full",
},
{
name: "editor",
policyFunc: getEditorPolicy,
fullNameCN: "编辑/操作",
fullName: "editor/operator",
},
{
name: "viewer",
policyFunc: getViewerPolicy,
fullNameCN: "只读",
fullName: "read-only",
},
}
} else {
roleConfs = []sRoleConf{
{
name: "",
policyFunc: nil,
fullNameCN: "",
fullName: "",
},
}
}
ret := make([]SPolicyData, 0)
for _, role := range roleConfs {
name := fmt.Sprintf("%s%s%s", level, def.Name, role.name)
var policy jsonutils.JSONObject
if def.Services != nil {
policy = role.policyFunc(def.Services)
} else {
policy = jsonutils.NewDict()
}
policy = addExtraPolicy(policy.(*jsonutils.JSONDict), def.Extra)
desc := ""
descCN := ""
switch scope {
case rbacutils.ScopeSystem:
descCN += "全局"
desc += "System-level"
case rbacutils.ScopeDomain:
descCN += "本域内"
desc += "Domain-level"
case rbacutils.ScopeProject:
descCN += "本项目内"
desc += "Project-level"
}
if len(role.fullName) > 0 {
desc += " " + role.fullName
}
desc += " previlliges for"
if len(def.Desc) > 0 {
desc += " " + def.Desc
}
if len(def.DescCN) > 0 {
descCN += def.DescCN
}
if len(role.fullNameCN) > 0 {
descCN += role.fullNameCN
}
descCN += "权限"
policyJson := jsonutils.NewDict()
policyJson.Add(policy, "policy")
ret = append(ret, SPolicyData{
Name: name,
Scope: scope,
Policy: policyJson,
Description: strings.TrimSpace(desc),
DescriptionCN: strings.TrimSpace(descCN),
})
}
return ret
}
+54
View File
@@ -0,0 +1,54 @@
// 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 locale
import (
"testing"
"golang.org/x/text/language"
"yunion.io/x/jsonutils"
)
func TestGenerateAllPolicies(t *testing.T) {
policies := GenerateAllPolicies()
for _, p := range policies {
t.Logf("name %s description %s scope %s policy %s", p.Name, p.Description, p.Scope, p.Policy)
}
t.Logf("total: %d", len(policies))
}
func TestPolicyDescriptions(t *testing.T) {
out := jsonutils.NewDict()
policies := GenerateAllPolicies()
for _, p := range policies {
item := jsonutils.NewDict()
item.Add(jsonutils.NewString(p.Description), language.English.String())
item.Add(jsonutils.NewString(p.DescriptionCN), language.Chinese.String())
out.Add(item, p.Name)
}
t.Logf("%s", out.PrettyString())
}
func TestRoleDescriptions(t *testing.T) {
out := jsonutils.NewDict()
for _, r := range RoleDefinitions {
item := jsonutils.NewDict()
item.Add(jsonutils.NewString(r.Description), language.English.String())
item.Add(jsonutils.NewString(r.DescriptionCN), language.Chinese.String())
out.Add(item, r.Name)
}
t.Logf("%s", out.PrettyString())
}
+39
View File
@@ -0,0 +1,39 @@
// 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 locale
import (
"yunion.io/x/onecloud/pkg/i18n"
)
var PredefinedPolicyI18nTable = i18n.Table{}
var PredefinedRoleI18nTable = i18n.Table{}
func init() {
policies := GenerateAllPolicies()
for _, p := range policies {
PredefinedPolicyI18nTable.Set(p.Name, i18n.NewTableEntry().
EN(p.Description).
CN(p.DescriptionCN),
)
}
for _, r := range RoleDefinitions {
PredefinedRoleI18nTable.Set(r.Name, i18n.NewTableEntry().
EN(r.Description).
CN(r.DescriptionCN),
)
}
}
+472
View File
@@ -0,0 +1,472 @@
// 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 locale
import (
"yunion.io/x/onecloud/pkg/util/rbacutils"
)
const (
RoleAdmin = "admin"
RoleFA = "fa"
RoleSA = "sa"
RoleProjectOwner = "project_owner"
RoleMember = "member"
RoleDomainAdmin = "domainadmin"
RoleProjectEditor = "project_editor"
)
type sPolicyDefinition struct {
Name string
DescCN string
Desc string
Scope rbacutils.TRbacScope
Services map[string][]string
Extra map[string]map[string][]string
}
type SRoleDefiniton struct {
Name string
Description string
Policies []string
Project string
DescriptionCN string
}
var (
policyDefinitons = []sPolicyDefinition{
{
Name: "",
DescCN: "任意资源",
Desc: "any resources",
Scope: rbacutils.ScopeProject,
Services: map[string][]string{
"*": nil,
},
},
{
Name: "dashboard",
DescCN: "控制面板查看相关资源",
Desc: "resources for viewing dashboard",
Scope: rbacutils.ScopeProject,
Extra: map[string]map[string][]string{
"compute": {
"capabilities": {
"list",
},
"usages": {
"list",
"get",
},
},
"image": {
"usages": {
"list",
"get",
},
},
"identity": {
"usages": {
"list",
"get",
},
},
"meter": {
"bill_conditions": {
"list",
},
},
"monitor": {
"alertresources": {
"list",
},
"unifiedmonitors": {
"perform",
},
},
"log": {
"actions": {
"list",
},
},
},
},
{
Name: "compute",
DescCN: "计算服务(云主机与容器)相关资源",
Desc: "resources of computing (cloud servers and containers)",
Scope: rbacutils.ScopeProject,
Services: map[string][]string{
"compute": nil,
"image": nil,
"k8s": nil,
},
},
{
Name: "server",
DescCN: "云主机相关资源",
Desc: "resources of cloud servers",
Scope: rbacutils.ScopeProject,
Services: map[string][]string{
"compute": {
"servers",
"servertemplates",
"instancegroups",
"scalinggroups",
"scalingactivities",
"scalingpolicies",
"disks",
"networks",
"eips",
"snapshotpolicies",
"snapshotpolicycaches",
"snapshotpolicydisks",
"snapshots",
"instance_snapshots",
"snapshotpolicies",
"secgroupcaches",
"secgrouprules",
"secgroups",
},
"image": nil,
},
Extra: map[string]map[string][]string{
"compute": {
"isolated_devices": {
"get",
"list",
},
},
},
},
{
Name: "host",
DescCN: "宿主机和物理机相关资源",
Desc: "resources of hosts and baremetals",
Scope: rbacutils.ScopeDomain,
Services: map[string][]string{
"compute": {
"hosts",
"isolated_devices",
"hostwires",
"hoststorages",
"baremetalagents",
"baremetalnetworks",
"baremetalevents",
},
},
},
{
Name: "storage",
DescCN: "云硬盘存储相关资源",
Desc: "resources of cloud disk storages",
Scope: rbacutils.ScopeDomain,
Services: map[string][]string{
"compute": {
"storages",
},
},
},
{
Name: "loadbalancer",
DescCN: "负载均衡相关资源",
Desc: "resources of load balancers",
Scope: rbacutils.ScopeProject,
Services: map[string][]string{
"compute": {
"loadbalanceracls",
"loadbalanceragents",
"loadbalancerbackendgroups",
"loadbalancerbackends",
"loadbalancercertificates",
"loadbalancerclusters",
"loadbalancerlistenerrules",
"loadbalancerlisteners",
"loadbalancernetworks",
"loadbalancers",
},
},
Extra: map[string]map[string][]string{
"compute": {
"networks": {
"get",
"list",
},
},
},
},
{
Name: "oss",
DescCN: "对象存储相关资源",
Desc: "resources of object storages",
Scope: rbacutils.ScopeProject,
Services: map[string][]string{
"compute": {
"buckets",
},
},
},
{
Name: "dbinstance",
DescCN: "关系型数据库(MySQL等)相关资源",
Desc: "resources of RDS",
Scope: rbacutils.ScopeProject,
Services: map[string][]string{
"compute": {
"dbinstance_skus",
"dbinstanceaccounts",
"dbinstancebackups",
"dbinstancedatabases",
"dbinstancenetworks",
"dbinstanceparameters",
"dbinstanceprivileges",
"dbinstances",
},
},
},
{
Name: "elasticcache",
DescCN: "弹性缓存(Redis等)相关资源",
Desc: "resources of elastic caches",
Scope: rbacutils.ScopeProject,
Services: map[string][]string{
"compute": {
"elasticcacheaccounts",
"elasticcacheacls",
"elasticcachebackups",
"elasticcacheparameters",
"elasticcaches",
"elasticcacheskus",
},
},
},
{
Name: "network",
DescCN: "网络相关资源",
Desc: "resources of networking",
Scope: rbacutils.ScopeDomain,
Services: map[string][]string{
"compute": {
"vpcs",
"wires",
"natdentries",
"natgateways",
"natsentries",
"networkinterfacenetworks",
"networkinterfaces",
"networks",
"reservedips",
"route_tables",
"globalvpcs",
"vpc_peering_connections",
"eips",
"dns_recordsets",
"dns_trafficpolicies",
"dns_zonecaches",
"dns_zones",
"dnsrecords",
},
},
},
{
Name: "meter",
DescCN: "计费计量分析服务相关资源",
Desc: "resources of metering and billing service",
Scope: rbacutils.ScopeProject,
Services: map[string][]string{
"meter": nil,
"notify": {
"receivers",
},
},
},
{
Name: "identity",
DescCN: "身份认证(IAM)服务相关资源",
Desc: "resources of identity service",
Scope: rbacutils.ScopeDomain,
Services: map[string][]string{
"identity": nil,
},
},
{
Name: "image",
DescCN: "镜像服务相关资源",
Desc: "resources of image service",
Scope: rbacutils.ScopeProject,
Services: map[string][]string{
"image": nil,
},
},
{
Name: "monitor",
DescCN: "监控服务相关资源",
Desc: "resources of monitor service",
Scope: rbacutils.ScopeProject,
Services: map[string][]string{
"monitor": nil,
},
},
{
Name: "container",
DescCN: "容器服务相关资源",
Desc: "resources of container service",
Scope: rbacutils.ScopeProject,
Services: map[string][]string{
"k8s": nil,
},
},
{
Name: "cloudid",
DescCN: "云用户及权限管理相关资源",
Desc: "resources of service CloudId and IAM",
Scope: rbacutils.ScopeDomain,
Services: map[string][]string{
"compute": {
"cloudaccounts",
"cloudproviders",
},
"identity": {
"users",
"projects",
"roles",
},
"cloudid": nil,
},
},
{
Name: "cloudaccount",
DescCN: "云账号管理相关资源",
Desc: "resources for cloud account administration",
Scope: rbacutils.ScopeDomain,
Services: map[string][]string{
"compute": {
"cloudaccounts",
"cloudproviderquotas",
"cloudproviderregions",
"cloudproviders",
},
},
},
{
Name: "projectresource",
DescCN: "项目管理相关资源",
Desc: "resources for project administration",
Scope: rbacutils.ScopeDomain,
Services: map[string][]string{
"compute": {
"project_quotas",
"quotas",
"region_quotas",
"zone_quotas",
},
"image": {
"image_quotas",
},
"identity": {
"projects",
"roles",
"policies",
},
},
},
{
Name: "domainresource",
DescCN: "域管理相关资源",
Desc: "resources for domain administration",
Scope: rbacutils.ScopeSystem,
Services: map[string][]string{
"compute": {
"domain_quotas",
"infras_quotas",
},
"identity": {
"domains",
"identity_quotas",
"projects",
"roles",
"policies",
"users",
"groups",
},
},
},
{
Name: "notify",
DescCN: "通知服务相关资源",
Desc: "resources of notify service",
Scope: rbacutils.ScopeSystem,
Services: map[string][]string{
"notify": nil,
},
},
}
RoleDefinitions = []SRoleDefiniton{
{
Name: RoleAdmin,
DescriptionCN: "系统管理员",
Description: "System administrator",
Policies: []string{
"sysadmin",
},
Project: "system",
},
{
Name: RoleDomainAdmin,
DescriptionCN: "域管理员",
Description: "Domain administrator",
Policies: []string{
"domainadmin",
},
},
{
Name: RoleProjectOwner,
DescriptionCN: "项目主管",
Description: "Project owner",
Policies: []string{
"projectadmin",
},
},
{
Name: RoleFA,
DescriptionCN: "财务管理员",
Description: "System finance administrator",
Policies: []string{
"sysmeteradmin",
"sysdashboard",
},
},
{
Name: RoleMember,
DescriptionCN: "项目只读成员",
Description: "Project read-only member",
Policies: []string{
"projectviewer",
"projectdashboard",
},
},
{
Name: RoleProjectEditor,
DescriptionCN: "项目操作员",
Description: "Project operator",
Policies: []string{
"projecteditor",
"projectdashboard",
},
},
}
)
+8
View File
@@ -32,6 +32,7 @@ import (
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
policyman "yunion.io/x/onecloud/pkg/cloudcommon/policy"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/keystone/locale"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/rbacutils"
"yunion.io/x/onecloud/pkg/util/stringutils2"
@@ -630,3 +631,10 @@ func (policy *SPolicy) PerformBindRole(ctx context.Context, userCred mcclient.To
}
return nil, nil
}
func (policy *SPolicy) GetI18N(ctx context.Context) *jsonutils.JSONDict {
r := jsonutils.NewDict()
act18 := locale.PredefinedPolicyI18nTable.Lookup(ctx, policy.Description)
r.Set("description", jsonutils.NewString(act18))
return r
}
+8
View File
@@ -32,6 +32,7 @@ import (
"yunion.io/x/onecloud/pkg/cloudcommon/db"
"yunion.io/x/onecloud/pkg/cloudcommon/db/quotas"
"yunion.io/x/onecloud/pkg/httperrors"
"yunion.io/x/onecloud/pkg/keystone/locale"
"yunion.io/x/onecloud/pkg/mcclient"
"yunion.io/x/onecloud/pkg/util/rbacutils"
"yunion.io/x/onecloud/pkg/util/stringutils2"
@@ -727,3 +728,10 @@ func (role *SRole) PerformRemovePolicy(ctx context.Context, userCred mcclient.To
func (role *SRole) GetChangeOwnerCandidateDomainIds() []string {
return db.ISharableChangeOwnerCandidateDomainIds(role)
}
func (role *SRole) GetI18N(ctx context.Context) *jsonutils.JSONDict {
r := jsonutils.NewDict()
act18 := locale.PredefinedRoleI18nTable.Lookup(ctx, role.Description)
r.Set("description", jsonutils.NewString(act18))
return r
}