refine tenant api

Signed-off-by: hongming <talonwan@yunify.com>
This commit is contained in:
hongming
2019-04-01 02:59:19 +08:00
parent 744bd053e3
commit 93ad572e19
202 changed files with 13517 additions and 7951 deletions

View File

@@ -20,42 +20,22 @@ package iam
import (
"github.com/emicklei/go-restful"
"k8s.io/api/rbac/v1"
k8serr "k8s.io/apimachinery/pkg/api/errors"
"kubesphere.io/kubesphere/pkg/params"
"net/http"
"sort"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/iam"
"kubesphere.io/kubesphere/pkg/models/iam/policy"
)
type roleList struct {
ClusterRoles []*v1.ClusterRole `json:"clusterRoles" protobuf:"bytes,2,rep,name=clusterRoles"`
ClusterRoles []*v1.ClusterRole `json:"clusterRole" protobuf:"bytes,2,rep,name=clusterRoles"`
Roles []*v1.Role `json:"roles" protobuf:"bytes,2,rep,name=roles"`
}
func RoleRules(req *restful.Request, resp *restful.Response) {
namespace := req.PathParameter("namespace")
roleName := req.PathParameter("role")
role, err := iam.GetRole(namespace, roleName)
if err != nil {
resp.WriteError(http.StatusInternalServerError, err)
return
}
rules, err := iam.GetRoleSimpleRules([]*v1.Role{role}, namespace)
if err != nil {
resp.WriteError(http.StatusInternalServerError, err)
return
}
resp.WriteAsJson(rules[namespace])
}
func RoleUsers(req *restful.Request, resp *restful.Response) {
func ListRoleUsers(req *restful.Request, resp *restful.Response) {
roleName := req.PathParameter("role")
namespace := req.PathParameter("namespace")
@@ -69,7 +49,53 @@ func RoleUsers(req *restful.Request, resp *restful.Response) {
resp.WriteAsJson(users)
}
func NamespaceUsers(req *restful.Request, resp *restful.Response) {
func ListClusterRoles(req *restful.Request, resp *restful.Response) {
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
orderBy := req.QueryParameter(params.OrderByParam)
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
reverse := params.ParseReverse(req)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
result, err := iam.ListClusterRoles(conditions, orderBy, reverse, limit, offset)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(result)
}
func ListRoles(req *restful.Request, resp *restful.Response) {
namespace := req.PathParameter("namespace")
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
orderBy := req.QueryParameter(params.OrderByParam)
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
reverse := params.ParseReverse(req)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
result, err := iam.ListRoles(namespace, conditions, orderBy, reverse, limit, offset)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(result)
}
// List users by namespace
func ListNamespaceUsers(req *restful.Request, resp *restful.Response) {
namespace := req.PathParameter("namespace")
@@ -80,25 +106,26 @@ func NamespaceUsers(req *restful.Request, resp *restful.Response) {
return
}
// sort by time by default
sort.Slice(users, func(i, j int) bool {
return users[i].Username < users[j].Username
return users[i].RoleBindTime.After(*users[j].RoleBindTime)
})
resp.WriteAsJson(users)
}
func UserRoles(req *restful.Request, resp *restful.Response) {
func ListUserRoles(req *restful.Request, resp *restful.Response) {
username := req.PathParameter("username")
roles, err := iam.GetRoles(username, "")
roles, err := iam.GetUserRoles("", username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
clusterRoles, err := iam.GetClusterRoles(username)
_, clusterRoles, err := iam.GetUserClusterRoles(username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
@@ -112,79 +139,62 @@ func UserRoles(req *restful.Request, resp *restful.Response) {
resp.WriteAsJson(roleList)
}
func NamespaceRulesHandler(req *restful.Request, resp *restful.Response) {
namespace := req.PathParameter("namespace")
username := req.HeaderParameter(constants.UserNameHeader)
clusterRoles, err := iam.GetClusterRoles(username)
if err != nil {
resp.WriteError(http.StatusInternalServerError, err)
return
}
roles, err := iam.GetRoles(username, namespace)
if err != nil {
resp.WriteError(http.StatusInternalServerError, err)
return
}
for _, clusterRole := range clusterRoles {
role := new(v1.Role)
role.Name = clusterRole.Name
role.Labels = clusterRole.Labels
role.Namespace = namespace
role.Annotations = clusterRole.Annotations
role.Kind = "Role"
role.Rules = clusterRole.Rules
roles = append(roles, role)
}
rules, err := iam.GetRoleSimpleRules(roles, namespace)
if err != nil {
resp.WriteError(http.StatusInternalServerError, err)
return
}
resp.WriteAsJson(rules[namespace])
}
func RulesMappingHandler(req *restful.Request, resp *restful.Response) {
func RulesMapping(req *restful.Request, resp *restful.Response) {
rules := policy.RoleRuleMapping
resp.WriteAsJson(rules)
}
func ClusterRulesMappingHandler(req *restful.Request, resp *restful.Response) {
func ClusterRulesMapping(req *restful.Request, resp *restful.Response) {
rules := policy.ClusterRoleRuleMapping
resp.WriteAsJson(rules)
}
func ClusterRoleRules(req *restful.Request, resp *restful.Response) {
func ListClusterRoleRules(req *restful.Request, resp *restful.Response) {
clusterRoleName := req.PathParameter("clusterrole")
clusterRole, err := iam.GetClusterRole(clusterRoleName)
rules, err := iam.GetClusterRoleSimpleRules(clusterRoleName)
if err != nil {
resp.WriteError(http.StatusInternalServerError, err)
return
}
rules, err := iam.GetClusterRoleSimpleRules([]*v1.ClusterRole{clusterRole})
resp.WriteAsJson(rules)
}
func ListClusterRoleUsers(req *restful.Request, resp *restful.Response) {
clusterRoleName := req.PathParameter("clusterrole")
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
orderBy := req.QueryParameter(params.OrderByParam)
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
reverse := params.ParseReverse(req)
if err != nil {
resp.WriteError(http.StatusInternalServerError, err)
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
result, err := iam.ListClusterRoleUsers(clusterRoleName, conditions, orderBy, reverse, limit, offset)
if err != nil {
if k8serr.IsNotFound(err) {
resp.WriteError(http.StatusNotFound, err)
} else {
resp.WriteError(http.StatusInternalServerError, err)
}
return
}
resp.WriteAsJson(result)
}
func ListRoleRules(req *restful.Request, resp *restful.Response) {
namespaceName := req.PathParameter("namespace")
roleName := req.PathParameter("role")
rules, err := iam.GetRoleSimpleRules(namespaceName, roleName)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(rules)
}
func ClusterRoleUsers(req *restful.Request, resp *restful.Response) {
clusterRoleName := req.PathParameter("clusterrole")
users, err := iam.ClusterRoleUsers(clusterRoleName)
if err != nil {
resp.WriteError(http.StatusInternalServerError, err)
return
}
resp.WriteAsJson(users)
}

View File

@@ -18,17 +18,14 @@
package iam
import (
"fmt"
"github.com/dgrijalva/jwt-go"
"github.com/emicklei/go-restful"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/simple/client/ldap"
"kubesphere.io/kubesphere/pkg/utils/iputil"
"kubesphere.io/kubesphere/pkg/utils/jwtutil"
"net/http"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/iam"
"kubesphere.io/kubesphere/pkg/utils"
jwtutils "kubesphere.io/kubesphere/pkg/utils/jwt"
)
type Spec struct {
@@ -63,11 +60,11 @@ func LoginHandler(req *restful.Request, resp *restful.Response) {
err := req.ReadEntity(&loginRequest)
if err != nil || loginRequest.Username == "" || loginRequest.Password == "" {
resp.WriteHeaderAndEntity(http.StatusUnauthorized, errors.Wrap(fmt.Errorf("incorrect username or password")))
resp.WriteHeaderAndEntity(http.StatusUnauthorized, errors.New("incorrect username or password"))
return
}
ip := utils.RemoteIp(req.Request)
ip := iputil.RemoteIp(req.Request)
token, err := iam.Login(loginRequest.Username, loginRequest.Password, ip)
@@ -76,7 +73,7 @@ func LoginHandler(req *restful.Request, resp *restful.Response) {
return
}
resp.WriteAsJson(models.Token{Token: token})
resp.WriteAsJson(token)
}
// k8s token review
@@ -91,13 +88,13 @@ func TokenReviewHandler(req *restful.Request, resp *restful.Response) {
}
if tokenReview.Spec == nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("token must not be null")))
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New("token must not be null"))
return
}
uToken := tokenReview.Spec.Token
token, err := jwtutils.ValidateToken(uToken)
token, err := jwtutil.ValidateToken(uToken)
if err != nil {
failed := TokenReview{APIVersion: APIVersion,
@@ -112,24 +109,29 @@ func TokenReviewHandler(req *restful.Request, resp *restful.Response) {
claims := token.Claims.(jwt.MapClaims)
username := claims["username"].(string)
username, ok := claims["username"].(string)
conn, err := ldap.Client()
if !ok {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New("username not found"))
return
}
user, err := iam.GetUserInfo(username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
defer conn.Close()
user, err := iam.UserDetail(username, conn)
groups, err := iam.GetUserGroups(username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
user.Groups = groups
success := TokenReview{APIVersion: APIVersion,
Kind: KindTokenReview,
Status: &Status{

View File

@@ -19,7 +19,6 @@ package iam
import (
"fmt"
ldapclient "kubesphere.io/kubesphere/pkg/simple/client/ldap"
"net/http"
"regexp"
"strings"
@@ -33,8 +32,6 @@ import (
)
func CreateGroup(req *restful.Request, resp *restful.Response) {
//var json map[string]interface{}
var group models.Group
err := req.ReadEntity(&group)
@@ -45,19 +42,18 @@ func CreateGroup(req *restful.Request, resp *restful.Response) {
}
if !regexp.MustCompile("[a-z0-9]([-a-z0-9]*[a-z0-9])?").MatchString(group.Name) {
resp.WriteHeaderAndEntity(http.StatusBadRequest, fmt.Errorf("incalid group name %s", group))
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.New(fmt.Sprintf("incalid group name %s", group)))
return
}
if group.Creator == "" {
resp.WriteHeaderAndEntity(http.StatusBadRequest, fmt.Errorf("creator should not be null"))
return
}
created, err := iam.CreateGroup(group)
created, err := iam.CreateGroup(&group)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
if ldap.IsErrorWithCode(err, ldap.LDAPResultEntryAlreadyExists) {
resp.WriteHeaderAndEntity(http.StatusConflict, errors.Wrap(err))
} else {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
}
return
}
@@ -75,6 +71,10 @@ func DeleteGroup(req *restful.Request, resp *restful.Response) {
err := iam.DeleteGroup(path)
if err != nil {
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
return
}
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
@@ -106,23 +106,18 @@ func UpdateGroup(req *restful.Request, resp *restful.Response) {
}
func GroupDetail(req *restful.Request, resp *restful.Response) {
func DescribeGroup(req *restful.Request, resp *restful.Response) {
path := req.PathParameter("path")
conn, err := ldapclient.Client()
group, err := iam.DescribeGroup(path)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
defer conn.Close()
group, err := iam.GroupDetail(path, conn)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
} else {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
}
return
}
@@ -130,20 +125,11 @@ func GroupDetail(req *restful.Request, resp *restful.Response) {
}
func GroupUsers(req *restful.Request, resp *restful.Response) {
func ListGroupUsers(req *restful.Request, resp *restful.Response) {
path := req.PathParameter("path")
conn, err := ldapclient.Client()
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
defer conn.Close()
group, err := iam.GroupDetail(path, conn)
group, err := iam.DescribeGroup(path)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
@@ -156,10 +142,10 @@ func GroupUsers(req *restful.Request, resp *restful.Response) {
for i := 0; i < len(group.Members); i++ {
name := group.Members[i]
user, err := iam.UserDetail(name, conn)
user, err := iam.DescribeUser(name)
if err != nil {
if ldap.IsErrorWithCode(err, 32) {
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
group.Members = append(group.Members[:i], group.Members[i+1:]...)
i--
modify = true
@@ -170,25 +156,6 @@ func GroupUsers(req *restful.Request, resp *restful.Response) {
}
}
clusterRoles, err := iam.GetClusterRoles(name)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
for i := 0; i < len(clusterRoles); i++ {
if clusterRoles[i].Annotations["rbac.authorization.k8s.io/clusterrole"] == "true" {
user.ClusterRole = clusterRoles[i].Name
break
}
}
if group.Path == group.Name {
workspaceRole := iam.GetWorkspaceRole(clusterRoles, group.Name)
user.WorkspaceRole = workspaceRole
}
users = append(users, user)
}
@@ -200,18 +167,7 @@ func GroupUsers(req *restful.Request, resp *restful.Response) {
}
func CountHandler(req *restful.Request, resp *restful.Response) {
count, err := iam.CountChild("")
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(map[string]int{"total_count": count})
}
func RootGroupList(req *restful.Request, resp *restful.Response) {
func ListGroups(req *restful.Request, resp *restful.Response) {
array := req.QueryParameter("path")
@@ -229,18 +185,9 @@ func RootGroupList(req *restful.Request, resp *restful.Response) {
groups := make([]*models.Group, 0)
conn, err := ldapclient.Client()
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
defer conn.Close()
for _, v := range paths {
path := strings.TrimSpace(v)
group, err := iam.GroupDetail(path, conn)
group, err := iam.DescribeGroup(path)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return

View File

@@ -19,9 +19,9 @@ package iam
import (
"fmt"
"kubesphere.io/kubesphere/pkg/params"
"net/http"
"regexp"
"strconv"
"strings"
"github.com/emicklei/go-restful"
@@ -31,7 +31,6 @@ import (
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/models/iam"
ldapclient "kubesphere.io/kubesphere/pkg/simple/client/ldap"
)
const (
@@ -63,7 +62,7 @@ func CreateUser(req *restful.Request, resp *restful.Response) {
return
}
err = iam.CreateUser(user)
created, err := iam.CreateUser(&user)
if err != nil {
if ldap.IsErrorWithCode(err, ldap.LDAPResultEntryAlreadyExists) {
@@ -74,7 +73,7 @@ func CreateUser(req *restful.Request, resp *restful.Response) {
return
}
resp.WriteAsJson(errors.None)
resp.WriteAsJson(created)
}
func DeleteUser(req *restful.Request, resp *restful.Response) {
@@ -100,7 +99,7 @@ func DeleteUser(req *restful.Request, resp *restful.Response) {
func UpdateUser(req *restful.Request, resp *restful.Response) {
usernameInPath := req.PathParameter("name")
username := req.HeaderParameter(constants.UserNameHeader)
usernameInHeader := req.HeaderParameter(constants.UserNameHeader)
var user models.User
err := req.ReadEntity(&user)
@@ -125,22 +124,23 @@ func UpdateUser(req *restful.Request, resp *restful.Response) {
return
}
if username == user.Username && user.Password != "" {
_, err = iam.Login(username, user.CurrentPassword, "")
// change password by self
if usernameInHeader == user.Username && user.Password != "" {
_, err = iam.Login(usernameInHeader, user.CurrentPassword, "")
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("incorrect current password")))
return
}
}
err = iam.UpdateUser(user)
result, err := iam.UpdateUser(&user)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(errors.None)
resp.WriteAsJson(result)
}
func UserLoginLog(req *restful.Request, resp *restful.Response) {
@@ -167,20 +167,11 @@ func UserLoginLog(req *restful.Request, resp *restful.Response) {
resp.WriteAsJson(result)
}
func CurrentUserDetail(req *restful.Request, resp *restful.Response) {
func DescribeUser(req *restful.Request, resp *restful.Response) {
username := req.HeaderParameter(constants.UserNameHeader)
username := req.PathParameter("username")
conn, err := ldapclient.Client()
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
defer conn.Close()
user, err := iam.UserDetail(username, conn)
user, err := iam.DescribeUser(username)
if err != nil {
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
@@ -191,186 +182,81 @@ func CurrentUserDetail(req *restful.Request, resp *restful.Response) {
return
}
clusterRoles, err := iam.GetClusterRoles(username)
clusterRole, err := iam.GetUserClusterRole(username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
clusterRules, err := iam.GetClusterRoleSimpleRules(clusterRoles)
user.ClusterRole = clusterRole.Name
clusterRules, err := iam.GetUserClusterSimpleRules(username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
for i := 0; i < len(clusterRoles); i++ {
if clusterRoles[i].Annotations["rbac.authorization.k8s.io/clusterrole"] == "true" {
user.ClusterRole = clusterRoles[i].Name
break
}
result := struct {
*models.User
ClusterRules []models.SimpleRule `json:"cluster_rules"`
}{
User: user,
ClusterRules: clusterRules,
}
user.ClusterRules = clusterRules
resp.WriteAsJson(user)
resp.WriteAsJson(result)
}
func NamespacesListHandler(req *restful.Request, resp *restful.Response) {
username := req.PathParameter("name")
func Precheck(req *restful.Request, resp *restful.Response) {
namespaces, err := iam.GetNamespaces(username)
check := req.QueryParameter("check")
exist, err := iam.UserCreateCheck(check)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(namespaces)
resp.WriteAsJson(map[string]bool{"exist": exist})
}
func UserDetail(req *restful.Request, resp *restful.Response) {
username := req.PathParameter("name")
usernameFromHeader := req.HeaderParameter(constants.UserNameHeader)
if username == usernameFromHeader {
CurrentUserDetail(req, resp)
return
}
conn, err := ldapclient.Client()
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
defer conn.Close()
user, err := iam.UserDetail(username, conn)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
clusterRoles, err := iam.GetClusterRoles(username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
clusterRules, err := iam.GetClusterRoleSimpleRules(clusterRoles)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
workspaceRoles := iam.GetWorkspaceRoles(clusterRoles)
for i := 0; i < len(clusterRoles); i++ {
if clusterRoles[i].Annotations["rbac.authorization.k8s.io/clusterrole"] == "true" {
user.ClusterRole = clusterRoles[i].Name
break
}
}
user.ClusterRules = clusterRules
user.WorkspaceRoles = workspaceRoles
resp.WriteAsJson(user)
}
func UserList(req *restful.Request, resp *restful.Response) {
limit, err := strconv.Atoi(req.QueryParameter("limit"))
if err != nil {
limit = 65535
}
offset, err := strconv.Atoi(req.QueryParameter("offset"))
if err != nil {
offset = 0
}
func ListUsers(req *restful.Request, resp *restful.Response) {
if check := req.QueryParameter("check"); check != "" {
exist, err := iam.UserCreateCheck(check)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(map[string]bool{"exist": exist})
Precheck(req, resp)
return
}
conn, err := ldapclient.Client()
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
orderBy := req.QueryParameter(params.OrderByParam)
reverse := params.ParseReverse(req)
names := params.ParseArray(req.QueryParameter(params.NameParam))
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
if len(names) > 0 {
users, err := iam.ListUsersByName(names)
defer conn.Close()
if query := req.QueryParameter("name"); query != "" {
names := strings.Split(query, ",")
users := make([]*models.User, 0)
for _, name := range names {
user, err := iam.UserDetail(name, conn)
if err != nil {
if ldap.IsErrorWithCode(err, 32) {
continue
} else {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
}
users = append(users, user)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
resp.WriteAsJson(users)
return
}
var total int
var users []models.User
if query := req.QueryParameter("search"); query != "" {
total, users, err = iam.Search(query, limit, offset)
} else if query := req.QueryParameter("keyword"); query != "" {
total, users, err = iam.Search(query, limit, offset)
} else {
total, users, err = iam.UserList(limit, offset)
}
users, err := iam.ListUsers(conditions, orderBy, reverse, limit, offset)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
for i := 0; i < len(users); i++ {
clusterRoles, err := iam.GetClusterRoles(users[i].Username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
for j := 0; j < len(clusterRoles); j++ {
if clusterRoles[j].Annotations["rbac.authorization.k8s.io/clusterrole"] == "true" {
users[i].ClusterRole = clusterRoles[j].Name
break
}
}
}
items := make([]interface{}, 0)
for _, u := range users {
items = append(items, u)
}
resp.WriteAsJson(models.PageableResponse{Items: items, TotalCount: total})
resp.WriteAsJson(users)
}

View File

@@ -0,0 +1,18 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package iam

View File

@@ -18,698 +18,155 @@
package iam
import (
"fmt"
"github.com/go-ldap/ldap"
"net/http"
"regexp"
"sort"
"strconv"
"strings"
"github.com/emicklei/go-restful"
"k8s.io/api/core/v1"
rbac "k8s.io/api/rbac/v1"
k8serr "k8s.io/apimachinery/pkg/api/errors"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/models/iam"
"kubesphere.io/kubesphere/pkg/models/metrics"
"kubesphere.io/kubesphere/pkg/models/workspaces"
ldapclient "kubesphere.io/kubesphere/pkg/simple/client/ldap"
sliceutils "kubesphere.io/kubesphere/pkg/utils"
"kubesphere.io/kubesphere/pkg/params"
"net/http"
)
const UserNameHeader = "X-Token-Username"
func ListWorkspaceRoles(req *restful.Request, resp *restful.Response) {
func WorkspaceRoles(req *restful.Request, resp *restful.Response) {
name := req.PathParameter("name")
workspace, err := workspaces.Detail(name)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
roles, err := workspaces.Roles(workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(roles)
}
func WorkspaceMemberDetail(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("name")
username := req.PathParameter("member")
user, err := iam.GetUser(username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
namespaces, err := workspaces.Namespaces(workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
user.WorkspaceRole = user.WorkspaceRoles[workspace]
roles := make(map[string]string)
for _, namespace := range namespaces {
if role := user.Roles[namespace.Name]; role != "" {
roles[namespace.Name] = role
}
}
user.Roles = roles
user.Rules = nil
user.WorkspaceRules = nil
user.WorkspaceRoles = nil
user.ClusterRules = nil
resp.WriteAsJson(user)
}
func WorkspaceMemberInvite(req *restful.Request, resp *restful.Response) {
var users []models.UserInvite
workspace := req.PathParameter("name")
err := req.ReadEntity(&users)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
err = workspaces.Invite(workspace, users)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(errors.None)
}
func WorkspaceMemberRemove(req *restful.Request, resp *restful.Response) {
query := req.QueryParameter("name")
workspace := req.PathParameter("name")
names := strings.Split(query, ",")
err := workspaces.RemoveMembers(workspace, names)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(errors.None)
}
func NamespaceCheckHandler(req *restful.Request, resp *restful.Response) {
namespace := req.PathParameter("namespace")
exist, err := workspaces.NamespaceExistCheck(namespace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(map[string]bool{"exist": exist})
}
func NamespaceDeleteHandler(req *restful.Request, resp *restful.Response) {
namespace := req.PathParameter("namespace")
workspace := req.PathParameter("name")
err := workspaces.DeleteNamespace(workspace, namespace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(errors.None)
}
func DevOpsProjectDeleteHandler(req *restful.Request, resp *restful.Response) {
devops := req.PathParameter("id")
workspace := req.PathParameter("name")
force := req.QueryParameter("force")
username := req.HeaderParameter(UserNameHeader)
err := workspaces.UnBindDevopsProject(workspace, devops)
if err != nil && force != "true" {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
err = workspaces.DeleteDevopsProject(username, devops)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(errors.None)
}
func DevOpsProjectCreateHandler(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("name")
username := req.HeaderParameter(UserNameHeader)
var devops models.DevopsProject
err := req.ReadEntity(&devops)
workspace := req.PathParameter("workspace")
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
orderBy := req.QueryParameter(params.OrderByParam)
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
reverse := params.ParseReverse(req)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
project, err := workspaces.CreateDevopsProject(username, workspace, devops)
result, err := iam.ListWorkspaceRoles(workspace, conditions, orderBy, reverse, limit, offset)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(project)
resp.WriteAsJson(result.Items)
}
func NamespaceCreateHandler(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("name")
username := req.HeaderParameter(UserNameHeader)
func ListWorkspaceRoleRules(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("workspace")
role := req.PathParameter("role")
namespace := &v1.Namespace{}
err := req.ReadEntity(namespace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
if namespace.Annotations == nil {
namespace.Annotations = make(map[string]string, 0)
}
namespace.Annotations["creator"] = username
namespace.Annotations["workspace"] = workspace
if namespace.Labels == nil {
namespace.Labels = make(map[string]string, 0)
}
namespace.Labels["kubesphere.io/workspace"] = workspace
namespace, err = workspaces.CreateNamespace(namespace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("invalid workspace name")))
return
}
resp.WriteAsJson(namespace)
}
func DevOpsProjectHandler(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("name")
username := req.PathParameter("username")
keyword := req.QueryParameter("keyword")
if username == "" {
username = req.HeaderParameter(UserNameHeader)
}
limit := 65535
offset := 0
orderBy := "createTime"
reverse := true
if groups := regexp.MustCompile(`^limit=(\d+),page=(\d+)$`).FindStringSubmatch(req.QueryParameter("paging")); len(groups) == 3 {
limit, _ = strconv.Atoi(groups[1])
page, _ := strconv.Atoi(groups[2])
offset = (page - 1) * limit
}
if groups := regexp.MustCompile(`^(createTime|name)$`).FindStringSubmatch(req.QueryParameter("order")); len(groups) == 2 {
orderBy = groups[1]
reverse = false
}
if q := req.QueryParameter("reverse"); q != "" {
b, err := strconv.ParseBool(q)
if err == nil {
reverse = b
}
}
total, devOpsProjects, err := workspaces.ListDevopsProjectsByUser(username, workspace, keyword, orderBy, reverse, limit, offset)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
result := models.PageableResponse{}
result.TotalCount = total
result.Items = make([]interface{}, 0)
for _, n := range devOpsProjects {
result.Items = append(result.Items, n)
}
resp.WriteAsJson(result)
}
func WorkspaceCreateHandler(req *restful.Request, resp *restful.Response) {
var workspace models.Workspace
username := req.HeaderParameter(UserNameHeader)
err := req.ReadEntity(&workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
if workspace.Name == "" || strings.Contains(workspace.Name, ":") {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("invalid workspace name")))
return
}
workspace.Path = workspace.Name
workspace.Members = nil
if workspace.Admin != "" {
workspace.Creator = workspace.Admin
} else {
workspace.Creator = username
}
created, err := workspaces.Create(&workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(created)
}
func DeleteWorkspaceHandler(req *restful.Request, resp *restful.Response) {
name := req.PathParameter("name")
if name == "" || strings.Contains(name, ":") {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("invalid workspace name")))
return
}
workspace, err := workspaces.Detail(name)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
err = workspaces.Delete(workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(errors.None)
}
func WorkspaceEditHandler(req *restful.Request, resp *restful.Response) {
var workspace models.Workspace
name := req.PathParameter("name")
err := req.ReadEntity(&workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
if name != workspace.Name {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("the name of workspace (%s) does not match the name on the URL (%s)", workspace.Name, name)))
return
}
if workspace.Name == "" || strings.Contains(workspace.Name, ":") {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(fmt.Errorf("invalid workspace name")))
return
}
workspace.Path = workspace.Name
workspace.Members = nil
edited, err := workspaces.Edit(&workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(edited)
}
func WorkspaceDetailHandler(req *restful.Request, resp *restful.Response) {
name := req.PathParameter("name")
workspace, err := workspaces.Detail(name)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(workspace)
}
// List all workspaces for the current user
func UserWorkspaceListHandler(req *restful.Request, resp *restful.Response) {
keyword := req.QueryParameter("keyword")
username := req.HeaderParameter(constants.UserNameHeader)
ws, err := workspaces.ListWorkspaceByUser(username, keyword)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
sort.Slice(ws, func(i, j int) bool {
t1, err := ws[i].GetCreateTime()
if err != nil {
return false
}
t2, err := ws[j].GetCreateTime()
if err != nil {
return true
}
return t1.After(t2)
})
resp.WriteAsJson(ws)
}
func UserNamespaceListHandler(req *restful.Request, resp *restful.Response) {
withMetrics, err := strconv.ParseBool(req.QueryParameter("metrics"))
if err != nil {
withMetrics = false
}
username := req.PathParameter("username")
keyword := req.QueryParameter("keyword")
if username == "" {
username = req.HeaderParameter(UserNameHeader)
}
limit := 65535
offset := 0
orderBy := "createTime"
reverse := true
if groups := regexp.MustCompile(`^limit=(\d+),page=(\d+)$`).FindStringSubmatch(req.QueryParameter("paging")); len(groups) == 3 {
limit, _ = strconv.Atoi(groups[1])
page, _ := strconv.Atoi(groups[2])
if page < 0 {
page = 1
}
offset = (page - 1) * limit
}
if groups := regexp.MustCompile(`^(createTime|name)$`).FindStringSubmatch(req.QueryParameter("order")); len(groups) == 2 {
orderBy = groups[1]
reverse = false
}
if q := req.QueryParameter("reverse"); q != "" {
b, err := strconv.ParseBool(q)
if err == nil {
reverse = b
}
}
workspaceName := req.PathParameter("workspace")
total, namespaces, err := workspaces.ListNamespaceByUser(workspaceName, username, keyword, orderBy, reverse, limit, offset)
if withMetrics {
namespaces = metrics.GetNamespacesWithMetrics(namespaces)
}
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
result := models.PageableResponse{}
result.TotalCount = total
result.Items = make([]interface{}, 0)
for _, n := range namespaces {
result.Items = append(result.Items, n)
}
resp.WriteAsJson(result)
}
func DevopsRulesHandler(req *restful.Request, resp *restful.Response) {
//workspaceName := req.PathParameter("workspace")
username := req.HeaderParameter(constants.UserNameHeader)
devopsName := req.PathParameter("devops")
var rules []models.SimpleRule
role, err := iam.GetDevopsRole(devopsName, username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
switch role {
case "developer":
rules = []models.SimpleRule{
{Name: "pipelines", Actions: []string{"view", "trigger"}},
{Name: "roles", Actions: []string{"view"}},
{Name: "members", Actions: []string{"view"}},
{Name: "devops", Actions: []string{"view"}},
}
break
case "owner":
rules = []models.SimpleRule{
{Name: "pipelines", Actions: []string{"create", "edit", "view", "delete", "trigger"}},
{Name: "roles", Actions: []string{"view"}},
{Name: "members", Actions: []string{"create", "edit", "view", "delete"}},
{Name: "credentials", Actions: []string{"create", "edit", "view", "delete"}},
{Name: "devops", Actions: []string{"edit", "view", "delete"}},
}
break
case "maintainer":
rules = []models.SimpleRule{
{Name: "pipelines", Actions: []string{"create", "edit", "view", "delete", "trigger"}},
{Name: "roles", Actions: []string{"view"}},
{Name: "members", Actions: []string{"view"}},
{Name: "credentials", Actions: []string{"create", "edit", "view", "delete"}},
{Name: "devops", Actions: []string{"view"}},
}
break
case "reporter":
fallthrough
default:
rules = []models.SimpleRule{
{Name: "pipelines", Actions: []string{"view"}},
{Name: "roles", Actions: []string{"view"}},
{Name: "members", Actions: []string{"view"}},
{Name: "devops", Actions: []string{"view"}},
}
break
}
rules := iam.GetWorkspaceRoleSimpleRules(workspace, role)
resp.WriteAsJson(rules)
}
func NamespacesRulesHandler(req *restful.Request, resp *restful.Response) {
//workspaceName := req.PathParameter("workspace")
username := req.HeaderParameter(constants.UserNameHeader)
namespaceName := req.PathParameter("namespace")
clusterRoles, err := iam.GetClusterRoles(username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
roles, err := iam.GetRoles(username, namespaceName)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
for _, clusterRole := range clusterRoles {
role := new(rbac.Role)
role.Name = clusterRole.Name
role.Labels = clusterRole.Labels
role.Namespace = namespaceName
role.Annotations = clusterRole.Annotations
role.Kind = "Role"
role.Rules = clusterRole.Rules
roles = append(roles, role)
}
rules, err := iam.GetRoleSimpleRules(roles, namespaceName)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
if rules[namespaceName] == nil {
resp.WriteAsJson(make([]models.SimpleRule, 0))
} else {
resp.WriteAsJson(rules[namespaceName])
}
}
func WorkspaceRulesHandler(req *restful.Request, resp *restful.Response) {
func DescribeWorkspaceRole(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("workspace")
roleName := req.PathParameter("role")
username := req.HeaderParameter(constants.UserNameHeader)
clusterRoles, err := iam.GetClusterRoles(username)
role, err := iam.GetWorkspaceRole(workspace, roleName)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
rules := iam.GetWorkspaceSimpleRules(clusterRoles, workspace)
if rules[workspace] != nil {
resp.WriteAsJson(rules[workspace])
} else if rules["*"] != nil {
resp.WriteAsJson(rules["*"])
} else {
resp.WriteAsJson(make([]models.SimpleRule, 0))
}
resp.WriteAsJson(role)
}
func WorkspaceMemberList(req *restful.Request, resp *restful.Response) {
func DescribeWorkspaceUser(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("workspace")
limit, err := strconv.Atoi(req.QueryParameter("limit"))
username := req.PathParameter("username")
workspaceRole, err := iam.GetUserWorkspaceRole(workspace, username)
if err != nil {
limit = 500
}
offset, err := strconv.Atoi(req.QueryParameter("offset"))
if err != nil {
offset = 0
if k8serr.IsNotFound(err) {
resp.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
} else {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
}
return
}
conn, err := ldapclient.Client()
user, err := iam.DescribeUser(username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
defer conn.Close()
user.WorkspaceRole = workspaceRole.Labels[constants.DisplayNameLabelKey]
group, err := iam.GroupDetail(workspace, conn)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
keyword := ""
if query := req.QueryParameter("keyword"); query != "" {
keyword = query
}
users := make([]*models.User, 0)
total := len(group.Members)
members := sliceutils.RemoveString(group.Members, func(item string) bool {
return keyword != "" && !strings.Contains(item, keyword)
})
for i := 0; i < len(members); i++ {
username := members[i]
if i < offset {
continue
}
if len(users) == limit {
break
}
user, err := iam.UserDetail(username, conn)
if err != nil {
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
group.Members = sliceutils.RemoveString(group.Members, func(item string) bool {
return item == username
})
continue
} else {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
}
clusterRoles, err := iam.GetClusterRoles(username)
for i := 0; i < len(clusterRoles); i++ {
if clusterRoles[i].Annotations["rbac.authorization.k8s.io/clusterrole"] == "true" {
user.ClusterRole = clusterRoles[i].Name
break
}
}
if group.Path == group.Name {
workspaceRole := iam.GetWorkspaceRole(clusterRoles, group.Name)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
user.WorkspaceRole = workspaceRole
}
users = append(users, user)
}
if total > len(group.Members) {
go iam.UpdateGroup(group)
}
if req.QueryParameter("limit") != "" {
resp.WriteAsJson(map[string]interface{}{"items": users, "total_count": len(members)})
} else {
resp.WriteAsJson(users)
}
resp.WriteAsJson(user)
}
func ListDevopsRoleRules(req *restful.Request, resp *restful.Response) {
role := req.PathParameter("role")
rules := iam.GetDevopsRoleSimpleRules(role)
resp.WriteAsJson(rules)
}
func InviteUser(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("workspace")
var user models.User
err := req.ReadEntity(&user)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
err = workspaces.InviteUser(workspace, &user)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(errors.None)
}
func RemoveUser(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("workspace")
var user models.User
err := req.ReadEntity(&user)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
err = workspaces.InviteUser(workspace, &user)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(errors.None)
}
func ListWorkspaceUsers(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("workspace")
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
orderBy := req.QueryParameter(params.OrderByParam)
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
reverse := params.ParseReverse(req)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
result, err := iam.ListWorkspaceUsers(workspace, conditions, orderBy, reverse, limit, offset)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(result)
}

View File

@@ -21,15 +21,17 @@ import (
"github.com/emicklei/go-restful"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/applications"
//"kubesphere.io/kubesphere/pkg/models/applications"
"kubesphere.io/kubesphere/pkg/params"
"net/http"
)
func ApplicationHandler(req *restful.Request, resp *restful.Response) {
limit, offset := params.ParsePaging(req)
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
clusterId := req.QueryParameter("cluster_id")
runtimeId := req.QueryParameter("runtime_id")
conditions, err := params.ParseConditions(req)
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
if err != nil {
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))

View File

@@ -1,44 +0,0 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package resources
import (
"github.com/emicklei/go-restful"
"net/http"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/resources"
"kubesphere.io/kubesphere/pkg/params"
)
func ClusterResourceHandler(req *restful.Request, resp *restful.Response) {
resourceName := req.PathParameter("resources")
conditions, err := params.ParseConditions(req)
orderBy := req.QueryParameter(params.OrderByParam)
limit, offset := params.ParsePaging(req)
reverse := params.ParseReverse(req)
result, err := resources.ListClusterResource(resourceName, conditions, orderBy, reverse, limit, offset)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(result)
}

View File

@@ -19,22 +19,39 @@ package resources
import (
"github.com/emicklei/go-restful"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/models/resources"
"net/http"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/resources"
"kubesphere.io/kubesphere/pkg/params"
)
func NamespaceResourceHandler(req *restful.Request, resp *restful.Response) {
func ListResources(req *restful.Request, resp *restful.Response) {
namespace := req.PathParameter("namespace")
resourceName := req.PathParameter("resources")
conditions, err := params.ParseConditions(req)
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
orderBy := req.QueryParameter(params.OrderByParam)
limit, offset := params.ParsePaging(req)
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
reverse := params.ParseReverse(req)
names := params.ParseArray(req.QueryParameter(params.NameParam))
result, err := resources.ListNamespaceResource(namespace, resourceName, conditions, orderBy, reverse, limit, offset)
if orderBy == "" {
orderBy = resources.CreateTime
reverse = true
}
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
var result *models.PageableResponse
if len(names) > 0 {
result, err = resources.ListResourcesByName(namespace, resourceName, names)
} else {
result, err = resources.ListResources(namespace, resourceName, conditions, orderBy, reverse, limit, offset)
}
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))

View File

@@ -50,21 +50,6 @@ func GetAllRouters(request *restful.Request, response *restful.Response) {
response.WriteAsJson(routers)
}
// Get all namespace ingress controller services for user
func GetAllRoutersOfUser(request *restful.Request, response *restful.Response) {
username := request.PathParameter("username")
routers, err := routers.GetAllRoutersOfUser(username)
if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
response.WriteAsJson(routers)
}
// Get ingress controller service for specified namespace
func GetRouter(request *restful.Request, response *restful.Response) {

View File

@@ -0,0 +1,264 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package tenant
import (
"github.com/emicklei/go-restful"
"k8s.io/api/core/v1"
k8serr "k8s.io/apimachinery/pkg/api/errors"
"kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/models/iam"
"kubesphere.io/kubesphere/pkg/models/tenant"
"kubesphere.io/kubesphere/pkg/models/workspaces"
"kubesphere.io/kubesphere/pkg/params"
"log"
"net/http"
)
func ListWorkspaceRules(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("workspace")
username := req.HeaderParameter(constants.UserNameHeader)
rules, err := iam.GetUserWorkspaceSimpleRules(workspace, username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(rules)
}
func ListWorkspaces(req *restful.Request, resp *restful.Response) {
username := req.HeaderParameter(constants.UserNameHeader)
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
orderBy := req.QueryParameter(params.OrderByParam)
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
reverse := params.ParseReverse(req)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
result, err := tenant.ListWorkspaces(username, conditions, orderBy, reverse, limit, offset)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(result)
}
func ListNamespaces(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("workspace")
username := req.PathParameter("username")
// /workspaces/{workspace}/members/{username}/namespaces
if username == "" {
// /workspaces/{workspace}/namespaces
username = req.HeaderParameter(constants.UserNameHeader)
}
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
orderBy := req.QueryParameter(params.OrderByParam)
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
reverse := params.ParseReverse(req)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
conditions.Match["kubesphere.io/workspace"] = workspace
result, err := tenant.ListNamespaces(username, conditions, orderBy, reverse, limit, offset)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(result)
}
func CreateNamespace(req *restful.Request, resp *restful.Response) {
workspaceName := req.PathParameter("workspace")
username := req.HeaderParameter(constants.UserNameHeader)
var namespace v1.Namespace
err := req.ReadEntity(&namespace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
workspace, err := tenant.GetWorkspace(workspaceName)
err = checkResourceQuotas(workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusForbidden, errors.Wrap(err))
return
}
if err != nil {
if k8serr.IsNotFound(err) {
resp.WriteHeaderAndEntity(http.StatusForbidden, errors.Wrap(err))
} else {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
}
return
}
created, err := tenant.CreateNamespace(workspaceName, &namespace, username)
if err != nil {
if k8serr.IsAlreadyExists(err) {
resp.WriteHeaderAndEntity(http.StatusConflict, err)
} else {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, err)
}
return
}
resp.WriteAsJson(created)
}
func DeleteNamespace(req *restful.Request, resp *restful.Response) {
workspaceName := req.PathParameter("workspace")
namespaceName := req.PathParameter("namespace")
err := workspaces.DeleteNamespace(workspaceName, namespaceName)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
resp.WriteAsJson(errors.None)
}
func checkResourceQuotas(wokrspace *v1alpha1.Workspace) error {
return nil
}
func ListDevopsProjects(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("workspace")
username := req.PathParameter(constants.UserNameHeader)
if username == "" {
username = req.HeaderParameter(constants.UserNameHeader)
}
orderBy := req.QueryParameter(params.OrderByParam)
reverse := params.ParseReverse(req)
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
result, err := tenant.ListDevopsProjects(workspace, username, conditions, orderBy, reverse, limit, offset)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(result)
}
func DeleteDevopsProject(req *restful.Request, resp *restful.Response) {
devops := req.PathParameter("id")
workspace := req.PathParameter("workspace")
force := req.QueryParameter("force")
username := req.HeaderParameter(constants.UserNameHeader)
err := workspaces.UnBindDevopsProject(workspace, devops)
if err != nil && force != "true" {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
err = workspaces.DeleteDevopsProject(username, devops)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(errors.None)
}
func CreateDevopsProject(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("workspace")
username := req.HeaderParameter(constants.UserNameHeader)
var devops models.DevopsProject
err := req.ReadEntity(&devops)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
return
}
log.Println("create workspace", username, workspace, devops)
project, err := workspaces.CreateDevopsProject(username, workspace, devops)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
resp.WriteAsJson(project)
}
func ListNamespaceRules(req *restful.Request, resp *restful.Response) {
namespace := req.PathParameter("namespace")
username := req.HeaderParameter(constants.UserNameHeader)
rules, err := iam.GetUserNamespaceSimpleRules(namespace, username)
if err != nil {
resp.WriteError(http.StatusInternalServerError, err)
return
}
resp.WriteAsJson(rules)
}
func ListDevopsRules(req *restful.Request, resp *restful.Response) {
devops := req.PathParameter("devops")
username := req.HeaderParameter(constants.UserNameHeader)
rules, err := iam.GetUserDevopsSimpleRules(username, devops)
if err != nil {
resp.WriteError(http.StatusInternalServerError, err)
return
}
resp.WriteAsJson(rules)
}

View File

@@ -0,0 +1,56 @@
/*
Copyright 2019 The KubeSphere Authors.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package terminal
import (
"github.com/emicklei/go-restful"
"gopkg.in/igm/sockjs-go.v2/sockjs"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/terminal"
"net/http"
)
// TerminalResponse is sent by handleExecShell. The Id is a random session id that binds the original REST request and the SockJS connection.
// Any clientapi in possession of this Id can hijack the terminal session.
type TerminalResponse struct {
Id string `json:"id"`
}
// CreateAttachHandler is called from main for /api/sockjs
func NewTerminalHandler(path string) http.Handler {
return sockjs.NewHandler(path, sockjs.DefaultOptions, terminal.HandleTerminalSession)
}
// Handles execute shell API call
func CreateTerminalSession(request *restful.Request, resp *restful.Response) {
namespace := request.PathParameter("namespace")
podName := request.PathParameter("pod")
containerName := request.QueryParameter("container")
shell := request.QueryParameter("shell")
sessionId, err := terminal.NewSession(shell, namespace, podName, containerName)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
TerminalResponse := &TerminalResponse{Id: sessionId}
resp.WriteAsJson(TerminalResponse)
}