refactor monitoring (#1751)
Signed-off-by: huanggze <loganhuang@yunify.com>
This commit is contained in:
69
pkg/models/monitoring/monitoring.go
Normal file
69
pkg/models/monitoring/monitoring.go
Normal file
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
|
||||
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 monitoring
|
||||
|
||||
import (
|
||||
"k8s.io/klog"
|
||||
"kubesphere.io/kubesphere/pkg/api/monitoring/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/monitoring"
|
||||
"time"
|
||||
)
|
||||
|
||||
type MonitoringOperator interface {
|
||||
GetMetrics(stmts []string, time time.Time) (v1alpha2.APIResponse, error)
|
||||
GetMetricsOverTime(stmts []string, start, end time.Time, step time.Duration) (v1alpha2.APIResponse, error)
|
||||
GetNamedMetrics(time time.Time, opt monitoring.QueryOption) (v1alpha2.APIResponse, error)
|
||||
GetNamedMetricsOverTime(start, end time.Time, step time.Duration, opt monitoring.QueryOption) (v1alpha2.APIResponse, error)
|
||||
SortMetrics(raw v1alpha2.APIResponse, target, order, identifier string) (v1alpha2.APIResponse, int)
|
||||
PageMetrics(raw v1alpha2.APIResponse, page, limit, rows int) v1alpha2.APIResponse
|
||||
}
|
||||
|
||||
type monitoringOperator struct {
|
||||
c monitoring.Interface
|
||||
}
|
||||
|
||||
func NewMonitoringOperator(client monitoring.Interface) MonitoringOperator {
|
||||
return &monitoringOperator{client}
|
||||
}
|
||||
|
||||
// TODO(huanggze): reserve for custom monitoring
|
||||
func (mo monitoringOperator) GetMetrics(stmts []string, time time.Time) (v1alpha2.APIResponse, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
// TODO(huanggze): reserve for custom monitoring
|
||||
func (mo monitoringOperator) GetMetricsOverTime(stmts []string, start, end time.Time, step time.Duration) (v1alpha2.APIResponse, error) {
|
||||
panic("implement me")
|
||||
}
|
||||
|
||||
func (mo monitoringOperator) GetNamedMetrics(time time.Time, opt monitoring.QueryOption) (v1alpha2.APIResponse, error) {
|
||||
metrics, err := mo.c.GetNamedMetrics(time, opt)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
return v1alpha2.APIResponse{Results: metrics}, err
|
||||
}
|
||||
|
||||
func (mo monitoringOperator) GetNamedMetricsOverTime(start, end time.Time, step time.Duration, opt monitoring.QueryOption) (v1alpha2.APIResponse, error) {
|
||||
metrics, err := mo.c.GetNamedMetricsOverTime(start, end, step, opt)
|
||||
if err != nil {
|
||||
klog.Error(err)
|
||||
}
|
||||
return v1alpha2.APIResponse{Results: metrics}, err
|
||||
}
|
||||
64
pkg/models/monitoring/namespaces.go
Normal file
64
pkg/models/monitoring/namespaces.go
Normal file
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
|
||||
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 monitoring
|
||||
|
||||
import "k8s.io/api/core/v1"
|
||||
|
||||
// TODO(wansir): Can we decouple this part from monitoring module, since the project structure has been changed
|
||||
func GetNamespacesWithMetrics(namespaces []*v1.Namespace) []*v1.Namespace {
|
||||
// var nsNameList []string
|
||||
// for i := range namespaces {
|
||||
// nsNameList = append(nsNameList, namespaces[i].Name)
|
||||
// }
|
||||
// nsFilter := "^(" + strings.Join(nsNameList, "|") + ")$"
|
||||
//
|
||||
// now := time.Now()
|
||||
// opt := &monitoring.QueryOptions{
|
||||
// Level: monitoring.MetricsLevelNamespace,
|
||||
// ResourcesFilter: nsFilter,
|
||||
// Start: now,
|
||||
// End: now,
|
||||
// MetricsFilter: "namespace_cpu_usage|namespace_memory_usage_wo_cache|namespace_pod_count",
|
||||
// }
|
||||
//
|
||||
// gm, err := monitoring.Get(opt)
|
||||
// if err != nil {
|
||||
// klog.Error(err)
|
||||
// return namespaces
|
||||
// }
|
||||
//
|
||||
// for _, m := range gm.Results {
|
||||
// for _, v := range m.Data.MetricsValues {
|
||||
// ns, exist := v.Metadata["namespace"]
|
||||
// if !exist {
|
||||
// continue
|
||||
// }
|
||||
//
|
||||
// for _, item := range namespaces {
|
||||
// if item.Name == ns {
|
||||
// if item.Annotations == nil {
|
||||
// item.Annotations = make(map[string]string, 0)
|
||||
// }
|
||||
// item.Annotations[m.MetricsName] = strconv.FormatFloat(v.Sample[1], 'f', -1, 64)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
return namespaces
|
||||
}
|
||||
204
pkg/models/monitoring/sort_page.go
Normal file
204
pkg/models/monitoring/sort_page.go
Normal file
@@ -0,0 +1,204 @@
|
||||
/*
|
||||
|
||||
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 monitoring
|
||||
|
||||
import (
|
||||
"kubesphere.io/kubesphere/pkg/api/monitoring/v1alpha2"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/monitoring"
|
||||
"math"
|
||||
"sort"
|
||||
)
|
||||
|
||||
// TODO(huanggze): the id value is dependent of Prometheus label-value pair (i.e. label_kubesphere_io_workspace). We should regulate the naming convention.
|
||||
const (
|
||||
IdentifierNode = "node"
|
||||
IdentifierWorkspace = "label_kubesphere_io_workspace"
|
||||
IdentifierNamespace = "namespace"
|
||||
IdentifierWorkload = "workload"
|
||||
IdentifierPod = "pod"
|
||||
IdentifierContainer = "container"
|
||||
IdentifierPVC = "persistentvolumeclaim"
|
||||
|
||||
OrderAscending = "asc"
|
||||
OrderDescending = "desc"
|
||||
)
|
||||
|
||||
type wrapper struct {
|
||||
monitoring.MetricData
|
||||
by func(p, q *monitoring.MetricValue) bool
|
||||
}
|
||||
|
||||
func (w wrapper) Len() int {
|
||||
return len(w.MetricValues)
|
||||
}
|
||||
|
||||
func (w wrapper) Less(i, j int) bool {
|
||||
return w.by(&w.MetricValues[i], &w.MetricValues[j])
|
||||
}
|
||||
|
||||
func (w wrapper) Swap(i, j int) {
|
||||
w.MetricValues[i], w.MetricValues[j] = w.MetricValues[j], w.MetricValues[i]
|
||||
}
|
||||
|
||||
// The sortMetrics sorts a group of resources by a given metric
|
||||
// Example:
|
||||
//
|
||||
// before sorting
|
||||
// |------| Metric 1 | Metric 2 | Metric 3 |
|
||||
// | ID a | 1 | XL | |
|
||||
// | ID b | 1 | S | |
|
||||
// | ID c | 3 | M | |
|
||||
//
|
||||
// sort by metrics_2
|
||||
// |------| Metric 1 | Metric 2 (asc) | Metric 3 |
|
||||
// | ID a | 1 | XL | |
|
||||
// | ID c | 3 | M | |
|
||||
// | ID b | 1 | S | |
|
||||
//
|
||||
// ranking can only be applied to instant query results, not range query
|
||||
func (mo monitoringOperator) SortMetrics(raw v1alpha2.APIResponse, target, order, identifier string) (v1alpha2.APIResponse, int) {
|
||||
if target == "" || len(raw.Results) == 0 {
|
||||
return raw, -1
|
||||
}
|
||||
|
||||
if order == "" {
|
||||
order = OrderDescending
|
||||
}
|
||||
|
||||
var currentResourceMap = make(map[string]int)
|
||||
|
||||
// resource-ordinal map
|
||||
var indexMap = make(map[string]int)
|
||||
i := 0
|
||||
|
||||
for _, item := range raw.Results {
|
||||
if item.MetricType == monitoring.MetricTypeVector && item.Status == monitoring.StatusSuccess {
|
||||
if item.MetricName == target {
|
||||
if order == OrderAscending {
|
||||
sort.Sort(wrapper{item.MetricData, func(p, q *monitoring.MetricValue) bool {
|
||||
if p.Sample[1] == q.Sample[1] {
|
||||
return p.Metadata[identifier] < q.Metadata[identifier]
|
||||
}
|
||||
return p.Sample[1] < q.Sample[1]
|
||||
}})
|
||||
} else {
|
||||
sort.Sort(wrapper{item.MetricData, func(p, q *monitoring.MetricValue) bool {
|
||||
if p.Sample[1] == q.Sample[1] {
|
||||
return p.Metadata[identifier] > q.Metadata[identifier]
|
||||
}
|
||||
return p.Sample[1] > q.Sample[1]
|
||||
}})
|
||||
}
|
||||
|
||||
for _, r := range item.MetricValues {
|
||||
// record the ordinal of resource to indexMap
|
||||
resourceName, exist := r.Metadata[identifier]
|
||||
if exist {
|
||||
if _, exist := indexMap[resourceName]; !exist {
|
||||
indexMap[resourceName] = i
|
||||
i = i + 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// get total number of rows
|
||||
for _, r := range item.MetricValues {
|
||||
k, ok := r.Metadata[identifier]
|
||||
if ok {
|
||||
currentResourceMap[k] = 1
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
var keys []string
|
||||
for k := range currentResourceMap {
|
||||
keys = append(keys, k)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
|
||||
for _, resource := range keys {
|
||||
if _, exist := indexMap[resource]; !exist {
|
||||
indexMap[resource] = i
|
||||
i = i + 1
|
||||
}
|
||||
}
|
||||
|
||||
// sort other metrics
|
||||
for i := 0; i < len(raw.Results); i++ {
|
||||
item := raw.Results[i]
|
||||
if item.MetricType == monitoring.MetricTypeVector && item.Status == monitoring.StatusSuccess {
|
||||
sortedMetric := make([]monitoring.MetricValue, len(indexMap))
|
||||
for j := 0; j < len(item.MetricValues); j++ {
|
||||
r := item.MetricValues[j]
|
||||
k, exist := r.Metadata[identifier]
|
||||
if exist {
|
||||
index, exist := indexMap[k]
|
||||
if exist {
|
||||
sortedMetric[index] = r
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
raw.Results[i].MetricValues = sortedMetric
|
||||
}
|
||||
}
|
||||
|
||||
return raw, len(indexMap)
|
||||
}
|
||||
|
||||
func (mo monitoringOperator) PageMetrics(raw v1alpha2.APIResponse, page, limit, rows int) v1alpha2.APIResponse {
|
||||
if page <= 0 || limit <= 0 || rows <= 0 || len(raw.Results) == 0 {
|
||||
return raw
|
||||
}
|
||||
|
||||
// matrix type can not be sorted
|
||||
for _, item := range raw.Results {
|
||||
if item.MetricType != monitoring.MetricTypeVector {
|
||||
return raw
|
||||
}
|
||||
}
|
||||
|
||||
// the i page: [(page-1) * limit, (page) * limit - 1]
|
||||
start := (page - 1) * limit
|
||||
end := (page)*limit - 1
|
||||
|
||||
for i := 0; i < len(raw.Results); i++ {
|
||||
if raw.Results[i].MetricType != monitoring.MetricTypeVector || raw.Results[i].Status != monitoring.StatusSuccess {
|
||||
continue
|
||||
}
|
||||
resultLen := len(raw.Results[i].MetricValues)
|
||||
if start >= resultLen {
|
||||
raw.Results[i].MetricValues = nil
|
||||
continue
|
||||
}
|
||||
if end >= resultLen {
|
||||
end = resultLen - 1
|
||||
}
|
||||
slice := raw.Results[i].MetricValues[start : end+1]
|
||||
raw.Results[i].MetricValues = slice
|
||||
}
|
||||
|
||||
raw.CurrentPage = page
|
||||
raw.TotalPage = int(math.Ceil(float64(rows) / float64(limit)))
|
||||
raw.TotalItem = rows
|
||||
return raw
|
||||
}
|
||||
Reference in New Issue
Block a user