fix: ks-account abnormal restart

Signed-off-by: hongming <talonwan@yunify.com>
This commit is contained in:
hongming
2019-04-16 15:31:37 +08:00
committed by zryfish
parent 5c8a087a9c
commit dd963c0be4
40 changed files with 394 additions and 314 deletions

View File

@@ -67,6 +67,8 @@ func Run(s *options.ServerRunOptions) error {
return err return err
} }
waitForResourceSync()
err = iam.Init(s.AdminEmail, s.AdminPassword, expireTime) err = iam.Init(s.AdminEmail, s.AdminPassword, expireTime)
jwtutil.Setup(s.JWTSecret) jwtutil.Setup(s.JWTSecret)
@@ -74,8 +76,6 @@ func Run(s *options.ServerRunOptions) error {
return err return err
} }
waitForResourceSync()
container := runtime.Container container := runtime.Container
container.Filter(filter.Logging) container.Filter(filter.Logging)

View File

@@ -72,7 +72,6 @@ func (h Auth) ServeHTTP(resp http.ResponseWriter, req *http.Request) (int, error
token, err := h.Validate(uToken) token, err := h.Validate(uToken)
if err != nil { if err != nil {
log.Println(uToken)
return h.HandleUnauthorized(resp, err), nil return h.HandleUnauthorized(resp, err), nil
} }

View File

@@ -24,6 +24,7 @@ import (
"k8s.io/apiserver/pkg/authorization/authorizer" "k8s.io/apiserver/pkg/authorization/authorizer"
"k8s.io/apiserver/pkg/endpoints/request" "k8s.io/apiserver/pkg/endpoints/request"
"kubesphere.io/kubesphere/pkg/utils/k8sutil" "kubesphere.io/kubesphere/pkg/utils/k8sutil"
"log"
"net/http" "net/http"
"strings" "strings"
@@ -82,6 +83,7 @@ func (c Authentication) ServeHTTP(w http.ResponseWriter, r *http.Request) (int,
func handleForbidden(w http.ResponseWriter, err error) int { func handleForbidden(w http.ResponseWriter, err error) int {
message := fmt.Sprintf("Forbidden,%s", err.Error()) message := fmt.Sprintf("Forbidden,%s", err.Error())
w.Header().Add("WWW-Authenticate", message) w.Header().Add("WWW-Authenticate", message)
log.Println(message)
return http.StatusForbidden return http.StatusForbidden
} }
@@ -94,6 +96,7 @@ func permissionValidate(attrs authorizer.Attributes) (bool, error) {
permitted, err := clusterRoleValidate(attrs) permitted, err := clusterRoleValidate(attrs)
if err != nil { if err != nil {
log.Println("lister error", err)
return false, err return false, err
} }
@@ -105,6 +108,7 @@ func permissionValidate(attrs authorizer.Attributes) (bool, error) {
permitted, err = roleValidate(attrs) permitted, err = roleValidate(attrs)
if err != nil { if err != nil {
log.Println("lister error", err)
return false, err return false, err
} }

View File

@@ -20,6 +20,7 @@ package iam
import ( import (
"github.com/dgrijalva/jwt-go" "github.com/dgrijalva/jwt-go"
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
"github.com/golang/glog"
"kubesphere.io/kubesphere/pkg/utils/iputil" "kubesphere.io/kubesphere/pkg/utils/iputil"
"kubesphere.io/kubesphere/pkg/utils/jwtutil" "kubesphere.io/kubesphere/pkg/utils/jwtutil"
"net/http" "net/http"
@@ -97,6 +98,7 @@ func TokenReviewHandler(req *restful.Request, resp *restful.Response) {
token, err := jwtutil.ValidateToken(uToken) token, err := jwtutil.ValidateToken(uToken)
if err != nil { if err != nil {
glog.Errorln("token review failed", uToken, err)
failed := TokenReview{APIVersion: APIVersion, failed := TokenReview{APIVersion: APIVersion,
Kind: KindTokenReview, Kind: KindTokenReview,
Status: &Status{ Status: &Status{

View File

@@ -26,7 +26,7 @@ import (
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
"github.com/go-ldap/ldap" "github.com/go-ldap/ldap"
rbacv1 "k8s.io/api/rbac/v1"
"kubesphere.io/kubesphere/pkg/constants" "kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/errors" "kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models" "kubesphere.io/kubesphere/pkg/models"
@@ -126,7 +126,14 @@ func UpdateUser(req *restful.Request, resp *restful.Response) {
// change password by self // change password by self
if usernameInHeader == user.Username && user.Password != "" { if usernameInHeader == user.Username && user.Password != "" {
_, err = iam.Login(usernameInHeader, user.CurrentPassword, "") isUserManager, err := isUserManager(usernameInHeader)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
if !isUserManager {
_, err = iam.Login(usernameInHeader, user.CurrentPassword, "")
}
if err != nil { if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("incorrect current password"))) resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("incorrect current password")))
return return
@@ -143,6 +150,17 @@ func UpdateUser(req *restful.Request, resp *restful.Response) {
resp.WriteAsJson(result) resp.WriteAsJson(result)
} }
func isUserManager(username string) (bool, error) {
rules, err := iam.GetUserClusterRules(username)
if err != nil {
return false, err
}
if iam.RulesMatchesRequired(rules, rbacv1.PolicyRule{Verbs: []string{"update"}, Resources: []string{"users"}, APIGroups: []string{"iam.kubesphere.io"}}) {
return true, nil
}
return false, nil
}
func UserLoginLog(req *restful.Request, resp *restful.Response) { func UserLoginLog(req *restful.Request, resp *restful.Response) {
username := req.PathParameter("name") username := req.PathParameter("name")
logs, err := iam.LoginLog(username) logs, err := iam.LoginLog(username)

View File

@@ -18,7 +18,6 @@
package tenant package tenant
import ( import (
"fmt"
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
@@ -31,11 +30,14 @@ import (
"kubesphere.io/kubesphere/pkg/errors" "kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models" "kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/models/iam" "kubesphere.io/kubesphere/pkg/models/iam"
"kubesphere.io/kubesphere/pkg/models/metrics"
"kubesphere.io/kubesphere/pkg/models/resources" "kubesphere.io/kubesphere/pkg/models/resources"
"kubesphere.io/kubesphere/pkg/models/tenant" "kubesphere.io/kubesphere/pkg/models/tenant"
"kubesphere.io/kubesphere/pkg/models/workspaces" "kubesphere.io/kubesphere/pkg/models/workspaces"
"kubesphere.io/kubesphere/pkg/params" "kubesphere.io/kubesphere/pkg/params"
"kubesphere.io/kubesphere/pkg/simple/client/elasticsearch"
"kubesphere.io/kubesphere/pkg/simple/client/kubesphere" "kubesphere.io/kubesphere/pkg/simple/client/kubesphere"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
"net/http" "net/http"
"strings" "strings"
) )
@@ -123,6 +125,22 @@ func ListNamespaces(req *restful.Request, resp *restful.Response) {
return return
} }
namespaces := make([]*v1.Namespace, 0)
for _, item := range result.Items {
namespaces = append(namespaces, item.(*v1.Namespace).DeepCopy())
}
namespaces = metrics.GetNamespacesWithMetrics(namespaces)
items := make([]interface{}, 0)
for _, item := range namespaces {
items = append(items, item)
}
result.Items = items
resp.WriteAsJson(result) resp.WriteAsJson(result)
} }
@@ -298,37 +316,84 @@ func LogQuery(req *restful.Request, resp *restful.Response) {
username := req.HeaderParameter(constants.UserNameHeader) username := req.HeaderParameter(constants.UserNameHeader)
mapping, err := iam.GetUserWorkspaceRoleMap(username)
if err != nil {
resp.WriteError(http.StatusInternalServerError, err)
glog.Errorln(err)
return
}
workspaces := make([]string, 0)
for workspaceName, role := range mapping {
if role == fmt.Sprintf("workspace:%s:admin", workspaceName) {
workspaces = append(workspaces, workspaceName)
}
}
// regenerate the request for log query // regenerate the request for log query
newUrl := net.FormatURL("http", "127.0.0.1", 80, "/kapis/logging.kubesphere.io/v1alpha2/cluster") newUrl := net.FormatURL("http", "127.0.0.1", 80, "/kapis/logging.kubesphere.io/v1alpha2/cluster")
values := req.Request.URL.Query() values := req.Request.URL.Query()
rules, err := iam.GetUserClusterRules(username) clusterRules, err := iam.GetUserClusterRules(username)
if err != nil { if err != nil {
resp.WriteError(http.StatusInternalServerError, err) resp.WriteError(http.StatusInternalServerError, err)
glog.Errorln(err) glog.Errorln(err)
return return
} }
if !iam.RulesMatchesRequired(rules, rbacv1.PolicyRule{Verbs: []string{"get"}, Resources: []string{"*"}, APIGroups: []string{"logging.kubesphere.io"}}) { hasClusterLogAccess := iam.RulesMatchesRequired(clusterRules, rbacv1.PolicyRule{Verbs: []string{"get"}, Resources: []string{"*"}, APIGroups: []string{"logging.kubesphere.io"}})
values.Set("workspaces", strings.Join(workspaces, ",")) // if the user is not a cluster admin
if !hasClusterLogAccess {
queryNamespaces := strings.Split(req.QueryParameter("namespaces"), ",")
// then the user can only view logs of namespaces he belongs to
namespaces := make([]string, 0)
roles, err := iam.GetUserRoles("", username)
if err != nil {
resp.WriteError(http.StatusInternalServerError, err)
glog.Errorln(err)
}
for _, role := range roles {
if !sliceutil.HasString(namespaces, role.Namespace) && iam.RulesMatchesRequired(role.Rules, rbacv1.PolicyRule{Verbs: []string{"get"}, Resources: []string{"*"}, APIGroups: []string{"logging.kubesphere.io"}}) {
namespaces = append(namespaces, role.Namespace)
}
}
// if the user belongs to no namespace
// then no log visible
if len(namespaces) == 0 {
res := esclient.QueryResult{Status: http.StatusOK}
resp.WriteAsJson(res)
return
} else if len(queryNamespaces) == 1 && queryNamespaces[0] == "" {
values.Set("namespaces", strings.Join(namespaces, ","))
} else {
inter := intersection(queryNamespaces, namespaces)
if len(inter) == 0 {
res := esclient.QueryResult{Status: http.StatusOK}
resp.WriteAsJson(res)
return
}
values.Set("namespaces", strings.Join(inter, ","))
}
} }
newUrl.RawQuery = values.Encode() newUrl.RawQuery = values.Encode()
// forward the request to logging model // forward the request to logging model
newHttpRequest, _ := http.NewRequest(http.MethodGet, newUrl.String(), nil) newHttpRequest, _ := http.NewRequest(http.MethodGet, newUrl.String(), nil)
logging.LoggingQueryCluster(restful.NewRequest(newHttpRequest), resp) logging.LoggingQueryCluster(restful.NewRequest(newHttpRequest), resp)
} }
func intersection(s1, s2 []string) (inter []string) {
hash := make(map[string]bool)
for _, e := range s1 {
hash[e] = true
}
for _, e := range s2 {
// If elements present in the hashmap then append intersection list.
if hash[e] {
inter = append(inter, e)
}
}
//Remove dups from slice.
inter = removeDups(inter)
return
}
//Remove dups from slice.
func removeDups(elements []string) (nodups []string) {
encountered := make(map[string]bool)
for _, element := range elements {
if !encountered[element] {
nodups = append(nodups, element)
encountered[element] = true
}
}
return
}

View File

@@ -142,9 +142,11 @@ func (r *ReconcileClusterRoleBinding) updateRoleBindings(clusterRoleBinding *rba
log.Info("Creating default role binding", "namespace", namespace.Name, "name", adminBinding.Name) log.Info("Creating default role binding", "namespace", namespace.Name, "name", adminBinding.Name)
err = r.Create(context.TODO(), adminBinding) err = r.Create(context.TODO(), adminBinding)
if err != nil { if err != nil {
return err log.Error(err, "default role binding create failed", "namespace", namespace.Name, "name", adminBinding.Name)
} }
return err
} else if err != nil { } else if err != nil {
log.Error(err, "default role binding not found", "namespace", namespace.Name, "name", adminBinding.Name)
return err return err
} }
@@ -182,9 +184,7 @@ func (r *ReconcileClusterRoleBinding) updateRoleBindings(clusterRoleBinding *rba
if errors.IsNotFound(err) { if errors.IsNotFound(err) {
log.Info("Creating default role binding", "namespace", namespace.Name, "name", viewerBinding.Name) log.Info("Creating default role binding", "namespace", namespace.Name, "name", viewerBinding.Name)
err = r.Create(context.TODO(), viewerBinding) err = r.Create(context.TODO(), viewerBinding)
if err != nil { return err
return err
}
} else if err != nil { } else if err != nil {
return err return err
} }

View File

@@ -232,6 +232,7 @@ func (r *ReconcileNamespace) checkAndCreateRoleBindings(namespace *corev1.Namesp
if err != nil { if err != nil {
return err return err
} }
found = adminBinding
} else if err != nil { } else if err != nil {
return err return err
} }
@@ -276,6 +277,7 @@ func (r *ReconcileNamespace) checkAndCreateRoleBindings(namespace *corev1.Namesp
if err != nil { if err != nil {
return err return err
} }
found = viewerBinding
} else if err != nil { } else if err != nil {
return err return err
} }
@@ -309,7 +311,8 @@ func (r *ReconcileNamespace) checkAndCreateRuntime(namespace *corev1.Namespace)
} }
cm := &corev1.ConfigMap{} cm := &corev1.ConfigMap{}
err := r.Get(context.TODO(), types.NamespacedName{Namespace: constants.KubeSphereControlNamespace, Name: constants.AdminUserName}, cm) configName := fmt.Sprintf("kubeconfig-%s", constants.AdminUserName)
err := r.Get(context.TODO(), types.NamespacedName{Namespace: constants.KubeSphereControlNamespace, Name: configName}, cm)
if err != nil { if err != nil {
return err return err
@@ -353,12 +356,8 @@ func (r *ReconcileNamespace) checkAndBindWorkspace(namespace *corev1.Namespace)
if err != nil { if err != nil {
if errors.IsNotFound(err) { if errors.IsNotFound(err) {
log.Error(err, "namespace", namespace.Name) log.Error(err, fmt.Sprintf("namespace %s bind workspace %s but not found", namespace.Name, workspaceName))
delete(namespace.Labels, constants.WorkspaceLabelKey) return nil
err = r.Update(context.TODO(), namespace)
if err != nil {
return err
}
} }
return err return err
} }

View File

@@ -188,9 +188,10 @@ func (r *ReconcileWorkspace) createWorkspaceAdmin(instance *tenantv1alpha1.Works
} }
// Update the found object and write the result back if there are any changes // Update the found object and write the result back if there are any changes
if !reflect.DeepEqual(admin.Rules, found.Rules) || !reflect.DeepEqual(admin.Labels, found.Labels) { if !reflect.DeepEqual(admin.Rules, found.Rules) || !reflect.DeepEqual(admin.Labels, found.Labels) || !reflect.DeepEqual(admin.Annotations, found.Annotations) {
found.Rules = admin.Rules found.Rules = admin.Rules
found.Labels = admin.Labels found.Labels = admin.Labels
found.Annotations = admin.Annotations
log.Info("Updating workspace role", "workspace", instance.Name, "name", admin.Name) log.Info("Updating workspace role", "workspace", instance.Name, "name", admin.Name)
err = r.Update(context.TODO(), found) err = r.Update(context.TODO(), found)
if err != nil { if err != nil {
@@ -226,9 +227,10 @@ func (r *ReconcileWorkspace) createWorkspaceRegular(instance *tenantv1alpha1.Wor
} }
// Update the found object and write the result back if there are any changes // Update the found object and write the result back if there are any changes
if !reflect.DeepEqual(regular.Rules, found.Rules) || !reflect.DeepEqual(regular.Labels, found.Labels) { if !reflect.DeepEqual(regular.Rules, found.Rules) || !reflect.DeepEqual(regular.Labels, found.Labels) || !reflect.DeepEqual(regular.Annotations, found.Annotations) {
found.Rules = regular.Rules found.Rules = regular.Rules
found.Labels = regular.Labels found.Labels = regular.Labels
found.Annotations = regular.Annotations
log.Info("Updating workspace role", "workspace", instance.Name, "name", regular.Name) log.Info("Updating workspace role", "workspace", instance.Name, "name", regular.Name)
err = r.Update(context.TODO(), found) err = r.Update(context.TODO(), found)
if err != nil { if err != nil {
@@ -264,9 +266,10 @@ func (r *ReconcileWorkspace) createWorkspaceViewer(instance *tenantv1alpha1.Work
} }
// Update the found object and write the result back if there are any changes // Update the found object and write the result back if there are any changes
if !reflect.DeepEqual(viewer.Rules, found.Rules) || !reflect.DeepEqual(viewer.Labels, found.Labels) { if !reflect.DeepEqual(viewer.Rules, found.Rules) || !reflect.DeepEqual(viewer.Labels, found.Labels) || !reflect.DeepEqual(viewer.Annotations, found.Annotations) {
found.Rules = viewer.Rules found.Rules = viewer.Rules
found.Labels = viewer.Labels found.Labels = viewer.Labels
found.Annotations = viewer.Annotations
log.Info("Updating workspace role", "workspace", instance.Name, "name", viewer.Name) log.Info("Updating workspace role", "workspace", instance.Name, "name", viewer.Name)
err = r.Update(context.TODO(), found) err = r.Update(context.TODO(), found)
if err != nil { if err != nil {

View File

@@ -19,10 +19,19 @@ package iam
import ( import (
"fmt" "fmt"
"github.com/go-ldap/ldap"
"github.com/golang/glog" "github.com/golang/glog"
rbacv1 "k8s.io/api/rbac/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/informers" "kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/models/iam/policy"
"kubesphere.io/kubesphere/pkg/models/kubeconfig"
"kubesphere.io/kubesphere/pkg/models/kubectl"
"kubesphere.io/kubesphere/pkg/models/resources" "kubesphere.io/kubesphere/pkg/models/resources"
"kubesphere.io/kubesphere/pkg/params" "kubesphere.io/kubesphere/pkg/params"
"kubesphere.io/kubesphere/pkg/simple/client/k8s" "kubesphere.io/kubesphere/pkg/simple/client/k8s"
@@ -31,22 +40,19 @@ import (
"kubesphere.io/kubesphere/pkg/utils/sliceutil" "kubesphere.io/kubesphere/pkg/utils/sliceutil"
"sort" "sort"
"strings" "strings"
"github.com/go-ldap/ldap"
"k8s.io/api/rbac/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/models/iam/policy"
) )
const ClusterRoleKind = "ClusterRole" const (
ClusterRoleKind = "ClusterRole"
NamespaceAdminRoleBindName = "admin"
NamespaceViewerRoleBindName = "viewer"
)
func GetUserDevopsSimpleRules(username, projectId string) ([]models.SimpleRule, error) { func GetUserDevopsSimpleRules(username, projectId string) ([]models.SimpleRule, error) {
role, err := kubesphere.Client().GetUserDevopsRole(username, projectId) role, err := kubesphere.Client().GetUserDevopsRole(username, projectId)
if err != nil { if err != nil {
glog.Errorln("get user devops role", username, projectId, err)
return nil, err return nil, err
} }
@@ -98,17 +104,18 @@ func GetDevopsRoleSimpleRules(role string) []models.SimpleRule {
} }
// Get user roles in namespace // Get user roles in namespace
func GetUserRoles(namespace, username string) ([]*v1.Role, error) { func GetUserRoles(namespace, username string) ([]*rbacv1.Role, error) {
clusterRoleLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister() clusterRoleLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister()
roleBindingLister := informers.SharedInformerFactory().Rbac().V1().RoleBindings().Lister() roleBindingLister := informers.SharedInformerFactory().Rbac().V1().RoleBindings().Lister()
roleLister := informers.SharedInformerFactory().Rbac().V1().Roles().Lister() roleLister := informers.SharedInformerFactory().Rbac().V1().Roles().Lister()
roleBindings, err := roleBindingLister.RoleBindings(namespace).List(labels.Everything()) roleBindings, err := roleBindingLister.RoleBindings(namespace).List(labels.Everything())
if err != nil { if err != nil {
glog.Errorln("get role bindings", namespace, err)
return nil, err return nil, err
} }
roles := make([]*v1.Role, 0) roles := make([]*rbacv1.Role, 0)
for _, roleBinding := range roleBindings { for _, roleBinding := range roleBindings {
if k8sutil.ContainsUser(roleBinding.Subjects, username) { if k8sutil.ContainsUser(roleBinding.Subjects, username) {
@@ -119,10 +126,11 @@ func GetUserRoles(namespace, username string) ([]*v1.Role, error) {
glog.Warningf("cluster role %s not found but bind user %s in namespace %s", roleBinding.RoleRef.Name, username, namespace) glog.Warningf("cluster role %s not found but bind user %s in namespace %s", roleBinding.RoleRef.Name, username, namespace)
continue continue
} else { } else {
glog.Errorln("get cluster role", roleBinding.RoleRef.Name, err)
return nil, err return nil, err
} }
} }
role := v1.Role{} role := rbacv1.Role{}
role.TypeMeta = clusterRole.TypeMeta role.TypeMeta = clusterRole.TypeMeta
role.ObjectMeta = clusterRole.ObjectMeta role.ObjectMeta = clusterRole.ObjectMeta
role.Rules = clusterRole.Rules role.Rules = clusterRole.Rules
@@ -133,9 +141,10 @@ func GetUserRoles(namespace, username string) ([]*v1.Role, error) {
if err != nil { if err != nil {
if apierrors.IsNotFound(err) { if apierrors.IsNotFound(err) {
glog.Warningf("role %s not found but bind user %s in namespace %s", roleBinding.RoleRef.Name, username, namespace) glog.Warningf("namespace %s role %s not found, but bind user %s", namespace, roleBinding.RoleRef.Name, username)
continue continue
} else { } else {
glog.Errorln("get role", roleBinding.Namespace, roleBinding.RoleRef.Name, err)
return nil, err return nil, err
} }
} }
@@ -147,17 +156,18 @@ func GetUserRoles(namespace, username string) ([]*v1.Role, error) {
return roles, nil return roles, nil
} }
func GetUserClusterRoles(username string) (*v1.ClusterRole, []*v1.ClusterRole, error) { func GetUserClusterRoles(username string) (*rbacv1.ClusterRole, []*rbacv1.ClusterRole, error) {
clusterRoleLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister() clusterRoleLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister()
clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister() clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
clusterRoleBindings, err := clusterRoleBindingLister.List(labels.Everything()) clusterRoleBindings, err := clusterRoleBindingLister.List(labels.Everything())
if err != nil { if err != nil {
glog.Errorln("get cluster role bindings", err)
return nil, nil, err return nil, nil, err
} }
clusterRoles := make([]*v1.ClusterRole, 0) clusterRoles := make([]*rbacv1.ClusterRole, 0)
userFacingClusterRole := &v1.ClusterRole{} userFacingClusterRole := &rbacv1.ClusterRole{}
for _, clusterRoleBinding := range clusterRoleBindings { for _, clusterRoleBinding := range clusterRoleBindings {
if k8sutil.ContainsUser(clusterRoleBinding.Subjects, username) { if k8sutil.ContainsUser(clusterRoleBinding.Subjects, username) {
clusterRole, err := clusterRoleLister.Get(clusterRoleBinding.RoleRef.Name) clusterRole, err := clusterRoleLister.Get(clusterRoleBinding.RoleRef.Name)
@@ -166,6 +176,7 @@ func GetUserClusterRoles(username string) (*v1.ClusterRole, []*v1.ClusterRole, e
glog.Warningf("cluster role %s not found but bind user %s", clusterRoleBinding.RoleRef.Name, username) glog.Warningf("cluster role %s not found but bind user %s", clusterRoleBinding.RoleRef.Name, username)
continue continue
} else { } else {
glog.Errorln("get cluster role", clusterRoleBinding.RoleRef.Name, err)
return nil, nil, err return nil, nil, err
} }
} }
@@ -179,7 +190,7 @@ func GetUserClusterRoles(username string) (*v1.ClusterRole, []*v1.ClusterRole, e
return userFacingClusterRole, clusterRoles, nil return userFacingClusterRole, clusterRoles, nil
} }
func GetUserClusterRole(username string) (*v1.ClusterRole, error) { func GetUserClusterRole(username string) (*rbacv1.ClusterRole, error) {
userFacingClusterRole, _, err := GetUserClusterRoles(username) userFacingClusterRole, _, err := GetUserClusterRoles(username)
if err != nil { if err != nil {
return nil, err return nil, err
@@ -187,14 +198,14 @@ func GetUserClusterRole(username string) (*v1.ClusterRole, error) {
return userFacingClusterRole, nil return userFacingClusterRole, nil
} }
func GetUserClusterRules(username string) ([]v1.PolicyRule, error) { func GetUserClusterRules(username string) ([]rbacv1.PolicyRule, error) {
_, clusterRoles, err := GetUserClusterRoles(username) _, clusterRoles, err := GetUserClusterRoles(username)
if err != nil { if err != nil {
return nil, err return nil, err
} }
rules := make([]v1.PolicyRule, 0) rules := make([]rbacv1.PolicyRule, 0)
for _, clusterRole := range clusterRoles { for _, clusterRole := range clusterRoles {
rules = append(rules, clusterRole.Rules...) rules = append(rules, clusterRole.Rules...)
} }
@@ -202,14 +213,14 @@ func GetUserClusterRules(username string) ([]v1.PolicyRule, error) {
return rules, nil return rules, nil
} }
func GetUserRules(namespace, username string) ([]v1.PolicyRule, error) { func GetUserRules(namespace, username string) ([]rbacv1.PolicyRule, error) {
roles, err := GetUserRoles(namespace, username) roles, err := GetUserRoles(namespace, username)
if err != nil { if err != nil {
return nil, err return nil, err
} }
rules := make([]v1.PolicyRule, 0) rules := make([]rbacv1.PolicyRule, 0)
for _, role := range roles { for _, role := range roles {
rules = append(rules, role.Rules...) rules = append(rules, role.Rules...)
} }
@@ -217,15 +228,16 @@ func GetUserRules(namespace, username string) ([]v1.PolicyRule, error) {
return rules, nil return rules, nil
} }
func GetWorkspaceRoleBindings(workspace string) ([]*v1.ClusterRoleBinding, error) { func GetWorkspaceRoleBindings(workspace string) ([]*rbacv1.ClusterRoleBinding, error) {
clusterRoleBindings, err := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister().List(labels.Everything()) clusterRoleBindings, err := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister().List(labels.Everything())
if err != nil { if err != nil {
glog.Errorln("get cluster role bindings", err)
return nil, err return nil, err
} }
result := make([]*v1.ClusterRoleBinding, 0) result := make([]*rbacv1.ClusterRoleBinding, 0)
for _, roleBinding := range clusterRoleBindings { for _, roleBinding := range clusterRoleBindings {
if k8sutil.IsControlledBy(roleBinding.OwnerReferences, "Workspace", workspace) { if k8sutil.IsControlledBy(roleBinding.OwnerReferences, "Workspace", workspace) {
@@ -236,7 +248,7 @@ func GetWorkspaceRoleBindings(workspace string) ([]*v1.ClusterRoleBinding, error
return result, nil return result, nil
} }
func GetWorkspaceRole(workspace, role string) (*v1.ClusterRole, error) { func GetWorkspaceRole(workspace, role string) (*rbacv1.ClusterRole, error) {
if !sliceutil.HasString(constants.WorkSpaceRoles, role) { if !sliceutil.HasString(constants.WorkSpaceRoles, role) {
return nil, apierrors.NewNotFound(schema.GroupResource{Resource: "workspace role"}, role) return nil, apierrors.NewNotFound(schema.GroupResource{Resource: "workspace role"}, role)
} }
@@ -249,6 +261,7 @@ func GetUserWorkspaceRoleMap(username string) (map[string]string, error) {
clusterRoleBindings, err := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister().List(labels.Everything()) clusterRoleBindings, err := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister().List(labels.Everything())
if err != nil { if err != nil {
glog.Errorln("get cluster role bindings", err)
return nil, err return nil, err
} }
@@ -264,7 +277,7 @@ func GetUserWorkspaceRoleMap(username string) (map[string]string, error) {
return result, nil return result, nil
} }
func GetUserWorkspaceRole(workspace, username string) (*v1.ClusterRole, error) { func GetUserWorkspaceRole(workspace, username string) (*rbacv1.ClusterRole, error) {
workspaceRoleMap, err := GetUserWorkspaceRoleMap(username) workspaceRoleMap, err := GetUserWorkspaceRoleMap(username)
if err != nil { if err != nil {
@@ -278,15 +291,16 @@ func GetUserWorkspaceRole(workspace, username string) (*v1.ClusterRole, error) {
return nil, apierrors.NewNotFound(schema.GroupResource{Resource: "workspace user"}, username) return nil, apierrors.NewNotFound(schema.GroupResource{Resource: "workspace user"}, username)
} }
func GetRoleBindings(namespace string, roleName string) ([]*v1.RoleBinding, error) { func GetRoleBindings(namespace string, roleName string) ([]*rbacv1.RoleBinding, error) {
roleBindingLister := informers.SharedInformerFactory().Rbac().V1().RoleBindings().Lister() roleBindingLister := informers.SharedInformerFactory().Rbac().V1().RoleBindings().Lister()
roleBindings, err := roleBindingLister.RoleBindings(namespace).List(labels.Everything()) roleBindings, err := roleBindingLister.RoleBindings(namespace).List(labels.Everything())
if err != nil { if err != nil {
glog.Errorln("get role bindings", namespace, err)
return nil, err return nil, err
} }
items := make([]*v1.RoleBinding, 0) items := make([]*rbacv1.RoleBinding, 0)
for _, roleBinding := range roleBindings { for _, roleBinding := range roleBindings {
if roleName == "" { if roleName == "" {
@@ -299,15 +313,16 @@ func GetRoleBindings(namespace string, roleName string) ([]*v1.RoleBinding, erro
return items, nil return items, nil
} }
func GetClusterRoleBindings(clusterRoleName string) ([]*v1.ClusterRoleBinding, error) { func GetClusterRoleBindings(clusterRoleName string) ([]*rbacv1.ClusterRoleBinding, error) {
clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister() clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
roleBindings, err := clusterRoleBindingLister.List(labels.Everything()) roleBindings, err := clusterRoleBindingLister.List(labels.Everything())
if err != nil { if err != nil {
glog.Errorln("get cluster role bindings", err)
return nil, err return nil, err
} }
items := make([]*v1.ClusterRoleBinding, 0) items := make([]*rbacv1.ClusterRoleBinding, 0)
for _, roleBinding := range roleBindings { for _, roleBinding := range roleBindings {
if roleBinding.RoleRef.Name == clusterRoleName { if roleBinding.RoleRef.Name == clusterRoleName {
@@ -328,12 +343,13 @@ func ListClusterRoleUsers(clusterRoleName string, conditions *params.Conditions,
users := make([]*models.User, 0) users := make([]*models.User, 0)
for _, roleBinding := range roleBindings { for _, roleBinding := range roleBindings {
for _, subject := range roleBinding.Subjects { for _, subject := range roleBinding.Subjects {
if subject.Kind == v1.UserKind && !k8sutil.ContainsUser(users, subject.Name) { if subject.Kind == rbacv1.UserKind && !k8sutil.ContainsUser(users, subject.Name) {
user, err := GetUserInfo(subject.Name) user, err := GetUserInfo(subject.Name)
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) { if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
continue continue
} }
if err != nil { if err != nil {
glog.Errorln("get user info", subject.Name, err)
return nil, err return nil, err
} }
users = append(users, user) users = append(users, user)
@@ -351,7 +367,7 @@ func ListClusterRoleUsers(clusterRoleName string, conditions *params.Conditions,
switch orderBy { switch orderBy {
default: default:
fallthrough fallthrough
case "name": case resources.Name:
return strings.Compare(users[i].Username, users[j].Username) <= 0 return strings.Compare(users[i].Username, users[j].Username) <= 0
} }
}) })
@@ -378,7 +394,7 @@ func RoleUsers(namespace string, roleName string) ([]*models.User, error) {
users := make([]*models.User, 0) users := make([]*models.User, 0)
for _, roleBinding := range roleBindings { for _, roleBinding := range roleBindings {
for _, subject := range roleBinding.Subjects { for _, subject := range roleBinding.Subjects {
if subject.Kind == v1.UserKind && !k8sutil.ContainsUser(users, subject.Name) { if subject.Kind == rbacv1.UserKind && !k8sutil.ContainsUser(users, subject.Name) {
user, err := GetUserInfo(subject.Name) user, err := GetUserInfo(subject.Name)
if err != nil { if err != nil {
@@ -402,8 +418,8 @@ func ListRoles(namespace string, conditions *params.Conditions, orderBy string,
} }
func ListWorkspaceRoles(workspace string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) { func ListWorkspaceRoles(workspace string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
conditions.Match["ownerName"] = workspace conditions.Match[resources.OwnerName] = workspace
conditions.Match["ownerKind"] = "Workspace" conditions.Match[resources.OwnerKind] = "Workspace"
result, err := resources.ListResources("", resources.ClusterRoles, conditions, orderBy, reverse, limit, offset) result, err := resources.ListResources("", resources.ClusterRoles, conditions, orderBy, reverse, limit, offset)
if err != nil { if err != nil {
@@ -411,7 +427,7 @@ func ListWorkspaceRoles(workspace string, conditions *params.Conditions, orderBy
} }
for i, item := range result.Items { for i, item := range result.Items {
if role, ok := item.(*v1.ClusterRole); ok { if role, ok := item.(*rbacv1.ClusterRole); ok {
role = role.DeepCopy() role = role.DeepCopy()
role.Name = role.Annotations[constants.DisplayNameAnnotationKey] role.Name = role.Annotations[constants.DisplayNameAnnotationKey]
result.Items[i] = role result.Items[i] = role
@@ -425,6 +441,11 @@ func ListClusterRoles(conditions *params.Conditions, orderBy string, reverse boo
} }
func NamespaceUsers(namespaceName string) ([]*models.User, error) { func NamespaceUsers(namespaceName string) ([]*models.User, error) {
namespace, err := informers.SharedInformerFactory().Core().V1().Namespaces().Lister().Get(namespaceName)
if err != nil {
glog.Errorln("get namespace", namespaceName, err)
return nil, err
}
roleBindings, err := GetRoleBindings(namespaceName, "") roleBindings, err := GetRoleBindings(namespaceName, "")
if err != nil { if err != nil {
@@ -435,11 +456,16 @@ func NamespaceUsers(namespaceName string) ([]*models.User, error) {
for _, roleBinding := range roleBindings { for _, roleBinding := range roleBindings {
// controlled by ks-controller-manager // controlled by ks-controller-manager
if roleBinding.Name == "admin" || roleBinding.Name == "viewer" { if roleBinding.Name == NamespaceViewerRoleBindName {
continue continue
} }
for _, subject := range roleBinding.Subjects { for _, subject := range roleBinding.Subjects {
if subject.Kind == v1.UserKind && !k8sutil.ContainsUser(users, subject.Name) { if subject.Kind == rbacv1.UserKind && !k8sutil.ContainsUser(users, subject.Name) {
// show creator
if roleBinding.Name == NamespaceAdminRoleBindName && subject.Name != namespace.Annotations[constants.CreatorLabelAnnotationKey] {
continue
}
user, err := GetUserInfo(subject.Name) user, err := GetUserInfo(subject.Name)
@@ -466,6 +492,7 @@ func GetUserWorkspaceSimpleRules(workspace, username string) ([]models.SimpleRul
if err != nil { if err != nil {
return nil, err return nil, err
} }
if workspacesManager, err := policy.GetClusterAction("workspaces", "edit"); err == nil { if workspacesManager, err := policy.GetClusterAction("workspaces", "edit"); err == nil {
if rulesMatchesAction(clusterRules, workspacesManager) { if rulesMatchesAction(clusterRules, workspacesManager) {
return GetWorkspaceRoleSimpleRules(workspace, constants.WorkspaceAdmin), nil return GetWorkspaceRoleSimpleRules(workspace, constants.WorkspaceAdmin), nil
@@ -475,6 +502,9 @@ func GetUserWorkspaceSimpleRules(workspace, username string) ([]models.SimpleRul
workspaceRole, err := GetUserWorkspaceRole(workspace, username) workspaceRole, err := GetUserWorkspaceRole(workspace, username)
if err != nil { if err != nil {
if apierrors.IsNotFound(err) {
return []models.SimpleRule{}, nil
}
return nil, err return nil, err
} }
return GetWorkspaceRoleSimpleRules(workspace, workspaceRole.Annotations[constants.DisplayNameAnnotationKey]), nil return GetWorkspaceRoleSimpleRules(workspace, workspaceRole.Annotations[constants.DisplayNameAnnotationKey]), nil
@@ -523,6 +553,7 @@ func GetClusterRoleSimpleRules(clusterRoleName string) ([]models.SimpleRule, err
clusterRole, err := clusterRoleLister.Get(clusterRoleName) clusterRole, err := clusterRoleLister.Get(clusterRoleName)
if err != nil { if err != nil {
glog.Errorln("get cluster role", clusterRoleName, clusterRoleName)
return nil, err return nil, err
} }
@@ -558,13 +589,14 @@ func GetRoleSimpleRules(namespace string, roleName string) ([]models.SimpleRule,
role, err := roleLister.Roles(namespace).Get(roleName) role, err := roleLister.Roles(namespace).Get(roleName)
if err != nil { if err != nil {
glog.Errorln("get role", namespace, roleName, err)
return nil, err return nil, err
} }
return getSimpleRule(role.Rules), nil return getSimpleRule(role.Rules), nil
} }
func getClusterSimpleRule(policyRules []v1.PolicyRule) []models.SimpleRule { func getClusterSimpleRule(policyRules []rbacv1.PolicyRule) []models.SimpleRule {
rules := make([]models.SimpleRule, 0) rules := make([]models.SimpleRule, 0)
for i := 0; i < len(policy.ClusterRoleRuleMapping); i++ { for i := 0; i < len(policy.ClusterRoleRuleMapping); i++ {
@@ -582,7 +614,7 @@ func getClusterSimpleRule(policyRules []v1.PolicyRule) []models.SimpleRule {
return rules return rules
} }
func getSimpleRule(policyRules []v1.PolicyRule) []models.SimpleRule { func getSimpleRule(policyRules []rbacv1.PolicyRule) []models.SimpleRule {
simpleRules := make([]models.SimpleRule, 0) simpleRules := make([]models.SimpleRule, 0)
for i := 0; i < len(policy.RoleRuleMapping); i++ { for i := 0; i < len(policy.RoleRuleMapping); i++ {
rule := models.SimpleRule{Name: policy.RoleRuleMapping[i].Name} rule := models.SimpleRule{Name: policy.RoleRuleMapping[i].Name}
@@ -605,46 +637,76 @@ func CreateClusterRoleBinding(username string, clusterRoleName string) error {
_, err := clusterRoleLister.Get(clusterRoleName) _, err := clusterRoleLister.Get(clusterRoleName)
if err != nil { if err != nil {
glog.Errorln("get cluster role", clusterRoleName, err)
return err return err
} }
clusterRoleBinding := &v1.ClusterRoleBinding{} clusterRoleBinding := &rbacv1.ClusterRoleBinding{}
clusterRoleBinding.Name = username clusterRoleBinding.Name = username
clusterRoleBinding.RoleRef = v1.RoleRef{Name: clusterRoleName, Kind: ClusterRoleKind} clusterRoleBinding.RoleRef = rbacv1.RoleRef{Name: clusterRoleName, Kind: ClusterRoleKind}
clusterRoleBinding.Subjects = []v1.Subject{{Kind: v1.UserKind, Name: username}} clusterRoleBinding.Subjects = []rbacv1.Subject{{Kind: rbacv1.UserKind, Name: username}}
clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister() clusterRoleBindingLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister()
found, err := clusterRoleBindingLister.Get(username) found, err := clusterRoleBindingLister.Get(username)
if apierrors.IsNotFound(err) { if apierrors.IsNotFound(err) {
_, err = k8s.Client().RbacV1().ClusterRoleBindings().Create(clusterRoleBinding) _, err = k8s.Client().RbacV1().ClusterRoleBindings().Create(clusterRoleBinding)
return err if err != nil {
glog.Errorln("create cluster role binding", err)
return err
}
if clusterRoleName == constants.ClusterAdmin {
if err := kubeconfig.CreateKubeConfig(username); err != nil {
glog.Errorln("create user kubeconfig failed", username, err)
}
if err := kubectl.CreateKubectlDeploy(username); err != nil {
glog.Errorln("create user terminal pod failed", username, err)
}
}
return nil
} else if err != nil { } else if err != nil {
return err return err
} }
// cluster role changed // cluster role changed
if found.RoleRef.Name != clusterRoleBinding.RoleRef.Name { if found.RoleRef.Name != clusterRoleName {
deletePolicy := metav1.DeletePropagationForeground deletePolicy := metav1.DeletePropagationForeground
deleteOption := &metav1.DeleteOptions{PropagationPolicy: &deletePolicy} gracePeriodSeconds := int64(0)
err := k8s.Client().RbacV1().ClusterRoleBindings().Delete(clusterRoleBinding.Name, deleteOption) deleteOption := &metav1.DeleteOptions{PropagationPolicy: &deletePolicy, GracePeriodSeconds: &gracePeriodSeconds}
err = k8s.Client().RbacV1().ClusterRoleBindings().Delete(found.Name, deleteOption)
if err != nil { if err != nil {
glog.Errorln("delete cluster role binding", err)
return err return err
} }
if found.RoleRef.Name == constants.ClusterAdmin {
if err := kubeconfig.DelKubeConfig(username); err != nil {
glog.Error("delete user kubeconfig failed", username, err)
}
if err := kubectl.DelKubectlDeploy(username); err != nil {
glog.Error("delete user terminal pod failed", username, err)
}
}
_, err = k8s.Client().RbacV1().ClusterRoleBindings().Create(clusterRoleBinding) _, err = k8s.Client().RbacV1().ClusterRoleBindings().Create(clusterRoleBinding)
return err if err != nil {
glog.Errorln("create cluster role binding", err)
return err
}
return nil
} }
if !k8sutil.ContainsUser(found.Subjects, username) { if !k8sutil.ContainsUser(found.Subjects, username) {
found.Subjects = clusterRoleBinding.Subjects found.Subjects = clusterRoleBinding.Subjects
_, err = k8s.Client().RbacV1().ClusterRoleBindings().Update(found) _, err = k8s.Client().RbacV1().ClusterRoleBindings().Update(found)
return err if err != nil {
glog.Errorln("update cluster role binding", err)
return err
}
} }
return nil return nil
} }
func RulesMatchesRequired(rules []v1.PolicyRule, required v1.PolicyRule) bool { func RulesMatchesRequired(rules []rbacv1.PolicyRule, required rbacv1.PolicyRule) bool {
for _, rule := range rules { for _, rule := range rules {
if ruleMatchesRequired(rule, required) { if ruleMatchesRequired(rule, required) {
return true return true
@@ -653,7 +715,7 @@ func RulesMatchesRequired(rules []v1.PolicyRule, required v1.PolicyRule) bool {
return false return false
} }
func rulesMatchesAction(rules []v1.PolicyRule, action models.Action) bool { func rulesMatchesAction(rules []rbacv1.PolicyRule, action models.Action) bool {
for _, required := range action.Rules { for _, required := range action.Rules {
if !RulesMatchesRequired(rules, required) { if !RulesMatchesRequired(rules, required) {
@@ -664,7 +726,7 @@ func rulesMatchesAction(rules []v1.PolicyRule, action models.Action) bool {
return true return true
} }
func ruleMatchesRequired(rule v1.PolicyRule, required v1.PolicyRule) bool { func ruleMatchesRequired(rule rbacv1.PolicyRule, required rbacv1.PolicyRule) bool {
if len(required.NonResourceURLs) == 0 { if len(required.NonResourceURLs) == 0 {
for _, apiGroup := range required.APIGroups { for _, apiGroup := range required.APIGroups {
@@ -707,13 +769,13 @@ func ruleMatchesRequired(rule v1.PolicyRule, required v1.PolicyRule) bool {
return true return true
} }
func ruleMatchesResources(rule v1.PolicyRule, apiGroup string, resource string, subresource string, resourceName string) bool { func ruleMatchesResources(rule rbacv1.PolicyRule, apiGroup string, resource string, subresource string, resourceName string) bool {
if resource == "" { if resource == "" {
return false return false
} }
if !hasString(rule.APIGroups, apiGroup) && !hasString(rule.APIGroups, v1.ResourceAll) { if !hasString(rule.APIGroups, apiGroup) && !hasString(rule.APIGroups, rbacv1.ResourceAll) {
return false return false
} }
@@ -730,7 +792,7 @@ func ruleMatchesResources(rule v1.PolicyRule, apiGroup string, resource string,
for _, res := range rule.Resources { for _, res := range rule.Resources {
// match "*" // match "*"
if res == v1.ResourceAll || res == combinedResource { if res == rbacv1.ResourceAll || res == combinedResource {
return true return true
} }
@@ -747,9 +809,9 @@ func ruleMatchesResources(rule v1.PolicyRule, apiGroup string, resource string,
return false return false
} }
func ruleMatchesRequest(rule v1.PolicyRule, apiGroup string, nonResourceURL string, resource string, subresource string, resourceName string, verb string) bool { 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, v1.VerbAll) { if !hasString(rule.Verbs, verb) && !hasString(rule.Verbs, rbacv1.VerbAll) {
return false return false
} }
@@ -760,7 +822,7 @@ func ruleMatchesRequest(rule v1.PolicyRule, apiGroup string, nonResourceURL stri
} }
} }
func ruleMatchesNonResource(rule v1.PolicyRule, nonResourceURL string) bool { func ruleMatchesNonResource(rule rbacv1.PolicyRule, nonResourceURL string) bool {
if nonResourceURL == "" { if nonResourceURL == "" {
return false return false

View File

@@ -18,8 +18,10 @@
package iam package iam
import ( import (
"encoding/json"
"errors" "errors"
"fmt" "fmt"
"io/ioutil"
"kubesphere.io/kubesphere/pkg/constants" "kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/informers" "kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/params" "kubesphere.io/kubesphere/pkg/params"
@@ -51,6 +53,10 @@ var (
tokenExpireTime time.Duration tokenExpireTime time.Duration
) )
const (
userInitFile = "/etc/ks-iam/users.json"
)
func Init(email, password string, t time.Duration) error { func Init(email, password string, t time.Duration) error {
adminEmail = email adminEmail = email
adminPassword = password adminPassword = password
@@ -67,12 +73,18 @@ func Init(email, password string, t time.Duration) error {
err = checkAndCreateDefaultUser(conn) err = checkAndCreateDefaultUser(conn)
if err != nil { if err != nil {
glog.Errorln("create default users", err)
return err return err
} }
err = checkAndCreateDefaultGroup(conn) err = checkAndCreateDefaultGroup(conn)
return err if err != nil {
glog.Errorln("create default groups", err)
return err
}
return nil
} }
func checkAndCreateDefaultGroup(conn ldap.Client) error { func checkAndCreateDefaultGroup(conn ldap.Client) error {
@@ -124,10 +136,19 @@ func checkAndCreateDefaultUser(conn ldap.Client) error {
return fmt.Errorf("iam database init failed: %s\n", err) return fmt.Errorf("iam database init failed: %s\n", err)
} }
if users == nil || len(users.Entries) == 0 { data, err := ioutil.ReadFile(userInitFile)
_, err := CreateUser(&models.User{Username: constants.AdminUserName, Email: adminEmail, Password: adminPassword, Description: "Administrator account that was always created by default."}) var initUsers []models.User
if err != nil { if err == nil {
return fmt.Errorf("admin create failed: %s\n", err) 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})
if users == nil || len(users.Entries) < len(initUsers) {
for _, user := range initUsers {
_, err = CreateUser(&user)
if err != nil && !ldap.IsErrorWithCode(err, ldap.LDAPResultEntryAlreadyExists) {
return fmt.Errorf("user %s init failed: %s\n", user.Username, err)
}
} }
} }
@@ -192,6 +213,7 @@ func Login(username string, password string, ip string) (*models.Token, error) {
err = conn.Bind(dn, password) err = conn.Bind(dn, password)
if err != nil { if err != nil {
glog.Errorln("auth error", username, err)
return nil, err return nil, err
} }
@@ -228,55 +250,6 @@ func LoginLog(username string) ([]string, error) {
return data, nil return data, nil
} }
func ListUsersByName(names []string) (*models.PageableResponse, error) {
users := make([]*models.User, 0)
for _, name := range names {
if !k8sutil.ContainsUser(users, name) {
user, err := GetUserInfo(name)
if err != nil {
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
continue
}
return nil, err
}
users = append(users, user)
}
}
items := make([]interface{}, 0)
for _, u := range users {
items = append(items, u)
}
return &models.PageableResponse{Items: items, TotalCount: len(items)}, nil
}
func ListUserByEmail(email []string) (*models.PageableResponse, error) {
users := make([]*models.User, 0)
for _, mail := range email {
user, err := GetUserInfoByEmail(mail)
if err != nil {
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
continue
}
return nil, err
}
if !k8sutil.ContainsUser(users, user.Username) {
users = append(users, user)
}
}
items := make([]interface{}, 0)
for _, u := range users {
items = append(items, u)
}
return &models.PageableResponse{Items: items, TotalCount: len(items)}, nil
}
func ListUsers(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) { func ListUsers(conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
conn, err := ldapclient.Client() conn, err := ldapclient.Client()
@@ -325,6 +298,7 @@ func ListUsers(conditions *params.Conditions, orderBy string, reverse bool, limi
response, err := conn.Search(userSearchRequest) response, err := conn.Search(userSearchRequest)
if err != nil { if err != nil {
glog.Errorln("search user", err)
return nil, err return nil, err
} }
@@ -396,55 +370,15 @@ func DescribeUser(username string) (*models.User, error) {
groups, err := GetUserGroups(username) groups, err := GetUserGroups(username)
if err != nil { if err == nil {
return nil, err user.Groups = groups
} }
user.Groups = groups
user.AvatarUrl = getAvatar(username) user.AvatarUrl = getAvatar(username)
return user, nil return user, nil
} }
func GetUserInfoByEmail(mail string) (*models.User, error) {
conn, err := ldapclient.Client()
if err != nil {
return nil, err
}
userSearchRequest := ldap.NewSearchRequest(
ldapclient.UserSearchBase,
ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, 0, false,
fmt.Sprintf("(&(objectClass=inetOrgPerson)(mail=%s))", mail),
[]string{"uid", "description", "preferredLanguage", "createTimestamp"},
nil,
)
result, err := conn.Search(userSearchRequest)
if err != nil {
return nil, err
}
if len(result.Entries) != 1 {
return nil, ldap.NewError(ldap.LDAPResultNoSuchObject, fmt.Errorf("user %s does not exist", mail))
}
username := result.Entries[0].GetAttributeValue("uid")
description := result.Entries[0].GetAttributeValue("description")
lang := result.Entries[0].GetAttributeValue("preferredLanguage")
createTimestamp, _ := time.Parse("20060102150405Z", result.Entries[0].GetAttributeValue("createTimestamp"))
user := &models.User{Username: username, Email: mail, Description: description, Lang: lang, CreateTime: createTimestamp}
user.LastLoginTime = getLastLoginTime(username)
clusterRole, err := GetUserClusterRole(user.Username)
if err != nil {
return nil, err
}
user.ClusterRole = clusterRole.Name
return user, nil
}
// Get user info only included email description & lang // Get user info only included email description & lang
func GetUserInfo(username string) (*models.User, error) { func GetUserInfo(username string) (*models.User, error) {
@@ -465,6 +399,7 @@ func GetUserInfo(username string) (*models.User, error) {
result, err := conn.Search(userSearchRequest) result, err := conn.Search(userSearchRequest)
if err != nil { if err != nil {
glog.Errorln("search user", err)
return nil, err return nil, err
} }
@@ -567,6 +502,7 @@ func DeleteUser(username string) error {
err = conn.Del(deleteRequest) err = conn.Del(deleteRequest)
if err != nil { if err != nil {
glog.Errorln("delete user", err)
return err return err
} }
@@ -673,14 +609,11 @@ func UserCreateCheck(check string) (exist bool, err error) {
result, err := conn.Search(userSearchRequest) result, err := conn.Search(userSearchRequest)
if err != nil { if err != nil {
glog.Errorln("search user", err)
return false, err return false, err
} }
if len(result.Entries) > 0 { return len(result.Entries) > 0, nil
return true, nil
} else {
return false, nil
}
} }
func CreateUser(user *models.User) (*models.User, error) { func CreateUser(user *models.User) (*models.User, error) {
@@ -708,6 +641,7 @@ func CreateUser(user *models.User) (*models.User, error) {
result, err := conn.Search(userSearchRequest) result, err := conn.Search(userSearchRequest)
if err != nil { if err != nil {
glog.Errorln("search user", err)
return nil, err return nil, err
} }
@@ -718,6 +652,7 @@ func CreateUser(user *models.User) (*models.User, error) {
maxUid, err := getMaxUid(conn) maxUid, err := getMaxUid(conn)
if err != nil { if err != nil {
glog.Errorln("get max uid", err)
return nil, err return nil, err
} }
@@ -743,6 +678,7 @@ func CreateUser(user *models.User) (*models.User, error) {
err = conn.Add(userCreateRequest) err = conn.Add(userCreateRequest)
if err != nil { if err != nil {
glog.Errorln("create user", err)
return nil, err return nil, err
} }
@@ -754,6 +690,7 @@ func CreateUser(user *models.User) (*models.User, error) {
err := CreateClusterRoleBinding(user.Username, user.ClusterRole) err := CreateClusterRoleBinding(user.Username, user.ClusterRole)
if err != nil { if err != nil {
glog.Errorln("create cluster role binding filed", err)
return nil, err return nil, err
} }
} }
@@ -864,6 +801,7 @@ func UpdateUser(user *models.User) (*models.User, error) {
err = CreateClusterRoleBinding(user.Username, user.ClusterRole) err = CreateClusterRoleBinding(user.Username, user.ClusterRole)
if err != nil { if err != nil {
glog.Errorln("create cluster role binding filed", err)
return nil, err return nil, err
} }
@@ -884,6 +822,7 @@ func DeleteGroup(path string) error {
err = conn.Del(groupDeleteRequest) err = conn.Del(groupDeleteRequest)
if err != nil { if err != nil {
glog.Errorln("delete user group", err)
return err return err
} }
@@ -903,6 +842,7 @@ func CreateGroup(group *models.Group) (*models.Group, error) {
maxGid, err := getMaxGid(conn) maxGid, err := getMaxGid(conn)
if err != nil { if err != nil {
glog.Errorln("get max gid", err)
return nil, err return nil, err
} }
@@ -930,6 +870,7 @@ func CreateGroup(group *models.Group) (*models.Group, error) {
err = conn.Add(groupCreateRequest) err = conn.Add(groupCreateRequest)
if err != nil { if err != nil {
glog.Errorln("create group", err)
return nil, err return nil, err
} }
@@ -976,45 +917,13 @@ func UpdateGroup(group *models.Group) (*models.Group, error) {
err = conn.Modify(groupUpdateRequest) err = conn.Modify(groupUpdateRequest)
if err != nil { if err != nil {
glog.Errorln("update group", err)
return nil, err return nil, err
} }
return group, nil return group, nil
} }
func CountChild(path string) (int, error) {
// bind root DN
conn, err := ldapclient.Client()
if err != nil {
return 0, err
}
defer conn.Close()
var groupSearchRequest *ldap.SearchRequest
if path == "" {
groupSearchRequest = ldap.NewSearchRequest(ldapclient.GroupSearchBase,
ldap.ScopeSingleLevel, ldap.NeverDerefAliases, 0, 0, false,
"(&(objectClass=posixGroup))",
[]string{"cn", "gidNumber", "memberUid", "description"},
nil)
} else {
searchBase, cn := splitPath(path)
groupSearchRequest = ldap.NewSearchRequest(fmt.Sprintf("cn=%s,%s", cn, searchBase),
ldap.ScopeSingleLevel, ldap.NeverDerefAliases, 0, 0, false,
"(&(objectClass=posixGroup))",
[]string{"cn", "gidNumber", "memberUid", "description"},
nil)
}
result, err := conn.Search(groupSearchRequest)
if err != nil {
return 0, err
}
return len(result.Entries), nil
}
func ChildList(path string) ([]models.Group, error) { func ChildList(path string) ([]models.Group, error) {
// bind root DN // bind root DN
@@ -1105,6 +1014,7 @@ func DescribeGroup(path string) (*models.Group, error) {
result, err := conn.Search(groupSearchRequest) result, err := conn.Search(groupSearchRequest)
if err != nil { if err != nil {
glog.Errorln("search group", err)
return nil, err return nil, err
} }

View File

@@ -101,11 +101,6 @@ var (
APIGroups: []string{"rbac.authorization.k8s.io"}, APIGroups: []string{"rbac.authorization.k8s.io"},
Resources: []string{"rolebindings", "roles"}, Resources: []string{"rolebindings", "roles"},
}, },
{
Verbs: []string{"*"},
APIGroups: []string{"jenkins.kubesphere.io", "devops.kubesphere.io"},
Resources: []string{"*"},
},
}, },
}, },
}, },

View File

@@ -26,6 +26,7 @@ import (
"crypto/x509/pkix" "crypto/x509/pkix"
"encoding/base64" "encoding/base64"
"encoding/pem" "encoding/pem"
"fmt"
"io/ioutil" "io/ioutil"
"kubesphere.io/kubesphere/pkg/simple/client/k8s" "kubesphere.io/kubesphere/pkg/simple/client/k8s"
"math/big" "math/big"
@@ -208,7 +209,7 @@ func generateCaAndKey(user, caPath, keyPath string) (string, string, error) {
return base64Cert, base64Key, nil return base64Cert, base64Key, nil
} }
func createKubeConfig(userName string) (string, error) { func createKubeConfig(username string) (string, error) {
tmpKubeConfig := kubeConfig{ApiVersion: "v1", Kind: "Config"} tmpKubeConfig := kubeConfig{ApiVersion: "v1", Kind: "Config"}
serverCa, err := ioutil.ReadFile(caPath) serverCa, err := ioutil.ReadFile(caPath)
if err != nil { if err != nil {
@@ -220,17 +221,17 @@ func createKubeConfig(userName string) (string, error) {
tmpCluster := cluster{Cluster: tmpClusterInfo, Name: clusterName} tmpCluster := cluster{Cluster: tmpClusterInfo, Name: clusterName}
tmpKubeConfig.Clusters = append(tmpKubeConfig.Clusters, tmpCluster) tmpKubeConfig.Clusters = append(tmpKubeConfig.Clusters, tmpCluster)
contextName := userName + "@" + clusterName contextName := username + "@" + clusterName
tmpContext := contextObject{Context: contextInfo{User: userName, Cluster: clusterName, NameSpace: defaultNamespace}, Name: contextName} tmpContext := contextObject{Context: contextInfo{User: username, Cluster: clusterName, NameSpace: defaultNamespace}, Name: contextName}
tmpKubeConfig.Contexts = append(tmpKubeConfig.Contexts, tmpContext) tmpKubeConfig.Contexts = append(tmpKubeConfig.Contexts, tmpContext)
cert, key, err := generateCaAndKey(userName, caPath, keyPath) cert, key, err := generateCaAndKey(username, caPath, keyPath)
if err != nil { if err != nil {
return "", err return "", err
} }
tmpUser := user{User: userInfo{CaData: cert, KeyData: key}, Name: userName} tmpUser := user{User: userInfo{CaData: cert, KeyData: key}, Name: username}
tmpKubeConfig.Users = append(tmpKubeConfig.Users, tmpUser) tmpKubeConfig.Users = append(tmpKubeConfig.Users, tmpUser)
tmpKubeConfig.CurrentContext = contextName tmpKubeConfig.CurrentContext = contextName
@@ -242,23 +243,23 @@ func createKubeConfig(userName string) (string, error) {
return string(config), nil return string(config), nil
} }
func CreateKubeConfig(user string) error { func CreateKubeConfig(username string) error {
k8sClient := k8s.Client() k8sClient := k8s.Client()
configName := fmt.Sprintf("kubeconfig-%s", username)
_, err := k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Get(user, metaV1.GetOptions{}) _, err := k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Get(configName, metaV1.GetOptions{})
if errors.IsNotFound(err) { if errors.IsNotFound(err) {
config, err := createKubeConfig(user) config, err := createKubeConfig(username)
if err != nil { if err != nil {
glog.Errorln(err) glog.Errorln(err)
return err return err
} }
data := map[string]string{"config": string(config)} data := map[string]string{"config": string(config)}
configMap := v1.ConfigMap{TypeMeta: metaV1.TypeMeta{Kind: "Configmap", APIVersion: "v1"}, ObjectMeta: metaV1.ObjectMeta{Name: user}, Data: data} configMap := v1.ConfigMap{TypeMeta: metaV1.TypeMeta{Kind: "Configmap", APIVersion: "v1"}, ObjectMeta: metaV1.ObjectMeta{Name: configName}, Data: data}
_, err = k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Create(&configMap) _, err = k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Create(&configMap)
if err != nil && !errors.IsAlreadyExists(err) { if err != nil && !errors.IsAlreadyExists(err) {
glog.Errorf("create user %s's kubeConfig failed, reason: %v", user, err) glog.Errorf("create username %s's kubeConfig failed, reason: %v", username, err)
return err return err
} }
} }
@@ -267,27 +268,29 @@ func CreateKubeConfig(user string) error {
} }
func GetKubeConfig(user string) (string, error) { func GetKubeConfig(username string) (string, error) {
k8sClient := k8s.Client() k8sClient := k8s.Client()
configMap, err := k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Get(user, metaV1.GetOptions{}) configName := fmt.Sprintf("kubeconfig-%s", username)
configMap, err := k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Get(configName, metaV1.GetOptions{})
if err != nil { if err != nil {
glog.Errorf("cannot get user %s's kubeConfig, reason: %v", user, err) glog.Errorf("cannot get username %s's kubeConfig, reason: %v", username, err)
return "", err return "", err
} }
return configMap.Data[kubectlConfigKey], nil return configMap.Data[kubectlConfigKey], nil
} }
func DelKubeConfig(user string) error { func DelKubeConfig(username string) error {
k8sClient := k8s.Client() k8sClient := k8s.Client()
_, err := k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Get(user, metaV1.GetOptions{}) configName := fmt.Sprintf("kubeconfig-%s", username)
_, err := k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Get(configName, metaV1.GetOptions{})
if errors.IsNotFound(err) { if errors.IsNotFound(err) {
return nil return nil
} }
deletePolicy := metaV1.DeletePropagationBackground deletePolicy := metaV1.DeletePropagationBackground
err = k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Delete(user, &metaV1.DeleteOptions{PropagationPolicy: &deletePolicy}) err = k8sClient.CoreV1().ConfigMaps(constants.KubeSphereControlNamespace).Delete(configName, &metaV1.DeleteOptions{PropagationPolicy: &deletePolicy})
if err != nil { if err != nil {
glog.Errorf("delete user %s's kubeConfig failed, reason: %v", user, err) glog.Errorf("delete username %s's kubeConfig failed, reason: %v", username, err)
return err return err
} }
return nil return nil

View File

@@ -23,9 +23,10 @@ import (
"kubesphere.io/kubesphere/pkg/models" "kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/simple/client/k8s" "kubesphere.io/kubesphere/pkg/simple/client/k8s"
"math/rand" "math/rand"
"os"
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/api/apps/v1beta2" appsv1 "k8s.io/api/apps/v1"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels" "k8s.io/apimachinery/pkg/labels"
@@ -39,9 +40,18 @@ const (
namespace = constants.KubeSphereControlNamespace namespace = constants.KubeSphereControlNamespace
) )
var DefaultImage = "kubesphere/kubectl:advanced-1.0.0"
func init() {
if env := os.Getenv("KUBECTL_IMAGE"); env != "" {
DefaultImage = env
}
}
func GetKubectlPod(username string) (models.PodInfo, error) { func GetKubectlPod(username string) (models.PodInfo, error) {
k8sClient := k8s.Client() k8sClient := k8s.Client()
deploy, err := k8sClient.AppsV1beta2().Deployments(namespace).Get(username, metav1.GetOptions{}) deployName := fmt.Sprintf("kubectl-%s", username)
deploy, err := k8sClient.AppsV1().Deployments(namespace).Get(deployName, metav1.GetOptions{})
if err != nil { if err != nil {
glog.Errorln(err) glog.Errorln(err)
return models.PodInfo{}, err return models.PodInfo{}, err
@@ -86,33 +96,35 @@ func selectCorrectPod(namespace string, pods []v1.Pod) (kubectlPod v1.Pod, err e
return kubectlPodList[random], nil return kubectlPodList[random], nil
} }
func CreateKubectlDeploy(user string) error { func CreateKubectlDeploy(username string) error {
k8sClient := k8s.Client() k8sClient := k8s.Client()
_, err := k8sClient.AppsV1().Deployments(namespace).Get(user, metav1.GetOptions{}) deployName := fmt.Sprintf("kubectl-%s", username)
configName := fmt.Sprintf("kubeconfig-%s", username)
_, err := k8sClient.AppsV1().Deployments(namespace).Get(deployName, metav1.GetOptions{})
if err == nil { if err == nil {
return nil return nil
} }
replica := int32(1) replica := int32(1)
selector := metav1.LabelSelector{MatchLabels: map[string]string{"user": user}} selector := metav1.LabelSelector{MatchLabels: map[string]string{"username": username}}
config := v1.ConfigMapVolumeSource{Items: []v1.KeyToPath{{Key: "config", Path: "config"}}, LocalObjectReference: v1.LocalObjectReference{Name: user}} config := v1.ConfigMapVolumeSource{Items: []v1.KeyToPath{{Key: "config", Path: "config"}}, LocalObjectReference: v1.LocalObjectReference{Name: configName}}
deployment := v1beta2.Deployment{ deployment := appsv1.Deployment{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Name: user, Name: deployName,
}, },
Spec: v1beta2.DeploymentSpec{ Spec: appsv1.DeploymentSpec{
Replicas: &replica, Replicas: &replica,
Selector: &selector, Selector: &selector,
Template: v1.PodTemplateSpec{ Template: v1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{ ObjectMeta: metav1.ObjectMeta{
Labels: map[string]string{ Labels: map[string]string{
"user": user, "username": username,
}, },
}, },
Spec: v1.PodSpec{ Spec: v1.PodSpec{
Containers: []v1.Container{ Containers: []v1.Container{
{Name: "kubectl", {Name: "kubectl",
Image: "", Image: DefaultImage,
VolumeMounts: []v1.VolumeMount{{Name: "kubeconfig", MountPath: "/root/.kube"}}, VolumeMounts: []v1.VolumeMount{{Name: "kubeconfig", MountPath: "/root/.kube"}},
}, },
}, },
@@ -122,28 +134,29 @@ func CreateKubectlDeploy(user string) error {
}, },
} }
_, err = k8sClient.AppsV1beta2().Deployments(namespace).Create(&deployment) _, err = k8sClient.AppsV1().Deployments(namespace).Create(&deployment)
return err return err
} }
func DelKubectlDeploy(user string) error { func DelKubectlDeploy(username string) error {
k8sClient := k8s.Client() k8sClient := k8s.Client()
_, err := k8sClient.AppsV1beta2().Deployments(namespace).Get(user, metav1.GetOptions{}) deployName := fmt.Sprintf("kubectl-%s", username)
_, err := k8sClient.AppsV1().Deployments(namespace).Get(deployName, metav1.GetOptions{})
if errors.IsNotFound(err) { if errors.IsNotFound(err) {
return nil return nil
} }
if err != nil { if err != nil {
err := fmt.Errorf("delete user %s failed, reason:%v", user, err) err := fmt.Errorf("delete username %s failed, reason:%v", username, err)
return err return err
} }
deletePolicy := metav1.DeletePropagationBackground deletePolicy := metav1.DeletePropagationBackground
err = k8sClient.AppsV1beta2().Deployments(namespace).Delete(user, &metav1.DeleteOptions{PropagationPolicy: &deletePolicy}) err = k8sClient.AppsV1().Deployments(namespace).Delete(deployName, &metav1.DeleteOptions{PropagationPolicy: &deletePolicy})
if err != nil { if err != nil {
err := fmt.Errorf("delete user %s failed, reason:%v", user, err) err := fmt.Errorf("delete username %s failed, reason:%v", username, err)
return err return err
} }

View File

@@ -47,7 +47,7 @@ func GetNamespacesWithMetrics(namespaces []*v1.Namespace) []*v1.Namespace {
for _, data := range result.Data.Result { for _, data := range result.Data.Result {
metricDescMap, ok := data["metric"].(map[string]interface{}) metricDescMap, ok := data["metric"].(map[string]interface{})
if ok { if ok {
if ns, exist := metricDescMap["namespace"]; exist { if ns, exist := metricDescMap["resource_name"]; exist {
timeAndValue, ok := data["value"].([]interface{}) timeAndValue, ok := data["value"].([]interface{})
if ok && len(timeAndValue) == 2 { if ok && len(timeAndValue) == 2 {
for i := 0; i < len(namespaces); i++ { for i := 0; i < len(namespaces); i++ {

View File

@@ -25,7 +25,7 @@ import (
"time" "time"
"github.com/golang/glog" "github.com/golang/glog"
"k8s.io/api/apps/v1beta2" appsv1 "k8s.io/api/apps/v1"
"k8s.io/api/core/v1" "k8s.io/api/core/v1"
policy "k8s.io/api/policy/v1beta1" policy "k8s.io/api/policy/v1beta1"
apierrors "k8s.io/apimachinery/pkg/api/errors" apierrors "k8s.io/apimachinery/pkg/api/errors"
@@ -78,7 +78,7 @@ func drainEviction(nodename string, donech chan bool, errch chan error) {
errch <- err errch <- err
} }
options.FieldSelector = "" options.FieldSelector = ""
daemonsetList, err := k8sclient.AppsV1beta2().DaemonSets("").List(options) daemonsetList, err := k8sclient.AppsV1().DaemonSets("").List(options)
if err != nil { if err != nil {
@@ -142,7 +142,7 @@ func isMirrorPod(pod *v1.Pod) bool {
return ok return ok
} }
func containDaemonset(pod v1.Pod, daemonsetList v1beta2.DaemonSetList) bool { func containDaemonset(pod v1.Pod, daemonsetList appsv1.DaemonSetList) bool {
flag := false flag := false
for _, daemonset := range daemonsetList.Items { for _, daemonset := range daemonsetList.Items {

View File

@@ -41,11 +41,11 @@ func (*clusterRoleSearcher) get(namespace, name string) (interface{}, error) {
func (*clusterRoleSearcher) match(match map[string]string, item *rbac.ClusterRole) bool { func (*clusterRoleSearcher) match(match map[string]string, item *rbac.ClusterRole) bool {
for k, v := range match { for k, v := range match {
switch k { switch k {
case ownerKind: case OwnerKind:
fallthrough fallthrough
case ownerName: case OwnerName:
kind := match[ownerKind] kind := match[OwnerKind]
name := match[ownerName] name := match[OwnerName]
if !k8sutil.IsControlledBy(item.OwnerReferences, kind, name) { if !k8sutil.IsControlledBy(item.OwnerReferences, kind, name) {
return false return false
} }
@@ -81,7 +81,7 @@ func (*clusterRoleSearcher) fuzzy(fuzzy map[string]string, item *rbac.ClusterRol
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) { if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false return false
} }
case label: case Label:
if !searchFuzzy(item.Labels, "", v) { if !searchFuzzy(item.Labels, "", v) {
return false return false
} }

View File

@@ -66,7 +66,7 @@ func (*configMapSearcher) fuzzy(fuzzy map[string]string, item *v1.ConfigMap) boo
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) { if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false return false
} }
case label: case Label:
if !searchFuzzy(item.Labels, "", v) { if !searchFuzzy(item.Labels, "", v) {
return false return false
} }

View File

@@ -78,7 +78,7 @@ func (*cronJobSearcher) fuzzy(fuzzy map[string]string, item *v1beta1.CronJob) bo
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) { if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false return false
} }
case label: case Label:
if !searchFuzzy(item.Labels, "", v) { if !searchFuzzy(item.Labels, "", v) {
return false return false
} }
@@ -103,7 +103,7 @@ func (*cronJobSearcher) fuzzy(fuzzy map[string]string, item *v1beta1.CronJob) bo
func (*cronJobSearcher) compare(a, b *v1beta1.CronJob, orderBy string) bool { func (*cronJobSearcher) compare(a, b *v1beta1.CronJob, orderBy string) bool {
switch orderBy { switch orderBy {
case lastScheduleTime: case LastScheduleTime:
if a.Status.LastScheduleTime == nil { if a.Status.LastScheduleTime == nil {
return true return true
} }

View File

@@ -80,7 +80,7 @@ func (*daemonSetSearcher) fuzzy(fuzzy map[string]string, item *v1.DaemonSet) boo
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) { if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false return false
} }
case label: case Label:
if !searchFuzzy(item.Labels, "", v) { if !searchFuzzy(item.Labels, "", v) {
return false return false
} }

View File

@@ -84,7 +84,7 @@ func (*deploymentSearcher) fuzzy(fuzzy map[string]string, item *v1.Deployment) b
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) { if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false return false
} }
case label: case Label:
if !searchFuzzy(item.Labels, "", v) { if !searchFuzzy(item.Labels, "", v) {
return false return false
} }

View File

@@ -67,7 +67,7 @@ func (*ingressSearcher) fuzzy(fuzzy map[string]string, item *extensions.Ingress)
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) { if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false return false
} }
case label: case Label:
if !searchFuzzy(item.Labels, "", v) { if !searchFuzzy(item.Labels, "", v) {
return false return false
} }

View File

@@ -86,7 +86,7 @@ func (*jobSearcher) fuzzy(fuzzy map[string]string, item *batchv1.Job) bool {
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) { if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false return false
} }
case label: case Label:
if !searchFuzzy(item.Labels, "", v) { if !searchFuzzy(item.Labels, "", v) {
return false return false
} }
@@ -126,7 +126,7 @@ func (*jobSearcher) compare(a, b *batchv1.Job, orderBy string) bool {
switch orderBy { switch orderBy {
case CreateTime: case CreateTime:
return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time) return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time)
case updateTime: case UpdateTime:
return jobUpdateTime(a).Before(jobUpdateTime(b)) return jobUpdateTime(a).Before(jobUpdateTime(b))
case Name: case Name:
fallthrough fallthrough

View File

@@ -66,7 +66,7 @@ func (*namespaceSearcher) fuzzy(fuzzy map[string]string, item *v1.Namespace) boo
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) { if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false return false
} }
case label: case Label:
if !searchFuzzy(item.Labels, "", v) { if !searchFuzzy(item.Labels, "", v) {
return false return false
} }

View File

@@ -66,7 +66,7 @@ func (*nodeSearcher) fuzzy(fuzzy map[string]string, item *v1.Node) bool {
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) { if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false return false
} }
case label: case Label:
if !searchFuzzy(item.Labels, "", v) { if !searchFuzzy(item.Labels, "", v) {
return false return false
} }

View File

@@ -66,7 +66,7 @@ func (*persistentVolumeClaimSearcher) fuzzy(fuzzy map[string]string, item *v1.Pe
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) { if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false return false
} }
case label: case Label:
if !searchFuzzy(item.Labels, "", v) { if !searchFuzzy(item.Labels, "", v) {
return false return false
} }

View File

@@ -18,7 +18,7 @@
package resources package resources
import ( import (
v12 "k8s.io/api/apps/v1" appsv1 "k8s.io/api/apps/v1"
"kubesphere.io/kubesphere/pkg/constants" "kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/informers" "kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/params" "kubesphere.io/kubesphere/pkg/params"
@@ -63,7 +63,7 @@ func podBelongTo(item *v1.Pod, kind string, name string) bool {
return false return false
} }
func replicaSetBelongToDeployment(replicaSet *v12.ReplicaSet, deploymentName string) bool { func replicaSetBelongToDeployment(replicaSet *appsv1.ReplicaSet, deploymentName string) bool {
for _, owner := range replicaSet.OwnerReferences { for _, owner := range replicaSet.OwnerReferences {
if owner.Kind == "Deployment" && owner.Name == deploymentName { if owner.Kind == "Deployment" && owner.Name == deploymentName {
return true return true
@@ -150,11 +150,11 @@ func podBelongToService(item *v1.Pod, serviceName string) bool {
func (*podSearcher) match(match map[string]string, item *v1.Pod) bool { func (*podSearcher) match(match map[string]string, item *v1.Pod) bool {
for k, v := range match { for k, v := range match {
switch k { switch k {
case ownerKind: case OwnerKind:
fallthrough fallthrough
case ownerName: case OwnerName:
kind := match[ownerKind] kind := match[OwnerKind]
name := match[ownerName] name := match[OwnerName]
if !podBelongTo(item, kind, name) { if !podBelongTo(item, kind, name) {
return false return false
} }
@@ -196,7 +196,7 @@ func (*podSearcher) fuzzy(fuzzy map[string]string, item *v1.Pod) bool {
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) { if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false return false
} }
case label: case Label:
if !searchFuzzy(item.Labels, "", v) { if !searchFuzzy(item.Labels, "", v) {
return false return false
} }

View File

@@ -19,6 +19,7 @@ package resources
import ( import (
"fmt" "fmt"
"github.com/golang/glog"
"kubesphere.io/kubesphere/pkg/models" "kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/params" "kubesphere.io/kubesphere/pkg/params"
"kubesphere.io/kubesphere/pkg/utils/sliceutil" "kubesphere.io/kubesphere/pkg/utils/sliceutil"
@@ -56,12 +57,12 @@ var (
const ( const (
Name = "name" Name = "name"
label = "label" Label = "label"
ownerKind = "ownerKind" OwnerKind = "ownerKind"
ownerName = "ownerName" OwnerName = "ownerName"
CreateTime = "createTime" CreateTime = "createTime"
updateTime = "updateTime" UpdateTime = "updateTime"
lastScheduleTime = "lastScheduleTime" LastScheduleTime = "lastScheduleTime"
chart = "chart" chart = "chart"
release = "release" release = "release"
annotation = "annotation" annotation = "annotation"
@@ -106,6 +107,7 @@ func GetResource(namespace, resource, name string) (interface{}, error) {
if searcher, ok := resources[resource]; ok { if searcher, ok := resources[resource]; ok {
resource, err := searcher.get(namespace, name) resource, err := searcher.get(namespace, name)
if err != nil { if err != nil {
glog.Errorln("get resource", namespace, resource, name, err)
return nil, err return nil, err
} }
return resource, nil return resource, nil
@@ -120,16 +122,19 @@ func ListResources(namespace, resource string, conditions *params.Conditions, or
// none namespace resource // none namespace resource
if namespace != "" && sliceutil.HasString(clusterResources, resource) { if namespace != "" && sliceutil.HasString(clusterResources, resource) {
glog.Errorln("resources not found", resource)
return nil, fmt.Errorf("not found") return nil, fmt.Errorf("not found")
} }
if searcher, ok := resources[resource]; ok { if searcher, ok := resources[resource]; ok {
result, err = searcher.search(namespace, conditions, orderBy, reverse) result, err = searcher.search(namespace, conditions, orderBy, reverse)
} else { } else {
glog.Errorln("resources not found", resource)
return nil, fmt.Errorf("not found") return nil, fmt.Errorf("not found")
} }
if err != nil { if err != nil {
glog.Errorln("resources search", err)
return nil, err return nil, err
} }

View File

@@ -66,7 +66,7 @@ func (*roleSearcher) fuzzy(fuzzy map[string]string, item *rbac.Role) bool {
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) { if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false return false
} }
case label: case Label:
if !searchFuzzy(item.Labels, "", v) { if !searchFuzzy(item.Labels, "", v) {
return false return false
} }

View File

@@ -66,7 +66,7 @@ func (*s2iBuilderSearcher) fuzzy(fuzzy map[string]string, item *v1alpha1.S2iBuil
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) { if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false return false
} }
case label: case Label:
if !searchFuzzy(item.Labels, "", v) { if !searchFuzzy(item.Labels, "", v) {
return false return false
} }

View File

@@ -66,7 +66,7 @@ func (*s2iBuilderTemplateSearcher) fuzzy(fuzzy map[string]string, item *v1alpha1
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) { if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false return false
} }
case label: case Label:
if !searchFuzzy(item.Labels, "", v) { if !searchFuzzy(item.Labels, "", v) {
return false return false
} }

View File

@@ -73,7 +73,7 @@ func (*s2iRunSearcher) fuzzy(fuzzy map[string]string, item *v1alpha1.S2iRun) boo
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) { if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false return false
} }
case label: case Label:
if !searchFuzzy(item.Labels, "", v) { if !searchFuzzy(item.Labels, "", v) {
return false return false
} }

View File

@@ -70,7 +70,7 @@ func (*secretSearcher) fuzzy(fuzzy map[string]string, item *v1.Secret) bool {
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) { if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false return false
} }
case label: case Label:
if !searchFuzzy(item.Labels, "", v) { if !searchFuzzy(item.Labels, "", v) {
return false return false
} }

View File

@@ -66,7 +66,7 @@ func (*serviceSearcher) fuzzy(fuzzy map[string]string, item *v1.Service) bool {
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) { if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false return false
} }
case label: case Label:
if !searchFuzzy(item.Labels, "", v) { if !searchFuzzy(item.Labels, "", v) {
return false return false
} }

View File

@@ -83,7 +83,7 @@ func (*statefulSetSearcher) fuzzy(fuzzy map[string]string, item *v1.StatefulSet)
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) { if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false return false
} }
case label: case Label:
if !searchFuzzy(item.Labels, "", v) { if !searchFuzzy(item.Labels, "", v) {
return false return false
} }

View File

@@ -66,7 +66,7 @@ func (*storageClassesSearcher) fuzzy(fuzzy map[string]string, item *v1.StorageCl
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) { if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false return false
} }
case label: case Label:
if !searchFuzzy(item.Labels, "", v) { if !searchFuzzy(item.Labels, "", v) {
return false return false
} }

View File

@@ -66,7 +66,7 @@ func (*workspaceSearcher) fuzzy(fuzzy map[string]string, item *tenantv1alpha1.Wo
if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) { if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) {
return false return false
} }
case label: case Label:
if !searchFuzzy(item.Labels, "", v) { if !searchFuzzy(item.Labels, "", v) {
return false return false
} }

View File

@@ -18,7 +18,7 @@
package models package models
import ( import (
v12 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
"time" "time"
"k8s.io/api/rbac/v1" "k8s.io/api/rbac/v1"
@@ -117,6 +117,6 @@ type Token struct {
} }
type ResourceQuota struct { type ResourceQuota struct {
Namespace string `json:"namespace"` Namespace string `json:"namespace"`
Data v12.ResourceQuotaStatus `json:"data"` Data corev1.ResourceQuotaStatus `json:"data"`
} }

View File

@@ -144,11 +144,10 @@ func CreateWorkspaceRoleBinding(workspace, username string, role string) error {
roleBindingName := fmt.Sprintf("workspace:%s:%s", workspace, strings.TrimPrefix(role, "workspace-")) roleBindingName := fmt.Sprintf("workspace:%s:%s", workspace, strings.TrimPrefix(role, "workspace-"))
workspaceRoleBinding, err := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister().Get(roleBindingName) workspaceRoleBinding, err := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister().Get(roleBindingName)
workspaceRoleBinding = workspaceRoleBinding.DeepCopy()
if err != nil { if err != nil {
return err return err
} }
workspaceRoleBinding = workspaceRoleBinding.DeepCopy()
if !k8sutil.ContainsUser(workspaceRoleBinding.Subjects, username) { if !k8sutil.ContainsUser(workspaceRoleBinding.Subjects, username) {
workspaceRoleBinding.Subjects = append(workspaceRoleBinding.Subjects, v1.Subject{APIGroup: "rbac.authorization.k8s.io", Kind: "User", Name: username}) workspaceRoleBinding.Subjects = append(workspaceRoleBinding.Subjects, v1.Subject{APIGroup: "rbac.authorization.k8s.io", Kind: "User", Name: username})
_, err = k8s.Client().RbacV1().ClusterRoleBindings().Update(workspaceRoleBinding) _, err = k8s.Client().RbacV1().ClusterRoleBindings().Update(workspaceRoleBinding)

View File

@@ -20,6 +20,7 @@ package ldap
import ( import (
"flag" "flag"
"github.com/go-ldap/ldap" "github.com/go-ldap/ldap"
"github.com/golang/glog"
"log" "log"
"sync" "sync"
) )
@@ -67,6 +68,7 @@ func Client() (ldap.Client, error) {
conn, err := ldapClientPool().Get() conn, err := ldapClientPool().Get()
if err != nil { if err != nil {
glog.Errorln("get ldap connection from pool", err)
return nil, err return nil, err
} }
@@ -74,6 +76,7 @@ func Client() (ldap.Client, error) {
if err != nil { if err != nil {
conn.Close() conn.Close()
glog.Errorln("bind manager dn", err)
return nil, err return nil, err
} }