pod监控图表信息修改

Former-commit-id: 2e7cfdfda57c7db575870bacd21b4bfa6d14bd4d
This commit is contained in:
zhangwei 2023-11-22 14:37:26 +08:00
parent 2f8c24339a
commit e5b02d4d32
14 changed files with 265 additions and 80 deletions

View File

@ -8,6 +8,21 @@ info(
) )
/******************find datasetList start*************************/ /******************find datasetList start*************************/
type ControllerMetricsReq {
ParticipantId int64 `form:"participantId"`
Namespace string `form:"namespace"`
Pods string `form:"pods"`
Steps string `form:"steps"`
Start string `form:"start"`
End string `form:"end"`
}
type ControllerMetricsResp {
Data interface{} `json:"data"`
}
type ApplyReq { type ApplyReq {
YamlString string `json:"yamlString" copier:"yamlString"` YamlString string `json:"yamlString" copier:"yamlString"`
} }

View File

@ -141,6 +141,10 @@ service pcm {
@doc "yaml删除" @doc "yaml删除"
@handler deleteYamlHandler @handler deleteYamlHandler
get /cloud/DeleteYaml (ApplyReq) returns (DeleteResp) get /cloud/DeleteYaml (ApplyReq) returns (DeleteResp)
@doc "控制器监控"
@handler controllerMetricsHandler
get /cloud/controller/Metrics (ControllerMetricsReq) returns (ControllerMetricsResp)
} }
//智算二级接口 //智算二级接口

View File

@ -24,7 +24,7 @@ func AddCronGroup(svc *svc.ServiceContext) {
SyncParticipantRpc(svc) SyncParticipantRpc(svc)
}) })
// 删除三天前的监控信息 // 删除三天前的监控信息
svc.Cron.AddFunc("*/5 * * * * ?", func() { svc.Cron.AddFunc("0 0 0 ? * ? ", func() {
ClearMetricsData(svc) ClearMetricsData(svc)
}) })

View File

@ -19,6 +19,7 @@ import (
"gitlink.org.cn/jcce-pcm/pcm-coordinator/api/internal/svc" "gitlink.org.cn/jcce-pcm/pcm-coordinator/api/internal/svc"
"gitlink.org.cn/jcce-pcm/pcm-coordinator/pkg/constants" "gitlink.org.cn/jcce-pcm/pcm-coordinator/pkg/constants"
"gitlink.org.cn/jcce-pcm/pcm-coordinator/pkg/models" "gitlink.org.cn/jcce-pcm/pcm-coordinator/pkg/models"
"gitlink.org.cn/jcce-pcm/pcm-coordinator/pkg/tracker"
"gitlink.org.cn/jcce-pcm/pcm-participant-kubernetes/kubernetesclient" "gitlink.org.cn/jcce-pcm/pcm-participant-kubernetes/kubernetesclient"
) )
@ -30,14 +31,22 @@ func SyncParticipantRpc(svc *svc.ServiceContext) {
} }
for _, participant := range participants { for _, participant := range participants {
// 初始化p端rpc客户端
if len(participant.RpcAddress) != 0 && svc.K8sRpc[participant.Id] == nil { if len(participant.RpcAddress) != 0 && svc.K8sRpc[participant.Id] == nil {
switch participant.Type { switch participant.Type {
case constants.CLOUD: case constants.CLOUD:
// 初始化p端rpc客户端
svc.K8sRpc[participant.Id] = kubernetesclient.NewKubernetes(zrpc.MustNewClient(zrpc.RpcClientConf{ svc.K8sRpc[participant.Id] = kubernetesclient.NewKubernetes(zrpc.MustNewClient(zrpc.RpcClientConf{
Endpoints: []string{participant.RpcAddress}, Endpoints: []string{participant.RpcAddress},
NonBlock: true, NonBlock: true,
})) }))
// 初始化p端prometheus client
promClient, err := tracker.NewPrometheus(participant.MetricsUrl)
if err != nil {
return
}
svc.PromClient[participant.Id] = promClient
} }
} }
} }

View File

@ -0,0 +1,25 @@
package cloud
import (
"gitlink.org.cn/jcce-pcm/pcm-coordinator/pkg/repository/result"
"net/http"
"github.com/zeromicro/go-zero/rest/httpx"
"gitlink.org.cn/jcce-pcm/pcm-coordinator/api/internal/logic/cloud"
"gitlink.org.cn/jcce-pcm/pcm-coordinator/api/internal/svc"
"gitlink.org.cn/jcce-pcm/pcm-coordinator/api/internal/types"
)
func ControllerMetricsHandler(svcCtx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req types.ControllerMetricsReq
if err := httpx.Parse(r, &req); err != nil {
httpx.ErrorCtx(r.Context(), w, err)
return
}
l := cloud.NewControllerMetricsLogic(r.Context(), svcCtx)
resp, err := l.ControllerMetrics(&req)
result.HttpResult(r, w, resp, err)
}
}

View File

@ -162,6 +162,11 @@ func RegisterHandlers(server *rest.Server, serverCtx *svc.ServiceContext) {
Path: "/cloud/DeleteYaml", Path: "/cloud/DeleteYaml",
Handler: cloud.DeleteYamlHandler(serverCtx), Handler: cloud.DeleteYamlHandler(serverCtx),
}, },
{
Method: http.MethodGet,
Path: "/cloud/controller/Metrics",
Handler: cloud.ControllerMetricsHandler(serverCtx),
},
}, },
rest.WithPrefix("/pcm/v1"), rest.WithPrefix("/pcm/v1"),
) )

View File

@ -0,0 +1,35 @@
package cloud
import (
"context"
"gitlink.org.cn/jcce-pcm/pcm-coordinator/api/internal/svc"
"gitlink.org.cn/jcce-pcm/pcm-coordinator/api/internal/types"
"gitlink.org.cn/jcce-pcm/pcm-coordinator/pkg/tracker"
"time"
"github.com/zeromicro/go-zero/core/logx"
)
type ControllerMetricsLogic struct {
logx.Logger
ctx context.Context
svcCtx *svc.ServiceContext
}
func NewControllerMetricsLogic(ctx context.Context, svcCtx *svc.ServiceContext) *ControllerMetricsLogic {
return &ControllerMetricsLogic{
Logger: logx.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *ControllerMetricsLogic) ControllerMetrics(req *types.ControllerMetricsReq) (resp *types.ControllerMetricsResp, err error) {
resp = &types.ControllerMetricsResp{}
metrics := l.svcCtx.PromClient[req.ParticipantId].GetNamedMetricsByTime([]string{"pod_cpu_usage", "pod_memory_usage_wo_cache"}, req.Start, req.End, 10*time.Minute, tracker.ControllerOption{
PodsName: req.Pods,
Namespace: req.Namespace,
})
resp.Data = metrics
return resp, nil
}

View File

@ -26,6 +26,7 @@ import (
"github.com/zeromicro/go-zero/zrpc" "github.com/zeromicro/go-zero/zrpc"
"gitlink.org.cn/jcce-pcm/pcm-ac/hpcacclient" "gitlink.org.cn/jcce-pcm/pcm-ac/hpcacclient"
"gitlink.org.cn/jcce-pcm/pcm-coordinator/api/internal/config" "gitlink.org.cn/jcce-pcm/pcm-coordinator/api/internal/config"
"gitlink.org.cn/jcce-pcm/pcm-coordinator/pkg/tracker"
"gitlink.org.cn/jcce-pcm/pcm-coordinator/pkg/utils" "gitlink.org.cn/jcce-pcm/pcm-coordinator/pkg/utils"
"gitlink.org.cn/jcce-pcm/pcm-coordinator/rpc/client/participantservice" "gitlink.org.cn/jcce-pcm/pcm-coordinator/rpc/client/participantservice"
"gitlink.org.cn/jcce-pcm/pcm-participant-ceph/cephclient" "gitlink.org.cn/jcce-pcm/pcm-participant-ceph/cephclient"
@ -56,6 +57,7 @@ type ServiceContext struct {
Downloader *s3manager.Downloader Downloader *s3manager.Downloader
Uploader *s3manager.Uploader Uploader *s3manager.Uploader
K8sRpc map[int64]kubernetesclient.Kubernetes K8sRpc map[int64]kubernetesclient.Kubernetes
PromClient map[int64]tracker.Prometheus
ParticipantRpc participantservice.ParticipantService ParticipantRpc participantservice.ParticipantService
} }
@ -103,6 +105,7 @@ func NewServiceContext(c config.Config) *ServiceContext {
OctopusRpc: octopusclient.NewOctopus(zrpc.MustNewClient(c.OctopusRpcConf)), OctopusRpc: octopusclient.NewOctopus(zrpc.MustNewClient(c.OctopusRpcConf)),
OpenstackRpc: openstackclient.NewOpenstack(zrpc.MustNewClient(c.OpenstackRpcConf)), OpenstackRpc: openstackclient.NewOpenstack(zrpc.MustNewClient(c.OpenstackRpcConf)),
K8sRpc: make(map[int64]kubernetesclient.Kubernetes), K8sRpc: make(map[int64]kubernetesclient.Kubernetes),
PromClient: make(map[int64]tracker.Prometheus),
ParticipantRpc: participantservice.NewParticipantService(zrpc.MustNewClient(c.PcmCoreRpcConf)), ParticipantRpc: participantservice.NewParticipantService(zrpc.MustNewClient(c.PcmCoreRpcConf)),
DockerClient: dockerClient, DockerClient: dockerClient,
Downloader: downloader, Downloader: downloader,

View File

@ -3325,6 +3325,19 @@ type ShowNodeDetailsResp struct {
ErrorMsg string `json:"errorMsg,omitempty"` ErrorMsg string `json:"errorMsg,omitempty"`
} }
type ControllerMetricsReq struct {
ParticipantId int64 `form:"participantId"`
Namespace string `form:"namespace"`
Pods string `form:"pods"`
Steps string `form:"steps"`
Start string `form:"start"`
End string `form:"end"`
}
type ControllerMetricsResp struct {
Data interface{} `json:"data"`
}
type ApplyReq struct { type ApplyReq struct {
YamlString string `json:"yamlString" copier:"yamlString"` YamlString string `json:"yamlString" copier:"yamlString"`
} }

View File

@ -20,7 +20,7 @@ type Interface interface {
//GetMetric(expr string, time time.Time) Metric //GetMetric(expr string, time time.Time) Metric
//GetMetricOverTime(expr string, start, end time.Time, step time.Duration) Metric //GetMetricOverTime(expr string, start, end time.Time, step time.Duration) Metric
GetNamedMetrics(metrics []string, time time.Time, opt QueryOption) []Metric GetNamedMetrics(metrics []string, time time.Time, opt QueryOption) []Metric
//GetNamedMetricsOverTime(metrics []string, start, end time.Time, step time.Duration, opt QueryOption) []Metric GetNamedMetricsByTime(metrics []string, start, end string, step time.Duration, opt QueryOption) []Metric
//GetMetadata(namespace string) []Metadata //GetMetadata(namespace string) []Metadata
//GetMetricLabelSet(expr string, start, end time.Time) []map[string]string //GetMetricLabelSet(expr string, start, end time.Time) []map[string]string
// //

View File

@ -202,7 +202,7 @@ var promQLTemplates = map[string]string{
"workload_statefulset_unavailable_replicas_ratio": `namespace:statefulset_unavailable_replicas:ratio{$1}`, "workload_statefulset_unavailable_replicas_ratio": `namespace:statefulset_unavailable_replicas:ratio{$1}`,
// pod // pod
"pod_cpu_usage": `round(sum by (namespace, pod) (irate(container_cpu_usage_seconds_total{job="kubelet", pod!="", image!=""}[5m])) * on (namespace, pod) group_left(owner_kind, owner_name) kube_pod_owner{$1} * on (namespace, pod) group_left(node) kube_pod_info{$2}, 0.001)`, "pod_cpu_usage": `round(sum by (namespace, pod) (irate(container_cpu_usage_seconds_total{job="kubelet", pod!="", image!=""}[5m])) * on (namespace, pod) group_left(owner_kind,owner_name) kube_pod_owner{$1} * on (namespace, pod) group_left(node) kube_pod_info{$2}, 0.001)`,
"pod_memory_usage": `sum by (namespace, pod) (container_memory_usage_bytes{job="kubelet", pod!="", image!=""}) * on (namespace, pod) group_left(owner_kind, owner_name) kube_pod_owner{$1} * on (namespace, pod) group_left(node) kube_pod_info{$2}`, "pod_memory_usage": `sum by (namespace, pod) (container_memory_usage_bytes{job="kubelet", pod!="", image!=""}) * on (namespace, pod) group_left(owner_kind, owner_name) kube_pod_owner{$1} * on (namespace, pod) group_left(node) kube_pod_info{$2}`,
"pod_memory_usage_wo_cache": `sum by (namespace, pod) (container_memory_working_set_bytes{job="kubelet", pod!="", image!=""}) * on (namespace, pod) group_left(owner_kind, owner_name) kube_pod_owner{$1} * on (namespace, pod) group_left(node) kube_pod_info{$2}`, "pod_memory_usage_wo_cache": `sum by (namespace, pod) (container_memory_working_set_bytes{job="kubelet", pod!="", image!=""}) * on (namespace, pod) group_left(owner_kind, owner_name) kube_pod_owner{$1} * on (namespace, pod) group_left(node) kube_pod_info{$2}`,
"pod_net_bytes_transmitted": `sum by (namespace, pod) (irate(container_network_transmit_bytes_total{pod!="", interface!~"^(cali.+|tunl.+|dummy.+|kube.+|flannel.+|cni.+|docker.+|veth.+|lo.*)", job="kubelet"}[5m])) * on (namespace, pod) group_left(owner_kind, owner_name) kube_pod_owner{$1} * on (namespace, pod) group_left(node) kube_pod_info{$2}`, "pod_net_bytes_transmitted": `sum by (namespace, pod) (irate(container_network_transmit_bytes_total{pod!="", interface!~"^(cali.+|tunl.+|dummy.+|kube.+|flannel.+|cni.+|docker.+|veth.+|lo.*)", job="kubelet"}[5m])) * on (namespace, pod) group_left(owner_kind, owner_name) kube_pod_owner{$1} * on (namespace, pod) group_left(node) kube_pod_info{$2}`,
@ -274,8 +274,8 @@ func makeExpr(metric string, opts QueryOptions) string {
return makeWorkspaceMetricExpr(tmpl, opts) return makeWorkspaceMetricExpr(tmpl, opts)
case LevelNamespace: case LevelNamespace:
return makeNamespaceMetricExpr(tmpl, opts) return makeNamespaceMetricExpr(tmpl, opts)
case LevelWorkload: case LevelController:
return makeWorkloadMetricExpr(metric, tmpl, opts) return makeControllerMetricExpr(tmpl, opts)
case LevelPod: case LevelPod:
return makePodMetricExpr(tmpl, opts) return makePodMetricExpr(tmpl, opts)
case LevelContainer: case LevelContainer:
@ -324,40 +324,20 @@ func makeNamespaceMetricExpr(tmpl string, o QueryOptions) string {
// For monitoring the specific namespaces // For monitoring the specific namespaces
// GET /namespaces/{namespace} or // GET /namespaces/{namespace} or
// GET /namespaces // GET /namespaces
if o.NamespaceName != "" { if o.Namespace != "" {
namespaceSelector = fmt.Sprintf(`namespace="%s"`, o.NamespaceName) namespaceSelector = fmt.Sprintf(`namespace="%s"`, o.Namespace)
} else { } else {
namespaceSelector = fmt.Sprintf(`namespace=~"%s"`, o.ResourceFilter) namespaceSelector = fmt.Sprintf(`namespace=~"%s"`, o.ResourceFilter)
} }
return strings.Replace(tmpl, "$1", namespaceSelector, -1) return strings.Replace(tmpl, "$1", namespaceSelector, -1)
} }
func makeWorkloadMetricExpr(metric, tmpl string, o QueryOptions) string { func makeControllerMetricExpr(tmpl string, o QueryOptions) string {
var kindSelector, workloadSelector string var namespace, podName string
switch o.WorkloadKind { namespace = fmt.Sprintf(`namespace="%s"`, o.Namespace)
case "deployment": podName = fmt.Sprintf(`pod=~"%s"`, o.PodName)
o.WorkloadKind = Deployment return strings.NewReplacer("$1", namespace, "$2", podName).Replace(tmpl)
case "statefulset":
o.WorkloadKind = StatefulSet
case "daemonset":
o.WorkloadKind = DaemonSet
default:
o.WorkloadKind = ".*"
}
workloadSelector = fmt.Sprintf(`namespace="%s", workload=~"%s:(%s)"`, o.NamespaceName, o.WorkloadKind, o.ResourceFilter)
if strings.Contains(metric, "deployment") {
kindSelector = fmt.Sprintf(`namespace="%s", deployment!="", deployment=~"%s"`, o.NamespaceName, o.ResourceFilter)
}
if strings.Contains(metric, "statefulset") {
kindSelector = fmt.Sprintf(`namespace="%s", statefulset!="", statefulset=~"%s"`, o.NamespaceName, o.ResourceFilter)
}
if strings.Contains(metric, "daemonset") {
kindSelector = fmt.Sprintf(`namespace="%s", daemonset!="", daemonset=~"%s"`, o.NamespaceName, o.ResourceFilter)
}
return strings.NewReplacer("$1", workloadSelector, "$2", kindSelector).Replace(tmpl)
} }
func makePodMetricExpr(tmpl string, o QueryOptions) string { func makePodMetricExpr(tmpl string, o QueryOptions) string {
@ -365,26 +345,16 @@ func makePodMetricExpr(tmpl string, o QueryOptions) string {
// For monitoriong pods of the specific workload // For monitoriong pods of the specific workload
// GET /namespaces/{namespace}/workloads/{kind}/{workload}/pods // GET /namespaces/{namespace}/workloads/{kind}/{workload}/pods
if o.WorkloadName != "" {
switch o.WorkloadKind {
case "deployment":
workloadSelector = fmt.Sprintf(`owner_kind="ReplicaSet", owner_name=~"^%s-[^-]{1,10}$"`, o.WorkloadName)
case "statefulset":
workloadSelector = fmt.Sprintf(`owner_kind="StatefulSet", owner_name="%s"`, o.WorkloadName)
case "daemonset":
workloadSelector = fmt.Sprintf(`owner_kind="DaemonSet", owner_name="%s"`, o.WorkloadName)
}
}
// For monitoring pods in the specific namespace // For monitoring pods in the specific namespace
// GET /namespaces/{namespace}/workloads/{kind}/{workload}/pods or // GET /namespaces/{namespace}/workloads/{kind}/{workload}/pods or
// GET /namespaces/{namespace}/pods/{pod} or // GET /namespaces/{namespace}/pods/{pod} or
// GET /namespaces/{namespace}/pods // GET /namespaces/{namespace}/pods
if o.NamespaceName != "" { if o.Namespace != "" {
if o.PodName != "" { if o.PodName != "" {
podSelector = fmt.Sprintf(`pod="%s", namespace="%s"`, o.PodName, o.NamespaceName) podSelector = fmt.Sprintf(`pod="%s", namespace="%s"`, o.PodName, o.Namespace)
} else { } else {
podSelector = fmt.Sprintf(`pod=~"%s", namespace="%s"`, o.ResourceFilter, o.NamespaceName) podSelector = fmt.Sprintf(`pod=~"%s", namespace="%s"`, o.ResourceFilter, o.Namespace)
} }
} else { } else {
var namespaces, pods []string var namespaces, pods []string
@ -445,9 +415,9 @@ func makePodMetricExpr(tmpl string, o QueryOptions) string {
func makeContainerMetricExpr(tmpl string, o QueryOptions) string { func makeContainerMetricExpr(tmpl string, o QueryOptions) string {
var containerSelector string var containerSelector string
if o.ContainerName != "" { if o.ContainerName != "" {
containerSelector = fmt.Sprintf(`pod="%s", namespace="%s", container="%s"`, o.PodName, o.NamespaceName, o.ContainerName) containerSelector = fmt.Sprintf(`pod="%s", namespace="%s", container="%s"`, o.PodName, o.Namespace, o.ContainerName)
} else { } else {
containerSelector = fmt.Sprintf(`pod="%s", namespace="%s", container=~"%s"`, o.PodName, o.NamespaceName, o.ResourceFilter) containerSelector = fmt.Sprintf(`pod="%s", namespace="%s", container=~"%s"`, o.PodName, o.Namespace, o.ResourceFilter)
} }
return strings.Replace(tmpl, "$1", containerSelector, -1) return strings.Replace(tmpl, "$1", containerSelector, -1)
} }
@ -458,11 +428,11 @@ func makePVCMetricExpr(tmpl string, o QueryOptions) string {
// For monitoring persistentvolumeclaims in the specific namespace // For monitoring persistentvolumeclaims in the specific namespace
// GET /namespaces/{namespace}/persistentvolumeclaims/{persistentvolumeclaim} or // GET /namespaces/{namespace}/persistentvolumeclaims/{persistentvolumeclaim} or
// GET /namespaces/{namespace}/persistentvolumeclaims // GET /namespaces/{namespace}/persistentvolumeclaims
if o.NamespaceName != "" { if o.Namespace != "" {
if o.PersistentVolumeClaimName != "" { if o.PersistentVolumeClaimName != "" {
pvcSelector = fmt.Sprintf(`namespace="%s", persistentvolumeclaim="%s"`, o.NamespaceName, o.PersistentVolumeClaimName) pvcSelector = fmt.Sprintf(`namespace="%s", persistentvolumeclaim="%s"`, o.Namespace, o.PersistentVolumeClaimName)
} else { } else {
pvcSelector = fmt.Sprintf(`namespace="%s", persistentvolumeclaim=~"%s"`, o.NamespaceName, o.ResourceFilter) pvcSelector = fmt.Sprintf(`namespace="%s", persistentvolumeclaim=~"%s"`, o.Namespace, o.ResourceFilter)
} }
return strings.Replace(tmpl, "$1", pvcSelector, -1) return strings.Replace(tmpl, "$1", pvcSelector, -1)
} }

View File

@ -29,7 +29,7 @@ const (
LevelNamespace LevelNamespace
LevelApplication LevelApplication
LevelOpenpitrix LevelOpenpitrix
LevelWorkload LevelController
LevelService LevelService
LevelPod LevelPod
LevelContainer LevelContainer
@ -44,7 +44,7 @@ var MeteringLevelMap = map[string]int{
"LevelWorkspace": LevelWorkspace, "LevelWorkspace": LevelWorkspace,
"LevelNamespace": LevelNamespace, "LevelNamespace": LevelNamespace,
"LevelApplication": LevelApplication, "LevelApplication": LevelApplication,
"LevelWorkload": LevelWorkload, "LevelController": LevelController,
"LevelService": LevelService, "LevelService": LevelService,
"LevelPod": LevelPod, "LevelPod": LevelPod,
"LevelContainer": LevelContainer, "LevelContainer": LevelContainer,
@ -70,10 +70,11 @@ type QueryOptions struct {
ResourceFilter string ResourceFilter string
NodeName string NodeName string
WorkspaceName string WorkspaceName string
NamespaceName string Namespace string
WorkloadKind string WorkloadKind string
WorkloadName string OwnerName string
PodName string PodName string
PodsName string
ContainerName string ContainerName string
StorageClassName string StorageClassName string
PersistentVolumeClaimName string PersistentVolumeClaimName string
@ -140,7 +141,7 @@ func (no NamespaceOption) Apply(o *QueryOptions) {
o.Level = LevelNamespace o.Level = LevelNamespace
o.ResourceFilter = no.ResourceFilter o.ResourceFilter = no.ResourceFilter
o.WorkspaceName = no.WorkspaceName o.WorkspaceName = no.WorkspaceName
o.NamespaceName = no.NamespaceName o.Namespace = no.NamespaceName
o.PVCFilter = no.PVCFilter o.PVCFilter = no.PVCFilter
o.StorageClassName = no.StorageClassName o.StorageClassName = no.StorageClassName
} }
@ -180,16 +181,16 @@ type ApplicationOption struct {
func (ao ApplicationOption) Apply(o *QueryOptions) { func (ao ApplicationOption) Apply(o *QueryOptions) {
o.Level = LevelApplication o.Level = LevelApplication
o.NamespaceName = ao.NamespaceName o.Namespace = ao.NamespaceName
o.ApplicationName = ao.Application o.ApplicationName = ao.Application
o.StorageClassName = ao.StorageClassName o.StorageClassName = ao.StorageClassName
app_components := strings.Join(ao.ApplicationComponents[:], "|") app_components := strings.Join(ao.ApplicationComponents[:], "|")
if len(app_components) > 0 { if len(app_components) > 0 {
o.ResourceFilter = fmt.Sprintf(`namespace="%s", workload=~"%s"`, o.NamespaceName, app_components) o.ResourceFilter = fmt.Sprintf(`namespace="%s", workload=~"%s"`, o.Namespace, app_components)
} else { } else {
o.ResourceFilter = fmt.Sprintf(`namespace="%s", workload=~"%s"`, o.NamespaceName, ".*") o.ResourceFilter = fmt.Sprintf(`namespace="%s", workload=~"%s"`, o.Namespace, ".*")
} }
} }
@ -200,9 +201,9 @@ type WorkloadOption struct {
} }
func (wo WorkloadOption) Apply(o *QueryOptions) { func (wo WorkloadOption) Apply(o *QueryOptions) {
o.Level = LevelWorkload o.Level = LevelController
o.ResourceFilter = wo.ResourceFilter o.ResourceFilter = wo.ResourceFilter
o.NamespaceName = wo.NamespaceName o.Namespace = wo.NamespaceName
o.WorkloadKind = wo.WorkloadKind o.WorkloadKind = wo.WorkloadKind
} }
@ -226,15 +227,15 @@ type ServiceOption struct {
func (so ServiceOption) Apply(o *QueryOptions) { func (so ServiceOption) Apply(o *QueryOptions) {
o.Level = LevelService o.Level = LevelService
o.NamespaceName = so.NamespaceName o.Namespace = so.NamespaceName
o.ServiceName = so.ServiceName o.ServiceName = so.ServiceName
pod_names := strings.Join(so.PodNames, "|") pod_names := strings.Join(so.PodNames, "|")
if len(pod_names) > 0 { if len(pod_names) > 0 {
o.ResourceFilter = fmt.Sprintf(`pod=~"%s", namespace="%s"`, pod_names, o.NamespaceName) o.ResourceFilter = fmt.Sprintf(`pod=~"%s", namespace="%s"`, pod_names, o.Namespace)
} else { } else {
o.ResourceFilter = fmt.Sprintf(`pod=~"%s", namespace="%s"`, ".*", o.NamespaceName) o.ResourceFilter = fmt.Sprintf(`pod=~"%s", namespace="%s"`, ".*", o.Namespace)
} }
} }
@ -248,17 +249,33 @@ type PodOption struct {
PodName string PodName string
} }
type ControllerOption struct {
PodsName string
Namespace string
Kind string
OwnerName string
}
func (po PodOption) Apply(o *QueryOptions) { func (po PodOption) Apply(o *QueryOptions) {
o.Level = LevelPod o.Level = LevelPod
o.NamespacedResourcesFilter = po.NamespacedResourcesFilter o.NamespacedResourcesFilter = po.NamespacedResourcesFilter
o.ResourceFilter = po.ResourceFilter o.ResourceFilter = po.ResourceFilter
o.NodeName = po.NodeName o.NodeName = po.NodeName
o.NamespaceName = po.NamespaceName o.Namespace = po.NamespaceName
o.WorkloadKind = po.WorkloadKind o.WorkloadKind = po.WorkloadKind
o.WorkloadName = po.WorkloadName o.OwnerName = po.WorkloadName
o.PodName = po.PodName o.PodName = po.PodName
} }
func (co ControllerOption) Apply(o *QueryOptions) {
o.Level = LevelController
o.Namespace = co.Namespace
o.WorkloadKind = co.Kind
o.OwnerName = co.OwnerName
o.PodName = co.PodsName
}
type ContainerOption struct { type ContainerOption struct {
ResourceFilter string ResourceFilter string
NamespaceName string NamespaceName string
@ -269,7 +286,7 @@ type ContainerOption struct {
func (co ContainerOption) Apply(o *QueryOptions) { func (co ContainerOption) Apply(o *QueryOptions) {
o.Level = LevelContainer o.Level = LevelContainer
o.ResourceFilter = co.ResourceFilter o.ResourceFilter = co.ResourceFilter
o.NamespaceName = co.NamespaceName o.Namespace = co.NamespaceName
o.PodName = co.PodName o.PodName = co.PodName
o.ContainerName = co.ContainerName o.ContainerName = co.ContainerName
} }
@ -284,7 +301,7 @@ type PVCOption struct {
func (po PVCOption) Apply(o *QueryOptions) { func (po PVCOption) Apply(o *QueryOptions) {
o.Level = LevelPVC o.Level = LevelPVC
o.ResourceFilter = po.ResourceFilter o.ResourceFilter = po.ResourceFilter
o.NamespaceName = po.NamespaceName o.Namespace = po.NamespaceName
o.StorageClassName = po.StorageClassName o.StorageClassName = po.StorageClassName
o.PersistentVolumeClaimName = po.PersistentVolumeClaimName o.PersistentVolumeClaimName = po.PersistentVolumeClaimName
@ -304,7 +321,7 @@ type IngressOption struct {
func (no IngressOption) Apply(o *QueryOptions) { func (no IngressOption) Apply(o *QueryOptions) {
o.Level = LevelIngress o.Level = LevelIngress
o.ResourceFilter = no.ResourceFilter o.ResourceFilter = no.ResourceFilter
o.NamespaceName = no.NamespaceName o.Namespace = no.NamespaceName
o.Ingress = no.Ingress o.Ingress = no.Ingress
o.Job = no.Job o.Job = no.Job
o.PodName = no.Pod o.PodName = no.Pod

View File

@ -19,26 +19,109 @@ import (
"github.com/prometheus/client_golang/api" "github.com/prometheus/client_golang/api"
v1 "github.com/prometheus/client_golang/api/prometheus/v1" v1 "github.com/prometheus/client_golang/api/prometheus/v1"
"github.com/prometheus/common/model" "github.com/prometheus/common/model"
"strconv"
"strings" "strings"
"sync" "sync"
"time" "time"
) )
type prometheus struct { type Prometheus struct {
client v1.API prometheus Interface
client v1.API
} }
// NewPrometheus 初始化Prometheus客户端 // NewPrometheus 初始化Prometheus客户端
func NewPrometheus(address string) (Interface, error) { func NewPrometheus(address string) (Prometheus, error) {
cfg := api.Config{ cfg := api.Config{
Address: address, Address: address,
} }
client, err := api.NewClient(cfg) client, err := api.NewClient(cfg)
return prometheus{client: v1.NewAPI(client)}, err return Prometheus{client: v1.NewAPI(client)}, err
} }
func (p prometheus) GetNamedMetrics(metrics []string, ts time.Time, o QueryOption) []Metric { func ParseTime(timestamp string) (time.Time, error) {
// Parse time params
startInt, err := strconv.ParseInt(timestamp, 10, 64)
if err != nil {
return time.Now(), err
}
return time.Unix(startInt, 0), nil
}
func (p Prometheus) GetNamedMetricsByTime(metrics []string, start, end string, step time.Duration, o QueryOption) []Metric {
var res []Metric
var mtx sync.Mutex
var wg sync.WaitGroup
opts := NewQueryOptions()
o.Apply(opts)
for _, metric := range metrics {
wg.Add(1)
go func(metric string) {
parsedResp := Metric{MetricName: metric}
startTimestamp, err := ParseTime(start)
if err != nil {
return
}
endTimestamp, err := ParseTime(end)
if err != nil {
return
}
timeRange := v1.Range{
Start: startTimestamp,
End: endTimestamp,
Step: step,
}
value, _, err := p.client.QueryRange(context.Background(), makeExpr(metric, *opts), timeRange)
if err != nil {
parsedResp.Error = err.Error()
} else {
parsedResp.MetricData = parseQueryRangeResp(value, genMetricFilter(o))
}
mtx.Lock()
res = append(res, parsedResp)
mtx.Unlock()
wg.Done()
}(metric)
}
wg.Wait()
return res
}
func parseQueryRangeResp(value model.Value, metricFilter func(metric model.Metric) bool) MetricData {
res := MetricData{MetricType: MetricTypeMatrix}
data, _ := value.(model.Matrix)
for _, v := range data {
if metricFilter != nil && !metricFilter(v.Metric) {
continue
}
mv := MetricValue{
Metadata: make(map[string]string),
}
for k, v := range v.Metric {
mv.Metadata[string(k)] = string(v)
}
for _, k := range v.Values {
mv.Series = append(mv.Series, Point{float64(k.Timestamp) / 1000, float64(k.Value)})
}
res.MetricValues = append(res.MetricValues, mv)
}
return res
}
func (p Prometheus) GetNamedMetrics(metrics []string, ts time.Time, o QueryOption) []Metric {
var res []Metric var res []Metric
var mtx sync.Mutex var mtx sync.Mutex
var wg sync.WaitGroup var wg sync.WaitGroup

View File

@ -20,12 +20,18 @@ import (
) )
func TestGetNamedMetrics(t *testing.T) { func TestGetNamedMetrics(t *testing.T) {
client, _ := NewPrometheus("http://10.101.15.3:32585") //client, _ := NewPrometheus("http://10.101.15.3:32585")
result := client.GetNamedMetrics([]string{"pod_cpu_resource_limits"}, time.Now(), PodOption{ //result := client.GetNamedMetrics([]string{"pod_cpu_resource_limits"}, time.Now(), PodOption{
//
// PodName: "prometheus-k8s-0",
// NamespaceName: "monitoring-system",
//})
//println("zzz", result[0].MetricValues[0].Sample.Value())
PodName: "prometheus-k8s-0", client, _ := NewPrometheus("http://10.105.20.4:30766")
NamespaceName: "monitoring-system", result := client.GetNamedMetricsByTime([]string{"pod_cpu_usage", "pod_memory_usage_wo_cache"}, "1700521446", "1700551446", 10*time.Minute, ControllerOption{
PodsName: "notification-manager-deployment-78664576cb-vkptn|notification-manager-deployment-78664576cb-5m6mt",
Namespace: "kubesphere-monitoring-system",
}) })
println("zzz", result[0].MetricValues[0].Sample.Value()) println("zzz", result)
} }