Skip to content

Commit

Permalink
Add users and groups mmrepquota (#59)
Browse files Browse the repository at this point in the history
* 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 <[email protected]>
  • Loading branch information
Evan-Vokey and treydock authored Jul 9, 2023
1 parent 609ee66 commit 7d13cd1
Show file tree
Hide file tree
Showing 3 changed files with 406 additions and 60 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
239 changes: 186 additions & 53 deletions collectors/mmrepquota.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package collectors
import (
"bytes"
"context"
"fmt"
"reflect"
"strconv"
"strings"
Expand All @@ -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",
Expand All @@ -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
Expand All @@ -59,102 +68,226 @@ 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() {
registerCollector("mmrepquota", false, NewMmrepquotaCollector)
}

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) {
level.Debug(c.logger).Log("msg", "Collecting mmrepquota metrics")
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
}
metric := parse_mmrepquota(out, c.logger)
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
Expand Down
Loading

0 comments on commit 7d13cd1

Please sign in to comment.