@@ -36,6 +36,7 @@ const (
|
||||
|
||||
WorkspaceLabelKey = "kubesphere.io/workspace"
|
||||
DisplayNameAnnotationKey = "displayName"
|
||||
DescriptionAnnotationKey = "desc"
|
||||
CreatorLabelAnnotationKey = "creator"
|
||||
OpenPitrixRuntimeAnnotationKey = "openpitrix_runtime"
|
||||
WorkspaceAdmin = "workspace-admin"
|
||||
|
||||
@@ -40,7 +40,7 @@ import (
|
||||
)
|
||||
|
||||
var (
|
||||
log = logf.Log.WithName("controller")
|
||||
log = logf.Log.WithName("clusterrolebinding-controller")
|
||||
)
|
||||
|
||||
/**
|
||||
|
||||
@@ -272,9 +272,7 @@ func (v *JobController) getCurrentRevision(item *batchv1.Job) JobRevision {
|
||||
revision.Status = Failed
|
||||
revision.Reasons = append(revision.Reasons, condition.Reason)
|
||||
revision.Messages = append(revision.Messages, condition.Message)
|
||||
}
|
||||
|
||||
if condition.Type == batchv1.JobComplete && condition.Status == v1.ConditionTrue {
|
||||
} else if condition.Type == batchv1.JobComplete && condition.Status == v1.ConditionTrue {
|
||||
revision.Status = Completed
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,13 +45,19 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||
)
|
||||
|
||||
const (
|
||||
adminDescription = "Allows admin access to perform any action on any resource, it gives full control over every resource in the namespace."
|
||||
operatorDescription = "The maintainer of the namespace who can manage resources other than users and roles in the namespace."
|
||||
viewerDescription = "Allows viewer access to view all resources in the namespace."
|
||||
)
|
||||
|
||||
var (
|
||||
log = logf.Log.WithName("controller")
|
||||
log = logf.Log.WithName("namespace-controller")
|
||||
defaultRoles = []rbac.Role{
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "admin"}, Rules: []rbac.PolicyRule{{Verbs: []string{"*"}, APIGroups: []string{"*"}, Resources: []string{"*"}}}},
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "operator"}, Rules: []rbac.PolicyRule{{Verbs: []string{"get", "list", "watch"}, APIGroups: []string{"*"}, Resources: []string{"*"}},
|
||||
{Verbs: []string{"*"}, APIGroups: []string{"", "apps", "extensions", "batch", "logging.kubesphere.io", "monitoring.kubesphere.io", "iam.kubesphere.io", "resources.kubesphere.io", "autoscaling"}, Resources: []string{"*"}}}},
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "viewer"}, Rules: []rbac.PolicyRule{{Verbs: []string{"get", "list", "watch"}, APIGroups: []string{"*"}, Resources: []string{"*"}}}},
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "admin", Annotations: map[string]string{constants.DescriptionAnnotationKey: adminDescription}}, Rules: []rbac.PolicyRule{{Verbs: []string{"*"}, APIGroups: []string{"*"}, Resources: []string{"*"}}}},
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "operator", Annotations: map[string]string{constants.DescriptionAnnotationKey: operatorDescription}}, Rules: []rbac.PolicyRule{{Verbs: []string{"get", "list", "watch"}, APIGroups: []string{"*"}, Resources: []string{"*"}},
|
||||
{Verbs: []string{"*"}, APIGroups: []string{"", "apps", "extensions", "batch", "logging.kubesphere.io", "monitoring.kubesphere.io", "iam.kubesphere.io", "resources.kubesphere.io", "autoscaling", "alerting.kubesphere.io"}, Resources: []string{"*"}}}},
|
||||
{ObjectMeta: metav1.ObjectMeta{Name: "viewer", Annotations: map[string]string{constants.DescriptionAnnotationKey: viewerDescription}}, Rules: []rbac.PolicyRule{{Verbs: []string{"get", "list", "watch"}, APIGroups: []string{"*"}, Resources: []string{"*"}}}},
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -21,8 +21,11 @@ package workspace
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
rbac "k8s.io/api/rbac/v1"
|
||||
"k8s.io/apimachinery/pkg/api/errors"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/apimachinery/pkg/types"
|
||||
"k8s.io/client-go/tools/record"
|
||||
@@ -42,7 +45,13 @@ import (
|
||||
"sigs.k8s.io/controller-runtime/pkg/source"
|
||||
)
|
||||
|
||||
var log = logf.Log.WithName("controller")
|
||||
const (
|
||||
workspaceAdminDescription = "Allows admin access to perform any action on any resource, it gives full control over every resource in the workspace."
|
||||
workspaceRegularDescription = "Normal user in the workspace, can create namespace and DevOps project."
|
||||
workspaceViewerDescription = "Allows viewer access to view all resources in the workspace."
|
||||
)
|
||||
|
||||
var log = logf.Log.WithName("workspace-controller")
|
||||
|
||||
/**
|
||||
* USER ACTION REQUIRED: This is a scaffold file intended for the user to modify with their own Controller
|
||||
@@ -161,6 +170,10 @@ func (r *ReconcileWorkspace) Reconcile(request reconcile.Request) (reconcile.Res
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
if err = r.bindNamespaces(instance); err != nil {
|
||||
return reconcile.Result{}, err
|
||||
}
|
||||
|
||||
return reconcile.Result{}, nil
|
||||
}
|
||||
|
||||
@@ -442,6 +455,33 @@ func (r *ReconcileWorkspace) createWorkspaceRoleBindings(instance *tenantv1alpha
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *ReconcileWorkspace) bindNamespaces(instance *tenantv1alpha1.Workspace) error {
|
||||
|
||||
nsList := &corev1.NamespaceList{}
|
||||
options := client.ListOptions{LabelSelector: labels.SelectorFromSet(labels.Set{constants.WorkspaceLabelKey: instance.Name})}
|
||||
err := r.List(context.TODO(), &options, nsList)
|
||||
|
||||
if err != nil {
|
||||
log.Error(err, fmt.Sprintf("list workspace %s namespace failed", instance.Name))
|
||||
return err
|
||||
}
|
||||
|
||||
for _, namespace := range nsList.Items {
|
||||
if !metav1.IsControlledBy(&namespace, instance) {
|
||||
if err := controllerutil.SetControllerReference(instance, &namespace, r.scheme); err != nil {
|
||||
return err
|
||||
}
|
||||
log.Info("Bind workspace", "namespace", namespace.Name, "workspace", instance.Name)
|
||||
err = r.Update(context.TODO(), &namespace)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func hasSubject(subjects []rbac.Subject, user rbac.Subject) bool {
|
||||
for _, subject := range subjects {
|
||||
if reflect.DeepEqual(subject, user) {
|
||||
@@ -477,7 +517,7 @@ func getWorkspaceAdmin(workspaceName string) *rbac.ClusterRole {
|
||||
admin := &rbac.ClusterRole{}
|
||||
admin.Name = getWorkspaceAdminRoleName(workspaceName)
|
||||
admin.Labels = map[string]string{constants.WorkspaceLabelKey: workspaceName}
|
||||
admin.Annotations = map[string]string{constants.DisplayNameAnnotationKey: constants.WorkspaceAdmin}
|
||||
admin.Annotations = map[string]string{constants.DisplayNameAnnotationKey: constants.WorkspaceAdmin, constants.DescriptionAnnotationKey: workspaceAdminDescription}
|
||||
admin.Rules = []rbac.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"*"},
|
||||
@@ -499,7 +539,7 @@ func getWorkspaceRegular(workspaceName string) *rbac.ClusterRole {
|
||||
regular := &rbac.ClusterRole{}
|
||||
regular.Name = getWorkspaceRegularRoleName(workspaceName)
|
||||
regular.Labels = map[string]string{constants.WorkspaceLabelKey: workspaceName}
|
||||
regular.Annotations = map[string]string{constants.DisplayNameAnnotationKey: constants.WorkspaceRegular}
|
||||
regular.Annotations = map[string]string{constants.DisplayNameAnnotationKey: constants.WorkspaceRegular, constants.DescriptionAnnotationKey: workspaceRegularDescription}
|
||||
regular.Rules = []rbac.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
@@ -527,7 +567,7 @@ func getWorkspaceViewer(workspaceName string) *rbac.ClusterRole {
|
||||
viewer := &rbac.ClusterRole{}
|
||||
viewer.Name = getWorkspaceViewerRoleName(workspaceName)
|
||||
viewer.Labels = map[string]string{constants.WorkspaceLabelKey: workspaceName}
|
||||
viewer.Annotations = map[string]string{constants.DisplayNameAnnotationKey: constants.WorkspaceViewer}
|
||||
viewer.Annotations = map[string]string{constants.DisplayNameAnnotationKey: constants.WorkspaceViewer, constants.DescriptionAnnotationKey: workspaceViewerDescription}
|
||||
viewer.Rules = []rbac.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
|
||||
@@ -509,16 +509,13 @@ func GetWorkspaceRoleSimpleRules(workspace, roleName string) []models.SimpleRule
|
||||
{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: "organizations", Actions: []string{"edit", "delete", "create", "view"}},
|
||||
{Name: "roles", Actions: []string{"view"}},
|
||||
}
|
||||
case constants.WorkspaceRegular:
|
||||
workspaceRules = []models.SimpleRule{
|
||||
{Name: "workspaces", Actions: []string{"view"}},
|
||||
{Name: "members", Actions: []string{"view"}},
|
||||
{Name: "devops", Actions: []string{"create"}},
|
||||
{Name: "projects", Actions: []string{"create"}},
|
||||
{Name: "organizations", Actions: []string{"view"}},
|
||||
}
|
||||
case constants.WorkspaceViewer:
|
||||
workspaceRules = []models.SimpleRule{
|
||||
@@ -526,7 +523,6 @@ func GetWorkspaceRoleSimpleRules(workspace, roleName string) []models.SimpleRule
|
||||
{Name: "members", Actions: []string{"view"}},
|
||||
{Name: "devops", Actions: []string{"view"}},
|
||||
{Name: "projects", Actions: []string{"view"}},
|
||||
{Name: "organizations", Actions: []string{"view"}},
|
||||
{Name: "roles", Actions: []string{"view"}},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,10 +53,16 @@ var (
|
||||
adminEmail string
|
||||
adminPassword string
|
||||
tokenExpireTime time.Duration
|
||||
initUsers []initUser
|
||||
)
|
||||
|
||||
type initUser struct {
|
||||
models.User
|
||||
Hidden bool `json:"hidden"`
|
||||
}
|
||||
|
||||
const (
|
||||
userInitFile = "/etc/ks-iam/users.json"
|
||||
userInitFile = "/Users/hongming/users.json"
|
||||
)
|
||||
|
||||
func Init(email, password string, t time.Duration) error {
|
||||
@@ -121,11 +127,11 @@ func checkAndCreateDefaultUser(conn ldap.Client) error {
|
||||
ldapclient.UserSearchBase,
|
||||
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
|
||||
"(&(objectClass=inetOrgPerson))",
|
||||
nil,
|
||||
[]string{"uid"},
|
||||
nil,
|
||||
)
|
||||
|
||||
users, err := conn.Search(userSearchRequest)
|
||||
result, err := conn.Search(userSearchRequest)
|
||||
|
||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||
err = createUserBaseDN(conn)
|
||||
@@ -139,16 +145,16 @@ func checkAndCreateDefaultUser(conn ldap.Client) error {
|
||||
}
|
||||
|
||||
data, err := ioutil.ReadFile(userInitFile)
|
||||
var initUsers []models.User
|
||||
if err == nil {
|
||||
json.Unmarshal(data, &initUsers)
|
||||
}
|
||||
initUsers = append(initUsers, models.User{Username: constants.AdminUserName, Email: adminEmail, Password: adminPassword, Description: "Administrator account that was always created by default.", ClusterRole: constants.ClusterAdmin})
|
||||
initUsers = append(initUsers, initUser{User: models.User{Username: constants.AdminUserName, Email: adminEmail, Password: adminPassword, Description: "Administrator account that was always created by default.", ClusterRole: constants.ClusterAdmin}})
|
||||
|
||||
if users == nil || len(users.Entries) < len(initUsers) {
|
||||
for _, user := range initUsers {
|
||||
_, err = CreateUser(&user)
|
||||
for _, user := range initUsers {
|
||||
if result == nil || !containsUser(result.Entries, user) {
|
||||
_, err = CreateUser(&user.User)
|
||||
if err != nil && !ldap.IsErrorWithCode(err, ldap.LDAPResultEntryAlreadyExists) {
|
||||
glog.Errorln("user init failed", user.Username, err)
|
||||
return fmt.Errorf("user %s init failed: %s\n", user.Username, err)
|
||||
}
|
||||
}
|
||||
@@ -157,6 +163,16 @@ func checkAndCreateDefaultUser(conn ldap.Client) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func containsUser(entries []*ldap.Entry, user initUser) bool {
|
||||
for _, entry := range entries {
|
||||
uid := entry.GetAttributeValue("uid")
|
||||
if uid == user.Username {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func createUserBaseDN(conn ldap.Client) error {
|
||||
|
||||
conn, err := ldapclient.Client()
|
||||
@@ -314,7 +330,9 @@ func ListUsers(conditions *params.Conditions, orderBy string, reverse bool, limi
|
||||
|
||||
user := models.User{Username: uid, Email: email, Description: description, Lang: lang, CreateTime: createTimestamp}
|
||||
|
||||
users = append(users, user)
|
||||
if !shouldHidden(user) {
|
||||
users = append(users, user)
|
||||
}
|
||||
}
|
||||
|
||||
updatedControl := ldap.FindControl(response.Controls, ldap.ControlTypePaging)
|
||||
@@ -362,6 +380,15 @@ func ListUsers(conditions *params.Conditions, orderBy string, reverse bool, limi
|
||||
return &models.PageableResponse{Items: items, TotalCount: len(users)}, nil
|
||||
}
|
||||
|
||||
func shouldHidden(user models.User) bool {
|
||||
for _, initUser := range initUsers {
|
||||
if initUser.Username == user.Username {
|
||||
return initUser.Hidden
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func DescribeUser(username string) (*models.User, error) {
|
||||
|
||||
user, err := GetUserInfo(username)
|
||||
|
||||
@@ -60,47 +60,13 @@ var (
|
||||
{Name: "workspaces",
|
||||
Actions: []models.Action{
|
||||
{
|
||||
Name: "create",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"create"},
|
||||
APIGroups: []string{"tenant.kubesphere.io"},
|
||||
Resources: []string{"workspaces"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"tenant.kubesphere.io"},
|
||||
Resources: []string{"workspaces"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "edit",
|
||||
Name: "manager",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"*"},
|
||||
APIGroups: []string{"tenant.kubesphere.io", "monitoring.kubesphere.io"},
|
||||
APIGroups: []string{"*"},
|
||||
Resources: []string{"workspaces", "workspaces/*"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"*"},
|
||||
APIGroups: []string{""},
|
||||
Resources: []string{"namespaces"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"*"},
|
||||
APIGroups: []string{"", "apps", "extensions", "batch", "resources.kubesphere.io"},
|
||||
Resources: []string{"serviceaccounts", "limitranges", "deployments", "configmaps", "secrets", "jobs", "cronjobs", "persistentvolumeclaims", "statefulsets", "daemonsets", "ingresses", "services", "pods/*", "pods", "events", "deployments/scale"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"*"},
|
||||
APIGroups: []string{"rbac.authorization.k8s.io"},
|
||||
Resources: []string{"rolebindings", "roles"},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -121,6 +87,32 @@ var (
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "alerting",
|
||||
Actions: []models.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"alerting.kubesphere.io"},
|
||||
Resources: []string{"*"},
|
||||
}},
|
||||
},
|
||||
{Name: "create",
|
||||
Rules: []v1.PolicyRule{{
|
||||
Verbs: []string{"create"},
|
||||
APIGroups: []string{"alerting.kubesphere.io"},
|
||||
Resources: []string{"*"},
|
||||
}},
|
||||
},
|
||||
{Name: "delete",
|
||||
Rules: []v1.PolicyRule{{
|
||||
Verbs: []string{"delete"},
|
||||
APIGroups: []string{"alerting.kubesphere.io"},
|
||||
Resources: []string{"*"},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "logging",
|
||||
Actions: []models.Action{
|
||||
@@ -210,12 +202,6 @@ var (
|
||||
APIGroups: []string{"rbac.authorization.k8s.io"},
|
||||
Resources: []string{"clusterroles"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
ResourceNames: []string{"cluster-roles"},
|
||||
Resources: []string{"resources"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"iam.kubesphere.io"},
|
||||
@@ -411,12 +397,12 @@ var (
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{""},
|
||||
APIGroups: []string{"*"},
|
||||
Resources: []string{"namespaces"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"list"},
|
||||
APIGroups: []string{""},
|
||||
APIGroups: []string{"*"},
|
||||
Resources: []string{"events"},
|
||||
},
|
||||
},
|
||||
@@ -441,6 +427,49 @@ var (
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "monitoring",
|
||||
Actions: []models.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"monitoring.kubesphere.io"},
|
||||
Resources: []string{"*"},
|
||||
}, {
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"resources.kubesphere.io"},
|
||||
Resources: []string{"health"},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
Name: "alerting",
|
||||
Actions: []models.Action{
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"alerting.kubesphere.io"},
|
||||
Resources: []string{"*"},
|
||||
}},
|
||||
},
|
||||
{Name: "create",
|
||||
Rules: []v1.PolicyRule{{
|
||||
Verbs: []string{"create"},
|
||||
APIGroups: []string{"alerting.kubesphere.io"},
|
||||
Resources: []string{"*"},
|
||||
}},
|
||||
},
|
||||
{Name: "delete",
|
||||
Rules: []v1.PolicyRule{{
|
||||
Verbs: []string{"delete"},
|
||||
APIGroups: []string{"alerting.kubesphere.io"},
|
||||
Resources: []string{"*"},
|
||||
}},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "members",
|
||||
Actions: []models.Action{
|
||||
|
||||
@@ -19,6 +19,8 @@ package workspaces
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"github.com/golang/glog"
|
||||
"github.com/kiali/kiali/log"
|
||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/db"
|
||||
@@ -94,16 +96,24 @@ func InviteUser(workspaceName string, user *models.User) error {
|
||||
workspaceRole, err := iam.GetUserWorkspaceRole(workspaceName, user.Username)
|
||||
|
||||
if err != nil && !apierrors.IsNotFound(err) {
|
||||
glog.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 workspaceRole != nil && workspaceRole.Name != workspaceRoleName {
|
||||
err := DeleteWorkspaceRoleBinding(workspaceName, user.Username, user.WorkspaceRole)
|
||||
if currentWorkspaceRoleName != workspaceRoleName && currentWorkspaceRoleName != "" {
|
||||
err := DeleteWorkspaceRoleBinding(workspaceName, user.Username, workspaceRole.Annotations[constants.DisplayNameAnnotationKey])
|
||||
if err != nil {
|
||||
glog.Errorf("delete workspace role binding failed: %+v", err)
|
||||
return err
|
||||
}
|
||||
} else if currentWorkspaceRoleName != "" {
|
||||
return nil
|
||||
}
|
||||
|
||||
return CreateWorkspaceRoleBinding(workspaceName, user.Username, user.WorkspaceRole)
|
||||
@@ -120,13 +130,18 @@ func CreateWorkspaceRoleBinding(workspace, username string, role string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
workspaceRoleBinding = workspaceRoleBinding.DeepCopy()
|
||||
|
||||
if !k8sutil.ContainsUser(workspaceRoleBinding.Subjects, username) {
|
||||
workspaceRoleBinding = workspaceRoleBinding.DeepCopy()
|
||||
workspaceRoleBinding.Subjects = append(workspaceRoleBinding.Subjects, v1.Subject{APIGroup: "rbac.authorization.k8s.io", Kind: "User", Name: username})
|
||||
_, err = k8s.Client().RbacV1().ClusterRoleBindings().Update(workspaceRoleBinding)
|
||||
if err != nil {
|
||||
log.Errorf("update workspace role binding failed: %+v", err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return err
|
||||
return nil
|
||||
}
|
||||
|
||||
func DeleteWorkspaceRoleBinding(workspace, username string, role string) error {
|
||||
|
||||
Reference in New Issue
Block a user