Resolved merge conflict

Signed-off-by: hongming <talonwan@yunify.com>
This commit is contained in:
hongming
2019-04-08 22:54:51 +08:00
327 changed files with 64018 additions and 406 deletions

View File

@@ -172,6 +172,8 @@ func addWebService(c *restful.Container) error {
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
// Only use this api to monitor status of pods under the {workload}
// To monitor a specific workload, try the next two apis with "resources_filter"
ws.Route(ws.GET("/namespaces/{namespace}/workloads/{workload_kind}/{workload}").To(monitoring.MonitorWorkload).
Doc("monitor specific workload level metrics").
Param(ws.PathParameter("namespace", "namespace").DataType("string").Required(true).DefaultValue("kube-system")).
@@ -188,6 +190,21 @@ func addWebService(c *restful.Container) error {
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET("/namespaces/{namespace}/workloads/{workload_kind}").To(monitoring.MonitorWorkload).
Doc("monitor specific workload kind level metrics").
Param(ws.PathParameter("namespace", "namespace").DataType("string").Required(true).DefaultValue("kube-system")).
Param(ws.PathParameter("workload_kind", "workload kind").DataType("string").Required(true).DefaultValue("daemonset")).
Param(ws.QueryParameter("metrics_filter", "metrics name cpu memory...").DataType("string").Required(false)).
Param(ws.QueryParameter("resources_filter", "pod re2 expression filter").DataType("string").Required(false).DefaultValue("openpitrix.*")).
Param(ws.QueryParameter("sort_metric", "sort metric").DataType("string").Required(false)).
Param(ws.QueryParameter("sort_type", "ascending descending order").DataType("string").Required(false)).
Param(ws.QueryParameter("page", "page number").DataType("string").Required(false).DefaultValue("1")).
Param(ws.QueryParameter("limit", "max metric items in a page").DataType("string").Required(false).DefaultValue("4")).
Param(ws.QueryParameter("type", "rank, statistic").DataType("string").Required(false).DefaultValue("rank")).
Metadata(restfulspec.KeyOpenAPITags, tags)).
Consumes(restful.MIME_JSON, restful.MIME_XML).
Produces(restful.MIME_JSON)
ws.Route(ws.GET("/namespaces/{namespace}/workloads").To(monitoring.MonitorWorkload).
Doc("monitor all workload level metrics").
Param(ws.PathParameter("namespace", "namespace").DataType("string").Required(true).DefaultValue("kube-system")).

View File

@@ -24,6 +24,7 @@ import (
corev1 "k8s.io/api/core/v1"
"k8s.io/apimachinery/pkg/runtime/schema"
"kubesphere.io/kubesphere/pkg/apiserver/components"
"kubesphere.io/kubesphere/pkg/apiserver/git"
"kubesphere.io/kubesphere/pkg/apiserver/quotas"
"kubesphere.io/kubesphere/pkg/apiserver/registries"
"kubesphere.io/kubesphere/pkg/apiserver/resources"
@@ -33,6 +34,7 @@ import (
"kubesphere.io/kubesphere/pkg/apiserver/workloadstatuses"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models"
gitmodel "kubesphere.io/kubesphere/pkg/models/git"
"kubesphere.io/kubesphere/pkg/params"
)
@@ -165,6 +167,15 @@ func addWebService(c *restful.Container) error {
Doc("docker registry verify").
Writes(errors.Error{}))
tags = []string{"Git"}
webservice.Route(webservice.POST("/git/readverify").
To(
git.GitReadVerify).
Metadata(restfulspec.KeyOpenAPITags, tags).
Doc("secret git read verify").
Reads(gitmodel.AuthInfo{}).
Writes(errors.Error{}),
)
tags = []string{"Revision"}
webservice.Route(webservice.GET("/namespaces/{namespace}/daemonsets/{daemonset}/revisions/{revision}").

View File

@@ -28,7 +28,6 @@ import (
type StrategyType string
const (
// Canary strategy type
CanaryType StrategyType = "Canary"
@@ -39,9 +38,21 @@ const (
Mirror StrategyType = "Mirror"
)
type StrategyPolicy string
const (
// apply strategy only until workload is ready
PolicyWaitForWorkloadReady StrategyPolicy = "WaitForWorkloadReady"
// apply strategy immediately no matter workload status is
PolicyImmediately StrategyPolicy = "Immediately"
// pause strategy
PolicyPause StrategyPolicy = "Paused"
)
// StrategySpec defines the desired state of Strategy
type StrategySpec struct {
// Strategy type
Type StrategyType `json:"type,omitempty"`
@@ -62,9 +73,9 @@ type StrategySpec struct {
// Template describes the virtual service that will be created.
Template VirtualServiceTemplateSpec `json:"template,omitempty"`
// Indicates that the strategy is paused and will not be processed
// strategy policy, how the strategy will be applied
// by the strategy controller
Paused bool `json:"paused,omitempty"`
StrategyPolicy StrategyPolicy `json:"strategyPolicy,omitempty"`
}
// VirtualServiceTemplateSpec

30
pkg/apiserver/git/git.go Normal file
View File

@@ -0,0 +1,30 @@
package git
import (
"net/http"
"github.com/emicklei/go-restful"
"kubesphere.io/kubesphere/pkg/errors"
"kubesphere.io/kubesphere/pkg/models/git"
)
func GitReadVerify(request *restful.Request, response *restful.Response) {
authInfo := git.AuthInfo{}
err := request.ReadEntity(&authInfo)
ns := request.PathParameter("namespace")
if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
err = git.GitReadVerify(ns, authInfo)
if err != nil {
response.WriteHeaderAndEntity(http.StatusInternalServerError, errors.Wrap(err))
return
}
response.WriteAsJson(errors.None)
}

View File

@@ -20,11 +20,11 @@ package monitoring
import (
"github.com/emicklei/go-restful"
"kubesphere.io/kubesphere/pkg/models/metrics"
prom "kubesphere.io/kubesphere/pkg/simple/client/prometheus"
"kubesphere.io/kubesphere/pkg/simple/client/prometheus"
)
func MonitorPod(request *restful.Request, response *restful.Response) {
requestParams := prom.ParseMonitoringRequestParams(request)
requestParams := prometheus.ParseMonitoringRequestParams(request)
podName := requestParams.PodName
metricName := requestParams.MetricsName
if podName != "" {
@@ -32,7 +32,7 @@ func MonitorPod(request *restful.Request, response *restful.Response) {
queryType, params, nullRule := metrics.AssemblePodMetricRequestInfo(requestParams, metricName)
var res *metrics.FormatedMetric
if !nullRule {
metricsStr := prom.SendMonitoringRequest(queryType, params)
metricsStr := prometheus.SendMonitoringRequest(queryType, params)
res = metrics.ReformatJson(metricsStr, metricName, map[string]string{"pod_name": ""})
}
response.WriteAsJson(res)
@@ -49,7 +49,7 @@ func MonitorPod(request *restful.Request, response *restful.Response) {
}
func MonitorContainer(request *restful.Request, response *restful.Response) {
requestParams := prom.ParseMonitoringRequestParams(request)
requestParams := prometheus.ParseMonitoringRequestParams(request)
metricName := requestParams.MetricsName
if requestParams.MetricsFilter != "" {
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelContainer)
@@ -68,23 +68,12 @@ func MonitorContainer(request *restful.Request, response *restful.Response) {
}
func MonitorWorkload(request *restful.Request, response *restful.Response) {
requestParams := prom.ParseMonitoringRequestParams(request)
requestParams := prometheus.ParseMonitoringRequestParams(request)
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelWorkload)
var sortedMetrics *metrics.FormatedLevelMetric
var maxMetricCount int
wlKind := requestParams.WorkloadKind
// sorting
if wlKind == "" {
sortedMetrics, maxMetricCount = metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics)
} else {
sortedMetrics, maxMetricCount = metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics)
}
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics)
// paging
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
@@ -95,7 +84,7 @@ func MonitorWorkload(request *restful.Request, response *restful.Response) {
func MonitorAllWorkspaces(request *restful.Request, response *restful.Response) {
requestParams := prom.ParseMonitoringRequestParams(request)
requestParams := prometheus.ParseMonitoringRequestParams(request)
tp := requestParams.Tp
if tp == "statistics" {
@@ -105,27 +94,31 @@ func MonitorAllWorkspaces(request *restful.Request, response *restful.Response)
} else if tp == "rank" {
rawMetrics := metrics.MonitorAllWorkspaces(requestParams)
// sorting
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics)
// paging
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
response.WriteAsJson(pagedMetrics)
} else {
res := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelWorkspace)
response.WriteAsJson(res)
rawMetrics := metrics.MonitorAllWorkspaces(requestParams)
response.WriteAsJson(rawMetrics)
}
}
func MonitorOneWorkspace(request *restful.Request, response *restful.Response) {
requestParams := prom.ParseMonitoringRequestParams(request)
requestParams := prometheus.ParseMonitoringRequestParams(request)
tp := requestParams.Tp
if tp == "rank" {
// multiple
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelWorkspace)
// sorting
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics)
// paging
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
response.WriteAsJson(pagedMetrics)
@@ -143,34 +136,25 @@ func MonitorOneWorkspace(request *restful.Request, response *restful.Response) {
}
func MonitorNamespace(request *restful.Request, response *restful.Response) {
requestParams := prom.ParseMonitoringRequestParams(request)
metricName := requestParams.MetricsName
nsName := requestParams.NsName
if nsName != "" {
// single
queryType, params := metrics.AssembleNamespaceMetricRequestInfo(requestParams, metricName)
metricsStr := prom.SendMonitoringRequest(queryType, params)
res := metrics.ReformatJson(metricsStr, metricName, map[string]string{"namespace": ""})
response.WriteAsJson(res)
} else {
// multiple
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelNamespace)
// sorting
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics)
// paging
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
response.WriteAsJson(pagedMetrics)
}
requestParams := prometheus.ParseMonitoringRequestParams(request)
// multiple
rawMetrics := metrics.MonitorAllMetrics(requestParams, metrics.MetricLevelNamespace)
// sorting
sortedMetrics, maxMetricCount := metrics.Sort(requestParams.SortMetricName, requestParams.SortType, rawMetrics)
// paging
pagedMetrics := metrics.Page(requestParams.PageNum, requestParams.LimitNum, sortedMetrics, maxMetricCount)
response.WriteAsJson(pagedMetrics)
}
func MonitorCluster(request *restful.Request, response *restful.Response) {
requestParams := prom.ParseMonitoringRequestParams(request)
requestParams := prometheus.ParseMonitoringRequestParams(request)
metricName := requestParams.MetricsName
if metricName != "" {
// single
queryType, params := metrics.AssembleClusterMetricRequestInfo(requestParams, metricName)
metricsStr := prom.SendMonitoringRequest(queryType, params)
metricsStr := prometheus.SendMonitoringRequest(queryType, params)
res := metrics.ReformatJson(metricsStr, metricName, map[string]string{"cluster": "local"})
response.WriteAsJson(res)
@@ -182,14 +166,17 @@ func MonitorCluster(request *restful.Request, response *restful.Response) {
}
func MonitorNode(request *restful.Request, response *restful.Response) {
requestParams := prom.ParseMonitoringRequestParams(request)
requestParams := prometheus.ParseMonitoringRequestParams(request)
metricName := requestParams.MetricsName
if metricName != "" {
// single
queryType, params := metrics.AssembleNodeMetricRequestInfo(requestParams, metricName)
metricsStr := prom.SendMonitoringRequest(queryType, params)
metricsStr := prometheus.SendMonitoringRequest(queryType, params)
res := metrics.ReformatJson(metricsStr, metricName, map[string]string{"node": ""})
// The raw node-exporter result doesn't include ip address information
// Thereby, append node ip address to .data.result[].metric
nodeAddress := metrics.GetNodeAddressInfo()
metrics.AddNodeAddressMetric(res, nodeAddress)

View File

@@ -220,10 +220,13 @@ func (v *DestinationRuleController) syncService(key string) error {
return nil
}
if len(service.Labels) < len(util.ApplicationLabels) || !util.IsApplicationComponent(service.Labels) ||
if len(service.Labels) < len(util.ApplicationLabels) ||
!util.IsApplicationComponent(service.Labels) ||
!util.IsServicemeshEnabled(service.Annotations) ||
len(service.Spec.Ports) == 0 {
// services don't have enough labels to create a virtualservice
// or they don't have necessary labels
// or they don't have servicemesh enabled
// or they don't have any ports defined
return nil
}
@@ -240,7 +243,10 @@ func (v *DestinationRuleController) syncService(key string) error {
for _, deployment := range deployments {
// not a valid deployment we required
if !util.IsApplicationComponent(deployment.Labels) || !util.IsApplicationComponent(deployment.Spec.Selector.MatchLabels) {
if !util.IsApplicationComponent(deployment.Labels) ||
!util.IsApplicationComponent(deployment.Spec.Selector.MatchLabels) ||
deployment.Status.ReadyReplicas == 0 ||
!util.IsServicemeshEnabled(deployment.Annotations) {
continue
}
@@ -406,7 +412,9 @@ func (v *DestinationRuleController) getDeploymentServiceMemberShip(deployment *a
for i := range allServices {
service := allServices[i]
if service.Spec.Selector == nil || !util.IsApplicationComponent(service.Labels) {
if service.Spec.Selector == nil ||
!util.IsApplicationComponent(service.Labels) ||
!util.IsServicemeshEnabled(service.Annotations) {
// services with nil selectors match nothing, not everything.
continue
}

View File

@@ -8,17 +8,16 @@ import (
)
const (
AppLabel = "app"
VersionLabel = "version"
ApplicationNameLabel = "app.kubernetes.io/name"
ApplicationVersionLabel = "app.kubernetes.io/version"
ServiceMeshEnabledLabel = "servicemesh.kubesphere.io/enabled"
AppLabel = "app"
VersionLabel = "version"
ApplicationNameLabel = "app.kubernetes.io/name"
ApplicationVersionLabel = "app.kubernetes.io/version"
ServiceMeshEnabledAnnotation = "servicemesh.kubesphere.io/enabled"
)
// resource with these following labels considered as part of servicemesh
var ApplicationLabels = [...]string{
ApplicationNameLabel,
ServiceMeshEnabledLabel,
AppLabel,
}
@@ -40,6 +39,15 @@ func GetComponentName(meta *metav1.ObjectMeta) string {
return ""
}
func IsServicemeshEnabled(annotations map[string]string) bool {
if enabled, ok := annotations[ServiceMeshEnabledAnnotation]; ok {
if enabled == "true" {
return true
}
}
return false
}
func GetComponentVersion(meta *metav1.ObjectMeta) string {
if len(meta.Labels[VersionLabel]) > 0 {
return meta.Labels[VersionLabel]

View File

@@ -17,9 +17,8 @@ import (
"k8s.io/kubernetes/pkg/util/metrics"
"kubesphere.io/kubesphere/pkg/controller/virtualservice/util"
"reflect"
"strings"
logf "sigs.k8s.io/controller-runtime/pkg/runtime/log"
"strings"
istioclient "github.com/knative/pkg/client/clientset/versioned"
istioinformers "github.com/knative/pkg/client/informers/externalversions/istio/v1alpha3"
@@ -31,6 +30,7 @@ import (
"k8s.io/client-go/tools/record"
"k8s.io/client-go/util/workqueue"
servicemeshv1alpha2 "kubesphere.io/kubesphere/pkg/apis/servicemesh/v1alpha2"
servicemeshclient "kubesphere.io/kubesphere/pkg/client/clientset/versioned"
servicemeshinformers "kubesphere.io/kubesphere/pkg/client/informers/externalversions/servicemesh/v1alpha2"
servicemeshlisters "kubesphere.io/kubesphere/pkg/client/listers/servicemesh/v1alpha2"
@@ -52,6 +52,7 @@ type VirtualServiceController struct {
client clientset.Interface
virtualServiceClient istioclient.Interface
servicemeshClient servicemeshclient.Interface
eventBroadcaster record.EventBroadcaster
eventRecorder record.EventRecorder
@@ -78,7 +79,8 @@ func NewVirtualServiceController(serviceInformer coreinformers.ServiceInformer,
destinationRuleInformer istioinformers.DestinationRuleInformer,
strategyInformer servicemeshinformers.StrategyInformer,
client clientset.Interface,
virtualServiceClient istioclient.Interface) *VirtualServiceController {
virtualServiceClient istioclient.Interface,
servicemeshClient servicemeshclient.Interface) *VirtualServiceController {
broadcaster := record.NewBroadcaster()
broadcaster.StartLogging(func(format string, args ...interface{}) {
@@ -94,6 +96,7 @@ func NewVirtualServiceController(serviceInformer coreinformers.ServiceInformer,
v := &VirtualServiceController{
client: client,
virtualServiceClient: virtualServiceClient,
servicemeshClient: servicemeshClient,
queue: workqueue.NewNamedRateLimitingQueue(workqueue.DefaultControllerRateLimiter(), "virtualservice"),
workerLoopPeriod: time.Second,
}
@@ -234,7 +237,9 @@ func (v *VirtualServiceController) syncService(key string) error {
return err
}
if len(service.Labels) < len(util.ApplicationLabels) || !util.IsApplicationComponent(service.Labels) ||
if len(service.Labels) < len(util.ApplicationLabels) ||
!util.IsApplicationComponent(service.Labels) ||
!util.IsServicemeshEnabled(service.Annotations) ||
len(service.Spec.Ports) == 0 {
// services don't have enough labels to create a virtualservice
// or they don't have necessary labels
@@ -294,40 +299,69 @@ func (v *VirtualServiceController) syncService(key string) error {
}
vs := currentVirtualService.DeepCopy()
// create a whole new virtualservice
// TODO(jeff): use FQDN to replace service name
vs.Spec.Hosts = []string{name}
// check if service has TCP protocol ports
for _, port := range service.Spec.Ports {
var route v1alpha3.DestinationWeight
if port.Protocol == v1.ProtocolTCP {
route = v1alpha3.DestinationWeight{
Destination: v1alpha3.Destination{
Host: name,
Subset: subsets[0].Name,
Port: v1alpha3.PortSelector{
Number: uint32(port.Port),
},
},
Weight: 100,
}
// a http port, add to HTTPRoute
if len(port.Name) > 0 && (port.Name == "http" || strings.HasPrefix(port.Name, "http-")) {
vs.Spec.Http = []v1alpha3.HTTPRoute{{Route: []v1alpha3.DestinationWeight{route}}}
break
}
// everything else treated as TCPRoute
vs.Spec.Tcp = []v1alpha3.TCPRoute{{Route: []v1alpha3.DestinationWeight{route}}}
}
}
if len(strategies) > 0 {
// apply strategy spec to virtualservice
vs.Spec = v.generateVirtualServiceSpec(strategies[0], service).Spec
} else {
// create a whole new virtualservice
// TODO(jeff): use FQDN to replace service name
vs.Spec.Hosts = []string{name}
switch strategies[0].Spec.StrategyPolicy {
case servicemeshv1alpha2.PolicyPause:
break
case servicemeshv1alpha2.PolicyWaitForWorkloadReady:
set := v.getSubsets(strategies[0])
// check if service has TCP protocol ports
for _, port := range service.Spec.Ports {
var route v1alpha3.DestinationWeight
if port.Protocol == v1.ProtocolTCP {
route = v1alpha3.DestinationWeight{
Destination: v1alpha3.Destination{
Host: name,
Subset: subsets[0].Name,
Port: v1alpha3.PortSelector{
Number: uint32(port.Port),
},
},
Weight: 100,
}
// a http port, add to HTTPRoute
if len(port.Name) > 0 && (port.Name == "http" || strings.HasPrefix(port.Name, "http-")) {
vs.Spec.Http = []v1alpha3.HTTPRoute{{Route: []v1alpha3.DestinationWeight{route}}}
break
}
// everything else treated as TCPRoute
vs.Spec.Tcp = []v1alpha3.TCPRoute{{Route: []v1alpha3.DestinationWeight{route}}}
setNames := sets.String{}
for i := range subsets {
setNames.Insert(subsets[i].Name)
}
nonExist := false
for k := range set {
if !setNames.Has(k) {
nonExist = true
}
}
// strategy has subset that are not ready
if nonExist {
break
} else {
vs.Spec = v.generateVirtualServiceSpec(strategies[0], service).Spec
}
case servicemeshv1alpha2.PolicyImmediately:
vs.Spec = v.generateVirtualServiceSpec(strategies[0], service).Spec
default:
vs.Spec = v.generateVirtualServiceSpec(strategies[0], service).Spec
}
}
createVirtualService := len(currentVirtualService.ResourceVersion) == 0
@@ -359,7 +393,6 @@ func (v *VirtualServiceController) syncService(key string) error {
}
if err != nil {
if createVirtualService {
v.eventRecorder.Event(newVirtualService, v1.EventTypeWarning, "FailedToCreateVirtualService", fmt.Sprintf("Failed to create virtualservice for service %v/%v: %v", namespace, name, err))
} else {
@@ -463,6 +496,34 @@ func (v *VirtualServiceController) handleErr(err error, key interface{}) {
utilruntime.HandleError(err)
}
func (v *VirtualServiceController) getSubsets(strategy *servicemeshv1alpha2.Strategy) sets.String {
set := sets.String{}
for _, httpRoute := range strategy.Spec.Template.Spec.Http {
for _, dw := range httpRoute.Route {
set.Insert(dw.Destination.Subset)
}
if httpRoute.Mirror != nil {
set.Insert(httpRoute.Mirror.Subset)
}
}
for _, tcpRoute := range strategy.Spec.Template.Spec.Tcp {
for _, dw := range tcpRoute.Route {
set.Insert(dw.Destination.Subset)
}
}
for _, tlsRoute := range strategy.Spec.Template.Spec.Tls {
for _, dw := range tlsRoute.Route {
set.Insert(dw.Destination.Subset)
}
}
return set
}
func (v *VirtualServiceController) generateVirtualServiceSpec(strategy *servicemeshv1alpha2.Strategy, service *v1.Service) *v1alpha3.VirtualService {
// Define VirtualService to be created
@@ -472,7 +533,6 @@ func (v *VirtualServiceController) generateVirtualServiceSpec(strategy *servicem
// one version rules them all
if len(strategy.Spec.GovernorVersion) > 0 {
governorDestinationWeight := v1alpha3.DestinationWeight{
Destination: v1alpha3.Destination{
Host: service.Name,

55
pkg/models/git/git.go Normal file
View File

@@ -0,0 +1,55 @@
package git
import (
"fmt"
"gopkg.in/src-d/go-git.v4"
"gopkg.in/src-d/go-git.v4/config"
"gopkg.in/src-d/go-git.v4/plumbing/transport/http"
"gopkg.in/src-d/go-git.v4/storage/memory"
corev1 "k8s.io/api/core/v1"
"kubesphere.io/kubesphere/pkg/informers"
)
type AuthInfo struct {
RemoteUrl string `json:"remoteUrl"`
SecretRef *corev1.SecretReference `json:"secretRef,omitempty"`
}
func GitReadVerify(namespace string, authInfo AuthInfo) error {
username := ""
password := ""
if authInfo.SecretRef != nil {
secret, err := informers.SharedInformerFactory().Core().V1().Secrets().Lister().
Secrets(authInfo.SecretRef.Namespace).Get(authInfo.SecretRef.Name)
if err != nil {
return err
}
usernameBytes, ok := secret.Data[corev1.BasicAuthUsernameKey]
if !ok {
return fmt.Errorf("could not get username in secret %s", secret.Name)
}
passwordBytes, ok := secret.Data[corev1.BasicAuthPasswordKey]
if !ok {
return fmt.Errorf("could not get password in secret %s", secret.Name)
}
username = string(usernameBytes)
password = string(passwordBytes)
}
return gitReadVerifyWithBasicAuth(string(username), string(password), authInfo.RemoteUrl)
}
func gitReadVerifyWithBasicAuth(username string, password string, remote string) error {
r, _ := git.Init(memory.NewStorage(), nil)
// Add a new remote, with the default fetch refspec
origin, err := r.CreateRemote(&config.RemoteConfig{
Name: git.DefaultRemoteName,
URLs: []string{remote},
})
if err != nil {
return err
}
_, err = origin.List(&git.ListOptions{Auth: &http.BasicAuth{Username: string(username), Password: string(password)}})
return err
}

View File

@@ -0,0 +1,51 @@
package git
import (
"testing"
)
func TestGitReadVerifyWithBasicAuth(t *testing.T) {
shouldSuccess := []map[string]string{
{
"username": "",
"password": "",
"remote": "https://github.com/kubesphere/kubesphere",
},
}
shouldFailed := []map[string]string{
{
"username": "",
"password": "",
"remote": "https://github.com/kubesphere/kubesphere12222",
},
{
"username": "",
"password": "",
"remote": "git@github.com:kubesphere/kubesphere.git",
},
{
"username": "runzexia",
"password": "",
"remote": "git@github.com:kubesphere/kubesphere.git",
},
{
"username": "",
"password": "",
"remote": "git@fdsfs41342`@@@2414!!!!github.com:kubesphere/kubesphere.git",
},
}
for _, item := range shouldSuccess {
err := gitReadVerifyWithBasicAuth(item["username"], item["password"], item["remote"])
if err != nil {
t.Errorf("should could access repo [%s] with %s:%s, %v", item["username"], item["password"], item["remote"], err)
}
}
for _, item := range shouldFailed {
err := gitReadVerifyWithBasicAuth(item["username"], item["password"], item["remote"])
if err == nil {
t.Errorf("should could access repo [%s] with %s:%s ", item["username"], item["password"], item["remote"])
}
}
}

View File

@@ -19,17 +19,16 @@
package metrics
import (
"github.com/golang/glog"
"kubesphere.io/kubesphere/pkg/informers"
"net/url"
"regexp"
"runtime/debug"
"sort"
"strings"
"sync"
"time"
"github.com/golang/glog"
"runtime/debug"
"sort"
"github.com/json-iterator/go"
"k8s.io/api/core/v1"
@@ -119,6 +118,7 @@ func getAllWorkspaceNames(formatedMetric *FormatedMetric) map[string]int {
var wsMap = make(map[string]int)
for i := 0; i < len(formatedMetric.Data.Result); i++ {
// metricDesc needs clear naming
metricDesc := formatedMetric.Data.Result[i][ResultItemMetric]
metricDescMap, ensure := metricDesc.(map[string]interface{})
if ensure {
@@ -256,7 +256,8 @@ func AssembleAllWorkloadMetricRequestInfo(monitoringRequest *client.MonitoringRe
paramValues := monitoringRequest.Params
rule := MakeWorkloadPromQL(metricName, monitoringRequest.NsName, monitoringRequest.ResourcesFilter)
rule := MakeWorkloadPromQL(metricName, monitoringRequest.NsName, monitoringRequest.ResourcesFilter, monitoringRequest.WorkloadKind)
params := makeRequestParamString(rule, paramValues)
return queryType, params
}
@@ -293,7 +294,7 @@ func AddNodeAddressMetric(nodeMetric *FormatedMetric, nodeAddress *map[string][]
metricDesc := nodeMetric.Data.Result[i][ResultItemMetric]
metricDescMap, ensure := metricDesc.(map[string]interface{})
if ensure {
if nodeId, exist := metricDescMap["node"]; exist {
if nodeId, exist := metricDescMap["resource_name"]; exist {
addr, exist := (*nodeAddress)[nodeId.(string)]
if exist {
metricDescMap["address"] = addr
@@ -330,6 +331,17 @@ func AssembleNamespaceMetricRequestInfo(monitoringRequest *client.MonitoringRequ
return queryType, params
}
func AssembleNamespaceMetricRequestInfoByNamesapce(monitoringRequest *client.MonitoringRequestParams, namespace string, metricName string) (string, string) {
queryType := monitoringRequest.QueryType
paramValues := monitoringRequest.Params
rule := MakeNamespacePromQL(namespace, monitoringRequest.ResourcesFilter, metricName)
params := makeRequestParamString(rule, paramValues)
return queryType, params
}
func AssembleSpecificWorkspaceMetricRequestInfo(monitoringRequest *client.MonitoringRequestParams, namespaceList []string, metricName string) (string, string) {
nsFilter := "^(" + strings.Join(namespaceList, "|") + ")$"
@@ -414,6 +426,7 @@ func MonitorAllWorkspaces(monitoringRequest *client.MonitoringRequestParams) *Fo
wsMap := getAllWorkspaces()
for ws := range wsMap {
// Only execute Prometheus queries for specific metrics on specific workspaces
bol, err := regexp.MatchString(monitoringRequest.ResourcesFilter, ws)
if err == nil && bol {
// a workspace
@@ -461,8 +474,9 @@ func collectWorkspaceMetric(monitoringRequest *client.MonitoringRequestParams, w
var ch = make(chan *FormatedMetric, ChannelMaxCapacity)
namespaceArray, err := workspaces.WorkspaceNamespaces(ws)
if err != nil {
glog.Errorln(err.Error())
glog.Errorln(err)
}
// add by namespace
for _, metricName := range filterMetricsName {
wg.Add(1)
@@ -470,7 +484,7 @@ func collectWorkspaceMetric(monitoringRequest *client.MonitoringRequestParams, w
queryType, params := AssembleSpecificWorkspaceMetricRequestInfo(monitoringRequest, namespaceArray, metricName)
metricsStr := client.SendMonitoringRequest(queryType, params)
ch <- ReformatJson(metricsStr, metricName, map[string]string{"namespace": ""})
ch <- ReformatJson(metricsStr, metricName, map[string]string{"resource_name": ws}) // It's adding "resource_name" field
wg.Done()
}(metricName)
@@ -482,7 +496,7 @@ func collectWorkspaceMetric(monitoringRequest *client.MonitoringRequestParams, w
var metricsArray []FormatedMetric
for oneMetric := range ch {
if oneMetric != nil {
// add "workspace" filed to oneMetric `metric` field
// add "workspace" to oneMetric "metric" field
for i := 0; i < len(oneMetric.Data.Result); i++ {
tmap, sure := oneMetric.Data.Result[i][ResultItemMetric].(map[string]interface{})
if sure {
@@ -510,8 +524,8 @@ func MonitorAllMetrics(monitoringRequest *client.MonitoringRequestParams, resour
case MetricLevelCluster:
{
for _, metricName := range ClusterMetricsNames {
bol, err := regexp.MatchString(metricsFilter, metricName)
if err == nil && bol {
matched, err := regexp.MatchString(metricsFilter, metricName)
if err == nil && matched {
wg.Add(1)
go func(metricName string) {
queryType, params := AssembleClusterMetricRequestInfo(monitoringRequest, metricName)
@@ -525,8 +539,8 @@ func MonitorAllMetrics(monitoringRequest *client.MonitoringRequestParams, resour
case MetricLevelNode:
{
for _, metricName := range NodeMetricsNames {
bol, err := regexp.MatchString(metricsFilter, metricName)
if err == nil && bol {
matched, err := regexp.MatchString(metricsFilter, metricName)
if err == nil && matched {
wg.Add(1)
go func(metricName string) {
queryType, params := AssembleNodeMetricRequestInfo(monitoringRequest, metricName)
@@ -553,36 +567,70 @@ func MonitorAllMetrics(monitoringRequest *client.MonitoringRequestParams, resour
continue
}
bol, err := regexp.MatchString(metricsFilter, metricName)
ns := "^(" + strings.Join(namespaceArray, "|") + ")$"
monitoringRequest.ResourcesFilter = ns
if err == nil && bol {
wg.Add(1)
go func(metricName string) {
queryType, params := AssembleNamespaceMetricRequestInfo(monitoringRequest, metricName)
metricsStr := client.SendMonitoringRequest(queryType, params)
ch <- ReformatJson(metricsStr, metricName, map[string]string{"workspace": "workspace"})
wg.Done()
}(metricName)
matched, err := regexp.MatchString(metricsFilter, metricName)
if err != nil || !matched {
continue
}
wg.Add(1)
go func(metricName string) {
var chForOneMetric = make(chan *FormatedMetric, ChannelMaxCapacity)
var wgForOneMetric sync.WaitGroup
for _, ns := range namespaceArray {
wgForOneMetric.Add(1)
go func(metricName string, namespace string) {
queryType, params := AssembleNamespaceMetricRequestInfoByNamesapce(monitoringRequest, namespace, metricName)
metricsStr := client.SendMonitoringRequest(queryType, params)
chForOneMetric <- ReformatJson(metricsStr, metricName, map[string]string{"resource_name": namespace})
wgForOneMetric.Done()
}(metricName, ns)
}
wgForOneMetric.Wait()
close(chForOneMetric)
// ranking is for vector type result only
aggregatedResult := FormatedMetric{MetricName: metricName, Status: "success", Data: FormatedMetricData{Result: []map[string]interface{}{}, ResultType: ResultTypeVector}}
for oneMetric := range chForOneMetric {
if oneMetric != nil {
// wrapper layer 1: append .data.result[0]
if len(oneMetric.Data.Result) > 0 {
aggregatedResult.Data.Result = append(aggregatedResult.Data.Result, oneMetric.Data.Result[0])
}
}
}
ch <- &aggregatedResult
wg.Done()
}(metricName)
}
} else {
workspace := monitoringRequest.WsName
for _, metricName := range WorkspaceMetricsNames {
if metricName == MetricNameWorkspaceAllProjectCount {
continue
}
bol, err := regexp.MatchString(metricsFilter, metricName)
if err == nil && bol {
matched, err := regexp.MatchString(metricsFilter, metricName)
if err == nil && matched {
wg.Add(1)
go func(metricName string) {
go func(metricName string, workspace string) {
queryType, params := AssembleSpecificWorkspaceMetricRequestInfo(monitoringRequest, namespaceArray, metricName)
metricsStr := client.SendMonitoringRequest(queryType, params)
ch <- ReformatJson(metricsStr, metricName, map[string]string{"workspace": "workspace"})
ch <- ReformatJson(metricsStr, metricName, map[string]string{"resource_name": workspace})
wg.Done()
}(metricName)
}(metricName, workspace)
}
}
}
@@ -590,8 +638,8 @@ func MonitorAllMetrics(monitoringRequest *client.MonitoringRequestParams, resour
// sum all workspaces
for _, metricName := range WorkspaceMetricsNames {
bol, err := regexp.MatchString(metricsFilter, metricName)
if err == nil && bol {
matched, err := regexp.MatchString(metricsFilter, metricName)
if err == nil && matched {
wg.Add(1)
@@ -599,6 +647,7 @@ func MonitorAllMetrics(monitoringRequest *client.MonitoringRequestParams, resour
queryType, params := AssembleAllWorkspaceMetricRequestInfo(monitoringRequest, nil, metricName)
metricsStr := client.SendMonitoringRequest(queryType, params)
ch <- ReformatJson(metricsStr, metricName, map[string]string{"workspace": "workspaces"})
wg.Done()
}(metricName)
}
@@ -608,13 +657,17 @@ func MonitorAllMetrics(monitoringRequest *client.MonitoringRequestParams, resour
case MetricLevelNamespace:
{
for _, metricName := range NamespaceMetricsNames {
bol, err := regexp.MatchString(metricsFilter, metricName)
if err == nil && bol {
matched, err := regexp.MatchString(metricsFilter, metricName)
if err == nil && matched {
wg.Add(1)
go func(metricName string) {
queryType, params := AssembleNamespaceMetricRequestInfo(monitoringRequest, metricName)
metricsStr := client.SendMonitoringRequest(queryType, params)
ch <- ReformatJson(metricsStr, metricName, map[string]string{"namespace": ""})
rawResult := ReformatJson(metricsStr, metricName, map[string]string{"namespace": ""})
ch <- rawResult
wg.Done()
}(metricName)
}
@@ -624,13 +677,15 @@ func MonitorAllMetrics(monitoringRequest *client.MonitoringRequestParams, resour
{
if monitoringRequest.WorkloadName == "" {
for _, metricName := range WorkloadMetricsNames {
bol, err := regexp.MatchString(metricsFilter, metricName)
if err == nil && bol {
matched, err := regexp.MatchString(metricsFilter, metricName)
if err == nil && matched {
wg.Add(1)
go func(metricName string) {
queryType, params := AssembleAllWorkloadMetricRequestInfo(monitoringRequest, metricName)
metricsStr := client.SendMonitoringRequest(queryType, params)
ch <- ReformatJson(metricsStr, metricName, map[string]string{"workload": ""})
reformattedResult := ReformatJson(metricsStr, metricName, map[string]string{"workload": ""})
// no need to append a null result
ch <- reformattedResult
wg.Done()
}(metricName)
}
@@ -658,8 +713,8 @@ func MonitorAllMetrics(monitoringRequest *client.MonitoringRequestParams, resour
case MetricLevelPod:
{
for _, metricName := range PodMetricsNames {
bol, err := regexp.MatchString(metricsFilter, metricName)
if err == nil && bol {
matched, err := regexp.MatchString(metricsFilter, metricName)
if err == nil && matched {
wg.Add(1)
go func(metricName string) {
queryType, params, nullRule := AssemblePodMetricRequestInfo(monitoringRequest, metricName)
@@ -677,8 +732,8 @@ func MonitorAllMetrics(monitoringRequest *client.MonitoringRequestParams, resour
case MetricLevelContainer:
{
for _, metricName := range ContainerMetricsNames {
bol, err := regexp.MatchString(metricsFilter, metricName)
if err == nil && bol {
matched, err := regexp.MatchString(metricsFilter, metricName)
if err == nil && matched {
wg.Add(1)
go func(metricName string) {
queryType, params := AssembleContainerMetricRequestInfo(monitoringRequest, metricName)
@@ -702,6 +757,7 @@ func MonitorAllMetrics(monitoringRequest *client.MonitoringRequestParams, resour
}
}
// wrapper layer 2:
return &FormatedLevelMetric{
MetricsLevel: resourceType,
Results: metricsArray,

View File

@@ -17,14 +17,54 @@ import (
"strings"
)
func MakeWorkloadPromQL(metricName, nsName, wlFilter string) string {
if wlFilter == "" {
wlFilter = ".*"
// resources_filter = xxxx|xxxx
func MakeWorkloadPromQL(metricName, nsName, resources_filter, wkKind string) string {
switch wkKind {
case "deployment":
wkKind = Deployment
case "daemonset":
wkKind = DaemonSet
case "statefulset":
wkKind = StatefulSet
default:
wkKind = "(.*)"
}
if resources_filter == "" {
resources_filter = ".*"
} else {
var prefix string
// The "workload_{deployment,statefulset,daemonset}_xxx" metric uses "deployment","statefulset" or "daemonset" label selectors
// which match exactly a workload name
// eg. kube_daemonset_status_number_unavailable{daemonset=~"^xxx$"}
if strings.Contains(metricName, "deployment") || strings.Contains(metricName, "daemonset") || strings.Contains(metricName, "statefulset") {
// to pass "resources_filter" to PromQL, we reformat it
prefix = ""
} else {
// While workload_{cpu,memory,net}_xxx metrics uses "workload"
// eg. namespace:workload_cpu_usage:sum{workload="Deployment:xxx"}
prefix = wkKind + ":"
}
filters := strings.Split(resources_filter, "|")
// reshape it to match PromQL re2 syntax
resources_filter = ""
for i, filter := range filters {
resources_filter += "^" + prefix + filter + "$" // eg. ^Deployment:xxx$
if i != len(filters)-1 {
resources_filter += resources_filter + "|"
}
}
}
var promql = RulePromQLTmplMap[metricName]
promql = strings.Replace(promql, "$2", nsName, -1)
promql = strings.Replace(promql, "$3", wlFilter, -1)
promql = strings.Replace(promql, "$3", resources_filter, -1)
return promql
}

View File

@@ -134,12 +134,16 @@ var ClusterMetricsNames = []string{
"cluster_replicaset_count",
"cluster_service_count",
"cluster_secret_count",
"cluster_ingresses_extensions_count",
"cluster_namespace_count",
"cluster_load1",
"cluster_load5",
"cluster_load15",
// New in ks 2.0
"cluster_pod_abnormal_ratio",
"cluster_node_offline_ratio",
}
var NodeMetricsNames = []string{
"node_cpu_utilisation",
@@ -176,6 +180,9 @@ var NodeMetricsNames = []string{
"node_load1",
"node_load5",
"node_load15",
// New in ks 2.0
"node_pod_abnormal_ratio",
}
var WorkspaceMetricsNames = []string{
"workspace_cpu_usage",
@@ -202,6 +209,9 @@ var WorkspaceMetricsNames = []string{
"workspace_secret_count",
"workspace_all_project_count",
// New in ks 2.0
"workspace_pod_abnormal_ratio",
}
var NamespaceMetricsNames = []string{
"namespace_cpu_usage",
@@ -267,6 +277,10 @@ var NamespaceMetricsNames = []string{
"namespace_secret_count",
"namespace_ingresses_extensions_count",
// New in ks 2.0
"namespace_pod_abnormal_ratio",
"namespace_resourcequota_used_ratio",
}
var PodMetricsNames = []string{
@@ -290,6 +304,11 @@ var WorkloadMetricsNames = []string{
"workload_statefulset_replica_available",
"workload_daemonset_replica",
"workload_daemonset_replica_available",
// New in ks 2.0
"workload_deployment_unavailable_replicas_ratio",
"workload_daemonset_unavailable_replicas_ratio",
"workload_statefulset_unavailable_replicas_ratio",
}
var ContainerMetricsNames = []string{
@@ -319,30 +338,28 @@ var RulePromQLTmplMap = MetricMap{
"cluster_disk_write_throughput": "sum(node:data_volume_throughput_bytes_written:sum)",
"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_utilisation": `cluster:disk_utilization:ratio`,
"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: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_disk_inode_utilisation": `cluster:disk_inode_utilization:ratio`,
"cluster_namespace_count": `count(kube_namespace_annotations)`,
// cluster_pod_count = cluster_pod_running_count + cluster_pod_succeeded_count + cluster_pod_abnormal_count
"cluster_pod_count": `sum((kube_pod_status_scheduled{condition="true"} > 0) * on (namespace, pod) group_left(node) (sum by (node, namespace, pod) (kube_pod_info)) unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0))`,
"cluster_pod_count": `cluster:pod:sum`,
"cluster_pod_quota": `sum(kube_node_status_capacity_pods unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0))`,
"cluster_pod_utilisation": `sum(kube_pod_info unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0)) / sum(kube_node_status_capacity_pods unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0))`,
"cluster_pod_utilisation": `cluster:pod_utilization:ratio`,
"cluster_pod_running_count": `count(kube_pod_info unless on (pod) (kube_pod_status_phase{phase=~"Failed|Pending|Unknown|Succeeded"} > 0) unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0))`,
"cluster_pod_succeeded_count": `count(kube_pod_info unless on (pod) (kube_pod_status_phase{phase=~"Failed|Pending|Unknown|Running"} > 0) unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0))`,
"cluster_pod_abnormal_count": `count(kube_pod_info unless on (pod) (kube_pod_status_phase{phase=~"Succeeded|Running"} > 0) unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0))`,
"cluster_pod_abnormal_count": `cluster:pod_abnormal:sum`,
"cluster_node_online": `sum(kube_node_status_condition{condition="Ready",status="true"})`,
"cluster_node_offline": `sum(kube_node_status_condition{condition="Ready",status=~"unknown|false"})`,
"cluster_node_offline": `cluster:node_offline:sum`,
"cluster_node_total": `sum(kube_node_status_condition{condition="Ready"})`,
"cluster_ingresses_extensions_count": `sum(kube_ingress_labels)`,
"cluster_configmap_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="count/configmaps"}) by (resource, type)`,
"cluster_jobs_batch_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="count/jobs.batch"}) by (resource, type)`,
"cluster_roles_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="count/roles.rbac.authorization.k8s.io"}) by (resource, type)`,
@@ -363,23 +380,28 @@ var RulePromQLTmplMap = MetricMap{
"cluster_cpu_request_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="requests.cpu"}) by (resource, type)`,
"cluster_service_loadbalancer_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", resource="services.loadbalancers"}) by (resource, type)`,
"cluster_cronjob_count": `sum(kube_cronjob_labels)`,
"cluster_pvc_count": `sum(kube_persistentvolumeclaim_info)`,
"cluster_daemonset_count": `sum(kube_daemonset_labels)`,
"cluster_deployment_count": `sum(kube_deployment_labels)`,
"cluster_endpoint_count": `sum(kube_endpoint_labels)`,
"cluster_hpa_count": `sum(kube_hpa_labels)`,
"cluster_job_count": `sum(kube_job_labels)`,
"cluster_statefulset_count": `sum(kube_statefulset_labels)`,
"cluster_replicaset_count": `count(kube_replicaset_created)`,
"cluster_service_count": `sum(kube_service_info)`,
"cluster_secret_count": `sum(kube_secret_info)`,
"cluster_pv_count": `sum(kube_persistentvolume_labels)`,
"cluster_cronjob_count": `sum(kube_cronjob_labels)`,
"cluster_pvc_count": `sum(kube_persistentvolumeclaim_info)`,
"cluster_daemonset_count": `sum(kube_daemonset_labels)`,
"cluster_deployment_count": `sum(kube_deployment_labels)`,
"cluster_endpoint_count": `sum(kube_endpoint_labels)`,
"cluster_hpa_count": `sum(kube_hpa_labels)`,
"cluster_job_count": `sum(kube_job_labels)`,
"cluster_statefulset_count": `sum(kube_statefulset_labels)`,
"cluster_replicaset_count": `count(kube_replicaset_created)`,
"cluster_service_count": `sum(kube_service_info)`,
"cluster_secret_count": `sum(kube_secret_info)`,
"cluster_pv_count": `sum(kube_persistentvolume_labels)`,
"cluster_ingresses_extensions_count": `sum(kube_ingress_labels)`,
"cluster_load1": `sum(node_load1{job="node-exporter"}) / sum(node:node_num_cpu:sum)`,
"cluster_load5": `sum(node_load5{job="node-exporter"}) / sum(node:node_num_cpu:sum)`,
"cluster_load15": `sum(node_load15{job="node-exporter"}) / sum(node:node_num_cpu:sum)`,
// cluster: New added in ks 2.0
"cluster_pod_abnormal_ratio": `cluster:pod_abnormal:ratio`,
"cluster_node_offline_ratio": `cluster:node_offline:ratio`,
//node
"node_cpu_utilisation": "node:node_cpu_utilisation:avg1m",
"node_cpu_total": "node:node_num_cpu:sum",
@@ -397,27 +419,30 @@ var RulePromQLTmplMap = MetricMap{
"node_disk_write_throughput": "node:data_volume_throughput_bytes_written:sum",
"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_available": `node:disk_space_available:$1`,
"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_size_utilisation": `node:disk_space_utilization:ratio$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_disk_inode_utilisation": `node:disk_inode_utilization:ratio$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_count": `node:pod_count:sum$1`,
"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)`,
"node_pod_utilisation": `(sum(kube_pod_info$1) by (node) / sum(kube_node_status_capacity_pods$1) by (node)) unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0)`,
"node_pod_running_count": `count(kube_pod_info$1 unless on (pod) (kube_pod_status_phase{phase=~"Failed|Pending|Unknown|Succeeded"} > 0)) by (node) unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0)`,
"node_pod_succeeded_count": `count(kube_pod_info$1 unless on (pod) (kube_pod_status_phase{phase=~"Failed|Pending|Unknown|Running"} > 0)) by (node) unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0)`,
"node_pod_abnormal_count": `count(kube_pod_info$1 unless on (pod) (kube_pod_status_phase{phase=~"Succeeded|Running"} > 0)) by (node) unless on (node) (kube_node_status_condition{condition="Ready",status=~"unknown|false"} > 0)`,
"node_pod_utilisation": `node:pod_utilization:ratio$1`,
"node_pod_running_count": `node:pod_running:count$1`,
"node_pod_succeeded_count": `node:pod_succeeded:count$1`,
"node_pod_abnormal_count": `node:pod_abnormal:count$1`,
// without log node: unless on(node) kube_node_labels{label_role="log"}
"node_cpu_usage": `node:node_cpu_utilisation:avg1m$1 * node:node_num_cpu:sum$1`,
"node_load1": `sum by (node) (node_load1{job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) / node:node_num_cpu:sum`,
"node_load5": `sum by (node) (node_load5{job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) / node:node_num_cpu:sum`,
"node_load15": `sum by (node) (node_load15{job="node-exporter"} * on (namespace, pod) group_left(node) node_namespace_pod:kube_pod_info:$1) / node:node_num_cpu:sum`,
"node_load1": `node:load1:ratio$1`,
"node_load5": `node:load5:ratio$1`,
"node_load15": `node:load15:ratio$1`,
// New in ks 2.0
"node_pod_abnormal_ratio": `node:pod_abnormal:ratio$1`,
//namespace
"namespace_cpu_usage": `namespace:container_cpu_usage_seconds_total:sum_rate{namespace!="", namespace=~"$1"} * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
@@ -430,45 +455,45 @@ var RulePromQLTmplMap = MetricMap{
"namespace_pod_succeeded_count": `sum(kube_pod_status_phase{phase="Succeeded", namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_pod_abnormal_count": `sum(kube_pod_status_phase{phase=~"Failed|Pending|Unknown", namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_configmap_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/configmaps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_jobs_batch_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/jobs.batch"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_roles_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/roles.rbac.authorization.k8s.io"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_memory_limit_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="limits.memory"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_pvc_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="persistentvolumeclaims"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_memory_request_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="requests.memory"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_pvc_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/persistentvolumeclaims"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_cronjobs_batch_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/cronjobs.batch"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_ingresses_extensions_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/ingresses.extensions"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_cpu_limit_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="limits.cpu"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_storage_request_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="requests.storage"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_deployment_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/deployments.apps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_pod_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/pods"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_statefulset_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/statefulsets.apps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_daemonset_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/daemonsets.apps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_secret_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/secrets"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_service_count_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/services"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_cpu_request_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="requests.cpu"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_service_loadbalancer_used": `sum(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="services.loadbalancers"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_configmap_count_used": `max(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/configmaps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_jobs_batch_count_used": `max(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/jobs.batch"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_roles_count_used": `max(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/roles.rbac.authorization.k8s.io"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_memory_limit_used": `max(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="limits.memory"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_pvc_used": `max(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="persistentvolumeclaims"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_memory_request_used": `max(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="requests.memory"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_pvc_count_used": `max(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/persistentvolumeclaims"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_cronjobs_batch_count_used": `max(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/cronjobs.batch"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_ingresses_extensions_count_used": `max(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/ingresses.extensions"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_cpu_limit_used": `max(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="limits.cpu"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_storage_request_used": `max(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="requests.storage"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_deployment_count_used": `max(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/deployments.apps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_pod_count_used": `max(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/pods"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_statefulset_count_used": `max(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/statefulsets.apps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_daemonset_count_used": `max(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/daemonsets.apps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_secret_count_used": `max(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/secrets"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_service_count_used": `max(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="count/services"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_cpu_request_used": `max(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="requests.cpu"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_service_loadbalancer_used": `max(kube_resourcequota{resourcequota!="quota", type="used", namespace!="", namespace=~"$1", resource="services.loadbalancers"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_configmap_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/configmaps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_jobs_batch_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/jobs.batch"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_roles_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/roles.rbac.authorization.k8s.io"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_memory_limit_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="limits.memory"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_pvc_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="persistentvolumeclaims"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_memory_request_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="requests.memory"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_pvc_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/persistentvolumeclaims"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_cronjobs_batch_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/cronjobs.batch"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_ingresses_extensions_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/ingresses.extensions"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_cpu_limit_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="limits.cpu"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_storage_request_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="requests.storage"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_deployment_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/deployments.apps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_pod_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/pods"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_statefulset_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/statefulsets.apps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_daemonset_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/daemonsets.apps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_secret_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/secrets"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_service_count_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/services"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_cpu_request_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="requests.cpu"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_service_loadbalancer_hard": `sum(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="services.loadbalancers"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_configmap_count_hard": `min(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/configmaps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_jobs_batch_count_hard": `min(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/jobs.batch"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_roles_count_hard": `min(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/roles.rbac.authorization.k8s.io"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_memory_limit_hard": `min(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="limits.memory"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_pvc_hard": `min(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="persistentvolumeclaims"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_memory_request_hard": `min(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="requests.memory"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_pvc_count_hard": `min(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/persistentvolumeclaims"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_cronjobs_batch_count_hard": `min(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/cronjobs.batch"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_ingresses_extensions_count_hard": `min(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/ingresses.extensions"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_cpu_limit_hard": `min(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="limits.cpu"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_storage_request_hard": `min(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="requests.storage"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_deployment_count_hard": `min(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/deployments.apps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_pod_count_hard": `min(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/pods"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_statefulset_count_hard": `min(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/statefulsets.apps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_daemonset_count_hard": `min(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/daemonsets.apps"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_secret_count_hard": `min(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/secrets"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_service_count_hard": `min(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="count/services"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_cpu_request_hard": `min(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="requests.cpu"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_service_loadbalancer_hard": `min(kube_resourcequota{resourcequota!="quota", type="hard", namespace!="", namespace=~"$1", resource="services.loadbalancers"}) by (namespace, resource, type) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_cronjob_count": `sum(kube_cronjob_labels{namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
"namespace_pvc_count": `sum(kube_persistentvolumeclaim_info{namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
@@ -484,6 +509,10 @@ var RulePromQLTmplMap = MetricMap{
"namespace_ingresses_extensions_count": `sum(kube_ingress_labels{namespace!="", namespace=~"$1"}) by (namespace) * on (namespace) group_left(label_kubesphere_io_workspace)(kube_namespace_labels)`,
// New in ks 2.0
"namespace_pod_abnormal_ratio": `namespace:pod_abnormal:ratio{namespace!="", namespace=~"$1"}`,
"namespace_resourcequota_used_ratio": `namespace:resourcequota_used:ratio{namespace!="", namespace=~"$1"}`,
// pod
"pod_cpu_usage": `sum(irate(container_cpu_usage_seconds_total{job="kubelet", namespace="$1", pod_name!="", pod_name="$2", image!=""}[5m])) by (namespace, pod_name)`,
"pod_memory_usage": `sum(container_memory_usage_bytes{job="kubelet", namespace="$1", pod_name!="", pod_name="$2", image!=""}) by (namespace, pod_name)`,
@@ -504,11 +533,12 @@ var RulePromQLTmplMap = MetricMap{
"pod_net_bytes_received_node": `sum by (node, pod_name) (irate(container_network_receive_bytes_total{pod_name!="", pod_name=~"$2", ` + ExcludedVirtualNetworkInterfaces + `, job="kubelet"}[5m]) * on (pod_name) group_left(node) label_join(node_namespace_pod:kube_pod_info:{node="$3"}, "pod_name", "", "pod", "_name"))`,
// workload
"workload_pod_cpu_usage": `label_join(sum(label_replace(label_replace(label_replace(label_join(label_join(label_replace(sum(irate(container_cpu_usage_seconds_total{job="kubelet", namespace="$2", pod_name!="", pod_name=~"$3", image!=""}[5m])) by (namespace, pod_name) * on (pod_name) group_left(owner_kind) label_join(label_replace(kube_pod_owner{namespace="$2", pod=~".*"}, "owner_kind", "POD", "owner_kind", "<none>"), "pod_name", "", "pod", "_name") , "postfix", "-POD", "owner_kind", "POD"), "pod_name", "", "pod_name", "postfix"), "dist", "-", "owner_kind", "pod_name"), "pod_name", "$1", "dist", "ReplicaSet-(.+)-(.+)"), "workload", "$1", "pod_name", "(.+)-(.+)"), "owner_kind", "Deployment", "owner_kind", "ReplicaSet.*")) by (namespace, workload, owner_kind), "workload", ":", "owner_kind", "workload")`,
"workload_pod_memory_usage": `label_join(sum(label_replace(label_replace(label_replace(label_join(label_join(label_replace(sum(container_memory_usage_bytes{job="kubelet", namespace="$2", pod_name!="", pod_name=~"$3", image!=""}) by (namespace, pod_name) * on (pod_name) group_left(owner_kind) label_join(label_replace(kube_pod_owner{namespace="$2", pod=~".*"}, "owner_kind", "POD", "owner_kind", "<none>"), "pod_name", "", "pod", "_name") , "postfix", "-POD", "owner_kind", "POD"), "pod_name", "", "pod_name", "postfix"), "dist", "-", "owner_kind", "pod_name"), "pod_name", "$1", "dist", "ReplicaSet-(.+)-(.+)"), "workload", "$1", "pod_name", "(.+)-(.+)"), "owner_kind", "Deployment", "owner_kind", "ReplicaSet.*")) by (namespace, workload, owner_kind), "workload", ":", "owner_kind", "workload")`,
"workload_pod_memory_usage_wo_cache": `label_join(sum(label_replace(label_replace(label_replace(label_join(label_join(label_replace(sum(container_memory_usage_bytes{job="kubelet", namespace="$2", pod_name!="", pod_name=~"$3", image!=""} - container_memory_cache{job="kubelet", namespace="$2", pod_name!="", pod_name=~"$3", image!=""}) by (namespace, pod_name) * on (pod_name) group_left(owner_kind) label_join(label_replace(kube_pod_owner{namespace="$2", pod=~".*"}, "owner_kind", "POD", "owner_kind", "<none>"), "pod_name", "", "pod", "_name") , "postfix", "-POD", "owner_kind", "POD"), "pod_name", "", "pod_name", "postfix"), "dist", "-", "owner_kind", "pod_name"), "pod_name", "$1", "dist", "ReplicaSet-(.+)-(.+)"), "workload", "$1", "pod_name", "(.+)-(.+)"), "owner_kind", "Deployment", "owner_kind", "ReplicaSet.*")) by (namespace, workload, owner_kind), "workload", ":", "owner_kind", "workload")`,
"workload_pod_net_bytes_transmitted": `label_join(sum(label_replace(label_replace(label_replace(label_join(label_join(label_replace(sum(irate(container_network_transmit_bytes_total{namespace="$2", pod_name!="", pod_name=~"$3", ` + ExcludedVirtualNetworkInterfaces + `, job="kubelet"}[5m])) by (namespace, pod_name) * on (pod_name) group_left(owner_kind) label_join(label_replace(kube_pod_owner{namespace="$2", pod=~".*"}, "owner_kind", "POD", "owner_kind", "<none>"), "pod_name", "", "pod", "_name") , "postfix", "-POD", "owner_kind", "POD"), "pod_name", "", "pod_name", "postfix"), "dist", "-", "owner_kind", "pod_name"), "pod_name", "$1", "dist", "ReplicaSet-(.+)-(.+)"), "workload", "$1", "pod_name", "(.+)-(.+)"), "owner_kind", "Deployment", "owner_kind", "ReplicaSet.*")) by (namespace, workload, owner_kind), "workload", ":", "owner_kind", "workload")`,
"workload_pod_net_bytes_received": `label_join(sum(label_replace(label_replace(label_replace(label_join(label_join(label_replace(sum(irate(container_network_receive_bytes_total{namespace="$2", pod_name!="", pod_name=~"$3", ` + ExcludedVirtualNetworkInterfaces + `, job="kubelet"}[5m])) by (namespace, pod_name) * on (pod_name) group_left(owner_kind) label_join(label_replace(kube_pod_owner{namespace="$2", pod=~".*"}, "owner_kind", "POD", "owner_kind", "<none>"), "pod_name", "", "pod", "_name") , "postfix", "-POD", "owner_kind", "POD"), "pod_name", "", "pod_name", "postfix"), "dist", "-", "owner_kind", "pod_name"), "pod_name", "$1", "dist", "ReplicaSet-(.+)-(.+)"), "workload", "$1", "pod_name", "(.+)-(.+)"), "owner_kind", "Deployment", "owner_kind", "ReplicaSet.*")) by (namespace, workload, owner_kind), "workload", ":", "owner_kind", "workload")`,
// Join the "container_cpu_usage_seconds_total" metric with "kube_pod_owner" to calculate workload-level resource usage
"workload_pod_cpu_usage": `namespace:workload_cpu_usage:sum{namespace="$2", workload=~"$3"}`,
"workload_pod_memory_usage": `namespace:workload_memory_usage:sum{namespace="$2", workload=~"$3"}`,
"workload_pod_memory_usage_wo_cache": `namespace:workload_memory_usage_wo_cache:sum{namespace="$2", workload=~"$3"}`,
"workload_pod_net_bytes_transmitted": `namespace:workload_net_bytes_transmitted:sum_irate{namespace="$2", workload=~"$3"}`,
"workload_pod_net_bytes_received": `namespace:workload_net_bytes_received:sum_irate{namespace="$2", workload=~"$3"}`,
"workload_deployment_replica": `label_join(sum (label_join(label_replace(kube_deployment_spec_replicas{namespace="$2", deployment=~"$3"}, "owner_kind", "Deployment", "", ""), "workload", "", "deployment")) by (namespace, owner_kind, workload), "workload", ":", "owner_kind", "workload")`,
"workload_deployment_replica_available": `label_join(sum (label_join(label_replace(kube_deployment_status_replicas_available{namespace="$2", deployment=~"$3"}, "owner_kind", "Deployment", "", ""), "workload", "", "deployment")) by (namespace, owner_kind, workload), "workload", ":", "owner_kind", "workload")`,
@@ -517,6 +547,11 @@ var RulePromQLTmplMap = MetricMap{
"workload_daemonset_replica": `label_join(sum (label_join(label_replace(kube_daemonset_status_desired_number_scheduled{namespace="$2", daemonset=~"$3"}, "owner_kind", "DaemonSet", "", ""), "workload", "", "daemonset")) by (namespace, owner_kind, workload), "workload", ":", "owner_kind", "workload")`,
"workload_daemonset_replica_available": `label_join(sum (label_join(label_replace(kube_daemonset_status_number_available{namespace="$2", daemonset=~"$3"}, "owner_kind", "DaemonSet", "", ""), "workload", "", "daemonset")) by (namespace, owner_kind, workload), "workload", ":", "owner_kind", "workload")`,
// New in ks 2.0
"workload_deployment_unavailable_replicas_ratio": `namespace:deployment_unavailable_replicas:ratio{namespace="$2", deployment=~"$3"}`,
"workload_daemonset_unavailable_replicas_ratio": `namespace:daemonset_unavailable_replicas:ratio{namespace="$2", daemonset=~"$3"}`,
"workload_statefulset_unavailable_replicas_ratio": `namespace:statefulset_unavailable_replicas:ratio{namespace="$2", statefulset=~"$3"}`,
// container
"container_cpu_usage": `sum(irate(container_cpu_usage_seconds_total{namespace="$1", pod_name="$2", container_name!="POD", container_name=~"$3"}[5m])) by (namespace, pod_name, container_name)`,
"container_memory_usage": `sum(container_memory_usage_bytes{namespace="$1", pod_name="$2", container_name!="POD", container_name=~"$3"}) by (namespace, pod_name, container_name)`,
@@ -576,4 +611,7 @@ var RulePromQLTmplMap = MetricMap{
"workspace_secret_count": `sum(kube_secret_info{namespace!="", namespace$1})`,
"workspace_all_project_count": `count(kube_namespace_annotations)`,
// New in ks 2.0
"workspace_pod_abnormal_ratio": `sum(kube_pod_status_phase{phase=~"Failed|Pending|Unknown", namespace!="", namespace$1}) / sum(kube_pod_status_phase{phase!~"Succeeded", namespace!="", namespace$1})`,
}

View File

@@ -52,7 +52,7 @@ func (wrapper FormatedMetricDataWrapper) Swap(i, j int) {
}
// sorted metric by ascending or descending order
func Sort(sortMetricName string, sortType string, fmtLevelMetric *FormatedLevelMetric) (*FormatedLevelMetric, int) {
func Sort(sortMetricName string, sortType string, rawMetrics *FormatedLevelMetric) (*FormatedLevelMetric, int) {
defer func() {
if err := recover(); err != nil {
glog.Errorln(err)
@@ -61,7 +61,7 @@ func Sort(sortMetricName string, sortType string, fmtLevelMetric *FormatedLevelM
}()
if sortMetricName == "" {
return fmtLevelMetric, -1
return rawMetrics, -1
}
// default sort type is descending order
@@ -71,14 +71,18 @@ func Sort(sortMetricName string, sortType string, fmtLevelMetric *FormatedLevelM
var currentResourceMap = make(map[string]int)
// indexMap store sorted index for each node/namespace/pod
// {<Resource Name>: <Ordering>}
var indexMap = make(map[string]int)
i := 0
for _, metricItem := range fmtLevelMetric.Results {
// each metricItem is the result for a specific metric name
// so we find the metricItem with sortMetricName, and sort it
for _, metricItem := range rawMetrics.Results {
// only vector type result can be sorted
if metricItem.Data.ResultType == ResultTypeVector && metricItem.Status == MetricStatusSuccess {
if metricItem.MetricName == sortMetricName {
if sortType == ResultSortTypeAsc {
// desc
// asc
sort.Sort(FormatedMetricDataWrapper{metricItem.Data, func(p, q *map[string]interface{}) bool {
value1 := (*p)[ResultItemValue].([]interface{})
value2 := (*q)[ResultItemValue].([]interface{})
@@ -111,16 +115,14 @@ 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{})["resource_name"]
key := k.(string)
// record the ordering of resource_name to indexMap
// example: {"metric":{"resource_name": "Deployment:xxx"},"value":[1541142931.731,"3"]}
resourceName, exist := r[ResultItemMetric].(map[string]interface{})["resource_name"]
if exist {
if _, exist := indexMap[key]; !exist {
indexMap[key] = i
if _, exist := indexMap[resourceName.(string)]; !exist {
indexMap[resourceName.(string)] = i
i = i + 1
}
}
}
}
@@ -150,8 +152,8 @@ func Sort(sortMetricName string, sortType string, fmtLevelMetric *FormatedLevelM
}
// sort other metric
for i := 0; i < len(fmtLevelMetric.Results); i++ {
re := fmtLevelMetric.Results[i]
for i := 0; i < len(rawMetrics.Results); i++ {
re := rawMetrics.Results[i]
if re.Data.ResultType == ResultTypeVector && re.Status == MetricStatusSuccess {
sortedMetric := make([]map[string]interface{}, len(indexMap))
for j := 0; j < len(re.Data.Result); j++ {
@@ -165,11 +167,11 @@ func Sort(sortMetricName string, sortType string, fmtLevelMetric *FormatedLevelM
}
}
fmtLevelMetric.Results[i].Data.Result = sortedMetric
rawMetrics.Results[i].Data.Result = sortedMetric
}
}
return fmtLevelMetric, len(indexMap)
return rawMetrics, len(indexMap)
}
func Page(pageNum string, limitNum string, fmtLevelMetric *FormatedLevelMetric, maxLength int) interface{} {
@@ -253,6 +255,7 @@ func Page(pageNum string, limitNum string, fmtLevelMetric *FormatedLevelMetric,
}
// maybe this function is time consuming
// The metric param is the result from Prometheus HTTP query
func ReformatJson(metric string, metricsName string, needAddParams map[string]string, needDelParams ...string) *FormatedMetric {
var formatMetric FormatedMetric
@@ -271,6 +274,8 @@ func ReformatJson(metric string, metricsName string, needAddParams map[string]st
result := formatMetric.Data.Result
for _, res := range result {
metric, exist := res[ResultItemMetric]
// Prometheus query result format: .data.result[].metric
// metricMap is the value of .data.result[].metric
metricMap, sure := metric.(map[string]interface{})
if exist && sure {
delete(metricMap, "__name__")

View File

@@ -20,13 +20,14 @@ package routers
import (
"fmt"
"github.com/golang/glog"
"io/ioutil"
"kubesphere.io/kubesphere/pkg/simple/client/k8s"
"sort"
"k8s.io/apimachinery/pkg/labels"
"kubesphere.io/kubesphere/pkg/informers"
"github.com/golang/glog"
corev1 "k8s.io/api/core/v1"
extensionsv1beta1 "k8s.io/api/extensions/v1beta1"
meta_v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -37,12 +38,68 @@ import (
"kubesphere.io/kubesphere/pkg/constants"
)
// choose router node ip by labels, currently select master node
var RouterNodeIPLabelSelector = map[string]string{
"node-role.kubernetes.io/master": "",
}
// get master node ip, if there are multiple master nodes,
// choose first one according by their names alphabetically
func getMasterNodeIp() string {
nodeLister := informers.SharedInformerFactory().Core().V1().Nodes().Lister()
selector := labels.SelectorFromSet(RouterNodeIPLabelSelector)
masters, err := nodeLister.List(selector)
sort.Slice(masters, func(i, j int) bool {
return strings.Compare(masters[i].Name, masters[j].Name) > 0
})
if err != nil {
glog.Error(err)
return ""
}
if len(masters) == 0 {
return ""
} else {
for _, address := range masters[0].Status.Addresses {
if address.Type == corev1.NodeInternalIP {
return address.Address
}
}
}
return ""
}
func addLoadBalancerIp(service *corev1.Service) {
// append selected node ip as loadbalancer ingress ip
if service.Spec.Type != corev1.ServiceTypeLoadBalancer && len(service.Status.LoadBalancer.Ingress) == 0 {
rip := getMasterNodeIp()
if len(rip) == 0 {
glog.Info("can not get node ip")
return
}
gIngress := corev1.LoadBalancerIngress{
IP: rip,
}
service.Status.LoadBalancer.Ingress = append(service.Status.LoadBalancer.Ingress, gIngress)
}
}
func GetAllRouters() ([]*corev1.Service, error) {
selector := labels.SelectorFromSet(labels.Set{"app": "kubesphere", "component": "ks-router", "tier": "backend"})
serviceLister := informers.SharedInformerFactory().Core().V1().Services().Lister()
services, err := serviceLister.Services(constants.IngressControllerNamespace).List(selector)
for i := range services {
addLoadBalancerIp(services[i])
}
if err != nil {
glog.Error(err)
return nil, err
@@ -63,9 +120,10 @@ func GetRouter(namespace string) (*corev1.Service, error) {
glog.Error(err)
return nil, err
}
for _, s := range services {
if s.Name == serviceName {
return s, nil
for i := range services {
if services[i].Name == serviceName {
addLoadBalancerIp(services[i])
return services[i], nil
}
}
@@ -172,6 +230,7 @@ func CreateRouter(namespace string, routerType corev1.ServiceType, annotations m
}
}
addLoadBalancerIp(router)
return router, nil
}
@@ -276,5 +335,6 @@ func UpdateRouter(namespace string, routerType corev1.ServiceType, annotations m
}
}
addLoadBalancerIp(router)
return router, nil
}

View File

@@ -31,21 +31,21 @@ import (
)
const (
DefaultScheme = "http"
DefaultPrometheusPort = "9090"
PrometheusApiPath = "/api/v1/"
DefaultQueryStep = "10m"
DefaultQueryTimeout = "10s"
RangeQueryType = "query_range?"
DefaultQueryType = "query?"
PrometheusAPIServerEnv = "PROMETHEUS_API_SERVER"
DefaultQueryStep = "10m"
DefaultQueryTimeout = "10s"
RangeQueryType = "query_range?"
DefaultQueryType = "query?"
)
var PrometheusAPIServer = "prometheus-k8s.kubesphere-monitoring-system.svc"
var PrometheusAPIEndpoint string
// Kubesphere sets up two Prometheus servers to balance monitoring workloads
var (
PrometheusEndpoint string // For monitoring node, namespace, pod ... level resources
SecondaryPrometheusEndpoint string // For monitoring components including etcd, apiserver, coredns, etc.
)
func init() {
flag.StringVar(&PrometheusAPIEndpoint, "prometheus-endpoint", "http://prometheus-k8s.kubesphere-monitoring-system.svc:9090/api/v1", "")
flag.StringVar(&PrometheusEndpoint, "prometheus-endpoint", "http://prometheus-k8s.kubesphere-monitoring-system.svc:9090/api/v1/", "")
flag.StringVar(&SecondaryPrometheusEndpoint, "secondary-prometheus-endpoint", "http://prometheus-k8s-system.kubesphere-monitoring-system.svc:9090/api/v1/", "")
}
type MonitoringRequestParams struct {
@@ -71,7 +71,7 @@ type MonitoringRequestParams struct {
var client = &http.Client{}
func SendMonitoringRequest(queryType string, params string) string {
epurl := PrometheusAPIEndpoint + queryType + params
epurl := PrometheusEndpoint + queryType + params
response, err := client.Get(epurl)
if err != nil {
glog.Error(err)
@@ -157,7 +157,6 @@ func ParseMonitoringRequestParams(request *restful.Request) *MonitoringRequestPa
requestParams.Params = u
return &requestParams
} else {
//u.Set("time", strconv.FormatInt(int64(time.Now().Unix()), 10))
u.Set("timeout", timeout)
requestParams.QueryType = DefaultQueryType
requestParams.Params = u