Add driver root abstraction

This change adds a driver root abstraction that defines how
libraries are located relative to the root. This allows for
this driver root to be constructed once and passed to discovery
code.

Signed-off-by: Evan Lezar <elezar@nvidia.com>
This commit is contained in:
Evan Lezar
2023-11-21 16:08:16 +01:00
parent f20ab793a2
commit bbd9222206
9 changed files with 119 additions and 83 deletions

View File

@@ -28,6 +28,7 @@ import (
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/cuda"
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/root"
)
// NewDRMNodesDiscoverer returns a discoverrer for the DRM device nodes associated with the specified visible devices.
@@ -48,15 +49,11 @@ func NewDRMNodesDiscoverer(logger logger.Interface, devices image.VisibleDevices
}
// NewGraphicsMountsDiscoverer creates a discoverer for the mounts required by graphics tools such as vulkan.
func NewGraphicsMountsDiscoverer(logger logger.Interface, driverRoot string, nvidiaCTKPath string) (Discover, error) {
locator := lookup.NewLibraryLocator(
lookup.WithLogger(logger),
lookup.WithRoot(driverRoot),
)
func NewGraphicsMountsDiscoverer(logger logger.Interface, driver *root.Driver, nvidiaCTKPath string) (Discover, error) {
libraries := NewMounts(
logger,
locator,
driverRoot,
driver.Libraries(),
driver.Root,
[]string{
"libnvidia-egl-gbm.so",
},
@@ -66,10 +63,10 @@ func NewGraphicsMountsDiscoverer(logger logger.Interface, driverRoot string, nvi
logger,
lookup.NewFileLocator(
lookup.WithLogger(logger),
lookup.WithRoot(driverRoot),
lookup.WithRoot(driver.Root),
lookup.WithSearchPaths("/etc", "/usr/share"),
),
driverRoot,
driver.Root,
[]string{
"glvnd/egl_vendor.d/10_nvidia.json",
"vulkan/icd.d/nvidia_icd.json",
@@ -79,7 +76,7 @@ func NewGraphicsMountsDiscoverer(logger logger.Interface, driverRoot string, nvi
},
)
xorg := optionalXorgDiscoverer(logger, driverRoot, nvidiaCTKPath)
xorg := optionalXorgDiscoverer(logger, driver, nvidiaCTKPath)
discover := Merge(
libraries,
@@ -247,8 +244,8 @@ var _ Discover = (*xorgHooks)(nil)
// optionalXorgDiscoverer creates a discoverer for Xorg libraries.
// If the creation of the discoverer fails, a None discoverer is returned.
func optionalXorgDiscoverer(logger logger.Interface, driverRoot string, nvidiaCTKPath string) Discover {
xorg, err := newXorgDiscoverer(logger, driverRoot, nvidiaCTKPath)
func optionalXorgDiscoverer(logger logger.Interface, driver *root.Driver, nvidiaCTKPath string) Discover {
xorg, err := newXorgDiscoverer(logger, driver, nvidiaCTKPath)
if err != nil {
logger.Warningf("Failed to create Xorg discoverer: %v; skipping xorg libraries", err)
return None{}
@@ -256,10 +253,9 @@ func optionalXorgDiscoverer(logger logger.Interface, driverRoot string, nvidiaCT
return xorg
}
func newXorgDiscoverer(logger logger.Interface, driverRoot string, nvidiaCTKPath string) (Discover, error) {
func newXorgDiscoverer(logger logger.Interface, driver *root.Driver, nvidiaCTKPath string) (Discover, error) {
libCudaPaths, err := cuda.New(
cuda.WithLogger(logger),
cuda.WithDriverRoot(driverRoot),
driver.Libraries(),
).Locate(".*.*")
if err != nil {
return nil, fmt.Errorf("failed to locate libcuda.so: %v", err)
@@ -276,11 +272,11 @@ func newXorgDiscoverer(logger logger.Interface, driverRoot string, nvidiaCTKPath
logger,
lookup.NewFileLocator(
lookup.WithLogger(logger),
lookup.WithRoot(driverRoot),
lookup.WithRoot(driver.Root),
lookup.WithSearchPaths(libRoot, "/usr/lib/x86_64-linux-gnu"),
lookup.WithCount(1),
),
driverRoot,
driver.Root,
[]string{
"nvidia/xorg/nvidia_drv.so",
fmt.Sprintf("nvidia/xorg/libglxserver_nvidia.so.%s", version),
@@ -296,10 +292,10 @@ func newXorgDiscoverer(logger logger.Interface, driverRoot string, nvidiaCTKPath
logger,
lookup.NewFileLocator(
lookup.WithLogger(logger),
lookup.WithRoot(driverRoot),
lookup.WithRoot(driver.Root),
lookup.WithSearchPaths("/usr/share"),
),
driverRoot,
driver.Root,
[]string{"X11/xorg.conf.d/10-nvidia.conf"},
)

View File

@@ -17,52 +17,19 @@
package cuda
import (
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
)
type cudaLocator struct {
lookup.Locator
logger logger.Interface
driverRoot string
}
// Options is a function that configures a cudaLocator.
type Options func(*cudaLocator)
// WithLogger is an option that configures the logger used by the locator.
func WithLogger(logger logger.Interface) Options {
return func(c *cudaLocator) {
c.logger = logger
}
}
// WithDriverRoot is an option that configures the driver root used by the locator.
func WithDriverRoot(driverRoot string) Options {
return func(c *cudaLocator) {
c.driverRoot = driverRoot
}
}
// New creates a new CUDA library locator.
func New(opts ...Options) lookup.Locator {
c := &cudaLocator{}
for _, opt := range opts {
opt(c)
func New(libraries lookup.Locator) lookup.Locator {
c := cudaLocator{
Locator: libraries,
}
if c.logger == nil {
c.logger = logger.New()
}
if c.driverRoot == "" {
c.driverRoot = "/"
}
c.Locator = lookup.NewLibraryLocator(
lookup.WithLogger(c.logger),
lookup.WithRoot(c.driverRoot),
)
return c
return &c
}
// Locate returns the path to the libcuda.so.RMVERSION file.

View File

@@ -57,8 +57,10 @@ func TestLocate(t *testing.T) {
require.NoError(t, err)
l := New(
WithLogger(logger),
WithDriverRoot(driverRoot),
lookup.NewLibraryLocator(
lookup.WithLogger(logger),
lookup.WithRoot(driverRoot),
),
)
candidates, err := l.Locate(".*")

View File

@@ -0,0 +1,65 @@
/**
# Copyright 2023 NVIDIA CORPORATION
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
**/
package root
import (
"path/filepath"
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup"
)
// Driver represents a filesystem in which a set of drivers or devices is defined.
type Driver struct {
logger logger.Interface
// Root represents the root from the perspective of the driver libraries and binaries.
Root string
// librarySearchPaths specifies explicit search paths for discovering libraries.
librarySearchPaths []string
}
// New creates a new Driver root at the specified path.
// TODO: Use functional options here.
func New(logger logger.Interface, path string, librarySearchPaths []string) *Driver {
return &Driver{
logger: logger,
Root: path,
librarySearchPaths: normalizeSearchPaths(librarySearchPaths...),
}
}
// Drivers returns a Locator for driver libraries.
func (r *Driver) Libraries() lookup.Locator {
return lookup.NewLibraryLocator(
lookup.WithLogger(r.logger),
lookup.WithRoot(r.Root),
lookup.WithSearchPaths(r.librarySearchPaths...),
)
}
// normalizeSearchPaths takes a list of paths and normalized these.
// Each of the elements in the list is expanded if it is a path list and the
// resultant list is returned.
// This allows, for example, for the contents of `PATH` or `LD_LIBRARY_PATH` to
// be passed as a search path directly.
func normalizeSearchPaths(paths ...string) []string {
var normalized []string
for _, path := range paths {
normalized = append(normalized, filepath.SplitList(path)...)
}
return normalized
}

View File

@@ -23,6 +23,7 @@ import (
"github.com/NVIDIA/nvidia-container-toolkit/internal/config/image"
"github.com/NVIDIA/nvidia-container-toolkit/internal/discover"
"github.com/NVIDIA/nvidia-container-toolkit/internal/logger"
"github.com/NVIDIA/nvidia-container-toolkit/internal/lookup/root"
"github.com/NVIDIA/nvidia-container-toolkit/internal/oci"
)
@@ -34,20 +35,21 @@ func NewGraphicsModifier(logger logger.Interface, cfg *config.Config, image imag
return nil, nil
}
driverRoot := cfg.NVIDIAContainerCLIConfig.Root
// TODO: We should not just pass `nil` as the search path here.
driver := root.New(logger, cfg.NVIDIAContainerCLIConfig.Root, nil)
nvidiaCTKPath := cfg.NVIDIACTKConfig.Path
mounts, err := discover.NewGraphicsMountsDiscoverer(
logger,
driverRoot,
driver,
nvidiaCTKPath,
)
if err != nil {
return nil, fmt.Errorf("failed to create mounts discoverer: %v", err)
}
// In standard usage, the devRoot is the same as the driverRoot.
devRoot := driverRoot
// In standard usage, the devRoot is the same as the driver.Root.
devRoot := driver.Root
drmNodes, err := discover.NewDRMNodesDiscoverer(
logger,
image.DevicesFromEnvvars(visibleDevicesEnvvar),