|
|
|
@ -41,6 +41,8 @@ const (
|
|
|
|
|
// kstatDataString = "7"
|
|
|
|
|
) |
|
|
|
|
|
|
|
|
|
var zfsPoolStatesName = []string{"online", "degraded", "faulted", "offline", "removed", "unavail"} |
|
|
|
|
|
|
|
|
|
func (c *zfsCollector) openProcFile(path string) (*os.File, error) { |
|
|
|
|
file, err := os.Open(procFilePath(path)) |
|
|
|
|
if err != nil { |
|
|
|
@ -97,10 +99,6 @@ func (c *zfsCollector) updatePoolStats(ch chan<- prometheus.Metric) error {
|
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if zpoolObjsetPaths == nil { |
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for _, zpoolPath := range zpoolObjsetPaths { |
|
|
|
|
file, err := os.Open(zpoolPath) |
|
|
|
|
if err != nil { |
|
|
|
@ -117,6 +115,34 @@ func (c *zfsCollector) updatePoolStats(ch chan<- prometheus.Metric) error {
|
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
zpoolStatePaths, err := filepath.Glob(procFilePath(filepath.Join(c.linuxProcpathBase, c.linuxZpoolStatePath))) |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if zpoolStatePaths == nil { |
|
|
|
|
level.Warn(c.logger).Log("msg", "Not found pool state files") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
for _, zpoolPath := range zpoolStatePaths { |
|
|
|
|
file, err := os.Open(zpoolPath) |
|
|
|
|
if err != nil { |
|
|
|
|
// this file should exist, but there is a race where an exporting pool can remove the files -- ok to ignore
|
|
|
|
|
level.Debug(c.logger).Log("msg", "Cannot open file for reading", "path", zpoolPath) |
|
|
|
|
return errZFSNotAvailable |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
err = c.parsePoolStateFile(file, zpoolPath, func(poolName string, stateName string, isActive uint64) { |
|
|
|
|
ch <- c.constPoolStateMetric(poolName, stateName, isActive) |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
file.Close() |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -235,3 +261,35 @@ func (c *zfsCollector) parsePoolObjsetFile(reader io.Reader, zpoolPath string, h
|
|
|
|
|
|
|
|
|
|
return scanner.Err() |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
func (c *zfsCollector) parsePoolStateFile(reader io.Reader, zpoolPath string, handler func(string, string, uint64)) error { |
|
|
|
|
scanner := bufio.NewScanner(reader) |
|
|
|
|
scanner.Scan() |
|
|
|
|
|
|
|
|
|
actualStateName, err := scanner.Text(), scanner.Err() |
|
|
|
|
if err != nil { |
|
|
|
|
return err |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
actualStateName = strings.ToLower(actualStateName) |
|
|
|
|
|
|
|
|
|
zpoolPathElements := strings.Split(zpoolPath, "/") |
|
|
|
|
pathLen := len(zpoolPathElements) |
|
|
|
|
if pathLen < 2 { |
|
|
|
|
return fmt.Errorf("zpool path did not return at least two elements") |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
zpoolName := zpoolPathElements[pathLen-2] |
|
|
|
|
|
|
|
|
|
for _, stateName := range zfsPoolStatesName { |
|
|
|
|
isActive := uint64(0) |
|
|
|
|
|
|
|
|
|
if actualStateName == stateName { |
|
|
|
|
isActive = 1 |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
handler(zpoolName, stateName, isActive) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return nil |
|
|
|
|
} |
|
|
|
|