Skip to content

Commit

Permalink
Merge pull request #243 from fromanirh/snapshots-gpu
Browse files Browse the repository at this point in the history
snapshot: collect data related to GPU devices
  • Loading branch information
jaypipes committed May 12, 2021
2 parents 56ca185 + bf547f1 commit a7823c0
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 38 deletions.
59 changes: 59 additions & 0 deletions pkg/snapshot/clonetree.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ func ExpectedCloneContent() []string {
fileSpecs := ExpectedCloneStaticContent()
fileSpecs = append(fileSpecs, ExpectedCloneNetContent()...)
fileSpecs = append(fileSpecs, ExpectedClonePCIContent()...)
fileSpecs = append(fileSpecs, ExpectedCloneGPUContent()...)
return fileSpecs
}

Expand Down Expand Up @@ -202,3 +203,61 @@ func copyLink(path, targetPath string) error {

return nil
}

type filterFunc func(string) bool

// cloneContentByClass copies all the content related to a given device class
// (devClass), possibly filtering out devices whose name does NOT pass a
// filter (filterName). Each entry in `/sys/class/$CLASS` is actually a
// symbolic link. We can filter out entries depending on the link target.
// Each filter is a simple function which takes the entry name or the link
// target and must return true if the entry should be collected, false
// otherwise. Last, explicitely collect a list of attributes for each entry,
// given as list of glob patterns as `subEntries`.
// Return the final list of glob patterns to be collected.
func cloneContentByClass(devClass string, subEntries []string, filterName filterFunc, filterLink filterFunc) []string {
var fileSpecs []string

// warning: don't use the context package here, this means not even the linuxpath package.
// TODO(fromani) remove the path duplication
sysClass := filepath.Join("sys", "class", devClass)
entries, err := ioutil.ReadDir(sysClass)
if err != nil {
// we should not import context, hence we can't Warn()
return fileSpecs
}
for _, entry := range entries {
devName := entry.Name()

if !filterName(devName) {
continue
}

devPath := filepath.Join(sysClass, devName)
dest, err := os.Readlink(devPath)
if err != nil {
continue
}

if !filterLink(dest) {
continue
}

// so, first copy the symlink itself
fileSpecs = append(fileSpecs, devPath)
// now we have to clone the content of the actual entry
// related (and found into a subdir of) the backing hardware
// device
devData := filepath.Clean(filepath.Join(sysClass, dest))
for _, subEntry := range subEntries {
fileSpecs = append(fileSpecs, filepath.Join(devData, subEntry))
}
}

return fileSpecs
}

// filterNone allows all content, filtering out none of it
func filterNone(_ string) bool {
return true
}
33 changes: 33 additions & 0 deletions pkg/snapshot/clonetree_gpu.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
//
// Use and distribution licensed under the Apache license version 2.
//
// See the COPYING file in the root project directory for full text.
//

package snapshot

import (
"strings"
)

// ExpectedCloneGPUContent returns a slice of strings pertaining to the GPU devices ghw
// cares about. We cannot use a static list because we want to grab only the first cardX data
// (see comment in pkg/gpu/gpu_linux.go)
// Additionally, we want to make sure to clone the backing device data.
func ExpectedCloneGPUContent() []string {
cardEntries := []string{
"device",
}

filterName := func(cardName string) bool {
if !strings.HasPrefix(cardName, "card") {
return false
}
if strings.ContainsRune(cardName, '-') {
return false
}
return true
}

return cloneContentByClass("drm", cardEntries, filterName, filterNone)
}
43 changes: 5 additions & 38 deletions pkg/snapshot/clonetree_net.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,58 +7,25 @@
package snapshot

import (
"io/ioutil"
"os"
"path/filepath"
"strings"
)

const (
// warning: don't use the context package here, this means not even the linuxpath package.
// TODO(fromani) remove the path duplication
sysClassNet = "/sys/class/net"
)

// ExpectedCloneNetContent returns a slice of strings pertaning to the network interfaces ghw
// cares about. We cannot use a static list because we want to filter away the virtual devices,
// which ghw doesn't concern itself about. So we need to do some runtime discovery.
// Additionally, we want to make sure to clone the backing device data.
func ExpectedCloneNetContent() []string {
var fileSpecs []string
ifaceEntries := []string{
"addr_assign_type",
// intentionally avoid to clone "address" to avoid to leak any host-idenfifiable data.
}
entries, err := ioutil.ReadDir(sysClassNet)
if err != nil {
// we should not import context, hence we can't Warn()
return fileSpecs
}
for _, entry := range entries {
netName := entry.Name()
netPath := filepath.Join(sysClassNet, netName)
dest, err := os.Readlink(netPath)
if err != nil {
continue
}
if strings.Contains(dest, "devices/virtual/net") {
// there is no point in cloning data for virtual devices,
// because ghw concerns itself with HardWare.
continue
}

// so, first copy the symlink itself
fileSpecs = append(fileSpecs, netPath)

// now we have to clone the content of the actual network interface
// data related (and found into a subdir of) the backing hardware
// device
netIface := filepath.Clean(filepath.Join(sysClassNet, dest))
for _, ifaceEntry := range ifaceEntries {
fileSpecs = append(fileSpecs, filepath.Join(netIface, ifaceEntry))
filterLink := func(linkDest string) bool {
if strings.Contains(linkDest, "devices/virtual/net") {
return false
}

return true
}

return fileSpecs
return cloneContentByClass("net", ifaceEntries, filterNone, filterLink)
}

0 comments on commit a7823c0

Please sign in to comment.