diff --git a/pkg/apis/v1alpha/users/user.go b/pkg/apis/v1alpha/users/user.go index 20ae6e212d103e3edbae1f85bf20d0a6f6356343..e7a4b1fa69504bb41708b1692bef5e1cc807ac99 100644 --- a/pkg/apis/v1alpha/users/user.go +++ b/pkg/apis/v1alpha/users/user.go @@ -26,6 +26,7 @@ import ( "kubesphere.io/kubesphere/pkg/constants" "kubesphere.io/kubesphere/pkg/models" + "kubesphere.io/kubesphere/pkg/models/kubectl" ) func Register(ws *restful.WebService, subPath string) { @@ -54,13 +55,6 @@ func createUser(req *restful.Request, resp *restful.Response) { return } - err = models.CreateKubectlDeploy(user) - - if err != nil { - resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()}) - return - } - resp.WriteEntity(constants.MessageResponse{Message: "successfully created"}) } @@ -68,7 +62,7 @@ func delUser(req *restful.Request, resp *restful.Response) { user := req.PathParameter("user") - err := models.DelKubectlDeploy(user) + err := kubectl.DelKubectlDeploy(user) if err != nil && !apierrors.IsNotFound(err) { resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()}) @@ -89,7 +83,7 @@ func getKubectl(req *restful.Request, resp *restful.Response) { user := req.PathParameter("user") - kubectlPod, err := models.GetKubectlPod(user) + kubectlPod, err := kubectl.GetKubectlPod(user) if err != nil { resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()}) diff --git a/pkg/app/app.go b/pkg/app/app.go index 3005ee6c2a54c5de60c2a6409439f33235e2f478..2dbb350ed43f7272dea5e56579da7b23dc2bd158 100644 --- a/pkg/app/app.go +++ b/pkg/app/app.go @@ -44,6 +44,7 @@ import ( "kubesphere.io/kubesphere/pkg/constants" "kubesphere.io/kubesphere/pkg/models" "kubesphere.io/kubesphere/pkg/models/controllers" + "kubesphere.io/kubesphere/pkg/models/kubectl" "kubesphere.io/kubesphere/pkg/models/workspaces" "kubesphere.io/kubesphere/pkg/options" ) @@ -93,7 +94,7 @@ func preCheck() error { if err = models.CreateKubeConfig(constants.AdminUserName); err != nil { return err } - if err = models.CreateKubectlDeploy(constants.AdminUserName); err != nil { + if err = kubectl.CreateKubectlDeploy(constants.AdminUserName); err != nil { return err } } else { diff --git a/pkg/constants/common.go b/pkg/constants/common.go index 398d7af702b230b1acb84b5ca4a9f46a1c6aa257..e89c96c6b1c8b2373ec6f51067597a2ae3a27acc 100644 --- a/pkg/constants/common.go +++ b/pkg/constants/common.go @@ -46,6 +46,7 @@ const ( OpenPitrixProxyTokenEnv = "OPENPITRIX_PROXY_TOKEN" WorkspaceLabelKey = "kubesphere.io/workspace" WorkspaceAdmin = "workspace-admin" + ClusterAdmin = "cluster-admin" WorkspaceRegular = "workspace-regular" WorkspaceViewer = "workspace-viewer" DevopsOwner = "owner" diff --git a/pkg/models/controllers/clusterrole_bindings.go b/pkg/models/controllers/clusterrole_bindings.go index 73887a190c92abd76a800344e86ea2809e2b70aa..86144823062688267d347b6e365dca09ffde473f 100644 --- a/pkg/models/controllers/clusterrole_bindings.go +++ b/pkg/models/controllers/clusterrole_bindings.go @@ -33,6 +33,7 @@ import ( "k8s.io/client-go/tools/cache" "kubesphere.io/kubesphere/pkg/constants" + "kubesphere.io/kubesphere/pkg/models/kubectl" ) func (ctl *ClusterRoleBindingCtl) Name() string { @@ -80,20 +81,84 @@ func (ctl *ClusterRoleBindingCtl) initListerAndInformer() { ctl.informer = informerFactory.Rbac().V1().ClusterRoleBindings().Informer() ctl.informer.AddEventHandler(cache.ResourceEventHandlerFuncs{ AddFunc: func(obj interface{}) { + clusterRoleBinding := obj.(*rbac.ClusterRoleBinding) + ctl.handleTerminalCreate(clusterRoleBinding) }, UpdateFunc: func(old, new interface{}) { oldValue := old.(*rbac.ClusterRoleBinding) newValue := new.(*rbac.ClusterRoleBinding) if !subjectsCompile(oldValue.Subjects, newValue.Subjects) { ctl.handleWorkspaceRoleChange(newValue) + ctl.handleTerminalUpdate(oldValue, newValue) } }, DeleteFunc: func(obj interface{}) { - + clusterRoleBinding := obj.(*rbac.ClusterRoleBinding) + ctl.handleTerminalDelete(clusterRoleBinding) }, }) } +func (ctl *ClusterRoleBindingCtl) handleTerminalCreate(clusterRoleBinding *rbac.ClusterRoleBinding) { + if clusterRoleBinding.RoleRef.Name == constants.ClusterAdmin { + for _, subject := range clusterRoleBinding.Subjects { + if subject.Kind == rbac.UserKind { + err := kubectl.CreateKubectlDeploy(subject.Name) + if err != nil { + glog.Error(fmt.Sprintf("create %s's terminal pod failed:%s", subject.Name, err)) + } + } + } + } +} +func (ctl *ClusterRoleBindingCtl) handleTerminalUpdate(old *rbac.ClusterRoleBinding, new *rbac.ClusterRoleBinding) { + if new.RoleRef.Name == constants.ClusterAdmin { + for _, newSubject := range new.Subjects { + isAdded := true + for _, oldSubject := range old.Subjects { + if oldSubject == newSubject { + isAdded = false + break + } + } + if isAdded && newSubject.Kind == rbac.UserKind { + err := kubectl.CreateKubectlDeploy(newSubject.Name) + if err != nil { + glog.Error(fmt.Sprintf("create %s's terminal pod failed:%s", newSubject.Name, err)) + } + } + } + for _, oldSubject := range old.Subjects { + isDeleted := true + for _, newSubject := range new.Subjects { + if newSubject == oldSubject { + isDeleted = false + break + } + } + if isDeleted && oldSubject.Kind == rbac.UserKind { + err := kubectl.DelKubectlDeploy(oldSubject.Name) + if err != nil { + glog.Error(fmt.Sprintf("delete %s's terminal pod failed:%s", oldSubject.Name, err)) + } + } + } + } +} + +func (ctl *ClusterRoleBindingCtl) handleTerminalDelete(clusterRoleBinding *rbac.ClusterRoleBinding) { + if clusterRoleBinding.RoleRef.Name == constants.ClusterAdmin { + for _, subject := range clusterRoleBinding.Subjects { + if subject.Kind == rbac.UserKind { + err := kubectl.DelKubectlDeploy(subject.Name) + if err != nil { + glog.Error(fmt.Sprintf("delete %s's terminal pod failed:%s", subject.Name, err)) + } + } + } + } +} + func subjectsCompile(s1 []rbac.Subject, s2 []rbac.Subject) bool { if len(s1) != len(s2) { return false diff --git a/pkg/models/iam/iam.go b/pkg/models/iam/iam.go index 72ba021937d820cf5e62901dfaf0f0c630ea957c..8bc6e44450af5800707218bc3aba4b37a422ccdc 100644 --- a/pkg/models/iam/iam.go +++ b/pkg/models/iam/iam.go @@ -126,15 +126,9 @@ func GetUser(name string) (*User, error) { // Get rules func WorkspaceRoleRules(workspace string, roleName string) (*v1.ClusterRole, []Rule, error) { - lister, err := controllers.GetLister(controllers.ClusterRoles) - - if err != nil { - return nil, nil, err - } + clusterRoleName := fmt.Sprintf("system:%s:%s", workspace, roleName) - clusterRoleLister := lister.(v12.ClusterRoleLister) - - workspaceRole, err := clusterRoleLister.Get(fmt.Sprintf("system:%s:%s", workspace, roleName)) + workspaceRole, err := GetClusterRole(clusterRoleName) if err != nil { return nil, nil, err @@ -232,7 +226,7 @@ func GetRole(namespace string, name string) (*v1.Role, error) { if err != nil { return nil, err } - return role, nil + return role.DeepCopy(), nil } func GetWorkspaceUsers(workspace string, workspaceRole string) ([]string, error) { @@ -268,7 +262,7 @@ func GetClusterRoleBindings(name string) ([]v1.ClusterRoleBinding, error) { clusterRoleBindingLister := lister.(v12.ClusterRoleBindingLister) - clusterRoleBindingList, err := clusterRoleBindingLister.List(labels.Everything()) + clusterRoleBindings, err := clusterRoleBindingLister.List(labels.Everything()) if err != nil { return nil, err @@ -276,9 +270,9 @@ func GetClusterRoleBindings(name string) ([]v1.ClusterRoleBinding, error) { items := make([]v1.ClusterRoleBinding, 0) - for _, roleBinding := range clusterRoleBindingList { - if roleBinding.RoleRef.Name == name { - items = append(items, *roleBinding) + for _, clusterRoleBinding := range clusterRoleBindings { + if clusterRoleBinding.RoleRef.Name == name { + items = append(items, *clusterRoleBinding) } } @@ -325,7 +319,7 @@ func GetClusterRole(name string) (*v1.ClusterRole, error) { if err != nil { return nil, err } - return role, nil + return role.DeepCopy(), nil } func GetRoles(namespace string, username string) ([]v1.Role, error) { @@ -381,9 +375,9 @@ func GetRoles(namespace string, username string) ([]v1.Role, error) { } else { if subject.Kind == v1.UserKind && subject.Name == username { - rule, err := roleLister.Roles(roleBinding.Namespace).Get(roleBinding.RoleRef.Name) + role, err := roleLister.Roles(roleBinding.Namespace).Get(roleBinding.RoleRef.Name) if err == nil { - roles = append(roles, *rule) + roles = append(roles, *role) break } else if apierrors.IsNotFound(err) { glog.Infoln(err.Error()) @@ -436,6 +430,7 @@ func GetClusterRoles(username string) ([]v1.ClusterRole, error) { if roleBinding.RoleRef.Kind == ClusterRoleKind { role, err := clusterRoleLister.Get(roleBinding.RoleRef.Name) if err == nil { + role = role.DeepCopy() if role.Annotations == nil { role.Annotations = make(map[string]string, 0) } diff --git a/pkg/models/kubectl.go b/pkg/models/kubectl/kubectl.go similarity index 99% rename from pkg/models/kubectl.go rename to pkg/models/kubectl/kubectl.go index 70aae7ccbb92b095eabd5ca34d9df5cd85ac714d..fe0671a41f710880457c350a08e010e47c102dbc 100644 --- a/pkg/models/kubectl.go +++ b/pkg/models/kubectl/kubectl.go @@ -14,7 +14,7 @@ See the License for the specific language governing permissions and limitations under the License. */ -package models +package kubectl import ( "fmt" diff --git a/pkg/models/workspaces/workspaces.go b/pkg/models/workspaces/workspaces.go index d80e4e75dc567ed6e09e0d08d4037c17dd2dbed7..c298c49bcda3c123a3a6b03fb6ca0784a7b14ff8 100644 --- a/pkg/models/workspaces/workspaces.go +++ b/pkg/models/workspaces/workspaces.go @@ -280,7 +280,13 @@ func Namespaces(workspaceName string) ([]*core.Namespace, error) { return make([]*core.Namespace, 0), nil } - return namespaces, nil + out := make([]*core.Namespace, len(namespaces)) + + for i, v := range namespaces { + out[i] = v.DeepCopy() + } + + return out, nil } func BindingDevopsProject(workspace string, devops string) error { @@ -841,6 +847,8 @@ func Roles(workspace *Workspace) ([]*v1.ClusterRole, error) { return nil, err } + clusterRole = clusterRole.DeepCopy() + clusterRole.Name = name roles = append(roles, clusterRole) }