994 lines
28 KiB
Go
994 lines
28 KiB
Go
/*
|
|
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 metrics
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net/url"
|
|
"regexp"
|
|
"strings"
|
|
"sync"
|
|
"time"
|
|
|
|
"github.com/golang/glog"
|
|
"github.com/pkg/errors"
|
|
"k8s.io/api/core/v1"
|
|
metaV1 "k8s.io/apimachinery/pkg/apis/meta/v1"
|
|
|
|
"kubesphere.io/kubesphere/pkg/client"
|
|
"kubesphere.io/kubesphere/pkg/models"
|
|
"kubesphere.io/kubesphere/pkg/models/workspaces"
|
|
)
|
|
|
|
var nodeStatusDelLables = []string{"endpoint", "instance", "job", "namespace", "pod", "service"}
|
|
|
|
const (
|
|
ChannelMaxCapacityWorkspaceMetric = 400
|
|
ChannelMaxCapacity = 100
|
|
)
|
|
|
|
type PagedFormatedLevelMetric struct {
|
|
CurrentPage int `json:"page"`
|
|
TotalPage int `json:"total_page"`
|
|
Message string `json:"msg"`
|
|
Metric FormatedLevelMetric `json:"metrics"`
|
|
}
|
|
|
|
type FormatedLevelMetric struct {
|
|
MetricsLevel string `json:"metrics_level"`
|
|
Results []FormatedMetric `json:"results"`
|
|
}
|
|
|
|
type FormatedMetric struct {
|
|
MetricName string `json:"metric_name, omitempty"`
|
|
Status string `json:"status"`
|
|
Data FormatedMetricData `json:"data, omitempty"`
|
|
}
|
|
|
|
type FormatedMetricData struct {
|
|
Result []map[string]interface{} `json:"result"`
|
|
ResultType string `json:"resultType"`
|
|
}
|
|
|
|
type MetricResultValues []MetricResultValue
|
|
|
|
type MetricResultValue struct {
|
|
timestamp float64
|
|
value string
|
|
}
|
|
|
|
type MetricItem struct {
|
|
MetricLabel map[string]string `json:"metric"`
|
|
Value []interface{} `json:"value"`
|
|
}
|
|
|
|
type CommonMetricsResult struct {
|
|
Status string `json:"status"`
|
|
Data CommonMetricsData `json:"data"`
|
|
}
|
|
|
|
type CommonMetricsData struct {
|
|
Result []CommonResultItem `json:"result"`
|
|
ResultType string `json:"resultType"`
|
|
}
|
|
|
|
type CommonResultItem struct {
|
|
KubePodMetric KubePodMetric `json:"metric"`
|
|
Value interface{} `json:"value"`
|
|
}
|
|
|
|
type KubePodMetric struct {
|
|
CreatedByKind string `json:"created_by_kind"`
|
|
CreatedByName string `json:"created_by_name"`
|
|
Namespace string `json:"namespace"`
|
|
Pod string `json:"pod"`
|
|
}
|
|
|
|
type ComponentStatus struct {
|
|
Name string `json:"metric_name,omitempty"`
|
|
Namespace string `json:"namespace,omitempty"`
|
|
Labels map[string]string `json:"labels,omitempty"`
|
|
ComponentStatus []OneComponentStatus `json:"component"`
|
|
}
|
|
|
|
type OneComponentStatus struct {
|
|
// Valid value: "Healthy"
|
|
Type string `json:"type"`
|
|
// Valid values for "Healthy": "True", "False", or "Unknown".
|
|
Status string `json:"status"`
|
|
// Message about the condition for a component.
|
|
Message string `json:"message,omitempty"`
|
|
// Condition error code for a component.
|
|
Error string `json:"error,omitempty"`
|
|
}
|
|
|
|
func getPodNameRegexInWorkload(res string) string {
|
|
|
|
data := []byte(res)
|
|
var dat CommonMetricsResult
|
|
jsonErr := json.Unmarshal(data, &dat)
|
|
if jsonErr != nil {
|
|
glog.Errorln("json parse failed", jsonErr)
|
|
}
|
|
var podNames []string
|
|
for _, item := range dat.Data.Result {
|
|
podName := item.KubePodMetric.Pod
|
|
podNames = append(podNames, podName)
|
|
}
|
|
podNamesFilter := "^(" + strings.Join(podNames, "|") + ")$"
|
|
return podNamesFilter
|
|
}
|
|
|
|
func AssembleWorkloadMetricRequestInfo(monitoringRequest *client.MonitoringRequestParams, metricName string) (string, string) {
|
|
rule := MakeWorkloadRule(monitoringRequest.WorkloadKind, monitoringRequest.WorkloadName, monitoringRequest.NsName)
|
|
paramValues := monitoringRequest.Params
|
|
params := makeRequestParamString(rule, paramValues)
|
|
|
|
res := client.SendMonitoringRequest(client.DefaultQueryType, params)
|
|
|
|
podNamesFilter := getPodNameRegexInWorkload(res)
|
|
|
|
queryType := monitoringRequest.QueryType
|
|
rule = MakePodPromQL(metricName, monitoringRequest.NsName, "", "", podNamesFilter)
|
|
params = makeRequestParamString(rule, paramValues)
|
|
|
|
return queryType, params
|
|
}
|
|
|
|
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)
|
|
params := makeRequestParamString(rule, paramValues)
|
|
return queryType, params, rule == ""
|
|
}
|
|
|
|
func GetMetric(queryType, params, metricName string) *FormatedMetric {
|
|
res := client.SendMonitoringRequest(queryType, params)
|
|
formatedMetric := ReformatJson(res, metricName)
|
|
return formatedMetric
|
|
}
|
|
|
|
func GetNodeAddressInfo() *map[string][]v1.NodeAddress {
|
|
nodeList, _ := client.NewK8sClient().CoreV1().Nodes().List(metaV1.ListOptions{})
|
|
var nodeAddress = make(map[string][]v1.NodeAddress)
|
|
for _, node := range nodeList.Items {
|
|
nodeAddress[node.Name] = node.Status.Addresses
|
|
}
|
|
return &nodeAddress
|
|
}
|
|
|
|
func AddNodeAddressMetric(nodeMetric *FormatedMetric, nodeAddress *map[string][]v1.NodeAddress) {
|
|
|
|
for i := 0; i < len(nodeMetric.Data.Result); i++ {
|
|
metricDesc := nodeMetric.Data.Result[i][ResultItemMetric]
|
|
metricDescMap := metricDesc.(map[string]interface{})
|
|
if nodeId, exist := metricDescMap["node"]; exist {
|
|
addr, exist := (*nodeAddress)[nodeId.(string)]
|
|
if exist {
|
|
metricDescMap["address"] = addr
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func MonitorContainer(monitoringRequest *client.MonitoringRequestParams) *FormatedMetric {
|
|
queryType := monitoringRequest.QueryType
|
|
|
|
paramValues := monitoringRequest.Params
|
|
rule := MakeContainerPromQL(monitoringRequest.NsName, monitoringRequest.PodName, monitoringRequest.ContainerName, monitoringRequest.MetricsName, monitoringRequest.ContainersFilter)
|
|
params := makeRequestParamString(rule, paramValues)
|
|
|
|
res := GetMetric(queryType, params, monitoringRequest.MetricsName)
|
|
return res
|
|
}
|
|
|
|
func AssembleNamespaceMetricRequestInfo(monitoringRequest *client.MonitoringRequestParams, metricName string) (string, string) {
|
|
queryType := monitoringRequest.QueryType
|
|
|
|
paramValues := monitoringRequest.Params
|
|
rule := MakeNamespacePromQL(monitoringRequest.NsName, monitoringRequest.NsFilter, metricName)
|
|
params := makeRequestParamString(rule, paramValues)
|
|
|
|
return queryType, params
|
|
}
|
|
|
|
func AssembleWorkspaceMetricRequestInfo(monitoringRequest *client.MonitoringRequestParams, namespaceList []string, metricName string) (string, string) {
|
|
nsFilter := "^(" + strings.Join(namespaceList, "|") + ")$"
|
|
|
|
queryType := monitoringRequest.QueryType
|
|
|
|
rule := MakeWorkspacePromQL(metricName, nsFilter)
|
|
paramValues := monitoringRequest.Params
|
|
params := makeRequestParamString(rule, paramValues)
|
|
return queryType, params
|
|
}
|
|
|
|
func makeRequestParamString(rule string, paramValues url.Values) string {
|
|
|
|
var values = make(url.Values)
|
|
for key, v := range paramValues {
|
|
values.Set(key, v[0])
|
|
}
|
|
|
|
values.Set("query", rule)
|
|
|
|
params := values.Encode()
|
|
|
|
return params
|
|
}
|
|
|
|
func filterNamespace(nsFilter string, namespaceList []string) []string {
|
|
var newNSlist []string
|
|
if nsFilter == "" {
|
|
nsFilter = ".*"
|
|
}
|
|
for _, ns := range namespaceList {
|
|
bol, _ := regexp.MatchString(nsFilter, ns)
|
|
if bol {
|
|
newNSlist = append(newNSlist, ns)
|
|
}
|
|
}
|
|
return newNSlist
|
|
}
|
|
|
|
func MonitorAllWorkspaces(monitoringRequest *client.MonitoringRequestParams) *FormatedLevelMetric {
|
|
metricsFilter := monitoringRequest.MetricsFilter
|
|
if strings.Trim(metricsFilter, " ") == "" {
|
|
metricsFilter = ".*"
|
|
}
|
|
var filterMetricsName []string
|
|
for _, metricName := range WorkspaceMetricsNames {
|
|
bol, err := regexp.MatchString(metricsFilter, metricName)
|
|
if err == nil && bol {
|
|
filterMetricsName = append(filterMetricsName, metricName)
|
|
}
|
|
}
|
|
|
|
var wgAll sync.WaitGroup
|
|
var wsAllch = make(chan *[]FormatedMetric, ChannelMaxCapacityWorkspaceMetric)
|
|
|
|
workspaceNamespaceMap, _, _ := workspaces.GetAllOrgAndProjList()
|
|
for ws, _ := range workspaceNamespaceMap {
|
|
bol, err := regexp.MatchString(monitoringRequest.WsFilter, ws)
|
|
if err == nil && bol {
|
|
// a workspace
|
|
wgAll.Add(1)
|
|
go collectWorkspaceMetric(monitoringRequest, ws, filterMetricsName, &wgAll, wsAllch)
|
|
}
|
|
}
|
|
|
|
wgAll.Wait()
|
|
close(wsAllch)
|
|
|
|
fmtMetricMap := make(map[string]FormatedMetric)
|
|
for oneWsMetric := range wsAllch {
|
|
if oneWsMetric != nil {
|
|
// aggregate workspace metric
|
|
for _, metric := range *oneWsMetric {
|
|
fm, exist := fmtMetricMap[metric.MetricName]
|
|
if exist {
|
|
if metric.Status == "error" {
|
|
fm.Status = metric.Status
|
|
}
|
|
fm.Data.Result = append(fm.Data.Result, metric.Data.Result...)
|
|
fmtMetricMap[metric.MetricName] = fm
|
|
} else {
|
|
fmtMetricMap[metric.MetricName] = metric
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var metricArray = make([]FormatedMetric, 0)
|
|
for _, metric := range fmtMetricMap {
|
|
metricArray = append(metricArray, metric)
|
|
}
|
|
|
|
return &FormatedLevelMetric{
|
|
MetricsLevel: MetricLevelClusterWorkspace,
|
|
Results: metricArray,
|
|
}
|
|
}
|
|
|
|
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)
|
|
namespaceArray, err := workspaces.WorkspaceNamespaces(ws)
|
|
if err != nil {
|
|
glog.Errorln(err.Error())
|
|
}
|
|
// add by namespace
|
|
for _, metricName := range filterMetricsName {
|
|
wg.Add(1)
|
|
go func(metricName string) {
|
|
defer func() {
|
|
if err := recover(); err != nil {
|
|
glog.Errorln(err)
|
|
}
|
|
}()
|
|
|
|
queryType, params := AssembleWorkspaceMetricRequestInfo(monitoringRequest, namespaceArray, metricName)
|
|
ch <- GetMetric(queryType, params, metricName)
|
|
|
|
wg.Done()
|
|
}(metricName)
|
|
}
|
|
|
|
wg.Wait()
|
|
close(ch)
|
|
|
|
var metricsArray []FormatedMetric
|
|
for oneMetric := range ch {
|
|
if oneMetric != nil {
|
|
// add "workspace" filed to oneMetric `metric` field
|
|
for i := 0; i < len(oneMetric.Data.Result); i++ {
|
|
tmap := oneMetric.Data.Result[i]["metric"].(map[string]interface{})
|
|
tmap[MetricLevelWorkspace] = ws
|
|
oneMetric.Data.Result[i]["metric"] = tmap
|
|
}
|
|
metricsArray = append(metricsArray, *oneMetric)
|
|
}
|
|
}
|
|
|
|
wsAllch <- &metricsArray
|
|
}
|
|
|
|
func MonitorAllMetrics(monitoringRequest *client.MonitoringRequestParams, resourceType string) *FormatedLevelMetric {
|
|
metricsFilter := monitoringRequest.MetricsFilter
|
|
if metricsFilter == "" {
|
|
metricsFilter = ".*"
|
|
}
|
|
|
|
var ch = make(chan *FormatedMetric, ChannelMaxCapacity)
|
|
var wg sync.WaitGroup
|
|
|
|
switch resourceType {
|
|
case MetricLevelCluster:
|
|
{
|
|
for _, metricName := range ClusterMetricsNames {
|
|
bol, err := regexp.MatchString(metricsFilter, metricName)
|
|
if err == nil && bol {
|
|
wg.Add(1)
|
|
go func(metricName string) {
|
|
queryType, params := AssembleClusterMetricRequestInfo(monitoringRequest, metricName)
|
|
clusterMetrics := GetMetric(queryType, params, metricName)
|
|
|
|
// for this special case, get namespace history which in a workspace by determining namespace label
|
|
if metricName == MetricNameWorkspaceAllProjectCount {
|
|
clusterMetrics = MonitorWorkspaceNamespaceHistory(clusterMetrics)
|
|
}
|
|
|
|
ch <- clusterMetrics
|
|
|
|
wg.Done()
|
|
}(metricName)
|
|
}
|
|
}
|
|
}
|
|
case MetricLevelNode:
|
|
{
|
|
for _, metricName := range NodeMetricsNames {
|
|
bol, err := regexp.MatchString(metricsFilter, metricName)
|
|
if err == nil && bol {
|
|
wg.Add(1)
|
|
go func(metricName string) {
|
|
queryType, params := AssembleNodeMetricRequestInfo(monitoringRequest, metricName)
|
|
ch <- GetMetric(queryType, params, metricName)
|
|
wg.Done()
|
|
}(metricName)
|
|
}
|
|
}
|
|
}
|
|
case MetricLevelWorkspace:
|
|
{
|
|
namespaceArray, err := workspaces.WorkspaceNamespaces(monitoringRequest.WsName)
|
|
if err != nil {
|
|
glog.Errorln(err.Error())
|
|
}
|
|
namespaceArray = filterNamespace(monitoringRequest.NsFilter, namespaceArray)
|
|
|
|
if monitoringRequest.Tp == "" {
|
|
for _, metricName := range WorkspaceMetricsNames {
|
|
bol, err := regexp.MatchString(metricsFilter, metricName)
|
|
if err == nil && bol {
|
|
wg.Add(1)
|
|
go func(metricName string) {
|
|
queryType, params := AssembleWorkspaceMetricRequestInfo(monitoringRequest, namespaceArray, metricName)
|
|
ch <- GetMetric(queryType, params, metricName)
|
|
wg.Done()
|
|
}(metricName)
|
|
}
|
|
}
|
|
} else {
|
|
for _, metricName := range NamespaceMetricsNames {
|
|
bol, err := regexp.MatchString(metricsFilter, metricName)
|
|
ns := "^(" + strings.Join(namespaceArray, "|") + ")$"
|
|
monitoringRequest.NsFilter = ns
|
|
if err == nil && bol {
|
|
wg.Add(1)
|
|
go func(metricName string) {
|
|
queryType, params := AssembleNamespaceMetricRequestInfo(monitoringRequest, metricName)
|
|
ch <- GetMetric(queryType, params, metricName)
|
|
wg.Done()
|
|
}(metricName)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
case MetricLevelNamespace:
|
|
{
|
|
for _, metricName := range NamespaceMetricsNames {
|
|
bol, err := regexp.MatchString(metricsFilter, metricName)
|
|
if err == nil && bol {
|
|
wg.Add(1)
|
|
go func(metricName string) {
|
|
queryType, params := AssembleNamespaceMetricRequestInfo(monitoringRequest, metricName)
|
|
ch <- GetMetric(queryType, params, metricName)
|
|
wg.Done()
|
|
}(metricName)
|
|
}
|
|
}
|
|
}
|
|
case MetricLevelWorkload:
|
|
{
|
|
for _, metricName := range WorkloadMetricsNames {
|
|
bol, err := regexp.MatchString(metricsFilter, metricName)
|
|
if err == nil && bol {
|
|
wg.Add(1)
|
|
go func(metricName string) {
|
|
metricName = strings.TrimLeft(metricName, "workload_")
|
|
queryType, params := AssembleWorkloadMetricRequestInfo(monitoringRequest, metricName)
|
|
ch <- GetMetric(queryType, params, metricName)
|
|
wg.Done()
|
|
}(metricName)
|
|
}
|
|
}
|
|
}
|
|
case MetricLevelPod:
|
|
{
|
|
for _, metricName := range PodMetricsNames {
|
|
bol, err := regexp.MatchString(metricsFilter, metricName)
|
|
if err == nil && bol {
|
|
wg.Add(1)
|
|
go func(metricName string) {
|
|
queryType, params, nullRule := AssemblePodMetricRequestInfo(monitoringRequest, metricName)
|
|
if !nullRule {
|
|
ch <- GetMetric(queryType, params, metricName)
|
|
} else {
|
|
ch <- nil
|
|
}
|
|
wg.Done()
|
|
}(metricName)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
wg.Wait()
|
|
close(ch)
|
|
|
|
var metricsArray []FormatedMetric
|
|
|
|
for oneMetric := range ch {
|
|
if oneMetric != nil {
|
|
metricsArray = append(metricsArray, *oneMetric)
|
|
}
|
|
}
|
|
|
|
return &FormatedLevelMetric{
|
|
MetricsLevel: resourceType,
|
|
Results: metricsArray,
|
|
}
|
|
}
|
|
|
|
func MonitorWorkspaceNamespaceHistory(metric *FormatedMetric) *FormatedMetric {
|
|
resultType := metric.Data.ResultType
|
|
//metric.Status
|
|
metricName := metric.MetricName
|
|
|
|
for i := 0; i < len(metric.Data.Result); i++ {
|
|
metricItem := metric.Data.Result[i]
|
|
|
|
if resultType == ResultTypeVector {
|
|
timeAndValue, sure := metricItem[ResultItemValue].([]interface{})
|
|
if !sure {
|
|
return metric
|
|
}
|
|
metric := getNamespaceHistoryMetric(timeAndValue[0].(float64), metricName)
|
|
|
|
workspaceNamespaceCount := calcWorkspaceNamespace(metric)
|
|
|
|
timeAndValue[1] = fmt.Sprintf("%d", workspaceNamespaceCount)
|
|
|
|
} else if resultType == ResultTypeMatrix {
|
|
|
|
values, sure := metricItem[ResultItemValues].([]interface{})
|
|
if !sure {
|
|
return metric
|
|
}
|
|
|
|
for _, valueItem := range values {
|
|
timeAndValue, sure := valueItem.([]interface{})
|
|
if !sure {
|
|
return metric
|
|
}
|
|
|
|
metric := getNamespaceHistoryMetric(timeAndValue[0].(float64), metricName)
|
|
|
|
workspaceNamespaceCount := calcWorkspaceNamespace(metric)
|
|
|
|
timeAndValue[1] = fmt.Sprintf("%d", workspaceNamespaceCount)
|
|
}
|
|
}
|
|
}
|
|
|
|
return metric
|
|
}
|
|
|
|
func getNamespaceHistoryMetric(timestamp float64, metricName string) *FormatedMetric {
|
|
var timeRelatedParams = make(url.Values)
|
|
timeRelatedParams.Set("time", fmt.Sprintf("%f", timestamp))
|
|
timeRelatedParams.Set("query", NamespaceLabelRule)
|
|
params := timeRelatedParams.Encode()
|
|
metric := GetMetric(client.DefaultQueryType, params, metricName)
|
|
return metric
|
|
}
|
|
|
|
// calculate all namespace which belong to workspaces
|
|
func calcWorkspaceNamespace(metric *FormatedMetric) int {
|
|
if metric.Status == "error" {
|
|
glog.Errorf("failed when retrive namespace history, the metric is %v", metric.Data.Result)
|
|
return 0
|
|
}
|
|
|
|
var workspaceNamespaceCount = 0
|
|
|
|
for _, result := range metric.Data.Result {
|
|
tmpMap := result[ResultItemMetric].(map[string]interface{})
|
|
wsName, exist := tmpMap[WorkspaceJoinedKey]
|
|
|
|
if exist && wsName != "" {
|
|
workspaceNamespaceCount += 1
|
|
}
|
|
}
|
|
|
|
return workspaceNamespaceCount
|
|
}
|
|
|
|
func MonitorAllWorkspacesStatistics() *FormatedLevelMetric {
|
|
|
|
wg := sync.WaitGroup{}
|
|
var metricsArray []FormatedMetric
|
|
timestamp := time.Now().Unix()
|
|
|
|
var orgResultItem *FormatedMetric
|
|
var devopsResultItem *FormatedMetric
|
|
var clusterProjResultItem *FormatedMetric
|
|
var workspaceProjResultItem *FormatedMetric
|
|
var accountResultItem *FormatedMetric
|
|
|
|
wsMap, projs, errProj := workspaces.GetAllOrgAndProjList()
|
|
|
|
wg.Add(5)
|
|
|
|
go func() {
|
|
orgNums, errOrg := workspaces.GetAllOrgNums()
|
|
if errOrg != nil {
|
|
glog.Errorln(errOrg.Error())
|
|
}
|
|
orgResultItem = getSpecificMetricItem(timestamp, MetricNameWorkspaceAllOrganizationCount, WorkspaceResourceKindOrganization, orgNums, errOrg)
|
|
wg.Done()
|
|
}()
|
|
|
|
go func() {
|
|
devOpsProjectNums, errDevops := workspaces.GetAllDevOpsProjectsNums()
|
|
if errDevops != nil {
|
|
glog.Errorln(errDevops.Error())
|
|
}
|
|
devopsResultItem = getSpecificMetricItem(timestamp, MetricNameWorkspaceAllDevopsCount, WorkspaceResourceKindDevops, devOpsProjectNums, errDevops)
|
|
wg.Done()
|
|
}()
|
|
|
|
go func() {
|
|
var projNums = 0
|
|
for _, v := range wsMap {
|
|
projNums += len(v)
|
|
}
|
|
if errProj != nil {
|
|
glog.Errorln(errProj.Error())
|
|
}
|
|
workspaceProjResultItem = getSpecificMetricItem(timestamp, MetricNameWorkspaceAllProjectCount, WorkspaceResourceKindNamespace, projNums, errProj)
|
|
wg.Done()
|
|
}()
|
|
|
|
go func() {
|
|
projNums := len(projs)
|
|
if errProj != nil {
|
|
glog.Errorln(errProj.Error())
|
|
}
|
|
clusterProjResultItem = getSpecificMetricItem(timestamp, MetricNameClusterAllProjectCount, WorkspaceResourceKindNamespace, projNums, errProj)
|
|
wg.Done()
|
|
}()
|
|
|
|
go func() {
|
|
actNums, errAct := workspaces.GetAllAccountNums()
|
|
if errAct != nil {
|
|
glog.Errorln(errAct.Error())
|
|
}
|
|
accountResultItem = getSpecificMetricItem(timestamp, MetricNameWorkspaceAllAccountCount, WorkspaceResourceKindAccount, actNums, errAct)
|
|
wg.Done()
|
|
}()
|
|
|
|
wg.Wait()
|
|
|
|
metricsArray = append(metricsArray, *orgResultItem, *devopsResultItem, *workspaceProjResultItem, *accountResultItem, *clusterProjResultItem)
|
|
|
|
return &FormatedLevelMetric{
|
|
MetricsLevel: MetricLevelWorkspace,
|
|
Results: metricsArray,
|
|
}
|
|
}
|
|
|
|
func MonitorOneWorkspaceStatistics(wsName string) *FormatedLevelMetric {
|
|
|
|
var nsMetrics *FormatedMetric
|
|
var devopsMetrics *FormatedMetric
|
|
var memberMetrics *FormatedMetric
|
|
var roleMetrics *FormatedMetric
|
|
|
|
wg := sync.WaitGroup{}
|
|
wg.Add(4)
|
|
|
|
var fMetricsArray []FormatedMetric
|
|
timestamp := int64(time.Now().Unix())
|
|
|
|
go func() {
|
|
// add namespaces(project) metric
|
|
namespaces, errNs := workspaces.WorkspaceNamespaces(wsName)
|
|
namespaces, noneExistentNs := getExistingNamespace(namespaces)
|
|
if len(noneExistentNs) != 0 {
|
|
nsStr := strings.Join(noneExistentNs, "|")
|
|
errStr := "the namespaces " + nsStr + " do not exist"
|
|
if errNs == nil {
|
|
errNs = errors.New(errStr)
|
|
} else {
|
|
errNs = errors.New(errNs.Error() + "\t" + errStr)
|
|
}
|
|
}
|
|
if errNs != nil {
|
|
glog.Errorln(errNs.Error())
|
|
}
|
|
nsMetrics = getSpecificMetricItem(timestamp, MetricNameWorkspaceNamespaceCount, WorkspaceResourceKindNamespace, len(namespaces), errNs)
|
|
wg.Done()
|
|
}()
|
|
|
|
go func() {
|
|
devOpsProjects, errDevOps := workspaces.GetDevOpsProjects(wsName)
|
|
if errDevOps != nil {
|
|
glog.Errorln(errDevOps.Error())
|
|
}
|
|
// add devops metric
|
|
devopsMetrics = getSpecificMetricItem(timestamp, MetricNameWorkspaceDevopsCount, WorkspaceResourceKindDevops, len(devOpsProjects), errDevOps)
|
|
wg.Done()
|
|
}()
|
|
|
|
go func() {
|
|
members, errMemb := workspaces.GetOrgMembers(wsName)
|
|
if errMemb != nil {
|
|
glog.Errorln(errMemb.Error())
|
|
}
|
|
// add member metric
|
|
memberMetrics = getSpecificMetricItem(timestamp, MetricNameWorkspaceMemberCount, WorkspaceResourceKindMember, len(members), errMemb)
|
|
wg.Done()
|
|
}()
|
|
|
|
go func() {
|
|
roles, errRole := workspaces.GetOrgRoles(wsName)
|
|
if errRole != nil {
|
|
glog.Errorln(errRole.Error())
|
|
}
|
|
// add role metric
|
|
roleMetrics = getSpecificMetricItem(timestamp, MetricNameWorkspaceRoleCount, WorkspaceResourceKindRole, len(roles), errRole)
|
|
wg.Done()
|
|
}()
|
|
|
|
wg.Wait()
|
|
|
|
fMetricsArray = append(fMetricsArray, *nsMetrics, *devopsMetrics, *memberMetrics, *roleMetrics)
|
|
|
|
return &FormatedLevelMetric{
|
|
MetricsLevel: MetricLevelWorkspace,
|
|
Results: fMetricsArray,
|
|
}
|
|
}
|
|
|
|
func getSpecificMetricItem(timestamp int64, metricName string, resource string, count int, err error, resourceType ...string) *FormatedMetric {
|
|
var nsMetrics FormatedMetric
|
|
nsMetrics.MetricName = metricName
|
|
nsMetrics.Data.ResultType = ResultTypeVector
|
|
resultItem := make(map[string]interface{})
|
|
tmp := make(map[string]string)
|
|
|
|
if len(resourceType) > 0 {
|
|
tmp[resourceType[0]] = resource
|
|
} else {
|
|
tmp[ResultItemMetricResource] = resource
|
|
}
|
|
|
|
if err == nil {
|
|
nsMetrics.Status = MetricStatusSuccess
|
|
} else {
|
|
nsMetrics.Status = MetricStatusError
|
|
resultItem["errormsg"] = err.Error()
|
|
}
|
|
|
|
resultItem[ResultItemMetric] = tmp
|
|
resultItem[ResultItemValue] = []interface{}{timestamp, count}
|
|
nsMetrics.Data.Result = make([]map[string]interface{}, 1)
|
|
nsMetrics.Data.Result[0] = resultItem
|
|
return &nsMetrics
|
|
}
|
|
|
|
// k8s component(controller, scheduler, etcd) status
|
|
func MonitorComponentStatus(monitoringRequest *client.MonitoringRequestParams) *[]interface{} {
|
|
componentList, err := client.NewK8sClient().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 := client.SendMonitoringRequest(queryType, params)
|
|
|
|
nodeStatusMetric := ReformatJson(res, "node_status", nodeStatusDelLables...)
|
|
nodeStatusMetric = ReformatNodeStatusField(nodeStatusMetric)
|
|
|
|
var normalNodes []string
|
|
var abnormalNodes []string
|
|
for _, result := range nodeStatusMetric.Data.Result {
|
|
tmap := result[ResultItemMetric].(map[string]interface{})
|
|
if tmap[MetricStatus].(string) == "false" {
|
|
abnormalNodes = append(abnormalNodes, tmap[MetricLevelNode].(string))
|
|
} else {
|
|
normalNodes = append(normalNodes, tmap[MetricLevelNode].(string))
|
|
}
|
|
}
|
|
|
|
Components, err := models.GetAllComponentsStatus()
|
|
|
|
if err != nil {
|
|
glog.Error(err.Error())
|
|
}
|
|
|
|
var namspaceComponentHealthyMap = make(map[string]int)
|
|
var namspaceComponentTotalMap = make(map[string]int)
|
|
|
|
for _, ns := range models.SYSTEM_NAMESPACES {
|
|
nsStatus, exist := Components[ns]
|
|
if exist {
|
|
for _, nsStatusItem := range nsStatus.(map[string]interface{}) {
|
|
component := nsStatusItem.(models.Component)
|
|
namspaceComponentTotalMap[ns] += 1
|
|
if component.HealthyBackends == component.TotalBackends {
|
|
namspaceComponentHealthyMap[ns] += 1
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
timestamp := int64(time.Now().Unix())
|
|
|
|
onlineMetricItems := makeMetricItems(timestamp, namspaceComponentHealthyMap, MetricLevelNamespace)
|
|
metricItems := makeMetricItems(timestamp, namspaceComponentTotalMap, 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
|
|
}
|
|
|
|
// monitor k8s event, there are two status: Normal, Warning
|
|
func MonitorEvents(nsFilter string) *[]v1.Event {
|
|
namespaceMap, err := getAllNamespace()
|
|
if err != nil {
|
|
glog.Errorln(err.Error())
|
|
}
|
|
var nsList = make([]string, 0)
|
|
for ns, _ := range namespaceMap {
|
|
nsList = append(nsList, ns)
|
|
}
|
|
|
|
filterNS := filterNamespace(nsFilter, nsList)
|
|
var eventsList = make([]v1.Event, 0)
|
|
|
|
for _, ns := range filterNS {
|
|
events, err := client.NewK8sClient().CoreV1().Events(ns).List(metaV1.ListOptions{})
|
|
if err != nil {
|
|
glog.Errorln(err.Error())
|
|
} else {
|
|
for _, item := range events.Items {
|
|
eventsList = append(eventsList, item)
|
|
}
|
|
}
|
|
}
|
|
return &eventsList
|
|
}
|
|
|
|
func AssembleClusterMetricRequestInfo(monitoringRequest *client.MonitoringRequestParams, metricName string) (string, string) {
|
|
queryType := monitoringRequest.QueryType
|
|
paramValues := monitoringRequest.Params
|
|
rule := MakeClusterRule(metricName)
|
|
params := makeRequestParamString(rule, paramValues)
|
|
|
|
return queryType, params
|
|
}
|
|
|
|
func AssembleNodeMetricRequestInfo(monitoringRequest *client.MonitoringRequestParams, metricName string) (string, string) {
|
|
queryType := monitoringRequest.QueryType
|
|
paramValues := monitoringRequest.Params
|
|
rule := MakeNodeRule(monitoringRequest.NodeId, monitoringRequest.NodesFilter, metricName)
|
|
params := makeRequestParamString(rule, paramValues)
|
|
|
|
return queryType, params
|
|
}
|
|
|
|
func getExistingNamespace(namespaces []string) ([]string, []string) {
|
|
namespaceMap, err := getAllNamespace()
|
|
var existedNS []string
|
|
var noneExistedNS []string
|
|
if err != nil {
|
|
return namespaces, nil
|
|
}
|
|
for _, ns := range namespaces {
|
|
if _, exist := namespaceMap[ns]; exist {
|
|
existedNS = append(existedNS, ns)
|
|
} else {
|
|
noneExistedNS = append(noneExistedNS, ns)
|
|
}
|
|
}
|
|
return existedNS, noneExistedNS
|
|
}
|
|
|
|
func getAllNamespace() (map[string]int, error) {
|
|
k8sClient := client.NewK8sClient()
|
|
nsList, err := k8sClient.CoreV1().Namespaces().List(metaV1.ListOptions{})
|
|
if err != nil {
|
|
glog.Errorln(err.Error())
|
|
return nil, err
|
|
}
|
|
namespaceMap := make(map[string]int)
|
|
for _, item := range nsList.Items {
|
|
namespaceMap[item.Name] = 0
|
|
}
|
|
return namespaceMap, nil
|
|
}
|
|
|
|
func MonitorWorkloadCount(namespace string) *FormatedMetric {
|
|
quotaMetric, err := models.GetNamespaceQuota(namespace)
|
|
fMetric := convertQuota2MetricStruct(quotaMetric)
|
|
|
|
// whether the namespace in request parameters exists?
|
|
namespaceMap, err := getAllNamespace()
|
|
|
|
_, exist := namespaceMap[namespace]
|
|
if err != nil {
|
|
exist = true
|
|
}
|
|
|
|
if !exist || err != nil {
|
|
fMetric.Status = MetricStatusError
|
|
fMetric.Data.ResultType = ""
|
|
errInfo := make(map[string]interface{})
|
|
if err != nil {
|
|
errInfo["errormsg"] = err.Error()
|
|
} else {
|
|
errInfo["errormsg"] = "namespace " + namespace + " does not exist"
|
|
}
|
|
fMetric.Data.Result = []map[string]interface{}{errInfo}
|
|
}
|
|
|
|
return fMetric
|
|
}
|
|
|
|
func convertQuota2MetricStruct(quotaMetric *models.ResourceQuota) *FormatedMetric {
|
|
var fMetric FormatedMetric
|
|
fMetric.MetricName = MetricNameWorkloadCount
|
|
fMetric.Status = MetricStatusSuccess
|
|
fMetric.Data.ResultType = ResultTypeVector
|
|
timestamp := int64(time.Now().Unix())
|
|
var resultItems []map[string]interface{}
|
|
|
|
hardMap := make(map[string]string)
|
|
for resourceName, v := range quotaMetric.Data.Hard {
|
|
hardMap[resourceName.String()] = v.String()
|
|
}
|
|
|
|
for resourceName, v := range quotaMetric.Data.Used {
|
|
resultItem := make(map[string]interface{})
|
|
tmp := make(map[string]string)
|
|
tmp[ResultItemMetricResource] = resourceName.String()
|
|
resultItem[ResultItemMetric] = tmp
|
|
resultItem[ResultItemValue] = []interface{}{timestamp, hardMap[resourceName.String()], v.String()}
|
|
resultItems = append(resultItems, resultItem)
|
|
}
|
|
|
|
fMetric.Data.Result = resultItems
|
|
return &fMetric
|
|
}
|