From 57ad2171b6d8ac586344793f1c96eec8480c6d56 Mon Sep 17 00:00:00 2001 From: jeff Date: Mon, 25 Jun 2018 20:28:15 +0800 Subject: [PATCH] fix router list --- pkg/apis/v1alpha/pods/pods_handler.go | 50 +++++++++- pkg/apis/v1alpha/routes/routes_handler.go | 27 ++++- pkg/models/controllers/services.go | 26 +++-- pkg/models/controllers/types.go | 1 + pkg/models/metrics/pods.go | 116 ++++++++++++++++++---- pkg/models/routes.go | 63 ++++++++++++ 6 files changed, 254 insertions(+), 29 deletions(-) diff --git a/pkg/apis/v1alpha/pods/pods_handler.go b/pkg/apis/v1alpha/pods/pods_handler.go index 5bd0b0c80..2eb7fba2f 100644 --- a/pkg/apis/v1alpha/pods/pods_handler.go +++ b/pkg/apis/v1alpha/pods/pods_handler.go @@ -33,6 +33,25 @@ func Register(ws *restful.WebService) { ws.Route(ws.GET("/namespaces/{namespace}/pods/{pod}").To(handlePodUnderNameSpace).Filter(route.RouteLogging)). Consumes(restful.MIME_JSON, restful.MIME_XML). Produces(restful.MIME_JSON) + + ws.Route(ws.GET("/namespaces/{namespace}/deployments/{deployment}/pods"). + To(handleGetDeploymentPodsMetrics). + Filter(route.RouteLogging). + Consumes(restful.MIME_JSON). + Produces(restful.MIME_JSON)) + + ws.Route(ws.GET("/namespaces/{namespace}/daemonsets/{daemonset}/pods"). + To(handleGetDaemonsetPodsMetrics). + Filter(route.RouteLogging). + Consumes(restful.MIME_JSON). + Produces(restful.MIME_JSON)) + + ws.Route(ws.GET("/namespaces/{namespace}/statefulsets/{statefulset}/pods"). + To(handleGetStatefulsetPodsMetrics). + Filter(route.RouteLogging). + Consumes(restful.MIME_JSON). + Produces(restful.MIME_JSON)) + ws.Route(ws.GET("/namespaces/{namespace}/pods").To(handlePodsUnderNameSpace).Filter(route.RouteLogging)). Consumes(restful.MIME_JSON, restful.MIME_XML). Produces(restful.MIME_JSON) @@ -44,30 +63,59 @@ func Register(ws *restful.WebService) { Produces(restful.MIME_JSON) } -func handleAllPods(request *restful.Request, response *restful.Response) { +// Get all pods metrics in cluster +func handleAllPods(_ *restful.Request, response *restful.Response) { var result constants.PageableResponse result = metrics.GetAllPodMetrics() response.WriteAsJson(result) } +// Get pods metrics in namespace func handlePodsUnderNameSpace(request *restful.Request, response *restful.Response) { var result constants.PageableResponse result = metrics.GetPodMetricsInNamespace(request.PathParameter("namespace")) response.WriteAsJson(result) } +// Get pods metrics in a deployment +func handleGetDeploymentPodsMetrics(request *restful.Request, response *restful.Response) { + namespace := request.PathParameter("namespace") + deployment := request.PathParameter("deployment") + result := metrics.GetPodMetricsInDeployment(namespace, deployment) + response.WriteAsJson(result) +} + +// Get pods metrics in daemonset deployment +func handleGetDaemonsetPodsMetrics(request *restful.Request, response *restful.Response) { + namespace := request.PathParameter("namespace") + daemonset := request.PathParameter("daemonset") + result := metrics.GetPodMetricsInDaemonset(namespace, daemonset) + response.WriteAsJson(result) +} + +// Get pods metrics in statefulset deployment +func handleGetStatefulsetPodsMetrics(request *restful.Request, response *restful.Response) { + namespace := request.PathParameter("namespace") + statefulset := request.PathParameter("statefulset") + result := metrics.GetPodMetricsInStatefulSet(namespace, statefulset) + response.WriteAsJson(result) +} + +// Get all pods metrics located in node func handlePodsUnderNode(request *restful.Request, response *restful.Response) { var result constants.PageableResponse result = metrics.GetPodMetricsInNode(request.PathParameter("node")) response.WriteAsJson(result) } +// Get a specific pod metrics func handlePodUnderNameSpace(request *restful.Request, response *restful.Response) { var resultPod metrics.PodMetrics resultPod = metrics.FormatPodMetrics(request.PathParameter("namespace"), request.PathParameter("pod")) response.WriteAsJson(resultPod) } +// Get pod metrics in a namespace located in deployment func handlePodsUnderNodeAndNameSpace(request *restful.Request, response *restful.Response) { var result constants.PageableResponse nodeName := request.PathParameter("node") diff --git a/pkg/apis/v1alpha/routes/routes_handler.go b/pkg/apis/v1alpha/routes/routes_handler.go index cd6035460..bfdfa52fd 100644 --- a/pkg/apis/v1alpha/routes/routes_handler.go +++ b/pkg/apis/v1alpha/routes/routes_handler.go @@ -36,26 +36,31 @@ func Register(ws *restful.WebService) { Filter(route.RouteLogging). Produces(restful.MIME_JSON)) - ws.Route(ws.GET("/{namespace}/router").To(GetRouter). + ws.Route(ws.GET("/users/{user}/routers").To(GetAllRoutersOfUser). + Doc("Get routers for user"). + Filter(route.RouteLogging). + Produces(restful.MIME_JSON)) + + ws.Route(ws.GET("/namespaces/{namespace}/router").To(GetRouter). Doc("Get router of a specified project"). Param(ws.PathParameter("namespace", "name of the project").DataType("string")). Filter(route.RouteLogging). Produces(restful.MIME_JSON)) - ws.Route(ws.DELETE("/{namespace}/router").To(DeleteRouter). + ws.Route(ws.DELETE("/namespaces/{namespace}/router").To(DeleteRouter). Doc("Get router of a specified project"). Param(ws.PathParameter("namespace", "name of the project").DataType("string")). Filter(route.RouteLogging). Produces(restful.MIME_JSON)) - ws.Route(ws.POST("/{namespace}/router").To(CreateRouter). + ws.Route(ws.POST("/namespaces/{namespace}/router").To(CreateRouter). Doc("Create a router for a specified project"). Param(ws.PathParameter("namespace", "name of the project").DataType("string")). Filter(route.RouteLogging). Consumes(restful.MIME_JSON). Produces(restful.MIME_JSON)) - ws.Route(ws.PUT("/{namespace}/router").To(UpdateRouter). + ws.Route(ws.PUT("/namespaces/{namespace}/router").To(UpdateRouter). Doc("Update a router for a specified project"). Param(ws.PathParameter("namespace", "name of the project").DataType("string")). Filter(route.RouteLogging). @@ -81,6 +86,20 @@ func GetAllRouters(request *restful.Request, response *restful.Response) { } } +// Get all namespace ingress controller services for user +func GetAllRoutersOfUser(request *restful.Request, response *restful.Response) { + username := request.PathParameter("user") + + routers, err := models.GetAllRoutersOfUser(username) + + if err != nil { + glog.Error(err) + response.WriteHeaderAndEntity(http.StatusInternalServerError, constants.MessageResponse{Message: err.Error()}) + } else { + response.WriteAsJson(routers) + } +} + // Get ingress controller service for specified namespace func GetRouter(request *restful.Request, response *restful.Response) { diff --git a/pkg/models/controllers/services.go b/pkg/models/controllers/services.go index 4a1bb4f32..17bdf6c4f 100644 --- a/pkg/models/controllers/services.go +++ b/pkg/models/controllers/services.go @@ -21,6 +21,8 @@ import ( "strings" "time" + "strconv" + "github.com/golang/glog" "k8s.io/api/core/v1" "k8s.io/apimachinery/pkg/labels" @@ -74,7 +76,7 @@ func (ctl *ServiceCtl) getExternalIp(item v1.Service) string { } return "" } - return "-" + return "" } func (ctl *ServiceCtl) generateObject(item v1.Service) *Service { @@ -86,6 +88,7 @@ func (ctl *ServiceCtl) generateObject(item v1.Service) *Service { serviceType := virtualIp vip := item.Spec.ClusterIP ports := "" + var nodePorts []string if createTime.IsZero() { createTime = time.Now() @@ -93,12 +96,10 @@ func (ctl *ServiceCtl) generateObject(item v1.Service) *Service { if item.Spec.ClusterIP == "None" { serviceType = headlessSelector - vip = "-" } if len(item.Spec.ExternalName) > 0 { serviceType = headlessExternal - vip = "-" } if len(item.Spec.ExternalIPs) > 0 { @@ -110,15 +111,29 @@ func (ctl *ServiceCtl) generateObject(item v1.Service) *Service { targetPort := portItem.TargetPort.String() protocol := portItem.Protocol ports += fmt.Sprintf("%d:%s/%s,", port, targetPort, protocol) + + if portItem.NodePort != 0 { + nodePorts = append(nodePorts, strconv.FormatInt(int64(portItem.NodePort), 10)) + } } + if len(ports) == 0 { ports = "-" } else { ports = ports[0 : len(ports)-1] } - object := &Service{Namespace: namespace, Name: name, ServiceType: serviceType, ExternalIp: externalIp, - VirtualIp: vip, CreateTime: createTime, Ports: ports, Annotation: Annotation{item.Annotations}} + object := &Service{ + Namespace: namespace, + Name: name, + ServiceType: serviceType, + ExternalIp: externalIp, + VirtualIp: vip, + CreateTime: createTime, + Ports: ports, + NodePorts: strings.Join(nodePorts, ","), + Annotation: Annotation{item.Annotations}, + } return object } @@ -154,7 +169,6 @@ func (ctl *ServiceCtl) listAndWatch() { for _, item := range list { obj := ctl.generateObject(*item) db.Create(obj) - } informer.AddEventHandler(cache.ResourceEventHandlerFuncs{ diff --git a/pkg/models/controllers/types.go b/pkg/models/controllers/types.go index 9ddce4762..7cd8ad592 100644 --- a/pkg/models/controllers/types.go +++ b/pkg/models/controllers/types.go @@ -140,6 +140,7 @@ type Service struct { ExternalIp string `json:"externalIp,omitempty"` Ports string `json:"ports,omitempty"` + NodePorts string `json:"nodePorts,omitempty"` Annotation Annotation `json:"annotations"` CreateTime time.Time `gorm:"column:createTime" json:"createTime,omitempty"` } diff --git a/pkg/models/metrics/pods.go b/pkg/models/metrics/pods.go index a09a7af8f..906529484 100644 --- a/pkg/models/metrics/pods.go +++ b/pkg/models/metrics/pods.go @@ -38,20 +38,6 @@ type PodMemoryMetrics struct { const Inf = "inf" -/* -Get all namespaces in default cluster -*/ -func GetNameSpaces() []string { - namespacesList := client.GetHeapsterMetrics("/namespaces") - var namespaces []string - dec := json.NewDecoder(strings.NewReader(namespacesList)) - err := dec.Decode(&namespaces) - if err != nil { - glog.Error(err) - } - return namespaces -} - /* Get all pods under specified namespace in default cluster */ @@ -73,14 +59,14 @@ func GetSinglePodMetrics(namespace string, podName string, ch chan PodMetrics) { } func GetPodsMetrics(podList *coreV1.PodList) []PodMetrics { - var items []PodMetrics + items := make([]PodMetrics, 0) ch := make(chan PodMetrics) for _, pod := range podList.Items { go GetSinglePodMetrics(pod.Namespace, pod.Name, ch) } - for _, _ = range podList.Items { + for range podList.Items { items = append(items, <-ch) } @@ -102,6 +88,96 @@ func GetPodMetricsInNamespace(namespace string) constants.PageableResponse { return podMetrics } +func GetPodMetricsInDeployment(namespace string, deployment string) constants.PageableResponse { + + var podMetrics constants.PageableResponse + + k8sClient := client.NewK8sClient() + + deploy, err := k8sClient.ExtensionsV1beta1().Deployments(namespace).Get(deployment, v1.GetOptions{}) + if err != nil { + glog.Error(err) + } + + labels := make([]string, 0) + for k, v := range deploy.Spec.Selector.MatchLabels { + labels = append(labels, k+"="+v) + } + + options := v1.ListOptions{ + LabelSelector: strings.Join(labels, ","), + } + + podList, err := k8sClient.CoreV1().Pods(namespace).List(options) + for _, podMetric := range GetPodsMetrics(podList) { + podMetrics.Items = append(podMetrics.Items, podMetric) + } + podMetrics.TotalCount = len(podMetrics.Items) + + return podMetrics + +} + +func GetPodMetricsInStatefulSet(namespace string, statefulSet string) constants.PageableResponse { + + var podMetrics constants.PageableResponse + + k8sClient := client.NewK8sClient() + + deploy, err := k8sClient.AppsV1().StatefulSets(namespace).Get(statefulSet, v1.GetOptions{}) + if err != nil { + glog.Error(err) + } + + labels := make([]string, 0) + for k, v := range deploy.Spec.Selector.MatchLabels { + labels = append(labels, k+"="+v) + } + + options := v1.ListOptions{ + LabelSelector: strings.Join(labels, ","), + } + + podList, err := k8sClient.CoreV1().Pods(namespace).List(options) + for _, podMetric := range GetPodsMetrics(podList) { + podMetrics.Items = append(podMetrics.Items, podMetric) + } + podMetrics.TotalCount = len(podMetrics.Items) + + return podMetrics + +} + +func GetPodMetricsInDaemonset(namespace string, daemonset string) constants.PageableResponse { + + var podMetrics constants.PageableResponse + + k8sClient := client.NewK8sClient() + + deploy, err := k8sClient.ExtensionsV1beta1().DaemonSets(namespace).Get(daemonset, v1.GetOptions{}) + if err != nil { + glog.Error(err) + } + + labels := make([]string, 0) + for k, v := range deploy.Spec.Selector.MatchLabels { + labels = append(labels, k+"="+v) + } + + options := v1.ListOptions{ + LabelSelector: strings.Join(labels, ","), + } + + podList, err := k8sClient.CoreV1().Pods(namespace).List(options) + for _, podMetric := range GetPodsMetrics(podList) { + podMetrics.Items = append(podMetrics.Items, podMetric) + } + podMetrics.TotalCount = len(podMetrics.Items) + + return podMetrics + +} + func GetPodMetricsInNode(nodeName string) constants.PageableResponse { var podMetrics constants.PageableResponse k8sClient := client.NewK8sClient() @@ -191,7 +267,9 @@ func FormatPodMetrics(namespace string, pod string) PodMetrics { resultPod.MemoryRequest = Inf } else { data, _ := memoryRequestMetrics[0].GetNumber("value") - resultPod.MemoryRequest = data.String() + memoryReq, _ := data.Float64() + memoryReq = memoryReq / 1024 / 1024 + resultPod.MemoryRequest = fmt.Sprintf("%.1f", memoryReq) } memoryLimit := client.GetHeapsterMetricsJson("/namespaces/" + namespace + "/pods/" + pod + "/metrics/memory/limit") @@ -200,7 +278,9 @@ func FormatPodMetrics(namespace string, pod string) PodMetrics { resultPod.MemoryLimit = Inf } else { data, _ := memoryLimitMetrics[0].GetNumber("value") - resultPod.MemoryLimit = data.String() + memoryLim, _ := data.Float64() + memoryLim = memoryLim / 1024 / 1024 + resultPod.MemoryLimit = fmt.Sprintf("%.1f", memoryLim) } cpuUsageRate := client.GetHeapsterMetricsJson("/namespaces/" + namespace + "/pods/" + pod + "/metrics/cpu/usage_rate") diff --git a/pkg/models/routes.go b/pkg/models/routes.go index 1c29c4322..2f7625b12 100644 --- a/pkg/models/routes.go +++ b/pkg/models/routes.go @@ -25,6 +25,10 @@ import ( metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/kubernetes/scheme" + "k8s.io/api/rbac/v1" + + "reflect" + "kubesphere.io/kubesphere/pkg/client" "kubesphere.io/kubesphere/pkg/constants" ) @@ -47,6 +51,64 @@ func GetAllRouters() ([]coreV1.Service, error) { return services.Items, nil } +func inArray(val interface{}, array interface{}) (exists bool) { + exists = false + + switch reflect.TypeOf(array).Kind() { + case reflect.Slice: + s := reflect.ValueOf(array) + + for i := 0; i < s.Len(); i++ { + if reflect.DeepEqual(val, s.Index(i).Interface()) == true { + exists = true + return + } + } + } + return exists +} + +func GetAllRoutersOfUser(username string) ([]coreV1.Service, error) { + + routers := make([]coreV1.Service, 0) + clusterRoles, err := GetClusterRoles(username) + + // return by cluster role + if err != nil { + glog.Error(err) + return routers, err + } else { + for _, clusterRole := range clusterRoles { + for _, rulePolicy := range clusterRole.Rules { + if (inArray(v1.VerbAll, rulePolicy.Verbs) || inArray("view", rulePolicy.Verbs)) && + (inArray(v1.ResourceAll, rulePolicy.Resources) || inArray("namespaces", rulePolicy.Resources)) { + return GetAllRouters() + } + } + } + } + + // return by role + roles, err := GetRoles(username) + if err != nil { + glog.Error(err) + return routers, err + } else { + for _, projectRole := range roles { + router, err := GetRouter(projectRole.Namespace) + if err != nil { + glog.Error(err) + return routers, err + } else if router != nil { + routers = append(routers, *router) + } + } + } + + return routers, nil + +} + // Get router from a namespace func GetRouter(namespace string) (*coreV1.Service, error) { k8sClient := client.NewK8sClient() @@ -131,6 +193,7 @@ func CreateRouter(namespace string, routerType coreV1.ServiceType, annotations m // Add project selector service.Labels["project"] = namespace + service.Spec.Selector["project"] = namespace service, err := k8sClient.CoreV1().Services(constants.IngressControllerNamespace).Create(service)