Merge branch 'fix-relative-files' into 'main'

Fix adjusting relative paths for containerised devices and mounts.

See merge request nvidia/container-toolkit/container-toolkit!193
This commit is contained in:
Evan Lezar 2022-07-20 11:40:28 +00:00
commit 629a68937e
8 changed files with 87 additions and 68 deletions

View File

@ -30,16 +30,14 @@ var _ Discover = (*charDevices)(nil)
func NewCharDeviceDiscoverer(logger *logrus.Logger, devices []string, root string) Discover { func NewCharDeviceDiscoverer(logger *logrus.Logger, devices []string, root string) Discover {
locator := lookup.NewCharDeviceLocator(logger, root) locator := lookup.NewCharDeviceLocator(logger, root)
return NewDeviceDiscoverer(logger, locator, devices) return NewDeviceDiscoverer(logger, locator, root, devices)
} }
// NewDeviceDiscoverer creates a discoverer which locates the specified set of device nodes using the specified locator. // NewDeviceDiscoverer creates a discoverer which locates the specified set of device nodes using the specified locator.
func NewDeviceDiscoverer(logger *logrus.Logger, locator lookup.Locator, devices []string) Discover { func NewDeviceDiscoverer(logger *logrus.Logger, locator lookup.Locator, root string, devices []string) Discover {
return &charDevices{ m := NewMounts(logger, locator, root, devices).(*mounts)
logger: logger,
lookup: locator, return (*charDevices)(m)
required: devices,
}
} }
// Mounts returns the discovered mounts for the charDevices. // Mounts returns the discovered mounts for the charDevices.

View File

@ -52,7 +52,7 @@ func NewFromCSVFiles(logger *logrus.Logger, files []string, root string) (Discov
mountSpecs = append(mountSpecs, targets...) mountSpecs = append(mountSpecs, targets...)
} }
return newFromMountSpecs(logger, locators, mountSpecs) return newFromMountSpecs(logger, locators, root, mountSpecs)
} }
// loadCSVFile loads the specified CSV file and returns the list of mount specs // loadCSVFile loads the specified CSV file and returns the list of mount specs
@ -71,7 +71,7 @@ func loadCSVFile(logger *logrus.Logger, filename string) ([]*csv.MountSpec, erro
// newFromMountSpecs creates a discoverer for the CSV file. A logger is also supplied. // newFromMountSpecs creates a discoverer for the CSV file. A logger is also supplied.
// A list of csvDiscoverers is returned, with each being associated with a single MountSpecType. // A list of csvDiscoverers is returned, with each being associated with a single MountSpecType.
func newFromMountSpecs(logger *logrus.Logger, locators map[csv.MountSpecType]lookup.Locator, targets []*csv.MountSpec) (Discover, error) { func newFromMountSpecs(logger *logrus.Logger, locators map[csv.MountSpecType]lookup.Locator, root string, targets []*csv.MountSpec) (Discover, error) {
if len(targets) == 0 { if len(targets) == 0 {
return &None{}, nil return &None{}, nil
} }
@ -95,13 +95,9 @@ func newFromMountSpecs(logger *logrus.Logger, locators map[csv.MountSpecType]loo
var m Discover var m Discover
switch t { switch t {
case csv.MountSpecDev: case csv.MountSpecDev:
m = NewDeviceDiscoverer(logger, locator, candidatesByType[t]) m = NewDeviceDiscoverer(logger, locator, root, candidatesByType[t])
default: default:
m = &mounts{ m = NewMounts(logger, locator, root, candidatesByType[t])
logger: logger,
lookup: locator,
required: candidatesByType[t],
}
} }
discoverers = append(discoverers, m) discoverers = append(discoverers, m)

View File

@ -36,6 +36,7 @@ func TestNewFromMountSpec(t *testing.T) {
testCases := []struct { testCases := []struct {
description string description string
root string
targets []*csv.MountSpec targets []*csv.MountSpec
expectedError error expectedError error
expectedDiscoverer Discover expectedDiscoverer Discover
@ -76,12 +77,50 @@ func TestNewFromMountSpec(t *testing.T) {
&mounts{ &mounts{
logger: logger, logger: logger,
lookup: locators["dev"], lookup: locators["dev"],
root: "/",
required: []string{"dev0", "dev1"}, required: []string{"dev0", "dev1"},
}, },
), ),
&mounts{ &mounts{
logger: logger, logger: logger,
lookup: locators["lib"], lookup: locators["lib"],
root: "/",
required: []string{"lib0"},
},
},
},
},
{
description: "sets root",
targets: []*csv.MountSpec{
{
Type: "dev",
Path: "dev0",
},
{
Type: "lib",
Path: "lib0",
},
{
Type: "dev",
Path: "dev1",
},
},
root: "/some/root",
expectedDiscoverer: &list{
discoverers: []Discover{
(*charDevices)(
&mounts{
logger: logger,
lookup: locators["dev"],
root: "/some/root",
required: []string{"dev0", "dev1"},
},
),
&mounts{
logger: logger,
lookup: locators["lib"],
root: "/some/root",
required: []string{"lib0"}, required: []string{"lib0"},
}, },
}, },
@ -91,7 +130,7 @@ func TestNewFromMountSpec(t *testing.T) {
for _, tc := range testCases { for _, tc := range testCases {
t.Run(tc.description, func(t *testing.T) { t.Run(tc.description, func(t *testing.T) {
discoverer, err := newFromMountSpecs(logger, locators, tc.targets) discoverer, err := newFromMountSpecs(logger, locators, tc.root, tc.targets)
if tc.expectedError != nil { if tc.expectedError != nil {
require.Error(t, err) require.Error(t, err)
return return

View File

@ -36,17 +36,19 @@ func NewGDSDiscoverer(logger *logrus.Logger, root string) (Discover, error) {
root, root,
) )
udev := &mounts{ udev := NewMounts(
logger: logger, logger,
lookup: lookup.NewDirectoryLocator(logger, root), lookup.NewDirectoryLocator(logger, root),
required: []string{"/run/udev"}, root,
} []string{"/run/udev"},
)
cufile := &mounts{ cufile := NewMounts(
logger: logger, logger,
lookup: lookup.NewFileLocator(logger, root), lookup.NewFileLocator(logger, root),
required: []string{"/etc/cufile.json"}, root,
} []string{"/etc/cufile.json"},
)
d := gdsDeviceDiscoverer{ d := gdsDeviceDiscoverer{
logger: logger, logger: logger,

View File

@ -18,6 +18,8 @@ package discover
import ( import (
"fmt" "fmt"
"path/filepath"
"strings"
"sync" "sync"
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup" "github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
@ -31,6 +33,7 @@ type mounts struct {
None None
logger *logrus.Logger logger *logrus.Logger
lookup lookup.Locator lookup lookup.Locator
root string
required []string required []string
sync.Mutex sync.Mutex
cache []Mount cache []Mount
@ -38,6 +41,16 @@ type mounts struct {
var _ Discover = (*mounts)(nil) var _ Discover = (*mounts)(nil)
// NewMounts creates a discoverer for the required mounts using the specified locator.
func NewMounts(logger *logrus.Logger, lookup lookup.Locator, root string, required []string) Discover {
return &mounts{
logger: logger,
lookup: lookup,
root: filepath.Join("/", root),
required: required,
}
}
func (d *mounts) Mounts() ([]Mount, error) { func (d *mounts) Mounts() ([]Mount, error) {
if d.lookup == nil { if d.lookup == nil {
return nil, fmt.Errorf("no lookup defined") return nil, fmt.Errorf("no lookup defined")
@ -71,11 +84,7 @@ func (d *mounts) Mounts() ([]Mount, error) {
continue continue
} }
r, err := d.lookup.Relative(p) r := d.relativeTo(p)
if err != nil {
d.logger.Warnf("Failed to get relative path of %v: %v", p, err)
continue
}
if r == "" { if r == "" {
r = p r = p
} }
@ -97,3 +106,12 @@ func (d *mounts) Mounts() ([]Mount, error) {
return d.cache, nil return d.cache, nil
} }
// relativeTo returns the path relative to the root for the file locator
func (d *mounts) relativeTo(path string) string {
if d.root == "/" {
return path
}
return strings.TrimPrefix(path, d.root)
}

View File

@ -140,37 +140,14 @@ func TestMounts(t *testing.T) {
input: &mounts{ input: &mounts{
lookup: &lookup.LocatorMock{ lookup: &lookup.LocatorMock{
LocateFunc: func(s string) ([]string, error) { LocateFunc: func(s string) ([]string, error) {
return []string{"located"}, nil return []string{"/some/root/located"}, nil
},
RelativeFunc: func(s string) (string, error) {
return "relative", nil
}, },
}, },
root: "/some/root",
required: []string{"required0", "multiple", "required1"}, required: []string{"required0", "multiple", "required1"},
}, },
expectedMounts: []Mount{ expectedMounts: []Mount{
{Path: "relative", HostPath: "located"}, {Path: "/located", HostPath: "/some/root/located"},
},
},
{
description: "mounts skips relative error",
input: &mounts{
lookup: &lookup.LocatorMock{
LocateFunc: func(s string) ([]string, error) {
return []string{s}, nil
},
RelativeFunc: func(s string) (string, error) {
if s == "error" {
return "", fmt.Errorf("no relative path")
}
return "relative" + s, nil
},
},
required: []string{"required0", "error", "required1"},
},
expectedMounts: []Mount{
{Path: "relativerequired0", HostPath: "required0"},
{Path: "relativerequired1", HostPath: "required1"},
}, },
}, },
} }

View File

@ -28,7 +28,6 @@ import (
// prefixes. The validity of a file is determined by a filter function. // prefixes. The validity of a file is determined by a filter function.
type file struct { type file struct {
logger *log.Logger logger *log.Logger
root string
prefixes []string prefixes []string
filter func(string) error filter func(string) error
} }
@ -78,15 +77,6 @@ func (p file) Locate(pattern string) ([]string, error) {
return filenames, nil return filenames, nil
} }
// Relative returns the path relative to the root for the file locator
func (p file) Relative(path string) (string, error) {
if p.root == "" || p.root == "/" {
return path, nil
}
return filepath.Rel(p.root, path)
}
// assertFile checks whether the specified path is a regular file // assertFile checks whether the specified path is a regular file
func assertFile(filename string) error { func assertFile(filename string) error {
info, err := os.Stat(filename) info, err := os.Stat(filename)

View File

@ -21,5 +21,4 @@ package lookup
// Locator defines the interface for locating files on a system. // Locator defines the interface for locating files on a system.
type Locator interface { type Locator interface {
Locate(string) ([]string, error) Locate(string) ([]string, error)
Relative(string) (string, error)
} }