@@ -11,8 +11,13 @@ import (
|
||||
|
||||
"k8s.io/kubernetes/pkg/util/slice"
|
||||
|
||||
"strconv"
|
||||
|
||||
"regexp"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/models/iam"
|
||||
"kubesphere.io/kubesphere/pkg/models/metrics"
|
||||
"kubesphere.io/kubesphere/pkg/models/workspaces"
|
||||
)
|
||||
|
||||
@@ -26,9 +31,13 @@ func Register(ws *restful.WebService, subPath string) {
|
||||
ws.Route(ws.GET(subPath + "/{name}").To(WorkspaceDetailHandler))
|
||||
ws.Route(ws.PUT(subPath + "/{name}").To(WorkspaceEditHandler))
|
||||
ws.Route(ws.GET(subPath + "/{workspace}/namespaces").To(UserNamespaceListHandler))
|
||||
ws.Route(ws.GET(subPath + "/{workspace}/members/{username}/namespaces").To(UserNamespaceListHandler))
|
||||
ws.Route(ws.POST(subPath + "/{name}/namespaces").To(NamespaceCreateHandler))
|
||||
ws.Route(ws.DELETE(subPath + "/{name}/namespaces/{namespace}").To(NamespaceDeleteHandler))
|
||||
ws.Route(ws.GET(subPath + "/{name}/namespaces/{namespace}").To(NamespaceCheckHandler))
|
||||
ws.Route(ws.GET("/namespaces/{namespace}").To(NamespaceCheckHandler))
|
||||
ws.Route(ws.GET(subPath + "/{name}/devops").To(DevOpsProjectHandler))
|
||||
ws.Route(ws.GET(subPath + "/{name}/members/{username}/devops").To(DevOpsProjectHandler))
|
||||
ws.Route(ws.POST(subPath + "/{name}/devops").To(DevOpsProjectCreateHandler))
|
||||
ws.Route(ws.DELETE(subPath + "/{name}/devops/{id}").To(DevOpsProjectDeleteHandler))
|
||||
|
||||
@@ -171,10 +180,22 @@ func MembersRemoveHandler(req *restful.Request, resp *restful.Response) {
|
||||
resp.WriteHeaderAndEntity(http.StatusOK, constants.MessageResponse{Message: "success"})
|
||||
}
|
||||
|
||||
func NamespaceCheckHandler(req *restful.Request, resp *restful.Response) {
|
||||
namespace := req.PathParameter("namespace")
|
||||
|
||||
exist, err := workspaces.NamespaceExistCheck(namespace)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(map[string]bool{"exist": exist})
|
||||
}
|
||||
|
||||
func NamespaceDeleteHandler(req *restful.Request, resp *restful.Response) {
|
||||
namespace := req.PathParameter("namespace")
|
||||
workspace := req.PathParameter("name")
|
||||
//force := req.QueryParameter("force")
|
||||
|
||||
err := workspaces.DeleteNamespace(workspace, namespace)
|
||||
|
||||
@@ -223,26 +244,14 @@ func DevOpsProjectCreateHandler(req *restful.Request, resp *restful.Response) {
|
||||
return
|
||||
}
|
||||
|
||||
project, err := workspaces.CreateDevopsProject(username, devops)
|
||||
project, err := workspaces.CreateDevopsProject(username, workspace, devops)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
if project.ProjectId == nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: "project create failed"})
|
||||
} else {
|
||||
err = workspaces.BindingDevopsProject(workspace, *project.ProjectId)
|
||||
|
||||
if err != nil {
|
||||
workspaces.DeleteDevopsProject(username, *project.ProjectId)
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(project)
|
||||
}
|
||||
resp.WriteEntity(project)
|
||||
|
||||
}
|
||||
|
||||
@@ -285,15 +294,53 @@ func NamespaceCreateHandler(req *restful.Request, resp *restful.Response) {
|
||||
func DevOpsProjectHandler(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
workspace := req.PathParameter("name")
|
||||
username := req.PathParameter("username")
|
||||
keyword := req.QueryParameter("keyword")
|
||||
|
||||
devOpsProjects, err := workspaces.DevopsProjects(workspace)
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
total, devOpsProjects, err := workspaces.ListDevopsProjectsByUser(username, workspace, keyword, orderBy, reverse, limit, offset)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(devOpsProjects)
|
||||
result := constants.PageableResponse{}
|
||||
result.TotalCount = total
|
||||
result.Items = make([]interface{}, 0)
|
||||
for _, n := range devOpsProjects {
|
||||
result.Items = append(result.Items, n)
|
||||
}
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
func WorkspaceCreateHandler(req *restful.Request, resp *restful.Response) {
|
||||
@@ -402,10 +449,10 @@ func WorkspaceDetailHandler(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
// List all workspaces for the current user
|
||||
func UserWorkspaceListHandler(req *restful.Request, resp *restful.Response) {
|
||||
|
||||
keyword := req.QueryParameter("keyword")
|
||||
username := req.HeaderParameter(UserNameHeader)
|
||||
|
||||
list, err := workspaces.ListByUser(username)
|
||||
list, err := workspaces.ListWorkspaceByUser(username, keyword)
|
||||
|
||||
if err != nil {
|
||||
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
|
||||
@@ -416,16 +463,62 @@ func UserWorkspaceListHandler(req *restful.Request, resp *restful.Response) {
|
||||
}
|
||||
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
username := req.HeaderParameter(UserNameHeader)
|
||||
workspaceName := req.PathParameter("workspace")
|
||||
|
||||
namespaces, err := workspaces.ListNamespaceByUser(workspaceName, username)
|
||||
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, constants.MessageResponse{Message: err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
resp.WriteEntity(namespaces)
|
||||
result := constants.PageableResponse{}
|
||||
result.TotalCount = total
|
||||
result.Items = make([]interface{}, 0)
|
||||
for _, n := range namespaces {
|
||||
result.Items = append(result.Items, n)
|
||||
}
|
||||
|
||||
resp.WriteEntity(result)
|
||||
}
|
||||
|
||||
@@ -19,10 +19,16 @@ package controllers
|
||||
import (
|
||||
"time"
|
||||
|
||||
"fmt"
|
||||
"regexp"
|
||||
|
||||
"github.com/golang/glog"
|
||||
"github.com/pkg/errors"
|
||||
rbac "k8s.io/api/rbac/v1"
|
||||
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"k8s.io/client-go/informers"
|
||||
"k8s.io/client-go/tools/cache"
|
||||
)
|
||||
|
||||
func (ctl *ClusterRoleBindingCtl) Name() string {
|
||||
@@ -43,10 +49,63 @@ func (ctl *ClusterRoleBindingCtl) total() int {
|
||||
return len(list)
|
||||
}
|
||||
|
||||
func (ctl *ClusterRoleBindingCtl) handleWorkspaceRoleChange(clusterRole *rbac.ClusterRoleBinding) {
|
||||
if groups := regexp.MustCompile("^system:(\\w+):(admin|operator|viewer)$").FindStringSubmatch(clusterRole.Name); len(groups) == 3 {
|
||||
workspace := groups[1]
|
||||
go ctl.restNamespaceRoleBinding(workspace)
|
||||
}
|
||||
}
|
||||
|
||||
func (ctl *ClusterRoleBindingCtl) restNamespaceRoleBinding(workspace string) {
|
||||
selector := labels.SelectorFromSet(labels.Set{"kubesphere.io/workspace": workspace})
|
||||
namespaces, err := ctl.K8sClient.CoreV1().Namespaces().List(meta_v1.ListOptions{LabelSelector: selector.String()})
|
||||
|
||||
if err != nil {
|
||||
glog.Warning("workspace roles sync failed", workspace, err)
|
||||
return
|
||||
}
|
||||
|
||||
for _, namespace := range namespaces.Items {
|
||||
pathJson := fmt.Sprintf(`{"metadata":{"annotations":{"%s":"%s"}}}`, initTimeAnnotateKey, "")
|
||||
_, err := ctl.K8sClient.CoreV1().Namespaces().Patch(namespace.Name, "application/strategic-merge-patch+json", []byte(pathJson))
|
||||
if err != nil {
|
||||
glog.Warning("workspace roles sync failed", workspace, err)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (ctl *ClusterRoleBindingCtl) initListerAndInformer() {
|
||||
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
|
||||
ctl.lister = informerFactory.Rbac().V1().ClusterRoleBindings().Lister()
|
||||
ctl.informer = informerFactory.Rbac().V1().ClusterRoleBindings().Informer()
|
||||
ctl.informer.AddEventHandler(cache.ResourceEventHandlerFuncs{
|
||||
AddFunc: func(obj interface{}) {
|
||||
},
|
||||
UpdateFunc: func(old, new interface{}) {
|
||||
oldValue := old.(*rbac.ClusterRoleBinding)
|
||||
newValue := new.(*rbac.ClusterRoleBinding)
|
||||
if !subjectsCompile(oldValue.Subjects, newValue.Subjects) {
|
||||
ctl.handleWorkspaceRoleChange(newValue)
|
||||
}
|
||||
},
|
||||
DeleteFunc: func(obj interface{}) {
|
||||
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func subjectsCompile(s1 []rbac.Subject, s2 []rbac.Subject) bool {
|
||||
if len(s1) != len(s2) {
|
||||
return false
|
||||
}
|
||||
|
||||
for i, v := range s1 {
|
||||
if v.Name != s2[i].Name || v.Kind != s2[i].Kind {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (ctl *ClusterRoleBindingCtl) CountWithConditions(conditions string) int {
|
||||
|
||||
@@ -46,17 +46,19 @@ import (
|
||||
const (
|
||||
provider = "kubernetes"
|
||||
admin = "admin"
|
||||
editor = "editor"
|
||||
editor = "operator"
|
||||
viewer = "viewer"
|
||||
kubectlNamespace = constants.KubeSphereControlNamespace
|
||||
kubectlConfigKey = "config"
|
||||
openPitrixRuntimeAnnotateKey = "openpitrix_runtime"
|
||||
creatorAnnotateKey = "creator"
|
||||
initTimeAnnotateKey = "kubesphere.io/init-time"
|
||||
workspaceLabelKey = "kubesphere.io/workspace"
|
||||
)
|
||||
|
||||
var adminRules = []rbac.PolicyRule{{Verbs: []string{"*"}, APIGroups: []string{"*"}, Resources: []string{"*"}}}
|
||||
var editorRules = []rbac.PolicyRule{{Verbs: []string{"*"}, APIGroups: []string{"", "apps", "extensions", "batch"}, Resources: []string{"*"}}}
|
||||
var viewerRules = []rbac.PolicyRule{{Verbs: []string{"list", "get", "watch"}, APIGroups: []string{"", "apps", "extensions", "batch"}, Resources: []string{"*"}}}
|
||||
var editorRules = []rbac.PolicyRule{{Verbs: []string{"*"}, APIGroups: []string{"", "apps", "extensions", "batch", "kubesphere.io", "account.kubesphere.io"}, Resources: []string{"*"}}}
|
||||
var viewerRules = []rbac.PolicyRule{{Verbs: []string{"list", "get", "watch"}, APIGroups: []string{"", "apps", "extensions", "batch", "kubesphere.io", "account.kubesphere.io"}, Resources: []string{"*"}}}
|
||||
|
||||
type runTime struct {
|
||||
RuntimeId string `json:"runtime_id"`
|
||||
@@ -131,15 +133,84 @@ func (ctl *NamespaceCtl) createOpRuntime(namespace string) ([]byte, error) {
|
||||
return makeHttpRequest("POST", url, string(body))
|
||||
}
|
||||
|
||||
func (ctl *NamespaceCtl) createDefaultRoleBinding(ns, user string) error {
|
||||
func (ctl *NamespaceCtl) createDefaultRoleBinding(namespace *v1.Namespace) error {
|
||||
|
||||
roleBinding := &rbac.RoleBinding{ObjectMeta: metaV1.ObjectMeta{Name: admin, Namespace: ns},
|
||||
Subjects: []rbac.Subject{{Name: user, Kind: rbac.UserKind}}, RoleRef: rbac.RoleRef{Kind: "Role", Name: admin}}
|
||||
workspace := ""
|
||||
creator := ""
|
||||
if namespace.Annotations != nil {
|
||||
creator = namespace.Annotations[creatorAnnotateKey]
|
||||
}
|
||||
if namespace.Labels != nil {
|
||||
workspace = namespace.Labels[workspaceLabelKey]
|
||||
}
|
||||
|
||||
_, err := ctl.K8sClient.RbacV1().RoleBindings(ns).Create(roleBinding)
|
||||
adminBinding, err := ctl.K8sClient.RbacV1().RoleBindings(namespace.Name).Get(admin, metaV1.GetOptions{})
|
||||
|
||||
if err != nil && !errors.IsAlreadyExists(err) {
|
||||
glog.Error(err)
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
adminBinding = new(rbac.RoleBinding)
|
||||
adminBinding.Name = admin
|
||||
adminBinding.Namespace = namespace.Name
|
||||
adminBinding.RoleRef = rbac.RoleRef{Kind: "Role", Name: admin}
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
adminBinding.Subjects = make([]rbac.Subject, 0)
|
||||
|
||||
if creator != "" {
|
||||
adminBinding.Subjects = append(adminBinding.Subjects, rbac.Subject{Name: creator, Kind: rbac.UserKind})
|
||||
}
|
||||
|
||||
if workspace != "" {
|
||||
workspaceAdmin, err := ctl.K8sClient.RbacV1().ClusterRoleBindings().Get(fmt.Sprintf("system:%s:admin", workspace), metaV1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
adminBinding.Subjects = append(adminBinding.Subjects, workspaceAdmin.Subjects...)
|
||||
}
|
||||
|
||||
if adminBinding.ResourceVersion == "" {
|
||||
_, err = ctl.K8sClient.RbacV1().RoleBindings(namespace.Name).Create(adminBinding)
|
||||
} else {
|
||||
_, err = ctl.K8sClient.RbacV1().RoleBindings(namespace.Name).Update(adminBinding)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
viewerBinding, err := ctl.K8sClient.RbacV1().RoleBindings(namespace.Name).Get(viewer, metaV1.GetOptions{})
|
||||
|
||||
if err != nil {
|
||||
if errors.IsNotFound(err) {
|
||||
viewerBinding = new(rbac.RoleBinding)
|
||||
viewerBinding.Name = viewer
|
||||
viewerBinding.Namespace = namespace.Name
|
||||
viewerBinding.RoleRef = rbac.RoleRef{Kind: "Role", Name: viewer}
|
||||
} else {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
viewerBinding.Subjects = make([]rbac.Subject, 0)
|
||||
|
||||
if workspace != "" {
|
||||
workspaceViewer, err := ctl.K8sClient.RbacV1().ClusterRoleBindings().Get(fmt.Sprintf("system:%s:viewer", workspace), metaV1.GetOptions{})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
viewerBinding.Subjects = append(viewerBinding.Subjects, workspaceViewer.Subjects...)
|
||||
}
|
||||
|
||||
if viewerBinding.ResourceVersion == "" {
|
||||
_, err = ctl.K8sClient.RbacV1().RoleBindings(namespace.Name).Create(viewerBinding)
|
||||
} else {
|
||||
_, err = ctl.K8sClient.RbacV1().RoleBindings(namespace.Name).Update(viewerBinding)
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -172,60 +243,44 @@ func (ctl *NamespaceCtl) createDefaultRole(ns string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (ctl *NamespaceCtl) createRoleAndRuntime(item v1.Namespace) {
|
||||
var creator string
|
||||
var runtime string
|
||||
ns := item.Name
|
||||
|
||||
if item.Annotations == nil {
|
||||
creator = ""
|
||||
runtime = ""
|
||||
} else {
|
||||
runtime = item.Annotations[openPitrixRuntimeAnnotateKey]
|
||||
creator = item.Annotations[creatorAnnotateKey]
|
||||
func (ctl *NamespaceCtl) createRoleAndRuntime(namespace *v1.Namespace) {
|
||||
runtime := ""
|
||||
initTime := ""
|
||||
if namespace.Annotations != nil {
|
||||
runtime = namespace.Annotations[openPitrixRuntimeAnnotateKey]
|
||||
initTime = namespace.Annotations[initTimeAnnotateKey]
|
||||
}
|
||||
|
||||
componentsNamespaces := []string{constants.KubeSystemNamespace, constants.OpenPitrixNamespace, constants.IstioNamespace, constants.KubeSphereNamespace}
|
||||
|
||||
if len(runtime) == 0 && !slice.ContainsString(componentsNamespaces, ns, nil) {
|
||||
glog.Infoln("create runtime:", ns)
|
||||
var runtimeCreateError error
|
||||
resp, runtimeCreateError := ctl.createOpRuntime(ns)
|
||||
|
||||
if runtimeCreateError == nil {
|
||||
var runtime runTime
|
||||
runtimeCreateError = json.Unmarshal(resp, &runtime)
|
||||
if runtimeCreateError == nil {
|
||||
|
||||
if item.Annotations == nil {
|
||||
item.Annotations = make(map[string]string, 0)
|
||||
}
|
||||
|
||||
item.Annotations[openPitrixRuntimeAnnotateKey] = runtime.RuntimeId
|
||||
_, runtimeCreateError = ctl.K8sClient.CoreV1().Namespaces().Update(&item)
|
||||
|
||||
}
|
||||
}
|
||||
if runtime == "" && !slice.ContainsString(componentsNamespaces, namespace.Name, nil) {
|
||||
glog.Infoln("create runtime:", namespace.Name)
|
||||
_, runtimeCreateError := ctl.createOpRuntime(namespace.Name)
|
||||
|
||||
if runtimeCreateError != nil {
|
||||
glog.Error("runtime create error:", runtimeCreateError)
|
||||
}
|
||||
}
|
||||
|
||||
if len(creator) > 0 {
|
||||
roleCreateError := ctl.createDefaultRole(ns)
|
||||
glog.Infoln("create default role:", ns)
|
||||
if roleCreateError == nil {
|
||||
|
||||
roleBindingError := ctl.createDefaultRoleBinding(ns, creator)
|
||||
glog.Infoln("create default role binding:", ns)
|
||||
if roleBindingError != nil {
|
||||
glog.Error("default role binding create error:", roleBindingError)
|
||||
}
|
||||
|
||||
} else {
|
||||
glog.Error("default role create error:", roleCreateError)
|
||||
if initTime == "" {
|
||||
err := ctl.createDefaultRole(namespace.Name)
|
||||
glog.Infoln("create default role:", namespace.Name)
|
||||
if err == nil {
|
||||
err = ctl.createDefaultRoleBinding(namespace)
|
||||
glog.Infoln("create default role binding:", namespace.Name)
|
||||
if err != nil {
|
||||
glog.Error("default role binding create error:", err)
|
||||
}
|
||||
} else {
|
||||
glog.Error("default role create error:", err)
|
||||
}
|
||||
|
||||
if err == nil {
|
||||
pathJson := fmt.Sprintf(`{"metadata":{"annotations":{"%s":"%s"}}}`, initTimeAnnotateKey, time.Now().UTC().Format("2006-01-02T15:04:05Z"))
|
||||
_, err = ctl.K8sClient.CoreV1().Namespaces().Patch(namespace.Name, "application/strategic-merge-patch+json", []byte(pathJson))
|
||||
if err != nil {
|
||||
glog.Error("annotations patch error init failed:", namespace.Name, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -293,7 +348,7 @@ func (ctl *NamespaceCtl) createCephSecretAfterNewNs(item v1.Namespace) {
|
||||
}
|
||||
}
|
||||
|
||||
func (ctl *NamespaceCtl) generateObject(item v1.Namespace) *Namespace {
|
||||
func (ctl *NamespaceCtl) generateObject(item *v1.Namespace) *Namespace {
|
||||
var displayName string
|
||||
|
||||
if item.Annotations != nil && len(item.Annotations[DisplayName]) > 0 {
|
||||
@@ -333,17 +388,17 @@ func (ctl *NamespaceCtl) sync(stopChan chan struct{}) {
|
||||
db = db.CreateTable(&Namespace{})
|
||||
|
||||
ctl.initListerAndInformer()
|
||||
list, err := ctl.lister.List(labels.Everything())
|
||||
if err != nil {
|
||||
glog.Error(err)
|
||||
return
|
||||
}
|
||||
//list, err := ctl.lister.List(labels.Everything())
|
||||
//if err != nil {
|
||||
// glog.Error(err)
|
||||
// return
|
||||
//}
|
||||
|
||||
for _, item := range list {
|
||||
obj := ctl.generateObject(*item)
|
||||
db.Create(obj)
|
||||
ctl.createRoleAndRuntime(*item)
|
||||
}
|
||||
//for _, item := range list {
|
||||
// obj := ctl.generateObject(item)
|
||||
// db.Create(obj)
|
||||
// ctl.createRoleAndRuntime(item)
|
||||
//}
|
||||
|
||||
ctl.informer.Run(stopChan)
|
||||
}
|
||||
@@ -369,16 +424,16 @@ func (ctl *NamespaceCtl) initListerAndInformer() {
|
||||
AddFunc: func(obj interface{}) {
|
||||
|
||||
object := obj.(*v1.Namespace)
|
||||
mysqlObject := ctl.generateObject(*object)
|
||||
mysqlObject := ctl.generateObject(object)
|
||||
db.Create(mysqlObject)
|
||||
ctl.createRoleAndRuntime(*object)
|
||||
ctl.createRoleAndRuntime(object)
|
||||
ctl.createCephSecretAfterNewNs(*object)
|
||||
},
|
||||
UpdateFunc: func(old, new interface{}) {
|
||||
object := new.(*v1.Namespace)
|
||||
mysqlObject := ctl.generateObject(*object)
|
||||
mysqlObject := ctl.generateObject(object)
|
||||
db.Save(mysqlObject)
|
||||
ctl.createRoleAndRuntime(*object)
|
||||
ctl.createRoleAndRuntime(object)
|
||||
},
|
||||
DeleteFunc: func(obj interface{}) {
|
||||
var item Namespace
|
||||
@@ -386,7 +441,6 @@ func (ctl *NamespaceCtl) initListerAndInformer() {
|
||||
db.Where("name=?", object.Name).Find(&item)
|
||||
db.Delete(item)
|
||||
ctl.deleteOpRuntime(*object)
|
||||
|
||||
},
|
||||
})
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ import (
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
v12 "k8s.io/client-go/listers/rbac/v1"
|
||||
|
||||
"k8s.io/kubernetes/pkg/util/slice"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/client"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/models/controllers"
|
||||
@@ -67,6 +69,7 @@ func GetUsers(names []string) ([]User, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer result.Body.Close()
|
||||
data, err := ioutil.ReadAll(result.Body)
|
||||
|
||||
if err != nil {
|
||||
@@ -94,6 +97,7 @@ func GetUser(name string) (*User, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer result.Body.Close()
|
||||
data, err := ioutil.ReadAll(result.Body)
|
||||
|
||||
if err != nil {
|
||||
@@ -228,7 +232,8 @@ func DeleteRoleBindings(username string) error {
|
||||
length2 := len(roleBinding.Subjects)
|
||||
|
||||
if length2 == 0 {
|
||||
k8s.RbacV1().RoleBindings(roleBinding.Namespace).Delete(roleBinding.Name, &meta_v1.DeleteOptions{})
|
||||
deletePolicy := meta_v1.DeletePropagationForeground
|
||||
k8s.RbacV1().RoleBindings(roleBinding.Namespace).Delete(roleBinding.Name, &meta_v1.DeleteOptions{PropagationPolicy: &deletePolicy})
|
||||
} else if length2 < length1 {
|
||||
k8s.RbacV1().RoleBindings(roleBinding.Namespace).Update(&roleBinding)
|
||||
}
|
||||
@@ -248,7 +253,8 @@ func DeleteRoleBindings(username string) error {
|
||||
|
||||
length2 := len(roleBinding.Subjects)
|
||||
if length2 == 0 {
|
||||
k8s.RbacV1().ClusterRoleBindings().Delete(roleBinding.Name, &meta_v1.DeleteOptions{})
|
||||
deletePolicy := meta_v1.DeletePropagationForeground
|
||||
k8s.RbacV1().ClusterRoleBindings().Delete(roleBinding.Name, &meta_v1.DeleteOptions{PropagationPolicy: &deletePolicy})
|
||||
} else if length2 < length1 {
|
||||
k8s.RbacV1().ClusterRoleBindings().Update(&roleBinding)
|
||||
}
|
||||
@@ -265,6 +271,21 @@ func GetRole(namespace string, name string) (*v1.Role, error) {
|
||||
}
|
||||
return role, nil
|
||||
}
|
||||
func GetWorkspaceUsers(workspace string, role string) []string {
|
||||
users := make([]string, 0)
|
||||
clusterRoleBindingLister := controllers.ResourceControllers.Controllers[controllers.ClusterRoleBindings].Lister().(v12.ClusterRoleBindingLister)
|
||||
clusterRoleBinding, err := clusterRoleBindingLister.Get(fmt.Sprintf("system:%s:%s", workspace, role))
|
||||
if err != nil {
|
||||
return users
|
||||
}
|
||||
|
||||
for _, s := range clusterRoleBinding.Subjects {
|
||||
if s.Kind == v1.UserKind && !slice.ContainsString(users, s.Name, nil) {
|
||||
users = append(users, s.Name)
|
||||
}
|
||||
}
|
||||
return users
|
||||
}
|
||||
|
||||
func GetClusterRoleBindings(name string) ([]v1.ClusterRoleBinding, error) {
|
||||
k8s := client.NewK8sClient()
|
||||
@@ -370,7 +391,6 @@ func GetRoles(namespace string, username string) ([]v1.Role, error) {
|
||||
|
||||
// Get cluster roles by username
|
||||
func GetClusterRoles(username string) ([]v1.ClusterRole, error) {
|
||||
//TODO fix NPE
|
||||
clusterRoleBindingLister := controllers.ResourceControllers.Controllers[controllers.ClusterRoleBindings].Lister().(v12.ClusterRoleBindingLister)
|
||||
clusterRoleLister := controllers.ResourceControllers.Controllers[controllers.ClusterRoles].Lister().(v12.ClusterRoleLister)
|
||||
clusterRoleBindings, err := clusterRoleBindingLister.List(labels.Everything())
|
||||
@@ -382,7 +402,7 @@ func GetClusterRoles(username string) ([]v1.ClusterRole, error) {
|
||||
roles := make([]v1.ClusterRole, 0)
|
||||
|
||||
for _, roleBinding := range clusterRoleBindings {
|
||||
for _, subject := range roleBinding.Subjects {
|
||||
for i, subject := range roleBinding.Subjects {
|
||||
if subject.Kind == v1.UserKind && subject.Name == username {
|
||||
if roleBinding.RoleRef.Kind == ClusterRoleKind {
|
||||
role, err := clusterRoleLister.Get(roleBinding.RoleRef.Name)
|
||||
@@ -398,7 +418,8 @@ func GetClusterRoles(username string) ([]v1.ClusterRole, error) {
|
||||
roles = append(roles, *role)
|
||||
break
|
||||
} else if apierrors.IsNotFound(err) {
|
||||
glog.Warning(err)
|
||||
roleBinding.Subjects = append(roleBinding.Subjects[:i], roleBinding.Subjects[i+1:]...)
|
||||
client.NewK8sClient().RbacV1().ClusterRoleBindings().Update(roleBinding)
|
||||
break
|
||||
} else {
|
||||
return nil, err
|
||||
@@ -411,76 +432,6 @@ func GetClusterRoles(username string) ([]v1.ClusterRole, error) {
|
||||
return roles, nil
|
||||
}
|
||||
|
||||
//func RuleValidate(rules []v1.PolicyRule, rule v1.PolicyRule) bool {
|
||||
//
|
||||
// for _, apiGroup := range rule.APIGroups {
|
||||
// if len(rule.NonResourceURLs) == 0 {
|
||||
// for _, resource := range rule.Resources {
|
||||
//
|
||||
// //if len(Rule.ResourceNames) == 0 {
|
||||
//
|
||||
// for _, verb := range rule.Verbs {
|
||||
// if !verbValidate(rules, apiGroup, "", resource, "", verb) {
|
||||
// return false
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// //} else {
|
||||
// // for _, resourceName := range Rule.ResourceNames {
|
||||
// // for _, verb := range Rule.Verbs {
|
||||
// // if !verbValidate(rules, apiGroup, "", resource, resourceName, verb) {
|
||||
// // return false
|
||||
// // }
|
||||
// // }
|
||||
// // }
|
||||
// //}
|
||||
// }
|
||||
// } else {
|
||||
// for _, nonResourceURL := range rule.NonResourceURLs {
|
||||
// for _, verb := range rule.Verbs {
|
||||
// if !verbValidate(rules, apiGroup, nonResourceURL, "", "", verb) {
|
||||
// return false
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return true
|
||||
//}
|
||||
|
||||
//func verbValidate(rules []v1.PolicyRule, apiGroup string, nonResourceURL string, resource string, resourceName string, verb string) bool {
|
||||
// for _, rule := range rules {
|
||||
//
|
||||
// if nonResourceURL == "" {
|
||||
// if slice.ContainsString(rule.APIGroups, apiGroup, nil) ||
|
||||
// slice.ContainsString(rule.APIGroups, v1.APIGroupAll, nil) {
|
||||
// if slice.ContainsString(rule.Verbs, verb, nil) ||
|
||||
// slice.ContainsString(rule.Verbs, v1.VerbAll, nil) {
|
||||
// if slice.ContainsString(rule.Resources, v1.ResourceAll, nil) {
|
||||
// return true
|
||||
// } else if slice.ContainsString(rule.Resources, resource, nil) {
|
||||
// if len(rule.ResourceNames) > 0 {
|
||||
// if slice.ContainsString(rule.ResourceNames, resourceName, nil) {
|
||||
// return true
|
||||
// }
|
||||
// } else if resourceName == "" {
|
||||
// return true
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// } else if slice.ContainsString(rule.NonResourceURLs, nonResourceURL, nil) ||
|
||||
// slice.ContainsString(rule.NonResourceURLs, v1.NonResourceAll, nil) {
|
||||
// if slice.ContainsString(rule.Verbs, verb, nil) ||
|
||||
// slice.ContainsString(rule.Verbs, v1.VerbAll, nil) {
|
||||
// return true
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// return false
|
||||
//}
|
||||
|
||||
func GetUserRules(username string) (map[string][]Rule, error) {
|
||||
|
||||
items := make(map[string][]Rule, 0)
|
||||
|
||||
@@ -60,9 +60,22 @@ var (
|
||||
{Name: "edit",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"update", "patch"},
|
||||
Verbs: []string{"*"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces"},
|
||||
}, {
|
||||
Verbs: []string{"*"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces/*"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"*"},
|
||||
APIGroups: []string{"jenkins.kubesphere.io"},
|
||||
Resources: []string{"*"},
|
||||
}, {
|
||||
Verbs: []string{"*"},
|
||||
APIGroups: []string{"devops.kubesphere.io"},
|
||||
Resources: []string{"*"},
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -83,7 +96,34 @@ var (
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"list"},
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces/members"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "create",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"create"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces/members"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "edit",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"patch", "update"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces/members"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "delete",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"delete"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces/members"},
|
||||
},
|
||||
@@ -97,7 +137,7 @@ var (
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"list"},
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces/devops"},
|
||||
},
|
||||
@@ -124,7 +164,7 @@ var (
|
||||
{Name: "delete",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"delete", "deletecollection"},
|
||||
Verbs: []string{"delete"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces/devops"},
|
||||
},
|
||||
@@ -138,7 +178,7 @@ var (
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"list"},
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces/namespaces"},
|
||||
},
|
||||
@@ -165,7 +205,7 @@ var (
|
||||
{Name: "delete",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"delete", "deletecollection"},
|
||||
Verbs: []string{"delete"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces/namespaces"},
|
||||
},
|
||||
@@ -173,31 +213,57 @@ var (
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "registries",
|
||||
Actions: []Action{
|
||||
{Name: "view"},
|
||||
{Name: "create"},
|
||||
{Name: "edit"},
|
||||
{Name: "delete"},
|
||||
},
|
||||
},
|
||||
{
|
||||
Name: "organizations",
|
||||
Actions: []Action{
|
||||
{Name: "view"},
|
||||
{Name: "create"},
|
||||
{Name: "edit"},
|
||||
{Name: "delete"},
|
||||
},
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"account.kubesphere.io"},
|
||||
Resources: []string{"workspaces/organizations"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "create",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"create"},
|
||||
APIGroups: []string{"account.kubesphere.io"},
|
||||
Resources: []string{"workspaces/organizations"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "edit",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"update", "patch"},
|
||||
APIGroups: []string{"account.kubesphere.io"},
|
||||
Resources: []string{"workspaces/organizations"},
|
||||
},
|
||||
},
|
||||
},
|
||||
{Name: "delete",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"delete"},
|
||||
APIGroups: []string{"account.kubesphere.io"},
|
||||
Resources: []string{"workspaces/organizations"},
|
||||
},
|
||||
},
|
||||
}},
|
||||
},
|
||||
{
|
||||
Name: "roles",
|
||||
Actions: []Action{
|
||||
{Name: "view"},
|
||||
{Name: "create"},
|
||||
{Name: "edit"},
|
||||
{Name: "delete"},
|
||||
{Name: "view",
|
||||
Rules: []v1.PolicyRule{
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces/roles"},
|
||||
},
|
||||
}},
|
||||
},
|
||||
},
|
||||
}
|
||||
@@ -242,56 +308,6 @@ var (
|
||||
},
|
||||
},
|
||||
},
|
||||
//{
|
||||
// Name: "projects",
|
||||
// Actions: []Action{
|
||||
// {Name: "view",
|
||||
// Rules: []v1.PolicyRule{
|
||||
// {
|
||||
// Verbs: []string{"get", "watch", "list"},
|
||||
// APIGroups: []string{""},
|
||||
// Resources: []string{"namespaces"},
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// {Name: "create",
|
||||
// Rules: []v1.PolicyRule{
|
||||
// {
|
||||
// Verbs: []string{"create"},
|
||||
// APIGroups: []string{""},
|
||||
// Resources: []string{"namespaces"},
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// {Name: "edit",
|
||||
// Rules: []v1.PolicyRule{
|
||||
// {
|
||||
// Verbs: []string{"update", "patch"},
|
||||
// APIGroups: []string{""},
|
||||
// Resources: []string{"namespaces"},
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// {Name: "delete",
|
||||
// Rules: []v1.PolicyRule{
|
||||
// {
|
||||
// Verbs: []string{"delete", "deletecollection"},
|
||||
// APIGroups: []string{""},
|
||||
// Resources: []string{"namespaces"},
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// {Name: "members",
|
||||
// Rules: []v1.PolicyRule{
|
||||
// {
|
||||
// Verbs: []string{"get", "watch", "list", "create", "delete", "patch", "update"},
|
||||
// APIGroups: []string{"rbac.authorization.k8s.io"},
|
||||
// Resources: []string{"rolebindings", "roles"},
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
// },
|
||||
//},
|
||||
{
|
||||
Name: "accounts",
|
||||
Actions: []Action{
|
||||
|
||||
@@ -20,11 +20,9 @@ type SimpleRule struct {
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Username string `json:"username"`
|
||||
//UID string `json:"uid"`
|
||||
Groups []string `json:"groups"`
|
||||
Password string `json:"password,omitempty"`
|
||||
//Extra map[string]interface{} `json:"extra"`
|
||||
Username string `json:"username"`
|
||||
Groups []string `json:"groups"`
|
||||
Password string `json:"password,omitempty"`
|
||||
AvatarUrl string `json:"avatar_url"`
|
||||
Description string `json:"description"`
|
||||
Email string `json:"email"`
|
||||
|
||||
51
pkg/models/metrics/namespaces.go
Normal file
51
pkg/models/metrics/namespaces.go
Normal file
@@ -0,0 +1,51 @@
|
||||
package metrics
|
||||
|
||||
import (
|
||||
"net/url"
|
||||
"strings"
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/client"
|
||||
)
|
||||
|
||||
func GetNamespacesWithMetrics(namespaces []*v1.Namespace) []*v1.Namespace {
|
||||
var nsNameList []string
|
||||
for i := range namespaces {
|
||||
nsNameList = append(nsNameList, namespaces[i].Name)
|
||||
}
|
||||
nsFilter := "^(" + strings.Join(nsNameList, "|") + ")$"
|
||||
var timeRelateParams = make(url.Values)
|
||||
|
||||
params := client.MonitoringRequestParams{
|
||||
NsFilter: nsFilter,
|
||||
Params: timeRelateParams,
|
||||
QueryType: client.DefaultQueryType,
|
||||
MetricsFilter: "namespace_cpu_usage|namespace_memory_usage_wo_cache|namespace_pod_count",
|
||||
}
|
||||
|
||||
rawMetrics := MonitorAllMetrics(¶ms, MetricLevelNamespace)
|
||||
|
||||
for _, result := range rawMetrics.Results {
|
||||
for _, data := range result.Data.Result {
|
||||
metricDescMap, ok := data["metric"].(map[string]interface{})
|
||||
if ok {
|
||||
if ns, exist := metricDescMap["namespace"]; exist {
|
||||
timeAndValue, ok := data["value"].([]interface{})
|
||||
if ok && len(timeAndValue) == 2 {
|
||||
for i := 0; i < len(namespaces); i++ {
|
||||
if namespaces[i].Name == ns {
|
||||
if namespaces[i].Annotations == nil {
|
||||
namespaces[i].Annotations = make(map[string]string, 0)
|
||||
}
|
||||
namespaces[i].Annotations[result.MetricName] = timeAndValue[1].(string)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return namespaces
|
||||
}
|
||||
@@ -26,6 +26,8 @@ import (
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"sort"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/client"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/models/controllers"
|
||||
@@ -54,6 +56,7 @@ func DeleteDevopsProject(username string, devops string) error {
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer result.Body.Close()
|
||||
data, err := ioutil.ReadAll(result.Body)
|
||||
if err != nil {
|
||||
return err
|
||||
@@ -64,7 +67,7 @@ func DeleteDevopsProject(username string, devops string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func CreateDevopsProject(username string, devops DevopsProject) (*DevopsProject, error) {
|
||||
func CreateDevopsProject(username string, workspace string, devops DevopsProject) (*DevopsProject, error) {
|
||||
|
||||
data, err := json.Marshal(devops)
|
||||
|
||||
@@ -81,6 +84,7 @@ func CreateDevopsProject(username string, devops DevopsProject) (*DevopsProject,
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer result.Body.Close()
|
||||
data, err = ioutil.ReadAll(result.Body)
|
||||
|
||||
if err != nil {
|
||||
@@ -99,21 +103,121 @@ func CreateDevopsProject(username string, devops DevopsProject) (*DevopsProject,
|
||||
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 ListNamespaceByUser(workspaceName string, username string) ([]*core.Namespace, error) {
|
||||
func createDefaultDevopsRoleBinding(workspace string, project DevopsProject) {
|
||||
admins := iam.GetWorkspaceUsers(workspace, "admin")
|
||||
|
||||
for _, admin := range admins {
|
||||
createDevopsRoleBinding(workspace, *project.ProjectId, admin, "maintainer")
|
||||
}
|
||||
|
||||
viewers := iam.GetWorkspaceUsers(workspace, "viewer")
|
||||
|
||||
for _, viewer := range viewers {
|
||||
createDevopsRoleBinding(workspace, *project.ProjectId, viewer, "reporter")
|
||||
}
|
||||
}
|
||||
|
||||
func deleteDevopsRoleBinding(workspace string, projectId string, user string) {
|
||||
projects := make([]string, 0)
|
||||
|
||||
if projectId != "" {
|
||||
projects = append(projects, projectId)
|
||||
} else {
|
||||
p, err := GetDevOpsProjects(workspace)
|
||||
if err != nil {
|
||||
glog.Warning("delete devops role binding failed", workspace, projectId, user)
|
||||
return
|
||||
}
|
||||
projects = append(projects, p...)
|
||||
}
|
||||
|
||||
for _, project := range projects {
|
||||
request, _ := http.NewRequest(http.MethodDelete, fmt.Sprintf("http://%s/api/v1alpha/projects/%s/members/%s", constants.DevopsAPIServer, project, user), nil)
|
||||
request.Header.Add("X-Token-Username", "admin")
|
||||
resp, err := http.DefaultClient.Do(request)
|
||||
if err != nil || resp.StatusCode > 200 {
|
||||
glog.Warning("delete devops role binding failed", workspace, project, user)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 nil, err
|
||||
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)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
clusterRoles, err := iam.GetClusterRoles(username)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
rules := make([]v1.PolicyRule, 0)
|
||||
@@ -124,13 +228,11 @@ func ListNamespaceByUser(workspaceName string, username string) ([]*core.Namespa
|
||||
|
||||
namespacesManager := v1.PolicyRule{APIGroups: []string{"kubesphere.io"}, ResourceNames: []string{workspaceName}, Verbs: []string{"get"}, Resources: []string{"workspaces/namespaces"}}
|
||||
|
||||
if iam.RulesMatchesRequired(rules, namespacesManager) {
|
||||
return namespaces, nil
|
||||
} else {
|
||||
if !iam.RulesMatchesRequired(rules, namespacesManager) {
|
||||
for i := 0; i < len(namespaces); i++ {
|
||||
roles, err := iam.GetRoles(namespaces[i].Name, username)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return 0, nil, err
|
||||
}
|
||||
rules := make([]v1.PolicyRule, 0)
|
||||
for _, role := range roles {
|
||||
@@ -143,7 +245,13 @@ func ListNamespaceByUser(workspaceName string, username string) ([]*core.Namespa
|
||||
}
|
||||
}
|
||||
|
||||
return namespaces, nil
|
||||
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) {
|
||||
@@ -202,6 +310,7 @@ func Delete(workspace *Workspace) error {
|
||||
return err
|
||||
}
|
||||
|
||||
defer result.Body.Close()
|
||||
data, err := ioutil.ReadAll(result.Body)
|
||||
|
||||
if err != nil {
|
||||
@@ -225,7 +334,7 @@ func release(workspace *Workspace) error {
|
||||
|
||||
for _, devops := range workspace.DevopsProjects {
|
||||
err := DeleteDevopsProject(workspace.Creator, devops)
|
||||
if err != nil {
|
||||
if err != nil && !strings.Contains(err.Error(), "not found") {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -270,7 +379,7 @@ func Create(workspace *Workspace) (*Workspace, error) {
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer result.Body.Close()
|
||||
data, err = ioutil.ReadAll(result.Body)
|
||||
|
||||
if err != nil {
|
||||
@@ -319,6 +428,7 @@ func Edit(workspace *Workspace) (*Workspace, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer result.Body.Close()
|
||||
data, err = ioutil.ReadAll(result.Body)
|
||||
|
||||
if err != nil {
|
||||
@@ -348,6 +458,7 @@ func Detail(name string) (*Workspace, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer result.Body.Close()
|
||||
data, err := ioutil.ReadAll(result.Body)
|
||||
|
||||
if err != nil {
|
||||
@@ -379,7 +490,7 @@ func Detail(name string) (*Workspace, error) {
|
||||
}
|
||||
|
||||
// List all workspaces for the current user
|
||||
func ListByUser(username string) ([]*Workspace, error) {
|
||||
func ListWorkspaceByUser(username string, keyword string) ([]*Workspace, error) {
|
||||
|
||||
clusterRoles, err := iam.GetClusterRoles(username)
|
||||
|
||||
@@ -395,24 +506,31 @@ func ListByUser(username string) ([]*Workspace, error) {
|
||||
|
||||
workspacesManager := v1.PolicyRule{APIGroups: []string{"kubesphere.io"}, Verbs: []string{"list", "get"}, Resources: []string{"workspaces"}}
|
||||
|
||||
var workspaces []*Workspace
|
||||
if iam.RulesMatchesRequired(rules, workspacesManager) {
|
||||
return fetch(nil)
|
||||
workspaces, err = fetch(nil)
|
||||
} else {
|
||||
workspaceNames := make([]string, 0)
|
||||
|
||||
for _, clusterRole := range clusterRoles {
|
||||
if regexp.MustCompile("^system:\\w+:(admin|operator|viewer)$").MatchString(clusterRole.Name) {
|
||||
arr := strings.Split(clusterRole.Name, ":")
|
||||
workspaceNames = append(workspaceNames, arr[1])
|
||||
if groups := regexp.MustCompile(`^system:(\w+):(admin|operator|viewer)$`).FindStringSubmatch(clusterRole.Name); len(groups) == 3 {
|
||||
if !slice.ContainsString(workspaceNames, groups[1], nil) {
|
||||
workspaceNames = append(workspaceNames, groups[1])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if len(workspaceNames) == 0 {
|
||||
return make([]*Workspace, 0), nil
|
||||
}
|
||||
|
||||
return fetch(workspaceNames)
|
||||
workspaces, err = fetch(workspaceNames)
|
||||
}
|
||||
|
||||
if keyword != "" {
|
||||
for i := 0; i < len(workspaces); i++ {
|
||||
if !strings.Contains(workspaces[i].Name, keyword) {
|
||||
workspaces = append(workspaces[:i], workspaces[i+1:]...)
|
||||
i--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return workspaces, err
|
||||
}
|
||||
|
||||
func fetch(names []string) ([]*Workspace, error) {
|
||||
@@ -420,7 +538,11 @@ func fetch(names []string) ([]*Workspace, error) {
|
||||
url := fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/groups", constants.AccountAPIServer)
|
||||
|
||||
if names != nil {
|
||||
url = url + "?path=" + strings.Join(names, ",")
|
||||
if len(names) == 0 {
|
||||
return make([]*Workspace, 0), nil
|
||||
} else {
|
||||
url = url + "?path=" + strings.Join(names, ",")
|
||||
}
|
||||
}
|
||||
|
||||
result, err := http.Get(url)
|
||||
@@ -429,6 +551,7 @@ func fetch(names []string) ([]*Workspace, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer result.Body.Close()
|
||||
data, err := ioutil.ReadAll(result.Body)
|
||||
|
||||
if err != nil {
|
||||
@@ -463,7 +586,7 @@ func fetch(names []string) ([]*Workspace, error) {
|
||||
return workspaces, nil
|
||||
}
|
||||
|
||||
func DevopsProjects(workspace string) ([]DevopsProject, error) {
|
||||
func ListDevopsProjectsByUser(username string, workspace string, keyword string, orderBy string, reverse bool, limit int, offset int) (int, []DevopsProject, error) {
|
||||
|
||||
db := client.NewSharedDBClient()
|
||||
defer db.Close()
|
||||
@@ -471,48 +594,89 @@ func DevopsProjects(workspace string) ([]DevopsProject, error) {
|
||||
var workspaceDOPBindings []WorkspaceDPBinding
|
||||
|
||||
if err := db.Where("workspace = ?", workspace).Find(&workspaceDOPBindings).Error; err != nil {
|
||||
return nil, err
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
devOpsProjects := make([]DevopsProject, 0)
|
||||
|
||||
for _, workspaceDOPBinding := range workspaceDOPBindings {
|
||||
request, _ := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s/api/v1alpha/projects/%s", constants.DevopsAPIServer, workspaceDOPBinding.DevOpsProject), nil)
|
||||
request.Header.Add("X-Token-Username", "admin")
|
||||
request, _ := http.NewRequest(http.MethodGet, fmt.Sprintf("http://%s/api/v1alpha/projects", constants.DevopsAPIServer), nil)
|
||||
request.Header.Add("X-Token-Username", username)
|
||||
|
||||
result, err := http.DefaultClient.Do(request)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
data, err := ioutil.ReadAll(result.Body)
|
||||
result, err := http.DefaultClient.Do(request)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
defer result.Body.Close()
|
||||
data, err := ioutil.ReadAll(result.Body)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if result.StatusCode == 403 || result.StatusCode == 404 {
|
||||
if err := db.Delete(&workspaceDOPBinding).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if result.StatusCode > 200 {
|
||||
return nil, ksErr.Wrap(data)
|
||||
}
|
||||
|
||||
var project DevopsProject
|
||||
|
||||
err = json.Unmarshal(data, &project)
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
devOpsProjects = append(devOpsProjects, project)
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
return devOpsProjects, nil
|
||||
//if result.StatusCode == 403 || result.StatusCode == 404 {
|
||||
// if err := db.Delete(&workspaceDOPBinding).Error; err != nil {
|
||||
// return nil, err
|
||||
// }
|
||||
// continue
|
||||
//}
|
||||
|
||||
if result.StatusCode > 200 {
|
||||
return 0, nil, ksErr.Wrap(data)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(data, &devOpsProjects)
|
||||
|
||||
if err != nil {
|
||||
return 0, nil, err
|
||||
}
|
||||
|
||||
if keyword != "" {
|
||||
for i := 0; i < len(devOpsProjects); i++ {
|
||||
if !strings.Contains(devOpsProjects[i].Name, keyword) {
|
||||
devOpsProjects = append(devOpsProjects[:i], devOpsProjects[i+1:]...)
|
||||
i--
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sort.Slice(devOpsProjects, func(i, j int) bool {
|
||||
switch orderBy {
|
||||
case "name":
|
||||
if reverse {
|
||||
return devOpsProjects[i].Name < devOpsProjects[j].Name
|
||||
} else {
|
||||
return devOpsProjects[i].Name > devOpsProjects[j].Name
|
||||
}
|
||||
default:
|
||||
if reverse {
|
||||
return devOpsProjects[i].CreateTime.After(*devOpsProjects[j].CreateTime)
|
||||
} else {
|
||||
return devOpsProjects[i].CreateTime.Before(*devOpsProjects[j].CreateTime)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
for i := 0; i < len(devOpsProjects); i++ {
|
||||
inWorkspace := false
|
||||
|
||||
for _, binding := range workspaceDOPBindings {
|
||||
if binding.DevOpsProject == *devOpsProjects[i].ProjectId {
|
||||
inWorkspace = true
|
||||
}
|
||||
}
|
||||
if !inWorkspace {
|
||||
devOpsProjects = append(devOpsProjects[:i], devOpsProjects[i+1:]...)
|
||||
i--
|
||||
}
|
||||
}
|
||||
|
||||
if len(devOpsProjects) < offset {
|
||||
return len(devOpsProjects), devOpsProjects, nil
|
||||
} else if len(devOpsProjects) < limit+offset {
|
||||
return len(devOpsProjects), devOpsProjects[offset:], nil
|
||||
} else {
|
||||
return len(devOpsProjects), devOpsProjects[offset : limit+offset], nil
|
||||
}
|
||||
}
|
||||
func convertGroupToWorkspace(db *gorm.DB, group Group) (*Workspace, error) {
|
||||
namespaces, err := Namespaces(group.Name)
|
||||
@@ -584,6 +748,19 @@ func Invite(workspaceName string, users []UserInvite) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func NamespaceExistCheck(namespaceName string) (bool, error) {
|
||||
_, err := client.NewK8sClient().CoreV1().Namespaces().Get(namespaceName, meta_v1.GetOptions{})
|
||||
|
||||
if err != nil {
|
||||
if apierrors.IsNotFound(err) {
|
||||
return false, nil
|
||||
} else {
|
||||
return false, err
|
||||
}
|
||||
}
|
||||
return true, nil
|
||||
}
|
||||
|
||||
func RemoveMembers(workspaceName string, users []string) error {
|
||||
|
||||
workspace, err := Detail(workspaceName)
|
||||
@@ -644,6 +821,7 @@ func GetWorkspaceMembers(workspace string) ([]iam.User, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
defer result.Body.Close()
|
||||
data, err := ioutil.ReadAll(result.Body)
|
||||
|
||||
if err != nil {
|
||||
@@ -673,133 +851,33 @@ func WorkspaceRoleInit(workspace *Workspace) error {
|
||||
admin.Name = fmt.Sprintf("system:%s:admin", workspace.Name)
|
||||
admin.Kind = iam.ClusterRoleKind
|
||||
admin.Rules = []v1.PolicyRule{
|
||||
// apis/kubesphere.io/v1alpha1/workspaces/sample
|
||||
// apis/kubesphere.io/v1alpha1/workspaces/sample/namespaces
|
||||
// apis/kubesphere.io/v1alpha1/workspaces/sample/devops
|
||||
// apis/kubesphere.io/v1alpha1/workspaces/sample/roles
|
||||
// apis/kubesphere.io/v1alpha1/workspaces/sample/members
|
||||
// apis/kubesphere.io/v1alpha1/workspaces/sample/members/admin
|
||||
|
||||
{
|
||||
Verbs: []string{"*"},
|
||||
APIGroups: []string{"kubesphere.io", "account.kubesphere.io"},
|
||||
ResourceNames: []string{workspace.Name},
|
||||
Resources: []string{"workspaces", "workspaces/*"},
|
||||
},
|
||||
|
||||
// post apis/kubesphere.io/v1alpha1/workspaces/sample/namespaces
|
||||
|
||||
{
|
||||
Verbs: []string{"create"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
ResourceNames: []string{workspace.Name},
|
||||
Resources: []string{"workspaces/namespaces"},
|
||||
},
|
||||
|
||||
// post apis/kubesphere.io/v1alpha1/workspaces/sample/members
|
||||
|
||||
{
|
||||
Verbs: []string{"create"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
ResourceNames: []string{workspace.Name},
|
||||
Resources: []string{"workspaces/members"},
|
||||
},
|
||||
|
||||
// post apis/kubesphere.io/v1alpha1/workspaces/sample/devops
|
||||
{
|
||||
Verbs: []string{"create"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
ResourceNames: []string{workspace.Name},
|
||||
Resources: []string{"workspaces/devops"},
|
||||
},
|
||||
// TODO have risks
|
||||
// get apis/apps/v1/namespaces/proj1/deployments/?labelSelector
|
||||
// post api/v1/namespaces/project-0vya57/limitranges
|
||||
{
|
||||
Verbs: []string{"*"},
|
||||
APIGroups: []string{"", "apps", "extensions", "batch"},
|
||||
Resources: []string{"limitranges", "deployments", "configmaps", "secrets", "jobs", "cronjobs", "persistentvolumes", "statefulsets", "daemonsets", "ingresses", "services", "pods/*", "pods", "events", "deployments/scale"},
|
||||
APIGroups: []string{"devops.kubesphere.io", "jenkins.kubesphere.io"},
|
||||
Resources: []string{"*"},
|
||||
},
|
||||
// get apis/kubesphere.io/v1alpha1/quota/namespaces/proj1
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"quota/*"},
|
||||
},
|
||||
// get api/v1/namespaces/proj1
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{""},
|
||||
Resources: []string{"namespaces", "serviceaccounts", "configmaps"},
|
||||
},
|
||||
// get api/v1/namespaces/proj1/serviceaccounts
|
||||
// get api/v1/namespaces/proj1/configmaps
|
||||
// get api/v1/namespaces/proj1/secrets
|
||||
|
||||
{
|
||||
Verbs: []string{"list"},
|
||||
APIGroups: []string{""},
|
||||
Resources: []string{"serviceaccounts", "configmaps", "secrets"},
|
||||
},
|
||||
|
||||
// get apis/kubesphere.io/v1alpha1/status/namespaces/proj1
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
ResourceNames: []string{"namespaces"},
|
||||
Resources: []string{"status/*"},
|
||||
Resources: []string{"status/*", "monitoring/*", "quota/*"},
|
||||
},
|
||||
// apis/kubesphere.io/v1alpha1/namespaces/proj1/router
|
||||
{
|
||||
Verbs: []string{"list"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"router"},
|
||||
},
|
||||
// get apis/kubesphere.io/v1alpha1/registries/proj1
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"registries"},
|
||||
},
|
||||
|
||||
// get apis/kubesphere.io/v1alpha1/monitoring/namespaces/proj1
|
||||
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
ResourceNames: []string{"namespaces"},
|
||||
Resources: []string{"monitoring/*"},
|
||||
},
|
||||
|
||||
// get apis/kubesphere.io/v1alpha1/resources/persistent-volume-claims
|
||||
// get apis/kubesphere.io/v1alpha1/resources/deployments
|
||||
// get apis/kubesphere.io/v1alpha1/resources/statefulsets
|
||||
// get apis/kubesphere.io/v1alpha1/resources/daemonsets
|
||||
// get apis/kubesphere.io/v1alpha1/resources/jobs
|
||||
// get apis/kubesphere.io/v1alpha1/resources/cronjobs
|
||||
// get apis/kubesphere.io/v1alpha1/resources/persistent-volume-claims
|
||||
// get apis/kubesphere.io/v1alpha1/resources/services
|
||||
// get apis/kubesphere.io/v1alpha1/resources/ingresses
|
||||
// get apis/kubesphere.io/v1alpha1/resources/secrets
|
||||
// get apis/kubesphere.io/v1alpha1/resources/configmaps
|
||||
// get apis/kubesphere.io/v1alpha1/resources/roles
|
||||
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"resources"},
|
||||
},
|
||||
|
||||
// apis/account.kubesphere.io/v1alpha1/users
|
||||
// apis/account.kubesphere.io/v1alpha1/namespaces/proj1/users
|
||||
{
|
||||
Verbs: []string{"list"},
|
||||
APIGroups: []string{"account.kubesphere.io"},
|
||||
Resources: []string{"users"},
|
||||
},
|
||||
|
||||
// apis/kubesphere.io/v1alpha1/monitoring/workspaces/sample?metrics_filter=
|
||||
// apis/kubesphere.io/v1alpha1/monitoring/workspaces/sample/pods?step=30m
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
@@ -820,15 +898,42 @@ func WorkspaceRoleInit(workspace *Workspace) error {
|
||||
Resources: []string{"workspaces"},
|
||||
ResourceNames: []string{workspace.Name},
|
||||
}, {
|
||||
Verbs: []string{"create", "get"},
|
||||
Verbs: []string{"create"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces/namespaces", "workspaces/devops"},
|
||||
ResourceNames: []string{workspace.Name},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"delete"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"workspaces/namespaces", "workspaces/devops"},
|
||||
ResourceNames: []string{workspace.Name},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
ResourceNames: []string{"namespaces"},
|
||||
Resources: []string{"quota/*", "status/*", "monitoring/*"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"*"},
|
||||
APIGroups: []string{"devops.kubesphere.io"},
|
||||
Resources: []string{"*"},
|
||||
}, {
|
||||
Verbs: []string{"*"},
|
||||
APIGroups: []string{"jenkins.kubesphere.io"},
|
||||
Resources: []string{"*"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"registries"},
|
||||
Resources: []string{"resources"},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
ResourceNames: []string{workspace.Name},
|
||||
Resources: []string{"workspaces/members"},
|
||||
},
|
||||
}
|
||||
|
||||
@@ -838,139 +943,38 @@ func WorkspaceRoleInit(workspace *Workspace) error {
|
||||
viewer.Name = fmt.Sprintf("system:%s:viewer", workspace.Name)
|
||||
viewer.Kind = iam.ClusterRoleKind
|
||||
viewer.Rules = []v1.PolicyRule{
|
||||
// apis/kubesphere.io/v1alpha1/workspaces/sample
|
||||
// apis/kubesphere.io/v1alpha1/workspaces/sample/namespaces
|
||||
// apis/kubesphere.io/v1alpha1/workspaces/sample/devops
|
||||
// apis/kubesphere.io/v1alpha1/workspaces/sample/roles
|
||||
// apis/kubesphere.io/v1alpha1/workspaces/sample/members
|
||||
// apis/kubesphere.io/v1alpha1/workspaces/sample/members/admin
|
||||
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"kubesphere.io", "account.kubesphere.io"},
|
||||
ResourceNames: []string{workspace.Name},
|
||||
Resources: []string{"workspaces", "workspaces/*"},
|
||||
},
|
||||
|
||||
// post apis/kubesphere.io/v1alpha1/workspaces/sample/namespaces
|
||||
|
||||
//{
|
||||
// Verbs: []string{"create"},
|
||||
// APIGroups: []string{"kubesphere.io"},
|
||||
// ResourceNames: []string{workspace.Name},
|
||||
// Resources: []string{"workspaces/namespaces"},
|
||||
//},
|
||||
|
||||
// post apis/kubesphere.io/v1alpha1/workspaces/sample/members
|
||||
|
||||
//{
|
||||
// Verbs: []string{"create"},
|
||||
// APIGroups: []string{"kubesphere.io"},
|
||||
// ResourceNames: []string{workspace.Name},
|
||||
// Resources: []string{"workspaces/members"},
|
||||
//},
|
||||
|
||||
// post apis/kubesphere.io/v1alpha1/workspaces/sample/devops
|
||||
//{
|
||||
// Verbs: []string{"create"},
|
||||
// APIGroups: []string{"kubesphere.io"},
|
||||
// ResourceNames: []string{workspace.Name},
|
||||
// Resources: []string{"workspaces/devops"},
|
||||
//},
|
||||
// TODO have risks
|
||||
// get apis/apps/v1/namespaces/proj1/deployments/?labelSelector
|
||||
// post api/v1/namespaces/project-0vya57/limitranges
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"", "apps", "extensions", "batch"},
|
||||
Resources: []string{"limitranges", "deployments", "configmaps", "secrets", "jobs", "cronjobs", "persistentvolumes", "statefulsets", "daemonsets", "ingresses", "services", "pods/*", "pods", "events", "deployments/scale"},
|
||||
},
|
||||
// get apis/kubesphere.io/v1alpha1/quota/namespaces/proj1
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"quota/*"},
|
||||
},
|
||||
// get api/v1/namespaces/proj1
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{""},
|
||||
Resources: []string{"namespaces", "serviceaccounts", "configmaps"},
|
||||
},
|
||||
// get api/v1/namespaces/proj1/serviceaccounts
|
||||
// get api/v1/namespaces/proj1/configmaps
|
||||
// get api/v1/namespaces/proj1/secrets
|
||||
|
||||
{
|
||||
Verbs: []string{"list"},
|
||||
APIGroups: []string{""},
|
||||
Resources: []string{"serviceaccounts", "configmaps", "secrets"},
|
||||
},
|
||||
|
||||
// get apis/kubesphere.io/v1alpha1/status/namespaces/proj1
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
ResourceNames: []string{"namespaces"},
|
||||
Resources: []string{"status/*"},
|
||||
Resources: []string{"quota/*", "status/*", "monitoring/*"},
|
||||
},
|
||||
// apis/kubesphere.io/v1alpha1/namespaces/proj1/router
|
||||
{
|
||||
Verbs: []string{"list"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"router"},
|
||||
},
|
||||
// get apis/kubesphere.io/v1alpha1/registries/proj1
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"registries"},
|
||||
},
|
||||
|
||||
// get apis/kubesphere.io/v1alpha1/monitoring/namespaces/proj1
|
||||
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
ResourceNames: []string{"namespaces"},
|
||||
Resources: []string{"monitoring/*"},
|
||||
},
|
||||
|
||||
// get apis/kubesphere.io/v1alpha1/resources/persistent-volume-claims
|
||||
// get apis/kubesphere.io/v1alpha1/resources/deployments
|
||||
// get apis/kubesphere.io/v1alpha1/resources/statefulsets
|
||||
// get apis/kubesphere.io/v1alpha1/resources/daemonsets
|
||||
// get apis/kubesphere.io/v1alpha1/resources/jobs
|
||||
// get apis/kubesphere.io/v1alpha1/resources/cronjobs
|
||||
// get apis/kubesphere.io/v1alpha1/resources/persistent-volume-claims
|
||||
// get apis/kubesphere.io/v1alpha1/resources/services
|
||||
// get apis/kubesphere.io/v1alpha1/resources/ingresses
|
||||
// get apis/kubesphere.io/v1alpha1/resources/secrets
|
||||
// get apis/kubesphere.io/v1alpha1/resources/configmaps
|
||||
// get apis/kubesphere.io/v1alpha1/resources/roles
|
||||
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
Resources: []string{"resources"},
|
||||
},
|
||||
|
||||
// apis/account.kubesphere.io/v1alpha1/users
|
||||
// apis/account.kubesphere.io/v1alpha1/namespaces/proj1/users
|
||||
{
|
||||
Verbs: []string{"list"},
|
||||
APIGroups: []string{"account.kubesphere.io"},
|
||||
Resources: []string{"users"},
|
||||
},
|
||||
|
||||
// apis/kubesphere.io/v1alpha1/monitoring/workspaces/sample?metrics_filter=
|
||||
// apis/kubesphere.io/v1alpha1/monitoring/workspaces/sample/pods?step=30m
|
||||
{
|
||||
Verbs: []string{"get"},
|
||||
APIGroups: []string{"kubesphere.io"},
|
||||
ResourceNames: []string{"workspaces"},
|
||||
Resources: []string{"monitoring/" + workspace.Name},
|
||||
},
|
||||
{
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"devops.kubesphere.io"},
|
||||
Resources: []string{"*"},
|
||||
}, {
|
||||
Verbs: []string{"get", "list"},
|
||||
APIGroups: []string{"jenkins.kubesphere.io"},
|
||||
Resources: []string{"*"},
|
||||
},
|
||||
}
|
||||
|
||||
viewer.Labels = map[string]string{"creator": "system"}
|
||||
@@ -1141,8 +1145,8 @@ func CreateWorkspaceRoleBinding(workspace *Workspace, username string, role stri
|
||||
} else {
|
||||
modify = true
|
||||
roleBinding.Subjects = append(roleBinding.Subjects[:i], roleBinding.Subjects[i+1:]...)
|
||||
if err != nil {
|
||||
return err
|
||||
if roleName == "admin" || roleName == "viewer" {
|
||||
go deleteDevopsRoleBinding(workspace.Name, "", username)
|
||||
}
|
||||
break
|
||||
}
|
||||
@@ -1152,6 +1156,11 @@ func CreateWorkspaceRoleBinding(workspace *Workspace, username string, role stri
|
||||
if roleName == role {
|
||||
modify = true
|
||||
roleBinding.Subjects = append(roleBinding.Subjects, v1.Subject{Kind: v1.UserKind, Name: username})
|
||||
if roleName == "admin" {
|
||||
go createDevopsRoleBinding(workspace.Name, "", username, "maintainer")
|
||||
} else if roleName == "viewer" {
|
||||
go createDevopsRoleBinding(workspace.Name, "", username, "reporter")
|
||||
}
|
||||
}
|
||||
|
||||
if !modify {
|
||||
@@ -1167,14 +1176,14 @@ func CreateWorkspaceRoleBinding(workspace *Workspace, username string, role stri
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetDevOpsProjects(name string) ([]string, error) {
|
||||
func GetDevOpsProjects(workspaceName string) ([]string, error) {
|
||||
|
||||
db := client.NewSharedDBClient()
|
||||
defer db.Close()
|
||||
|
||||
var workspaceDOPBindings []WorkspaceDPBinding
|
||||
|
||||
if err := db.Where("workspace = ?", name).Find(&workspaceDOPBindings).Error; err != nil {
|
||||
if err := db.Where("workspace = ?", workspaceName).Find(&workspaceDOPBindings).Error; err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
@@ -1221,6 +1230,7 @@ func CountAll() (int, error) {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
defer result.Body.Close()
|
||||
data, err := ioutil.ReadAll(result.Body)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
@@ -1270,7 +1280,7 @@ func GetAllDevOpsProjectsNums() (int, error) {
|
||||
defer db.Close()
|
||||
|
||||
var count int
|
||||
if err := db.Find(&WorkspaceDPBinding{}).Count(&count).Error; err != nil {
|
||||
if err := db.Model(&WorkspaceDPBinding{}).Count(&count).Error; err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return count, nil
|
||||
@@ -1283,6 +1293,7 @@ func GetAllAccountNums() (int, error) {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
defer result.Body.Close()
|
||||
data, err := ioutil.ReadAll(result.Body)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
|
||||
Reference in New Issue
Block a user