From 4368639580a7b097223baa7e526c627e6d9c53da Mon Sep 17 00:00:00 2001 From: hongming Date: Fri, 30 Aug 2019 16:14:33 +0800 Subject: [PATCH] feat: support horizontalpodautoscalers query Signed-off-by: hongming --- cmd/ks-apiserver/app/server.go | 1 + .../resources/horizontalpodautoscalers.go | 147 ++++++++++++++++++ pkg/models/resources/resources.go | 102 ++++++------ 3 files changed, 201 insertions(+), 49 deletions(-) create mode 100644 pkg/models/resources/horizontalpodautoscalers.go diff --git a/cmd/ks-apiserver/app/server.go b/cmd/ks-apiserver/app/server.go index fbd960770..78327eb3b 100644 --- a/cmd/ks-apiserver/app/server.go +++ b/cmd/ks-apiserver/app/server.go @@ -176,6 +176,7 @@ func waitForResourceSync() { informerFactory.Batch().V1().Jobs().Lister() informerFactory.Batch().V1beta1().CronJobs().Lister() informerFactory.Extensions().V1beta1().Ingresses().Lister() + informerFactory.Autoscaling().V2beta2().HorizontalPodAutoscalers().Lister() informerFactory.Start(stopChan) informerFactory.WaitForCacheSync(stopChan) diff --git a/pkg/models/resources/horizontalpodautoscalers.go b/pkg/models/resources/horizontalpodautoscalers.go new file mode 100644 index 000000000..b6fce14ce --- /dev/null +++ b/pkg/models/resources/horizontalpodautoscalers.go @@ -0,0 +1,147 @@ +/* + * + * Copyright 2019 The KubeSphere Authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * / + */ +package resources + +import ( + autoscalingv2beta2 "k8s.io/api/autoscaling/v2beta2" + "kubesphere.io/kubesphere/pkg/constants" + "kubesphere.io/kubesphere/pkg/informers" + "kubesphere.io/kubesphere/pkg/params" + "kubesphere.io/kubesphere/pkg/utils/sliceutil" + "sort" + "strings" + + "k8s.io/apimachinery/pkg/labels" +) + +type hpaSearcher struct { +} + +func (*hpaSearcher) get(namespace, name string) (interface{}, error) { + return informers.SharedInformerFactory().Autoscaling().V2beta2().HorizontalPodAutoscalers().Lister().HorizontalPodAutoscalers(namespace).Get(name) +} + +func hpaTargetMatch(item *autoscalingv2beta2.HorizontalPodAutoscaler, kind, name string) bool { + return item.Spec.ScaleTargetRef.Kind == kind && item.Spec.ScaleTargetRef.Name == name +} + +// exactly Match +func (*hpaSearcher) match(match map[string]string, item *autoscalingv2beta2.HorizontalPodAutoscaler) bool { + for k, v := range match { + switch k { + case TargetKind: + fallthrough + case TargetName: + kind := match[TargetKind] + name := match[TargetName] + if !hpaTargetMatch(item, kind, name) { + return false + } + case Name: + names := strings.Split(v, "|") + if !sliceutil.HasString(names, item.Name) { + return false + } + case Keyword: + if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) { + return false + } + default: + if item.Labels[k] != v { + return false + } + } + } + return true +} + +// Fuzzy searchInNamespace +func (*hpaSearcher) fuzzy(fuzzy map[string]string, item *autoscalingv2beta2.HorizontalPodAutoscaler) bool { + for k, v := range fuzzy { + switch k { + case Name: + if !strings.Contains(item.Name, v) && !strings.Contains(item.Annotations[constants.DisplayNameAnnotationKey], v) { + return false + } + case Label: + if !searchFuzzy(item.Labels, "", v) { + return false + } + case annotation: + if !searchFuzzy(item.Annotations, "", v) { + return false + } + return false + case app: + if !strings.Contains(item.Labels[chart], v) && !strings.Contains(item.Labels[release], v) { + return false + } + default: + if !searchFuzzy(item.Labels, k, v) && !searchFuzzy(item.Annotations, k, v) { + return false + } + } + } + return true +} + +func (*hpaSearcher) compare(a, b *autoscalingv2beta2.HorizontalPodAutoscaler, orderBy string) bool { + switch orderBy { + case CreateTime: + return a.CreationTimestamp.Time.Before(b.CreationTimestamp.Time) + case Name: + fallthrough + default: + return strings.Compare(a.Name, b.Name) <= 0 + } +} + +func (s *hpaSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) { + + horizontalPodAutoscalers, err := informers.SharedInformerFactory().Autoscaling().V2beta2().HorizontalPodAutoscalers().Lister().HorizontalPodAutoscalers(namespace).List(labels.Everything()) + + if err != nil { + return nil, err + } + + result := make([]*autoscalingv2beta2.HorizontalPodAutoscaler, 0) + + if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 { + result = horizontalPodAutoscalers + } else { + for _, item := range horizontalPodAutoscalers { + if s.match(conditions.Match, item) && s.fuzzy(conditions.Fuzzy, item) { + result = append(result, item) + } + } + } + sort.Slice(result, func(i, j int) bool { + if reverse { + tmp := i + i = j + j = tmp + } + return s.compare(result[i], result[j], orderBy) + }) + + r := make([]interface{}, 0) + for _, i := range result { + r = append(r, i) + } + return r, nil +} diff --git a/pkg/models/resources/resources.go b/pkg/models/resources/resources.go index 356c46017..85b02dae0 100644 --- a/pkg/models/resources/resources.go +++ b/pkg/models/resources/resources.go @@ -41,6 +41,7 @@ func init() { resources[Roles] = &roleSearcher{} resources[S2iBuilders] = &s2iBuilderSearcher{} resources[S2iRuns] = &s2iRunSearcher{} + resources[HorizontalPodAutoscalers] = &hpaSearcher{} resources[Nodes] = &nodeSearcher{} resources[Namespaces] = &namespaceSearcher{} @@ -57,55 +58,58 @@ var ( ) const ( - Name = "name" - Label = "label" - OwnerKind = "ownerKind" - OwnerName = "ownerName" - Role = "role" - CreateTime = "createTime" - UpdateTime = "updateTime" - LastScheduleTime = "lastScheduleTime" - chart = "chart" - release = "release" - annotation = "annotation" - Keyword = "keyword" - Status = "status" - includeCronJob = "includeCronJob" - storageClassName = "storageClassName" - cronJobKind = "CronJob" - s2iRunKind = "S2iRun" - includeS2iRun = "includeS2iRun" - StatusRunning = "running" - StatusPaused = "paused" - StatusPending = "pending" - StatusUpdating = "updating" - StatusStopped = "stopped" - StatusFailed = "failed" - StatusBound = "bound" - StatusLost = "lost" - StatusComplete = "complete" - app = "app" - Deployments = "deployments" - DaemonSets = "daemonsets" - Roles = "roles" - Workspaces = "workspaces" - WorkspaceRoles = "workspaceroles" - CronJobs = "cronjobs" - ConfigMaps = "configmaps" - Ingresses = "ingresses" - Jobs = "jobs" - PersistentVolumeClaims = "persistentvolumeclaims" - Pods = "pods" - Secrets = "secrets" - Services = "services" - StatefulSets = "statefulsets" - Nodes = "nodes" - Namespaces = "namespaces" - StorageClasses = "storageclasses" - ClusterRoles = "clusterroles" - S2iBuilderTemplates = "s2ibuildertemplates" - S2iBuilders = "s2ibuilders" - S2iRuns = "s2iruns" + Name = "name" + Label = "label" + OwnerKind = "ownerKind" + OwnerName = "ownerName" + TargetKind = "targetKind" + TargetName = "targetName" + Role = "role" + CreateTime = "createTime" + UpdateTime = "updateTime" + LastScheduleTime = "lastScheduleTime" + chart = "chart" + release = "release" + annotation = "annotation" + Keyword = "keyword" + Status = "status" + includeCronJob = "includeCronJob" + storageClassName = "storageClassName" + cronJobKind = "CronJob" + s2iRunKind = "S2iRun" + includeS2iRun = "includeS2iRun" + StatusRunning = "running" + StatusPaused = "paused" + StatusPending = "pending" + StatusUpdating = "updating" + StatusStopped = "stopped" + StatusFailed = "failed" + StatusBound = "bound" + StatusLost = "lost" + StatusComplete = "complete" + app = "app" + Deployments = "deployments" + DaemonSets = "daemonsets" + Roles = "roles" + Workspaces = "workspaces" + WorkspaceRoles = "workspaceroles" + CronJobs = "cronjobs" + ConfigMaps = "configmaps" + Ingresses = "ingresses" + Jobs = "jobs" + PersistentVolumeClaims = "persistentvolumeclaims" + Pods = "pods" + Secrets = "secrets" + Services = "services" + StatefulSets = "statefulsets" + HorizontalPodAutoscalers = "horizontalpodautoscalers" + Nodes = "nodes" + Namespaces = "namespaces" + StorageClasses = "storageclasses" + ClusterRoles = "clusterroles" + S2iBuilderTemplates = "s2ibuildertemplates" + S2iBuilders = "s2ibuilders" + S2iRuns = "s2iruns" ) type resourceSearchInterface interface {