Merge remote-tracking branch 'upstream/master'
# Conflicts: # cmd/ks-apiserver/app/server.go
This commit is contained in:
30
pkg/models/log/constants.go
Normal file
30
pkg/models/log/constants.go
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
|
||||
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 log
|
||||
|
||||
type LogQueryLevel int
|
||||
|
||||
const (
|
||||
QueryLevelCluster LogQueryLevel = iota
|
||||
QueryLevelWorkspace
|
||||
QueryLevelNamespace
|
||||
QueryLevelWorkload
|
||||
QueryLevelPod
|
||||
QueryLevelContainer
|
||||
)
|
||||
309
pkg/models/log/logcollector.go
Normal file
309
pkg/models/log/logcollector.go
Normal file
@@ -0,0 +1,309 @@
|
||||
/*
|
||||
|
||||
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 log
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"reflect"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func intersection(s1, s2 []string) (inter []string) {
|
||||
hash := make(map[string]bool)
|
||||
for _, e := range s1 {
|
||||
hash[e] = true
|
||||
}
|
||||
for _, e := range s2 {
|
||||
// If elements present in the hashmap then append intersection list.
|
||||
if hash[e] {
|
||||
inter = append(inter, e)
|
||||
}
|
||||
}
|
||||
//Remove dups from slice.
|
||||
inter = removeDups(inter)
|
||||
return
|
||||
}
|
||||
|
||||
//Remove dups from slice.
|
||||
func removeDups(elements []string) (nodups []string) {
|
||||
encountered := make(map[string]bool)
|
||||
for _, element := range elements {
|
||||
if !encountered[element] {
|
||||
nodups = append(nodups, element)
|
||||
encountered[element] = true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func in(value interface{}, container interface{}) int {
|
||||
if container == nil {
|
||||
return -1
|
||||
}
|
||||
containerValue := reflect.ValueOf(container)
|
||||
switch reflect.TypeOf(container).Kind() {
|
||||
case reflect.Slice, reflect.Array:
|
||||
for i := 0; i < containerValue.Len(); i++ {
|
||||
if containerValue.Index(i).Interface() == value {
|
||||
return i
|
||||
}
|
||||
}
|
||||
case reflect.Map:
|
||||
if containerValue.MapIndex(reflect.ValueOf(value)).IsValid() {
|
||||
return -1
|
||||
}
|
||||
default:
|
||||
return -1
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
func getWorkloadName(name string, kind string) string {
|
||||
if kind == "ReplicaSet" {
|
||||
lastIndex := strings.LastIndex(name, "-")
|
||||
if lastIndex >= 0 {
|
||||
return name[:lastIndex]
|
||||
}
|
||||
}
|
||||
|
||||
return name
|
||||
}
|
||||
|
||||
func matchLabel(label string, labelsMatch []string) bool {
|
||||
var result = false
|
||||
|
||||
for _, labelMatch := range labelsMatch {
|
||||
if strings.Compare(label, labelMatch) == 0 {
|
||||
result = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func queryLabel(label string, labelsQuery []string) bool {
|
||||
var result = false
|
||||
|
||||
for _, labelQuery := range labelsQuery {
|
||||
if strings.Contains(label, labelQuery) {
|
||||
result = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
func QueryWorkspace(workspaceMatch string, workspaceQuery string) (bool, []string) {
|
||||
if workspaceMatch == "" && workspaceQuery == "" {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
nsLister := informers.SharedInformerFactory().Core().V1().Namespaces().Lister()
|
||||
nsList, err := nsLister.List(labels.Everything())
|
||||
if err != nil {
|
||||
glog.Error("failed to list namespace, error: ", err)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
var namespaces []string
|
||||
|
||||
var hasMatch = false
|
||||
var workspacesMatch []string
|
||||
if workspaceMatch != "" {
|
||||
workspacesMatch = strings.Split(strings.Replace(workspaceMatch, ",", " ", -1), " ")
|
||||
hasMatch = true
|
||||
}
|
||||
|
||||
var hasQuery = false
|
||||
var workspacesQuery []string
|
||||
if workspaceQuery != "" {
|
||||
workspacesQuery = strings.Split(strings.ToLower(strings.Replace(workspaceQuery, ",", " ", -1)), " ")
|
||||
hasQuery = true
|
||||
}
|
||||
|
||||
for _, ns := range nsList {
|
||||
labels := ns.GetLabels()
|
||||
_, ok := labels[constants.WorkspaceLabelKey]
|
||||
if ok {
|
||||
var namespaceCanAppend = true
|
||||
if hasMatch {
|
||||
if !matchLabel(labels[constants.WorkspaceLabelKey], workspacesMatch) {
|
||||
namespaceCanAppend = false
|
||||
}
|
||||
}
|
||||
if hasQuery {
|
||||
if !queryLabel(strings.ToLower(labels[constants.WorkspaceLabelKey]), workspacesQuery) {
|
||||
namespaceCanAppend = false
|
||||
}
|
||||
}
|
||||
|
||||
if namespaceCanAppend {
|
||||
namespaces = append(namespaces, ns.GetName())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true, namespaces
|
||||
}
|
||||
|
||||
func MatchNamespace(namespaceMatch string, namespaceFilled bool, namespaces []string) (bool, []string) {
|
||||
if namespaceMatch == "" {
|
||||
return namespaceFilled, namespaces
|
||||
}
|
||||
|
||||
namespacesMatch := strings.Split(strings.Replace(namespaceMatch, ",", " ", -1), " ")
|
||||
|
||||
if namespaceFilled {
|
||||
return true, intersection(namespacesMatch, namespaces)
|
||||
}
|
||||
|
||||
return true, namespacesMatch
|
||||
}
|
||||
|
||||
func QueryWorkload(workloadMatch string, workloadQuery string, namespaces []string) (bool, []string) {
|
||||
if workloadMatch == "" && workloadQuery == "" {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
podLister := informers.SharedInformerFactory().Core().V1().Pods().Lister()
|
||||
podList, err := podLister.List(labels.Everything())
|
||||
if err != nil {
|
||||
glog.Error("failed to list pods, error: ", err)
|
||||
return true, nil
|
||||
}
|
||||
|
||||
var pods []string
|
||||
|
||||
var hasMatch = false
|
||||
var workloadsMatch []string
|
||||
if workloadMatch != "" {
|
||||
workloadsMatch = strings.Split(strings.Replace(workloadMatch, ",", " ", -1), " ")
|
||||
hasMatch = true
|
||||
}
|
||||
|
||||
var hasQuery = false
|
||||
var workloadsQuery []string
|
||||
if workloadQuery != "" {
|
||||
workloadsQuery = strings.Split(strings.ToLower(strings.Replace(workloadQuery, ",", " ", -1)), " ")
|
||||
hasQuery = true
|
||||
}
|
||||
|
||||
if namespaces == nil {
|
||||
for _, pod := range podList {
|
||||
/*if len(pod.ObjectMeta.OwnerReferences) > 0 {
|
||||
glog.Infof("List Pod %v:%v:%v", pod.Name, pod.ObjectMeta.OwnerReferences[0].Name, pod.ObjectMeta.OwnerReferences[0].Kind)
|
||||
}*/
|
||||
if len(pod.ObjectMeta.OwnerReferences) > 0 {
|
||||
var podCanAppend = true
|
||||
workloadName := getWorkloadName(pod.ObjectMeta.OwnerReferences[0].Name, pod.ObjectMeta.OwnerReferences[0].Kind)
|
||||
if hasMatch {
|
||||
if !matchLabel(workloadName, workloadsMatch) {
|
||||
podCanAppend = false
|
||||
}
|
||||
}
|
||||
if hasQuery {
|
||||
if !queryLabel(strings.ToLower(workloadName), workloadsQuery) {
|
||||
podCanAppend = false
|
||||
}
|
||||
}
|
||||
|
||||
if podCanAppend {
|
||||
pods = append(pods, pod.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for _, pod := range podList {
|
||||
/*if len(pod.ObjectMeta.OwnerReferences) > 0 {
|
||||
glog.Infof("List Pod %v:%v:%v", pod.Name, pod.ObjectMeta.OwnerReferences[0].Name, pod.ObjectMeta.OwnerReferences[0].Kind)
|
||||
}*/
|
||||
if len(pod.ObjectMeta.OwnerReferences) > 0 && in(pod.Namespace, namespaces) >= 0 {
|
||||
var podCanAppend = true
|
||||
workloadName := getWorkloadName(pod.ObjectMeta.OwnerReferences[0].Name, pod.ObjectMeta.OwnerReferences[0].Kind)
|
||||
if hasMatch {
|
||||
if !matchLabel(workloadName, workloadsMatch) {
|
||||
podCanAppend = false
|
||||
}
|
||||
}
|
||||
if hasQuery {
|
||||
if !queryLabel(strings.ToLower(workloadName), workloadsQuery) {
|
||||
podCanAppend = false
|
||||
}
|
||||
}
|
||||
|
||||
if podCanAppend {
|
||||
pods = append(pods, pod.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true, pods
|
||||
}
|
||||
|
||||
func MatchPod(podMatch string, podFilled bool, pods []string) (bool, []string) {
|
||||
if podMatch == "" {
|
||||
return podFilled, pods
|
||||
}
|
||||
|
||||
podsMatch := strings.Split(strings.Replace(podMatch, ",", " ", -1), " ")
|
||||
|
||||
if podFilled {
|
||||
return true, intersection(podsMatch, pods)
|
||||
}
|
||||
|
||||
return true, podsMatch
|
||||
}
|
||||
|
||||
func MatchContainer(containerMatch string) (bool, []string) {
|
||||
if containerMatch == "" {
|
||||
return false, nil
|
||||
}
|
||||
|
||||
return true, strings.Split(strings.Replace(containerMatch, ",", " ", -1), " ")
|
||||
}
|
||||
|
||||
func GetWorkspaceOfNamesapce(namespace string) string {
|
||||
var workspace string
|
||||
workspace = ""
|
||||
|
||||
nsLister := informers.SharedInformerFactory().Core().V1().Namespaces().Lister()
|
||||
nsList, err := nsLister.List(labels.Everything())
|
||||
if err != nil {
|
||||
glog.Error("failed to list namespace, error: ", err)
|
||||
return workspace
|
||||
}
|
||||
|
||||
for _, ns := range nsList {
|
||||
if ns.GetName() == namespace {
|
||||
labels := ns.GetLabels()
|
||||
_, ok := labels[constants.WorkspaceLabelKey]
|
||||
if ok {
|
||||
workspace = labels[constants.WorkspaceLabelKey]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return workspace
|
||||
}
|
||||
543
pkg/models/log/logcrd.go
Normal file
543
pkg/models/log/logcrd.go
Normal file
@@ -0,0 +1,543 @@
|
||||
/*
|
||||
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 log
|
||||
|
||||
import (
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/golang/glog"
|
||||
"github.com/google/uuid"
|
||||
"github.com/json-iterator/go"
|
||||
corev1 "k8s.io/api/core/v1"
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"k8s.io/apimachinery/pkg/runtime"
|
||||
"k8s.io/client-go/kubernetes"
|
||||
"k8s.io/client-go/rest"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
es "kubesphere.io/kubesphere/pkg/simple/client/elasticsearch"
|
||||
fb "kubesphere.io/kubesphere/pkg/simple/client/fluentbit"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
var jsonIter = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
|
||||
const (
|
||||
ConfigMapName = "fluent-bit-output-config"
|
||||
ConfigMapData = "outputs"
|
||||
LoggingNamespace = "kubesphere-logging-system"
|
||||
)
|
||||
|
||||
func createCRDClientSet() (*rest.RESTClient, *runtime.Scheme, error) {
|
||||
config, err := fb.GetClientConfig("")
|
||||
if err != nil {
|
||||
//panic(err.Error())
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
// Create a new clientset which include our CRD schema
|
||||
return fb.NewFluentbitCRDClient(config)
|
||||
}
|
||||
|
||||
func getParameterValue(parameters []fb.Parameter, name string) string {
|
||||
var value string
|
||||
|
||||
value = ""
|
||||
for _, parameter := range parameters {
|
||||
if parameter.Name == name {
|
||||
value = parameter.Value
|
||||
}
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func getFilters(result *FluentbitFiltersResult, Filters []fb.Plugin) {
|
||||
for _, filter := range Filters {
|
||||
if strings.Compare(filter.Name, "fluentbit-filter-input-regex") == 0 {
|
||||
parameters := strings.Split(getParameterValue(filter.Parameters, "Regex"), " ")
|
||||
field := strings.TrimSuffix(strings.TrimPrefix(parameters[0], "kubernetes_"), "_name")
|
||||
expression := parameters[1]
|
||||
result.Filters = append(result.Filters, FluentbitFilter{"Regex", field, expression})
|
||||
}
|
||||
if strings.Compare(filter.Name, "fluentbit-filter-input-exclude") == 0 {
|
||||
parameters := strings.Split(getParameterValue(filter.Parameters, "Exclude"), " ")
|
||||
field := strings.TrimSuffix(strings.TrimPrefix(parameters[0], "kubernetes_"), "_name")
|
||||
expression := parameters[1]
|
||||
result.Filters = append(result.Filters, FluentbitFilter{"Exclude", field, expression})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func FluentbitFiltersQuery() *FluentbitFiltersResult {
|
||||
var result FluentbitFiltersResult
|
||||
|
||||
crdcs, scheme, err := createCRDClientSet()
|
||||
if err != nil {
|
||||
result.Status = http.StatusInternalServerError
|
||||
return &result
|
||||
}
|
||||
|
||||
// Create a CRD client interface
|
||||
crdclient := fb.CrdClient(crdcs, scheme, LoggingNamespace)
|
||||
|
||||
item, err := crdclient.Get("fluent-bit")
|
||||
if err != nil {
|
||||
result.Status = http.StatusInternalServerError
|
||||
return &result
|
||||
}
|
||||
|
||||
getFilters(&result, item.Spec.Filter)
|
||||
|
||||
result.Status = http.StatusOK
|
||||
|
||||
return &result
|
||||
}
|
||||
|
||||
func FluentbitFiltersUpdate(filters *[]FluentbitFilter) *FluentbitFiltersResult {
|
||||
var result FluentbitFiltersResult
|
||||
|
||||
//Generate filter plugin config
|
||||
var filter []fb.Plugin
|
||||
|
||||
var para_kubernetes []fb.Parameter
|
||||
para_kubernetes = append(para_kubernetes, fb.Parameter{Name: "Name", Value: "kubernetes"})
|
||||
para_kubernetes = append(para_kubernetes, fb.Parameter{Name: "Match", Value: "kube.*"})
|
||||
para_kubernetes = append(para_kubernetes, fb.Parameter{Name: "Kube_URL", Value: "https://kubernetes.default.svc:443"})
|
||||
para_kubernetes = append(para_kubernetes, fb.Parameter{Name: "Kube_CA_File", Value: "/var/run/secrets/kubernetes.io/serviceaccount/ca.crt"})
|
||||
para_kubernetes = append(para_kubernetes, fb.Parameter{Name: "Kube_Token_File", Value: "/var/run/secrets/kubernetes.io/serviceaccount/token"})
|
||||
filter = append(filter, fb.Plugin{Type: "fluentbit_filter", Name: "fluentbit-filter-kubernetes", Parameters: para_kubernetes})
|
||||
|
||||
var para_lift []fb.Parameter
|
||||
para_lift = append(para_lift, fb.Parameter{Name: "Name", Value: "nest"})
|
||||
para_lift = append(para_lift, fb.Parameter{Name: "Match", Value: "kube.*"})
|
||||
para_lift = append(para_lift, fb.Parameter{Name: "Operation", Value: "lift"})
|
||||
para_lift = append(para_lift, fb.Parameter{Name: "Nested_under", Value: "kubernetes"})
|
||||
para_lift = append(para_lift, fb.Parameter{Name: "Prefix_with", Value: "kubernetes_"})
|
||||
filter = append(filter, fb.Plugin{Type: "fluentbit_filter", Name: "fluentbit-filter-input-lift", Parameters: para_lift})
|
||||
|
||||
var para_remove_stream []fb.Parameter
|
||||
para_remove_stream = append(para_remove_stream, fb.Parameter{Name: "Name", Value: "modify"})
|
||||
para_remove_stream = append(para_remove_stream, fb.Parameter{Name: "Match", Value: "kube.*"})
|
||||
para_remove_stream = append(para_remove_stream, fb.Parameter{Name: "Remove", Value: "stream"})
|
||||
filter = append(filter, fb.Plugin{Type: "fluentbit_filter", Name: "fluentbit-filter-input-remove-stream", Parameters: para_remove_stream})
|
||||
|
||||
var para_remove_labels []fb.Parameter
|
||||
para_remove_labels = append(para_remove_labels, fb.Parameter{Name: "Name", Value: "modify"})
|
||||
para_remove_labels = append(para_remove_labels, fb.Parameter{Name: "Match", Value: "kube.*"})
|
||||
para_remove_labels = append(para_remove_labels, fb.Parameter{Name: "Remove", Value: "kubernetes_labels"})
|
||||
filter = append(filter, fb.Plugin{Type: "fluentbit_filter", Name: "fluentbit-filter-input-remove-labels", Parameters: para_remove_labels})
|
||||
|
||||
var para_remove_annotations []fb.Parameter
|
||||
para_remove_annotations = append(para_remove_annotations, fb.Parameter{Name: "Name", Value: "modify"})
|
||||
para_remove_annotations = append(para_remove_annotations, fb.Parameter{Name: "Match", Value: "kube.*"})
|
||||
para_remove_annotations = append(para_remove_annotations, fb.Parameter{Name: "Remove", Value: "kubernetes_annotations"})
|
||||
filter = append(filter, fb.Plugin{Type: "fluentbit_filter", Name: "fluentbit-filter-input-remove-annotations", Parameters: para_remove_annotations})
|
||||
|
||||
var para_remove_pod_id []fb.Parameter
|
||||
para_remove_pod_id = append(para_remove_pod_id, fb.Parameter{Name: "Name", Value: "modify"})
|
||||
para_remove_pod_id = append(para_remove_pod_id, fb.Parameter{Name: "Match", Value: "kube.*"})
|
||||
para_remove_pod_id = append(para_remove_pod_id, fb.Parameter{Name: "Remove", Value: "kubernetes_pod_id"})
|
||||
filter = append(filter, fb.Plugin{Type: "fluentbit_filter", Name: "fluentbit-filter-input-remove-podid", Parameters: para_remove_pod_id})
|
||||
|
||||
var para_remove_docker_id []fb.Parameter
|
||||
para_remove_docker_id = append(para_remove_docker_id, fb.Parameter{Name: "Name", Value: "modify"})
|
||||
para_remove_docker_id = append(para_remove_docker_id, fb.Parameter{Name: "Match", Value: "kube.*"})
|
||||
para_remove_docker_id = append(para_remove_docker_id, fb.Parameter{Name: "Remove", Value: "kubernetes_docker_id"})
|
||||
filter = append(filter, fb.Plugin{Type: "fluentbit_filter", Name: "fluentbit-filter-input-remove-dockerid", Parameters: para_remove_docker_id})
|
||||
|
||||
if len(*filters) > 0 {
|
||||
for _, item := range *filters {
|
||||
if strings.Compare(item.Type, "Regex") == 0 {
|
||||
field := "kubernetes_" + strings.TrimSpace(item.Field) + "_name"
|
||||
expression := strings.TrimSpace(item.Expression)
|
||||
|
||||
var para_regex []fb.Parameter
|
||||
para_regex = append(para_regex, fb.Parameter{Name: "Name", Value: "grep"})
|
||||
para_regex = append(para_regex, fb.Parameter{Name: "Match", Value: "kube.*"})
|
||||
para_regex = append(para_regex, fb.Parameter{Name: "Regex", Value: field + " " + expression})
|
||||
filter = append(filter, fb.Plugin{Type: "fluentbit_filter", Name: "fluentbit-filter-input-regex", Parameters: para_regex})
|
||||
}
|
||||
|
||||
if strings.Compare(item.Type, "Exclude") == 0 {
|
||||
field := "kubernetes_" + strings.TrimSpace(item.Field) + "_name"
|
||||
expression := strings.TrimSpace(item.Expression)
|
||||
|
||||
var para_exclude []fb.Parameter
|
||||
para_exclude = append(para_exclude, fb.Parameter{Name: "Name", Value: "grep"})
|
||||
para_exclude = append(para_exclude, fb.Parameter{Name: "Match", Value: "kube.*"})
|
||||
para_exclude = append(para_exclude, fb.Parameter{Name: "Exclude", Value: field + " " + expression})
|
||||
filter = append(filter, fb.Plugin{Type: "fluentbit_filter", Name: "fluentbit-filter-input-exclude", Parameters: para_exclude})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var para_nest []fb.Parameter
|
||||
para_nest = append(para_nest, fb.Parameter{Name: "Name", Value: "nest"})
|
||||
para_nest = append(para_nest, fb.Parameter{Name: "Match", Value: "kube.*"})
|
||||
para_nest = append(para_nest, fb.Parameter{Name: "Operation", Value: "nest"})
|
||||
para_nest = append(para_nest, fb.Parameter{Name: "Wildcard", Value: "kubernetes_*"})
|
||||
para_nest = append(para_nest, fb.Parameter{Name: "Nested_under", Value: "kubernetes"})
|
||||
para_nest = append(para_nest, fb.Parameter{Name: "Remove_prefix", Value: "kubernetes_"})
|
||||
filter = append(filter, fb.Plugin{Type: "fluentbit_filter", Name: "fluentbit-filter-input-nest", Parameters: para_nest})
|
||||
|
||||
crdcs, scheme, err := createCRDClientSet()
|
||||
if err != nil {
|
||||
result.Status = http.StatusInternalServerError
|
||||
return &result
|
||||
}
|
||||
|
||||
// Create a CRD client interface
|
||||
crdclient := fb.CrdClient(crdcs, scheme, LoggingNamespace)
|
||||
|
||||
var item *fb.FluentBit
|
||||
var err_read error
|
||||
|
||||
item, err_read = crdclient.Get("fluent-bit")
|
||||
if err_read != nil {
|
||||
result.Status = http.StatusInternalServerError
|
||||
return &result
|
||||
}
|
||||
|
||||
item.Spec.Filter = filter
|
||||
|
||||
itemnew, err := crdclient.Update("fluent-bit", item)
|
||||
if err != nil {
|
||||
result.Status = http.StatusInternalServerError
|
||||
return &result
|
||||
}
|
||||
|
||||
getFilters(&result, itemnew.Spec.Filter)
|
||||
result.Status = http.StatusOK
|
||||
|
||||
return &result
|
||||
}
|
||||
|
||||
func FluentbitOutputsQuery() *FluentbitOutputsResult {
|
||||
var result FluentbitOutputsResult
|
||||
|
||||
outputs, err := GetFluentbitOutputFromConfigMap()
|
||||
if err != nil {
|
||||
result.Status = http.StatusNotFound
|
||||
return &result
|
||||
}
|
||||
|
||||
result.Outputs = outputs
|
||||
result.Status = http.StatusOK
|
||||
|
||||
return &result
|
||||
}
|
||||
|
||||
func FluentbitOutputInsert(output fb.OutputPlugin) *FluentbitOutputsResult {
|
||||
var result FluentbitOutputsResult
|
||||
|
||||
// 1. Update ConfigMap
|
||||
var outputs []fb.OutputPlugin
|
||||
outputs, err := GetFluentbitOutputFromConfigMap()
|
||||
if err != nil {
|
||||
// If the ConfigMap doesn't exist, a new one will be created later
|
||||
glog.Errorln(err)
|
||||
}
|
||||
|
||||
// When adding a new output for the first time, one should always set it disabled
|
||||
output.Enable = false
|
||||
output.Id = uuid.New().String()
|
||||
output.Updatetime = time.Now()
|
||||
|
||||
outputs = append(outputs, output)
|
||||
|
||||
err = updateFluentbitOutputConfigMap(outputs)
|
||||
if err != nil {
|
||||
result.Status = http.StatusInternalServerError
|
||||
return &result
|
||||
}
|
||||
|
||||
// 2. Keep CRD in inline with ConfigMap
|
||||
err = syncFluentbitCRDOutputWithConfigMap(outputs)
|
||||
if err != nil {
|
||||
result.Status = http.StatusInternalServerError
|
||||
return &result
|
||||
}
|
||||
|
||||
// 3. If it's an configs output added, reset configs client configs
|
||||
configs := ParseEsOutputParams(output.Parameters)
|
||||
if configs != nil {
|
||||
configs.WriteESConfigs()
|
||||
}
|
||||
|
||||
result.Status = http.StatusOK
|
||||
return &result
|
||||
}
|
||||
|
||||
func FluentbitOutputUpdate(output fb.OutputPlugin, id string) *FluentbitOutputsResult {
|
||||
var result FluentbitOutputsResult
|
||||
|
||||
// 1. Update ConfigMap
|
||||
var outputs []fb.OutputPlugin
|
||||
outputs, err := GetFluentbitOutputFromConfigMap()
|
||||
if err != nil {
|
||||
// If the ConfigMap doesn't exist, a new one will be created later
|
||||
glog.Errorln(err)
|
||||
}
|
||||
|
||||
index := 0
|
||||
for _, output := range outputs {
|
||||
if output.Id == id {
|
||||
break
|
||||
}
|
||||
index++
|
||||
}
|
||||
|
||||
if index >= len(outputs) {
|
||||
result.Status = http.StatusNotFound
|
||||
return &result
|
||||
}
|
||||
|
||||
output.Updatetime = time.Now()
|
||||
outputs = append(append(outputs[:index], outputs[index+1:]...), output)
|
||||
|
||||
err = updateFluentbitOutputConfigMap(outputs)
|
||||
if err != nil {
|
||||
result.Status = http.StatusInternalServerError
|
||||
return &result
|
||||
}
|
||||
|
||||
// 2. Keep CRD in inline with ConfigMap
|
||||
err = syncFluentbitCRDOutputWithConfigMap(outputs)
|
||||
if err != nil {
|
||||
result.Status = http.StatusInternalServerError
|
||||
return &result
|
||||
}
|
||||
|
||||
// 3. If it's an configs output updated, reset configs client configs
|
||||
configs := ParseEsOutputParams(output.Parameters)
|
||||
if configs != nil {
|
||||
configs.WriteESConfigs()
|
||||
}
|
||||
|
||||
result.Status = http.StatusOK
|
||||
return &result
|
||||
}
|
||||
|
||||
func FluentbitOutputDelete(id string) *FluentbitOutputsResult {
|
||||
var result FluentbitOutputsResult
|
||||
|
||||
// 1. Update ConfigMap
|
||||
// If the ConfigMap doesn't exist, a new one will be created
|
||||
outputs, _ := GetFluentbitOutputFromConfigMap()
|
||||
|
||||
index := 0
|
||||
for _, output := range outputs {
|
||||
if output.Id == id {
|
||||
break
|
||||
}
|
||||
index++
|
||||
}
|
||||
|
||||
if index >= len(outputs) {
|
||||
result.Status = http.StatusNotFound
|
||||
return &result
|
||||
}
|
||||
|
||||
outputs = append(outputs[:index], outputs[index+1:]...)
|
||||
|
||||
err := updateFluentbitOutputConfigMap(outputs)
|
||||
if err != nil {
|
||||
result.Status = http.StatusInternalServerError
|
||||
return &result
|
||||
}
|
||||
|
||||
// 2. Keep CRD in inline with DB
|
||||
err = syncFluentbitCRDOutputWithConfigMap(outputs)
|
||||
if err != nil {
|
||||
result.Status = http.StatusInternalServerError
|
||||
return &result
|
||||
}
|
||||
|
||||
result.Status = http.StatusOK
|
||||
return &result
|
||||
}
|
||||
|
||||
func GetFluentbitOutputFromConfigMap() ([]fb.OutputPlugin, error) {
|
||||
configMap, err := informers.SharedInformerFactory().Core().V1().ConfigMaps().Lister().ConfigMaps(LoggingNamespace).Get(ConfigMapName)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
data := configMap.Data[ConfigMapData]
|
||||
|
||||
var outputs []fb.OutputPlugin
|
||||
if err = jsonIter.UnmarshalFromString(data, &outputs); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return outputs, nil
|
||||
}
|
||||
|
||||
func updateFluentbitOutputConfigMap(outputs []fb.OutputPlugin) error {
|
||||
|
||||
var data string
|
||||
data, err := jsonIter.MarshalToString(outputs)
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Update the ConfigMap
|
||||
config, err := rest.InClusterConfig()
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
return err
|
||||
}
|
||||
|
||||
// Creates the clientset
|
||||
clientset, err := kubernetes.NewForConfig(config)
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
return err
|
||||
}
|
||||
|
||||
configMapClient := clientset.CoreV1().ConfigMaps(LoggingNamespace)
|
||||
|
||||
configMap, err := configMapClient.Get(ConfigMapName, metav1.GetOptions{})
|
||||
if err != nil {
|
||||
|
||||
// If the ConfigMap doesn't exist, create a new one
|
||||
newConfigMap := &corev1.ConfigMap{
|
||||
ObjectMeta: metav1.ObjectMeta{
|
||||
Name: ConfigMapName,
|
||||
},
|
||||
Data: map[string]string{ConfigMapData: data},
|
||||
}
|
||||
|
||||
_, err = configMapClient.Create(newConfigMap)
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
|
||||
// update
|
||||
configMap.Data = map[string]string{ConfigMapData: data}
|
||||
_, err = configMapClient.Update(configMap)
|
||||
if err != nil {
|
||||
glog.Errorln(err)
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func syncFluentbitCRDOutputWithConfigMap(outputs []fb.OutputPlugin) error {
|
||||
|
||||
var enabledOutputs []fb.Plugin
|
||||
for _, output := range outputs {
|
||||
if output.Enable {
|
||||
enabledOutputs = append(enabledOutputs, fb.Plugin{Type: output.Type, Name: output.Name, Parameters: output.Parameters})
|
||||
}
|
||||
}
|
||||
|
||||
// Empty output is not allowed, must specify a null-type output
|
||||
if len(enabledOutputs) == 0 {
|
||||
enabledOutputs = []fb.Plugin{
|
||||
{
|
||||
Type: "fluentbit_output",
|
||||
Name: "fluentbit-output-null",
|
||||
Parameters: []fb.Parameter{
|
||||
{
|
||||
Name: "Name",
|
||||
Value: "null",
|
||||
},
|
||||
{
|
||||
Name: "Match",
|
||||
Value: "*",
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
crdcs, scheme, err := createCRDClientSet()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Create a CRD client interface
|
||||
crdclient := fb.CrdClient(crdcs, scheme, LoggingNamespace)
|
||||
|
||||
fluentbit, err := crdclient.Get("fluent-bit")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
fluentbit.Spec.Output = enabledOutputs
|
||||
_, err = crdclient.Update("fluent-bit", fluentbit)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// Parse es host, port and index
|
||||
func ParseEsOutputParams(params []fb.Parameter) *es.ESConfigs {
|
||||
|
||||
var (
|
||||
isEsFound bool
|
||||
|
||||
host = "127.0.0.1"
|
||||
port = "9200"
|
||||
index = "logstash"
|
||||
logstashFormat string
|
||||
logstashPrefix string
|
||||
)
|
||||
|
||||
for _, param := range params {
|
||||
switch param.Name {
|
||||
case "Name":
|
||||
if param.Value == "es" {
|
||||
isEsFound = true
|
||||
}
|
||||
case "Host":
|
||||
host = param.Value
|
||||
case "Port":
|
||||
port = param.Value
|
||||
case "Index":
|
||||
index = param.Value
|
||||
case "Logstash_Format":
|
||||
logstashFormat = strings.ToLower(param.Value)
|
||||
case "Logstash_Prefix":
|
||||
logstashPrefix = param.Value
|
||||
}
|
||||
}
|
||||
|
||||
if !isEsFound {
|
||||
return nil
|
||||
}
|
||||
|
||||
// If Logstash_Format is On/True, ignore Index
|
||||
if logstashFormat == "on" || logstashFormat == "true" {
|
||||
if logstashPrefix != "" {
|
||||
index = logstashPrefix
|
||||
} else {
|
||||
index = "logstash"
|
||||
}
|
||||
}
|
||||
|
||||
return &es.ESConfigs{Host: host, Port: port, Index: index}
|
||||
}
|
||||
53
pkg/models/log/types.go
Normal file
53
pkg/models/log/types.go
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
|
||||
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 log
|
||||
|
||||
import (
|
||||
fb "kubesphere.io/kubesphere/pkg/simple/client/fluentbit"
|
||||
)
|
||||
|
||||
type FluentbitCRDResult struct {
|
||||
Status int `json:"status"`
|
||||
CRD fb.FluentBitSpec `json:"CRD,omitempty"`
|
||||
}
|
||||
|
||||
type FluentbitCRDDeleteResult struct {
|
||||
Status int `json:"status"`
|
||||
}
|
||||
|
||||
type FluentbitSettingsResult struct {
|
||||
Status int `json:"status"`
|
||||
Enable string `json:"Enable,omitempty"`
|
||||
}
|
||||
|
||||
type FluentbitFilter struct {
|
||||
Type string `json:"type"`
|
||||
Field string `json:"field"`
|
||||
Expression string `json:"expression"`
|
||||
}
|
||||
|
||||
type FluentbitFiltersResult struct {
|
||||
Status int `json:"status"`
|
||||
Filters []FluentbitFilter `json:"filters,omitempty"`
|
||||
}
|
||||
|
||||
type FluentbitOutputsResult struct {
|
||||
Status int `json:"status"`
|
||||
Outputs []fb.OutputPlugin `json:"outputs,omitempty"`
|
||||
}
|
||||
@@ -1,42 +1,32 @@
|
||||
/*
|
||||
|
||||
Copyright 2019 The KubeSphere Authors.
|
||||
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
|
||||
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
|
||||
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.
|
||||
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 metrics
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"kubesphere.io/kubesphere/pkg/models"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/prometheus"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"net/url"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/constants"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/models/components"
|
||||
"kubesphere.io/kubesphere/pkg/models/workspaces"
|
||||
|
||||
"github.com/golang/glog"
|
||||
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
|
||||
"runtime/debug"
|
||||
"sort"
|
||||
|
||||
@@ -44,12 +34,12 @@ import (
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/models/workspaces"
|
||||
client "kubesphere.io/kubesphere/pkg/simple/client/prometheus"
|
||||
)
|
||||
|
||||
var (
|
||||
jsonIter = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
nodeStatusDelLabel = []string{"endpoint", "instance", "job", "namespace", "pod", "service"}
|
||||
)
|
||||
var jsonIter = jsoniter.ConfigCompatibleWithStandardLibrary
|
||||
|
||||
const (
|
||||
ChannelMaxCapacityWorkspaceMetric = 800
|
||||
@@ -145,9 +135,9 @@ func getAllWorkspaces() map[string]int {
|
||||
paramValues := make(url.Values)
|
||||
paramValues.Set("query", WorkspaceNamespaceLabelRule)
|
||||
params := paramValues.Encode()
|
||||
res := prometheus.SendMonitoringRequest(prometheus.DefaultQueryType, params)
|
||||
res := client.SendMonitoringRequest(client.DefaultQueryType, params)
|
||||
|
||||
metric := ReformatJson(res, "")
|
||||
metric := ReformatJson(res, "", map[string]string{"workspace": "workspace"})
|
||||
|
||||
return getAllWorkspaceNames(metric)
|
||||
}
|
||||
@@ -240,17 +230,17 @@ func unifyMetricHistoryTimeRange(fmtMetrics *FormatedMetric) {
|
||||
}
|
||||
}
|
||||
|
||||
func AssembleSpecificWorkloadMetricRequestInfo(monitoringRequest *prometheus.MonitoringRequestParams, metricName string) (string, string, bool) {
|
||||
func AssembleSpecificWorkloadMetricRequestInfo(monitoringRequest *client.MonitoringRequestParams, metricName string) (string, string, bool) {
|
||||
|
||||
nsName := monitoringRequest.NsName
|
||||
wkName := monitoringRequest.WorkloadName
|
||||
podsFilter := monitoringRequest.PodsFilter
|
||||
wlName := monitoringRequest.WorkloadName
|
||||
podsFilter := monitoringRequest.ResourcesFilter
|
||||
|
||||
rule := MakeSpecificWorkloadRule(monitoringRequest.WorkloadKind, wkName, nsName)
|
||||
rule := MakeSpecificWorkloadRule(monitoringRequest.WorkloadKind, wlName, nsName)
|
||||
paramValues := monitoringRequest.Params
|
||||
params := makeRequestParamString(rule, paramValues)
|
||||
|
||||
res := prometheus.SendMonitoringRequest(prometheus.DefaultQueryType, params)
|
||||
res := client.SendMonitoringRequest(client.DefaultQueryType, params)
|
||||
|
||||
podNamesFilter := getPodNameRegexInWorkload(res, podsFilter)
|
||||
|
||||
@@ -261,32 +251,26 @@ func AssembleSpecificWorkloadMetricRequestInfo(monitoringRequest *prometheus.Mon
|
||||
return queryType, params, rule == ""
|
||||
}
|
||||
|
||||
func AssembleAllWorkloadMetricRequestInfo(monitoringRequest *prometheus.MonitoringRequestParams, metricName string) (string, string) {
|
||||
func AssembleAllWorkloadMetricRequestInfo(monitoringRequest *client.MonitoringRequestParams, metricName string) (string, string) {
|
||||
queryType := monitoringRequest.QueryType
|
||||
|
||||
paramValues := monitoringRequest.Params
|
||||
|
||||
rule := MakeWorkloadPromQL(metricName, monitoringRequest.NsName, monitoringRequest.WlFilter)
|
||||
rule := MakeWorkloadPromQL(metricName, monitoringRequest.NsName, monitoringRequest.ResourcesFilter)
|
||||
params := makeRequestParamString(rule, paramValues)
|
||||
return queryType, params
|
||||
}
|
||||
|
||||
func AssemblePodMetricRequestInfo(monitoringRequest *prometheus.MonitoringRequestParams, metricName string) (string, string, bool) {
|
||||
func AssemblePodMetricRequestInfo(monitoringRequest *client.MonitoringRequestParams, metricName string) (string, string, bool) {
|
||||
queryType := monitoringRequest.QueryType
|
||||
|
||||
paramValues := monitoringRequest.Params
|
||||
|
||||
rule := MakePodPromQL(metricName, monitoringRequest.NsName, monitoringRequest.NodeId, monitoringRequest.PodName, monitoringRequest.PodsFilter)
|
||||
rule := MakePodPromQL(metricName, monitoringRequest.NsName, monitoringRequest.NodeId, monitoringRequest.PodName, monitoringRequest.ResourcesFilter)
|
||||
params := makeRequestParamString(rule, paramValues)
|
||||
return queryType, params, rule == ""
|
||||
}
|
||||
|
||||
func GetMetric(queryType, params, metricName string) *FormatedMetric {
|
||||
res := prometheus.SendMonitoringRequest(queryType, params)
|
||||
formatedMetric := ReformatJson(res, metricName)
|
||||
return formatedMetric
|
||||
}
|
||||
|
||||
func GetNodeAddressInfo() *map[string][]v1.NodeAddress {
|
||||
nodeLister := informers.SharedInformerFactory().Core().V1().Nodes().Lister()
|
||||
nodes, err := nodeLister.List(labels.Everything())
|
||||
@@ -319,33 +303,34 @@ func AddNodeAddressMetric(nodeMetric *FormatedMetric, nodeAddress *map[string][]
|
||||
}
|
||||
}
|
||||
|
||||
func MonitorContainer(monitoringRequest *prometheus.MonitoringRequestParams, metricName string) *FormatedMetric {
|
||||
func MonitorContainer(monitoringRequest *client.MonitoringRequestParams, metricName string) *FormatedMetric {
|
||||
queryType, params := AssembleContainerMetricRequestInfo(monitoringRequest, metricName)
|
||||
res := GetMetric(queryType, params, metricName)
|
||||
metricsStr := client.SendMonitoringRequest(queryType, params)
|
||||
res := ReformatJson(metricsStr, metricName, map[string]string{"container_name": ""})
|
||||
return res
|
||||
}
|
||||
|
||||
func AssembleContainerMetricRequestInfo(monitoringRequest *prometheus.MonitoringRequestParams, metricName string) (string, string) {
|
||||
func AssembleContainerMetricRequestInfo(monitoringRequest *client.MonitoringRequestParams, metricName string) (string, string) {
|
||||
queryType := monitoringRequest.QueryType
|
||||
|
||||
paramValues := monitoringRequest.Params
|
||||
rule := MakeContainerPromQL(monitoringRequest.NsName, monitoringRequest.NodeId, monitoringRequest.PodName, monitoringRequest.ContainerName, metricName, monitoringRequest.ContainersFilter)
|
||||
rule := MakeContainerPromQL(monitoringRequest.NsName, monitoringRequest.NodeId, monitoringRequest.PodName, monitoringRequest.ContainerName, metricName, monitoringRequest.ResourcesFilter)
|
||||
params := makeRequestParamString(rule, paramValues)
|
||||
|
||||
return queryType, params
|
||||
}
|
||||
|
||||
func AssembleNamespaceMetricRequestInfo(monitoringRequest *prometheus.MonitoringRequestParams, metricName string) (string, string) {
|
||||
func AssembleNamespaceMetricRequestInfo(monitoringRequest *client.MonitoringRequestParams, metricName string) (string, string) {
|
||||
queryType := monitoringRequest.QueryType
|
||||
|
||||
paramValues := monitoringRequest.Params
|
||||
rule := MakeNamespacePromQL(monitoringRequest.NsName, monitoringRequest.NsFilter, metricName)
|
||||
rule := MakeNamespacePromQL(monitoringRequest.NsName, monitoringRequest.ResourcesFilter, metricName)
|
||||
params := makeRequestParamString(rule, paramValues)
|
||||
|
||||
return queryType, params
|
||||
}
|
||||
|
||||
func AssembleSpecificWorkspaceMetricRequestInfo(monitoringRequest *prometheus.MonitoringRequestParams, namespaceList []string, metricName string) (string, string) {
|
||||
func AssembleSpecificWorkspaceMetricRequestInfo(monitoringRequest *client.MonitoringRequestParams, namespaceList []string, metricName string) (string, string) {
|
||||
|
||||
nsFilter := "^(" + strings.Join(namespaceList, "|") + ")$"
|
||||
|
||||
@@ -357,7 +342,7 @@ func AssembleSpecificWorkspaceMetricRequestInfo(monitoringRequest *prometheus.Mo
|
||||
return queryType, params
|
||||
}
|
||||
|
||||
func AssembleAllWorkspaceMetricRequestInfo(monitoringRequest *prometheus.MonitoringRequestParams, namespaceList []string, metricName string) (string, string) {
|
||||
func AssembleAllWorkspaceMetricRequestInfo(monitoringRequest *client.MonitoringRequestParams, namespaceList []string, metricName string) (string, string) {
|
||||
var nsFilter = "^()$"
|
||||
|
||||
if namespaceList != nil {
|
||||
@@ -407,7 +392,7 @@ func filterNamespace(nsFilter string, namespaceList []string) []string {
|
||||
return newNSlist
|
||||
}
|
||||
|
||||
func MonitorAllWorkspaces(monitoringRequest *prometheus.MonitoringRequestParams) *FormatedLevelMetric {
|
||||
func MonitorAllWorkspaces(monitoringRequest *client.MonitoringRequestParams) *FormatedLevelMetric {
|
||||
metricsFilter := monitoringRequest.MetricsFilter
|
||||
if strings.Trim(metricsFilter, " ") == "" {
|
||||
metricsFilter = ".*"
|
||||
@@ -429,7 +414,7 @@ func MonitorAllWorkspaces(monitoringRequest *prometheus.MonitoringRequestParams)
|
||||
wsMap := getAllWorkspaces()
|
||||
|
||||
for ws := range wsMap {
|
||||
bol, err := regexp.MatchString(monitoringRequest.WsFilter, ws)
|
||||
bol, err := regexp.MatchString(monitoringRequest.ResourcesFilter, ws)
|
||||
if err == nil && bol {
|
||||
// a workspace
|
||||
wgAll.Add(1)
|
||||
@@ -470,7 +455,7 @@ func MonitorAllWorkspaces(monitoringRequest *prometheus.MonitoringRequestParams)
|
||||
}
|
||||
}
|
||||
|
||||
func collectWorkspaceMetric(monitoringRequest *prometheus.MonitoringRequestParams, ws string, filterMetricsName []string, wgAll *sync.WaitGroup, wsAllch chan *[]FormatedMetric) {
|
||||
func collectWorkspaceMetric(monitoringRequest *client.MonitoringRequestParams, ws string, filterMetricsName []string, wgAll *sync.WaitGroup, wsAllch chan *[]FormatedMetric) {
|
||||
defer wgAll.Done()
|
||||
var wg sync.WaitGroup
|
||||
var ch = make(chan *FormatedMetric, ChannelMaxCapacity)
|
||||
@@ -484,7 +469,8 @@ func collectWorkspaceMetric(monitoringRequest *prometheus.MonitoringRequestParam
|
||||
go func(metricName string) {
|
||||
|
||||
queryType, params := AssembleSpecificWorkspaceMetricRequestInfo(monitoringRequest, namespaceArray, metricName)
|
||||
ch <- GetMetric(queryType, params, metricName)
|
||||
metricsStr := client.SendMonitoringRequest(queryType, params)
|
||||
ch <- ReformatJson(metricsStr, metricName, map[string]string{"namespace": ""})
|
||||
|
||||
wg.Done()
|
||||
}(metricName)
|
||||
@@ -511,7 +497,7 @@ func collectWorkspaceMetric(monitoringRequest *prometheus.MonitoringRequestParam
|
||||
wsAllch <- &metricsArray
|
||||
}
|
||||
|
||||
func MonitorAllMetrics(monitoringRequest *prometheus.MonitoringRequestParams, resourceType string) *FormatedLevelMetric {
|
||||
func MonitorAllMetrics(monitoringRequest *client.MonitoringRequestParams, resourceType string) *FormatedLevelMetric {
|
||||
metricsFilter := monitoringRequest.MetricsFilter
|
||||
if metricsFilter == "" {
|
||||
metricsFilter = ".*"
|
||||
@@ -529,10 +515,8 @@ func MonitorAllMetrics(monitoringRequest *prometheus.MonitoringRequestParams, re
|
||||
wg.Add(1)
|
||||
go func(metricName string) {
|
||||
queryType, params := AssembleClusterMetricRequestInfo(monitoringRequest, metricName)
|
||||
clusterMetrics := GetMetric(queryType, params, metricName)
|
||||
|
||||
ch <- clusterMetrics
|
||||
|
||||
metricsStr := client.SendMonitoringRequest(queryType, params)
|
||||
ch <- ReformatJson(metricsStr, metricName, map[string]string{"cluster": "local"})
|
||||
wg.Done()
|
||||
}(metricName)
|
||||
}
|
||||
@@ -546,7 +530,8 @@ func MonitorAllMetrics(monitoringRequest *prometheus.MonitoringRequestParams, re
|
||||
wg.Add(1)
|
||||
go func(metricName string) {
|
||||
queryType, params := AssembleNodeMetricRequestInfo(monitoringRequest, metricName)
|
||||
ch <- GetMetric(queryType, params, metricName)
|
||||
metricsStr := client.SendMonitoringRequest(queryType, params)
|
||||
ch <- ReformatJson(metricsStr, metricName, map[string]string{"node": ""})
|
||||
wg.Done()
|
||||
}(metricName)
|
||||
}
|
||||
@@ -560,7 +545,7 @@ func MonitorAllMetrics(monitoringRequest *prometheus.MonitoringRequestParams, re
|
||||
if err != nil {
|
||||
glog.Errorln(err.Error())
|
||||
}
|
||||
namespaceArray = filterNamespace(monitoringRequest.NsFilter, namespaceArray)
|
||||
namespaceArray = filterNamespace(monitoringRequest.ResourcesFilter, namespaceArray)
|
||||
|
||||
if monitoringRequest.Tp == "rank" {
|
||||
for _, metricName := range NamespaceMetricsNames {
|
||||
@@ -570,12 +555,13 @@ func MonitorAllMetrics(monitoringRequest *prometheus.MonitoringRequestParams, re
|
||||
|
||||
bol, err := regexp.MatchString(metricsFilter, metricName)
|
||||
ns := "^(" + strings.Join(namespaceArray, "|") + ")$"
|
||||
monitoringRequest.NsFilter = ns
|
||||
monitoringRequest.ResourcesFilter = ns
|
||||
if err == nil && bol {
|
||||
wg.Add(1)
|
||||
go func(metricName string) {
|
||||
queryType, params := AssembleNamespaceMetricRequestInfo(monitoringRequest, metricName)
|
||||
ch <- GetMetric(queryType, params, metricName)
|
||||
metricsStr := client.SendMonitoringRequest(queryType, params)
|
||||
ch <- ReformatJson(metricsStr, metricName, map[string]string{"workspace": "workspace"})
|
||||
wg.Done()
|
||||
}(metricName)
|
||||
}
|
||||
@@ -593,7 +579,8 @@ func MonitorAllMetrics(monitoringRequest *prometheus.MonitoringRequestParams, re
|
||||
wg.Add(1)
|
||||
go func(metricName string) {
|
||||
queryType, params := AssembleSpecificWorkspaceMetricRequestInfo(monitoringRequest, namespaceArray, metricName)
|
||||
ch <- GetMetric(queryType, params, metricName)
|
||||
metricsStr := client.SendMonitoringRequest(queryType, params)
|
||||
ch <- ReformatJson(metricsStr, metricName, map[string]string{"workspace": "workspace"})
|
||||
wg.Done()
|
||||
}(metricName)
|
||||
}
|
||||
@@ -610,9 +597,8 @@ func MonitorAllMetrics(monitoringRequest *prometheus.MonitoringRequestParams, re
|
||||
|
||||
go func(metricName string) {
|
||||
queryType, params := AssembleAllWorkspaceMetricRequestInfo(monitoringRequest, nil, metricName)
|
||||
|
||||
ch <- GetMetric(queryType, params, metricName)
|
||||
|
||||
metricsStr := client.SendMonitoringRequest(queryType, params)
|
||||
ch <- ReformatJson(metricsStr, metricName, map[string]string{"workspace": "workspaces"})
|
||||
wg.Done()
|
||||
}(metricName)
|
||||
}
|
||||
@@ -627,7 +613,8 @@ func MonitorAllMetrics(monitoringRequest *prometheus.MonitoringRequestParams, re
|
||||
wg.Add(1)
|
||||
go func(metricName string) {
|
||||
queryType, params := AssembleNamespaceMetricRequestInfo(monitoringRequest, metricName)
|
||||
ch <- GetMetric(queryType, params, metricName)
|
||||
metricsStr := client.SendMonitoringRequest(queryType, params)
|
||||
ch <- ReformatJson(metricsStr, metricName, map[string]string{"namespace": ""})
|
||||
wg.Done()
|
||||
}(metricName)
|
||||
}
|
||||
@@ -635,15 +622,15 @@ func MonitorAllMetrics(monitoringRequest *prometheus.MonitoringRequestParams, re
|
||||
}
|
||||
case MetricLevelWorkload:
|
||||
{
|
||||
if monitoringRequest.Tp == "rank" {
|
||||
if monitoringRequest.WorkloadName == "" {
|
||||
for _, metricName := range WorkloadMetricsNames {
|
||||
bol, err := regexp.MatchString(metricsFilter, metricName)
|
||||
if err == nil && bol {
|
||||
wg.Add(1)
|
||||
go func(metricName string) {
|
||||
queryType, params := AssembleAllWorkloadMetricRequestInfo(monitoringRequest, metricName)
|
||||
fmtMetrics := GetMetric(queryType, params, metricName)
|
||||
ch <- fmtMetrics
|
||||
metricsStr := client.SendMonitoringRequest(queryType, params)
|
||||
ch <- ReformatJson(metricsStr, metricName, map[string]string{"workload": ""})
|
||||
wg.Done()
|
||||
}(metricName)
|
||||
}
|
||||
@@ -657,7 +644,8 @@ func MonitorAllMetrics(monitoringRequest *prometheus.MonitoringRequestParams, re
|
||||
metricName = strings.TrimLeft(metricName, "workload_")
|
||||
queryType, params, nullRule := AssembleSpecificWorkloadMetricRequestInfo(monitoringRequest, metricName)
|
||||
if !nullRule {
|
||||
fmtMetrics := GetMetric(queryType, params, metricName)
|
||||
metricsStr := client.SendMonitoringRequest(queryType, params)
|
||||
fmtMetrics := ReformatJson(metricsStr, metricName, map[string]string{"pod_name": ""})
|
||||
unifyMetricHistoryTimeRange(fmtMetrics)
|
||||
ch <- fmtMetrics
|
||||
}
|
||||
@@ -676,7 +664,8 @@ func MonitorAllMetrics(monitoringRequest *prometheus.MonitoringRequestParams, re
|
||||
go func(metricName string) {
|
||||
queryType, params, nullRule := AssemblePodMetricRequestInfo(monitoringRequest, metricName)
|
||||
if !nullRule {
|
||||
ch <- GetMetric(queryType, params, metricName)
|
||||
metricsStr := client.SendMonitoringRequest(queryType, params)
|
||||
ch <- ReformatJson(metricsStr, metricName, map[string]string{"pod_name": ""})
|
||||
} else {
|
||||
ch <- nil
|
||||
}
|
||||
@@ -693,7 +682,8 @@ func MonitorAllMetrics(monitoringRequest *prometheus.MonitoringRequestParams, re
|
||||
wg.Add(1)
|
||||
go func(metricName string) {
|
||||
queryType, params := AssembleContainerMetricRequestInfo(monitoringRequest, metricName)
|
||||
ch <- GetMetric(queryType, params, metricName)
|
||||
metricsStr := client.SendMonitoringRequest(queryType, params)
|
||||
ch <- ReformatJson(metricsStr, metricName, map[string]string{"container_name": ""})
|
||||
wg.Done()
|
||||
}(metricName)
|
||||
}
|
||||
@@ -868,125 +858,7 @@ func getSpecificMetricItem(timestamp int64, metricName string, resource string,
|
||||
return &nsMetrics
|
||||
}
|
||||
|
||||
// k8s component(controller, scheduler, etcd) status
|
||||
func MonitorComponentStatus(monitoringRequest *prometheus.MonitoringRequestParams) *[]interface{} {
|
||||
componentList, err := k8s.Client().CoreV1().ComponentStatuses().List(metaV1.ListOptions{})
|
||||
if err != nil {
|
||||
glog.Errorln(err.Error())
|
||||
}
|
||||
|
||||
var componentStatusList []*ComponentStatus
|
||||
for _, item := range componentList.Items {
|
||||
var status []OneComponentStatus
|
||||
for _, cond := range item.Conditions {
|
||||
status = append(status, OneComponentStatus{
|
||||
Type: string(cond.Type),
|
||||
Status: string(cond.Status),
|
||||
Message: cond.Message,
|
||||
Error: cond.Error,
|
||||
})
|
||||
}
|
||||
|
||||
componentStatusList = append(componentStatusList, &ComponentStatus{
|
||||
Name: item.Name,
|
||||
Namespace: item.Namespace,
|
||||
Labels: item.Labels,
|
||||
ComponentStatus: status,
|
||||
})
|
||||
}
|
||||
|
||||
// node status
|
||||
queryType := monitoringRequest.QueryType
|
||||
paramValues := monitoringRequest.Params
|
||||
paramValues.Set("query", NodeStatusRule)
|
||||
params := paramValues.Encode()
|
||||
res := prometheus.SendMonitoringRequest(queryType, params)
|
||||
|
||||
nodeStatusMetric := ReformatJson(res, "node_status", nodeStatusDelLabel...)
|
||||
nodeStatusMetric = ReformatNodeStatusField(nodeStatusMetric)
|
||||
|
||||
var normalNodes []string
|
||||
var abnormalNodes []string
|
||||
for _, result := range nodeStatusMetric.Data.Result {
|
||||
tmap, sure := result[ResultItemMetric].(map[string]interface{})
|
||||
|
||||
if sure {
|
||||
if tmap[MetricStatus].(string) == "false" {
|
||||
abnormalNodes = append(abnormalNodes, tmap[MetricLevelNode].(string))
|
||||
} else {
|
||||
normalNodes = append(normalNodes, tmap[MetricLevelNode].(string))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Components, err := components.GetAllComponentsStatus()
|
||||
|
||||
if err != nil {
|
||||
glog.Error(err.Error())
|
||||
}
|
||||
|
||||
var namespaceComponentHealthyMap = make(map[string]int)
|
||||
var namespaceComponentTotalMap = make(map[string]int)
|
||||
|
||||
for _, ns := range constants.SystemNamespaces {
|
||||
nsStatus, exist := Components[ns]
|
||||
if exist {
|
||||
for _, nsStatusItem := range nsStatus.(map[string]interface{}) {
|
||||
component := nsStatusItem.(models.Component)
|
||||
namespaceComponentTotalMap[ns] += 1
|
||||
if component.HealthyBackends != 0 && component.HealthyBackends == component.TotalBackends {
|
||||
namespaceComponentHealthyMap[ns] += 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
timestamp := int64(time.Now().Unix())
|
||||
|
||||
onlineMetricItems := makeMetricItems(timestamp, namespaceComponentHealthyMap, MetricLevelNamespace)
|
||||
metricItems := makeMetricItems(timestamp, namespaceComponentTotalMap, MetricLevelNamespace)
|
||||
|
||||
var assembleList []interface{}
|
||||
assembleList = append(assembleList, nodeStatusMetric)
|
||||
|
||||
for _, statusItem := range componentStatusList {
|
||||
assembleList = append(assembleList, statusItem)
|
||||
}
|
||||
|
||||
assembleList = append(assembleList, FormatedMetric{
|
||||
Data: FormatedMetricData{
|
||||
Result: *onlineMetricItems,
|
||||
ResultType: ResultTypeVector,
|
||||
},
|
||||
MetricName: MetricNameComponentOnLine,
|
||||
Status: MetricStatusSuccess,
|
||||
})
|
||||
|
||||
assembleList = append(assembleList, FormatedMetric{
|
||||
Data: FormatedMetricData{
|
||||
Result: *metricItems,
|
||||
ResultType: ResultTypeVector,
|
||||
},
|
||||
MetricName: MetricNameComponentLine,
|
||||
Status: MetricStatusSuccess,
|
||||
})
|
||||
|
||||
return &assembleList
|
||||
}
|
||||
|
||||
func makeMetricItems(timestamp int64, statusMap map[string]int, resourceType string) *[]map[string]interface{} {
|
||||
var metricItems []map[string]interface{}
|
||||
|
||||
for ns, count := range statusMap {
|
||||
metricItems = append(metricItems, map[string]interface{}{
|
||||
ResultItemMetric: map[string]string{resourceType: ns},
|
||||
ResultItemValue: []interface{}{timestamp, fmt.Sprintf("%d", count)},
|
||||
})
|
||||
}
|
||||
return &metricItems
|
||||
}
|
||||
|
||||
func AssembleClusterMetricRequestInfo(monitoringRequest *prometheus.MonitoringRequestParams, metricName string) (string, string) {
|
||||
func AssembleClusterMetricRequestInfo(monitoringRequest *client.MonitoringRequestParams, metricName string) (string, string) {
|
||||
queryType := monitoringRequest.QueryType
|
||||
paramValues := monitoringRequest.Params
|
||||
rule := MakeClusterRule(metricName)
|
||||
@@ -995,10 +867,10 @@ func AssembleClusterMetricRequestInfo(monitoringRequest *prometheus.MonitoringRe
|
||||
return queryType, params
|
||||
}
|
||||
|
||||
func AssembleNodeMetricRequestInfo(monitoringRequest *prometheus.MonitoringRequestParams, metricName string) (string, string) {
|
||||
func AssembleNodeMetricRequestInfo(monitoringRequest *client.MonitoringRequestParams, metricName string) (string, string) {
|
||||
queryType := monitoringRequest.QueryType
|
||||
paramValues := monitoringRequest.Params
|
||||
rule := MakeNodeRule(monitoringRequest.NodeId, monitoringRequest.NodesFilter, metricName)
|
||||
rule := MakeNodeRule(monitoringRequest.NodeId, monitoringRequest.ResourcesFilter, metricName)
|
||||
params := makeRequestParamString(rule, paramValues)
|
||||
|
||||
return queryType, params
|
||||
|
||||
@@ -318,14 +318,14 @@ var RulePromQLTmplMap = MetricMap{
|
||||
"cluster_disk_read_throughput": "sum(node:data_volume_throughput_bytes_read:sum)",
|
||||
"cluster_disk_write_throughput": "sum(node:data_volume_throughput_bytes_written:sum)",
|
||||
|
||||
"cluster_disk_size_usage": `sum(max((node_filesystem_size{device=~"/dev/.+", job="node-exporter"} - node_filesystem_avail{device=~"/dev/.+", job="node-exporter"}) * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node))`,
|
||||
"cluster_disk_size_utilisation": `1 - sum(max(node_filesystem_avail{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node)) / sum(max(node_filesystem_size{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node))`,
|
||||
"cluster_disk_size_capacity": `sum(max(node_filesystem_size{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node))`,
|
||||
"cluster_disk_size_available": `sum(max(node_filesystem_avail{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node))`,
|
||||
"cluster_disk_size_usage": `sum(max((node_filesystem_size_bytes{device=~"/dev/.+", job="node-exporter"} - node_filesystem_avail_bytes{device=~"/dev/.+", job="node-exporter"}) * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node))`,
|
||||
"cluster_disk_size_utilisation": `1 - sum(max(node_filesystem_avail_bytes{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node)) / sum(max(node_filesystem_size_bytes{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node))`,
|
||||
"cluster_disk_size_capacity": `sum(max(node_filesystem_size_bytes{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node))`,
|
||||
"cluster_disk_size_available": `sum(max(node_filesystem_avail_bytes{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:) by (node))`,
|
||||
|
||||
"cluster_disk_inode_total": `sum(node:disk_inodes_total:)`,
|
||||
"cluster_disk_inode_usage": `sum(node:disk_inodes_total:) - sum(node:disk_inodes_free:)`,
|
||||
"cluster_disk_inode_utilisation": `1 - sum(node:disk_inodes_free:) / sum(node:disk_inodes_total:)`,
|
||||
"cluster_disk_inode_total": `sum(node:node_inodes_total:)`,
|
||||
"cluster_disk_inode_usage": `sum(node:node_inodes_total:) - sum(node:node_inodes_free:)`,
|
||||
"cluster_disk_inode_utilisation": `1 - sum(node:node_inodes_free:) / sum(node:node_inodes_total:)`,
|
||||
|
||||
"cluster_namespace_count": `count(kube_namespace_annotations)`,
|
||||
|
||||
@@ -396,14 +396,14 @@ var RulePromQLTmplMap = MetricMap{
|
||||
"node_disk_read_throughput": "node:data_volume_throughput_bytes_read:sum",
|
||||
"node_disk_write_throughput": "node:data_volume_throughput_bytes_written:sum",
|
||||
|
||||
"node_disk_size_capacity": `max(node_filesystem_size{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) by (node)`,
|
||||
"node_disk_size_available": `max(node_filesystem_avail{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) by (node)`,
|
||||
"node_disk_size_usage": `max((node_filesystem_size{device=~"/dev/.+", job="node-exporter"} - node_filesystem_avail{device=~"/dev/.+", job="node-exporter"}) * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) by (node)`,
|
||||
"node_disk_size_utilisation": `max(((node_filesystem_size{device=~"/dev/.+", job="node-exporter"} - node_filesystem_avail{device=~"/dev/.+", job="node-exporter"}) / node_filesystem_size{device=~"/dev/.+", job="node-exporter"}) * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) by (node)`,
|
||||
"node_disk_size_capacity": `max(node_filesystem_size_bytes{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) by (node)`,
|
||||
"node_disk_size_available": `max(node_filesystem_avail_bytes{device=~"/dev/.+", job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) by (node)`,
|
||||
"node_disk_size_usage": `max((node_filesystem_size_bytes{device=~"/dev/.+", job="node-exporter"} - node_filesystem_avail_bytes{device=~"/dev/.+", job="node-exporter"}) * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) by (node)`,
|
||||
"node_disk_size_utilisation": `max(((node_filesystem_size_bytes{device=~"/dev/.+", job="node-exporter"} - node_filesystem_avail_bytes{device=~"/dev/.+", job="node-exporter"}) / node_filesystem_size_bytes{device=~"/dev/.+", job="node-exporter"}) * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) by (node)`,
|
||||
|
||||
"node_disk_inode_total": `node:disk_inodes_total:$1`,
|
||||
"node_disk_inode_usage": `node:disk_inodes_total:$1 - node:disk_inodes_free:$1`,
|
||||
"node_disk_inode_utilisation": `(1 - (node:disk_inodes_free:$1 / node:disk_inodes_total:$1))`,
|
||||
"node_disk_inode_total": `node:node_inodes_total:$1`,
|
||||
"node_disk_inode_usage": `node:node_inodes_total:$1 - node:node_inodes_free:$1`,
|
||||
"node_disk_inode_utilisation": `(1 - (node:node_inodes_free:$1 / node:node_inodes_total:$1))`,
|
||||
|
||||
"node_pod_count": `sum by (node) ((kube_pod_status_scheduled{condition="true"} > 0) * on (namespace, pod) group_left(node) kube_pod_info$1 unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0))`,
|
||||
"node_pod_quota": `sum(kube_node_status_capacity_pods$1) by (node) unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0)`,
|
||||
|
||||
@@ -23,7 +23,7 @@ import (
|
||||
|
||||
"k8s.io/api/core/v1"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/simple/client/prometheus"
|
||||
prom "kubesphere.io/kubesphere/pkg/simple/client/prometheus"
|
||||
)
|
||||
|
||||
func GetNamespacesWithMetrics(namespaces []*v1.Namespace) []*v1.Namespace {
|
||||
@@ -34,11 +34,11 @@ func GetNamespacesWithMetrics(namespaces []*v1.Namespace) []*v1.Namespace {
|
||||
nsFilter := "^(" + strings.Join(nsNameList, "|") + ")$"
|
||||
var timeRelateParams = make(url.Values)
|
||||
|
||||
params := prometheus.MonitoringRequestParams{
|
||||
NsFilter: nsFilter,
|
||||
Params: timeRelateParams,
|
||||
QueryType: prometheus.DefaultQueryType,
|
||||
MetricsFilter: "namespace_cpu_usage|namespace_memory_usage_wo_cache|namespace_pod_count",
|
||||
params := prom.MonitoringRequestParams{
|
||||
ResourcesFilter: nsFilter,
|
||||
Params: timeRelateParams,
|
||||
QueryType: prom.DefaultQueryType,
|
||||
MetricsFilter: "namespace_cpu_usage|namespace_memory_usage_wo_cache|namespace_pod_count",
|
||||
}
|
||||
|
||||
rawMetrics := MonitorAllMetrics(¶ms, MetricLevelNamespace)
|
||||
|
||||
@@ -50,7 +50,7 @@ func (wrapper FormatedMetricDataWrapper) Swap(i, j int) {
|
||||
}
|
||||
|
||||
// sorted metric by ascending or descending order
|
||||
func Sort(sortMetricName string, sortType string, fmtLevelMetric *FormatedLevelMetric, resourceType string) (*FormatedLevelMetric, int) {
|
||||
func Sort(sortMetricName string, sortType string, fmtLevelMetric *FormatedLevelMetric) (*FormatedLevelMetric, int) {
|
||||
defer func() {
|
||||
if err := recover(); err != nil {
|
||||
glog.Errorln(err)
|
||||
@@ -83,8 +83,8 @@ func Sort(sortMetricName string, sortType string, fmtLevelMetric *FormatedLevelM
|
||||
v1, _ := strconv.ParseFloat(value1[len(value1)-1].(string), 64)
|
||||
v2, _ := strconv.ParseFloat(value2[len(value2)-1].(string), 64)
|
||||
if v1 == v2 {
|
||||
resourceName1 := (*p)[ResultItemMetric].(map[string]interface{})[resourceType]
|
||||
resourceName2 := (*q)[ResultItemMetric].(map[string]interface{})[resourceType]
|
||||
resourceName1 := (*p)[ResultItemMetric].(map[string]interface{})["resource_name"]
|
||||
resourceName2 := (*q)[ResultItemMetric].(map[string]interface{})["resource_name"]
|
||||
return resourceName1.(string) < resourceName2.(string)
|
||||
}
|
||||
|
||||
@@ -99,8 +99,8 @@ func Sort(sortMetricName string, sortType string, fmtLevelMetric *FormatedLevelM
|
||||
v2, _ := strconv.ParseFloat(value2[len(value2)-1].(string), 64)
|
||||
|
||||
if v1 == v2 {
|
||||
resourceName1 := (*p)[ResultItemMetric].(map[string]interface{})[resourceType]
|
||||
resourceName2 := (*q)[ResultItemMetric].(map[string]interface{})[resourceType]
|
||||
resourceName1 := (*p)[ResultItemMetric].(map[string]interface{})["resource_name"]
|
||||
resourceName2 := (*q)[ResultItemMetric].(map[string]interface{})["resource_name"]
|
||||
return resourceName1.(string) > resourceName2.(string)
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ func Sort(sortMetricName string, sortType string, fmtLevelMetric *FormatedLevelM
|
||||
for _, r := range metricItem.Data.Result {
|
||||
// for some reasons, 'metric' may not contain `resourceType` field
|
||||
// example: {"metric":{},"value":[1541142931.731,"3"]}
|
||||
k, exist := r[ResultItemMetric].(map[string]interface{})[resourceType]
|
||||
k, exist := r[ResultItemMetric].(map[string]interface{})["resource_name"]
|
||||
key := k.(string)
|
||||
if exist {
|
||||
if _, exist := indexMap[key]; !exist {
|
||||
@@ -125,7 +125,7 @@ func Sort(sortMetricName string, sortType string, fmtLevelMetric *FormatedLevelM
|
||||
|
||||
// iterator all metric to find max metricItems length
|
||||
for _, r := range metricItem.Data.Result {
|
||||
k, ok := r[ResultItemMetric].(map[string]interface{})[resourceType]
|
||||
k, ok := r[ResultItemMetric].(map[string]interface{})["resource_name"]
|
||||
if ok {
|
||||
currentResourceMap[k.(string)] = 1
|
||||
}
|
||||
@@ -154,7 +154,7 @@ func Sort(sortMetricName string, sortType string, fmtLevelMetric *FormatedLevelM
|
||||
sortedMetric := make([]map[string]interface{}, len(indexMap))
|
||||
for j := 0; j < len(re.Data.Result); j++ {
|
||||
r := re.Data.Result[j]
|
||||
k, exist := r[ResultItemMetric].(map[string]interface{})[resourceType]
|
||||
k, exist := r[ResultItemMetric].(map[string]interface{})["resource_name"]
|
||||
if exist {
|
||||
index, exist := indexMap[k.(string)]
|
||||
if exist {
|
||||
@@ -176,7 +176,7 @@ func Page(pageNum string, limitNum string, fmtLevelMetric *FormatedLevelMetric,
|
||||
}
|
||||
// matrix type can not be sorted
|
||||
for _, metricItem := range fmtLevelMetric.Results {
|
||||
// if metric reterieved field, resultType is ""
|
||||
// if metric reterieved field, resultType: ""
|
||||
if metricItem.Data.ResultType == ResultTypeMatrix {
|
||||
return fmtLevelMetric
|
||||
}
|
||||
@@ -251,7 +251,7 @@ func Page(pageNum string, limitNum string, fmtLevelMetric *FormatedLevelMetric,
|
||||
}
|
||||
|
||||
// maybe this function is time consuming
|
||||
func ReformatJson(metric string, metricsName string, needDelParams ...string) *FormatedMetric {
|
||||
func ReformatJson(metric string, metricsName string, needAddParams map[string]string, needDelParams ...string) *FormatedMetric {
|
||||
var formatMetric FormatedMetric
|
||||
|
||||
err := jsonIter.Unmarshal([]byte(metric), &formatMetric)
|
||||
@@ -277,6 +277,17 @@ func ReformatJson(metric string, metricsName string, needDelParams ...string) *F
|
||||
delete(metricMap, p)
|
||||
}
|
||||
}
|
||||
|
||||
if needAddParams != nil && len(needAddParams) > 0 {
|
||||
for n := range needAddParams {
|
||||
if v, ok := metricMap[n]; ok {
|
||||
delete(metricMap, n)
|
||||
metricMap["resource_name"] = v
|
||||
} else {
|
||||
metricMap["resource_name"] = needAddParams[n]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,11 +37,14 @@ func init() {
|
||||
namespacedResources[StatefulSets] = &statefulSetSearcher{}
|
||||
namespacedResources[Pods] = &podSearcher{}
|
||||
namespacedResources[Roles] = &roleSearcher{}
|
||||
namespacedResources[S2iBuilders] = &s2iBuilderSearcher{}
|
||||
namespacedResources[S2iRuns] = &s2iRunSearcher{}
|
||||
|
||||
clusterResources[Nodes] = &nodeSearcher{}
|
||||
clusterResources[Namespaces] = &namespaceSearcher{}
|
||||
clusterResources[ClusterRoles] = &clusterRoleSearcher{}
|
||||
clusterResources[StorageClasses] = &storageClassesSearcher{}
|
||||
clusterResources[S2iBuilderTemplates] = &s2iBuilderTemplateSearcher{}
|
||||
}
|
||||
|
||||
var namespacedResources = make(map[string]namespacedSearcherInterface)
|
||||
@@ -82,6 +85,9 @@ const (
|
||||
Namespaces = "namespaces"
|
||||
StorageClasses = "storageclasses"
|
||||
ClusterRoles = "clusterroles"
|
||||
S2iBuilderTemplates = "s2ibuildertemplates"
|
||||
S2iBuilders = "s2ibuilders"
|
||||
S2iRuns = "s2iruns"
|
||||
)
|
||||
|
||||
type namespacedSearcherInterface interface {
|
||||
|
||||
125
pkg/models/resources/s2ibuilder.go
Normal file
125
pkg/models/resources/s2ibuilder.go
Normal file
@@ -0,0 +1,125 @@
|
||||
/*
|
||||
|
||||
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 (
|
||||
"github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1"
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type s2iBuilderSearcher struct {
|
||||
}
|
||||
|
||||
// exactly Match
|
||||
func (*s2iBuilderSearcher) match(match map[string]string, item *v1alpha1.S2iBuilder) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case name:
|
||||
if item.Name != v && item.Labels[displayName] != v {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Fuzzy searchInNamespace
|
||||
func (*s2iBuilderSearcher) fuzzy(fuzzy map[string]string, item *v1alpha1.S2iBuilder) bool {
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
case name:
|
||||
if !strings.Contains(item.Name, v) && !strings.Contains(item.Labels[displayName], 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
|
||||
}
|
||||
case keyword:
|
||||
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if !searchFuzzy(item.Labels, k, v) && !searchFuzzy(item.Annotations, k, v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (*s2iBuilderSearcher) compare(a, b *v1alpha1.S2iBuilder, 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 *s2iBuilderSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
s2iBuilders, err := informers.S2iSharedInformerFactory().Devops().V1alpha1().S2iBuilders().Lister().S2iBuilders(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]*v1alpha1.S2iBuilder, 0)
|
||||
|
||||
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||
result = s2iBuilders
|
||||
} else {
|
||||
for _, item := range s2iBuilders {
|
||||
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
|
||||
}
|
||||
121
pkg/models/resources/s2ibuildertemplate.go
Normal file
121
pkg/models/resources/s2ibuildertemplate.go
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
|
||||
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 (
|
||||
"github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1"
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
)
|
||||
|
||||
type s2iBuilderTemplateSearcher struct {
|
||||
}
|
||||
|
||||
// exactly Match
|
||||
func (*s2iBuilderTemplateSearcher) match(match map[string]string, item *v1alpha1.S2iBuilderTemplate) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case name:
|
||||
if item.Name != v && item.Labels[displayName] != v {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Fuzzy searchInNamespace
|
||||
func (*s2iBuilderTemplateSearcher) fuzzy(fuzzy map[string]string, item *v1alpha1.S2iBuilderTemplate) bool {
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
case name:
|
||||
if !strings.Contains(item.Name, v) && !strings.Contains(item.Labels[displayName], v) {
|
||||
return false
|
||||
}
|
||||
case label:
|
||||
if !searchFuzzy(item.Labels, "", v) {
|
||||
return false
|
||||
}
|
||||
case annotation:
|
||||
if !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
return false
|
||||
case keyword:
|
||||
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if !searchFuzzy(item.Labels, k, v) && !searchFuzzy(item.Annotations, k, v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (*s2iBuilderTemplateSearcher) compare(a, b *v1alpha1.S2iBuilderTemplate, 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 *s2iBuilderTemplateSearcher) search(conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
builderTemplates, err := informers.S2iSharedInformerFactory().Devops().V1alpha1().S2iBuilderTemplates().Lister().List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]*v1alpha1.S2iBuilderTemplate, 0)
|
||||
|
||||
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||
result = builderTemplates
|
||||
} else {
|
||||
for _, item := range builderTemplates {
|
||||
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
|
||||
}
|
||||
132
pkg/models/resources/s2irun.go
Normal file
132
pkg/models/resources/s2irun.go
Normal file
@@ -0,0 +1,132 @@
|
||||
/*
|
||||
|
||||
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 (
|
||||
"sort"
|
||||
"strings"
|
||||
|
||||
"kubesphere.io/kubesphere/pkg/informers"
|
||||
"kubesphere.io/kubesphere/pkg/params"
|
||||
|
||||
"k8s.io/apimachinery/pkg/labels"
|
||||
|
||||
"github.com/kubesphere/s2ioperator/pkg/apis/devops/v1alpha1"
|
||||
)
|
||||
|
||||
type s2iRunSearcher struct {
|
||||
}
|
||||
|
||||
// exactly Match
|
||||
func (*s2iRunSearcher) match(match map[string]string, item *v1alpha1.S2iRun) bool {
|
||||
for k, v := range match {
|
||||
switch k {
|
||||
case name:
|
||||
if item.Name != v && item.Labels[displayName] != v {
|
||||
return false
|
||||
}
|
||||
case status:
|
||||
if string(item.Status.RunState) != v{
|
||||
return false
|
||||
}
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// Fuzzy searchInNamespace
|
||||
func (*s2iRunSearcher) fuzzy(fuzzy map[string]string, item *v1alpha1.S2iRun) bool {
|
||||
for k, v := range fuzzy {
|
||||
switch k {
|
||||
case name:
|
||||
if !strings.Contains(item.Name, v) && !strings.Contains(item.Labels[displayName], 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
|
||||
}
|
||||
case keyword:
|
||||
if !strings.Contains(item.Name, v) && !searchFuzzy(item.Labels, "", v) && !searchFuzzy(item.Annotations, "", v) {
|
||||
return false
|
||||
}
|
||||
default:
|
||||
if !searchFuzzy(item.Labels, k, v) && !searchFuzzy(item.Annotations, k, v) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
func (*s2iRunSearcher) compare(a, b *v1alpha1.S2iRun, 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 *s2iRunSearcher) search(namespace string, conditions *params.Conditions, orderBy string, reverse bool) ([]interface{}, error) {
|
||||
s2iRuns, err := informers.S2iSharedInformerFactory().Devops().V1alpha1().S2iRuns().Lister().S2iRuns(namespace).List(labels.Everything())
|
||||
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result := make([]*v1alpha1.S2iRun, 0)
|
||||
|
||||
if len(conditions.Match) == 0 && len(conditions.Fuzzy) == 0 {
|
||||
result = s2iRuns
|
||||
} else {
|
||||
for _, item := range s2iRuns {
|
||||
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
|
||||
}
|
||||
69
pkg/models/servicemesh/application.go
Normal file
69
pkg/models/servicemesh/application.go
Normal file
@@ -0,0 +1,69 @@
|
||||
package servicemesh
|
||||
|
||||
import (
|
||||
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
||||
"strings"
|
||||
)
|
||||
|
||||
const (
|
||||
AppLabel = "app"
|
||||
VersionLabel = "version"
|
||||
ApplicationNameLabel = "app.kubernetes.io/name"
|
||||
ApplicationVersionLabel = "app.kubernetes.io/version"
|
||||
)
|
||||
|
||||
var ApplicationLabels = [...]string{
|
||||
ApplicationNameLabel,
|
||||
ApplicationVersionLabel,
|
||||
AppLabel,
|
||||
}
|
||||
|
||||
var TrimChars = [...]string{".", "_", "-"}
|
||||
|
||||
// normalize version names
|
||||
// strip [_.-]
|
||||
func NormalizeVersionName(version string) string {
|
||||
for _, char := range TrimChars {
|
||||
version = strings.ReplaceAll(version, char, "")
|
||||
}
|
||||
return version
|
||||
}
|
||||
|
||||
func GetComponentName(meta *metav1.ObjectMeta) string {
|
||||
if len(meta.Labels[AppLabel]) > 0 {
|
||||
return meta.Labels[AppLabel]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func GetComponentVersion(meta *metav1.ObjectMeta) string {
|
||||
if len(meta.Labels[VersionLabel]) > 0 {
|
||||
return meta.Labels[VersionLabel]
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func ExtractApplicationLabels(meta *metav1.ObjectMeta) map[string]string {
|
||||
|
||||
labels := make(map[string]string, 0)
|
||||
for _, label := range ApplicationLabels {
|
||||
if len(meta.Labels[label]) == 0 {
|
||||
return nil
|
||||
} else {
|
||||
labels[label] = meta.Labels[label]
|
||||
}
|
||||
}
|
||||
|
||||
return labels
|
||||
}
|
||||
|
||||
func IsApplicationComponent(meta *metav1.ObjectMeta) bool {
|
||||
|
||||
for _, label := range ApplicationLabels {
|
||||
if len(meta.Labels[label]) == 0 {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
Reference in New Issue
Block a user