fix(inputs.diskio): Add missing udev properties (#15003)
This commit is contained in:
parent
13c786bdfa
commit
c9fb4e74be
|
|
@ -16,24 +16,20 @@ See the [CONFIGURATION.md][CONFIGURATION.md] for more details.
|
||||||
```toml @sample.conf
|
```toml @sample.conf
|
||||||
# Read metrics about disk IO by device
|
# Read metrics about disk IO by device
|
||||||
[[inputs.diskio]]
|
[[inputs.diskio]]
|
||||||
## By default, telegraf will gather stats for all devices including
|
## Devices to collect stats for
|
||||||
## disk partitions.
|
## Wildcards are supported except for disk synonyms like '/dev/disk/by-id'.
|
||||||
## Setting devices will restrict the stats to the specified devices.
|
## ex. devices = ["sda", "sdb", "vd*", "/dev/disk/by-id/nvme-eui.00123deadc0de123"]
|
||||||
## NOTE: Globbing expressions (e.g. asterix) are not supported for
|
# devices = ["*"]
|
||||||
## disk synonyms like '/dev/disk/by-id'.
|
|
||||||
# devices = ["sda", "sdb", "vd*", "/dev/disk/by-id/nvme-eui.00123deadc0de123"]
|
## Skip gathering of the disk's serial numbers.
|
||||||
## Uncomment the following line if you need disk serial numbers.
|
# skip_serial_number = true
|
||||||
# skip_serial_number = false
|
|
||||||
#
|
## Device metadata tags to add on systems supporting it (Linux only)
|
||||||
## On systems which support it, device metadata can be added in the form of
|
## Use 'udevadm info -q property -n <device>' to get a list of properties.
|
||||||
## tags.
|
|
||||||
## Currently only Linux is supported via udev properties. You can view
|
|
||||||
## available properties for a device by running:
|
|
||||||
## 'udevadm info -q property -n /dev/sda'
|
|
||||||
## Note: Most, but not all, udev properties can be accessed this way. Properties
|
## Note: Most, but not all, udev properties can be accessed this way. Properties
|
||||||
## that are currently inaccessible include DEVTYPE, DEVNAME, and DEVPATH.
|
## that are currently inaccessible include DEVTYPE, DEVNAME, and DEVPATH.
|
||||||
# device_tags = ["ID_FS_TYPE", "ID_FS_USAGE"]
|
# device_tags = ["ID_FS_TYPE", "ID_FS_USAGE"]
|
||||||
#
|
|
||||||
## Using the same metadata source as device_tags, you can also customize the
|
## Using the same metadata source as device_tags, you can also customize the
|
||||||
## name of the device via templates.
|
## name of the device via templates.
|
||||||
## The 'name_templates' parameter is a list of templates to try and apply to
|
## The 'name_templates' parameter is a list of templates to try and apply to
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,18 @@ func hasMeta(s string) bool {
|
||||||
return strings.ContainsAny(s, "*?[")
|
return strings.ContainsAny(s, "*?[")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DiskIO struct {
|
||||||
|
Devices []string `toml:"devices"`
|
||||||
|
DeviceTags []string `toml:"device_tags"`
|
||||||
|
NameTemplates []string `toml:"name_templates"`
|
||||||
|
SkipSerialNumber bool `toml:"skip_serial_number"`
|
||||||
|
Log telegraf.Logger `toml:"-"`
|
||||||
|
|
||||||
|
ps system.PS
|
||||||
|
infoCache map[string]diskInfoCache
|
||||||
|
deviceFilter filter.Filter
|
||||||
|
}
|
||||||
|
|
||||||
func (*DiskIO) SampleConfig() string {
|
func (*DiskIO) SampleConfig() string {
|
||||||
return sampleConfig
|
return sampleConfig
|
||||||
}
|
}
|
||||||
|
|
@ -39,6 +51,9 @@ func (d *DiskIO) Init() error {
|
||||||
d.deviceFilter = deviceFilter
|
d.deviceFilter = deviceFilter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
d.infoCache = make(map[string]diskInfoCache)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -11,51 +11,30 @@ import (
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
"golang.org/x/sys/unix"
|
"golang.org/x/sys/unix"
|
||||||
|
|
||||||
"github.com/influxdata/telegraf"
|
|
||||||
"github.com/influxdata/telegraf/filter"
|
|
||||||
"github.com/influxdata/telegraf/plugins/inputs/system"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
type DiskIO struct {
|
|
||||||
ps system.PS
|
|
||||||
|
|
||||||
Devices []string
|
|
||||||
DeviceTags []string
|
|
||||||
NameTemplates []string
|
|
||||||
SkipSerialNumber bool
|
|
||||||
|
|
||||||
Log telegraf.Logger
|
|
||||||
|
|
||||||
infoCache map[string]diskInfoCache
|
|
||||||
deviceFilter filter.Filter
|
|
||||||
}
|
|
||||||
|
|
||||||
type diskInfoCache struct {
|
type diskInfoCache struct {
|
||||||
modifiedAt int64 // Unix Nano timestamp of the last modification of the device. This value is used to invalidate the cache
|
modifiedAt int64 // Unix Nano timestamp of the last modification of the device. This value is used to invalidate the cache
|
||||||
udevDataPath string
|
udevDataPath string
|
||||||
|
sysBlockPath string
|
||||||
values map[string]string
|
values map[string]string
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *DiskIO) diskInfo(devName string) (map[string]string, error) {
|
func (d *DiskIO) diskInfo(devName string) (map[string]string, error) {
|
||||||
var err error
|
// Check if the device exists
|
||||||
var stat unix.Stat_t
|
|
||||||
|
|
||||||
path := "/dev/" + devName
|
path := "/dev/" + devName
|
||||||
err = unix.Stat(path, &stat)
|
var stat unix.Stat_t
|
||||||
if err != nil {
|
if err := unix.Stat(path, &stat); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if d.infoCache == nil {
|
// Check if we already got a cached and valid entry
|
||||||
d.infoCache = map[string]diskInfoCache{}
|
|
||||||
}
|
|
||||||
ic, ok := d.infoCache[devName]
|
ic, ok := d.infoCache[devName]
|
||||||
|
|
||||||
if ok && stat.Mtim.Nano() == ic.modifiedAt {
|
if ok && stat.Mtim.Nano() == ic.modifiedAt {
|
||||||
return ic.values, nil
|
return ic.values, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Determine udev properties
|
||||||
var udevDataPath string
|
var udevDataPath string
|
||||||
if ok && len(ic.udevDataPath) > 0 {
|
if ok && len(ic.udevDataPath) > 0 {
|
||||||
// We can reuse the udev data path from a "previous" entry.
|
// We can reuse the udev data path from a "previous" entry.
|
||||||
|
|
@ -65,33 +44,60 @@ func (d *DiskIO) diskInfo(devName string) (map[string]string, error) {
|
||||||
major := unix.Major(uint64(stat.Rdev)) //nolint:unconvert // Conversion needed for some architectures
|
major := unix.Major(uint64(stat.Rdev)) //nolint:unconvert // Conversion needed for some architectures
|
||||||
minor := unix.Minor(uint64(stat.Rdev)) //nolint:unconvert // Conversion needed for some architectures
|
minor := unix.Minor(uint64(stat.Rdev)) //nolint:unconvert // Conversion needed for some architectures
|
||||||
udevDataPath = fmt.Sprintf("/run/udev/data/b%d:%d", major, minor)
|
udevDataPath = fmt.Sprintf("/run/udev/data/b%d:%d", major, minor)
|
||||||
|
if _, err := os.Stat(udevDataPath); err != nil {
|
||||||
_, err := os.Stat(udevDataPath)
|
|
||||||
if err != nil {
|
|
||||||
// This path failed, try the fallback .udev style (non-systemd)
|
// This path failed, try the fallback .udev style (non-systemd)
|
||||||
udevDataPath = "/dev/.udev/db/block:" + devName
|
udevDataPath = "/dev/.udev/db/block:" + devName
|
||||||
_, err := os.Stat(udevDataPath)
|
if _, err := os.Stat(udevDataPath); err != nil {
|
||||||
if err != nil {
|
|
||||||
// Giving up, cannot retrieve disk info
|
// Giving up, cannot retrieve disk info
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
info, err := readUdevData(udevDataPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read additional device properties
|
||||||
|
var sysBlockPath string
|
||||||
|
if ok && len(ic.sysBlockPath) > 0 {
|
||||||
|
// We can reuse the /sys block path from a "previous" entry.
|
||||||
|
// This allows us to also "poison" it during test scenarios
|
||||||
|
sysBlockPath = ic.sysBlockPath
|
||||||
|
} else {
|
||||||
|
sysBlockPath = "/sys/block/" + devName
|
||||||
|
if _, err := os.Stat(sysBlockPath); err != nil {
|
||||||
|
// Giving up, cannot retrieve additional info
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
devInfo, err := readDevData(sysBlockPath)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
for k, v := range devInfo {
|
||||||
|
info[k] = v
|
||||||
|
}
|
||||||
|
|
||||||
|
d.infoCache[devName] = diskInfoCache{
|
||||||
|
modifiedAt: stat.Mtim.Nano(),
|
||||||
|
udevDataPath: udevDataPath,
|
||||||
|
values: info,
|
||||||
|
}
|
||||||
|
|
||||||
|
return info, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readUdevData(path string) (map[string]string, error) {
|
||||||
// Final open of the confirmed (or the previously detected/used) udev file
|
// Final open of the confirmed (or the previously detected/used) udev file
|
||||||
f, err := os.Open(udevDataPath)
|
f, err := os.Open(path)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
defer f.Close()
|
defer f.Close()
|
||||||
|
|
||||||
di := map[string]string{}
|
info := make(map[string]string)
|
||||||
|
|
||||||
d.infoCache[devName] = diskInfoCache{
|
|
||||||
modifiedAt: stat.Mtim.Nano(),
|
|
||||||
udevDataPath: udevDataPath,
|
|
||||||
values: di,
|
|
||||||
}
|
|
||||||
|
|
||||||
scnr := bufio.NewScanner(f)
|
scnr := bufio.NewScanner(f)
|
||||||
var devlinks bytes.Buffer
|
var devlinks bytes.Buffer
|
||||||
for scnr.Scan() {
|
for scnr.Scan() {
|
||||||
|
|
@ -114,14 +120,51 @@ func (d *DiskIO) diskInfo(devName string) (map[string]string, error) {
|
||||||
if len(kv) < 2 {
|
if len(kv) < 2 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
di[kv[0]] = kv[1]
|
info[kv[0]] = kv[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
if devlinks.Len() > 0 {
|
if devlinks.Len() > 0 {
|
||||||
di["DEVLINKS"] = devlinks.String()
|
info["DEVLINKS"] = devlinks.String()
|
||||||
}
|
}
|
||||||
|
|
||||||
return di, nil
|
return info, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func readDevData(path string) (map[string]string, error) {
|
||||||
|
// Open the file and read line-wise
|
||||||
|
f, err := os.Open(filepath.Join(path, "uevent"))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
// Read DEVNAME and DEVTYPE
|
||||||
|
info := make(map[string]string)
|
||||||
|
scanner := bufio.NewScanner(f)
|
||||||
|
for scanner.Scan() {
|
||||||
|
line := scanner.Text()
|
||||||
|
if !strings.HasPrefix(line, "DEV") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
k, v, found := strings.Cut(line, "=")
|
||||||
|
if !found {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
info[strings.TrimSpace(k)] = strings.TrimSpace(v)
|
||||||
|
}
|
||||||
|
if d, found := info["DEVNAME"]; found && !strings.HasPrefix(d, "/dev") {
|
||||||
|
info["DEVNAME"] = "/dev/" + d
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find the DEVPATH property
|
||||||
|
if devlnk, err := filepath.EvalSymlinks(filepath.Join(path, "device")); err == nil {
|
||||||
|
devlnk = filepath.Join(devlnk, filepath.Base(path))
|
||||||
|
devlnk = strings.TrimPrefix(devlnk, "/sys")
|
||||||
|
info["DEVPATH"] = devlnk
|
||||||
|
}
|
||||||
|
|
||||||
|
return info, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func resolveName(name string) string {
|
func resolveName(name string) string {
|
||||||
|
|
@ -129,7 +172,7 @@ func resolveName(name string) string {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return resolved
|
return resolved
|
||||||
}
|
}
|
||||||
if err != nil && !errors.Is(err, fs.ErrNotExist) {
|
if !errors.Is(err, fs.ErrNotExist) {
|
||||||
return name
|
return name
|
||||||
}
|
}
|
||||||
// Try to prepend "/dev"
|
// Try to prepend "/dev"
|
||||||
|
|
|
||||||
|
|
@ -3,72 +3,29 @@
|
||||||
package diskio
|
package diskio
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"os"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/stretchr/testify/require"
|
"github.com/stretchr/testify/require"
|
||||||
)
|
)
|
||||||
|
|
||||||
var nullDiskInfo = []byte(`
|
|
||||||
E:MY_PARAM_1=myval1
|
|
||||||
E:MY_PARAM_2=myval2
|
|
||||||
S:foo/bar/devlink
|
|
||||||
S:foo/bar/devlink1
|
|
||||||
`)
|
|
||||||
|
|
||||||
// setupNullDisk sets up fake udev info as if /dev/null were a disk.
|
|
||||||
func setupNullDisk(t *testing.T, s *DiskIO, devName string) func() {
|
|
||||||
td, err := os.CreateTemp("", ".telegraf.DiskInfoTest")
|
|
||||||
require.NoError(t, err)
|
|
||||||
|
|
||||||
if s.infoCache == nil {
|
|
||||||
s.infoCache = make(map[string]diskInfoCache)
|
|
||||||
}
|
|
||||||
ic, ok := s.infoCache[devName]
|
|
||||||
if !ok {
|
|
||||||
// No previous calls for the device were done, easy to poison the cache
|
|
||||||
s.infoCache[devName] = diskInfoCache{
|
|
||||||
modifiedAt: 0,
|
|
||||||
udevDataPath: td.Name(),
|
|
||||||
values: map[string]string{},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
origUdevPath := ic.udevDataPath
|
|
||||||
|
|
||||||
cleanFunc := func() {
|
|
||||||
ic.udevDataPath = origUdevPath
|
|
||||||
os.Remove(td.Name())
|
|
||||||
}
|
|
||||||
|
|
||||||
ic.udevDataPath = td.Name()
|
|
||||||
_, err = td.Write(nullDiskInfo)
|
|
||||||
if err != nil {
|
|
||||||
cleanFunc()
|
|
||||||
t.Fatal(err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return cleanFunc
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestDiskInfo(t *testing.T) {
|
func TestDiskInfo(t *testing.T) {
|
||||||
s := &DiskIO{}
|
plugin := &DiskIO{
|
||||||
clean := setupNullDisk(t, s, "null")
|
infoCache: map[string]diskInfoCache{
|
||||||
defer clean()
|
"null": {
|
||||||
di, err := s.diskInfo("null")
|
modifiedAt: 0,
|
||||||
|
udevDataPath: "testdata/udev.txt",
|
||||||
|
sysBlockPath: "testdata",
|
||||||
|
values: map[string]string{},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
di, err := plugin.diskInfo("null")
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, "myval1", di["MY_PARAM_1"])
|
require.Equal(t, "myval1", di["MY_PARAM_1"])
|
||||||
require.Equal(t, "myval2", di["MY_PARAM_2"])
|
require.Equal(t, "myval2", di["MY_PARAM_2"])
|
||||||
require.Equal(t, "/dev/foo/bar/devlink /dev/foo/bar/devlink1", di["DEVLINKS"])
|
require.Equal(t, "/dev/foo/bar/devlink /dev/foo/bar/devlink1", di["DEVLINKS"])
|
||||||
|
|
||||||
// test that data is cached
|
|
||||||
clean()
|
|
||||||
|
|
||||||
di, err = s.diskInfo("null")
|
|
||||||
require.NoError(t, err)
|
|
||||||
require.Equal(t, "myval1", di["MY_PARAM_1"])
|
|
||||||
require.Equal(t, "myval2", di["MY_PARAM_2"])
|
|
||||||
require.Equal(t, "/dev/foo/bar/devlink /dev/foo/bar/devlink1", di["DEVLINKS"])
|
|
||||||
// unfortunately we can't adjust mtime on /dev/null to test cache invalidation
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// DiskIOStats.diskName isn't a linux specific function, but dependent
|
// DiskIOStats.diskName isn't a linux specific function, but dependent
|
||||||
|
|
@ -89,25 +46,39 @@ func TestDiskIOStats_diskName(t *testing.T) {
|
||||||
{[]string{"$MY_PARAM_2/$MISSING"}, "null"},
|
{[]string{"$MY_PARAM_2/$MISSING"}, "null"},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tc := range tests {
|
for i, tc := range tests {
|
||||||
func() {
|
t.Run(fmt.Sprintf("template %d", i), func(t *testing.T) {
|
||||||
s := DiskIO{
|
plugin := DiskIO{
|
||||||
NameTemplates: tc.templates,
|
NameTemplates: tc.templates,
|
||||||
|
infoCache: map[string]diskInfoCache{
|
||||||
|
"null": {
|
||||||
|
modifiedAt: 0,
|
||||||
|
udevDataPath: "testdata/udev.txt",
|
||||||
|
sysBlockPath: "testdata",
|
||||||
|
values: map[string]string{},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
defer setupNullDisk(t, &s, "null")() //nolint:revive // done on purpose, cleaning will be executed properly
|
name, _ := plugin.diskName("null")
|
||||||
name, _ := s.diskName("null")
|
|
||||||
require.Equal(t, tc.expected, name, "Templates: %#v", tc.templates)
|
require.Equal(t, tc.expected, name, "Templates: %#v", tc.templates)
|
||||||
}()
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DiskIOStats.diskTags isn't a linux specific function, but dependent
|
// DiskIOStats.diskTags isn't a linux specific function, but dependent
|
||||||
// functions are a no-op on non-Linux.
|
// functions are a no-op on non-Linux.
|
||||||
func TestDiskIOStats_diskTags(t *testing.T) {
|
func TestDiskIOStats_diskTags(t *testing.T) {
|
||||||
s := &DiskIO{
|
plugin := &DiskIO{
|
||||||
DeviceTags: []string{"MY_PARAM_2"},
|
DeviceTags: []string{"MY_PARAM_2"},
|
||||||
|
infoCache: map[string]diskInfoCache{
|
||||||
|
"null": {
|
||||||
|
modifiedAt: 0,
|
||||||
|
udevDataPath: "testdata/udev.txt",
|
||||||
|
sysBlockPath: "testdata",
|
||||||
|
values: map[string]string{},
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
defer setupNullDisk(t, s, "null")() //nolint:revive // done on purpose, cleaning will be executed properly
|
dt := plugin.diskTags("null")
|
||||||
dt := s.diskTags("null")
|
|
||||||
require.Equal(t, map[string]string{"MY_PARAM_2": "myval2"}, dt)
|
require.Equal(t, map[string]string{"MY_PARAM_2": "myval2"}, dt)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,24 +2,7 @@
|
||||||
|
|
||||||
package diskio
|
package diskio
|
||||||
|
|
||||||
import (
|
type diskInfoCache struct{}
|
||||||
"github.com/influxdata/telegraf"
|
|
||||||
"github.com/influxdata/telegraf/filter"
|
|
||||||
"github.com/influxdata/telegraf/plugins/inputs/system"
|
|
||||||
)
|
|
||||||
|
|
||||||
type DiskIO struct {
|
|
||||||
ps system.PS
|
|
||||||
|
|
||||||
Devices []string
|
|
||||||
DeviceTags []string
|
|
||||||
NameTemplates []string
|
|
||||||
SkipSerialNumber bool
|
|
||||||
|
|
||||||
Log telegraf.Logger
|
|
||||||
|
|
||||||
deviceFilter filter.Filter
|
|
||||||
}
|
|
||||||
|
|
||||||
func (*DiskIO) diskInfo(_ string) (map[string]string, error) {
|
func (*DiskIO) diskInfo(_ string) (map[string]string, error) {
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
|
||||||
|
|
@ -1,23 +1,19 @@
|
||||||
# Read metrics about disk IO by device
|
# Read metrics about disk IO by device
|
||||||
[[inputs.diskio]]
|
[[inputs.diskio]]
|
||||||
## By default, telegraf will gather stats for all devices including
|
## Devices to collect stats for
|
||||||
## disk partitions.
|
## Wildcards are supported except for disk synonyms like '/dev/disk/by-id'.
|
||||||
## Setting devices will restrict the stats to the specified devices.
|
## ex. devices = ["sda", "sdb", "vd*", "/dev/disk/by-id/nvme-eui.00123deadc0de123"]
|
||||||
## NOTE: Globbing expressions (e.g. asterix) are not supported for
|
# devices = ["*"]
|
||||||
## disk synonyms like '/dev/disk/by-id'.
|
|
||||||
# devices = ["sda", "sdb", "vd*", "/dev/disk/by-id/nvme-eui.00123deadc0de123"]
|
## Skip gathering of the disk's serial numbers.
|
||||||
## Uncomment the following line if you need disk serial numbers.
|
# skip_serial_number = true
|
||||||
# skip_serial_number = false
|
|
||||||
#
|
## Device metadata tags to add on systems supporting it (Linux only)
|
||||||
## On systems which support it, device metadata can be added in the form of
|
## Use 'udevadm info -q property -n <device>' to get a list of properties.
|
||||||
## tags.
|
|
||||||
## Currently only Linux is supported via udev properties. You can view
|
|
||||||
## available properties for a device by running:
|
|
||||||
## 'udevadm info -q property -n /dev/sda'
|
|
||||||
## Note: Most, but not all, udev properties can be accessed this way. Properties
|
## Note: Most, but not all, udev properties can be accessed this way. Properties
|
||||||
## that are currently inaccessible include DEVTYPE, DEVNAME, and DEVPATH.
|
## that are currently inaccessible include DEVTYPE, DEVNAME, and DEVPATH.
|
||||||
# device_tags = ["ID_FS_TYPE", "ID_FS_USAGE"]
|
# device_tags = ["ID_FS_TYPE", "ID_FS_USAGE"]
|
||||||
#
|
|
||||||
## Using the same metadata source as device_tags, you can also customize the
|
## Using the same metadata source as device_tags, you can also customize the
|
||||||
## name of the device via templates.
|
## name of the device via templates.
|
||||||
## The 'name_templates' parameter is a list of templates to try and apply to
|
## The 'name_templates' parameter is a list of templates to try and apply to
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,4 @@
|
||||||
|
E:MY_PARAM_1=myval1
|
||||||
|
E:MY_PARAM_2=myval2
|
||||||
|
S:foo/bar/devlink
|
||||||
|
S:foo/bar/devlink1
|
||||||
|
|
@ -0,0 +1,5 @@
|
||||||
|
MAJOR=259
|
||||||
|
MINOR=1
|
||||||
|
DEVNAME=null
|
||||||
|
DEVTYPE=disk
|
||||||
|
DISKSEQ=2
|
||||||
Loading…
Reference in New Issue