未验证 提交 5c695a1c 编写于 作者: H huanggze

monitor: add platform metrics

Signed-off-by: Nhuanggze <loganhuang@yunify.com>
上级 b8e6a670
...@@ -152,7 +152,7 @@ func (s *APIServer) installKubeSphereAPIs() { ...@@ -152,7 +152,7 @@ func (s *APIServer) installKubeSphereAPIs() {
urlruntime.Must(configv1alpha2.AddToContainer(s.container, s.Config)) urlruntime.Must(configv1alpha2.AddToContainer(s.container, s.Config))
urlruntime.Must(resourcev1alpha3.AddToContainer(s.container, s.InformerFactory)) urlruntime.Must(resourcev1alpha3.AddToContainer(s.container, s.InformerFactory))
urlruntime.Must(loggingv1alpha2.AddToContainer(s.container, s.KubernetesClient, s.LoggingClient)) urlruntime.Must(loggingv1alpha2.AddToContainer(s.container, s.KubernetesClient, s.LoggingClient))
urlruntime.Must(monitoringv1alpha3.AddToContainer(s.container, s.KubernetesClient.Kubernetes(), s.MonitoringClient)) urlruntime.Must(monitoringv1alpha3.AddToContainer(s.container, s.KubernetesClient.Kubernetes(), s.MonitoringClient, s.InformerFactory, s.OpenpitrixClient))
urlruntime.Must(openpitrixv1.AddToContainer(s.container, s.InformerFactory, s.OpenpitrixClient)) urlruntime.Must(openpitrixv1.AddToContainer(s.container, s.InformerFactory, s.OpenpitrixClient))
urlruntime.Must(networkv1alpha2.AddToContainer(s.container, s.Config.NetworkOptions.WeaveScopeHost)) urlruntime.Must(networkv1alpha2.AddToContainer(s.container, s.Config.NetworkOptions.WeaveScopeHost))
urlruntime.Must(operationsv1alpha2.AddToContainer(s.container, s.KubernetesClient.Kubernetes())) urlruntime.Must(operationsv1alpha2.AddToContainer(s.container, s.KubernetesClient.Kubernetes()))
......
...@@ -69,6 +69,7 @@ const ( ...@@ -69,6 +69,7 @@ const (
DevOpsWebhookTag = "DevOps Webhook" DevOpsWebhookTag = "DevOps Webhook"
DevOpsJenkinsfileTag = "DevOps Jenkinsfile" DevOpsJenkinsfileTag = "DevOps Jenkinsfile"
DevOpsScmTag = "DevOps Scm" DevOpsScmTag = "DevOps Scm"
KubeSphereMetricsTag = "KubeSphere Metrics"
ClusterMetricsTag = "Cluster Metrics" ClusterMetricsTag = "Cluster Metrics"
NodeMetricsTag = "Node Metrics" NodeMetricsTag = "Node Metrics"
NamespaceMetricsTag = "Namespace Metrics" NamespaceMetricsTag = "Namespace Metrics"
......
...@@ -23,8 +23,10 @@ import ( ...@@ -23,8 +23,10 @@ import (
"github.com/emicklei/go-restful" "github.com/emicklei/go-restful"
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
"kubesphere.io/kubesphere/pkg/api" "kubesphere.io/kubesphere/pkg/api"
"kubesphere.io/kubesphere/pkg/informers"
model "kubesphere.io/kubesphere/pkg/models/monitoring" model "kubesphere.io/kubesphere/pkg/models/monitoring"
"kubesphere.io/kubesphere/pkg/simple/client/monitoring" "kubesphere.io/kubesphere/pkg/simple/client/monitoring"
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
"regexp" "regexp"
) )
...@@ -33,8 +35,13 @@ type handler struct { ...@@ -33,8 +35,13 @@ type handler struct {
mo model.MonitoringOperator mo model.MonitoringOperator
} }
func newHandler(k kubernetes.Interface, m monitoring.Interface) *handler { func newHandler(k kubernetes.Interface, m monitoring.Interface, f informers.InformerFactory, o openpitrix.Client) *handler {
return &handler{k, model.NewMonitoringOperator(m)} return &handler{k, model.NewMonitoringOperator(m, k, f, o)}
}
func (h handler) handleKubeSphereMetricsQuery(req *restful.Request, resp *restful.Response) {
res := h.mo.GetKubeSphereStats()
resp.WriteAsJson(res)
} }
func (h handler) handleClusterMetricsQuery(req *restful.Request, resp *restful.Response) { func (h handler) handleClusterMetricsQuery(req *restful.Request, resp *restful.Response) {
...@@ -64,7 +71,13 @@ func (h handler) handleWorkspaceMetricsQuery(req *restful.Request, resp *restful ...@@ -64,7 +71,13 @@ func (h handler) handleWorkspaceMetricsQuery(req *restful.Request, resp *restful
api.HandleBadRequest(resp, nil, err) api.HandleBadRequest(resp, nil, err)
return return
} }
h.handleNamedMetricsQuery(resp, opt)
if req.QueryParameter("type") == "statistics" {
res := h.mo.GetWorkspaceStats(params.workspaceName)
resp.WriteAsJson(res)
} else {
h.handleNamedMetricsQuery(resp, opt)
}
} }
func (h handler) handleNamespaceMetricsQuery(req *restful.Request, resp *restful.Response) { func (h handler) handleNamespaceMetricsQuery(req *restful.Request, resp *restful.Response) {
......
...@@ -6,6 +6,7 @@ import ( ...@@ -6,6 +6,7 @@ import (
corev1 "k8s.io/api/core/v1" corev1 "k8s.io/api/core/v1"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/client-go/kubernetes/fake" "k8s.io/client-go/kubernetes/fake"
"kubesphere.io/kubesphere/pkg/informers"
model "kubesphere.io/kubesphere/pkg/models/monitoring" model "kubesphere.io/kubesphere/pkg/models/monitoring"
"kubesphere.io/kubesphere/pkg/simple/client/monitoring" "kubesphere.io/kubesphere/pkg/simple/client/monitoring"
"testing" "testing"
...@@ -209,7 +210,8 @@ func TestParseRequestParams(t *testing.T) { ...@@ -209,7 +210,8 @@ func TestParseRequestParams(t *testing.T) {
for i, tt := range tests { for i, tt := range tests {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) { t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
client := fake.NewSimpleClientset(&tt.namespace) client := fake.NewSimpleClientset(&tt.namespace)
handler := newHandler(client, nil) fakeInformerFactory := informers.NewInformerFactories(client, nil, nil, nil, nil, nil)
handler := newHandler(client, nil, fakeInformerFactory, nil)
result, err := handler.makeQueryOptions(tt.params, tt.lvl) result, err := handler.makeQueryOptions(tt.params, tt.lvl)
if err != nil { if err != nil {
......
...@@ -24,8 +24,10 @@ import ( ...@@ -24,8 +24,10 @@ import (
"k8s.io/client-go/kubernetes" "k8s.io/client-go/kubernetes"
"kubesphere.io/kubesphere/pkg/apiserver/runtime" "kubesphere.io/kubesphere/pkg/apiserver/runtime"
"kubesphere.io/kubesphere/pkg/constants" "kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/informers"
model "kubesphere.io/kubesphere/pkg/models/monitoring" model "kubesphere.io/kubesphere/pkg/models/monitoring"
"kubesphere.io/kubesphere/pkg/simple/client/monitoring" "kubesphere.io/kubesphere/pkg/simple/client/monitoring"
"kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
"net/http" "net/http"
) )
...@@ -36,10 +38,18 @@ const ( ...@@ -36,10 +38,18 @@ const (
var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha3"} var GroupVersion = schema.GroupVersion{Group: GroupName, Version: "v1alpha3"}
func AddToContainer(c *restful.Container, k8sClient kubernetes.Interface, monitoringClient monitoring.Interface) error { func AddToContainer(c *restful.Container, k8sClient kubernetes.Interface, monitoringClient monitoring.Interface, factory informers.InformerFactory, opClient openpitrix.Client) error {
ws := runtime.NewWebService(GroupVersion) ws := runtime.NewWebService(GroupVersion)
h := newHandler(k8sClient, monitoringClient) h := newHandler(k8sClient, monitoringClient, factory, opClient)
ws.Route(ws.GET("/kubesphere").
To(h.handleKubeSphereMetricsQuery).
Doc("Get platform-level metric data.").
Metadata(restfulspec.KeyOpenAPITags, []string{constants.KubeSphereMetricsTag}).
Writes(model.Metrics{}).
Returns(http.StatusOK, RespOK, model.Metrics{})).
Produces(restful.MIME_JSON)
ws.Route(ws.GET("/cluster"). ws.Route(ws.GET("/cluster").
To(h.handleClusterMetricsQuery). To(h.handleClusterMetricsQuery).
...@@ -113,6 +123,7 @@ func AddToContainer(c *restful.Container, k8sClient kubernetes.Interface, monito ...@@ -113,6 +123,7 @@ func AddToContainer(c *restful.Container, k8sClient kubernetes.Interface, monito
Param(ws.QueryParameter("end", "End time of query. Use **start** and **end** to retrieve metric data over a time span. It is a string with Unix time format, eg. 1561939200. ").DataType("string").Required(false)). Param(ws.QueryParameter("end", "End time of query. Use **start** and **end** to retrieve metric data over a time span. It is a string with Unix time format, eg. 1561939200. ").DataType("string").Required(false)).
Param(ws.QueryParameter("step", "Time interval. Retrieve metric data at a fixed interval within the time range of start and end. It requires both **start** and **end** are provided. The format is [0-9]+[smhdwy]. Defaults to 10m (i.e. 10 min).").DataType("string").DefaultValue("10m").Required(false)). Param(ws.QueryParameter("step", "Time interval. Retrieve metric data at a fixed interval within the time range of start and end. It requires both **start** and **end** are provided. The format is [0-9]+[smhdwy]. Defaults to 10m (i.e. 10 min).").DataType("string").DefaultValue("10m").Required(false)).
Param(ws.QueryParameter("time", "A timestamp in Unix time format. Retrieve metric data at a single point in time. Defaults to now. Time and the combination of start, end, step are mutually exclusive.").DataType("string").Required(false)). Param(ws.QueryParameter("time", "A timestamp in Unix time format. Retrieve metric data at a single point in time. Defaults to now. Time and the combination of start, end, step are mutually exclusive.").DataType("string").Required(false)).
Param(ws.QueryParameter("type", "Additional operations. Currently available types is statistics. It retrieves the total number of namespaces, devops projects, members and roles in this workspace at the moment.").DataType("string").Required(false)).
Metadata(restfulspec.KeyOpenAPITags, []string{constants.WorkspaceMetricsTag}). Metadata(restfulspec.KeyOpenAPITags, []string{constants.WorkspaceMetricsTag}).
Writes(model.Metrics{}). Writes(model.Metrics{}).
Returns(http.StatusOK, RespOK, model.Metrics{})). Returns(http.StatusOK, RespOK, model.Metrics{})).
......
...@@ -19,9 +19,18 @@ ...@@ -19,9 +19,18 @@
package monitoring package monitoring
import ( import (
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/client-go/kubernetes"
"k8s.io/klog" "k8s.io/klog"
ksinformers "kubesphere.io/kubesphere/pkg/client/informers/externalversions"
"kubesphere.io/kubesphere/pkg/constants"
"kubesphere.io/kubesphere/pkg/informers"
"kubesphere.io/kubesphere/pkg/models/monitoring/expressions" "kubesphere.io/kubesphere/pkg/models/monitoring/expressions"
"kubesphere.io/kubesphere/pkg/models/openpitrix"
"kubesphere.io/kubesphere/pkg/server/params"
"kubesphere.io/kubesphere/pkg/simple/client/monitoring" "kubesphere.io/kubesphere/pkg/simple/client/monitoring"
opclient "kubesphere.io/kubesphere/pkg/simple/client/openpitrix"
"time" "time"
) )
...@@ -32,14 +41,26 @@ type MonitoringOperator interface { ...@@ -32,14 +41,26 @@ type MonitoringOperator interface {
GetNamedMetricsOverTime(metrics []string, start, end time.Time, step time.Duration, opt monitoring.QueryOption) Metrics GetNamedMetricsOverTime(metrics []string, start, end time.Time, step time.Duration, opt monitoring.QueryOption) Metrics
GetMetadata(namespace string) Metadata GetMetadata(namespace string) Metadata
GetMetricLabelSet(metric, namespace string, start, end time.Time) MetricLabelSet GetMetricLabelSet(metric, namespace string, start, end time.Time) MetricLabelSet
// TODO: refactor
GetKubeSphereStats() Metrics
GetWorkspaceStats(workspace string) Metrics
} }
type monitoringOperator struct { type monitoringOperator struct {
c monitoring.Interface c monitoring.Interface
k8s kubernetes.Interface
ks ksinformers.SharedInformerFactory
op openpitrix.Interface
} }
func NewMonitoringOperator(client monitoring.Interface) MonitoringOperator { func NewMonitoringOperator(client monitoring.Interface, k8s kubernetes.Interface, factory informers.InformerFactory, opClient opclient.Client) MonitoringOperator {
return &monitoringOperator{client} return &monitoringOperator{
c: client,
k8s: k8s,
ks: factory.KubeSphereSharedInformerFactory(),
op: openpitrix.NewOpenpitrixOperator(factory.KubernetesSharedInformerFactory(), opClient),
}
} }
func (mo monitoringOperator) GetMetric(expr, namespace string, time time.Time) (monitoring.Metric, error) { func (mo monitoringOperator) GetMetric(expr, namespace string, time time.Time) (monitoring.Metric, error) {
...@@ -94,3 +115,184 @@ func (mo monitoringOperator) GetMetricLabelSet(metric, namespace string, start, ...@@ -94,3 +115,184 @@ func (mo monitoringOperator) GetMetricLabelSet(metric, namespace string, start,
data := mo.c.GetMetricLabelSet(expr, start, end) data := mo.c.GetMetricLabelSet(expr, start, end)
return MetricLabelSet{Data: data} return MetricLabelSet{Data: data}
} }
func (mo monitoringOperator) GetKubeSphereStats() Metrics {
var res Metrics
now := float64(time.Now().Unix())
clusterList, err := mo.ks.Cluster().V1alpha1().Clusters().Lister().List(labels.Everything())
clusterTotal := len(clusterList)
if clusterTotal == 0 {
clusterTotal = 1
}
if err != nil {
res.Results = append(res.Results, monitoring.Metric{
MetricName: KubeSphereClusterCount,
Error: err.Error(),
})
} else {
res.Results = append(res.Results, monitoring.Metric{
MetricName: KubeSphereClusterCount,
MetricData: monitoring.MetricData{
MetricType: monitoring.MetricTypeVector,
MetricValues: []monitoring.MetricValue{
{
Sample: &monitoring.Point{now, float64(clusterTotal)},
},
},
},
})
}
wkList, err := mo.ks.Tenant().V1alpha1().Workspaces().Lister().List(labels.Everything())
if err != nil {
res.Results = append(res.Results, monitoring.Metric{
MetricName: KubeSphereWorkspaceCount,
Error: err.Error(),
})
} else {
res.Results = append(res.Results, monitoring.Metric{
MetricName: KubeSphereWorkspaceCount,
MetricData: monitoring.MetricData{
MetricType: monitoring.MetricTypeVector,
MetricValues: []monitoring.MetricValue{
{
Sample: &monitoring.Point{now, float64(len(wkList))},
},
},
},
})
}
usrList, err := mo.ks.Iam().V1alpha2().Users().Lister().List(labels.Everything())
if err != nil {
res.Results = append(res.Results, monitoring.Metric{
MetricName: KubeSphereUserCount,
Error: err.Error(),
})
} else {
res.Results = append(res.Results, monitoring.Metric{
MetricName: KubeSphereUserCount,
MetricData: monitoring.MetricData{
MetricType: monitoring.MetricTypeVector,
MetricValues: []monitoring.MetricValue{
{
Sample: &monitoring.Point{now, float64(len(usrList))},
},
},
},
})
}
tmpls, err := mo.op.ListApps(&params.Conditions{}, "", false, 0, 0)
if err != nil {
res.Results = append(res.Results, monitoring.Metric{
MetricName: KubeSphereAppTmplCount,
Error: err.Error(),
})
} else {
res.Results = append(res.Results, monitoring.Metric{
MetricName: KubeSphereAppTmplCount,
MetricData: monitoring.MetricData{
MetricType: monitoring.MetricTypeVector,
MetricValues: []monitoring.MetricValue{
{
Sample: &monitoring.Point{now, float64(tmpls.TotalCount)},
},
},
},
})
}
return res
}
func (mo monitoringOperator) GetWorkspaceStats(workspace string) Metrics {
var res Metrics
now := float64(time.Now().Unix())
selector := labels.SelectorFromSet(labels.Set{constants.WorkspaceLabelKey: workspace})
opt := metav1.ListOptions{LabelSelector: selector.String()}
nsList, err := mo.k8s.CoreV1().Namespaces().List(opt)
if err != nil {
res.Results = append(res.Results, monitoring.Metric{
MetricName: WorkspaceNamespaceCount,
Error: err.Error(),
})
} else {
res.Results = append(res.Results, monitoring.Metric{
MetricName: WorkspaceNamespaceCount,
MetricData: monitoring.MetricData{
MetricType: monitoring.MetricTypeVector,
MetricValues: []monitoring.MetricValue{
{
Sample: &monitoring.Point{now, float64(len(nsList.Items))},
},
},
},
})
}
devopsList, err := mo.ks.Devops().V1alpha3().DevOpsProjects().Lister().List(selector)
if err != nil {
res.Results = append(res.Results, monitoring.Metric{
MetricName: WorkspaceDevopsCount,
Error: err.Error(),
})
} else {
res.Results = append(res.Results, monitoring.Metric{
MetricName: WorkspaceDevopsCount,
MetricData: monitoring.MetricData{
MetricType: monitoring.MetricTypeVector,
MetricValues: []monitoring.MetricValue{
{
Sample: &monitoring.Point{now, float64(len(devopsList))},
},
},
},
})
}
memberList, err := mo.ks.Iam().V1alpha2().WorkspaceRoleBindings().Lister().List(selector)
if err != nil {
res.Results = append(res.Results, monitoring.Metric{
MetricName: WorkspaceMemberCount,
Error: err.Error(),
})
} else {
res.Results = append(res.Results, monitoring.Metric{
MetricName: WorkspaceMemberCount,
MetricData: monitoring.MetricData{
MetricType: monitoring.MetricTypeVector,
MetricValues: []monitoring.MetricValue{
{
Sample: &monitoring.Point{now, float64(len(memberList))},
},
},
},
})
}
roleList, err := mo.ks.Iam().V1alpha2().WorkspaceRoles().Lister().List(selector)
if err != nil {
res.Results = append(res.Results, monitoring.Metric{
MetricName: WorkspaceRoleCount,
Error: err.Error(),
})
} else {
res.Results = append(res.Results, monitoring.Metric{
MetricName: WorkspaceRoleCount,
MetricData: monitoring.MetricData{
MetricType: monitoring.MetricTypeVector,
MetricValues: []monitoring.MetricValue{
{
Sample: &monitoring.Point{now, float64(len(roleList))},
},
},
},
})
}
return res
}
package monitoring package monitoring
const (
KubeSphereWorkspaceCount = "kubesphere_workspace_count"
KubeSphereUserCount = "kubesphere_user_count"
KubeSphereClusterCount = "kubesphere_cluser_count"
KubeSphereAppTmplCount = "kubesphere_app_template_count"
WorkspaceNamespaceCount = "workspace_namespace_count"
WorkspaceDevopsCount = "workspace_devops_project_count"
WorkspaceMemberCount = "workspace_member_count"
WorkspaceRoleCount = "workspace_role_count"
)
var ClusterMetrics = []string{ var ClusterMetrics = []string{
"cluster_cpu_utilisation", "cluster_cpu_utilisation",
"cluster_cpu_usage", "cluster_cpu_usage",
......
...@@ -115,7 +115,7 @@ func generateSwaggerJson() []byte { ...@@ -115,7 +115,7 @@ func generateSwaggerJson() []byte {
urlruntime.Must(devopsv1alpha2.AddToContainer(container, informerFactory.KubeSphereSharedInformerFactory(), &fake.Devops{}, nil, clientsets.KubeSphere(), fakes3.NewFakeS3())) urlruntime.Must(devopsv1alpha2.AddToContainer(container, informerFactory.KubeSphereSharedInformerFactory(), &fake.Devops{}, nil, clientsets.KubeSphere(), fakes3.NewFakeS3()))
urlruntime.Must(iamv1alpha2.AddToContainer(container, im.NewOperator(clientsets.KubeSphere(), informerFactory), am.NewAMOperator(informerFactory), authoptions.NewAuthenticateOptions())) urlruntime.Must(iamv1alpha2.AddToContainer(container, im.NewOperator(clientsets.KubeSphere(), informerFactory), am.NewAMOperator(informerFactory), authoptions.NewAuthenticateOptions()))
urlruntime.Must(loggingv1alpha2.AddToContainer(container, clientsets, nil)) urlruntime.Must(loggingv1alpha2.AddToContainer(container, clientsets, nil))
urlruntime.Must(monitoringv1alpha3.AddToContainer(container, clientsets.Kubernetes(), nil)) urlruntime.Must(monitoringv1alpha3.AddToContainer(container, clientsets.Kubernetes(), nil, informerFactory, nil))
urlruntime.Must(openpitrixv1.AddToContainer(container, informerFactory, nil)) urlruntime.Must(openpitrixv1.AddToContainer(container, informerFactory, nil))
urlruntime.Must(operationsv1alpha2.AddToContainer(container, clientsets.Kubernetes())) urlruntime.Must(operationsv1alpha2.AddToContainer(container, clientsets.Kubernetes()))
urlruntime.Must(resourcesv1alpha2.AddToContainer(container, clientsets.Kubernetes(), informerFactory)) urlruntime.Must(resourcesv1alpha2.AddToContainer(container, clientsets.Kubernetes(), informerFactory))
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册