Signed-off-by: hongming <talonwan@yunify.com>
This commit is contained in:
hongming
2020-03-19 22:44:05 +08:00
parent 23f6be88c6
commit 9769357005
332 changed files with 69808 additions and 4129 deletions

View File

@@ -1,606 +0,0 @@
/*
Copyright 2019 The KubeSphere Authors.
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 iam
import (
rbacv1 "k8s.io/api/rbac/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/models/iam/policy"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/clusterrole"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/resource"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/role"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
)
const (
ClusterRoleKind = "ClusterRole"
NamespaceAdminRoleBindName = "admin"
NamespaceViewerRoleBindName = "viewer"
)
type AccessManagementInterface interface {
GetClusterRole(username string) (*rbacv1.ClusterRole, error)
UnBindAllRoles(username string) error
ListRoleBindings(namespace string, role string) ([]*rbacv1.RoleBinding, error)
CreateClusterRoleBinding(username string, clusterRole string) error
ListRoles(namespace string, conditions *params.Conditions, orderBy string, reverse bool, limit int, offset int) (*models.PageableResponse, error)
ListClusterRoles(conditions *params.Conditions, orderBy string, reverse bool, limit int, offset int) (*models.PageableResponse, error)
ListClusterRoleBindings(clusterRole string) ([]*rbacv1.ClusterRoleBinding, error)
GetClusterRoleSimpleRules(clusterRole string) ([]policy.SimpleRule, error)
GetRoleSimpleRules(namespace string, role string) ([]policy.SimpleRule, error)
GetRoles(namespace, username string) ([]*rbacv1.Role, error)
GetClusterPolicyRules(username string) ([]rbacv1.PolicyRule, error)
GetPolicyRules(namespace, username string) ([]rbacv1.PolicyRule, error)
GetWorkspaceRoleSimpleRules(workspace, roleName string) []policy.SimpleRule
GetWorkspaceRole(workspace, username string) (*rbacv1.ClusterRole, error)
GetWorkspaceRoleMap(username string) (map[string]string, error)
}
type amOperator struct {
informers informers.SharedInformerFactory
resources resource.ResourceGetter
kubeClient kubernetes.Interface
}
func (am *amOperator) ListClusterRoleBindings(clusterRole string) ([]*rbacv1.ClusterRoleBinding, error) {
panic("implement me")
}
func (am *amOperator) GetRoles(namespace, username string) ([]*rbacv1.Role, error) {
panic("implement me")
}
func (am *amOperator) GetClusterPolicyRules(username string) ([]rbacv1.PolicyRule, error) {
panic("implement me")
}
func (am *amOperator) GetPolicyRules(namespace, username string) ([]rbacv1.PolicyRule, error) {
panic("implement me")
}
func (am *amOperator) GetWorkspaceRole(workspace, username string) (*rbacv1.ClusterRole, error) {
panic("implement me")
}
func (am *amOperator) UnBindAllRoles(username string) error {
panic("implement me")
}
func NewAMOperator(kubeClient kubernetes.Interface, informers informers.SharedInformerFactory) *amOperator {
resourceGetter := resource.ResourceGetter{}
resourceGetter.Add(v1alpha2.Role, role.NewRoleSearcher(informers))
resourceGetter.Add(v1alpha2.ClusterRoles, clusterrole.NewClusterRoleSearcher(informers))
return &amOperator{
informers: informers,
resources: resourceGetter,
kubeClient: kubeClient,
}
}
func (am *amOperator) GetDevopsRoleSimpleRules(role string) []policy.SimpleRule {
var rules []policy.SimpleRule
switch role {
case "developer":
rules = []policy.SimpleRule{
{Name: "pipelines", Actions: []string{"view", "trigger"}},
{Name: "roles", Actions: []string{"view"}},
{Name: "members", Actions: []string{"view"}},
{Name: "devops", Actions: []string{"view"}},
}
break
case "owner":
rules = []policy.SimpleRule{
{Name: "pipelines", Actions: []string{"create", "edit", "view", "delete", "trigger"}},
{Name: "roles", Actions: []string{"view"}},
{Name: "members", Actions: []string{"create", "edit", "view", "delete"}},
{Name: "credentials", Actions: []string{"create", "edit", "view", "delete"}},
{Name: "devops", Actions: []string{"edit", "view", "delete"}},
}
break
case "maintainer":
rules = []policy.SimpleRule{
{Name: "pipelines", Actions: []string{"create", "edit", "view", "delete", "trigger"}},
{Name: "roles", Actions: []string{"view"}},
{Name: "members", Actions: []string{"view"}},
{Name: "credentials", Actions: []string{"create", "edit", "view", "delete"}},
{Name: "devops", Actions: []string{"view"}},
}
break
case "reporter":
fallthrough
default:
rules = []policy.SimpleRule{
{Name: "pipelines", Actions: []string{"view"}},
{Name: "roles", Actions: []string{"view"}},
{Name: "members", Actions: []string{"view"}},
{Name: "devops", Actions: []string{"view"}},
}
break
}
return rules
}
// Get user roles in namespace
func (am *amOperator) GetUserRoles(namespace, username string) ([]*rbacv1.Role, error) {
clusterRoleLister := am.informers.Rbac().V1().ClusterRoles().Lister()
roleBindingLister := am.informers.Rbac().V1().RoleBindings().Lister()
roleLister := am.informers.Rbac().V1().Roles().Lister()
roleBindings, err := roleBindingLister.RoleBindings(namespace).List(labels.Everything())
if err != nil {
klog.Errorln(err)
return nil, err
}
roles := make([]*rbacv1.Role, 0)
for _, roleBinding := range roleBindings {
if ContainsUser(roleBinding.Subjects, username) {
if roleBinding.RoleRef.Kind == ClusterRoleKind {
clusterRole, err := clusterRoleLister.Get(roleBinding.RoleRef.Name)
if err != nil {
if apierrors.IsNotFound(err) {
klog.Warningf("cluster role %s not found but bind user %s in namespace %s", roleBinding.RoleRef.Name, username, namespace)
continue
} else {
klog.Errorln(err)
return nil, err
}
}
role := rbacv1.Role{}
role.TypeMeta = clusterRole.TypeMeta
role.ObjectMeta = clusterRole.ObjectMeta
role.Rules = clusterRole.Rules
role.Namespace = roleBinding.Namespace
roles = append(roles, &role)
} else {
role, err := roleLister.Roles(roleBinding.Namespace).Get(roleBinding.RoleRef.Name)
if err != nil {
if apierrors.IsNotFound(err) {
klog.Warningf("namespace %s role %s not found, but bind user %s", namespace, roleBinding.RoleRef.Name, username)
continue
} else {
klog.Errorln(err)
return nil, err
}
}
roles = append(roles, role)
}
}
}
return roles, nil
}
func (am *amOperator) GetUserClusterRoles(username string) (*rbacv1.ClusterRole, []*rbacv1.ClusterRole, error) {
clusterRoleLister := am.informers.Rbac().V1().ClusterRoles().Lister()
clusterRoleBindingLister := am.informers.Rbac().V1().ClusterRoleBindings().Lister()
clusterRoleBindings, err := clusterRoleBindingLister.List(labels.Everything())
if err != nil {
klog.Errorln(err)
return nil, nil, err
}
clusterRoles := make([]*rbacv1.ClusterRole, 0)
userFacingClusterRole := &rbacv1.ClusterRole{}
for _, clusterRoleBinding := range clusterRoleBindings {
if ContainsUser(clusterRoleBinding.Subjects, username) {
clusterRole, err := clusterRoleLister.Get(clusterRoleBinding.RoleRef.Name)
if err != nil {
if apierrors.IsNotFound(err) {
klog.Warningf("cluster role %s not found but bind user %s", clusterRoleBinding.RoleRef.Name, username)
continue
} else {
klog.Errorln(err)
return nil, nil, err
}
}
if clusterRoleBinding.Name == username {
userFacingClusterRole = clusterRole
}
clusterRoles = append(clusterRoles, clusterRole)
}
}
return userFacingClusterRole, clusterRoles, nil
}
func (am *amOperator) GetClusterRole(username string) (*rbacv1.ClusterRole, error) {
userFacingClusterRole, _, err := am.GetUserClusterRoles(username)
if err != nil {
return nil, err
}
return userFacingClusterRole, nil
}
func (am *amOperator) GetUserClusterRules(username string) ([]rbacv1.PolicyRule, error) {
_, clusterRoles, err := am.GetUserClusterRoles(username)
if err != nil {
return nil, err
}
rules := make([]rbacv1.PolicyRule, 0)
for _, clusterRole := range clusterRoles {
rules = append(rules, clusterRole.Rules...)
}
return rules, nil
}
func (am *amOperator) GetUserRules(namespace, username string) ([]rbacv1.PolicyRule, error) {
roles, err := am.GetUserRoles(namespace, username)
if err != nil {
return nil, err
}
rules := make([]rbacv1.PolicyRule, 0)
for _, role := range roles {
rules = append(rules, role.Rules...)
}
return rules, nil
}
func (am *amOperator) GetWorkspaceRoleBindings(workspace string) ([]*rbacv1.ClusterRoleBinding, error) {
clusterRoleBindings, err := am.informers.Rbac().V1().ClusterRoleBindings().Lister().List(labels.Everything())
if err != nil {
klog.Errorln("get cluster role bindings", err)
return nil, err
}
result := make([]*rbacv1.ClusterRoleBinding, 0)
for _, roleBinding := range clusterRoleBindings {
if k8sutil.IsControlledBy(roleBinding.OwnerReferences, "Workspace", workspace) {
result = append(result, roleBinding)
}
}
return result, nil
}
//func (am *amOperator) GetWorkspaceRole(workspace, role string) (*rbacv1.ClusterRole, error) {
// if !sliceutil.HasString(constants.WorkSpaceRoles, role) {
// return nil, apierrors.NewNotFound(schema.GroupResource{Resource: "workspace role"}, role)
// }
// role = fmt.Sprintf("workspace:%s:%s", workspace, strings.TrimPrefix(role, "workspace-"))
// return am.informers.Rbac().V1().ClusterRoles().Lister().Get(role)
//}
func (am *amOperator) GetWorkspaceRoleMap(username string) (map[string]string, error) {
clusterRoleBindings, err := am.informers.Rbac().V1().ClusterRoleBindings().Lister().List(labels.Everything())
if err != nil {
klog.Errorln("get cluster role bindings", err)
return nil, err
}
result := make(map[string]string, 0)
for _, roleBinding := range clusterRoleBindings {
if workspace := k8sutil.GetControlledWorkspace(roleBinding.OwnerReferences); workspace != "" &&
ContainsUser(roleBinding.Subjects, username) {
result[workspace] = roleBinding.RoleRef.Name
}
}
return result, nil
}
func (am *amOperator) GetUserWorkspaceRole(workspace, username string) (*rbacv1.ClusterRole, error) {
workspaceRoleMap, err := am.GetWorkspaceRoleMap(username)
if err != nil {
return nil, err
}
if workspaceRole := workspaceRoleMap[workspace]; workspaceRole != "" {
return am.informers.Rbac().V1().ClusterRoles().Lister().Get(workspaceRole)
}
return nil, apierrors.NewNotFound(schema.GroupResource{Resource: "workspace user"}, username)
}
func (am *amOperator) GetRoleBindings(namespace string, roleName string) ([]*rbacv1.RoleBinding, error) {
roleBindingLister := am.informers.Rbac().V1().RoleBindings().Lister()
roleBindings, err := roleBindingLister.RoleBindings(namespace).List(labels.Everything())
if err != nil {
klog.Errorln(err)
return nil, err
}
items := make([]*rbacv1.RoleBinding, 0)
for _, roleBinding := range roleBindings {
if roleName == "" {
items = append(items, roleBinding)
} else if roleBinding.RoleRef.Name == roleName {
items = append(items, roleBinding)
}
}
return items, nil
}
func (am *amOperator) GetClusterRoleBindings(clusterRoleName string) ([]*rbacv1.ClusterRoleBinding, error) {
clusterRoleBindingLister := am.informers.Rbac().V1().ClusterRoleBindings().Lister()
roleBindings, err := clusterRoleBindingLister.List(labels.Everything())
if err != nil {
klog.Errorln(err)
return nil, err
}
items := make([]*rbacv1.ClusterRoleBinding, 0)
for _, roleBinding := range roleBindings {
if roleBinding.RoleRef.Name == clusterRoleName {
items = append(items, roleBinding)
}
}
return items, nil
}
func (am *amOperator) ListRoles(namespace string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
return am.resources.ListResources(namespace, v1alpha2.Roles, conditions, orderBy, reverse, limit, offset)
}
func (am *amOperator) ListRoleBindings(namespace string, role string) ([]*rbacv1.RoleBinding, error) {
rbs, err := am.informers.Rbac().V1().RoleBindings().Lister().RoleBindings(namespace).List(labels.Everything())
if err != nil {
return nil, err
}
result := make([]*rbacv1.RoleBinding, 0)
for _, rb := range rbs {
if rb.RoleRef.Name == role {
result = append(result, rb.DeepCopy())
}
}
return result, nil
}
func (am *amOperator) ListWorkspaceRoles(workspace string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
conditions.Match[v1alpha2.OwnerName] = workspace
conditions.Match[v1alpha2.OwnerKind] = "Workspace"
result, err := am.resources.ListResources("", v1alpha2.ClusterRoles, conditions, orderBy, reverse, limit, offset)
if err != nil {
return nil, err
}
for i, item := range result.Items {
if role, ok := item.(*rbacv1.ClusterRole); ok {
role = role.DeepCopy()
role.Name = role.Annotations[constants.DisplayNameAnnotationKey]
result.Items[i] = role
}
}
return result, nil
}
func (am *amOperator) ListClusterRoles(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
return am.resources.ListResources("", v1alpha2.ClusterRoles, conditions, orderBy, reverse, limit, offset)
}
func (am *amOperator) GetWorkspaceRoleSimpleRules(workspace, roleName string) []policy.SimpleRule {
workspaceRules := make([]policy.SimpleRule, 0)
switch roleName {
case constants.WorkspaceAdmin:
workspaceRules = []policy.SimpleRule{
{Name: "workspaces", Actions: []string{"edit", "delete", "view"}},
{Name: "members", Actions: []string{"edit", "delete", "create", "view"}},
{Name: "devops", Actions: []string{"edit", "delete", "create", "view"}},
{Name: "projects", Actions: []string{"edit", "delete", "create", "view"}},
{Name: "roles", Actions: []string{"view"}},
{Name: "apps", Actions: []string{"view", "create", "manage"}},
{Name: "repos", Actions: []string{"view", "manage"}},
}
case constants.WorkspaceRegular:
workspaceRules = []policy.SimpleRule{
{Name: "members", Actions: []string{"view"}},
{Name: "devops", Actions: []string{"view", "create"}},
{Name: "projects", Actions: []string{"view", "create"}},
{Name: "apps", Actions: []string{"view", "create"}},
{Name: "repos", Actions: []string{"view"}},
}
case constants.WorkspaceViewer:
workspaceRules = []policy.SimpleRule{
{Name: "workspaces", Actions: []string{"view"}},
{Name: "members", Actions: []string{"view"}},
{Name: "devops", Actions: []string{"view"}},
{Name: "projects", Actions: []string{"view"}},
{Name: "roles", Actions: []string{"view"}},
{Name: "apps", Actions: []string{"view"}},
{Name: "repos", Actions: []string{"view"}},
}
case constants.WorkspacesManager:
workspaceRules = []policy.SimpleRule{
{Name: "workspaces", Actions: []string{"edit", "delete", "view"}},
{Name: "members", Actions: []string{"edit", "delete", "create", "view"}},
{Name: "roles", Actions: []string{"view"}},
}
}
return workspaceRules
}
// Convert cluster role to rules
func (am *amOperator) GetClusterRoleSimpleRules(clusterRoleName string) ([]policy.SimpleRule, error) {
clusterRoleLister := am.informers.Rbac().V1().ClusterRoles().Lister()
clusterRole, err := clusterRoleLister.Get(clusterRoleName)
if err != nil {
klog.Errorln(err)
return nil, err
}
return getClusterSimpleRule(clusterRole.Rules), nil
}
func (am *amOperator) GetUserClusterSimpleRules(username string) ([]policy.SimpleRule, error) {
clusterRules, err := am.GetUserClusterRules(username)
if err != nil {
return nil, err
}
return getClusterSimpleRule(clusterRules), nil
}
// Convert roles to rules
func (am *amOperator) GetRoleSimpleRules(namespace string, roleName string) ([]policy.SimpleRule, error) {
roleLister := am.informers.Rbac().V1().Roles().Lister()
role, err := roleLister.Roles(namespace).Get(roleName)
if err != nil {
klog.Errorln(err)
return nil, err
}
return ConvertToSimpleRule(role.Rules), nil
}
func getClusterSimpleRule(policyRules []rbacv1.PolicyRule) []policy.SimpleRule {
rules := make([]policy.SimpleRule, 0)
for i := 0; i < len(policy.ClusterRoleRuleMapping); i++ {
validActions := make([]string, 0)
for j := 0; j < (len(policy.ClusterRoleRuleMapping[i].Actions)); j++ {
if rulesMatchesAction(policyRules, policy.ClusterRoleRuleMapping[i].Actions[j]) {
validActions = append(validActions, policy.ClusterRoleRuleMapping[i].Actions[j].Name)
}
}
if len(validActions) > 0 {
rules = append(rules, policy.SimpleRule{Name: policy.ClusterRoleRuleMapping[i].Name, Actions: validActions})
}
}
return rules
}
func ConvertToSimpleRule(policyRules []rbacv1.PolicyRule) []policy.SimpleRule {
simpleRules := make([]policy.SimpleRule, 0)
for i := 0; i < len(policy.RoleRuleMapping); i++ {
rule := policy.SimpleRule{Name: policy.RoleRuleMapping[i].Name}
rule.Actions = make([]string, 0)
for j := 0; j < len(policy.RoleRuleMapping[i].Actions); j++ {
if rulesMatchesAction(policyRules, policy.RoleRuleMapping[i].Actions[j]) {
rule.Actions = append(rule.Actions, policy.RoleRuleMapping[i].Actions[j].Name)
}
}
if len(rule.Actions) > 0 {
simpleRules = append(simpleRules, rule)
}
}
return simpleRules
}
func (am *amOperator) CreateClusterRoleBinding(username string, clusterRoleName string) error {
clusterRoleLister := am.informers.Rbac().V1().ClusterRoles().Lister()
_, err := clusterRoleLister.Get(clusterRoleName)
if err != nil {
klog.Errorln(err)
return err
}
// TODO move to user controller
if clusterRoleName == constants.ClusterAdmin {
// create kubectl pod if cluster role is cluster-admin
//if err := kubectl.CreateKubectlDeploy(username); err != nil {
// klog.Error("create user terminal pod failed", username, err)
//}
} else {
// delete kubectl pod if cluster role is not cluster-admin, whether it exists or not
//if err := kubectl.DelKubectlDeploy(username); err != nil {
// klog.Error("delete user terminal pod failed", username, err)
//}
}
clusterRoleBinding := &rbacv1.ClusterRoleBinding{}
clusterRoleBinding.Name = username
clusterRoleBinding.RoleRef = rbacv1.RoleRef{Name: clusterRoleName, Kind: ClusterRoleKind}
clusterRoleBinding.Subjects = []rbacv1.Subject{{Kind: rbacv1.UserKind, Name: username}}
clusterRoleBindingLister := am.informers.Rbac().V1().ClusterRoleBindings().Lister()
found, err := clusterRoleBindingLister.Get(username)
if apierrors.IsNotFound(err) {
_, err = am.kubeClient.RbacV1().ClusterRoleBindings().Create(clusterRoleBinding)
if err != nil {
klog.Errorln("create cluster role binding", err)
return err
}
return nil
} else if err != nil {
return err
}
// cluster role changed
if found.RoleRef.Name != clusterRoleName {
deletePolicy := metav1.DeletePropagationBackground
gracePeriodSeconds := int64(0)
deleteOption := &metav1.DeleteOptions{PropagationPolicy: &deletePolicy, GracePeriodSeconds: &gracePeriodSeconds}
err = am.kubeClient.RbacV1().ClusterRoleBindings().Delete(found.Name, deleteOption)
if err != nil {
klog.Errorln(err)
return err
}
_, err = am.kubeClient.RbacV1().ClusterRoleBindings().Create(clusterRoleBinding)
if err != nil {
klog.Errorln(err)
return err
}
return nil
}
if !ContainsUser(found.Subjects, username) {
found.Subjects = clusterRoleBinding.Subjects
_, err = am.kubeClient.RbacV1().ClusterRoleBindings().Update(found)
if err != nil {
klog.Errorln("update cluster role binding", err)
return err
}
}
return nil
}

100
pkg/models/iam/am/am.go Normal file
View File

@@ -0,0 +1,100 @@
/*
*
* Copyright 2020 The KubeSphere Authors.
*
* 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 am
import (
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/clusterrole"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/resource"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2/role"
)
const (
ClusterRoleKind = "ClusterRole"
NamespaceAdminRoleBindName = "admin"
NamespaceViewerRoleBindName = "viewer"
)
type AccessManagementInterface interface {
GetPlatformRole(username string) (Role, error)
GetClusterRole(cluster, username string) (Role, error)
GetWorkspaceRole(workspace, username string) (Role, error)
GetNamespaceRole(namespace, username string) (Role, error)
GetDevOpsRole(project, username string) (Role, error)
}
type Role interface {
GetName() string
GetRego() string
}
type amOperator struct {
informers informers.SharedInformerFactory
resources resource.ResourceGetter
kubeClient kubernetes.Interface
}
func (am *amOperator) ListClusterRoleBindings(clusterRole string) ([]*rbacv1.ClusterRoleBinding, error) {
panic("implement me")
}
func (am *amOperator) GetRoles(namespace, username string) ([]*rbacv1.Role, error) {
panic("implement me")
}
func (am *amOperator) GetClusterPolicyRules(username string) ([]rbacv1.PolicyRule, error) {
panic("implement me")
}
func (am *amOperator) GetPolicyRules(namespace, username string) ([]rbacv1.PolicyRule, error) {
panic("implement me")
}
func (am *amOperator) GetWorkspaceRole(workspace, username string) (Role, error) {
panic("implement me")
}
func NewAMOperator(kubeClient kubernetes.Interface, informers informers.SharedInformerFactory) AccessManagementInterface {
resourceGetter := resource.ResourceGetter{}
resourceGetter.Add(v1alpha2.Role, role.NewRoleSearcher(informers))
resourceGetter.Add(v1alpha2.ClusterRoles, clusterrole.NewClusterRoleSearcher(informers))
return &amOperator{
informers: informers,
resources: resourceGetter,
kubeClient: kubeClient,
}
}
func (am *amOperator) GetPlatformRole(username string) (Role, error) {
panic("implement me")
}
func (am *amOperator) GetClusterRole(cluster, username string) (Role, error) {
panic("implement me")
}
func (am *amOperator) GetNamespaceRole(namespace, username string) (Role, error) {
panic("implement me")
}
func (am *amOperator) GetDevOpsRole(namespace, username string) (Role, error) {
panic("implement me")
}

View File

@@ -15,7 +15,7 @@
* limitations under the License.
* /
*/
package iam
package im
import (
"fmt"

View File

@@ -16,4 +16,4 @@
* /
*/
package iam
package im

File diff suppressed because it is too large Load Diff

View File

@@ -1,213 +0,0 @@
/*
*
* Copyright 2020 The KubeSphere Authors.
*
* 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 iam
import (
rbacv1 "k8s.io/api/rbac/v1"
"kubesphere.io/kubesphere/pkg/api/iam"
"kubesphere.io/kubesphere/pkg/models/iam/policy"
"strings"
)
func RulesMatchesRequired(rules []rbacv1.PolicyRule, required rbacv1.PolicyRule) bool {
for _, rule := range rules {
if ruleMatchesRequired(rule, required) {
return true
}
}
return false
}
func rulesMatchesAction(rules []rbacv1.PolicyRule, action policy.Action) bool {
for _, required := range action.Rules {
if !RulesMatchesRequired(rules, required) {
return false
}
}
return true
}
func ruleMatchesRequired(rule rbacv1.PolicyRule, required rbacv1.PolicyRule) bool {
if len(required.NonResourceURLs) == 0 {
for _, apiGroup := range required.APIGroups {
for _, resource := range required.Resources {
resources := strings.Split(resource, "/")
resource = resources[0]
var subsource string
if len(resources) > 1 {
subsource = resources[1]
}
if len(required.ResourceNames) == 0 {
for _, verb := range required.Verbs {
if !ruleMatchesRequest(rule, apiGroup, "", resource, subsource, "", verb) {
return false
}
}
} else {
for _, resourceName := range required.ResourceNames {
for _, verb := range required.Verbs {
if !ruleMatchesRequest(rule, apiGroup, "", resource, subsource, resourceName, verb) {
return false
}
}
}
}
}
}
} else {
for _, apiGroup := range required.APIGroups {
for _, nonResourceURL := range required.NonResourceURLs {
for _, verb := range required.Verbs {
if !ruleMatchesRequest(rule, apiGroup, nonResourceURL, "", "", "", verb) {
return false
}
}
}
}
}
return true
}
func ruleMatchesResources(rule rbacv1.PolicyRule, apiGroup string, resource string, subresource string, resourceName string) bool {
if resource == "" {
return false
}
if !hasString(rule.APIGroups, apiGroup) && !hasString(rule.APIGroups, rbacv1.ResourceAll) {
return false
}
if len(rule.ResourceNames) > 0 && !hasString(rule.ResourceNames, resourceName) {
return false
}
combinedResource := resource
if subresource != "" {
combinedResource = combinedResource + "/" + subresource
}
for _, res := range rule.Resources {
// match "*"
if res == rbacv1.ResourceAll || res == combinedResource {
return true
}
// match "*/subresource"
if len(subresource) > 0 && strings.HasPrefix(res, "*/") && subresource == strings.TrimLeft(res, "*/") {
return true
}
// match "resource/*"
if strings.HasSuffix(res, "/*") && resource == strings.TrimRight(res, "/*") {
return true
}
}
return false
}
func ruleMatchesRequest(rule rbacv1.PolicyRule, apiGroup string, nonResourceURL string, resource string, subresource string, resourceName string, verb string) bool {
if !hasString(rule.Verbs, verb) && !hasString(rule.Verbs, rbacv1.VerbAll) {
return false
}
if nonResourceURL == "" {
return ruleMatchesResources(rule, apiGroup, resource, subresource, resourceName)
} else {
return ruleMatchesNonResource(rule, nonResourceURL)
}
}
func ruleMatchesNonResource(rule rbacv1.PolicyRule, nonResourceURL string) bool {
if nonResourceURL == "" {
return false
}
for _, spec := range rule.NonResourceURLs {
if pathMatches(nonResourceURL, spec) {
return true
}
}
return false
}
func pathMatches(path, spec string) bool {
// Allow wildcard match
if spec == "*" {
return true
}
// Allow exact match
if spec == path {
return true
}
// Allow a trailing * subpath match
if strings.HasSuffix(spec, "*") && strings.HasPrefix(path, strings.TrimRight(spec, "*")) {
return true
}
return false
}
func hasString(slice []string, value string) bool {
for _, s := range slice {
if s == value {
return true
}
}
return false
}
func ContainsUser(subjects interface{}, username string) bool {
switch subjects.(type) {
case []*rbacv1.Subject:
for _, subject := range subjects.([]*rbacv1.Subject) {
if subject.Kind == rbacv1.UserKind && subject.Name == username {
return true
}
}
case []rbacv1.Subject:
for _, subject := range subjects.([]rbacv1.Subject) {
if subject.Kind == rbacv1.UserKind && subject.Name == username {
return true
}
}
case []iam.User:
for _, u := range subjects.([]iam.User) {
if u.Username == username {
return true
}
}
case []*iam.User:
for _, u := range subjects.([]*iam.User) {
if u.Username == username {
return true
}
}
}
return false
}

View File

@@ -26,7 +26,6 @@ import (
"kubesphere.io/kubesphere/pkg/db"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/models/devops"
"kubesphere.io/kubesphere/pkg/models/iam/policy"
"kubesphere.io/kubesphere/pkg/server/params"
dsClient "kubesphere.io/kubesphere/pkg/simple/client/devops"
"kubesphere.io/kubesphere/pkg/simple/client/mysql"
@@ -38,7 +37,6 @@ type DevOpsProjectOperator interface {
CreateDevOpsProject(username string, workspace string, req *v1alpha2.DevOpsProject) (*v1alpha2.DevOpsProject, error)
GetDevOpsProjectsCount(username string) (uint32, error)
DeleteDevOpsProject(projectId, username string) error
GetUserDevOpsSimpleRules(username, projectId string) ([]policy.SimpleRule, error)
}
type devopsProjectOperator struct {
@@ -208,16 +206,6 @@ func (o *devopsProjectOperator) CreateDevOpsProject(username string, workspace s
return project, nil
}
func (o *devopsProjectOperator) GetUserDevOpsSimpleRules(username, projectId string) ([]policy.SimpleRule, error) {
role, err := o.getProjectUserRole(username, projectId)
if err != nil {
klog.Errorf("%+v", err)
return nil, restful.NewError(http.StatusForbidden, err.Error())
}
return GetDevopsRoleSimpleRules(role), nil
}
func (o *devopsProjectOperator) getProjectUserRole(username, projectId string) (string, error) {
if username == devops.KS_ADMIN {
return dsClient.ProjectOwner, nil
@@ -235,47 +223,3 @@ func (o *devopsProjectOperator) getProjectUserRole(username, projectId string) (
return membership.Role, nil
}
func GetDevopsRoleSimpleRules(role string) []policy.SimpleRule {
var rules []policy.SimpleRule
switch role {
case "developer":
rules = []policy.SimpleRule{
{Name: "pipelines", Actions: []string{"view", "trigger"}},
{Name: "roles", Actions: []string{"view"}},
{Name: "members", Actions: []string{"view"}},
{Name: "devops", Actions: []string{"view"}},
}
break
case "owner":
rules = []policy.SimpleRule{
{Name: "pipelines", Actions: []string{"create", "edit", "view", "delete", "trigger"}},
{Name: "roles", Actions: []string{"view"}},
{Name: "members", Actions: []string{"create", "edit", "view", "delete"}},
{Name: "credentials", Actions: []string{"create", "edit", "view", "delete"}},
{Name: "devops", Actions: []string{"edit", "view", "delete"}},
}
break
case "maintainer":
rules = []policy.SimpleRule{
{Name: "pipelines", Actions: []string{"create", "edit", "view", "delete", "trigger"}},
{Name: "roles", Actions: []string{"view"}},
{Name: "members", Actions: []string{"view"}},
{Name: "credentials", Actions: []string{"create", "edit", "view", "delete"}},
{Name: "devops", Actions: []string{"view"}},
}
break
case "reporter":
fallthrough
default:
rules = []policy.SimpleRule{
{Name: "pipelines", Actions: []string{"view"}},
{Name: "roles", Actions: []string{"view"}},
{Name: "members", Actions: []string{"view"}},
{Name: "devops", Actions: []string{"view"}},
}
break
}
return rules
}

View File

@@ -19,17 +19,13 @@ package tenant
import (
"k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/labels"
k8sinformers "k8s.io/client-go/informers"
kubernetes "k8s.io/client-go/kubernetes"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/iam"
am2 "kubesphere.io/kubesphere/pkg/models/iam/am"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
)
@@ -41,7 +37,7 @@ type NamespaceInterface interface {
type namespaceSearcher struct {
k8s kubernetes.Interface
informers k8sinformers.SharedInformerFactory
am iam.AccessManagementInterface
am am2.AccessManagementInterface
}
func (s *namespaceSearcher) CreateNamespace(workspace string, namespace *v1.Namespace, username string) (*v1.Namespace, error) {
@@ -57,7 +53,7 @@ func (s *namespaceSearcher) CreateNamespace(workspace string, namespace *v1.Name
return s.k8s.CoreV1().Namespaces().Create(namespace)
}
func newNamespaceOperator(k8s kubernetes.Interface, informers k8sinformers.SharedInformerFactory, am iam.AccessManagementInterface) NamespaceInterface {
func newNamespaceOperator(k8s kubernetes.Interface, informers k8sinformers.SharedInformerFactory, am am2.AccessManagementInterface) NamespaceInterface {
return &namespaceSearcher{k8s: k8s, informers: informers, am: am}
}
@@ -111,76 +107,9 @@ func (s *namespaceSearcher) compare(a, b *v1.Namespace, orderBy string) bool {
}
func (s *namespaceSearcher) GetNamespaces(username string) ([]*v1.Namespace, error) {
roles, err := s.am.GetRoles("", username)
if err != nil {
return nil, err
}
namespaces := make([]*v1.Namespace, 0)
namespaceLister := s.informers.Core().V1().Namespaces().Lister()
for _, role := range roles {
namespace, err := namespaceLister.Get(role.Namespace)
if err != nil {
klog.Errorf("get namespace failed: %+v", err)
return nil, err
}
if !containsNamespace(namespaces, namespace) {
namespaces = append(namespaces, namespace)
}
}
return namespaces, nil
}
func containsNamespace(namespaces []*v1.Namespace, namespace *v1.Namespace) bool {
for _, item := range namespaces {
if item.Name == namespace.Name {
return true
}
}
return false
panic("implement me")
}
func (s *namespaceSearcher) Search(username string, conditions *params.Conditions, orderBy string, reverse bool) ([]*v1.Namespace, error) {
rules, err := s.am.GetClusterPolicyRules(username)
if err != nil {
return nil, err
}
namespaces := make([]*v1.Namespace, 0)
if iam.RulesMatchesRequired(rules, rbacv1.PolicyRule{Verbs: []string{"list"}, APIGroups: []string{"tenant.kubesphere.io"}, Resources: []string{"namespaces"}}) {
namespaces, err = s.informers.Core().V1().Namespaces().Lister().List(labels.Everything())
} else {
namespaces, err = s.GetNamespaces(username)
}
if err != nil {
return nil, err
}
result := make([]*v1.Namespace, 0)
for _, namespace := range namespaces {
if s.match(conditions.Match, namespace) && s.fuzzy(conditions.Fuzzy, namespace) {
result = append(result, namespace)
}
}
// order & reverse
sort.Slice(result, func(i, j int) bool {
if reverse {
i, j = j, i
}
return s.compare(result[i], result[j], orderBy)
})
return result, nil
}
func CreateNamespace() {
panic("implement me")
}

View File

@@ -19,20 +19,14 @@ package tenant
import (
"k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
k8sinformers "k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
ksinformers "kubesphere.io/kubesphere/pkg/client/informers/externalversions"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/models/iam"
"kubesphere.io/kubesphere/pkg/models/iam/policy"
am2 "kubesphere.io/kubesphere/pkg/models/iam/am"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/simple/client/mysql"
"strconv"
)
type Interface interface {
@@ -42,17 +36,14 @@ type Interface interface {
ListWorkspaces(username string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error)
ListNamespaces(username string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error)
ListDevopsProjects(username string, conditions *params.Conditions, orderBy string, reverse bool, limit int, offset int) (*models.PageableResponse, error)
GetWorkspaceSimpleRules(workspace, username string) ([]policy.SimpleRule, error)
GetNamespaceSimpleRules(namespace, username string) ([]policy.SimpleRule, error)
CountDevOpsProjects(username string) (uint32, error)
DeleteDevOpsProject(username, projectId string) error
GetUserDevopsSimpleRules(username string, devops string) (interface{}, error)
}
type tenantOperator struct {
workspaces WorkspaceInterface
namespaces NamespaceInterface
am iam.AccessManagementInterface
am am2.AccessManagementInterface
devops DevOpsProjectOperator
}
@@ -65,7 +56,7 @@ func (t *tenantOperator) DeleteDevOpsProject(username, projectId string) error {
}
func (t *tenantOperator) GetUserDevopsSimpleRules(username string, projectId string) (interface{}, error) {
return t.devops.GetUserDevOpsSimpleRules(username, projectId)
panic("implement me")
}
func (t *tenantOperator) ListDevopsProjects(username string, conditions *params.Conditions, orderBy string, reverse bool, limit int, offset int) (*models.PageableResponse, error) {
@@ -77,7 +68,7 @@ func (t *tenantOperator) DeleteNamespace(workspace, namespace string) error {
}
func New(client kubernetes.Interface, informers k8sinformers.SharedInformerFactory, ksinformers ksinformers.SharedInformerFactory, db *mysql.Database) Interface {
amOperator := iam.NewAMOperator(client, informers)
amOperator := am2.NewAMOperator(client, informers)
return &tenantOperator{
workspaces: newWorkspaceOperator(client, informers, ksinformers, amOperator, db),
namespaces: newNamespaceOperator(client, informers, amOperator),
@@ -96,105 +87,11 @@ func (t *tenantOperator) DescribeWorkspace(username, workspaceName string) (*v1a
return nil, err
}
if username != "" {
workspace = t.appendAnnotations(username, workspace)
}
return workspace, nil
}
func (t *tenantOperator) ListWorkspaces(username string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
workspaces, err := t.workspaces.SearchWorkspace(username, conditions, orderBy, reverse)
if err != nil {
return nil, err
}
// limit offset
result := make([]interface{}, 0)
for i, workspace := range workspaces {
if len(result) < limit && i >= offset {
workspace := t.appendAnnotations(username, workspace)
result = append(result, workspace)
}
}
return &models.PageableResponse{Items: result, TotalCount: len(workspaces)}, nil
}
func (t *tenantOperator) GetWorkspaceSimpleRules(workspace, username string) ([]policy.SimpleRule, error) {
clusterRules, err := t.am.GetClusterPolicyRules(username)
if err != nil {
return nil, err
}
// cluster-admin
if iam.RulesMatchesRequired(clusterRules, rbacv1.PolicyRule{
Verbs: []string{"*"},
APIGroups: []string{"*"},
Resources: []string{"*"},
}) {
return t.am.GetWorkspaceRoleSimpleRules(workspace, constants.WorkspaceAdmin), nil
}
workspaceRole, err := t.am.GetWorkspaceRole(workspace, username)
// workspaces-manager
if iam.RulesMatchesRequired(clusterRules, rbacv1.PolicyRule{
Verbs: []string{"*"},
APIGroups: []string{"*"},
Resources: []string{"workspaces", "workspaces/*"},
}) {
return t.am.GetWorkspaceRoleSimpleRules(workspace, constants.WorkspacesManager), nil
}
if err != nil {
if apierrors.IsNotFound(err) {
return []policy.SimpleRule{}, nil
}
klog.Error(err)
return nil, err
}
return t.am.GetWorkspaceRoleSimpleRules(workspace, workspaceRole.Annotations[constants.DisplayNameAnnotationKey]), nil
}
func (t *tenantOperator) GetNamespaceSimpleRules(namespace, username string) ([]policy.SimpleRule, error) {
clusterRules, err := t.am.GetClusterPolicyRules(username)
if err != nil {
return nil, err
}
rules, err := t.am.GetPolicyRules(namespace, username)
if err != nil {
return nil, err
}
rules = append(rules, clusterRules...)
return iam.ConvertToSimpleRule(rules), nil
}
func (t *tenantOperator) appendAnnotations(username string, workspace *v1alpha1.Workspace) *v1alpha1.Workspace {
workspace = workspace.DeepCopy()
if workspace.Annotations == nil {
workspace.Annotations = make(map[string]string)
}
if ns, err := t.ListNamespaces(username, &params.Conditions{Match: map[string]string{constants.WorkspaceLabelKey: workspace.Name}}, "", false, 1, 0); err == nil {
workspace.Annotations["kubesphere.io/namespace-count"] = strconv.Itoa(ns.TotalCount)
}
if devops, err := t.ListDevopsProjects(username, &params.Conditions{Match: map[string]string{"workspace": workspace.Name}}, "", false, 1, 0); err == nil {
workspace.Annotations["kubesphere.io/devops-count"] = strconv.Itoa(devops.TotalCount)
}
userCount, err := t.workspaces.CountUsersInWorkspace(workspace.Name)
if err == nil {
workspace.Annotations["kubesphere.io/member-count"] = strconv.Itoa(userCount)
}
return workspace
panic("implement me")
}
func (t *tenantOperator) ListNamespaces(username string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {

View File

@@ -18,27 +18,22 @@
package tenant
import (
"fmt"
core "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"k8s.io/client-go/informers"
"k8s.io/client-go/kubernetes"
"k8s.io/klog"
"kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
"kubesphere.io/kubesphere/pkg/client/informers/externalversions"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/db"
"kubesphere.io/kubesphere/pkg/models/devops"
"kubesphere.io/kubesphere/pkg/models/iam"
am2 "kubesphere.io/kubesphere/pkg/models/iam/am"
"kubesphere.io/kubesphere/pkg/models/resources/v1alpha2"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/simple/client/mysql"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort"
"strings"
"k8s.io/api/rbac/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
@@ -69,14 +64,14 @@ type workspaceOperator struct {
client kubernetes.Interface
informers informers.SharedInformerFactory
ksInformers externalversions.SharedInformerFactory
am iam.AccessManagementInterface
am am2.AccessManagementInterface
// TODO: use db interface instead of mysql client
// we can refactor this after rewrite devops using crd
db *mysql.Database
}
func newWorkspaceOperator(client kubernetes.Interface, informers informers.SharedInformerFactory, ksinformers externalversions.SharedInformerFactory, am iam.AccessManagementInterface, db *mysql.Database) WorkspaceInterface {
func newWorkspaceOperator(client kubernetes.Interface, informers informers.SharedInformerFactory, ksinformers externalversions.SharedInformerFactory, am am2.AccessManagementInterface, db *mysql.Database) WorkspaceInterface {
return &workspaceOperator{
client: client,
informers: informers,
@@ -111,96 +106,12 @@ func (w *workspaceOperator) DeleteNamespace(workspace string, namespace string)
}
func (w *workspaceOperator) RemoveUser(workspace string, username string) error {
workspaceRole, err := w.am.GetWorkspaceRole(workspace, username)
if err != nil {
return err
}
err = w.deleteWorkspaceRoleBinding(workspace, username, workspaceRole.Annotations[constants.DisplayNameAnnotationKey])
if err != nil {
return err
}
return nil
panic("implement me")
}
func (w *workspaceOperator) AddUser(workspaceName string, user *InWorkspaceUser) error {
workspaceRole, err := w.am.GetWorkspaceRole(workspaceName, user.Username)
if err != nil && !apierrors.IsNotFound(err) {
klog.Errorf("get workspace role failed: %+v", err)
return err
}
workspaceRoleName := fmt.Sprintf("workspace:%s:%s", workspaceName, strings.TrimPrefix(user.WorkspaceRole, "workspace-"))
var currentWorkspaceRoleName string
if workspaceRole != nil {
currentWorkspaceRoleName = workspaceRole.Name
}
if currentWorkspaceRoleName != workspaceRoleName && currentWorkspaceRoleName != "" {
err := w.deleteWorkspaceRoleBinding(workspaceName, user.Username, workspaceRole.Annotations[constants.DisplayNameAnnotationKey])
if err != nil {
klog.Errorf("delete workspace role binding failed: %+v", err)
return err
}
} else if currentWorkspaceRoleName != "" {
return nil
}
return w.createWorkspaceRoleBinding(workspaceName, user.Username, user.WorkspaceRole)
}
func (w *workspaceOperator) createWorkspaceRoleBinding(workspace, username string, role string) error {
if !sliceutil.HasString(constants.WorkSpaceRoles, role) {
return apierrors.NewNotFound(schema.GroupResource{Resource: "workspace role"}, role)
}
roleBindingName := fmt.Sprintf("workspace:%s:%s", workspace, strings.TrimPrefix(role, "workspace-"))
workspaceRoleBinding, err := w.informers.Rbac().V1().ClusterRoleBindings().Lister().Get(roleBindingName)
if err != nil {
return err
}
if !iam.ContainsUser(workspaceRoleBinding.Subjects, username) {
workspaceRoleBinding = workspaceRoleBinding.DeepCopy()
workspaceRoleBinding.Subjects = append(workspaceRoleBinding.Subjects, v1.Subject{APIGroup: "rbac.authorization.k8s.io", Kind: "User", Name: username})
_, err = w.client.RbacV1().ClusterRoleBindings().Update(workspaceRoleBinding)
if err != nil {
klog.Errorf("update workspace role binding failed: %+v", err)
return err
}
}
return nil
}
func (w *workspaceOperator) deleteWorkspaceRoleBinding(workspace, username string, role string) error {
if !sliceutil.HasString(constants.WorkSpaceRoles, role) {
return apierrors.NewNotFound(schema.GroupResource{Resource: "workspace role"}, role)
}
roleBindingName := fmt.Sprintf("workspace:%s:%s", workspace, strings.TrimPrefix(role, "workspace-"))
workspaceRoleBinding, err := w.informers.Rbac().V1().ClusterRoleBindings().Lister().Get(roleBindingName)
if err != nil {
return err
}
workspaceRoleBinding = workspaceRoleBinding.DeepCopy()
for i, v := range workspaceRoleBinding.Subjects {
if v.Kind == v1.UserKind && v.Name == username {
workspaceRoleBinding.Subjects = append(workspaceRoleBinding.Subjects[:i], workspaceRoleBinding.Subjects[i+1:]...)
i--
}
}
workspaceRoleBinding, err = w.client.RbacV1().ClusterRoleBindings().Update(workspaceRoleBinding)
return err
panic("implement me")
}
func (w *workspaceOperator) CountDevopsProjectsInWorkspace(workspaceName string) (int, error) {
@@ -288,50 +199,7 @@ func (*workspaceOperator) compare(a, b *v1alpha1.Workspace, orderBy string) bool
}
func (w *workspaceOperator) SearchWorkspace(username string, conditions *params.Conditions, orderBy string, reverse bool) ([]*v1alpha1.Workspace, error) {
rules, err := w.am.GetClusterPolicyRules(username)
if err != nil {
return nil, err
}
workspaces := make([]*v1alpha1.Workspace, 0)
if iam.RulesMatchesRequired(rules, rbacv1.PolicyRule{Verbs: []string{"list"}, APIGroups: []string{"tenant.kubesphere.io"}, Resources: []string{"workspaces"}}) {
workspaces, err = w.ksInformers.Tenant().V1alpha1().Workspaces().Lister().List(labels.Everything())
if err != nil {
return nil, err
}
} else {
workspaceRoles, err := w.am.GetWorkspaceRoleMap(username)
if err != nil {
return nil, err
}
for k := range workspaceRoles {
workspace, err := w.ksInformers.Tenant().V1alpha1().Workspaces().Lister().Get(k)
if err != nil {
return nil, err
}
workspaces = append(workspaces, workspace)
}
}
result := make([]*v1alpha1.Workspace, 0)
for _, workspace := range workspaces {
if w.match(conditions.Match, workspace) && w.fuzzy(conditions.Fuzzy, workspace) {
result = append(result, workspace)
}
}
// order & reverse
sort.Slice(result, func(i, j int) bool {
if reverse {
i, j = j, i
}
return w.compare(result[i], result[j], orderBy)
})
return result, nil
panic("implement me")
}
func (w *workspaceOperator) GetWorkspace(workspaceName string) (*v1alpha1.Workspace, error) {