From 7d13cd17656d482e11d279d01f00493f048694f6 Mon Sep 17 00:00:00 2001 From: Evan Vokey <49615340+Evan-Vokey@users.noreply.github.com> Date: Sun, 9 Jul 2023 14:21:32 -0230 Subject: [PATCH] Add users and groups mmrepquota (#59) * added users and groups to mmrepquota * modified tests for mmrepquota to include users and groups * added documentation to README.md for collector.mmrepquota.quotatypes flag Co-authored-by: treydock --- README.md | 1 + collectors/mmrepquota.go | 239 ++++++++++++++++++++++++++-------- collectors/mmrepquota_test.go | 226 +++++++++++++++++++++++++++++++- 3 files changed, 406 insertions(+), 60 deletions(-) diff --git a/README.md b/README.md index 06dc6cd..74cc37f 100644 --- a/README.md +++ b/README.md @@ -61,6 +61,7 @@ The default is FQDN of those running the exporter. ### mmrepquota * `--collector.mmrepquota.filesystems` - A comma separated list of filesystems to collect. Default is to collect all filesystems. +* `--collector.mmrepquota.quota-types` - Comma seperated list of filesystem types to collect (`fileset` for FILESET, `user` for USR, `group` for GRP). Default is FILESET only. Ex: `fileset,user` collects FILESET and USR. ### mmlssnapshot diff --git a/collectors/mmrepquota.go b/collectors/mmrepquota.go index 05cb4fe..cabb576 100644 --- a/collectors/mmrepquota.go +++ b/collectors/mmrepquota.go @@ -16,6 +16,7 @@ package collectors import ( "bytes" "context" + "fmt" "reflect" "strconv" "strings" @@ -29,10 +30,12 @@ import ( var ( configMmrepquotaFilesystems = kingpin.Flag("collector.mmrepquota.filesystems", "Filesystems to query with mmrepquota, comma separated. Defaults to all filesystems.").Default("").String() + configMmrepquotaTypes = kingpin.Flag("collector.mmrepquota.quota-types", "Quota Types to query with mmrepquota, Default to fileset only").Default("fileset").String() mmrepquotaTimeout = kingpin.Flag("collector.mmrepquota.timeout", "Timeout for mmrepquota execution").Default("20").Int() quotaMap = map[string]string{ "name": "Name", "filesystemName": "FS", + "quotaType": "QuotaType", "blockUsage": "BlockUsage", "blockQuota": "BlockQuota", "blockLimit": "BlockLimit", @@ -42,12 +45,18 @@ var ( "filesLimit": "FilesLimit", "filesInDoubt": "FilesInDoubt", } + quotaTypeMap = map[string]rune{ + "user": 'u', + "group": 'g', + "fileset": 'j', + } mmrepquotaExec = mmrepquota ) type QuotaMetric struct { Name string FS string + QuotaType string BlockUsage float64 BlockQuota float64 BlockLimit float64 @@ -59,15 +68,39 @@ type QuotaMetric struct { } type MmrepquotaCollector struct { - BlockUsage *prometheus.Desc - BlockQuota *prometheus.Desc - BlockLimit *prometheus.Desc - BlockInDoubt *prometheus.Desc - FilesUsage *prometheus.Desc - FilesQuota *prometheus.Desc - FilesLimit *prometheus.Desc - FilesInDoubt *prometheus.Desc - logger log.Logger + FilesetBlockUsage *prometheus.Desc + FilesetBlockQuota *prometheus.Desc + FilesetBlockLimit *prometheus.Desc + FilesetBlockInDoubt *prometheus.Desc + FilesetFilesUsage *prometheus.Desc + FilesetFilesQuota *prometheus.Desc + FilesetFilesLimit *prometheus.Desc + FilesetFilesInDoubt *prometheus.Desc + + UserBlockUsage *prometheus.Desc + UserBlockQuota *prometheus.Desc + UserBlockLimit *prometheus.Desc + UserBlockInDoubt *prometheus.Desc + UserFilesUsage *prometheus.Desc + UserFilesQuota *prometheus.Desc + UserFilesLimit *prometheus.Desc + UserFilesInDoubt *prometheus.Desc + + GroupBlockUsage *prometheus.Desc + GroupBlockQuota *prometheus.Desc + GroupBlockLimit *prometheus.Desc + GroupBlockInDoubt *prometheus.Desc + GroupFilesUsage *prometheus.Desc + GroupFilesQuota *prometheus.Desc + GroupFilesLimit *prometheus.Desc + GroupFilesInDoubt *prometheus.Desc + + logger log.Logger +} + +type MetricCollectionResult struct { + Result []QuotaMetric + Error error } func init() { @@ -75,37 +108,92 @@ func init() { } func NewMmrepquotaCollector(logger log.Logger) Collector { - labels := []string{"fileset", "fs"} + fileset_labels := []string{"fileset", "fs"} + user_labels := []string{"user", "fs"} + group_labels := []string{"group", "fs"} return &MmrepquotaCollector{ - BlockUsage: prometheus.NewDesc(prometheus.BuildFQName(namespace, "fileset", "used_bytes"), - "GPFS fileset quota used", labels, nil), - BlockQuota: prometheus.NewDesc(prometheus.BuildFQName(namespace, "fileset", "quota_bytes"), - "GPFS fileset block quota", labels, nil), - BlockLimit: prometheus.NewDesc(prometheus.BuildFQName(namespace, "fileset", "limit_bytes"), - "GPFS fileset quota block limit", labels, nil), - BlockInDoubt: prometheus.NewDesc(prometheus.BuildFQName(namespace, "fileset", "in_doubt_bytes"), - "GPFS fileset quota block in doubt", labels, nil), - FilesUsage: prometheus.NewDesc(prometheus.BuildFQName(namespace, "fileset", "used_files"), - "GPFS fileset quota files used", labels, nil), - FilesQuota: prometheus.NewDesc(prometheus.BuildFQName(namespace, "fileset", "quota_files"), - "GPFS fileset files quota", labels, nil), - FilesLimit: prometheus.NewDesc(prometheus.BuildFQName(namespace, "fileset", "limit_files"), - "GPFS fileset quota files limit", labels, nil), - FilesInDoubt: prometheus.NewDesc(prometheus.BuildFQName(namespace, "fileset", "in_doubt_files"), - "GPFS fileset quota files in doubt", labels, nil), + FilesetBlockUsage: prometheus.NewDesc(prometheus.BuildFQName(namespace, "fileset", "used_bytes"), + "GPFS fileset quota used", fileset_labels, nil), + FilesetBlockQuota: prometheus.NewDesc(prometheus.BuildFQName(namespace, "fileset", "quota_bytes"), + "GPFS fileset block quota", fileset_labels, nil), + FilesetBlockLimit: prometheus.NewDesc(prometheus.BuildFQName(namespace, "fileset", "limit_bytes"), + "GPFS fileset quota block limit", fileset_labels, nil), + FilesetBlockInDoubt: prometheus.NewDesc(prometheus.BuildFQName(namespace, "fileset", "in_doubt_bytes"), + "GPFS fileset quota block in doubt", fileset_labels, nil), + FilesetFilesUsage: prometheus.NewDesc(prometheus.BuildFQName(namespace, "fileset", "used_files"), + "GPFS fileset quota files used", fileset_labels, nil), + FilesetFilesQuota: prometheus.NewDesc(prometheus.BuildFQName(namespace, "fileset", "quota_files"), + "GPFS fileset files quota", fileset_labels, nil), + FilesetFilesLimit: prometheus.NewDesc(prometheus.BuildFQName(namespace, "fileset", "limit_files"), + "GPFS fileset quota files limit", fileset_labels, nil), + FilesetFilesInDoubt: prometheus.NewDesc(prometheus.BuildFQName(namespace, "fileset", "in_doubt_files"), + "GPFS fileset quota files in doubt", fileset_labels, nil), + + UserBlockUsage: prometheus.NewDesc(prometheus.BuildFQName(namespace, "user", "used_bytes"), + "GPFS user quota used", user_labels, nil), + UserBlockQuota: prometheus.NewDesc(prometheus.BuildFQName(namespace, "user", "quota_bytes"), + "GPFS user block quota", user_labels, nil), + UserBlockLimit: prometheus.NewDesc(prometheus.BuildFQName(namespace, "user", "limit_bytes"), + "GPFS user quota block limit", user_labels, nil), + UserBlockInDoubt: prometheus.NewDesc(prometheus.BuildFQName(namespace, "user", "in_doubt_bytes"), + "GPFS user quota block in doubt", user_labels, nil), + UserFilesUsage: prometheus.NewDesc(prometheus.BuildFQName(namespace, "user", "used_files"), + "GPFS user quota files used", user_labels, nil), + UserFilesQuota: prometheus.NewDesc(prometheus.BuildFQName(namespace, "user", "quota_files"), + "GPFS user files quota", user_labels, nil), + UserFilesLimit: prometheus.NewDesc(prometheus.BuildFQName(namespace, "user", "limit_files"), + "GPFS user quota files limit", user_labels, nil), + UserFilesInDoubt: prometheus.NewDesc(prometheus.BuildFQName(namespace, "user", "in_doubt_files"), + "GPFS user quota files in doubt", user_labels, nil), + + GroupBlockUsage: prometheus.NewDesc(prometheus.BuildFQName(namespace, "group", "used_bytes"), + "GPFS group quota used", group_labels, nil), + GroupBlockQuota: prometheus.NewDesc(prometheus.BuildFQName(namespace, "group", "quota_bytes"), + "GPFS group block quota", group_labels, nil), + GroupBlockLimit: prometheus.NewDesc(prometheus.BuildFQName(namespace, "group", "limit_bytes"), + "GPFS group quota block limit", group_labels, nil), + GroupBlockInDoubt: prometheus.NewDesc(prometheus.BuildFQName(namespace, "group", "in_doubt_bytes"), + "GPFS group quota block in doubt", group_labels, nil), + GroupFilesUsage: prometheus.NewDesc(prometheus.BuildFQName(namespace, "group", "used_files"), + "GPFS group quota files used", group_labels, nil), + GroupFilesQuota: prometheus.NewDesc(prometheus.BuildFQName(namespace, "group", "quota_files"), + "GPFS group files quota", group_labels, nil), + GroupFilesLimit: prometheus.NewDesc(prometheus.BuildFQName(namespace, "group", "limit_files"), + "GPFS group quota files limit", group_labels, nil), + GroupFilesInDoubt: prometheus.NewDesc(prometheus.BuildFQName(namespace, "group", "in_doubt_files"), + "GPFS group quota files in doubt", group_labels, nil), + logger: logger, } } func (c *MmrepquotaCollector) Describe(ch chan<- *prometheus.Desc) { - ch <- c.BlockUsage - ch <- c.BlockQuota - ch <- c.BlockLimit - ch <- c.BlockInDoubt - ch <- c.FilesUsage - ch <- c.FilesQuota - ch <- c.FilesLimit - ch <- c.FilesInDoubt + ch <- c.FilesetBlockUsage + ch <- c.FilesetBlockQuota + ch <- c.FilesetBlockLimit + ch <- c.FilesetBlockInDoubt + ch <- c.FilesetFilesUsage + ch <- c.FilesetFilesQuota + ch <- c.FilesetFilesLimit + ch <- c.FilesetFilesInDoubt + + ch <- c.UserBlockUsage + ch <- c.UserBlockQuota + ch <- c.UserBlockLimit + ch <- c.UserBlockInDoubt + ch <- c.UserFilesUsage + ch <- c.UserFilesQuota + ch <- c.UserFilesLimit + ch <- c.UserFilesInDoubt + + ch <- c.GroupBlockUsage + ch <- c.GroupBlockQuota + ch <- c.GroupBlockLimit + ch <- c.GroupBlockInDoubt + ch <- c.GroupFilesUsage + ch <- c.GroupFilesQuota + ch <- c.GroupFilesLimit + ch <- c.GroupFilesInDoubt } func (c *MmrepquotaCollector) Collect(ch chan<- prometheus.Metric) { @@ -113,34 +201,77 @@ func (c *MmrepquotaCollector) Collect(ch chan<- prometheus.Metric) { collectTime := time.Now() timeout := 0 errorMetric := 0 - metrics, err := c.collect() - if err == context.DeadlineExceeded { - timeout = 1 - level.Error(c.logger).Log("msg", "Timeout executing mmrepquota") - } else if err != nil { - level.Error(c.logger).Log("msg", err) - errorMetric = 1 + metrics := []QuotaMetric{} + + typesToCollect := strings.Split(*configMmrepquotaTypes, ",") + + results := make(chan MetricCollectionResult, len(typesToCollect)-1) + + for _, quotaType := range typesToCollect { + quotaType = strings.TrimSpace(quotaType) + quotaArg := quotaTypeMap[quotaType] + + // Collect quota types concurrently, place metrics on results channel as MetricCollectionResult + go func(quotaArg rune) { + metric, err := c.collect(fmt.Sprintf("-%c", quotaArg)) + results <- MetricCollectionResult{Result: metric, Error: err} + }(quotaArg) + } + + // merge metrics from results channel + for range typesToCollect { + result := <-results + metrics = append(metrics, result.Result...) + + err := result.Error + if err == context.DeadlineExceeded { + timeout = 1 + level.Error(c.logger).Log("msg", "Timeout executing mmrepquota") + } else if err != nil { + level.Error(c.logger).Log("msg", err) + errorMetric = 1 + } } for _, m := range metrics { - ch <- prometheus.MustNewConstMetric(c.BlockUsage, prometheus.GaugeValue, m.BlockUsage, m.Name, m.FS) - ch <- prometheus.MustNewConstMetric(c.BlockQuota, prometheus.GaugeValue, m.BlockQuota, m.Name, m.FS) - ch <- prometheus.MustNewConstMetric(c.BlockLimit, prometheus.GaugeValue, m.BlockLimit, m.Name, m.FS) - ch <- prometheus.MustNewConstMetric(c.BlockInDoubt, prometheus.GaugeValue, m.BlockInDoubt, m.Name, m.FS) - ch <- prometheus.MustNewConstMetric(c.FilesUsage, prometheus.GaugeValue, m.FilesUsage, m.Name, m.FS) - ch <- prometheus.MustNewConstMetric(c.FilesQuota, prometheus.GaugeValue, m.FilesQuota, m.Name, m.FS) - ch <- prometheus.MustNewConstMetric(c.FilesLimit, prometheus.GaugeValue, m.FilesLimit, m.Name, m.FS) - ch <- prometheus.MustNewConstMetric(c.FilesInDoubt, prometheus.GaugeValue, m.FilesInDoubt, m.Name, m.FS) + if m.QuotaType == "FILESET" { + ch <- prometheus.MustNewConstMetric(c.FilesetBlockUsage, prometheus.GaugeValue, m.BlockUsage, m.Name, m.FS) + ch <- prometheus.MustNewConstMetric(c.FilesetBlockQuota, prometheus.GaugeValue, m.BlockQuota, m.Name, m.FS) + ch <- prometheus.MustNewConstMetric(c.FilesetBlockLimit, prometheus.GaugeValue, m.BlockLimit, m.Name, m.FS) + ch <- prometheus.MustNewConstMetric(c.FilesetBlockInDoubt, prometheus.GaugeValue, m.BlockInDoubt, m.Name, m.FS) + ch <- prometheus.MustNewConstMetric(c.FilesetFilesUsage, prometheus.GaugeValue, m.FilesUsage, m.Name, m.FS) + ch <- prometheus.MustNewConstMetric(c.FilesetFilesQuota, prometheus.GaugeValue, m.FilesQuota, m.Name, m.FS) + ch <- prometheus.MustNewConstMetric(c.FilesetFilesLimit, prometheus.GaugeValue, m.FilesLimit, m.Name, m.FS) + ch <- prometheus.MustNewConstMetric(c.FilesetFilesInDoubt, prometheus.GaugeValue, m.FilesInDoubt, m.Name, m.FS) + } else if m.QuotaType == "USR" { + ch <- prometheus.MustNewConstMetric(c.UserBlockUsage, prometheus.GaugeValue, m.BlockUsage, m.Name, m.FS) + ch <- prometheus.MustNewConstMetric(c.UserBlockQuota, prometheus.GaugeValue, m.BlockQuota, m.Name, m.FS) + ch <- prometheus.MustNewConstMetric(c.UserBlockLimit, prometheus.GaugeValue, m.BlockLimit, m.Name, m.FS) + ch <- prometheus.MustNewConstMetric(c.UserBlockInDoubt, prometheus.GaugeValue, m.BlockInDoubt, m.Name, m.FS) + ch <- prometheus.MustNewConstMetric(c.UserFilesUsage, prometheus.GaugeValue, m.FilesUsage, m.Name, m.FS) + ch <- prometheus.MustNewConstMetric(c.UserFilesQuota, prometheus.GaugeValue, m.FilesQuota, m.Name, m.FS) + ch <- prometheus.MustNewConstMetric(c.UserFilesLimit, prometheus.GaugeValue, m.FilesLimit, m.Name, m.FS) + ch <- prometheus.MustNewConstMetric(c.UserFilesInDoubt, prometheus.GaugeValue, m.FilesInDoubt, m.Name, m.FS) + } else if m.QuotaType == "GRP" { + ch <- prometheus.MustNewConstMetric(c.GroupBlockUsage, prometheus.GaugeValue, m.BlockUsage, m.Name, m.FS) + ch <- prometheus.MustNewConstMetric(c.GroupBlockQuota, prometheus.GaugeValue, m.BlockQuota, m.Name, m.FS) + ch <- prometheus.MustNewConstMetric(c.GroupBlockLimit, prometheus.GaugeValue, m.BlockLimit, m.Name, m.FS) + ch <- prometheus.MustNewConstMetric(c.GroupBlockInDoubt, prometheus.GaugeValue, m.BlockInDoubt, m.Name, m.FS) + ch <- prometheus.MustNewConstMetric(c.GroupFilesUsage, prometheus.GaugeValue, m.FilesUsage, m.Name, m.FS) + ch <- prometheus.MustNewConstMetric(c.GroupFilesQuota, prometheus.GaugeValue, m.FilesQuota, m.Name, m.FS) + ch <- prometheus.MustNewConstMetric(c.GroupFilesLimit, prometheus.GaugeValue, m.FilesLimit, m.Name, m.FS) + ch <- prometheus.MustNewConstMetric(c.GroupFilesInDoubt, prometheus.GaugeValue, m.FilesInDoubt, m.Name, m.FS) + } } ch <- prometheus.MustNewConstMetric(collectError, prometheus.GaugeValue, float64(errorMetric), "mmrepquota") ch <- prometheus.MustNewConstMetric(collecTimeout, prometheus.GaugeValue, float64(timeout), "mmrepquota") ch <- prometheus.MustNewConstMetric(collectDuration, prometheus.GaugeValue, time.Since(collectTime).Seconds(), "mmrepquota") } -func (c *MmrepquotaCollector) collect() ([]QuotaMetric, error) { +func (c *MmrepquotaCollector) collect(typeArg string) ([]QuotaMetric, error) { ctx, cancel := context.WithTimeout(context.Background(), time.Duration(*mmrepquotaTimeout)*time.Second) defer cancel() - out, err := mmrepquotaExec(ctx) + out, err := mmrepquotaExec(ctx, typeArg) if err != nil { return nil, err } @@ -148,13 +279,15 @@ func (c *MmrepquotaCollector) collect() ([]QuotaMetric, error) { return metric, nil } -func mmrepquota(ctx context.Context) (string, error) { - args := []string{"/usr/lpp/mmfs/bin/mmrepquota", "-j", "-Y"} +func mmrepquota(ctx context.Context, typeArg string) (string, error) { + args := []string{"/usr/lpp/mmfs/bin/mmrepquota", typeArg, "-Y"} + if *configMmrepquotaFilesystems == "" { args = append(args, "-a") } else { args = append(args, strings.Split(*configMmrepquotaFilesystems, ",")...) } + cmd := execCommand(ctx, *sudoCmd, args...) var out bytes.Buffer cmd.Stdout = &out diff --git a/collectors/mmrepquota_test.go b/collectors/mmrepquota_test.go index a41189f..3359f05 100644 --- a/collectors/mmrepquota_test.go +++ b/collectors/mmrepquota_test.go @@ -35,6 +35,30 @@ mmrepquota::0:1:::project:FILESET:408:PZS1003:341467872:2147483648:2147483648:0: *** Report for FILESET quotas on scratch mmrepquota::HEADER:version:reserved:reserved:filesystemName:quotaType:id:name:blockUsage:blockQuota:blockLimit:blockInDoubt:blockGrace:filesUsage:filesQuota:filesLimit:filesInDoubt:filesGrace:remarks:quota:defQuota:fid:filesetname: mmrepquota::0:1:::scratch:FILESET:0:root:928235294208:0:0:5308909920:none:141909093:0:0:140497:none:i:on:off::: +` + + mmrepquotaStdoutAll = ` +*** Report for FILESET quotas on project +mmrepquota::HEADER:version:reserved:reserved:filesystemName:quotaType:id:name:blockUsage:blockQuota:blockLimit:blockInDoubt:blockGrace:filesUsage:filesQuota:filesLimit:filesInDoubt:filesGrace:remarks:quota:defQuota:fid:filesetname: +mmrepquota::0:1:::project:FILESET:0:root:337419744:0:0:163840:none:1395:0:0:400:none:i:on:off::: +mmrepquota::0:1:::project:FILESET:408:PZS1003:341467872:2147483648:2147483648:0:none:6286:2000000:2000000:0:none:e:on:off::: +*** Report for FILESET quotas on scratch +mmrepquota::HEADER:version:reserved:reserved:filesystemName:quotaType:id:name:blockUsage:blockQuota:blockLimit:blockInDoubt:blockGrace:filesUsage:filesQuota:filesLimit:filesInDoubt:filesGrace:remarks:quota:defQuota:fid:filesetname: +mmrepquota::0:1:::scratch:FILESET:0:root:928235294208:0:0:5308909920:none:141909093:0:0:140497:none:i:on:off::: +*** Report for USR quotas on home +mmrepquota::HEADER:version:reserved:reserved:filesystemName:quotaType:id:name:blockUsage:blockQuota:blockLimit:blockInDoubt:blockGrace:filesUsage:filesQuota:filesLimit:filesInDoubt:filesGrace:remarks:quota:defQuota:fid:filesetname: +mmrepquota::0:1:::home:USR:0:root:337419744:0:0:163840:none:1395:0:0:400:none:i:on:off::: +mmrepquota::0:1:::home:USR:408:PZS1003:341467872:2147483648:2147483648:0:none:6286:2000000:2000000:0:none:e:on:off::: +*** Report for USR quotas on scratch +mmrepquota::HEADER:version:reserved:reserved:filesystemName:quotaType:id:name:blockUsage:blockQuota:blockLimit:blockInDoubt:blockGrace:filesUsage:filesQuota:filesLimit:filesInDoubt:filesGrace:remarks:quota:defQuota:fid:filesetname: +mmrepquota::0:1:::scratch:USR:0:root:928235294208:0:0:5308909920:none:141909093:0:0:140497:none:i:on:off::: +*** Report for GRP quotas on project +mmrepquota::HEADER:version:reserved:reserved:filesystemName:quotaType:id:name:blockUsage:blockQuota:blockLimit:blockInDoubt:blockGrace:filesUsage:filesQuota:filesLimit:filesInDoubt:filesGrace:remarks:quota:defQuota:fid:filesetname: +mmrepquota::0:1:::project:GRP:0:root:337419744:0:0:163840:none:1395:0:0:400:none:i:on:off::: +mmrepquota::0:1:::project:GRP:408:PZS1003:341467872:2147483648:2147483648:0:none:6286:2000000:2000000:0:none:e:on:off::: +*** Report for GRP quotas on scratch +mmrepquota::HEADER:version:reserved:reserved:filesystemName:quotaType:id:name:blockUsage:blockQuota:blockLimit:blockInDoubt:blockGrace:filesUsage:filesQuota:filesLimit:filesInDoubt:filesGrace:remarks:quota:defQuota:fid:filesetname: +mmrepquota::0:1:::scratch:GRP:0:root:928235294208:0:0:5308909920:none:141909093:0:0:140497:none:i:on:off::: ` ) @@ -45,7 +69,7 @@ func TestMmrepquota(t *testing.T) { defer func() { execCommand = exec.CommandContext }() ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() - out, err := mmrepquota(ctx) + out, err := mmrepquota(ctx, "-j") if err != nil { t.Errorf("Unexpected error: %s", err.Error()) } @@ -61,7 +85,7 @@ func TestMmrepquotaError(t *testing.T) { defer func() { execCommand = exec.CommandContext }() ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) defer cancel() - out, err := mmrepquota(ctx) + out, err := mmrepquota(ctx, "-j") if err == nil { t.Errorf("Expected error") } @@ -77,7 +101,7 @@ func TestMmrepquotaTimeout(t *testing.T) { defer func() { execCommand = exec.CommandContext }() ctx, cancel := context.WithTimeout(context.Background(), 0*time.Second) defer cancel() - out, err := mmrepquota(ctx) + out, err := mmrepquota(ctx, "-j") if err != context.DeadlineExceeded { t.Errorf("Expected DeadlineExceeded") } @@ -105,12 +129,31 @@ func TestParseMmrepquota(t *testing.T) { t.Errorf("Unexpected BlockInDoubt got %v", val) } } +func TestParseMmrepquotaAll(t *testing.T) { + metrics := parse_mmrepquota(mmrepquotaStdoutAll, log.NewNopLogger()) + if len(metrics) != 9 { + t.Errorf("Unexpected metric count: %d", len(metrics)) + return + } + if val := metrics[0].BlockUsage; val != 345517817856 { + t.Errorf("Unexpected BlockUsage got %v", val) + } + if val := metrics[0].BlockQuota; val != 0 { + t.Errorf("Unexpected BlockQuota got %v", val) + } + if val := metrics[0].BlockLimit; val != 0 { + t.Errorf("Unexpected BlockLimit got %v", val) + } + if val := metrics[0].BlockInDoubt; val != 167772160 { + t.Errorf("Unexpected BlockInDoubt got %v", val) + } +} func TestMmrepquotaCollector(t *testing.T) { if _, err := kingpin.CommandLine.Parse([]string{}); err != nil { t.Fatal(err) } - mmrepquotaExec = func(ctx context.Context) (string, error) { + mmrepquotaExec = func(ctx context.Context, typeArg string) (string, error) { return mmrepquotaStdout, nil } expected := ` @@ -120,6 +163,7 @@ gpfs_exporter_collect_error{collector="mmrepquota"} 0 # HELP gpfs_exporter_collect_timeout Indicates the collector timed out # TYPE gpfs_exporter_collect_timeout gauge gpfs_exporter_collect_timeout{collector="mmrepquota"} 0 + # HELP gpfs_fileset_in_doubt_bytes GPFS fileset quota block in doubt # TYPE gpfs_fileset_in_doubt_bytes gauge gpfs_fileset_in_doubt_bytes{fileset="PZS1003",fs="project"} 0 @@ -160,7 +204,8 @@ gpfs_fileset_used_bytes{fileset="root",fs="scratch"} 950512941268992 gpfs_fileset_used_files{fileset="PZS1003",fs="project"} 6286 gpfs_fileset_used_files{fileset="root",fs="project"} 1395 gpfs_fileset_used_files{fileset="root",fs="scratch"} 141909093 - ` +` + collector := NewMmrepquotaCollector(log.NewNopLogger()) gatherers := setupGatherer(collector) if val, err := testutil.GatherAndCount(gatherers); err != nil { @@ -170,6 +215,7 @@ gpfs_fileset_used_files{fileset="root",fs="scratch"} 141909093 } if err := testutil.GatherAndCompare(gatherers, strings.NewReader(expected), "gpfs_exporter_collect_error", "gpfs_exporter_collect_timeout", + "gpfs_fileset_in_doubt_bytes", "gpfs_fileset_in_doubt_files", "gpfs_fileset_limit_bytes", "gpfs_fileset_limit_files", "gpfs_fileset_quota_bytes", "gpfs_fileset_quota_files", @@ -178,11 +224,177 @@ gpfs_fileset_used_files{fileset="root",fs="scratch"} 141909093 } } +func TestMmrepquotaCollectorAll(t *testing.T) { + if _, err := kingpin.CommandLine.Parse([]string{}); err != nil { + t.Fatal(err) + } + mmrepquotaExec = func(ctx context.Context, typeArg string) (string, error) { + return mmrepquotaStdoutAll, nil + } + expected := ` +# HELP gpfs_exporter_collect_error Indicates if error has occurred during collection +# TYPE gpfs_exporter_collect_error gauge +gpfs_exporter_collect_error{collector="mmrepquota"} 0 +# HELP gpfs_exporter_collect_timeout Indicates the collector timed out +# TYPE gpfs_exporter_collect_timeout gauge +gpfs_exporter_collect_timeout{collector="mmrepquota"} 0 + +# HELP gpfs_fileset_in_doubt_bytes GPFS fileset quota block in doubt +# TYPE gpfs_fileset_in_doubt_bytes gauge +gpfs_fileset_in_doubt_bytes{fileset="PZS1003",fs="project"} 0 +gpfs_fileset_in_doubt_bytes{fileset="root",fs="project"} 167772160 +gpfs_fileset_in_doubt_bytes{fileset="root",fs="scratch"} 5436323758080 +# HELP gpfs_fileset_in_doubt_files GPFS fileset quota files in doubt +# TYPE gpfs_fileset_in_doubt_files gauge +gpfs_fileset_in_doubt_files{fileset="PZS1003",fs="project"} 0 +gpfs_fileset_in_doubt_files{fileset="root",fs="project"} 400 +gpfs_fileset_in_doubt_files{fileset="root",fs="scratch"} 140497 +# HELP gpfs_fileset_limit_bytes GPFS fileset quota block limit +# TYPE gpfs_fileset_limit_bytes gauge +gpfs_fileset_limit_bytes{fileset="PZS1003",fs="project"} 2199023255552 +gpfs_fileset_limit_bytes{fileset="root",fs="project"} 0 +gpfs_fileset_limit_bytes{fileset="root",fs="scratch"} 0 +# HELP gpfs_fileset_limit_files GPFS fileset quota files limit +# TYPE gpfs_fileset_limit_files gauge +gpfs_fileset_limit_files{fileset="PZS1003",fs="project"} 2000000 +gpfs_fileset_limit_files{fileset="root",fs="project"} 0 +gpfs_fileset_limit_files{fileset="root",fs="scratch"} 0 +# HELP gpfs_fileset_quota_bytes GPFS fileset block quota +# TYPE gpfs_fileset_quota_bytes gauge +gpfs_fileset_quota_bytes{fileset="PZS1003",fs="project"} 2199023255552 +gpfs_fileset_quota_bytes{fileset="root",fs="project"} 0 +gpfs_fileset_quota_bytes{fileset="root",fs="scratch"} 0 +# HELP gpfs_fileset_quota_files GPFS fileset files quota +# TYPE gpfs_fileset_quota_files gauge +gpfs_fileset_quota_files{fileset="PZS1003",fs="project"} 2000000 +gpfs_fileset_quota_files{fileset="root",fs="project"} 0 +gpfs_fileset_quota_files{fileset="root",fs="scratch"} 0 +# HELP gpfs_fileset_used_bytes GPFS fileset quota used +# TYPE gpfs_fileset_used_bytes gauge +gpfs_fileset_used_bytes{fileset="PZS1003",fs="project"} 349663100928 +gpfs_fileset_used_bytes{fileset="root",fs="project"} 345517817856 +gpfs_fileset_used_bytes{fileset="root",fs="scratch"} 950512941268992 +# HELP gpfs_fileset_used_files GPFS fileset quota files used +# TYPE gpfs_fileset_used_files gauge +gpfs_fileset_used_files{fileset="PZS1003",fs="project"} 6286 +gpfs_fileset_used_files{fileset="root",fs="project"} 1395 +gpfs_fileset_used_files{fileset="root",fs="scratch"} 141909093 +# HELP gpfs_user_in_doubt_bytes GPFS user quota block in doubt +# TYPE gpfs_user_in_doubt_bytes gauge +gpfs_user_in_doubt_bytes{fs="home",user="PZS1003"} 0 +gpfs_user_in_doubt_bytes{fs="home",user="root"} 167772160 +gpfs_user_in_doubt_bytes{fs="scratch",user="root"} 5436323758080 +# HELP gpfs_user_in_doubt_files GPFS user quota files in doubt +# TYPE gpfs_user_in_doubt_files gauge +gpfs_user_in_doubt_files{fs="home",user="PZS1003"} 0 +gpfs_user_in_doubt_files{fs="home",user="root"} 400 +gpfs_user_in_doubt_files{fs="scratch",user="root"} 140497 +# HELP gpfs_user_limit_bytes GPFS user quota block limit +# TYPE gpfs_user_limit_bytes gauge +gpfs_user_limit_bytes{fs="home",user="PZS1003"} 2199023255552 +gpfs_user_limit_bytes{fs="home",user="root"} 0 +gpfs_user_limit_bytes{fs="scratch",user="root"} 0 +# HELP gpfs_user_limit_files GPFS user quota files limit +# TYPE gpfs_user_limit_files gauge +gpfs_user_limit_files{fs="home",user="PZS1003"} 2000000 +gpfs_user_limit_files{fs="home",user="root"} 0 +gpfs_user_limit_files{fs="scratch",user="root"} 0 +# HELP gpfs_user_quota_bytes GPFS user block quota +# TYPE gpfs_user_quota_bytes gauge +gpfs_user_quota_bytes{fs="home",user="PZS1003"} 2199023255552 +gpfs_user_quota_bytes{fs="home",user="root"} 0 +gpfs_user_quota_bytes{fs="scratch",user="root"} 0 +# HELP gpfs_user_quota_files GPFS user files quota +# TYPE gpfs_user_quota_files gauge +gpfs_user_quota_files{fs="home",user="PZS1003"} 2000000 +gpfs_user_quota_files{fs="home",user="root"} 0 +gpfs_user_quota_files{fs="scratch",user="root"} 0 +# HELP gpfs_user_used_bytes GPFS user quota used +# TYPE gpfs_user_used_bytes gauge +gpfs_user_used_bytes{fs="home",user="PZS1003"} 349663100928 +gpfs_user_used_bytes{fs="home",user="root"} 345517817856 +gpfs_user_used_bytes{fs="scratch",user="root"} 950512941268992 +# HELP gpfs_user_used_files GPFS user quota files used +# TYPE gpfs_user_used_files gauge +gpfs_user_used_files{fs="home",user="PZS1003"} 6286 +gpfs_user_used_files{fs="home",user="root"} 1395 +gpfs_user_used_files{fs="scratch",user="root"} 141909093 + +# HELP gpfs_group_in_doubt_bytes GPFS group quota block in doubt +# TYPE gpfs_group_in_doubt_bytes gauge +gpfs_group_in_doubt_bytes{fs="project",group="PZS1003"} 0 +gpfs_group_in_doubt_bytes{fs="project",group="root"} 167772160 +gpfs_group_in_doubt_bytes{fs="scratch",group="root"} 5436323758080 +# HELP gpfs_group_in_doubt_files GPFS group quota files in doubt +# TYPE gpfs_group_in_doubt_files gauge +gpfs_group_in_doubt_files{fs="project",group="PZS1003"} 0 +gpfs_group_in_doubt_files{fs="project",group="root"} 400 +gpfs_group_in_doubt_files{fs="scratch",group="root"} 140497 +# HELP gpfs_group_limit_bytes GPFS group quota block limit +# TYPE gpfs_group_limit_bytes gauge +gpfs_group_limit_bytes{fs="project",group="PZS1003"} 2199023255552 +gpfs_group_limit_bytes{fs="project",group="root"} 0 +gpfs_group_limit_bytes{fs="scratch",group="root"} 0 +# HELP gpfs_group_limit_files GPFS group quota files limit +# TYPE gpfs_group_limit_files gauge +gpfs_group_limit_files{fs="project",group="PZS1003"} 2000000 +gpfs_group_limit_files{fs="project",group="root"} 0 +gpfs_group_limit_files{fs="scratch",group="root"} 0 +# HELP gpfs_group_quota_bytes GPFS group block quota +# TYPE gpfs_group_quota_bytes gauge +gpfs_group_quota_bytes{fs="project",group="PZS1003"} 2199023255552 +gpfs_group_quota_bytes{fs="project",group="root"} 0 +gpfs_group_quota_bytes{fs="scratch",group="root"} 0 +# HELP gpfs_group_quota_files GPFS group files quota +# TYPE gpfs_group_quota_files gauge +gpfs_group_quota_files{fs="project",group="PZS1003"} 2000000 +gpfs_group_quota_files{fs="project",group="root"} 0 +gpfs_group_quota_files{fs="scratch",group="root"} 0 +# HELP gpfs_group_used_bytes GPFS group quota used +# TYPE gpfs_group_used_bytes gauge +gpfs_group_used_bytes{fs="project",group="PZS1003"} 349663100928 +gpfs_group_used_bytes{fs="project",group="root"} 345517817856 +gpfs_group_used_bytes{fs="scratch",group="root"} 950512941268992 +# HELP gpfs_group_used_files GPFS group quota files used +# TYPE gpfs_group_used_files gauge +gpfs_group_used_files{fs="project",group="PZS1003"} 6286 +gpfs_group_used_files{fs="project",group="root"} 1395 +gpfs_group_used_files{fs="scratch",group="root"} 141909093 +` + + collector := NewMmrepquotaCollector(log.NewNopLogger()) + gatherers := setupGatherer(collector) + if val, err := testutil.GatherAndCount(gatherers); err != nil { + t.Errorf("Unexpected error: %v", err) + } else if val != 75 { + t.Errorf("Unexpected collection count %d, expected 75", val) + } + if err := testutil.GatherAndCompare(gatherers, strings.NewReader(expected), + "gpfs_exporter_collect_error", "gpfs_exporter_collect_timeout", + + "gpfs_fileset_in_doubt_bytes", "gpfs_fileset_in_doubt_files", + "gpfs_fileset_limit_bytes", "gpfs_fileset_limit_files", + "gpfs_fileset_quota_bytes", "gpfs_fileset_quota_files", + "gpfs_fileset_used_bytes", "gpfs_fileset_used_files", + + "gpfs_user_in_doubt_bytes", "gpfs_user_in_doubt_files", + "gpfs_user_limit_bytes", "gpfs_user_limit_files", + "gpfs_user_quota_bytes", "gpfs_user_quota_files", + "gpfs_user_used_bytes", "gpfs_user_used_files", + + "gpfs_group_in_doubt_bytes", "gpfs_group_in_doubt_files", + "gpfs_group_limit_bytes", "gpfs_group_limit_files", + "gpfs_group_quota_bytes", "gpfs_group_quota_files", + "gpfs_group_used_bytes", "gpfs_group_used_files"); err != nil { + t.Errorf("unexpected collecting result:\n%s", err) + } +} + func TestMMrepquotaCollectorError(t *testing.T) { if _, err := kingpin.CommandLine.Parse([]string{}); err != nil { t.Fatal(err) } - mmrepquotaExec = func(ctx context.Context) (string, error) { + mmrepquotaExec = func(ctx context.Context, typeArg string) (string, error) { return "", fmt.Errorf("Error") } expected := ` @@ -207,7 +419,7 @@ func TestMMrepquotaCollectorTimeout(t *testing.T) { if _, err := kingpin.CommandLine.Parse([]string{}); err != nil { t.Fatal(err) } - mmrepquotaExec = func(ctx context.Context) (string, error) { + mmrepquotaExec = func(ctx context.Context, typeArg string) (string, error) { return "", context.DeadlineExceeded } expected := `