Merge pull request #199 from wansir/master

refactor workspace api
This commit is contained in:
不羁
2018-11-06 10:49:57 +08:00
committed by GitHub
20 changed files with 1651 additions and 866 deletions

View File

@@ -63,7 +63,7 @@ func userRolesHandler(req *restful.Request, resp *restful.Response) {
username := req.PathParameter("username")
roles, err := iam.GetRoles(username)
roles, err := iam.GetRoles("", username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
@@ -206,7 +206,7 @@ func clusterRoleRulesHandler(req *restful.Request, resp *restful.Response) {
var rules []iam.Rule
if name == "" {
rules = iam.ClusterRoleRuleGroup
rules = iam.ClusterRoleRuleMapping
} else {
var err error
rules, err = iam.GetClusterRoleRules(name)
@@ -227,7 +227,7 @@ func roleRulesHandler(req *restful.Request, resp *restful.Response) {
var rules []iam.Rule
if namespace == "" && name == "" {
rules = iam.RoleRuleGroup
rules = iam.RoleRuleMapping
} else {
var err error
rules, err = iam.GetRoleRules(namespace, name)

37
pkg/apis/v1alpha/monitoring/monitor_handler.go Normal file → Executable file
View File

@@ -58,6 +58,18 @@ func (u MonitorResource) monitorWorkload(request *restful.Request, response *res
}
}
// merge multiple metric: all-devops, all-roles, all-projects...this api is designed for admin
func (u MonitorResource) monitorWorkspaceUserInfo(request *restful.Request, response *restful.Response) {
res := metrics.MonitorWorkspaceUserInfo(request)
response.WriteAsJson(res)
}
// merge multiple metric: devops, roles, projects...
func (u MonitorResource) monitorWorkspaceResourceLevelMetrics(request *restful.Request, response *restful.Response) {
res := metrics.MonitorWorkspaceResourceLevelMetrics(request)
response.WriteAsJson(res)
}
func (u MonitorResource) monitorWorkspacePodLevelMetrics(request *restful.Request, response *restful.Response) {
res := metrics.MonitorAllMetrics(request)
response.WriteAsJson(res)
@@ -223,4 +235,29 @@ func Register(ws *restful.WebService, subPath string) {
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/workspaces/{workspace_name}/pods").To(u.monitorWorkspacePodLevelMetrics).
Filter(route.RouteLogging).
Doc("monitor specific workspace level metrics").
Param(ws.PathParameter("workspace_name", "workspace name").DataType("string").Required(true)).
Param(ws.QueryParameter("namespaces_filter", "namespaces filter").DataType("string").Required(false).DefaultValue("k.*")).
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").DataType("string").Required(false).DefaultValue("tenant_memory_utilisation_wo_cache")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/workspaces/{workspace_name}").To(u.monitorWorkspaceResourceLevelMetrics).
Filter(route.RouteLogging).
Doc("monitor specific workspace level metrics").
Param(ws.PathParameter("workspace_name", "workspace name").DataType("string").Required(true)).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET(subPath+"/workspaces").To(u.monitorWorkspaceUserInfo).
Filter(route.RouteLogging).
Doc("monitor specific workspace level metrics").
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
}

View File

@@ -16,18 +16,22 @@ import (
"kubesphere.io/kubesphere/pkg/models/workspaces"
)
const UserNameHeader = "X-Token-Username"
func Register(ws *restful.WebService, subPath string) {
ws.Route(ws.GET(subPath).To(WorkspaceListHandler))
ws.Route(ws.GET(subPath).To(UserWorkspaceListHandler))
ws.Route(ws.POST(subPath).To(WorkspaceCreateHandler))
ws.Route(ws.DELETE(subPath + "/{name}").To(DeleteWorkspaceHandler))
ws.Route(ws.GET(subPath + "/{name}").To(WorkspaceDetailHandler))
ws.Route(ws.PUT(subPath + "/{name}").To(WorkspaceEditHandler))
ws.Route(ws.GET(subPath + "/{name}/namespaces").To(NamespaceHandler))
ws.Route(ws.GET(subPath + "/{workspace}/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}/devops").To(DevOpsProjectHandler))
ws.Route(ws.POST(subPath + "/{name}/devops").To(DevOpsProjectCreateHandler))
ws.Route(ws.DELETE(subPath + "/{name}/devops/{id}").To(DevOpsProjectDeleteHandler))
ws.Route(ws.GET(subPath + "/{name}/members").To(MembersHandler))
ws.Route(ws.GET(subPath + "/{name}/members/{member}").To(MemberHandler))
ws.Route(ws.GET(subPath + "/{name}/roles").To(RolesHandler))
@@ -107,6 +111,7 @@ func MemberHandler(req *restful.Request, resp *restful.Response) {
}
namespaces, err := workspaces.Namespaces(workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
@@ -169,14 +174,9 @@ func MembersRemoveHandler(req *restful.Request, resp *restful.Response) {
func NamespaceDeleteHandler(req *restful.Request, resp *restful.Response) {
namespace := req.PathParameter("namespace")
workspace := req.PathParameter("name")
force := req.QueryParameter("force")
err := workspaces.UnBindNamespace(workspace, namespace)
//force := req.QueryParameter("force")
if err != nil && force != "true" {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
err = workspaces.DeleteNamespace(namespace)
err := workspaces.DeleteNamespace(workspace, namespace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
@@ -190,7 +190,7 @@ func DevOpsProjectDeleteHandler(req *restful.Request, resp *restful.Response) {
devops := req.PathParameter("id")
workspace := req.PathParameter("name")
force := req.QueryParameter("force")
username := req.HeaderParameter("X-Token-Username")
username := req.HeaderParameter(UserNameHeader)
err := workspaces.UnBindDevopsProject(workspace, devops)
@@ -212,7 +212,7 @@ func DevOpsProjectDeleteHandler(req *restful.Request, resp *restful.Response) {
func DevOpsProjectCreateHandler(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("name")
username := req.HeaderParameter("X-Token-Username")
username := req.HeaderParameter(UserNameHeader)
var devops workspaces.DevopsProject
@@ -248,7 +248,7 @@ func DevOpsProjectCreateHandler(req *restful.Request, resp *restful.Response) {
func NamespaceCreateHandler(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("name")
username := req.HeaderParameter("X-Token-Username")
username := req.HeaderParameter(UserNameHeader)
namespace := &v1.Namespace{}
@@ -266,6 +266,12 @@ func NamespaceCreateHandler(req *restful.Request, resp *restful.Response) {
namespace.Annotations["creator"] = username
namespace.Annotations["workspace"] = workspace
if namespace.Labels == nil {
namespace.Labels = make(map[string]string, 0)
}
namespace.Labels["kubesphere.io/workspace"] = workspace
namespace, err = workspaces.CreateNamespace(namespace)
if err != nil {
@@ -273,14 +279,6 @@ func NamespaceCreateHandler(req *restful.Request, resp *restful.Response) {
return
}
err = workspaces.BindingNamespace(workspace, namespace.Name)
if err != nil {
workspaces.DeleteNamespace(namespace.Name)
resp.WriteHeaderAndEntity(http.StatusBadRequest, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(namespace)
}
@@ -298,22 +296,9 @@ func DevOpsProjectHandler(req *restful.Request, resp *restful.Response) {
resp.WriteEntity(devOpsProjects)
}
func NamespaceHandler(req *restful.Request, resp *restful.Response) {
workspace := req.PathParameter("name")
namespaces, err := workspaces.Namespaces(workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(namespaces)
}
func WorkspaceCreateHandler(req *restful.Request, resp *restful.Response) {
var workspace workspaces.Workspace
username := req.HeaderParameter("X-Token-Username")
username := req.HeaderParameter(UserNameHeader)
err := req.ReadEntity(&workspace)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusBadRequest, constants.MessageResponse{Message: err.Error()})
@@ -327,7 +312,11 @@ func WorkspaceCreateHandler(req *restful.Request, resp *restful.Response) {
workspace.Path = workspace.Name
workspace.Members = nil
workspace.Creator = username
if workspace.Admin != "" {
workspace.Creator = workspace.Admin
} else {
workspace.Creator = username
}
created, err := workspaces.Create(&workspace)
@@ -411,15 +400,12 @@ func WorkspaceDetailHandler(req *restful.Request, resp *restful.Response) {
resp.WriteEntity(workspace)
}
func WorkspaceListHandler(req *restful.Request, resp *restful.Response) {
// List all workspaces for the current user
func UserWorkspaceListHandler(req *restful.Request, resp *restful.Response) {
var names []string
username := req.HeaderParameter(UserNameHeader)
if query := req.QueryParameter("name"); query != "" {
names = strings.Split(query, ",")
}
list, err := workspaces.List(names)
list, err := workspaces.ListByUser(username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
@@ -428,3 +414,18 @@ func WorkspaceListHandler(req *restful.Request, resp *restful.Response) {
resp.WriteEntity(list)
}
func UserNamespaceListHandler(req *restful.Request, resp *restful.Response) {
username := req.HeaderParameter(UserNameHeader)
workspaceName := req.PathParameter("workspace")
namespaces, err := workspaces.ListNamespaceByUser(workspaceName, username)
if err != nil {
resp.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()})
return
}
resp.WriteEntity(namespaces)
}

View File

@@ -0,0 +1,62 @@
/*
Copyright 2018 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 controllers
import (
"time"
"github.com/golang/glog"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
)
func (ctl *ClusterRoleBindingCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *ClusterRoleBindingCtl) sync(stopChan chan struct{}) {
ctl.initListerAndInformer()
ctl.informer.Run(stopChan)
}
func (ctl *ClusterRoleBindingCtl) total() int {
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Errorf("count %s falied, reason:%s", err, ctl.Name())
return 0
}
return len(list)
}
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()
}
func (ctl *ClusterRoleBindingCtl) CountWithConditions(conditions string) int {
return 0
}
func (ctl *ClusterRoleBindingCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
return 0, nil, errors.New("not implement")
}
func (ctl *ClusterRoleBindingCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -74,7 +74,9 @@ func (ctl *ClusterRoleCtl) sync(stopChan chan struct{}) {
for _, item := range list {
obj := ctl.generateObject(*item)
if obj != nil {
db.Create(obj)
if err := db.Create(obj).Error; err != nil {
glog.Error("cluster roles sync error", err)
}
}
}
@@ -111,14 +113,18 @@ func (ctl *ClusterRoleCtl) initListerAndInformer() {
object := obj.(*v1.ClusterRole)
mysqlObject := ctl.generateObject(*object)
if mysqlObject != nil {
db.Create(mysqlObject)
if err := db.Create(mysqlObject).Error; err != nil {
glog.Error("cluster roles sync error", err)
}
}
},
UpdateFunc: func(old, new interface{}) {
object := new.(*v1.ClusterRole)
mysqlObject := ctl.generateObject(*object)
if mysqlObject != nil {
db.Save(mysqlObject)
if err := db.Save(mysqlObject).Error; err != nil {
glog.Error("cluster roles update error", err)
}
}
},
DeleteFunc: func(obj interface{}) {

View File

@@ -147,9 +147,9 @@ func (ctl *NamespaceCtl) createDefaultRoleBinding(ns, user string) error {
}
func (ctl *NamespaceCtl) createDefaultRole(ns string) error {
adminRole := &rbac.Role{ObjectMeta: metaV1.ObjectMeta{Name: admin, Namespace: ns}, Rules: adminRules}
editorRole := &rbac.Role{ObjectMeta: metaV1.ObjectMeta{Name: editor, Namespace: ns}, Rules: editorRules}
viewerRole := &rbac.Role{ObjectMeta: metaV1.ObjectMeta{Name: viewer, Namespace: ns}, Rules: viewerRules}
adminRole := &rbac.Role{ObjectMeta: metaV1.ObjectMeta{Name: admin, Namespace: ns, Annotations: map[string]string{"creator": "system"}}, Rules: adminRules}
editorRole := &rbac.Role{ObjectMeta: metaV1.ObjectMeta{Name: editor, Namespace: ns, Annotations: map[string]string{"creator": "system"}}, Rules: editorRules}
viewerRole := &rbac.Role{ObjectMeta: metaV1.ObjectMeta{Name: viewer, Namespace: ns, Annotations: map[string]string{"creator": "system"}}, Rules: viewerRules}
_, err := ctl.K8sClient.RbacV1().Roles(ns).Create(adminRole)

View File

@@ -0,0 +1,64 @@
/*
Copyright 2018 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 controllers
import (
"time"
"github.com/golang/glog"
"github.com/pkg/errors"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/informers"
)
func (ctl *RoleBindingCtl) Name() string {
return ctl.CommonAttribute.Name
}
func (ctl *RoleBindingCtl) sync(stopChan chan struct{}) {
ctl.initListerAndInformer()
ctl.informer.Run(stopChan)
}
func (ctl *RoleBindingCtl) total() int {
list, err := ctl.lister.List(labels.Everything())
if err != nil {
glog.Errorf("count %s falied, reason:%s", err, ctl.Name())
return 0
}
return len(list)
}
func (ctl *RoleBindingCtl) initListerAndInformer() {
informerFactory := informers.NewSharedInformerFactory(ctl.K8sClient, time.Second*resyncCircle)
ctl.lister = informerFactory.Rbac().V1().RoleBindings().Lister()
ctl.informer = informerFactory.Rbac().V1().RoleBindings().Informer()
}
func (ctl *RoleBindingCtl) CountWithConditions(conditions string) int {
return 0
}
func (ctl *RoleBindingCtl) ListWithConditions(conditions string, paging *Paging, order string) (int, interface{}, error) {
return 0, nil, errors.New("not implement")
}
func (ctl *RoleBindingCtl) Lister() interface{} {
return ctl.lister
}

View File

@@ -37,7 +37,7 @@ type resourceControllers struct {
var ResourceControllers resourceControllers
func (rec *resourceControllers) runContoller(name string, stopChan chan struct{}, wg *sync.WaitGroup) {
func (rec *resourceControllers) runController(name string, stopChan chan struct{}, wg *sync.WaitGroup) {
var ctl Controller
attr := CommonAttribute{DB: client.NewDBClient(), K8sClient: rec.k8sClient, stopChan: stopChan,
aliveChan: make(chan struct{}), Name: name}
@@ -78,6 +78,10 @@ func (rec *resourceControllers) runContoller(name string, stopChan chan struct{}
ctl = &ConfigMapCtl{CommonAttribute: attr}
case Secrets:
ctl = &SecretCtl{CommonAttribute: attr}
case ClusterRoleBindings:
ctl = &ClusterRoleBindingCtl{CommonAttribute: attr}
case RoleBindings:
ctl = &RoleBindingCtl{CommonAttribute: attr}
default:
return
}
@@ -116,9 +120,9 @@ func Run(stopChan chan struct{}, wg *sync.WaitGroup) {
ResourceControllers = resourceControllers{k8sClient: k8sClient, Controllers: make(map[string]Controller)}
for _, item := range []string{Deployments, Statefulsets, Daemonsets, PersistentVolumeClaim, Pods, Services,
Ingresses, Roles, ClusterRoles, Namespaces, StorageClasses, Jobs, Cronjobs, Nodes, Replicasets,
Ingresses, Roles, RoleBindings, ClusterRoles, ClusterRoleBindings, Namespaces, StorageClasses, Jobs, Cronjobs, Nodes, Replicasets,
ControllerRevisions, ConfigMaps, Secrets} {
ResourceControllers.runContoller(item, stopChan, wg)
ResourceControllers.runController(item, stopChan, wg)
}
go dbHealthCheck(client.NewDBClient())
@@ -131,7 +135,7 @@ func Run(stopChan chan struct{}, wg *sync.WaitGroup) {
case _, isClose := <-controller.chanAlive():
if !isClose {
glog.Errorf("controller %s have stopped, restart it", ctlName)
ResourceControllers.runContoller(ctlName, stopChan, wg)
ResourceControllers.runController(ctlName, stopChan, wg)
}
default:
time.Sleep(3 * time.Second)

View File

@@ -59,7 +59,9 @@ const (
Ingresses = "ingresses"
PersistentVolumeClaim = "persistent-volume-claims"
Roles = "roles"
RoleBindings = "role-bindings"
ClusterRoles = "cluster-roles"
ClusterRoleBindings = "cluster-role-bindings"
Services = "services"
StorageClasses = "storage-classes"
Applications = "applications"
@@ -464,6 +466,17 @@ type ClusterRoleCtl struct {
CommonAttribute
}
type ClusterRoleBindingCtl struct {
lister rbacV1.ClusterRoleBindingLister
informer cache.SharedIndexInformer
CommonAttribute
}
type RoleBindingCtl struct {
lister rbacV1.RoleBindingLister
informer cache.SharedIndexInformer
CommonAttribute
}
type JobCtl struct {
lister batchv1.JobLister
informer cache.SharedIndexInformer

View File

@@ -4,7 +4,6 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"net/http"
"strings"
@@ -12,10 +11,12 @@ import (
"k8s.io/api/rbac/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kubernetes/pkg/util/slice"
"k8s.io/apimachinery/pkg/labels"
v12 "k8s.io/client-go/listers/rbac/v1"
"kubesphere.io/kubesphere/pkg/client"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/models/controllers"
ksErr "kubesphere.io/kubesphere/pkg/util/errors"
)
@@ -133,7 +134,7 @@ func WorkspaceRoleRules(workspace string, roleName string) (*v1.ClusterRole, []R
rule := Rule{Name: WorkspaceRoleRuleMapping[i].Name}
rule.Actions = make([]Action, 0)
for j := 0; j < len(WorkspaceRoleRuleMapping[i].Actions); j++ {
if actionValidate(role.Rules, WorkspaceRoleRuleMapping[i].Actions[j]) {
if rulesMatchesAction(role.Rules, WorkspaceRoleRuleMapping[i].Actions[j]) {
rule.Actions = append(rule.Actions, WorkspaceRoleRuleMapping[i].Actions[j])
}
}
@@ -161,18 +162,22 @@ func GetUserNamespaces(username string, requiredRule v1.PolicyRule) (allNamespac
}
if requiredRule.Size() == 0 {
if ruleValidate(clusterRules, v1.PolicyRule{
Verbs: []string{"get", "list"},
APIGroups: []string{""},
Resources: []string{"namespaces"},
if RulesMatchesRequired(clusterRules, v1.PolicyRule{
Verbs: []string{"get"},
APIGroups: []string{"kubesphere.io"},
Resources: []string{"workspaces/namespaces"},
}) {
return true, nil, nil
}
} else if ruleValidate(clusterRules, requiredRule) {
return true, nil, nil
} else {
if RulesMatchesRequired(clusterRules, requiredRule) {
return true, nil, nil
}
}
roles, err := GetRoles(username)
roles, err := GetRoles("", username)
if err != nil {
return false, nil, err
@@ -192,7 +197,7 @@ func GetUserNamespaces(username string, requiredRule v1.PolicyRule) (allNamespac
namespaces = make([]string, 0)
for namespace, rules := range rulesMapping {
if requiredRule.Size() == 0 || ruleValidate(rules, requiredRule) {
if requiredRule.Size() == 0 || RulesMatchesRequired(rules, requiredRule) {
namespaces = append(namespaces, namespace)
}
}
@@ -309,22 +314,24 @@ func GetClusterRole(name string) (*v1.ClusterRole, error) {
return role, nil
}
func GetRoles(username string) ([]v1.Role, error) {
k8s := client.NewK8sClient()
func GetRoles(namespace string, username string) ([]v1.Role, error) {
roleBindingLister := controllers.ResourceControllers.Controllers[controllers.RoleBindings].Lister().(v12.RoleBindingLister)
roleLister := controllers.ResourceControllers.Controllers[controllers.Roles].Lister().(v12.RoleLister)
clusterRoleLister := controllers.ResourceControllers.Controllers[controllers.ClusterRoles].Lister().(v12.ClusterRoleLister)
roleBindings, err := k8s.RbacV1().RoleBindings("").List(meta_v1.ListOptions{})
roleBindings, err := roleBindingLister.RoleBindings(namespace).List(labels.Everything())
if err != nil {
return nil, err
}
roles := make([]v1.Role, 0)
for _, roleBinding := range roleBindings.Items {
for _, roleBinding := range roleBindings {
for _, subject := range roleBinding.Subjects {
if subject.Kind == v1.UserKind && subject.Name == username {
if roleBinding.RoleRef.Kind == ClusterRoleKind {
clusterRole, err := k8s.RbacV1().ClusterRoles().Get(roleBinding.RoleRef.Name, meta_v1.GetOptions{})
clusterRole, err := clusterRoleLister.Get(roleBinding.RoleRef.Name)
if err == nil {
var role = v1.Role{TypeMeta: (*clusterRole).TypeMeta, ObjectMeta: (*clusterRole).ObjectMeta, Rules: (*clusterRole).Rules}
role.Namespace = roleBinding.Namespace
@@ -339,7 +346,7 @@ func GetRoles(username string) ([]v1.Role, error) {
} else {
if subject.Kind == v1.UserKind && subject.Name == username {
rule, err := k8s.RbacV1().Roles(roleBinding.Namespace).Get(roleBinding.RoleRef.Name, meta_v1.GetOptions{})
rule, err := roleLister.Roles(roleBinding.Namespace).Get(roleBinding.RoleRef.Name)
if err == nil {
roles = append(roles, *rule)
break
@@ -361,10 +368,12 @@ func GetRoles(username string) ([]v1.Role, error) {
return roles, nil
}
// Get cluster roles by username
func GetClusterRoles(username string) ([]v1.ClusterRole, error) {
k8s := client.NewK8sClient()
clusterRoleBindings, err := k8s.RbacV1().ClusterRoleBindings().List(meta_v1.ListOptions{})
//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())
if err != nil {
return nil, err
@@ -372,27 +381,24 @@ func GetClusterRoles(username string) ([]v1.ClusterRole, error) {
roles := make([]v1.ClusterRole, 0)
for _, roleBinding := range clusterRoleBindings.Items {
for _, roleBinding := range clusterRoleBindings {
for _, subject := range roleBinding.Subjects {
if subject.Kind == v1.UserKind && subject.Name == username {
if roleBinding.RoleRef.Kind == ClusterRoleKind {
role, err := k8s.RbacV1().ClusterRoles().Get(roleBinding.RoleRef.Name, meta_v1.GetOptions{})
role, err := clusterRoleLister.Get(roleBinding.RoleRef.Name)
if err == nil {
if role.Annotations == nil {
role.Annotations = make(map[string]string, 0)
}
role.Annotations["rbac.authorization.k8s.io/clusterrolebinding"] = roleBinding.Name
if roleBinding.Annotations != nil &&
roleBinding.Annotations["rbac.authorization.k8s.io/clusterrole"] == roleBinding.RoleRef.Name {
role.Annotations["rbac.authorization.k8s.io/clusterrole"] = "true"
}
roles = append(roles, *role)
break
} else if apierrors.IsNotFound(err) {
log.Println(err)
glog.Warning(err)
break
} else {
return nil, err
@@ -405,80 +411,80 @@ func GetClusterRoles(username string) ([]v1.ClusterRole, error) {
return roles, nil
}
func ruleValidate(rules []v1.PolicyRule, rule v1.PolicyRule) bool {
//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
//}
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 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)
userRoles, err := GetRoles(username)
userRoles, err := GetRoles("", username)
if err != nil {
return nil, err
@@ -508,12 +514,12 @@ func GetUserRules(username string) (map[string][]Rule, error) {
func convertToRules(policyRules []v1.PolicyRule) []Rule {
rules := make([]Rule, 0)
for i := 0; i < (len(RoleRuleGroup)); i++ {
rule := Rule{Name: RoleRuleGroup[i].Name}
for i := 0; i < (len(RoleRuleMapping)); i++ {
rule := Rule{Name: RoleRuleMapping[i].Name}
rule.Actions = make([]Action, 0)
for j := 0; j < (len(RoleRuleGroup[i].Actions)); j++ {
if actionValidate(policyRules, RoleRuleGroup[i].Actions[j]) {
rule.Actions = append(rule.Actions, RoleRuleGroup[i].Actions[j])
for j := 0; j < (len(RoleRuleMapping[i].Actions)); j++ {
if rulesMatchesAction(policyRules, RoleRuleMapping[i].Actions[j]) {
rule.Actions = append(rule.Actions, RoleRuleMapping[i].Actions[j])
}
}
@@ -541,12 +547,12 @@ func GetUserClusterRules(username string) ([]Rule, error) {
clusterRules = append(clusterRules, role.Rules...)
}
for i := 0; i < (len(ClusterRoleRuleGroup)); i++ {
rule := Rule{Name: ClusterRoleRuleGroup[i].Name}
for i := 0; i < (len(ClusterRoleRuleMapping)); i++ {
rule := Rule{Name: ClusterRoleRuleMapping[i].Name}
rule.Actions = make([]Action, 0)
for j := 0; j < (len(ClusterRoleRuleGroup[i].Actions)); j++ {
if actionValidate(clusterRules, ClusterRoleRuleGroup[i].Actions[j]) {
rule.Actions = append(rule.Actions, ClusterRoleRuleGroup[i].Actions[j])
for j := 0; j < (len(ClusterRoleRuleMapping[i].Actions)); j++ {
if rulesMatchesAction(clusterRules, ClusterRoleRuleMapping[i].Actions[j]) {
rule.Actions = append(rule.Actions, ClusterRoleRuleMapping[i].Actions[j])
}
}
if len(rule.Actions) > 0 {
@@ -567,12 +573,12 @@ func GetClusterRoleRules(name string) ([]Rule, error) {
rules := make([]Rule, 0)
for i := 0; i < len(ClusterRoleRuleGroup); i++ {
rule := Rule{Name: ClusterRoleRuleGroup[i].Name}
for i := 0; i < len(ClusterRoleRuleMapping); i++ {
rule := Rule{Name: ClusterRoleRuleMapping[i].Name}
rule.Actions = make([]Action, 0)
for j := 0; j < (len(ClusterRoleRuleGroup[i].Actions)); j++ {
if actionValidate(clusterRole.Rules, ClusterRoleRuleGroup[i].Actions[j]) {
rule.Actions = append(rule.Actions, ClusterRoleRuleGroup[i].Actions[j])
for j := 0; j < (len(ClusterRoleRuleMapping[i].Actions)); j++ {
if rulesMatchesAction(clusterRole.Rules, ClusterRoleRuleMapping[i].Actions[j]) {
rule.Actions = append(rule.Actions, ClusterRoleRuleMapping[i].Actions[j])
}
}
if len(rule.Actions) > 0 {
@@ -590,12 +596,12 @@ func GetRoleRules(namespace string, name string) ([]Rule, error) {
}
rules := make([]Rule, 0)
for i := 0; i < len(RoleRuleGroup); i++ {
rule := Rule{Name: RoleRuleGroup[i].Name}
for i := 0; i < len(RoleRuleMapping); i++ {
rule := Rule{Name: RoleRuleMapping[i].Name}
rule.Actions = make([]Action, 0)
for j := 0; j < len(RoleRuleGroup[i].Actions); j++ {
if actionValidate(role.Rules, RoleRuleGroup[i].Actions[j]) {
rule.Actions = append(rule.Actions, RoleRuleGroup[i].Actions[j])
for j := 0; j < len(RoleRuleMapping[i].Actions); j++ {
if rulesMatchesAction(role.Rules, RoleRuleMapping[i].Actions[j]) {
rule.Actions = append(rule.Actions, RoleRuleMapping[i].Actions[j])
}
}
if len(rule.Actions) > 0 {
@@ -605,11 +611,157 @@ func GetRoleRules(namespace string, name string) ([]Rule, error) {
return rules, nil
}
func actionValidate(rules []v1.PolicyRule, action Action) bool {
func rulesMatchesAction(rules []v1.PolicyRule, action Action) bool {
for _, rule := range action.Rules {
if !ruleValidate(rules, rule) {
if !RulesMatchesRequired(rules, rule) {
return false
}
}
return true
}
func RulesMatchesRequired(rules []v1.PolicyRule, required v1.PolicyRule) bool {
for _, rule := range rules {
if ruleMatchesRequired(rule, required) {
return true
}
}
return false
}
func ruleMatchesRequired(rule v1.PolicyRule, required v1.PolicyRule) bool {
if len(required.NonResourceURLs) == 0 {
for _, apiGroup := range required.APIGroups {
for _, resource := range required.Resources {
resources := strings.Split(resource, "/")
resource = resources[0]
var subsource string
if len(resources) > 1 {
subsource = resources[1]
}
if len(required.ResourceNames) == 0 {
for _, verb := range required.Verbs {
if !ruleMatchesRequest(rule, apiGroup, "", resource, subsource, "", verb) {
return false
}
}
} else {
for _, resourceName := range required.ResourceNames {
for _, verb := range required.Verbs {
if !ruleMatchesRequest(rule, apiGroup, "", resource, subsource, resourceName, verb) {
return false
}
}
}
}
}
}
} else {
for _, apiGroup := range required.APIGroups {
for _, nonResourceURL := range required.NonResourceURLs {
for _, verb := range required.Verbs {
if !ruleMatchesRequest(rule, apiGroup, nonResourceURL, "", "", "", verb) {
return false
}
}
}
}
}
return true
}
func ruleMatchesResources(rule v1.PolicyRule, apiGroup string, resource string, subresource string, resourceName string) bool {
if resource == "" {
return false
}
if !hasString(rule.APIGroups, apiGroup) && !hasString(rule.APIGroups, v1.ResourceAll) {
return false
}
if len(rule.ResourceNames) > 0 && !hasString(rule.ResourceNames, resourceName) {
return false
}
combinedResource := resource
if subresource != "" {
combinedResource = combinedResource + "/" + subresource
}
for _, res := range rule.Resources {
// match "*"
if res == v1.ResourceAll || res == combinedResource {
return true
}
// match "*/subresource"
if len(subresource) > 0 && strings.HasPrefix(res, "*/") && subresource == strings.TrimLeft(res, "*/") {
return true
}
// match "resource/*"
if strings.HasSuffix(res, "/*") && resource == strings.TrimRight(res, "/*") {
return true
}
}
return false
}
func ruleMatchesRequest(rule v1.PolicyRule, apiGroup string, nonResourceURL string, resource string, subresource string, resourceName string, verb string) bool {
if !hasString(rule.Verbs, verb) && !hasString(rule.Verbs, v1.VerbAll) {
return false
}
if nonResourceURL == "" {
return ruleMatchesResources(rule, apiGroup, resource, subresource, resourceName)
} else {
return ruleMatchesNonResource(rule, nonResourceURL)
}
}
func ruleMatchesNonResource(rule v1.PolicyRule, nonResourceURL string) bool {
if nonResourceURL == "" {
return false
}
for _, spec := range rule.NonResourceURLs {
if pathMatches(nonResourceURL, spec) {
return true
}
}
return false
}
func pathMatches(path, spec string) bool {
// Allow wildcard match
if spec == "*" {
return true
}
// Allow exact match
if spec == path {
return true
}
// Allow a trailing * subpath match
if strings.HasSuffix(spec, "*") && strings.HasPrefix(path, strings.TrimRight(spec, "*")) {
return true
}
return false
}
func hasString(slice []string, value string) bool {
for _, s := range slice {
if s == value {
return true
}
}
return false
}

File diff suppressed because it is too large Load Diff

0
pkg/models/metrics/containers.go Normal file → Executable file
View File

129
pkg/models/metrics/metricscollector.go Normal file → Executable file
View File

@@ -26,11 +26,19 @@ import (
"time"
"github.com/pkg/errors"
"k8s.io/api/core/v1"
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"sync"
"k8s.io/apimachinery/pkg/labels"
v12 "k8s.io/client-go/listers/core/v1"
"kubesphere.io/kubesphere/pkg/client"
"kubesphere.io/kubesphere/pkg/models"
"kubesphere.io/kubesphere/pkg/models/controllers"
"kubesphere.io/kubesphere/pkg/models/workspaces"
)
func getPodNameRegexInWorkload(request *restful.Request) string {
@@ -186,6 +194,15 @@ func MonitorAllMetrics(request *restful.Request) FormatedLevelMetric {
go collectPodMetrics(request, metricName, ch)
} else if sourceType == MetricLevelWorkload {
go collectWorkloadMetrics(request, metricName, ch)
} else if sourceType == MetricLevelWorkspace {
name := request.PathParameter("workspace_name")
namespaces, err := workspaces.WorkspaceNamespaces(name)
if err != nil {
glog.Errorln(err)
}
namespaces = filterNamespace(request, namespaces)
go collectWorkspaceMetrics(request, metricName, namespaces, ch)
}
}
}
@@ -213,6 +230,106 @@ func MonitorAllMetrics(request *restful.Request) FormatedLevelMetric {
}
}
func MonitorWorkspaceUserInfo(req *restful.Request) FormatedLevelMetric {
var metricsArray []FormatedMetric
timestamp := time.Now().Unix()
wg := sync.WaitGroup{}
var orgResultItem FormatedMetric
var dvpResultItem FormatedMetric
var projResultItem FormatedMetric
var actResultItem FormatedMetric
wg.Add(4)
go func() {
orgNums, errOrg := workspaces.GetAllOrgNums()
orgResultItem = getSpecificMetricItem(timestamp, MetricNameWorkspaceAllOrganizationCount, WorkspaceResourceKindOrganization, orgNums, errOrg)
wg.Done()
}()
go func() {
devOpsProjectNums, errDevops := workspaces.GetAllDevOpsProjectsNums()
dvpResultItem = getSpecificMetricItem(timestamp, MetricNameWorkspaceAllDevopsCount, WorkspaceResourceKindDevops, devOpsProjectNums, errDevops)
wg.Done()
}()
go func() {
projNums, errProj := workspaces.GetAllProjectNums()
projResultItem = getSpecificMetricItem(timestamp, MetricNameWorkspaceAllProjectCount, WorkspaceResourceKindNamespace, projNums, errProj)
wg.Done()
}()
go func() {
actNums, errAct := workspaces.GetAllAccountNums()
actResultItem = getSpecificMetricItem(timestamp, MetricNameWorkspaceAllAccountCount, WorkspaceResourceKindAccount, actNums, errAct)
wg.Done()
}()
wg.Wait()
metricsArray = append(metricsArray, orgResultItem, dvpResultItem, projResultItem, actResultItem)
return FormatedLevelMetric{
MetricsLevel: MetricLevelWorkspace,
Results: metricsArray,
}
}
//func getWorkspaceMetricItem(timestamp int64, namespaceNums int64, resourceName string, err error) FormatedMetric {
// var fMetric FormatedMetric
// fMetric.Data.ResultType = ResultTypeVector
// fMetric.MetricName = MetricNameWorkspaceInfoCount
// fMetric.Status = MetricStatusSuccess
// if err != nil {
// fMetric.Status = MetricStatusError
// }
// resultItem := make(map[string]interface{})
// tmp := make(map[string]string)
// tmp[ResultItemMetricResource] = resourceName
// resultItem[ResultItemMetric] = tmp
// resultItem[ResultItemValue] = []interface{}{timestamp, strconv.FormatInt(namespaceNums, 10)}
// return fMetric
//}
func MonitorWorkspaceResourceLevelMetrics(request *restful.Request) FormatedLevelMetric {
wsName := request.PathParameter("workspace_name")
namspaces, errNs := workspaces.WorkspaceNamespaces(wsName)
devOpsProjects, errDevOps := workspaces.GetDevOpsProjects(wsName)
members, errMemb := workspaces.GetOrgMembers(wsName)
roles, errRole := workspaces.GetOrgRoles(wsName)
var fMetricsArray []FormatedMetric
timestamp := int64(time.Now().Unix())
namespaces, noneExistentNs := getExistingNamespace(namspaces)
if len(noneExistentNs) != 0 {
nsStr := strings.Join(noneExistentNs, "|")
errStr := "the namespaces " + nsStr + " do not exist"
if errNs == nil {
errNs = errors.New(errStr)
} else {
errNs = errors.New(errNs.Error() + "\t" + errStr)
}
}
// add namespaces(project) metric
nsMetrics := getSpecificMetricItem(timestamp, MetricNameWorkspaceNamespaceCount, WorkspaceResourceKindNamespace, len(namespaces), errNs)
// add devops metric
devopsMetrics := getSpecificMetricItem(timestamp, MetricNameWorkspaceDevopsCount, WorkspaceResourceKindDevops, len(devOpsProjects), errDevOps)
// add member metric
memberMetrics := getSpecificMetricItem(timestamp, MetricNameWorkspaceMemberCount, WorkspaceResourceKindMember, len(members), errMemb)
// add role metric
roleMetrics := getSpecificMetricItem(timestamp, MetricNameWorkspaceRoleCount, WorkspaceResourceKindRole, len(roles), errRole)
// add workloads count metric
wlMetrics := getWorkspaceWorkloadCountMetrics(namespaces)
// add pods count metric
podsCountMetrics := getWorkspacePodsCountMetrics(request, namespaces)
fMetricsArray = append(fMetricsArray, nsMetrics, devopsMetrics, memberMetrics, roleMetrics, wlMetrics, *podsCountMetrics)
return FormatedLevelMetric{
MetricsLevel: MetricLevelWorkspace,
Results: fMetricsArray,
}
}
func getWorkspacePodsCountMetrics(request *restful.Request, namespaces []string) *FormatedMetric {
metricName := MetricNameNamespacePodCount
var recordingRule = RulePromQLTmplMap[metricName]
@@ -289,13 +406,13 @@ func MonitorNodeorClusterSingleMetric(request *restful.Request, metricsName stri
var fMetric FormatedMetric
timestamp := int64(time.Now().Unix())
if metricsName == MetricNameClusterHealthyNodeCount {
if metricsName == "cluster_node_online" {
onlineNodes, _ := getNodeHealthyConditionMetric()
fMetric = getSpecificMetricItem(timestamp, MetricNameClusterHealthyNodeCount, "node_count", len(onlineNodes), nil)
} else if metricsName == MetricNameClusterUnhealthyNodeCount {
} else if metricsName == "cluster_node_offline" {
_, offlineNodes := getNodeHealthyConditionMetric()
fMetric = getSpecificMetricItem(timestamp, MetricNameClusterUnhealthyNodeCount, "node_count", len(offlineNodes), nil)
} else if metricsName == MetricNameClusterNodeCount {
} else if metricsName == "cluster_node_total" {
onlineNodes, offlineNodes := getNodeHealthyConditionMetric()
fMetric = getSpecificMetricItem(timestamp, MetricNameClusterNodeCount, "node_count", len(onlineNodes)+len(offlineNodes), nil)
} else {
@@ -355,14 +472,14 @@ func getExistingNamespace(namespaces []string) ([]string, []string) {
}
func getAllNamespace() (map[string]int, error) {
k8sClient := client.NewK8sClient()
nsList, err := k8sClient.CoreV1().Namespaces().List(metaV1.ListOptions{})
lister := controllers.ResourceControllers.Controllers[controllers.Namespaces].Lister().(v12.NamespaceLister)
nsList, err := lister.List(labels.Everything())
if err != nil {
glog.Errorln(err)
return nil, err
}
namespaceMap := make(map[string]int)
for _, item := range nsList.Items {
for _, item := range nsList {
namespaceMap[item.Name] = 0
}
return namespaceMap, nil

2
pkg/models/metrics/metricsconst.go Normal file → Executable file
View File

@@ -148,7 +148,7 @@ var RulePromQLTmplMap = MetricMap{
"cluster_memory_bytes_available": "sum(node:node_memory_bytes_available:sum)",
"cluster_memory_bytes_total": "sum(node:node_memory_bytes_total:sum)",
"cluster_memory_bytes_usage": "sum(node:node_memory_bytes_total:sum) - sum(node:node_memory_bytes_available:sum)",
"cluster_net_utilisation": "sum(node:node_net_utilisation:sum_irate)",
"cluster_net_utilisation": ":node_net_utilisation:sum_irate",
"cluster_net_bytes_transmitted": "sum(node:node_net_bytes_transmitted:sum_irate)",
"cluster_net_bytes_received": "sum(node:node_net_bytes_received:sum_irate)",
"cluster_disk_read_iops": "sum(node:data_volume_iops_reads:sum)",

0
pkg/models/metrics/metricsrule.go Normal file → Executable file
View File

0
pkg/models/metrics/metricsstruct.go Normal file → Executable file
View File

0
pkg/models/metrics/nodes.go Normal file → Executable file
View File

0
pkg/models/metrics/pods.go Normal file → Executable file
View File

View File

@@ -4,8 +4,9 @@ import "time"
type Workspace struct {
Group `json:",inline"`
Namespaces []string `json:"namespaces,omitempty"`
DevopsProjects []string `json:"devops_projects,omitempty"`
Admin string `json:"admin,omitempty"`
Namespaces []string `json:"namespaces"`
DevopsProjects []string `json:"devops_projects"`
}
type UserInvite struct {

View File

@@ -7,19 +7,21 @@ import (
"io/ioutil"
"net/http"
"github.com/jinzhu/gorm"
core "k8s.io/api/core/v1"
k8sErr "k8s.io/apimachinery/pkg/api/errors"
"log"
"strings"
"github.com/jinzhu/gorm"
core "k8s.io/api/core/v1"
"errors"
"regexp"
"github.com/emicklei/go-restful"
"k8s.io/api/rbac/v1"
apierrors "k8s.io/apimachinery/pkg/api/errors"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
v13 "k8s.io/client-go/listers/rbac/v1"
clientV1 "k8s.io/client-go/listers/core/v1"
"k8s.io/kubernetes/pkg/util/slice"
"kubesphere.io/kubesphere/pkg/client"
@@ -31,12 +33,6 @@ import (
var WorkSpaceRoles = []string{"admin", "operator", "viewer"}
func UnBindNamespace(workspace string, namespace string) error {
db := client.NewSharedDBClient()
defer db.Close()
return db.Delete(&WorkspaceNSBinding{Workspace: workspace, Namespace: namespace}).Error
}
func UnBindDevopsProject(workspace string, devops string) error {
db := client.NewSharedDBClient()
defer db.Close()
@@ -100,44 +96,85 @@ func CreateDevopsProject(username string, devops DevopsProject) (*DevopsProject,
return &project, nil
}
func Namespaces(workspace string) ([]*core.Namespace, error) {
db := client.NewSharedDBClient()
defer db.Close()
func ListNamespaceByUser(workspaceName string, username string) ([]*core.Namespace, error) {
var workspaceNSBindings []WorkspaceNSBinding
namespaces, err := Namespaces(workspaceName)
if err := db.Where("workspace = ?", workspace).Find(&workspaceNSBindings).Error; err != nil {
if err != nil {
return nil, err
}
namespaces := make([]*core.Namespace, 0)
clusterRoles, err := iam.GetClusterRoles(username)
for _, workspaceNSBinding := range workspaceNSBindings {
namespace, err := client.NewK8sClient().CoreV1().Namespaces().Get(workspaceNSBinding.Namespace, meta_v1.GetOptions{})
if err != nil {
if k8sErr.IsNotFound(err) {
db.Delete(&WorkspaceNSBinding{Workspace: workspace, Namespace: workspaceNSBinding.Namespace})
} else {
if err != nil {
return nil, err
}
rules := make([]v1.PolicyRule, 0)
for _, clusterRole := range clusterRoles {
rules = append(rules, clusterRole.Rules...)
}
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 {
for i := 0; i < len(namespaces); i++ {
roles, err := iam.GetRoles(namespaces[i].Name, username)
if err != nil {
return nil, err
}
} else {
namespaces = append(namespaces, namespace)
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--
}
}
}
return namespaces, nil
}
func Namespaces(workspaceName string) ([]*core.Namespace, error) {
lister := controllers.ResourceControllers.Controllers[controllers.Namespaces].Lister().(clientV1.NamespaceLister)
namespaces, err := lister.List(labels.SelectorFromSet(labels.Set{"kubesphere.io/workspace": workspaceName}))
if err != nil {
return nil, err
}
if namespaces == nil {
return make([]*core.Namespace, 0), nil
}
return namespaces, nil
}
func BindingDevopsProject(workspace string, devops string) error {
db := client.NewSharedDBClient()
defer db.Close()
return db.Create(&WorkspaceDPBinding{Workspace: workspace, DevOpsProject: devops}).Error
}
func DeleteNamespace(namespace string) error {
deletePolicy := meta_v1.DeletePropagationBackground
err := client.NewK8sClient().CoreV1().Namespaces().Delete(namespace, &meta_v1.DeleteOptions{PropagationPolicy: &deletePolicy})
return err
func DeleteNamespace(workspace string, namespaceName string) error {
namespace, err := client.NewK8sClient().CoreV1().Namespaces().Get(namespaceName, meta_v1.GetOptions{})
if err != nil {
return err
}
if namespace.Labels != nil && namespace.Labels["kubesphere.io/workspace"] == workspace {
deletePolicy := meta_v1.DeletePropagationBackground
return client.NewK8sClient().CoreV1().Namespaces().Delete(namespaceName, &meta_v1.DeleteOptions{PropagationPolicy: &deletePolicy})
} else {
return errors.New("resource not found")
}
}
func Delete(workspace *Workspace) error {
@@ -174,7 +211,7 @@ func Delete(workspace *Workspace) error {
func release(workspace *Workspace) error {
for _, namespace := range workspace.Namespaces {
err := DeleteNamespace(namespace)
err := DeleteNamespace(workspace.Name, namespace)
if err != nil && !apierrors.IsNotFound(err) {
return err
}
@@ -335,7 +372,44 @@ func Detail(name string) (*Workspace, error) {
return workspace, nil
}
func List(names []string) ([]*Workspace, error) {
// List all workspaces for the current user
func ListByUser(username string) ([]*Workspace, error) {
clusterRoles, err := iam.GetClusterRoles(username)
if err != nil {
return nil, err
}
rules := make([]v1.PolicyRule, 0)
for _, clusterRole := range clusterRoles {
rules = append(rules, clusterRole.Rules...)
}
workspacesManager := v1.PolicyRule{APIGroups: []string{"kubesphere.io"}, Verbs: []string{"list", "get"}, Resources: []string{"workspaces"}}
if iam.RulesMatchesRequired(rules, workspacesManager) {
return 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 len(workspaceNames) == 0 {
return make([]*Workspace, 0), nil
}
return fetch(workspaceNames)
}
}
func fetch(names []string) ([]*Workspace, error) {
url := fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/groups", constants.AccountAPIServer)
@@ -379,6 +453,7 @@ func List(names []string) ([]*Workspace, error) {
}
workspaces = append(workspaces, workspace)
}
return workspaces, nil
}
@@ -434,16 +509,16 @@ func DevopsProjects(workspace string) ([]DevopsProject, error) {
}
func convertGroupToWorkspace(db *gorm.DB, group Group) (*Workspace, error) {
var workspaceNSBindings []WorkspaceNSBinding
namespaces, err := Namespaces(group.Name)
if err := db.Where("workspace = ?", group.Name).Find(&workspaceNSBindings).Error; err != nil {
if err != nil {
return nil, err
}
namespaces := make([]string, 0)
namespacesNames := make([]string, 0)
for _, workspaceNSBinding := range workspaceNSBindings {
namespaces = append(namespaces, workspaceNSBinding.Namespace)
for _, namespace := range namespaces {
namespacesNames = append(namespacesNames, namespace.Name)
}
var workspaceDOPBindings []WorkspaceDPBinding
@@ -459,7 +534,7 @@ func convertGroupToWorkspace(db *gorm.DB, group Group) (*Workspace, error) {
}
workspace := Workspace{Group: group}
workspace.Namespaces = namespaces
workspace.Namespaces = namespacesNames
workspace.DevopsProjects = devOpsProjects
return &workspace, nil
}
@@ -468,12 +543,6 @@ func CreateNamespace(namespace *core.Namespace) (*core.Namespace, error) {
return client.NewK8sClient().CoreV1().Namespaces().Create(namespace)
}
func BindingNamespace(workspace string, namespace string) error {
db := client.NewSharedDBClient()
defer db.Close()
return db.Create(&WorkspaceNSBinding{Workspace: workspace, Namespace: namespace}).Error
}
func Invite(workspaceName string, users []UserInvite) error {
for _, user := range users {
if !slice.ContainsString(WorkSpaceRoles, user.Role, nil) {
@@ -523,38 +592,22 @@ func RemoveMembers(workspaceName string, users []string) error {
return err
}
for i := 0; i < len(workspace.Members); i++ {
if slice.ContainsString(users, workspace.Members[i], nil) {
workspace.Members = append(workspace.Members[:i], workspace.Members[i+1:]...)
i--
}
}
workspace, err = Edit(workspace)
if err != nil {
return err
}
return nil
}
//func checkUserExist(username string) (bool, error) {
// result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/users?check=%s", constants.AccountAPIServer, username))
//
// if err != nil {
// return false, err
// }
//
// data, err := ioutil.ReadAll(result.Body)
//
// if err != nil {
// return false, err
// }
//
// if result.StatusCode > 200 {
// return false, ksErr.Wrap(data)
// }
//
// var r map[string]bool
//
// err = json.Unmarshal(data, &r)
//
// if err != nil {
// return false, err
// }
//
// return r["exist"], nil
//
//}
func Roles(workspace *Workspace) ([]*v1.ClusterRole, error) {
roles := make([]*v1.ClusterRole, 0)
@@ -614,11 +667,138 @@ 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", "workspaces/namespaces", "workspaces/members", "workspaces/devops", "workspaces/registries"},
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"},
},
// 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/*"},
},
// 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},
},
}
@@ -634,35 +814,159 @@ func WorkspaceRoleInit(workspace *Workspace) error {
Resources: []string{"workspaces"},
ResourceNames: []string{workspace.Name},
}, {
Verbs: []string{"list", "create"},
Verbs: []string{"create", "get"},
APIGroups: []string{"kubesphere.io"},
Resources: []string{"workspaces/namespaces", "workspaces/devops"},
ResourceNames: []string{workspace.Name},
}, {
Verbs: []string{"list"},
APIGroups: []string{"kubesphere.io"},
Resources: []string{"workspaces/members", "workspaces/registries"},
ResourceNames: []string{workspace.Name},
},
{
Verbs: []string{"get"},
APIGroups: []string{"kubesphere.io"},
Resources: []string{"registries"},
},
}
operator.Labels = map[string]string{"creator": "system"}
viewer := new(v1.ClusterRole)
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"},
Resources: []string{"workspaces"},
ResourceNames: []string{workspace.Name},
}, {
Verbs: []string{"list"},
ResourceNames: []string{"namespaces"},
Resources: []string{"status/*"},
},
// 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"},
Resources: []string{"workspaces/namespaces", "workspaces/members", "workspaces/devops", "workspaces/registries"},
ResourceNames: []string{workspace.Name},
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},
},
}
viewer.Labels = map[string]string{"creator": "system"}
_, err := k8sClient.RbacV1().ClusterRoles().Create(admin)
@@ -677,6 +981,7 @@ func WorkspaceRoleInit(workspace *Workspace) error {
adminRoleBinding.Name = admin.Name
adminRoleBinding.RoleRef = v1.RoleRef{Kind: "ClusterRole", Name: admin.Name}
adminRoleBinding.Subjects = []v1.Subject{{Kind: v1.UserKind, Name: workspace.Creator}}
_, err = k8sClient.RbacV1().ClusterRoleBindings().Create(adminRoleBinding)
if err != nil {
if !apierrors.IsAlreadyExists(err) {
@@ -761,17 +1066,15 @@ func unbindWorkspaceRole(workspace string, users []string) error {
func unbindNamespacesRole(namespaces []string, users []string) error {
lister := controllers.ResourceControllers.Controllers[controllers.Namespaces].Lister().(v13.RoleBindingLister)
k8sClient := client.NewK8sClient()
for _, namespace := range namespaces {
roleBindings, err := lister.RoleBindings(namespace).List(labels.Everything())
roleBindings, err := k8sClient.RbacV1().RoleBindings(namespace).List(meta_v1.ListOptions{})
if err != nil {
return err
}
for _, roleBinding := range roleBindings {
for _, roleBinding := range roleBindings.Items {
modify := false
for i := 0; i < len(roleBinding.Subjects); i++ {
@@ -781,7 +1084,7 @@ func unbindNamespacesRole(namespaces []string, users []string) error {
}
}
if modify {
_, err := k8sClient.RbacV1().RoleBindings(namespace).Update(roleBinding)
_, err := k8sClient.RbacV1().RoleBindings(namespace).Update(&roleBinding)
if err != nil {
return err
}
@@ -857,3 +1160,150 @@ func CreateWorkspaceRoleBinding(workspace *Workspace, username string, role stri
return nil
}
func GetDevOpsProjects(name string) ([]string, error) {
db := client.NewSharedDBClient()
defer db.Close()
var workspaceDOPBindings []WorkspaceDPBinding
if err := db.Where("workspace = ?", name).Find(&workspaceDOPBindings).Error; err != nil {
return nil, err
}
devOpsProjects := make([]string, 0)
for _, workspaceDOPBinding := range workspaceDOPBindings {
devOpsProjects = append(devOpsProjects, workspaceDOPBinding.DevOpsProject)
}
return devOpsProjects, nil
}
func GetOrgMembers(workspace string) ([]string, error) {
ws, err := Detail(workspace)
if err != nil {
return nil, err
}
return ws.Members, nil
}
func GetOrgRoles(name string) ([]string, error) {
return []string{"admin", "operator", "user"}, nil
}
func WorkspaceNamespaces(workspaceName string) ([]string, error) {
ns, err := Namespaces(workspaceName)
namespaces := make([]string, 0)
if err != nil {
return namespaces, err
}
for i := 0; i < len(ns); i++ {
namespaces = append(namespaces, ns[i].Name)
}
return namespaces, nil
}
func CountAll() (int, error) {
result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/groups/count", constants.AccountAPIServer))
if err != nil {
return 0, err
}
data, err := ioutil.ReadAll(result.Body)
if err != nil {
return 0, err
}
if result.StatusCode > 200 {
return 0, ksErr.Wrap(data)
}
var count map[string]interface{}
err = json.Unmarshal(data, &count)
if err != nil {
return 0, err
}
val, ok := count["total"]
if !ok {
return 0, errors.New("not found")
}
switch val.(type) {
case int:
return val.(int), nil
case float32:
return int(val.(float32)), nil
case float64:
return int(val.(float64)), nil
}
return 0, errors.New("not found")
}
func GetAllOrgNums() (int, error) {
count, err := CountAll()
if err != nil {
return 0, err
}
return count, nil
}
func GetAllProjectNums() (int, error) {
return controllers.ResourceControllers.Controllers[controllers.Namespaces].CountWithConditions(""), nil
}
func GetAllDevOpsProjectsNums() (int, error) {
db := client.NewSharedDBClient()
defer db.Close()
var count int
if err := db.Find(&WorkspaceDPBinding{}).Count(&count).Error; err != nil {
return 0, err
}
return count, nil
}
func GetAllAccountNums() (int, error) {
result, err := http.Get(fmt.Sprintf("http://%s/apis/account.kubesphere.io/v1alpha1/users", constants.AccountAPIServer))
if err != nil {
return 0, err
}
data, err := ioutil.ReadAll(result.Body)
if err != nil {
return 0, err
}
if result.StatusCode > 200 {
return 0, ksErr.Wrap(data)
}
var count map[string]interface{}
err = json.Unmarshal(data, &count)
if err != nil {
return 0, err
}
val, ok := count["total"]
if !ok {
return 0, errors.New("not found")
}
switch val.(type) {
case int:
return val.(int), nil
case float32:
return int(val.(float32)), nil
case float64:
return int(val.(float64)), nil
}
return 0, errors.New("not found")
}