@@ -192,9 +192,10 @@ func addWebService(c *restful.Container) error {
|
|||||||
Param(ws.PathParameter("workspace", "workspace name")).
|
Param(ws.PathParameter("workspace", "workspace name")).
|
||||||
Doc("Add user to workspace").
|
Doc("Add user to workspace").
|
||||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||||
ws.Route(ws.POST("/workspaces/{workspace}/members").
|
ws.Route(ws.DELETE("/workspaces/{workspace}/members/{username}").
|
||||||
To(iam.RemoveUser).
|
To(iam.RemoveUser).
|
||||||
Param(ws.PathParameter("workspace", "workspace name")).
|
Param(ws.PathParameter("workspace", "workspace name")).
|
||||||
|
Param(ws.PathParameter("name", "username")).
|
||||||
Doc("Remove user from workspace").
|
Doc("Remove user from workspace").
|
||||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||||
ws.Route(ws.GET("/workspaces/{workspace}/members/{username}").
|
ws.Route(ws.GET("/workspaces/{workspace}/members/{username}").
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ func addWebService(c *restful.Container) error {
|
|||||||
To(resources.ApplicationHandler).
|
To(resources.ApplicationHandler).
|
||||||
Writes(models.PageableResponse{}).
|
Writes(models.PageableResponse{}).
|
||||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||||
Doc("Cluster level resource query").
|
Doc("List applications in cluster").
|
||||||
Param(webservice.QueryParameter(params.ConditionsParam, "query conditions").
|
Param(webservice.QueryParameter(params.ConditionsParam, "query conditions").
|
||||||
Required(false).
|
Required(false).
|
||||||
DataFormat("key=value,key~value").
|
DataFormat("key=value,key~value").
|
||||||
@@ -103,9 +103,24 @@ func addWebService(c *restful.Container) error {
|
|||||||
DataFormat("limit=%d,page=%d").
|
DataFormat("limit=%d,page=%d").
|
||||||
DefaultValue("limit=10,page=1")))
|
DefaultValue("limit=10,page=1")))
|
||||||
|
|
||||||
|
webservice.Route(webservice.GET("/namespaces/{namespace}/applications").
|
||||||
|
To(resources.NamespacedApplicationHandler).
|
||||||
|
Writes(models.PageableResponse{}).
|
||||||
|
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||||
|
Doc("List applications").
|
||||||
|
Param(webservice.QueryParameter(params.ConditionsParam, "query conditions").
|
||||||
|
Required(false).
|
||||||
|
DataFormat("key=value,key~value").
|
||||||
|
DefaultValue("")).
|
||||||
|
Param(webservice.PathParameter("namespace", "namespace")).
|
||||||
|
Param(webservice.QueryParameter(params.PagingParam, "page").
|
||||||
|
Required(false).
|
||||||
|
DataFormat("limit=%d,page=%d").
|
||||||
|
DefaultValue("limit=10,page=1")))
|
||||||
|
|
||||||
webservice.Route(webservice.GET("/storageclasses/{storageclass}/persistentvolumeclaims").
|
webservice.Route(webservice.GET("/storageclasses/{storageclass}/persistentvolumeclaims").
|
||||||
To(resources.GetPvcListBySc).
|
To(resources.GetPvcListBySc).
|
||||||
Doc("get user's kubectl pod").
|
Doc("query persistent volume claims by storageclass").
|
||||||
Param(webservice.PathParameter("username", "username")).
|
Param(webservice.PathParameter("username", "username")).
|
||||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,10 @@ func addWebService(c *restful.Container) error {
|
|||||||
To(tenant.ListWorkspaces).
|
To(tenant.ListWorkspaces).
|
||||||
Doc("List workspace by user").
|
Doc("List workspace by user").
|
||||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||||
|
ws.Route(ws.GET("/workspaces/{workspace}").
|
||||||
|
To(tenant.DescribeWorkspace).
|
||||||
|
Doc("Get workspace detail").
|
||||||
|
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||||
ws.Route(ws.GET("/workspaces/{workspace}/rules").
|
ws.Route(ws.GET("/workspaces/{workspace}/rules").
|
||||||
To(tenant.ListWorkspaceRules).
|
To(tenant.ListWorkspaceRules).
|
||||||
Param(ws.PathParameter("workspace", "workspace name")).
|
Param(ws.PathParameter("workspace", "workspace name")).
|
||||||
@@ -96,7 +100,7 @@ func addWebService(c *restful.Container) error {
|
|||||||
Param(ws.PathParameter("workspace", "workspace name")).
|
Param(ws.PathParameter("workspace", "workspace name")).
|
||||||
Doc("Create devops project").
|
Doc("Create devops project").
|
||||||
Metadata(restfulspec.KeyOpenAPITags, tags))
|
Metadata(restfulspec.KeyOpenAPITags, tags))
|
||||||
ws.Route(ws.DELETE("/workspaces/{workspace}/devops").
|
ws.Route(ws.DELETE("/workspaces/{workspace}/devops/{id}").
|
||||||
To(tenant.DeleteDevopsProject).
|
To(tenant.DeleteDevopsProject).
|
||||||
Param(ws.PathParameter("workspace", "workspace name")).
|
Param(ws.PathParameter("workspace", "workspace name")).
|
||||||
Doc("Delete devops project").
|
Doc("Delete devops project").
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ func addWebService(c *restful.Container) error {
|
|||||||
|
|
||||||
tags := []string{"Terminal"}
|
tags := []string{"Terminal"}
|
||||||
|
|
||||||
webservice.Route(webservice.GET("/namespace/{namespace}/pods/{pods}").
|
webservice.Route(webservice.GET("/namespaces/{namespace}/pods/{pods}").
|
||||||
To(terminal.CreateTerminalSession).
|
To(terminal.CreateTerminalSession).
|
||||||
Doc("create terminal session").
|
Doc("create terminal session").
|
||||||
Metadata(restfulspec.KeyOpenAPITags, tags).
|
Metadata(restfulspec.KeyOpenAPITags, tags).
|
||||||
|
|||||||
@@ -142,7 +142,7 @@ func ListGroupUsers(req *restful.Request, resp *restful.Response) {
|
|||||||
|
|
||||||
for i := 0; i < len(group.Members); i++ {
|
for i := 0; i < len(group.Members); i++ {
|
||||||
name := group.Members[i]
|
name := group.Members[i]
|
||||||
user, err := iam.DescribeUser(name)
|
user, err := iam.GetUserInfo(name)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||||
|
|||||||
@@ -234,22 +234,11 @@ func ListUsers(req *restful.Request, resp *restful.Response) {
|
|||||||
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||||
orderBy := req.QueryParameter(params.OrderByParam)
|
orderBy := req.QueryParameter(params.OrderByParam)
|
||||||
reverse := params.ParseReverse(req)
|
reverse := params.ParseReverse(req)
|
||||||
names := params.ParseArray(req.QueryParameter(params.NameParam))
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if len(names) > 0 {
|
|
||||||
users, err := iam.ListUsersByName(names)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
resp.WriteAsJson(users)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
users, err := iam.ListUsers(conditions, orderBy, reverse, limit, offset)
|
users, err := iam.ListUsers(conditions, orderBy, reverse, limit, offset)
|
||||||
|
|
||||||
|
|||||||
@@ -91,7 +91,7 @@ func DescribeWorkspaceUser(req *restful.Request, resp *restful.Response) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := iam.DescribeUser(username)
|
user, err := iam.GetUserInfo(username)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
@@ -132,15 +132,9 @@ func InviteUser(req *restful.Request, resp *restful.Response) {
|
|||||||
|
|
||||||
func RemoveUser(req *restful.Request, resp *restful.Response) {
|
func RemoveUser(req *restful.Request, resp *restful.Response) {
|
||||||
workspace := req.PathParameter("workspace")
|
workspace := req.PathParameter("workspace")
|
||||||
var user models.User
|
username := req.PathParameter("username")
|
||||||
err := req.ReadEntity(&user)
|
|
||||||
if err != nil {
|
|
||||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
err = workspaces.InviteUser(workspace, &user)
|
|
||||||
|
|
||||||
|
err := workspaces.RemoveUser(workspace, username)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -19,10 +19,11 @@ package resources
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
|
"k8s.io/api/core/v1"
|
||||||
|
"kubesphere.io/kubesphere/pkg/constants"
|
||||||
"kubesphere.io/kubesphere/pkg/errors"
|
"kubesphere.io/kubesphere/pkg/errors"
|
||||||
"kubesphere.io/kubesphere/pkg/models/applications"
|
"kubesphere.io/kubesphere/pkg/models/applications"
|
||||||
|
"kubesphere.io/kubesphere/pkg/models/resources"
|
||||||
//"kubesphere.io/kubesphere/pkg/models/applications"
|
|
||||||
"kubesphere.io/kubesphere/pkg/params"
|
"kubesphere.io/kubesphere/pkg/params"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
@@ -58,3 +59,42 @@ func ApplicationHandler(req *restful.Request, resp *restful.Response) {
|
|||||||
resp.WriteAsJson(result)
|
resp.WriteAsJson(result)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func NamespacedApplicationHandler(req *restful.Request, resp *restful.Response) {
|
||||||
|
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||||
|
namespaceName := req.PathParameter("namespace")
|
||||||
|
conditions, err := params.ParseConditions(req.QueryParameter(params.ConditionsParam))
|
||||||
|
if err != nil {
|
||||||
|
if err != nil {
|
||||||
|
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace, err := resources.GetResource("", resources.Namespaces, namespaceName)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
var runtimeId string
|
||||||
|
|
||||||
|
if ns, ok := namespace.(*v1.Namespace); ok {
|
||||||
|
runtimeId = ns.Annotations[constants.OpenPitrixRuntimeAnnotationKey]
|
||||||
|
}
|
||||||
|
|
||||||
|
if runtimeId == "" {
|
||||||
|
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.New("openpitrix runtime not init"))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
result, err := applications.ListApplication(runtimeId, conditions, limit, offset)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.WriteAsJson(result)
|
||||||
|
}
|
||||||
|
|||||||
@@ -19,7 +19,6 @@ package resources
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
"kubesphere.io/kubesphere/pkg/models"
|
|
||||||
"kubesphere.io/kubesphere/pkg/models/resources"
|
"kubesphere.io/kubesphere/pkg/models/resources"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
@@ -34,7 +33,6 @@ func ListResources(req *restful.Request, resp *restful.Response) {
|
|||||||
orderBy := req.QueryParameter(params.OrderByParam)
|
orderBy := req.QueryParameter(params.OrderByParam)
|
||||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||||
reverse := params.ParseReverse(req)
|
reverse := params.ParseReverse(req)
|
||||||
names := params.ParseArray(req.QueryParameter(params.NameParam))
|
|
||||||
|
|
||||||
if orderBy == "" {
|
if orderBy == "" {
|
||||||
orderBy = resources.CreateTime
|
orderBy = resources.CreateTime
|
||||||
@@ -46,12 +44,7 @@ func ListResources(req *restful.Request, resp *restful.Response) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
var result *models.PageableResponse
|
result, err := resources.ListResources(namespace, resourceName, conditions, orderBy, reverse, limit, offset)
|
||||||
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 {
|
if err != nil {
|
||||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ package routers
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
|
k8serr "k8s.io/apimachinery/pkg/api/errors"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/errors"
|
"kubesphere.io/kubesphere/pkg/errors"
|
||||||
@@ -57,7 +58,11 @@ func GetRouter(request *restful.Request, response *restful.Response) {
|
|||||||
router, err := routers.GetRouter(namespace)
|
router, err := routers.GetRouter(namespace)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
if k8serr.IsNotFound(err) {
|
||||||
|
response.WriteHeaderAndEntity(http.StatusNotFound, errors.Wrap(err))
|
||||||
|
} else {
|
||||||
|
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ package tenant
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/emicklei/go-restful"
|
"github.com/emicklei/go-restful"
|
||||||
|
"github.com/golang/glog"
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
k8serr "k8s.io/apimachinery/pkg/api/errors"
|
k8serr "k8s.io/apimachinery/pkg/api/errors"
|
||||||
"kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
|
"kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
|
||||||
@@ -26,10 +27,11 @@ 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/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"
|
||||||
"log"
|
"kubesphere.io/kubesphere/pkg/simple/client/kubesphere"
|
||||||
"net/http"
|
"net/http"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -54,6 +56,11 @@ func ListWorkspaces(req *restful.Request, resp *restful.Response) {
|
|||||||
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
limit, offset := params.ParsePaging(req.QueryParameter(params.PagingParam))
|
||||||
reverse := params.ParseReverse(req)
|
reverse := params.ParseReverse(req)
|
||||||
|
|
||||||
|
if orderBy == "" {
|
||||||
|
orderBy = resources.CreateTime
|
||||||
|
reverse = true
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
@@ -69,6 +76,20 @@ func ListWorkspaces(req *restful.Request, resp *restful.Response) {
|
|||||||
resp.WriteAsJson(result)
|
resp.WriteAsJson(result)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DescribeWorkspace(req *restful.Request, resp *restful.Response) {
|
||||||
|
username := req.HeaderParameter(constants.UserNameHeader)
|
||||||
|
workspaceName := req.PathParameter("workspace")
|
||||||
|
|
||||||
|
result, err := tenant.DescribeWorkspace(username, workspaceName)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
resp.WriteAsJson(result)
|
||||||
|
}
|
||||||
|
|
||||||
func ListNamespaces(req *restful.Request, resp *restful.Response) {
|
func ListNamespaces(req *restful.Request, resp *restful.Response) {
|
||||||
workspace := req.PathParameter("workspace")
|
workspace := req.PathParameter("workspace")
|
||||||
username := req.PathParameter("username")
|
username := req.PathParameter("username")
|
||||||
@@ -88,7 +109,7 @@ func ListNamespaces(req *restful.Request, resp *restful.Response) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
conditions.Match["kubesphere.io/workspace"] = workspace
|
conditions.Match[constants.WorkspaceLabelKey] = workspace
|
||||||
|
|
||||||
result, err := tenant.ListNamespaces(username, conditions, orderBy, reverse, limit, offset)
|
result, err := tenant.ListNamespaces(username, conditions, orderBy, reverse, limit, offset)
|
||||||
|
|
||||||
@@ -188,18 +209,24 @@ func ListDevopsProjects(req *restful.Request, resp *restful.Response) {
|
|||||||
|
|
||||||
func DeleteDevopsProject(req *restful.Request, resp *restful.Response) {
|
func DeleteDevopsProject(req *restful.Request, resp *restful.Response) {
|
||||||
devops := req.PathParameter("id")
|
devops := req.PathParameter("id")
|
||||||
workspace := req.PathParameter("workspace")
|
workspaceName := req.PathParameter("workspace")
|
||||||
force := req.QueryParameter("force")
|
|
||||||
username := req.HeaderParameter(constants.UserNameHeader)
|
username := req.HeaderParameter(constants.UserNameHeader)
|
||||||
|
|
||||||
err := workspaces.UnBindDevopsProject(workspace, devops)
|
_, err := tenant.GetWorkspace(workspaceName)
|
||||||
|
|
||||||
if err != nil && force != "true" {
|
if err != nil {
|
||||||
|
resp.WriteHeaderAndEntity(http.StatusBadRequest, errors.Wrap(err))
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
err = kubesphere.Client().DeleteDevopsProject(username, devops)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
err = workspaces.DeleteDevopsProject(username, devops)
|
err = workspaces.UnBindDevopsProject(workspaceName, devops)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
@@ -211,7 +238,7 @@ func DeleteDevopsProject(req *restful.Request, resp *restful.Response) {
|
|||||||
|
|
||||||
func CreateDevopsProject(req *restful.Request, resp *restful.Response) {
|
func CreateDevopsProject(req *restful.Request, resp *restful.Response) {
|
||||||
|
|
||||||
workspace := req.PathParameter("workspace")
|
workspaceName := req.PathParameter("workspace")
|
||||||
username := req.HeaderParameter(constants.UserNameHeader)
|
username := req.HeaderParameter(constants.UserNameHeader)
|
||||||
|
|
||||||
var devops models.DevopsProject
|
var devops models.DevopsProject
|
||||||
@@ -223,8 +250,8 @@ func CreateDevopsProject(req *restful.Request, resp *restful.Response) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Println("create workspace", username, workspace, devops)
|
glog.Infoln("create workspace", username, workspaceName, devops)
|
||||||
project, err := workspaces.CreateDevopsProject(username, workspace, devops)
|
project, err := workspaces.CreateDevopsProject(username, workspaceName, &devops)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
resp.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
|
||||||
@@ -232,7 +259,6 @@ func CreateDevopsProject(req *restful.Request, resp *restful.Response) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
resp.WriteAsJson(project)
|
resp.WriteAsJson(project)
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListNamespaceRules(req *restful.Request, resp *restful.Response) {
|
func ListNamespaceRules(req *restful.Request, resp *restful.Response) {
|
||||||
|
|||||||
@@ -47,7 +47,5 @@ const (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
WorkSpaceRoles = []string{WorkspaceAdmin, WorkspaceRegular, WorkspaceViewer}
|
WorkSpaceRoles = []string{WorkspaceAdmin, WorkspaceRegular, WorkspaceViewer}
|
||||||
SystemWorkspace = "system-workspace"
|
|
||||||
DevopsAPIServer = "ks-devops.kubesphere-devops-system.svc"
|
|
||||||
SystemNamespaces = []string{KubeSphereNamespace, OpenPitrixNamespace, KubeSystemNamespace}
|
SystemNamespaces = []string{KubeSphereNamespace, OpenPitrixNamespace, KubeSystemNamespace}
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -153,9 +153,9 @@ func (r *ReconcileWorkspace) Reconcile(request reconcile.Request) (reconcile.Res
|
|||||||
return reconcile.Result{}, err
|
return reconcile.Result{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = r.createGroup(instance); err != nil {
|
//if err = r.createGroup(instance); err != nil {
|
||||||
return reconcile.Result{}, err
|
// return reconcile.Result{}, err
|
||||||
}
|
//}
|
||||||
|
|
||||||
if err = r.createWorkspaceRoleBindings(instance); err != nil {
|
if err = r.createWorkspaceRoleBindings(instance); err != nil {
|
||||||
return reconcile.Result{}, err
|
return reconcile.Result{}, err
|
||||||
@@ -369,7 +369,7 @@ func (r *ReconcileWorkspace) createWorkspaceRoleBindings(instance *tenantv1alpha
|
|||||||
regularRoleBinding := &rbac.ClusterRoleBinding{}
|
regularRoleBinding := &rbac.ClusterRoleBinding{}
|
||||||
regularRoleBinding.Name = getWorkspaceRegularRoleBindingName(instance.Name)
|
regularRoleBinding.Name = getWorkspaceRegularRoleBindingName(instance.Name)
|
||||||
regularRoleBinding.Labels = map[string]string{constants.WorkspaceLabelKey: instance.Name}
|
regularRoleBinding.Labels = map[string]string{constants.WorkspaceLabelKey: instance.Name}
|
||||||
regularRoleBinding.RoleRef = rbac.RoleRef{APIGroup: "rbac.authorization.k8s.io", Kind: "ClusterRole", Name: getWorkspaceViewerRoleName(instance.Name)}
|
regularRoleBinding.RoleRef = rbac.RoleRef{APIGroup: "rbac.authorization.k8s.io", Kind: "ClusterRole", Name: getWorkspaceRegularRoleName(instance.Name)}
|
||||||
regularRoleBinding.Subjects = []rbac.Subject{}
|
regularRoleBinding.Subjects = []rbac.Subject{}
|
||||||
|
|
||||||
if err = controllerutil.SetControllerReference(instance, regularRoleBinding, r.scheme); err != nil {
|
if err = controllerutil.SetControllerReference(instance, regularRoleBinding, r.scheme); err != nil {
|
||||||
|
|||||||
@@ -18,20 +18,17 @@
|
|||||||
package iam
|
package iam
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"io/ioutil"
|
|
||||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"kubesphere.io/kubesphere/pkg/informers"
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
"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"
|
||||||
|
"kubesphere.io/kubesphere/pkg/simple/client/kubesphere"
|
||||||
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
|
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
|
||||||
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
|
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
|
||||||
"net/http"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
@@ -47,7 +44,7 @@ import (
|
|||||||
const ClusterRoleKind = "ClusterRole"
|
const ClusterRoleKind = "ClusterRole"
|
||||||
|
|
||||||
func GetUserDevopsSimpleRules(username, projectId string) ([]models.SimpleRule, error) {
|
func GetUserDevopsSimpleRules(username, projectId string) ([]models.SimpleRule, error) {
|
||||||
role, err := GetUserDevopsRole(projectId, username)
|
role, err := kubesphere.Client().GetUserDevopsRole(username, projectId)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -100,53 +97,6 @@ func GetDevopsRoleSimpleRules(role string) []models.SimpleRule {
|
|||||||
return rules
|
return rules
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetUserDevopsRole(projectId string, username string) (string, error) {
|
|
||||||
|
|
||||||
//Hard fix
|
|
||||||
if username == "admin" {
|
|
||||||
return "owner", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s/api/v1alpha/projects/%s/members", constants.DevopsAPIServer, projectId), nil)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
req.Header.Set(constants.UserNameHeader, username)
|
|
||||||
resp, err := http.DefaultClient.Do(req)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
defer resp.Body.Close()
|
|
||||||
data, err := ioutil.ReadAll(resp.Body)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
if resp.StatusCode > 200 {
|
|
||||||
return "", errors.New(string(data))
|
|
||||||
}
|
|
||||||
|
|
||||||
var result []map[string]string
|
|
||||||
|
|
||||||
err = json.Unmarshal(data, &result)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, item := range result {
|
|
||||||
if item["username"] == username {
|
|
||||||
return item["role"], nil
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return "", nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get user roles in namespace
|
// Get user roles in namespace
|
||||||
func GetUserRoles(namespace, username string) ([]*v1.Role, error) {
|
func GetUserRoles(namespace, username string) ([]*v1.Role, error) {
|
||||||
clusterRoleLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister()
|
clusterRoleLister := informers.SharedInformerFactory().Rbac().V1().ClusterRoles().Lister()
|
||||||
@@ -267,13 +217,6 @@ func GetUserRules(namespace, username string) ([]v1.PolicyRule, error) {
|
|||||||
return rules, nil
|
return rules, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func isUserFacingClusterRole(role *v1.ClusterRole) bool {
|
|
||||||
if role.Labels[constants.CreatorLabelKey] != "" {
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
func GetWorkspaceRoleBindings(workspace string) ([]*v1.ClusterRoleBinding, error) {
|
func GetWorkspaceRoleBindings(workspace string) ([]*v1.ClusterRoleBinding, error) {
|
||||||
|
|
||||||
clusterRoleBindings, err := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister().List(labels.Everything())
|
clusterRoleBindings, err := informers.SharedInformerFactory().Rbac().V1().ClusterRoleBindings().Lister().List(labels.Everything())
|
||||||
@@ -386,7 +329,7 @@ func ListClusterRoleUsers(clusterRoleName string, conditions *params.Conditions,
|
|||||||
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 == v1.UserKind && !k8sutil.ContainsUser(users, subject.Name) {
|
||||||
user, err := DescribeUser(subject.Name)
|
user, err := GetUserInfo(subject.Name)
|
||||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -436,7 +379,7 @@ func RoleUsers(namespace string, roleName string) ([]*models.User, error) {
|
|||||||
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 == v1.UserKind && !k8sutil.ContainsUser(users, subject.Name) {
|
||||||
user, err := DescribeUser(subject.Name)
|
user, err := GetUserInfo(subject.Name)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||||
@@ -491,10 +434,14 @@ func NamespaceUsers(namespaceName string) ([]*models.User, error) {
|
|||||||
users := make([]*models.User, 0)
|
users := make([]*models.User, 0)
|
||||||
|
|
||||||
for _, roleBinding := range roleBindings {
|
for _, roleBinding := range roleBindings {
|
||||||
|
// controlled by ks-controller-manager
|
||||||
|
if roleBinding.Name == "admin" || roleBinding.Name == "viewer" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
for _, subject := range roleBinding.Subjects {
|
for _, subject := range roleBinding.Subjects {
|
||||||
if subject.Kind == v1.UserKind && !k8sutil.ContainsUser(users, subject.Name) {
|
if subject.Kind == v1.UserKind && !k8sutil.ContainsUser(users, subject.Name) {
|
||||||
|
|
||||||
user, err := DescribeUser(subject.Name)
|
user, err := GetUserInfo(subject.Name)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import (
|
|||||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||||
"kubesphere.io/kubesphere/pkg/simple/client/redis"
|
"kubesphere.io/kubesphere/pkg/simple/client/redis"
|
||||||
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
|
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
|
||||||
|
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
"sort"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -232,7 +233,7 @@ func ListUsersByName(names []string) (*models.PageableResponse, error) {
|
|||||||
|
|
||||||
for _, name := range names {
|
for _, name := range names {
|
||||||
if !k8sutil.ContainsUser(users, name) {
|
if !k8sutil.ContainsUser(users, name) {
|
||||||
user, err := DescribeUser(name)
|
user, err := GetUserInfo(name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
if ldap.IsErrorWithCode(err, ldap.LDAPResultNoSuchObject) {
|
||||||
continue
|
continue
|
||||||
@@ -252,6 +253,30 @@ func ListUsersByName(names []string) (*models.PageableResponse, error) {
|
|||||||
return &models.PageableResponse{Items: items, TotalCount: len(items)}, nil
|
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()
|
||||||
@@ -272,6 +297,22 @@ func ListUsers(conditions *params.Conditions, orderBy string, reverse bool, limi
|
|||||||
filter = fmt.Sprintf("(&(objectClass=inetOrgPerson)(|(uid=*%s*)(mail=*%s*)(description=*%s*)))", keyword, keyword, keyword)
|
filter = fmt.Sprintf("(&(objectClass=inetOrgPerson)(|(uid=*%s*)(mail=*%s*)(description=*%s*)))", keyword, keyword, keyword)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if username := conditions.Match["username"]; username != "" {
|
||||||
|
uidFilter := ""
|
||||||
|
for _, username := range strings.Split(username, "|") {
|
||||||
|
uidFilter += fmt.Sprintf("(uid=%s)", username)
|
||||||
|
}
|
||||||
|
filter = fmt.Sprintf("(&(objectClass=inetOrgPerson)(|%s))", uidFilter)
|
||||||
|
}
|
||||||
|
|
||||||
|
if email := conditions.Match["email"]; email != "" {
|
||||||
|
emailFilter := ""
|
||||||
|
for _, username := range strings.Split(email, "|") {
|
||||||
|
emailFilter += fmt.Sprintf("(mail=%s)", username)
|
||||||
|
}
|
||||||
|
filter = fmt.Sprintf("(&(objectClass=inetOrgPerson)(|%s))", emailFilter)
|
||||||
|
}
|
||||||
|
|
||||||
for {
|
for {
|
||||||
userSearchRequest := ldap.NewSearchRequest(
|
userSearchRequest := ldap.NewSearchRequest(
|
||||||
ldapclient.UserSearchBase,
|
ldapclient.UserSearchBase,
|
||||||
@@ -331,26 +372,13 @@ func ListUsers(conditions *params.Conditions, orderBy string, reverse bool, limi
|
|||||||
|
|
||||||
if i >= offset && len(items) < limit {
|
if i >= offset && len(items) < limit {
|
||||||
|
|
||||||
avatar, err := getAvatar(user.Username)
|
user.AvatarUrl = getAvatar(user.Username)
|
||||||
if err != nil {
|
user.LastLoginTime = getLastLoginTime(user.Username)
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
user.AvatarUrl = avatar
|
|
||||||
|
|
||||||
lastLoginTime, err := getLastLoginTime(user.Username)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
user.LastLoginTime = lastLoginTime
|
|
||||||
|
|
||||||
clusterRole, err := GetUserClusterRole(user.Username)
|
clusterRole, err := GetUserClusterRole(user.Username)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
user.ClusterRole = clusterRole.Name
|
user.ClusterRole = clusterRole.Name
|
||||||
|
|
||||||
items = append(items, user)
|
items = append(items, user)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -373,23 +401,47 @@ func DescribeUser(username string) (*models.User, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
user.Groups = groups
|
user.Groups = groups
|
||||||
|
user.AvatarUrl = getAvatar(username)
|
||||||
|
|
||||||
avatar, err := getAvatar(username)
|
return user, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetUserInfoByEmail(mail string) (*models.User, error) {
|
||||||
|
conn, err := ldapclient.Client()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
user.AvatarUrl = avatar
|
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,
|
||||||
|
)
|
||||||
|
|
||||||
lastLoginTime, err := getLastLoginTime(username)
|
result, err := conn.Search(userSearchRequest)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
user.LastLoginTime = lastLoginTime
|
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
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -426,6 +478,8 @@ func GetUserInfo(username string) (*models.User, error) {
|
|||||||
createTimestamp, _ := time.Parse("20060102150405Z", result.Entries[0].GetAttributeValue("createTimestamp"))
|
createTimestamp, _ := time.Parse("20060102150405Z", result.Entries[0].GetAttributeValue("createTimestamp"))
|
||||||
user := &models.User{Username: username, Email: email, Description: description, Lang: lang, CreateTime: createTimestamp}
|
user := &models.User{Username: username, Email: email, Description: description, Lang: lang, CreateTime: createTimestamp}
|
||||||
|
|
||||||
|
user.LastLoginTime = getLastLoginTime(username)
|
||||||
|
|
||||||
return user, nil
|
return user, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -462,17 +516,18 @@ func GetUserGroups(username string) ([]string, error) {
|
|||||||
return groups, nil
|
return groups, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func getLastLoginTime(username string) (string, error) {
|
func getLastLoginTime(username string) string {
|
||||||
lastLogin, err := redis.Client().LRange(fmt.Sprintf("kubesphere:users:%s:login-log", username), -1, -1).Result()
|
lastLogin, err := redis.Client().LRange(fmt.Sprintf("kubesphere:users:%s:login-log", username), -1, -1).Result()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(lastLogin) > 0 {
|
if len(lastLogin) > 0 {
|
||||||
return strings.Split(lastLogin[0], ",")[0], nil
|
return strings.Split(lastLogin[0], ",")[0]
|
||||||
}
|
}
|
||||||
return "", nil
|
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func setAvatar(username, avatar string) error {
|
func setAvatar(username, avatar string) error {
|
||||||
@@ -480,20 +535,21 @@ func setAvatar(username, avatar string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
func getAvatar(username string) (string, error) {
|
func getAvatar(username string) string {
|
||||||
|
|
||||||
avatar, err := redis.Client().HMGet("kubesphere:users:avatar", username).Result()
|
avatar, err := redis.Client().HMGet("kubesphere:users:avatar", username).Result()
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(avatar) > 0 {
|
if len(avatar) > 0 {
|
||||||
if url, ok := avatar[0].(string); ok {
|
if url, ok := avatar[0].(string); ok {
|
||||||
return url, nil
|
return url
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return "", nil
|
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteUser(username string) error {
|
func DeleteUser(username string) error {
|
||||||
@@ -811,7 +867,7 @@ func UpdateUser(user *models.User) (*models.User, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return DescribeUser(user.Username)
|
return GetUserInfo(user.Username)
|
||||||
}
|
}
|
||||||
func DeleteGroup(path string) error {
|
func DeleteGroup(path string) error {
|
||||||
|
|
||||||
@@ -1105,13 +1161,15 @@ func ListWorkspaceUsers(workspace string, conditions *params.Conditions, orderBy
|
|||||||
for _, roleBinding := range workspaceRoleBindings {
|
for _, roleBinding := range workspaceRoleBindings {
|
||||||
for _, subject := range roleBinding.Subjects {
|
for _, subject := range roleBinding.Subjects {
|
||||||
if subject.Kind == v1.UserKind && !k8sutil.ContainsUser(users, subject.Name) {
|
if subject.Kind == v1.UserKind && !k8sutil.ContainsUser(users, subject.Name) {
|
||||||
user, err := DescribeUser(subject.Name)
|
user, err := GetUserInfo(subject.Name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
prefix := fmt.Sprintf("workspace:%s:", workspace)
|
prefix := fmt.Sprintf("workspace:%s:", workspace)
|
||||||
user.WorkspaceRole = fmt.Sprintf("workspace-%s", strings.TrimPrefix(roleBinding.Name, prefix))
|
user.WorkspaceRole = fmt.Sprintf("workspace-%s", strings.TrimPrefix(roleBinding.Name, prefix))
|
||||||
users = append(users, user)
|
if matchConditions(conditions, user) {
|
||||||
|
users = append(users, user)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1141,3 +1199,31 @@ func ListWorkspaceUsers(workspace string, conditions *params.Conditions, orderBy
|
|||||||
|
|
||||||
return &models.PageableResponse{Items: result, TotalCount: len(users)}, nil
|
return &models.PageableResponse{Items: result, TotalCount: len(users)}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func matchConditions(conditions *params.Conditions, user *models.User) bool {
|
||||||
|
for k, v := range conditions.Match {
|
||||||
|
switch k {
|
||||||
|
case "keyword":
|
||||||
|
if !strings.Contains(user.Username, v) &&
|
||||||
|
!strings.Contains(user.Email, v) &&
|
||||||
|
!strings.Contains(user.Description, v) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case "name":
|
||||||
|
names := strings.Split(v, "|")
|
||||||
|
if !sliceutil.HasString(names, user.Username) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case "email":
|
||||||
|
email := strings.Split(v, "|")
|
||||||
|
if !sliceutil.HasString(email, user.Email) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case "role":
|
||||||
|
if user.WorkspaceRole != v {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|||||||
@@ -126,6 +126,18 @@ var (
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
Name: "logging",
|
||||||
|
Actions: []models.Action{
|
||||||
|
{Name: "view",
|
||||||
|
Rules: []v1.PolicyRule{{
|
||||||
|
Verbs: []string{"get", "list"},
|
||||||
|
APIGroups: []string{"logging.kubesphere.io"},
|
||||||
|
Resources: []string{"*"},
|
||||||
|
}},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
Name: "accounts",
|
Name: "accounts",
|
||||||
Actions: []models.Action{
|
Actions: []models.Action{
|
||||||
@@ -683,8 +695,8 @@ var (
|
|||||||
Rules: []v1.PolicyRule{
|
Rules: []v1.PolicyRule{
|
||||||
{
|
{
|
||||||
Verbs: []string{"get"},
|
Verbs: []string{"get"},
|
||||||
APIGroups: []string{"resources.kubesphere.io"},
|
APIGroups: []string{"terminal.kubesphere.io"},
|
||||||
Resources: []string{"pod/terminal"},
|
Resources: []string{"pods"},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
package resources
|
package resources
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"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"
|
||||||
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
|
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
|
||||||
@@ -55,6 +56,12 @@ func (*clusterRoleSearcher) match(match map[string]string, item *rbac.ClusterRol
|
|||||||
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
|
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
case "userfacing":
|
||||||
|
if v == "true" {
|
||||||
|
if !isUserFacingClusterRole(item) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
if item.Labels[k] != v {
|
if item.Labels[k] != v {
|
||||||
return false
|
return false
|
||||||
@@ -134,3 +141,10 @@ func (s *clusterRoleSearcher) search(namespace string, conditions *params.Condit
|
|||||||
}
|
}
|
||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func isUserFacingClusterRole(role *rbac.ClusterRole) bool {
|
||||||
|
if role.Labels[constants.CreatorLabelKey] != "" && role.Labels[constants.WorkspaceLabelKey] == "" {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|||||||
@@ -103,24 +103,15 @@ type resourceSearchInterface interface {
|
|||||||
search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error)
|
search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListResourcesByName(namespace, resource string, names []string) (*models.PageableResponse, error) {
|
func GetResource(namespace, resource, name string) (interface{}, error) {
|
||||||
items := make([]interface{}, 0)
|
|
||||||
if searcher, ok := resources[resource]; ok {
|
if searcher, ok := resources[resource]; ok {
|
||||||
for _, name := range names {
|
resource, err := searcher.get(namespace, name)
|
||||||
item, err := searcher.get(namespace, name)
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
items = append(items, item)
|
|
||||||
}
|
}
|
||||||
|
return resource, nil
|
||||||
} else {
|
|
||||||
return nil, fmt.Errorf("not found")
|
|
||||||
}
|
}
|
||||||
|
return nil, fmt.Errorf("resource %s not found", resource)
|
||||||
return &models.PageableResponse{TotalCount: len(items), Items: items}, nil
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func ListResources(namespace, resource string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
func ListResources(namespace, resource string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/golang/glog"
|
"github.com/golang/glog"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"k8s.io/apimachinery/pkg/api/errors"
|
||||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||||
"sort"
|
"sort"
|
||||||
|
|
||||||
@@ -127,7 +128,7 @@ func GetRouter(namespace string) (*corev1.Service, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil, fmt.Errorf("resources not found %s", serviceName)
|
return nil, errors.NewNotFound(corev1.Resource("service"), serviceName)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Load all resource yamls
|
// Load all resource yamls
|
||||||
|
|||||||
@@ -18,15 +18,10 @@
|
|||||||
package tenant
|
package tenant
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
|
||||||
"io/ioutil"
|
|
||||||
"kubesphere.io/kubesphere/pkg/constants"
|
|
||||||
kserr "kubesphere.io/kubesphere/pkg/errors"
|
|
||||||
"kubesphere.io/kubesphere/pkg/models"
|
"kubesphere.io/kubesphere/pkg/models"
|
||||||
"kubesphere.io/kubesphere/pkg/params"
|
"kubesphere.io/kubesphere/pkg/params"
|
||||||
|
"kubesphere.io/kubesphere/pkg/simple/client/kubesphere"
|
||||||
"kubesphere.io/kubesphere/pkg/simple/client/mysql"
|
"kubesphere.io/kubesphere/pkg/simple/client/mysql"
|
||||||
"net/http"
|
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
)
|
)
|
||||||
@@ -41,79 +36,55 @@ func ListDevopsProjects(workspace, username string, conditions *params.Condition
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
devOpsProjects := make([]models.DevopsProject, 0)
|
projects, err := kubesphere.Client().ListDevopsProjects(username)
|
||||||
|
|
||||||
request, _ := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s/api/v1alpha/projects", constants.DevopsAPIServer), nil)
|
|
||||||
request.Header.Add(constants.UserNameHeader, username)
|
|
||||||
|
|
||||||
resp, err := http.DefaultClient.Do(request)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
data, err := ioutil.ReadAll(resp.Body)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if resp.StatusCode > 200 {
|
|
||||||
return nil, kserr.Parse(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
err = json.Unmarshal(data, &devOpsProjects)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if keyword := conditions.Match["keyword"]; keyword != "" {
|
if keyword := conditions.Match["keyword"]; keyword != "" {
|
||||||
for i := 0; i < len(devOpsProjects); i++ {
|
for i := 0; i < len(projects); i++ {
|
||||||
if !strings.Contains(devOpsProjects[i].Name, keyword) {
|
if !strings.Contains(projects[i].Name, keyword) {
|
||||||
devOpsProjects = append(devOpsProjects[:i], devOpsProjects[i+1:]...)
|
projects = append(projects[:i], projects[i+1:]...)
|
||||||
i--
|
i--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sort.Slice(devOpsProjects, func(i, j int) bool {
|
sort.Slice(projects, func(i, j int) bool {
|
||||||
|
if reverse {
|
||||||
|
tmp := i
|
||||||
|
i = j
|
||||||
|
j = tmp
|
||||||
|
}
|
||||||
switch orderBy {
|
switch orderBy {
|
||||||
case "name":
|
case "name":
|
||||||
if reverse {
|
return projects[i].Name > projects[j].Name
|
||||||
return devOpsProjects[i].Name < devOpsProjects[j].Name
|
|
||||||
} else {
|
|
||||||
return devOpsProjects[i].Name > devOpsProjects[j].Name
|
|
||||||
}
|
|
||||||
default:
|
default:
|
||||||
if reverse {
|
return projects[i].CreateTime.Before(*projects[j].CreateTime)
|
||||||
return devOpsProjects[i].CreateTime.After(*devOpsProjects[j].CreateTime)
|
|
||||||
} else {
|
|
||||||
return devOpsProjects[i].CreateTime.Before(*devOpsProjects[j].CreateTime)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
for i := 0; i < len(devOpsProjects); i++ {
|
for i := 0; i < len(projects); i++ {
|
||||||
inWorkspace := false
|
inWorkspace := false
|
||||||
|
|
||||||
for _, binding := range workspaceDOPBindings {
|
for _, binding := range workspaceDOPBindings {
|
||||||
if binding.DevOpsProject == *devOpsProjects[i].ProjectId {
|
if binding.DevOpsProject == projects[i].ProjectId {
|
||||||
inWorkspace = true
|
inWorkspace = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !inWorkspace {
|
if !inWorkspace {
|
||||||
devOpsProjects = append(devOpsProjects[:i], devOpsProjects[i+1:]...)
|
projects = append(projects[:i], projects[i+1:]...)
|
||||||
i--
|
i--
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// limit offset
|
// limit offset
|
||||||
result := make([]interface{}, 0)
|
result := make([]interface{}, 0)
|
||||||
for i, v := range devOpsProjects {
|
for i, v := range projects {
|
||||||
if len(result) < limit && i >= offset {
|
if len(result) < limit && i >= offset {
|
||||||
result = append(result, v)
|
result = append(result, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &models.PageableResponse{Items: result, TotalCount: len(devOpsProjects)}, nil
|
return &models.PageableResponse{Items: result, TotalCount: len(projects)}, nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import (
|
|||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
rbacv1 "k8s.io/api/rbac/v1"
|
rbacv1 "k8s.io/api/rbac/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
|
"kubesphere.io/kubesphere/pkg/constants"
|
||||||
"kubesphere.io/kubesphere/pkg/informers"
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||||
"kubesphere.io/kubesphere/pkg/params"
|
"kubesphere.io/kubesphere/pkg/params"
|
||||||
@@ -35,6 +36,14 @@ type namespaceSearcher struct {
|
|||||||
func (*namespaceSearcher) match(match map[string]string, item *v1.Namespace) bool {
|
func (*namespaceSearcher) match(match map[string]string, item *v1.Namespace) bool {
|
||||||
for k, v := range match {
|
for k, v := range match {
|
||||||
switch k {
|
switch k {
|
||||||
|
case "name":
|
||||||
|
if item.Name != v && item.Labels[constants.DisplayNameLabelKey] != v {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
case "keyword":
|
||||||
|
if !strings.Contains(item.Name, v) && !contains(item.Labels, "", v) && !contains(item.Annotations, "", v) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
if item.Labels[k] != v {
|
if item.Labels[k] != v {
|
||||||
return false
|
return false
|
||||||
|
|||||||
@@ -19,7 +19,9 @@ package tenant
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"k8s.io/api/core/v1"
|
"k8s.io/api/core/v1"
|
||||||
|
"kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
|
||||||
"kubesphere.io/kubesphere/pkg/constants"
|
"kubesphere.io/kubesphere/pkg/constants"
|
||||||
|
"kubesphere.io/kubesphere/pkg/informers"
|
||||||
"kubesphere.io/kubesphere/pkg/models"
|
"kubesphere.io/kubesphere/pkg/models"
|
||||||
ws "kubesphere.io/kubesphere/pkg/models/workspaces"
|
ws "kubesphere.io/kubesphere/pkg/models/workspaces"
|
||||||
"kubesphere.io/kubesphere/pkg/params"
|
"kubesphere.io/kubesphere/pkg/params"
|
||||||
@@ -45,6 +47,18 @@ func CreateNamespace(workspaceName string, namespace *v1.Namespace, username str
|
|||||||
return k8s.Client().CoreV1().Namespaces().Create(namespace)
|
return k8s.Client().CoreV1().Namespaces().Create(namespace)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func DescribeWorkspace(username, workspaceName string) (*v1alpha1.Workspace, error) {
|
||||||
|
workspace, err := informers.KsSharedInformerFactory().Tenant().V1alpha1().Workspaces().Lister().Get(workspaceName)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
workspace = appendAnnotations(username, workspace)
|
||||||
|
|
||||||
|
return workspace, nil
|
||||||
|
}
|
||||||
|
|
||||||
func ListWorkspaces(username string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
func ListWorkspaces(username string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||||
|
|
||||||
workspaces, err := workspaces.search(username, conditions, orderBy, reverse)
|
workspaces, err := workspaces.search(username, conditions, orderBy, reverse)
|
||||||
@@ -57,25 +71,7 @@ func ListWorkspaces(username string, conditions *params.Conditions, orderBy stri
|
|||||||
result := make([]interface{}, 0)
|
result := make([]interface{}, 0)
|
||||||
for i, workspace := range workspaces {
|
for i, workspace := range workspaces {
|
||||||
if len(result) < limit && i >= offset {
|
if len(result) < limit && i >= offset {
|
||||||
workspace := workspace.DeepCopy()
|
workspace := appendAnnotations(username, workspace)
|
||||||
ns, err := ListNamespaces(username, ¶ms.Conditions{Match: map[string]string{"kubesphere.io/workspace": workspace.Name}}, "", false, 1, 0)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
if workspace.Annotations == nil {
|
|
||||||
workspace.Annotations = make(map[string]string)
|
|
||||||
}
|
|
||||||
workspace.Annotations["kubesphere.io/namespace-count"] = strconv.Itoa(ns.TotalCount)
|
|
||||||
devops, err := ListDevopsProjects(workspace.Name, username, ¶ms.Conditions{}, "", false, 1, 0)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
workspace.Annotations["kubesphere.io/devops-count"] = strconv.Itoa(devops.TotalCount)
|
|
||||||
userCount, err := ws.WorkspaceUserCount(workspace.Name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
workspace.Annotations["kubesphere.io/member-count"] = strconv.Itoa(userCount)
|
|
||||||
result = append(result, workspace)
|
result = append(result, workspace)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -83,6 +79,32 @@ func ListWorkspaces(username string, conditions *params.Conditions, orderBy stri
|
|||||||
return &models.PageableResponse{Items: result, TotalCount: len(workspaces)}, nil
|
return &models.PageableResponse{Items: result, TotalCount: len(workspaces)}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func appendAnnotations(username string, workspace *v1alpha1.Workspace) *v1alpha1.Workspace {
|
||||||
|
workspace = workspace.DeepCopy()
|
||||||
|
if workspace.Annotations == nil {
|
||||||
|
workspace.Annotations = make(map[string]string)
|
||||||
|
}
|
||||||
|
ns, err := ListNamespaces(username, ¶ms.Conditions{Match: map[string]string{constants.WorkspaceLabelKey: workspace.Name}}, "", false, 1, 0)
|
||||||
|
if err == nil {
|
||||||
|
workspace.Annotations["kubesphere.io/namespace-count"] = strconv.Itoa(ns.TotalCount)
|
||||||
|
} else {
|
||||||
|
workspace.Annotations["kubesphere.io/namespace-count"] = "-1"
|
||||||
|
}
|
||||||
|
devops, err := ListDevopsProjects(workspace.Name, username, ¶ms.Conditions{}, "", false, 1, 0)
|
||||||
|
if err == nil {
|
||||||
|
workspace.Annotations["kubesphere.io/devops-count"] = strconv.Itoa(devops.TotalCount)
|
||||||
|
} else {
|
||||||
|
workspace.Annotations["kubesphere.io/devops-count"] = "-1"
|
||||||
|
}
|
||||||
|
userCount, err := ws.WorkspaceUserCount(workspace.Name)
|
||||||
|
if err == nil {
|
||||||
|
workspace.Annotations["kubesphere.io/member-count"] = strconv.Itoa(userCount)
|
||||||
|
} else {
|
||||||
|
workspace.Annotations["kubesphere.io/member-count"] = "-1"
|
||||||
|
}
|
||||||
|
return workspace
|
||||||
|
}
|
||||||
|
|
||||||
func ListNamespaces(username string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
func ListNamespaces(username string, conditions *params.Conditions, orderBy string, reverse bool, limit, offset int) (*models.PageableResponse, error) {
|
||||||
|
|
||||||
namespaces, err := namespaces.search(username, conditions, orderBy, reverse)
|
namespaces, err := namespaces.search(username, conditions, orderBy, reverse)
|
||||||
|
|||||||
@@ -40,6 +40,10 @@ func (*workspaceSearcher) match(match map[string]string, item *v1alpha1.Workspac
|
|||||||
if item.Name != v && item.Labels[constants.DisplayNameLabelKey] != v {
|
if item.Name != v && item.Labels[constants.DisplayNameLabelKey] != v {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
case "keyword":
|
||||||
|
if !strings.Contains(item.Name, v) && !contains(item.Labels, "", v) && !contains(item.Annotations, "", v) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
if item.Labels[k] != v {
|
if item.Labels[k] != v {
|
||||||
return false
|
return false
|
||||||
@@ -128,3 +132,16 @@ func (s *workspaceSearcher) search(username string, conditions *params.Condition
|
|||||||
func GetWorkspace(workspaceName string) (*v1alpha1.Workspace, error) {
|
func GetWorkspace(workspaceName string) (*v1alpha1.Workspace, error) {
|
||||||
return informers.KsSharedInformerFactory().Tenant().V1alpha1().Workspaces().Lister().Get(workspaceName)
|
return informers.KsSharedInformerFactory().Tenant().V1alpha1().Workspaces().Lister().Get(workspaceName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func contains(m map[string]string, key, value string) bool {
|
||||||
|
for k, v := range m {
|
||||||
|
if key == "" {
|
||||||
|
if strings.Contains(k, value) || strings.Contains(v, value) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
} else if k == key && strings.Contains(v, value) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ type WorkspaceDPBinding struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type DevopsProject struct {
|
type DevopsProject struct {
|
||||||
ProjectId *string `json:"project_id,omitempty"`
|
ProjectId string `json:"project_id,omitempty"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
Description string `json:"description"`
|
Description string `json:"description"`
|
||||||
Creator string `json:"creator"`
|
Creator string `json:"creator"`
|
||||||
|
|||||||
@@ -18,41 +18,29 @@
|
|||||||
package workspaces
|
package workspaces
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"encoding/json"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
|
||||||
"k8s.io/apimachinery/pkg/runtime/schema"
|
"k8s.io/apimachinery/pkg/runtime/schema"
|
||||||
"kubesphere.io/kubesphere/pkg/apis/tenant/v1alpha1"
|
|
||||||
"kubesphere.io/kubesphere/pkg/models/resources"
|
|
||||||
"kubesphere.io/kubesphere/pkg/params"
|
|
||||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
|
||||||
"kubesphere.io/kubesphere/pkg/simple/client/ldap"
|
|
||||||
"kubesphere.io/kubesphere/pkg/simple/client/mysql"
|
|
||||||
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
|
|
||||||
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
|
|
||||||
"net/http"
|
|
||||||
|
|
||||||
"kubesphere.io/kubesphere/pkg/constants"
|
"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"
|
||||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||||
|
"kubesphere.io/kubesphere/pkg/models/resources"
|
||||||
|
"kubesphere.io/kubesphere/pkg/params"
|
||||||
|
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||||
|
"kubesphere.io/kubesphere/pkg/simple/client/kubesphere"
|
||||||
|
"kubesphere.io/kubesphere/pkg/simple/client/mysql"
|
||||||
|
"kubesphere.io/kubesphere/pkg/utils/k8sutil"
|
||||||
|
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
|
||||||
|
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"github.com/jinzhu/gorm"
|
|
||||||
core "k8s.io/api/core/v1"
|
core "k8s.io/api/core/v1"
|
||||||
|
|
||||||
"errors"
|
"errors"
|
||||||
"github.com/golang/glog"
|
|
||||||
"k8s.io/api/rbac/v1"
|
"k8s.io/api/rbac/v1"
|
||||||
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
apierrors "k8s.io/apimachinery/pkg/api/errors"
|
||||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||||
"k8s.io/apimachinery/pkg/labels"
|
"k8s.io/apimachinery/pkg/labels"
|
||||||
|
|
||||||
"sort"
|
|
||||||
|
|
||||||
kserr "kubesphere.io/kubesphere/pkg/errors"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func UnBindDevopsProject(workspace string, devops string) error {
|
func UnBindDevopsProject(workspace string, devops string) error {
|
||||||
@@ -60,191 +48,26 @@ func UnBindDevopsProject(workspace string, devops string) error {
|
|||||||
return db.Delete(&models.WorkspaceDPBinding{Workspace: workspace, DevOpsProject: devops}).Error
|
return db.Delete(&models.WorkspaceDPBinding{Workspace: workspace, DevOpsProject: devops}).Error
|
||||||
}
|
}
|
||||||
|
|
||||||
func DeleteDevopsProject(username string, devops string) error {
|
func CreateDevopsProject(username string, workspace string, devops *models.DevopsProject) (*models.DevopsProject, error) {
|
||||||
request, _ := http.NewRequest(http.MethodDelete, fmt.Sprintf("http://%s/api/v1alpha/projects/%s", constants.DevopsAPIServer, devops), nil)
|
|
||||||
request.Header.Add("X-Token-Username", username)
|
|
||||||
|
|
||||||
result, err := http.DefaultClient.Do(request)
|
created, err := kubesphere.Client().CreateDevopsProject(username, devops)
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
defer result.Body.Close()
|
|
||||||
data, err := ioutil.ReadAll(result.Body)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
if result.StatusCode > 200 {
|
|
||||||
return kserr.Parse(data)
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func CreateDevopsProject(username string, workspace string, devops models.DevopsProject) (*models.DevopsProject, error) {
|
|
||||||
|
|
||||||
data, err := json.Marshal(devops)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
request, _ := http.NewRequest(http.MethodPost, fmt.Sprintf("http://%s/api/v1alpha/projects", constants.DevopsAPIServer), bytes.NewReader(data))
|
err = BindingDevopsProject(workspace, created.ProjectId)
|
||||||
request.Header.Add("X-Token-Username", username)
|
|
||||||
request.Header.Add("Content-Type", "application/json")
|
|
||||||
result, err := http.DefaultClient.Do(request)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
defer result.Body.Close()
|
return created, nil
|
||||||
data, err = ioutil.ReadAll(result.Body)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if result.StatusCode > 200 {
|
|
||||||
return nil, kserr.Parse(data)
|
|
||||||
}
|
|
||||||
|
|
||||||
var project models.DevopsProject
|
|
||||||
|
|
||||||
err = json.Unmarshal(data, &project)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = BindingDevopsProject(workspace, *project.ProjectId)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
DeleteDevopsProject(username, *project.ProjectId)
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
go createDefaultDevopsRoleBinding(workspace, project)
|
|
||||||
|
|
||||||
return &project, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createDefaultDevopsRoleBinding(workspace string, project models.DevopsProject) error {
|
|
||||||
admins := []string{""}
|
|
||||||
|
|
||||||
for _, admin := range admins {
|
|
||||||
createDevopsRoleBinding(workspace, *project.ProjectId, admin, constants.DevopsOwner)
|
|
||||||
}
|
|
||||||
|
|
||||||
viewers := []string{""}
|
|
||||||
|
|
||||||
for _, viewer := range viewers {
|
|
||||||
createDevopsRoleBinding(workspace, *project.ProjectId, viewer, constants.DevopsReporter)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func createDevopsRoleBinding(workspace string, projectId string, user string, role string) {
|
|
||||||
|
|
||||||
projects := make([]string, 0)
|
|
||||||
|
|
||||||
if projectId != "" {
|
|
||||||
projects = append(projects, projectId)
|
|
||||||
} else {
|
|
||||||
p, err := GetDevOpsProjects(workspace)
|
|
||||||
if err != nil {
|
|
||||||
glog.Warning("create devops role binding failed", workspace, projectId, user, role)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
projects = append(projects, p...)
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, project := range projects {
|
|
||||||
data := []byte(fmt.Sprintf(`{"username":"%s","role":"%s"}`, user, role))
|
|
||||||
request, _ := http.NewRequest(http.MethodPost, fmt.Sprintf("http://%s/api/v1alpha/projects/%s/members", constants.DevopsAPIServer, project), bytes.NewReader(data))
|
|
||||||
request.Header.Add("Content-Type", "application/json")
|
|
||||||
request.Header.Add("X-Token-Username", "admin")
|
|
||||||
resp, err := http.DefaultClient.Do(request)
|
|
||||||
if err != nil || resp.StatusCode > 200 {
|
|
||||||
glog.Warning(fmt.Sprintf("create devops role binding failed %s,%s,%s,%s", workspace, project, user, role))
|
|
||||||
}
|
|
||||||
if resp != nil {
|
|
||||||
resp.Body.Close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ListNamespaceByUser(workspaceName string, username string, keyword string, orderBy string, reverse bool, limit int, offset int) (int, []*core.Namespace, error) {
|
|
||||||
|
|
||||||
namespaces, err := Namespaces(workspaceName)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return 0, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if keyword != "" {
|
|
||||||
for i := 0; i < len(namespaces); i++ {
|
|
||||||
if !strings.Contains(namespaces[i].Name, keyword) {
|
|
||||||
namespaces = append(namespaces[:i], namespaces[i+1:]...)
|
|
||||||
i--
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sort.Slice(namespaces, func(i, j int) bool {
|
|
||||||
switch orderBy {
|
|
||||||
case "name":
|
|
||||||
if reverse {
|
|
||||||
return namespaces[i].Name < namespaces[j].Name
|
|
||||||
} else {
|
|
||||||
return namespaces[i].Name > namespaces[j].Name
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
if reverse {
|
|
||||||
return namespaces[i].CreationTimestamp.Time.After(namespaces[j].CreationTimestamp.Time)
|
|
||||||
} else {
|
|
||||||
return namespaces[i].CreationTimestamp.Time.Before(namespaces[j].CreationTimestamp.Time)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
rules, err := iam.GetUserClusterRules(username)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return 0, nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
namespacesManager := v1.PolicyRule{APIGroups: []string{"kubesphere.io"}, ResourceNames: []string{workspaceName}, Verbs: []string{"get"}, Resources: []string{"workspaces/namespaces"}}
|
|
||||||
|
|
||||||
if !iam.RulesMatchesRequired(rules, namespacesManager) {
|
|
||||||
for i := 0; i < len(namespaces); i++ {
|
|
||||||
roles, err := iam.GetUserRoles(namespaces[i].Name, username)
|
|
||||||
if err != nil {
|
|
||||||
return 0, nil, err
|
|
||||||
}
|
|
||||||
rules := make([]v1.PolicyRule, 0)
|
|
||||||
for _, role := range roles {
|
|
||||||
rules = append(rules, role.Rules...)
|
|
||||||
}
|
|
||||||
if !iam.RulesMatchesRequired(rules, v1.PolicyRule{APIGroups: []string{""}, ResourceNames: []string{namespaces[i].Name}, Verbs: []string{"get"}, Resources: []string{"namespaces"}}) {
|
|
||||||
namespaces = append(namespaces[:i], namespaces[i+1:]...)
|
|
||||||
i--
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(namespaces) < offset {
|
|
||||||
return len(namespaces), namespaces, nil
|
|
||||||
} else if len(namespaces) < limit+offset {
|
|
||||||
return len(namespaces), namespaces[offset:], nil
|
|
||||||
} else {
|
|
||||||
return len(namespaces), namespaces[offset : limit+offset], nil
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func Namespaces(workspaceName string) ([]*core.Namespace, error) {
|
func Namespaces(workspaceName string) ([]*core.Namespace, error) {
|
||||||
namespaceLister := informers.SharedInformerFactory().Core().V1().Namespaces().Lister()
|
namespaceLister := informers.SharedInformerFactory().Core().V1().Namespaces().Lister()
|
||||||
namespaces, err := namespaceLister.List(labels.SelectorFromSet(labels.Set{"kubesphere.io/workspace": workspaceName}))
|
namespaces, err := namespaceLister.List(labels.SelectorFromSet(labels.Set{constants.WorkspaceLabelKey: workspaceName}))
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@@ -281,161 +104,18 @@ func DeleteNamespace(workspace string, namespaceName string) error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func Delete(workspace *models.Workspace) error {
|
func RemoveUser(workspaceName string, username string) error {
|
||||||
|
workspaceRole, err := iam.GetUserWorkspaceRole(workspaceName, username)
|
||||||
err := release(workspace)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
err = DeleteWorkspaceRoleBinding(workspaceName, username, workspaceRole.Labels[constants.DisplayNameLabelKey])
|
||||||
err = iam.DeleteGroup(workspace.Name)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO
|
|
||||||
func release(workspace *models.Workspace) error {
|
|
||||||
for _, namespace := range workspace.Namespaces {
|
|
||||||
err := DeleteNamespace(workspace.Name, namespace)
|
|
||||||
if err != nil && !apierrors.IsNotFound(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, devops := range workspace.DevopsProjects {
|
|
||||||
err := DeleteDevopsProject("admin", devops)
|
|
||||||
if err != nil && !strings.Contains(err.Error(), "not found") {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
err := workspaceRoleRelease(workspace.Name)
|
|
||||||
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
func workspaceRoleRelease(workspace string) error {
|
|
||||||
k8sClient := k8s.Client()
|
|
||||||
deletePolicy := meta_v1.DeletePropagationForeground
|
|
||||||
|
|
||||||
for _, role := range constants.WorkSpaceRoles {
|
|
||||||
err := k8sClient.RbacV1().ClusterRoles().Delete(fmt.Sprintf("system:%s:%s", workspace, role), &meta_v1.DeleteOptions{PropagationPolicy: &deletePolicy})
|
|
||||||
|
|
||||||
if err != nil && !apierrors.IsNotFound(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for _, role := range constants.WorkSpaceRoles {
|
|
||||||
err := k8sClient.RbacV1().ClusterRoleBindings().Delete(fmt.Sprintf("system:%s:%s", workspace, role), &meta_v1.DeleteOptions{PropagationPolicy: &deletePolicy})
|
|
||||||
|
|
||||||
if err != nil && !apierrors.IsNotFound(err) {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func Edit(workspace *models.Workspace) (*models.Workspace, error) {
|
|
||||||
|
|
||||||
group, err := iam.UpdateGroup(&workspace.Group)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
workspace.Group = *group
|
|
||||||
|
|
||||||
return workspace, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func DescribeWorkspace(workspaceName string) (*v1alpha1.Workspace, error) {
|
|
||||||
workspace, err := informers.KsSharedInformerFactory().Tenant().V1alpha1().Workspaces().Lister().Get(workspaceName)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
return workspace, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func fetch(names []string) ([]*models.Workspace, error) {
|
|
||||||
|
|
||||||
if names != nil && len(names) == 0 {
|
|
||||||
return make([]*models.Workspace, 0), nil
|
|
||||||
}
|
|
||||||
var groups []models.Group
|
|
||||||
var err error
|
|
||||||
if names == nil {
|
|
||||||
groups, err = iam.ChildList("")
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
conn, err := ldap.Client()
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
defer conn.Close()
|
|
||||||
for _, name := range names {
|
|
||||||
group, err := iam.DescribeGroup(name)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
groups = append(groups, *group)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
db := mysql.Client()
|
|
||||||
|
|
||||||
workspaces := make([]*models.Workspace, 0)
|
|
||||||
for _, group := range groups {
|
|
||||||
workspace, err := convertGroupToWorkspace(db, group)
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
workspaces = append(workspaces, workspace)
|
|
||||||
}
|
|
||||||
|
|
||||||
return workspaces, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func convertGroupToWorkspace(db *gorm.DB, group models.Group) (*models.Workspace, error) {
|
|
||||||
namespaces, err := Namespaces(group.Name)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
namespacesNames := make([]string, 0)
|
|
||||||
|
|
||||||
for _, namespace := range namespaces {
|
|
||||||
namespacesNames = append(namespacesNames, namespace.Name)
|
|
||||||
}
|
|
||||||
|
|
||||||
var workspaceDOPBindings []models.WorkspaceDPBinding
|
|
||||||
|
|
||||||
if err := db.Where("workspace = ?", group.Name).Find(&workspaceDOPBindings).Error; err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
devOpsProjects := make([]string, 0)
|
|
||||||
|
|
||||||
for _, workspaceDOPBinding := range workspaceDOPBindings {
|
|
||||||
devOpsProjects = append(devOpsProjects, workspaceDOPBinding.DevOpsProject)
|
|
||||||
}
|
|
||||||
|
|
||||||
workspace := models.Workspace{Group: group}
|
|
||||||
workspace.Namespaces = namespacesNames
|
|
||||||
workspace.DevopsProjects = devOpsProjects
|
|
||||||
return &workspace, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func InviteUser(workspaceName string, user *models.User) error {
|
func InviteUser(workspaceName string, user *models.User) error {
|
||||||
|
|
||||||
workspaceRole, err := iam.GetUserWorkspaceRole(workspaceName, user.Username)
|
workspaceRole, err := iam.GetUserWorkspaceRole(workspaceName, user.Username)
|
||||||
@@ -463,7 +143,6 @@ 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()
|
workspaceRoleBinding = workspaceRoleBinding.DeepCopy()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -487,11 +166,10 @@ func DeleteWorkspaceRoleBinding(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()
|
||||||
|
|
||||||
for i, v := range workspaceRoleBinding.Subjects {
|
for i, v := range workspaceRoleBinding.Subjects {
|
||||||
if v.Kind == v1.UserKind && v.Name == username {
|
if v.Kind == v1.UserKind && v.Name == username {
|
||||||
|
|||||||
@@ -82,18 +82,6 @@ func ParseReverse(req *restful.Request) bool {
|
|||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
|
|
||||||
func ParseArray(str string) []string {
|
|
||||||
arr := make([]string, 0)
|
|
||||||
|
|
||||||
for _, item := range strings.Split(str, ",") {
|
|
||||||
if item = strings.TrimSpace(item); item != "" {
|
|
||||||
arr = append(arr, item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return arr
|
|
||||||
}
|
|
||||||
|
|
||||||
type Conditions struct {
|
type Conditions struct {
|
||||||
Match map[string]string
|
Match map[string]string
|
||||||
Fuzzy map[string]string
|
Fuzzy map[string]string
|
||||||
|
|||||||
186
pkg/simple/client/kubesphere/devops.go
Normal file
186
pkg/simple/client/kubesphere/devops.go
Normal file
@@ -0,0 +1,186 @@
|
|||||||
|
/*
|
||||||
|
|
||||||
|
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 kubesphere
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"github.com/golang/glog"
|
||||||
|
"io/ioutil"
|
||||||
|
"kubesphere.io/kubesphere/pkg/constants"
|
||||||
|
"kubesphere.io/kubesphere/pkg/models"
|
||||||
|
"net/http"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (c client) DeleteDevopsProject(username string, projectId string) error {
|
||||||
|
request, _ := http.NewRequest(http.MethodDelete, fmt.Sprintf("%s/api/v1alpha/projects/%s", devopsAPIServer, projectId), nil)
|
||||||
|
if username == "" {
|
||||||
|
username = constants.AdminUserName
|
||||||
|
}
|
||||||
|
request.Header.Add("X-Token-Username", username)
|
||||||
|
|
||||||
|
resp, err := c.client.Do(request)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
data, err := ioutil.ReadAll(resp.Body)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if resp.StatusCode > http.StatusOK {
|
||||||
|
return Error{resp.StatusCode, string(data)}
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c client) GetUserDevopsRole(username string, projectId string) (string, error) {
|
||||||
|
|
||||||
|
if username == "admin" {
|
||||||
|
return "owner", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/api/v1alpha/projects/%s/members", devopsAPIServer, projectId), nil)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
req.Header.Set(constants.UserNameHeader, username)
|
||||||
|
resp, err := c.client.Do(req)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer resp.Body.Close()
|
||||||
|
data, err := ioutil.ReadAll(resp.Body)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode > http.StatusOK {
|
||||||
|
return "", Error{resp.StatusCode, string(data)}
|
||||||
|
}
|
||||||
|
|
||||||
|
var result []map[string]string
|
||||||
|
|
||||||
|
err = json.Unmarshal(data, &result)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, item := range result {
|
||||||
|
if item["username"] == username {
|
||||||
|
return item["role"], nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return "", nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c client) CreateDevopsProject(username string, project *models.DevopsProject) (*models.DevopsProject, error) {
|
||||||
|
data, err := json.Marshal(project)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
request, _ := http.NewRequest(http.MethodPost, fmt.Sprintf("%s/api/v1alpha/projects", devopsAPIServer), bytes.NewReader(data))
|
||||||
|
request.Header.Add("X-Token-Username", username)
|
||||||
|
request.Header.Add("Content-Type", "application/json")
|
||||||
|
resp, err := c.client.Do(request)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
defer resp.Body.Close()
|
||||||
|
data, err = ioutil.ReadAll(resp.Body)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode > http.StatusOK {
|
||||||
|
return nil, Error{resp.StatusCode, string(data)}
|
||||||
|
}
|
||||||
|
|
||||||
|
var created models.DevopsProject
|
||||||
|
|
||||||
|
err = json.Unmarshal(data, &created)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return &created, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c client) CreateDevopsRoleBinding(projectId string, user string, role string) {
|
||||||
|
|
||||||
|
projects := make([]string, 0)
|
||||||
|
projects = append(projects, projectId)
|
||||||
|
|
||||||
|
for _, project := range projects {
|
||||||
|
data := []byte(fmt.Sprintf(`{"username":"%s","role":"%s"}`, user, role))
|
||||||
|
request, _ := http.NewRequest(http.MethodPost, fmt.Sprintf("%s/api/v1alpha/projects/%s/members", devopsAPIServer, project), bytes.NewReader(data))
|
||||||
|
request.Header.Add("Content-Type", "application/json")
|
||||||
|
request.Header.Add("X-Token-Username", "admin")
|
||||||
|
resp, err := c.client.Do(request)
|
||||||
|
if err != nil || resp.StatusCode > 200 {
|
||||||
|
glog.Warning(fmt.Sprintf("create devops role binding failed %s,%s,%s", project, user, role))
|
||||||
|
}
|
||||||
|
if resp != nil {
|
||||||
|
resp.Body.Close()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c client) ListDevopsProjects(username string) ([]models.DevopsProject, error) {
|
||||||
|
projects := make([]models.DevopsProject, 0)
|
||||||
|
|
||||||
|
request, _ := http.NewRequest(http.MethodGet, fmt.Sprintf("%s/api/v1alpha/projects", devopsAPIServer), nil)
|
||||||
|
request.Header.Add(constants.UserNameHeader, username)
|
||||||
|
|
||||||
|
resp, err := c.client.Do(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
data, err := ioutil.ReadAll(resp.Body)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
if resp.StatusCode > http.StatusOK {
|
||||||
|
return nil, Error{resp.StatusCode, string(data)}
|
||||||
|
}
|
||||||
|
|
||||||
|
err = json.Unmarshal(data, &projects)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return projects, nil
|
||||||
|
}
|
||||||
@@ -32,6 +32,7 @@ import (
|
|||||||
|
|
||||||
var (
|
var (
|
||||||
accountAPIServer string
|
accountAPIServer string
|
||||||
|
devopsAPIServer string
|
||||||
once sync.Once
|
once sync.Once
|
||||||
c client
|
c client
|
||||||
)
|
)
|
||||||
@@ -41,6 +42,11 @@ type Interface interface {
|
|||||||
UpdateGroup(group *models.Group) (*models.Group, error)
|
UpdateGroup(group *models.Group) (*models.Group, error)
|
||||||
DescribeGroup(name string) (*models.Group, error)
|
DescribeGroup(name string) (*models.Group, error)
|
||||||
DeleteGroup(name string) error
|
DeleteGroup(name string) error
|
||||||
|
DeleteDevopsProject(username string, projectId string) error
|
||||||
|
GetUserDevopsRole(username string, projectId string) (string, error)
|
||||||
|
CreateDevopsProject(username string, project *models.DevopsProject) (*models.DevopsProject, error)
|
||||||
|
CreateDevopsRoleBinding(projectId string, user string, role string)
|
||||||
|
ListDevopsProjects(username string) ([]models.DevopsProject, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type client struct {
|
type client struct {
|
||||||
@@ -49,6 +55,7 @@ type client struct {
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
flag.StringVar(&accountAPIServer, "ks-account-api-server", "http://ks-account.kubesphere-system.svc", "kubesphere account api server")
|
flag.StringVar(&accountAPIServer, "ks-account-api-server", "http://ks-account.kubesphere-system.svc", "kubesphere account api server")
|
||||||
|
flag.StringVar(&devopsAPIServer, "ks-devops-api-server", "http://ks-devops.kubesphere-devops-system.svc", "kubesphere devops api server")
|
||||||
}
|
}
|
||||||
|
|
||||||
func Client() Interface {
|
func Client() Interface {
|
||||||
|
|||||||
@@ -273,11 +273,10 @@ func makeHttpRequest(method, url, data string) ([]byte, error) {
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
httpClient := &http.Client{}
|
resp, err := http.DefaultClient.Do(req)
|
||||||
resp, err := httpClient.Do(req)
|
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
err := fmt.Errorf("Request to %s failed, method: %s, reason: %s ", url, method, err)
|
err := fmt.Errorf("Request to %s failed, method: %s,token: %s, reason: %s ", url, method, openpitrixProxyToken, err)
|
||||||
glog.Error(err)
|
glog.Error(err)
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user