diff --git a/cmd/collectors/restperf/restperf.go b/cmd/collectors/restperf/restperf.go index 74fa003cb..feabed9d3 100644 --- a/cmd/collectors/restperf/restperf.go +++ b/cmd/collectors/restperf/restperf.go @@ -25,6 +25,7 @@ import ( "github.com/rs/zerolog" "github.com/tidwall/gjson" "path" + "regexp" "strconv" "strings" "time" @@ -38,6 +39,10 @@ const ( objWorkloadVolumeClass = "autovolume" ) +var ( + constituentRegex = regexp.MustCompile(`^(.*)__(\d{4})$`) +) + var qosQuery = "api/cluster/counter/tables/qos" var qosVolumeQuery = "api/cluster/counter/tables/qos_volume" var qosDetailQuery = "api/cluster/counter/tables/qos_detail" @@ -69,10 +74,11 @@ type counter struct { } type perfProp struct { - isCacheEmpty bool - counterInfo map[string]*counter - latencyIoReqd int - qosLabels map[string]string + isCacheEmpty bool + counterInfo map[string]*counter + latencyIoReqd int + qosLabels map[string]string + disableConstituents bool } type metricResponse struct { @@ -126,7 +132,7 @@ func (r *RestPerf) Init(a *collector.AbstractCollector) error { return err } - if err = r.InitQOSLabels(); err != nil { + if err = r.InitQOS(); err != nil { return err } @@ -137,7 +143,7 @@ func (r *RestPerf) Init(a *collector.AbstractCollector) error { return nil } -func (r *RestPerf) InitQOSLabels() error { +func (r *RestPerf) InitQOS() error { if isWorkloadObject(r.Prop.Query) || isWorkloadDetailObject(r.Prop.Query) { qosLabels := r.Params.GetChildS("qos_labels") if qosLabels == nil { @@ -155,6 +161,15 @@ func (r *RestPerf) InitQOSLabels() error { r.perfProp.qosLabels[label] = display } } + if counters := r.Params.GetChildS("counters"); counters != nil { + refine := counters.GetChildS("refine") + if refine != nil { + withConstituents := refine.GetChildContentS("with_constituents") + if withConstituents == "false" { + r.perfProp.disableConstituents = true + } + } + } return nil } @@ -1411,6 +1426,7 @@ func (r *RestPerf) pollInstance(records []gjson.Result, apiD time.Duration) (map if len(records) == 0 { return nil, errs.New(errs.ErrNoInstance, "no "+r.Object+" instances on cluster") } + for _, instanceData := range records { var ( instanceKey string @@ -1421,6 +1437,17 @@ func (r *RestPerf) pollInstance(records []gjson.Result, apiD time.Duration) (map continue } + if isWorkloadObject(r.Prop.Query) || isWorkloadDetailObject(r.Prop.Query) { + // The API endpoint api/storage/qos/workloads lacks an is_constituent filter, unlike qos-workload-get-iter. As a result, we must perform client-side filtering. + // Although the api/private/cli/qos/workload endpoint includes this filter, it doesn't provide an option to fetch all records, both constituent and flexgroup types. + if r.perfProp.disableConstituents { + if constituentRegex.MatchString(instanceData.Get("volume").String()) { + // skip constituent + continue + } + } + } + // extract instance key(s) for _, k := range instanceKeys { var value gjson.Result diff --git a/cmd/collectors/zapiperf/zapiperf.go b/cmd/collectors/zapiperf/zapiperf.go index fce2295df..7d0156159 100644 --- a/cmd/collectors/zapiperf/zapiperf.go +++ b/cmd/collectors/zapiperf/zapiperf.go @@ -282,7 +282,9 @@ func (z *ZapiPerf) loadWorkloadClassQuery(defaultValue string) string { func (z *ZapiPerf) updateWorkloadQuery(query *node.Node) { // filter -> workload-class takes precedence over workload_class param at root level + // filter -> is-constituent takes precedence over refine -> with_constituents workloadClass := "" + isConstituent := "" counters := z.Params.GetChildS("counters") if counters != nil { filter := counters.GetChildS("filter") @@ -294,20 +296,32 @@ func (z *ZapiPerf) updateWorkloadQuery(query *node.Node) { if name == "workload-class" { workloadClass = content } + if name == "is-constituent" { + isConstituent = content + } } } } - if workloadClass != "" { - return + if workloadClass == "" { + var workloadClassQuery string + if z.Query == objWorkloadVolume || z.Query == objWorkloadDetailVolume { + workloadClassQuery = z.loadWorkloadClassQuery(objWorkloadVolumeClass) + } else { + workloadClassQuery = z.loadWorkloadClassQuery(objWorkloadClass) + } + query.NewChildS("workload-class", workloadClassQuery) } - - var workloadClassQuery string - if z.Query == objWorkloadVolume || z.Query == objWorkloadDetailVolume { - workloadClassQuery = z.loadWorkloadClassQuery(objWorkloadVolumeClass) - } else { - workloadClassQuery = z.loadWorkloadClassQuery(objWorkloadClass) + if isConstituent == "" { + if counters != nil { + refine := counters.GetChildS("refine") + if refine != nil { + isConstituent = refine.GetChildContentS("with_constituents") + if isConstituent == "false" { + query.NewChildS("is-constituent", isConstituent) + } + } + } } - query.NewChildS("workload-class", workloadClassQuery) } // load an int parameter or use defaultValue diff --git a/conf/restperf/9.12.0/workload_detail.yaml b/conf/restperf/9.12.0/workload_detail.yaml index 823e2a579..148921f5b 100644 --- a/conf/restperf/9.12.0/workload_detail.yaml +++ b/conf/restperf/9.12.0/workload_detail.yaml @@ -15,10 +15,11 @@ schedule: counters: - ^^id - - ^node.name => node - service_time - visits - wait_time + - refine: + - with_constituents: false # The possible values are true or false. Setting this to true will include constituents in the results, while false will exclude them. resource_map: CPU_dblade: backend diff --git a/conf/restperf/9.12.0/workload_detail_volume.yaml b/conf/restperf/9.12.0/workload_detail_volume.yaml index 0f542aada..ee48165db 100644 --- a/conf/restperf/9.12.0/workload_detail_volume.yaml +++ b/conf/restperf/9.12.0/workload_detail_volume.yaml @@ -17,6 +17,8 @@ counters: - service_time - visits - wait_time + - refine: + - with_constituents: false # The possible values are true or false. Setting this to true will include constituents in the results, while false will exclude them. resource_map: CPU_dblade : backend diff --git a/conf/zapiperf/cdot/9.8.0/workload_detail.yaml b/conf/zapiperf/cdot/9.8.0/workload_detail.yaml index 59cf7ccab..6a0ff5b33 100644 --- a/conf/zapiperf/cdot/9.8.0/workload_detail.yaml +++ b/conf/zapiperf/cdot/9.8.0/workload_detail.yaml @@ -21,6 +21,8 @@ counters: - service_time - visits - wait_time + - refine: + - with_constituents: false # The possible values are true or false. Setting this to true will include constituents in the results, while false will exclude them. resource_map: CPU_dblade: backend diff --git a/conf/zapiperf/cdot/9.8.0/workload_detail_volume.yaml b/conf/zapiperf/cdot/9.8.0/workload_detail_volume.yaml index f75c6d225..38cdf866b 100644 --- a/conf/zapiperf/cdot/9.8.0/workload_detail_volume.yaml +++ b/conf/zapiperf/cdot/9.8.0/workload_detail_volume.yaml @@ -20,6 +20,8 @@ counters: - service_time - visits - wait_time + - refine: + - with_constituents: false # The possible values are true or false. Setting this to true will include constituents in the results, while false will exclude them. resource_map: CPU_dblade : backend